@@ -38,25 +38,31 @@ SOFTWARE.
3838
3939static int s_IRQsAutoAck [11 ];
4040
41+ #if 0
4142static __attribute__((section (".ramtext" ))) int IRQVerifier (void ) {
42- // The original code does read IMASK and IREG for every if,
43- // and recompute that same mask for every of them, which is
44- // a big waste of cycles. Since IMASK and IREG are volatiles,
45- // they can't be cached by the compiler, if this is what the
46- // original author was thinking.
47- uint32_t mask = IMASK & IREG ;
48- if ((mask & IRQ_CDROM ) != 0 ) deliverEvent (EVENT_CDROM , 0x1000 );
49- if ((mask & IRQ_SPU ) != 0 ) deliverEvent (EVENT_SPU , 0x1000 );
50- if ((mask & IRQ_GPU ) != 0 ) deliverEvent (EVENT_GPU , 0x1000 );
51- if ((mask & IRQ_PIO ) != 0 ) deliverEvent (EVENT_PIO , 0x1000 );
52- if ((mask & IRQ_SIO ) != 0 ) deliverEvent (EVENT_SIO , 0x1000 );
53- if ((mask & IRQ_VBLANK ) != 0 ) deliverEvent (EVENT_VBLANK , 0x1000 );
54- if ((mask & IRQ_TIMER0 ) != 0 ) deliverEvent (EVENT_RTC0 , 0x1000 );
55- if ((mask & IRQ_TIMER1 ) != 0 )
56- deliverEvent (EVENT_RTC1 , 0x1000 ); // Yes that's a copy-paste mistake from the BIOS code directly.
57- if ((mask & IRQ_TIMER2 ) != 0 ) deliverEvent (EVENT_RTC1 , 0x1000 ); // Keeping it this way to avoid breaking stuff.
58- if ((mask & IRQ_CONTROLLER ) != 0 ) deliverEvent (EVENT_CONTROLLER , 0x1000 );
59- if ((mask & IRQ_DMA ) != 0 ) deliverEvent (EVENT_DMA , 0x1000 );
43+ // This is the original code from the retail BIOS, which is broken
44+ // beyond repair. There is a race condition between the IRQs being
45+ // checked and the IRQs being acknowledged. If an IRQ is issued
46+ // after the IRQ is checked to call the event delivery, but before
47+ // the IRQ is acknowledged, the IRQ will be lost. Disabling IRQs
48+ // with cop0 will not help, as it merely prevents the CPU from
49+ // jumping to the handler at 0x80, but the IREG register will still
50+ // be mutated by the hardware. The only way to fix this is to
51+ // acknowledge the IRQs during the same if statement that checks
52+ // for them, which is what the code after the #else does.
53+ // This defunct code is kept here for reference.
54+ if ((IMASK & IREG & IRQ_CDROM ) != 0 ) deliverEvent (EVENT_CDROM , 0x1000 );
55+ if ((IMASK & IREG & IRQ_SPU ) != 0 ) deliverEvent (EVENT_SPU , 0x1000 );
56+ if ((IMASK & IREG & IRQ_GPU ) != 0 ) deliverEvent (EVENT_GPU , 0x1000 );
57+ if ((IMASK & IREG & IRQ_PIO ) != 0 ) deliverEvent (EVENT_PIO , 0x1000 );
58+ if ((IMASK & IREG & IRQ_SIO ) != 0 ) deliverEvent (EVENT_SIO , 0x1000 );
59+ if ((IMASK & IREG & IRQ_VBLANK ) != 0 ) deliverEvent (EVENT_VBLANK , 0x1000 );
60+ if ((IMASK & IREG & IRQ_TIMER0 ) != 0 ) deliverEvent (EVENT_RTC0 , 0x1000 );
61+ if ((IMASK & IREG & IRQ_TIMER1 ) != 0 ) deliverEvent (EVENT_RTC1 , 0x1000 );
62+ // Yes that's a copy-paste mistake from the BIOS code directly.
63+ if ((IMASK & IREG & IRQ_TIMER2 ) != 0 ) deliverEvent (EVENT_RTC1 , 0x1000 );
64+ if ((IMASK & IREG & IRQ_CONTROLLER ) != 0 ) deliverEvent (EVENT_CONTROLLER , 0x1000 );
65+ if ((IMASK & IREG & IRQ_DMA ) != 0 ) deliverEvent (EVENT_DMA , 0x1000 );
6066 uint32_t ackMask = 0 ;
6167 int * ptr = s_IRQsAutoAck ;
6268 for (int IRQ = 0 ; IRQ < 11 ; IRQ ++ , ptr ++ ) {
@@ -65,6 +71,58 @@ static __attribute__((section(".ramtext"))) int IRQVerifier(void) {
6571 IREG = ~ackMask ;
6672 return 0 ;
6773}
74+ #else
75+ static __attribute__((section (".ramtext" ))) int IRQVerifier (void ) {
76+ // This version of the IRQ verifier is a bit bigger, but it's
77+ // guaranteed to not lose any IRQs.
78+ if ((IMASK & IREG & IRQ_CDROM ) != 0 ) {
79+ deliverEvent (EVENT_CDROM , 0x1000 );
80+ if (s_IRQsAutoAck [IRQ_CDROM ]) IREG &= ~IRQ_CDROM ;
81+ }
82+ if ((IMASK & IREG & IRQ_SPU ) != 0 ) {
83+ deliverEvent (EVENT_SPU , 0x1000 );
84+ if (s_IRQsAutoAck [IRQ_SPU ]) IREG &= ~IRQ_SPU ;
85+ }
86+ if ((IMASK & IREG & IRQ_GPU ) != 0 ) {
87+ deliverEvent (EVENT_GPU , 0x1000 );
88+ if (s_IRQsAutoAck [IRQ_GPU ]) IREG &= ~IRQ_GPU ;
89+ }
90+ if ((IMASK & IREG & IRQ_PIO ) != 0 ) {
91+ deliverEvent (EVENT_PIO , 0x1000 );
92+ if (s_IRQsAutoAck [IRQ_PIO ]) IREG &= ~IRQ_PIO ;
93+ }
94+ if ((IMASK & IREG & IRQ_SIO ) != 0 ) {
95+ deliverEvent (EVENT_SIO , 0x1000 );
96+ if (s_IRQsAutoAck [IRQ_SIO ]) IREG &= ~IRQ_SIO ;
97+ }
98+ if ((IMASK & IREG & IRQ_VBLANK ) != 0 ) {
99+ deliverEvent (EVENT_VBLANK , 0x1000 );
100+ if (s_IRQsAutoAck [IRQ_VBLANK ]) IREG &= ~IRQ_VBLANK ;
101+ }
102+ if ((IMASK & IREG & IRQ_TIMER0 ) != 0 ) {
103+ deliverEvent (EVENT_RTC0 , 0x1000 );
104+ if (s_IRQsAutoAck [IRQ_TIMER0 ]) IREG &= ~IRQ_TIMER0 ;
105+ }
106+ if ((IMASK & IREG & IRQ_TIMER1 ) != 0 ) {
107+ deliverEvent (EVENT_RTC1 , 0x1000 );
108+ if (s_IRQsAutoAck [IRQ_TIMER1 ]) IREG &= ~IRQ_TIMER1 ;
109+ }
110+ if ((IMASK & IREG & IRQ_TIMER2 ) != 0 ) {
111+ // Keeping this copy/paste mistake this way to avoid breaking stuff.
112+ deliverEvent (EVENT_RTC1 , 0x1000 );
113+ if (s_IRQsAutoAck [IRQ_TIMER2 ]) IREG &= ~IRQ_TIMER2 ;
114+ }
115+ if ((IMASK & IREG & IRQ_CONTROLLER ) != 0 ) {
116+ deliverEvent (EVENT_CONTROLLER , 0x1000 );
117+ if (s_IRQsAutoAck [IRQ_CONTROLLER ]) IREG &= ~IRQ_CONTROLLER ;
118+ }
119+ if ((IMASK & IREG & IRQ_DMA ) != 0 ) {
120+ deliverEvent (EVENT_DMA , 0x1000 );
121+ if (s_IRQsAutoAck [IRQ_DMA ]) IREG &= ~IRQ_DMA ;
122+ }
123+ return 0 ;
124+ }
125+ #endif
68126
69127static struct HandlerInfo s_IRQHandlerInfo = {
70128 .next = NULL ,
0 commit comments