Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-core/src/r4300/interupt.c
2 views
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
* Mupen64plus - interupt.c *
3
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4
* Copyright (C) 2002 Hacktarux *
5
* *
6
* This program is free software; you can redistribute it and/or modify *
7
* it under the terms of the GNU General Public License as published by *
8
* the Free Software Foundation; either version 2 of the License, or *
9
* (at your option) any later version. *
10
* *
11
* This program is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU General Public License for more details. *
15
* *
16
* You should have received a copy of the GNU General Public License *
17
* along with this program; if not, write to the *
18
* Free Software Foundation, Inc., *
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22
#include <stdlib.h>
23
24
#include <SDL.h>
25
26
#define M64P_CORE_PROTOTYPES 1
27
#include "api/m64p_types.h"
28
#include "api/callbacks.h"
29
#include "api/m64p_vidext.h"
30
#include "api/vidext.h"
31
#include "memory/memory.h"
32
#include "main/rom.h"
33
#include "main/main.h"
34
#include "main/savestates.h"
35
#include "main/cheat.h"
36
#include "osd/osd.h"
37
#include "plugin/plugin.h"
38
39
#include "interupt.h"
40
#include "r4300.h"
41
#include "macros.h"
42
#include "exception.h"
43
#include "reset.h"
44
#include "new_dynarec/new_dynarec.h"
45
46
#ifdef WITH_LIRC
47
#include "main/lirc.h"
48
#endif
49
50
unsigned int next_vi;
51
int vi_field=0;
52
static int vi_counter=0;
53
54
int interupt_unsafe_state = 0;
55
56
typedef struct _interupt_queue
57
{
58
int type;
59
unsigned int count;
60
struct _interupt_queue *next;
61
} interupt_queue;
62
63
static interupt_queue *q = NULL;
64
65
static void clear_queue(void)
66
{
67
while(q != NULL)
68
{
69
interupt_queue *aux = q->next;
70
free(q);
71
q = aux;
72
}
73
}
74
75
/*static void print_queue(void)
76
{
77
interupt_queue *aux;
78
//if (Count < 0x7000000) return;
79
DebugMessage(M64MSG_INFO, "------------------ 0x%x", (unsigned int)Count);
80
aux = q;
81
while (aux != NULL)
82
{
83
DebugMessage(M64MSG_INFO, "Count:%x, %x", (unsigned int)aux->count, aux->type);
84
aux = aux->next;
85
}
86
}*/
87
88
static int SPECIAL_done = 0;
89
90
static int before_event(unsigned int evt1, unsigned int evt2, int type2)
91
{
92
if(evt1 - Count < 0x80000000)
93
{
94
if(evt2 - Count < 0x80000000)
95
{
96
if((evt1 - Count) < (evt2 - Count)) return 1;
97
else return 0;
98
}
99
else
100
{
101
if((Count - evt2) < 0x10000000)
102
{
103
switch(type2)
104
{
105
case SPECIAL_INT:
106
if(SPECIAL_done) return 1;
107
else return 0;
108
break;
109
default:
110
return 0;
111
}
112
}
113
else return 1;
114
}
115
}
116
else return 0;
117
}
118
119
void add_interupt_event(int type, unsigned int delay)
120
{
121
unsigned int count = Count + delay/**2*/;
122
int special = 0;
123
interupt_queue *aux = q;
124
125
if(type == SPECIAL_INT /*|| type == COMPARE_INT*/) special = 1;
126
if(Count > 0x80000000) SPECIAL_done = 0;
127
128
if (get_event(type)) {
129
DebugMessage(M64MSG_WARNING, "two events of type 0x%x in interrupt queue", type);
130
return;
131
}
132
133
if (q == NULL)
134
{
135
q = (interupt_queue *) malloc(sizeof(interupt_queue));
136
q->next = NULL;
137
q->count = count;
138
q->type = type;
139
next_interupt = q->count;
140
//print_queue();
141
return;
142
}
143
144
if(before_event(count, q->count, q->type) && !special)
145
{
146
q = (interupt_queue *) malloc(sizeof(interupt_queue));
147
q->next = aux;
148
q->count = count;
149
q->type = type;
150
next_interupt = q->count;
151
//print_queue();
152
return;
153
}
154
155
while (aux->next != NULL && (!before_event(count, aux->next->count, aux->next->type) || special))
156
aux = aux->next;
157
158
if (aux->next == NULL)
159
{
160
aux->next = (interupt_queue *) malloc(sizeof(interupt_queue));
161
aux = aux->next;
162
aux->next = NULL;
163
aux->count = count;
164
aux->type = type;
165
}
166
else
167
{
168
interupt_queue *aux2;
169
if (type != SPECIAL_INT)
170
while(aux->next != NULL && aux->next->count == count)
171
aux = aux->next;
172
aux2 = aux->next;
173
aux->next = (interupt_queue *) malloc(sizeof(interupt_queue));
174
aux = aux->next;
175
aux->next = aux2;
176
aux->count = count;
177
aux->type = type;
178
}
179
}
180
181
void add_interupt_event_count(int type, unsigned int count)
182
{
183
add_interupt_event(type, (count - Count)/*/2*/);
184
}
185
186
static void remove_interupt_event(void)
187
{
188
interupt_queue *aux = q->next;
189
if(q->type == SPECIAL_INT) SPECIAL_done = 1;
190
free(q);
191
q = aux;
192
if (q != NULL && (q->count > Count || (Count - q->count) < 0x80000000))
193
next_interupt = q->count;
194
else
195
next_interupt = 0;
196
}
197
198
unsigned int get_event(int type)
199
{
200
interupt_queue *aux = q;
201
if (q == NULL) return 0;
202
if (q->type == type)
203
return q->count;
204
while (aux->next != NULL && aux->next->type != type)
205
aux = aux->next;
206
if (aux->next != NULL)
207
return aux->next->count;
208
return 0;
209
}
210
211
int get_next_event_type(void)
212
{
213
if (q == NULL) return 0;
214
return q->type;
215
}
216
217
void remove_event(int type)
218
{
219
interupt_queue *aux = q;
220
if (q == NULL) return;
221
if (q->type == type)
222
{
223
aux = aux->next;
224
free(q);
225
q = aux;
226
return;
227
}
228
while (aux->next != NULL && aux->next->type != type)
229
aux = aux->next;
230
if (aux->next != NULL) // it's a type int
231
{
232
interupt_queue *aux2 = aux->next->next;
233
free(aux->next);
234
aux->next = aux2;
235
}
236
}
237
238
void translate_event_queue(unsigned int base)
239
{
240
interupt_queue *aux;
241
remove_event(COMPARE_INT);
242
remove_event(SPECIAL_INT);
243
aux=q;
244
while (aux != NULL)
245
{
246
aux->count = (aux->count - Count)+base;
247
aux = aux->next;
248
}
249
add_interupt_event_count(COMPARE_INT, Compare);
250
add_interupt_event_count(SPECIAL_INT, 0);
251
}
252
253
int save_eventqueue_infos(char *buf)
254
{
255
int len = 0;
256
interupt_queue *aux = q;
257
if (q == NULL)
258
{
259
*((unsigned int*)&buf[0]) = 0xFFFFFFFF;
260
return 4;
261
}
262
while (aux != NULL)
263
{
264
memcpy(buf+len , &aux->type , 4);
265
memcpy(buf+len+4, &aux->count, 4);
266
len += 8;
267
aux = aux->next;
268
}
269
*((unsigned int*)&buf[len]) = 0xFFFFFFFF;
270
return len+4;
271
}
272
273
void load_eventqueue_infos(char *buf)
274
{
275
int len = 0;
276
clear_queue();
277
while (*((unsigned int*)&buf[len]) != 0xFFFFFFFF)
278
{
279
int type = *((unsigned int*)&buf[len]);
280
unsigned int count = *((unsigned int*)&buf[len+4]);
281
add_interupt_event_count(type, count);
282
len += 8;
283
}
284
}
285
286
void init_interupt(void)
287
{
288
SPECIAL_done = 1;
289
next_vi = next_interupt = 5000;
290
vi_register.vi_delay = next_vi;
291
vi_field = 0;
292
clear_queue();
293
add_interupt_event_count(VI_INT, next_vi);
294
add_interupt_event_count(SPECIAL_INT, 0);
295
}
296
297
void check_interupt(void)
298
{
299
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
300
Cause = (Cause | 0x400) & 0xFFFFFF83;
301
else
302
Cause &= ~0x400;
303
if ((Status & 7) != 1) return;
304
if (Status & Cause & 0xFF00)
305
{
306
if(q == NULL)
307
{
308
q = (interupt_queue *) malloc(sizeof(interupt_queue));
309
q->next = NULL;
310
q->count = Count;
311
q->type = CHECK_INT;
312
}
313
else
314
{
315
interupt_queue* aux = (interupt_queue *) malloc(sizeof(interupt_queue));
316
aux->next = q;
317
aux->count = Count;
318
aux->type = CHECK_INT;
319
q = aux;
320
}
321
next_interupt = Count;
322
}
323
}
324
325
void gen_interupt(void)
326
{
327
if (stop == 1)
328
{
329
vi_counter = 0; // debug
330
dyna_stop();
331
}
332
333
if (!interupt_unsafe_state)
334
{
335
if (savestates_get_job() == savestates_job_load)
336
{
337
savestates_load();
338
return;
339
}
340
341
if (reset_hard_job)
342
{
343
reset_hard();
344
reset_hard_job = 0;
345
return;
346
}
347
}
348
349
if (skip_jump)
350
{
351
unsigned int dest = skip_jump;
352
skip_jump = 0;
353
354
if (q->count > Count || (Count - q->count) < 0x80000000)
355
next_interupt = q->count;
356
else
357
next_interupt = 0;
358
359
last_addr = dest;
360
generic_jump_to(dest);
361
return;
362
}
363
364
switch(q->type)
365
{
366
case SPECIAL_INT:
367
if (Count > 0x10000000) return;
368
remove_interupt_event();
369
add_interupt_event_count(SPECIAL_INT, 0);
370
return;
371
break;
372
case VI_INT:
373
if(vi_counter < 60)
374
{
375
if (vi_counter == 0)
376
cheat_apply_cheats(ENTRY_BOOT);
377
vi_counter++;
378
}
379
else
380
{
381
cheat_apply_cheats(ENTRY_VI);
382
}
383
gfx.updateScreen();
384
#ifdef WITH_LIRC
385
lircCheckInput();
386
#endif
387
SDL_PumpEvents();
388
389
refresh_stat();
390
391
// if paused, poll for input events
392
//if(rompause)
393
//{
394
osd_render(); // draw Paused message in case gfx.updateScreen didn't do it
395
//VidExt_GL_SwapBuffers();
396
// while(rompause)
397
// {
398
//SDL_Delay(10);
399
400
SDL_PumpEvents();
401
#ifdef WITH_LIRC
402
lircCheckInput();
403
#endif //WITH_LIRC
404
// }
405
//}
406
407
new_vi();
408
WaitForSingleObject(rompausesem, INFINITE);
409
if (vi_register.vi_v_sync == 0) vi_register.vi_delay = 500000;
410
else vi_register.vi_delay = ((vi_register.vi_v_sync + 1)*1500);
411
next_vi += vi_register.vi_delay;
412
if (vi_register.vi_status&0x40) vi_field=1-vi_field;
413
else vi_field=0;
414
415
remove_interupt_event();
416
add_interupt_event_count(VI_INT, next_vi);
417
418
MI_register.mi_intr_reg |= 0x08;
419
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
420
Cause = (Cause | 0x400) & 0xFFFFFF83;
421
else
422
return;
423
if ((Status & 7) != 1) return;
424
if (!(Status & Cause & 0xFF00)) return;
425
break;
426
427
case COMPARE_INT:
428
remove_interupt_event();
429
Count+=2;
430
add_interupt_event_count(COMPARE_INT, Compare);
431
Count-=2;
432
433
Cause = (Cause | 0x8000) & 0xFFFFFF83;
434
if ((Status & 7) != 1) return;
435
if (!(Status & Cause & 0xFF00)) return;
436
break;
437
438
case CHECK_INT:
439
remove_interupt_event();
440
break;
441
442
case SI_INT:
443
#ifdef WITH_LIRC
444
lircCheckInput();
445
#endif //WITH_LIRC
446
SDL_PumpEvents();
447
PIF_RAMb[0x3F] = 0x0;
448
remove_interupt_event();
449
MI_register.mi_intr_reg |= 0x02;
450
si_register.si_stat |= 0x1000;
451
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
452
Cause = (Cause | 0x400) & 0xFFFFFF83;
453
else
454
return;
455
if ((Status & 7) != 1) return;
456
if (!(Status & Cause & 0xFF00)) return;
457
break;
458
459
case PI_INT:
460
remove_interupt_event();
461
MI_register.mi_intr_reg |= 0x10;
462
pi_register.read_pi_status_reg &= ~3;
463
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
464
Cause = (Cause | 0x400) & 0xFFFFFF83;
465
else
466
return;
467
if ((Status & 7) != 1) return;
468
if (!(Status & Cause & 0xFF00)) return;
469
break;
470
471
case AI_INT:
472
if (ai_register.ai_status & 0x80000000) // full
473
{
474
unsigned int ai_event = get_event(AI_INT);
475
remove_interupt_event();
476
ai_register.ai_status &= ~0x80000000;
477
ai_register.current_delay = ai_register.next_delay;
478
ai_register.current_len = ai_register.next_len;
479
add_interupt_event_count(AI_INT, ai_event+ai_register.next_delay);
480
481
MI_register.mi_intr_reg |= 0x04;
482
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
483
Cause = (Cause | 0x400) & 0xFFFFFF83;
484
else
485
return;
486
if ((Status & 7) != 1) return;
487
if (!(Status & Cause & 0xFF00)) return;
488
}
489
else
490
{
491
remove_interupt_event();
492
ai_register.ai_status &= ~0x40000000;
493
494
//-------
495
MI_register.mi_intr_reg |= 0x04;
496
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
497
Cause = (Cause | 0x400) & 0xFFFFFF83;
498
else
499
return;
500
if ((Status & 7) != 1) return;
501
if (!(Status & Cause & 0xFF00)) return;
502
}
503
break;
504
505
case SP_INT:
506
remove_interupt_event();
507
sp_register.sp_status_reg |= 0x203;
508
// sp_register.sp_status_reg |= 0x303;
509
510
if (!(sp_register.sp_status_reg & 0x40)) return; // !intr_on_break
511
MI_register.mi_intr_reg |= 0x01;
512
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
513
Cause = (Cause | 0x400) & 0xFFFFFF83;
514
else
515
return;
516
if ((Status & 7) != 1) return;
517
if (!(Status & Cause & 0xFF00)) return;
518
break;
519
520
case DP_INT:
521
remove_interupt_event();
522
dpc_register.dpc_status &= ~2;
523
dpc_register.dpc_status |= 0x81;
524
MI_register.mi_intr_reg |= 0x20;
525
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
526
Cause = (Cause | 0x400) & 0xFFFFFF83;
527
else
528
return;
529
if ((Status & 7) != 1) return;
530
if (!(Status & Cause & 0xFF00)) return;
531
break;
532
533
case HW2_INT:
534
// Hardware Interrupt 2 -- remove interrupt event from queue
535
remove_interupt_event();
536
// setup r4300 Status flags: reset TS, and SR, set IM2
537
Status = (Status & ~0x00380000) | 0x1000;
538
Cause = (Cause | 0x1000) & 0xFFFFFF83;
539
/* the exception_general() call below will jump to the interrupt vector (0x80000180) and setup the
540
* interpreter or dynarec
541
*/
542
break;
543
544
case NMI_INT:
545
// Non Maskable Interrupt -- remove interrupt event from queue
546
remove_interupt_event();
547
// setup r4300 Status flags: reset TS and SR, set BEV, ERL, and SR
548
Status = (Status & ~0x00380000) | 0x00500004;
549
Cause = 0x00000000;
550
// simulate the soft reset code which would run from the PIF ROM
551
r4300_reset_soft();
552
// clear all interrupts, reset interrupt counters back to 0
553
Count = 0;
554
vi_counter = 0;
555
init_interupt();
556
// clear the audio status register so that subsequent write_ai() calls will work properly
557
ai_register.ai_status = 0;
558
// set ErrorEPC with the last instruction address
559
ErrorEPC = PC->addr;
560
// reset the r4300 internal state
561
if (r4300emu != CORE_PURE_INTERPRETER)
562
{
563
// clear all the compiled instruction blocks and re-initialize
564
free_blocks();
565
init_blocks();
566
}
567
// adjust ErrorEPC if we were in a delay slot, and clear the delay_slot and dyna_interp flags
568
if(delay_slot==1 || delay_slot==3)
569
{
570
ErrorEPC-=4;
571
}
572
delay_slot = 0;
573
dyna_interp = 0;
574
// set next instruction address to reset vector
575
last_addr = 0xa4000040;
576
generic_jump_to(0xa4000040);
577
return;
578
579
default:
580
DebugMessage(M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", q->type);
581
remove_interupt_event();
582
break;
583
}
584
585
#ifdef NEW_DYNAREC
586
if (r4300emu == CORE_DYNAREC) {
587
EPC = pcaddr;
588
pcaddr = 0x80000180;
589
Status |= 2;
590
Cause &= 0x7FFFFFFF;
591
pending_exception=1;
592
} else {
593
exception_general();
594
}
595
#else
596
exception_general();
597
#endif
598
599
if (!interupt_unsafe_state)
600
{
601
if (savestates_get_job() == savestates_job_save)
602
{
603
savestates_save();
604
return;
605
}
606
}
607
}
608
609
610