ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / mupen64plus-core / src / r4300 / interupt.c
CommitLineData
451ab91e 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
50unsigned int next_vi;
51int vi_field=0;
52static int vi_counter=0;
53
54int interupt_unsafe_state = 0;
55
56typedef struct _interupt_queue
57{
58 int type;
59 unsigned int count;
60 struct _interupt_queue *next;
61} interupt_queue;
62
63static interupt_queue *q = NULL;
64
65static 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
88static int SPECIAL_done = 0;
89
90static 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
119void 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)) {
3c86bdb6 129 //DebugMessage(M64MSG_WARNING, "two events of type 0x%x in interrupt queue", type);
130 return; // silently return...
451ab91e 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
181void add_interupt_event_count(int type, unsigned int count)
182{
183 add_interupt_event(type, (count - Count)/*/2*/);
184}
185
186static 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
198unsigned 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
211int get_next_event_type(void)
212{
213 if (q == NULL) return 0;
214 return q->type;
215}
216
217void 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
238void 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
253int 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
273void 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
286void 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
297void 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
325void 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 SDL_PumpEvents();
400#ifdef WITH_LIRC
401 lircCheckInput();
402#endif //WITH_LIRC
403 }
404 }
405
406 new_vi();
407 if (vi_register.vi_v_sync == 0) vi_register.vi_delay = 500000;
408 else vi_register.vi_delay = ((vi_register.vi_v_sync + 1)*1500);
409 next_vi += vi_register.vi_delay;
410 if (vi_register.vi_status&0x40) vi_field=1-vi_field;
411 else vi_field=0;
412
413 remove_interupt_event();
414 add_interupt_event_count(VI_INT, next_vi);
415
416 MI_register.mi_intr_reg |= 0x08;
417 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
418 Cause = (Cause | 0x400) & 0xFFFFFF83;
419 else
420 return;
421 if ((Status & 7) != 1) return;
422 if (!(Status & Cause & 0xFF00)) return;
423 break;
424
425 case COMPARE_INT:
426 remove_interupt_event();
2d262872 427 Count+=count_per_op;
451ab91e 428 add_interupt_event_count(COMPARE_INT, Compare);
2d262872 429 Count-=count_per_op;
451ab91e 430
431 Cause = (Cause | 0x8000) & 0xFFFFFF83;
432 if ((Status & 7) != 1) return;
433 if (!(Status & Cause & 0xFF00)) return;
434 break;
435
436 case CHECK_INT:
437 remove_interupt_event();
438 break;
439
440 case SI_INT:
441#ifdef WITH_LIRC
442 lircCheckInput();
443#endif //WITH_LIRC
444 SDL_PumpEvents();
445 PIF_RAMb[0x3F] = 0x0;
446 remove_interupt_event();
447 MI_register.mi_intr_reg |= 0x02;
448 si_register.si_stat |= 0x1000;
449 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
450 Cause = (Cause | 0x400) & 0xFFFFFF83;
451 else
452 return;
453 if ((Status & 7) != 1) return;
454 if (!(Status & Cause & 0xFF00)) return;
455 break;
456
457 case PI_INT:
458 remove_interupt_event();
459 MI_register.mi_intr_reg |= 0x10;
460 pi_register.read_pi_status_reg &= ~3;
461 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
462 Cause = (Cause | 0x400) & 0xFFFFFF83;
463 else
464 return;
465 if ((Status & 7) != 1) return;
466 if (!(Status & Cause & 0xFF00)) return;
467 break;
468
469 case AI_INT:
470 if (ai_register.ai_status & 0x80000000) // full
471 {
472 unsigned int ai_event = get_event(AI_INT);
473 remove_interupt_event();
474 ai_register.ai_status &= ~0x80000000;
475 ai_register.current_delay = ai_register.next_delay;
476 ai_register.current_len = ai_register.next_len;
477 add_interupt_event_count(AI_INT, ai_event+ai_register.next_delay);
478
479 MI_register.mi_intr_reg |= 0x04;
480 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
481 Cause = (Cause | 0x400) & 0xFFFFFF83;
482 else
483 return;
484 if ((Status & 7) != 1) return;
485 if (!(Status & Cause & 0xFF00)) return;
486 }
487 else
488 {
489 remove_interupt_event();
490 ai_register.ai_status &= ~0x40000000;
491
492 //-------
493 MI_register.mi_intr_reg |= 0x04;
494 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
495 Cause = (Cause | 0x400) & 0xFFFFFF83;
496 else
497 return;
498 if ((Status & 7) != 1) return;
499 if (!(Status & Cause & 0xFF00)) return;
500 }
501 break;
502
503 case SP_INT:
504 remove_interupt_event();
505 sp_register.sp_status_reg |= 0x203;
506 // sp_register.sp_status_reg |= 0x303;
507
508 if (!(sp_register.sp_status_reg & 0x40)) return; // !intr_on_break
509 MI_register.mi_intr_reg |= 0x01;
510 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
511 Cause = (Cause | 0x400) & 0xFFFFFF83;
512 else
513 return;
514 if ((Status & 7) != 1) return;
515 if (!(Status & Cause & 0xFF00)) return;
516 break;
517
518 case DP_INT:
519 remove_interupt_event();
520 dpc_register.dpc_status &= ~2;
521 dpc_register.dpc_status |= 0x81;
522 MI_register.mi_intr_reg |= 0x20;
523 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
524 Cause = (Cause | 0x400) & 0xFFFFFF83;
525 else
526 return;
527 if ((Status & 7) != 1) return;
528 if (!(Status & Cause & 0xFF00)) return;
529 break;
530
531 case HW2_INT:
532 // Hardware Interrupt 2 -- remove interrupt event from queue
533 remove_interupt_event();
534 // setup r4300 Status flags: reset TS, and SR, set IM2
535 Status = (Status & ~0x00380000) | 0x1000;
536 Cause = (Cause | 0x1000) & 0xFFFFFF83;
537 /* the exception_general() call below will jump to the interrupt vector (0x80000180) and setup the
538 * interpreter or dynarec
539 */
540 break;
541
542 case NMI_INT:
543 // Non Maskable Interrupt -- remove interrupt event from queue
544 remove_interupt_event();
545 // setup r4300 Status flags: reset TS and SR, set BEV, ERL, and SR
546 Status = (Status & ~0x00380000) | 0x00500004;
547 Cause = 0x00000000;
548 // simulate the soft reset code which would run from the PIF ROM
549 r4300_reset_soft();
550 // clear all interrupts, reset interrupt counters back to 0
551 Count = 0;
552 vi_counter = 0;
553 init_interupt();
554 // clear the audio status register so that subsequent write_ai() calls will work properly
555 ai_register.ai_status = 0;
556 // set ErrorEPC with the last instruction address
557 ErrorEPC = PC->addr;
558 // reset the r4300 internal state
559 if (r4300emu != CORE_PURE_INTERPRETER)
560 {
561 // clear all the compiled instruction blocks and re-initialize
562 free_blocks();
563 init_blocks();
564 }
565 // adjust ErrorEPC if we were in a delay slot, and clear the delay_slot and dyna_interp flags
566 if(delay_slot==1 || delay_slot==3)
567 {
568 ErrorEPC-=4;
569 }
570 delay_slot = 0;
571 dyna_interp = 0;
572 // set next instruction address to reset vector
573 last_addr = 0xa4000040;
574 generic_jump_to(0xa4000040);
575 return;
576
577 default:
578 DebugMessage(M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", q->type);
579 remove_interupt_event();
580 break;
581 }
582
583#ifdef NEW_DYNAREC
584 if (r4300emu == CORE_DYNAREC) {
585 EPC = pcaddr;
586 pcaddr = 0x80000180;
587 Status |= 2;
588 Cause &= 0x7FFFFFFF;
589 pending_exception=1;
590 } else {
591 exception_general();
592 }
593#else
594 exception_general();
595#endif
596
597 if (!interupt_unsafe_state)
598 {
599 if (savestates_get_job() == savestates_job_save)
600 {
601 savestates_save();
602 return;
603 }
604 }
605}
606