@@ -38,25 +38,31 @@ SOFTWARE.
38
38
39
39
static int s_IRQsAutoAck [11 ];
40
40
41
+ #if 0
41
42
static __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 );
60
66
uint32_t ackMask = 0 ;
61
67
int * ptr = s_IRQsAutoAck ;
62
68
for (int IRQ = 0 ; IRQ < 11 ; IRQ ++ , ptr ++ ) {
@@ -65,6 +71,58 @@ static __attribute__((section(".ramtext"))) int IRQVerifier(void) {
65
71
IREG = ~ackMask ;
66
72
return 0 ;
67
73
}
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
68
126
69
127
static struct HandlerInfo s_IRQHandlerInfo = {
70
128
.next = NULL ,
0 commit comments