Mupen64launcher: Fixed crash on exit of a game
[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)) {
129 DebugMessage(M64MSG_WARNING, "two events of type 0x%x in interrupt queue", type);
130 }
131
132 if (q == NULL)
133 {
134 q = (interupt_queue *) malloc(sizeof(interupt_queue));
135 q->next = NULL;
136 q->count = count;
137 q->type = type;
138 next_interupt = q->count;
139 //print_queue();
140 return;
141 }
142
143 if(before_event(count, q->count, q->type) && !special)
144 {
145 q = (interupt_queue *) malloc(sizeof(interupt_queue));
146 q->next = aux;
147 q->count = count;
148 q->type = type;
149 next_interupt = q->count;
150 //print_queue();
151 return;
152 }
153
154 while (aux->next != NULL && (!before_event(count, aux->next->count, aux->next->type) || special))
155 aux = aux->next;
156
157 if (aux->next == NULL)
158 {
159 aux->next = (interupt_queue *) malloc(sizeof(interupt_queue));
160 aux = aux->next;
161 aux->next = NULL;
162 aux->count = count;
163 aux->type = type;
164 }
165 else
166 {
167 interupt_queue *aux2;
168 if (type != SPECIAL_INT)
169 while(aux->next != NULL && aux->next->count == count)
170 aux = aux->next;
171 aux2 = aux->next;
172 aux->next = (interupt_queue *) malloc(sizeof(interupt_queue));
173 aux = aux->next;
174 aux->next = aux2;
175 aux->count = count;
176 aux->type = type;
177 }
178}
179
180void add_interupt_event_count(int type, unsigned int count)
181{
182 add_interupt_event(type, (count - Count)/*/2*/);
183}
184
185static void remove_interupt_event(void)
186{
187 interupt_queue *aux = q->next;
188 if(q->type == SPECIAL_INT) SPECIAL_done = 1;
189 free(q);
190 q = aux;
191 if (q != NULL && (q->count > Count || (Count - q->count) < 0x80000000))
192 next_interupt = q->count;
193 else
194 next_interupt = 0;
195}
196
197unsigned int get_event(int type)
198{
199 interupt_queue *aux = q;
200 if (q == NULL) return 0;
201 if (q->type == type)
202 return q->count;
203 while (aux->next != NULL && aux->next->type != type)
204 aux = aux->next;
205 if (aux->next != NULL)
206 return aux->next->count;
207 return 0;
208}
209
210int get_next_event_type(void)
211{
212 if (q == NULL) return 0;
213 return q->type;
214}
215
216void remove_event(int type)
217{
218 interupt_queue *aux = q;
219 if (q == NULL) return;
220 if (q->type == type)
221 {
222 aux = aux->next;
223 free(q);
224 q = aux;
225 return;
226 }
227 while (aux->next != NULL && aux->next->type != type)
228 aux = aux->next;
229 if (aux->next != NULL) // it's a type int
230 {
231 interupt_queue *aux2 = aux->next->next;
232 free(aux->next);
233 aux->next = aux2;
234 }
235}
236
237void translate_event_queue(unsigned int base)
238{
239 interupt_queue *aux;
240 remove_event(COMPARE_INT);
241 remove_event(SPECIAL_INT);
242 aux=q;
243 while (aux != NULL)
244 {
245 aux->count = (aux->count - Count)+base;
246 aux = aux->next;
247 }
248 add_interupt_event_count(COMPARE_INT, Compare);
249 add_interupt_event_count(SPECIAL_INT, 0);
250}
251
252int save_eventqueue_infos(char *buf)
253{
254 int len = 0;
255 interupt_queue *aux = q;
256 if (q == NULL)
257 {
258 *((unsigned int*)&buf[0]) = 0xFFFFFFFF;
259 return 4;
260 }
261 while (aux != NULL)
262 {
263 memcpy(buf+len , &aux->type , 4);
264 memcpy(buf+len+4, &aux->count, 4);
265 len += 8;
266 aux = aux->next;
267 }
268 *((unsigned int*)&buf[len]) = 0xFFFFFFFF;
269 return len+4;
270}
271
272void load_eventqueue_infos(char *buf)
273{
274 int len = 0;
275 clear_queue();
276 while (*((unsigned int*)&buf[len]) != 0xFFFFFFFF)
277 {
278 int type = *((unsigned int*)&buf[len]);
279 unsigned int count = *((unsigned int*)&buf[len+4]);
280 add_interupt_event_count(type, count);
281 len += 8;
282 }
283}
284
285void init_interupt(void)
286{
287 SPECIAL_done = 1;
288 next_vi = next_interupt = 5000;
289 vi_register.vi_delay = next_vi;
290 vi_field = 0;
291 clear_queue();
292 add_interupt_event_count(VI_INT, next_vi);
293 add_interupt_event_count(SPECIAL_INT, 0);
294}
295
296void check_interupt(void)
297{
298 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
299 Cause = (Cause | 0x400) & 0xFFFFFF83;
300 else
301 Cause &= ~0x400;
302 if ((Status & 7) != 1) return;
303 if (Status & Cause & 0xFF00)
304 {
305 if(q == NULL)
306 {
307 q = (interupt_queue *) malloc(sizeof(interupt_queue));
308 q->next = NULL;
309 q->count = Count;
310 q->type = CHECK_INT;
311 }
312 else
313 {
314 interupt_queue* aux = (interupt_queue *) malloc(sizeof(interupt_queue));
315 aux->next = q;
316 aux->count = Count;
317 aux->type = CHECK_INT;
318 q = aux;
319 }
320 next_interupt = Count;
321 }
322}
323
324void gen_interupt(void)
325{
326 if (stop == 1)
327 {
328 vi_counter = 0; // debug
329 dyna_stop();
330 }
331
332 if (!interupt_unsafe_state)
333 {
334 if (savestates_get_job() == savestates_job_load)
335 {
336 savestates_load();
337 return;
338 }
339
340 if (reset_hard_job)
341 {
342 reset_hard();
343 reset_hard_job = 0;
344 return;
345 }
346 }
347
348 if (skip_jump)
349 {
350 unsigned int dest = skip_jump;
351 skip_jump = 0;
352
353 if (q->count > Count || (Count - q->count) < 0x80000000)
354 next_interupt = q->count;
355 else
356 next_interupt = 0;
357
358 last_addr = dest;
359 generic_jump_to(dest);
360 return;
361 }
362
363 switch(q->type)
364 {
365 case SPECIAL_INT:
366 if (Count > 0x10000000) return;
367 remove_interupt_event();
368 add_interupt_event_count(SPECIAL_INT, 0);
369 return;
370 break;
371 case VI_INT:
372 if(vi_counter < 60)
373 {
374 if (vi_counter == 0)
375 cheat_apply_cheats(ENTRY_BOOT);
376 vi_counter++;
377 }
378 else
379 {
380 cheat_apply_cheats(ENTRY_VI);
381 }
382 gfx.updateScreen();
383#ifdef WITH_LIRC
384 lircCheckInput();
385#endif
386 SDL_PumpEvents();
387
388 refresh_stat();
389
390 // if paused, poll for input events
391 if(rompause)
392 {
393 osd_render(); // draw Paused message in case gfx.updateScreen didn't do it
394 VidExt_GL_SwapBuffers();
395 while(rompause)
396 {
397 SDL_Delay(10);
398 SDL_PumpEvents();
399#ifdef WITH_LIRC
400 lircCheckInput();
401#endif //WITH_LIRC
402 }
403 }
404
405 new_vi();
406 if (vi_register.vi_v_sync == 0) vi_register.vi_delay = 500000;
407 else vi_register.vi_delay = ((vi_register.vi_v_sync + 1)*1500);
408 next_vi += vi_register.vi_delay;
409 if (vi_register.vi_status&0x40) vi_field=1-vi_field;
410 else vi_field=0;
411
412 remove_interupt_event();
413 add_interupt_event_count(VI_INT, next_vi);
414
415 MI_register.mi_intr_reg |= 0x08;
416 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
417 Cause = (Cause | 0x400) & 0xFFFFFF83;
418 else
419 return;
420 if ((Status & 7) != 1) return;
421 if (!(Status & Cause & 0xFF00)) return;
422 break;
423
424 case COMPARE_INT:
425 remove_interupt_event();
426 Count+=2;
427 add_interupt_event_count(COMPARE_INT, Compare);
428 Count-=2;
429
430 Cause = (Cause | 0x8000) & 0xFFFFFF83;
431 if ((Status & 7) != 1) return;
432 if (!(Status & Cause & 0xFF00)) return;
433 break;
434
435 case CHECK_INT:
436 remove_interupt_event();
437 break;
438
439 case SI_INT:
440#ifdef WITH_LIRC
441 lircCheckInput();
442#endif //WITH_LIRC
443 SDL_PumpEvents();
444 PIF_RAMb[0x3F] = 0x0;
445 remove_interupt_event();
446 MI_register.mi_intr_reg |= 0x02;
447 si_register.si_stat |= 0x1000;
448 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
449 Cause = (Cause | 0x400) & 0xFFFFFF83;
450 else
451 return;
452 if ((Status & 7) != 1) return;
453 if (!(Status & Cause & 0xFF00)) return;
454 break;
455
456 case PI_INT:
457 remove_interupt_event();
458 MI_register.mi_intr_reg |= 0x10;
459 pi_register.read_pi_status_reg &= ~3;
460 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
461 Cause = (Cause | 0x400) & 0xFFFFFF83;
462 else
463 return;
464 if ((Status & 7) != 1) return;
465 if (!(Status & Cause & 0xFF00)) return;
466 break;
467
468 case AI_INT:
469 if (ai_register.ai_status & 0x80000000) // full
470 {
471 unsigned int ai_event = get_event(AI_INT);
472 remove_interupt_event();
473 ai_register.ai_status &= ~0x80000000;
474 ai_register.current_delay = ai_register.next_delay;
475 ai_register.current_len = ai_register.next_len;
476 add_interupt_event_count(AI_INT, ai_event+ai_register.next_delay);
477
478 MI_register.mi_intr_reg |= 0x04;
479 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
480 Cause = (Cause | 0x400) & 0xFFFFFF83;
481 else
482 return;
483 if ((Status & 7) != 1) return;
484 if (!(Status & Cause & 0xFF00)) return;
485 }
486 else
487 {
488 remove_interupt_event();
489 ai_register.ai_status &= ~0x40000000;
490
491 //-------
492 MI_register.mi_intr_reg |= 0x04;
493 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
494 Cause = (Cause | 0x400) & 0xFFFFFF83;
495 else
496 return;
497 if ((Status & 7) != 1) return;
498 if (!(Status & Cause & 0xFF00)) return;
499 }
500 break;
501
502 case SP_INT:
503 remove_interupt_event();
504 sp_register.sp_status_reg |= 0x203;
505 // sp_register.sp_status_reg |= 0x303;
506
507 if (!(sp_register.sp_status_reg & 0x40)) return; // !intr_on_break
508 MI_register.mi_intr_reg |= 0x01;
509 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
510 Cause = (Cause | 0x400) & 0xFFFFFF83;
511 else
512 return;
513 if ((Status & 7) != 1) return;
514 if (!(Status & Cause & 0xFF00)) return;
515 break;
516
517 case DP_INT:
518 remove_interupt_event();
519 dpc_register.dpc_status &= ~2;
520 dpc_register.dpc_status |= 0x81;
521 MI_register.mi_intr_reg |= 0x20;
522 if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
523 Cause = (Cause | 0x400) & 0xFFFFFF83;
524 else
525 return;
526 if ((Status & 7) != 1) return;
527 if (!(Status & Cause & 0xFF00)) return;
528 break;
529
530 case HW2_INT:
531 // Hardware Interrupt 2 -- remove interrupt event from queue
532 remove_interupt_event();
533 // setup r4300 Status flags: reset TS, and SR, set IM2
534 Status = (Status & ~0x00380000) | 0x1000;
535 Cause = (Cause | 0x1000) & 0xFFFFFF83;
536 /* the exception_general() call below will jump to the interrupt vector (0x80000180) and setup the
537 * interpreter or dynarec
538 */
539 break;
540
541 case NMI_INT:
542 // Non Maskable Interrupt -- remove interrupt event from queue
543 remove_interupt_event();
544 // setup r4300 Status flags: reset TS and SR, set BEV, ERL, and SR
545 Status = (Status & ~0x00380000) | 0x00500004;
546 Cause = 0x00000000;
547 // simulate the soft reset code which would run from the PIF ROM
548 r4300_reset_soft();
549 // clear all interrupts, reset interrupt counters back to 0
550 Count = 0;
551 vi_counter = 0;
552 init_interupt();
553 // clear the audio status register so that subsequent write_ai() calls will work properly
554 ai_register.ai_status = 0;
555 // set ErrorEPC with the last instruction address
556 ErrorEPC = PC->addr;
557 // reset the r4300 internal state
558 if (r4300emu != CORE_PURE_INTERPRETER)
559 {
560 // clear all the compiled instruction blocks and re-initialize
561 free_blocks();
562 init_blocks();
563 }
564 // adjust ErrorEPC if we were in a delay slot, and clear the delay_slot and dyna_interp flags
565 if(delay_slot==1 || delay_slot==3)
566 {
567 ErrorEPC-=4;
568 }
569 delay_slot = 0;
570 dyna_interp = 0;
571 // set next instruction address to reset vector
572 last_addr = 0xa4000040;
573 generic_jump_to(0xa4000040);
574 return;
575
576 default:
577 DebugMessage(M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", q->type);
578 remove_interupt_event();
579 break;
580 }
581
582#ifdef NEW_DYNAREC
583 if (r4300emu == CORE_DYNAREC) {
584 EPC = pcaddr;
585 pcaddr = 0x80000180;
586 Status |= 2;
587 Cause &= 0x7FFFFFFF;
588 pending_exception=1;
589 } else {
590 exception_general();
591 }
592#else
593 exception_general();
594#endif
595
596 if (!interupt_unsafe_state)
597 {
598 if (savestates_get_job() == savestates_job_save)
599 {
600 savestates_save();
601 return;
602 }
603 }
604}
605