Skip to content

Commit a1d2375

Browse files
committed
Merged upstream changes to fix issues with interrupt handling, which results in AI interrupts missing an entire round of the count register
1 parent 193774c commit a1d2375

14 files changed

+188
-127
lines changed

ai/ai_controller.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@ static uint32_t get_remaining_dma_length(struct ai_controller* ai)
5353
if (next_ai_event == 0)
5454
return 0;
5555

56+
if ((int)(ai->r4300->state->g_cp0_regs[CP0_COUNT_REG] - next_ai_event) >= 0)
57+
return 0;
58+
5659
remaining_dma_duration = next_ai_event - ai->r4300->state->g_cp0_regs[CP0_COUNT_REG];
5760

5861
if (remaining_dma_duration >= 0x80000000)
5962
return 0;
6063

61-
return (uint32_t)((uint64_t)remaining_dma_duration * ai->fifo[0].length / ai->fifo[0].duration);
64+
return (uint32_t)((uint64_t)remaining_dma_duration * ai->fifo[0].length / ai->fifo[0].duration) & ~7;
6265
}
6366

6467
static unsigned int get_dma_duration(struct ai_controller* ai)

r4300/cached_interp.c

+8-8
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
update_count(state); \
7777
} \
7878
state->last_addr = state->PC->addr; \
79-
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \
79+
if (state->cycle_count >=0) gen_interupt(state); \
8080
} \
8181
static void osal_fastcall name##_OUT(usf_state_t * state) \
8282
{ \
@@ -108,21 +108,21 @@
108108
update_count(state); \
109109
} \
110110
state->last_addr = state->PC->addr; \
111-
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \
111+
if (state->cycle_count >=0) gen_interupt(state); \
112112
} \
113113
static void osal_fastcall name##_IDLE(usf_state_t * state) \
114114
{ \
115115
const int take_jump = (condition); \
116-
int skip; \
117116
if (cop1 && check_cop1_unusable(state)) return; \
118117
if (take_jump) \
119118
{ \
120-
update_count(state); \
121-
skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \
122-
if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \
123-
else name(state); \
119+
if (state->cycle_count < 0) \
120+
{ \
121+
state->g_cp0_regs[CP0_COUNT_REG] -= state->cycle_count; \
122+
state->cycle_count = 0; \
123+
} \
124124
} \
125-
else name(state); \
125+
name(state); \
126126
}
127127

128128
#define CHECK_MEMORY() \

r4300/cp0.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ void update_count(usf_state_t * state)
5656
if (r4300emu != CORE_DYNAREC)
5757
{
5858
#endif
59-
state->g_cp0_regs[CP0_COUNT_REG] += ((state->PC->addr - state->last_addr) >> 2) * state->count_per_op;
59+
uint32_t count = ((state->PC->addr - state->last_addr) >> 2) * state->count_per_op;
60+
state->g_cp0_regs[CP0_COUNT_REG] += count;
61+
state->cycle_count += count;
6062
state->last_addr = state->PC->addr;
6163
#ifdef NEW_DYNAREC
6264
}

r4300/interpreter_cop0.def

+10-3
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ DECLARE_INSTRUCTION(MTC0)
7171
case CP0_COUNT_REG:
7272
update_count(state);
7373
state->interupt_unsafe_state = 1;
74-
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state);
74+
if (state->cycle_count >= 0) gen_interupt(state);
7575
state->interupt_unsafe_state = 0;
7676
translate_event_queue(state, (unsigned int) rrt & 0xFFFFFFFF);
7777
state->g_cp0_regs[CP0_COUNT_REG] = (unsigned int) rrt & 0xFFFFFFFF;
@@ -82,7 +82,14 @@ DECLARE_INSTRUCTION(MTC0)
8282
case CP0_COMPARE_REG:
8383
update_count(state);
8484
remove_event(state, COMPARE_INT);
85-
add_interupt_event_count(state, COMPARE_INT, (unsigned int)rrt);
85+
/* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
86+
state->g_cp0_regs[CP0_COUNT_REG] += state->count_per_op;
87+
state->cycle_count += state->count_per_op;
88+
add_interupt_event_count(state, COMPARE_INT, rrt);
89+
state->g_cp0_regs[CP0_COUNT_REG] -= state->count_per_op;
90+
91+
/* Update next interrupt in case first event is COMPARE_INT */
92+
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
8693
state->g_cp0_regs[CP0_COMPARE_REG] = (unsigned int) rrt;
8794
state->g_cp0_regs[CP0_CAUSE_REG] &= 0xFFFF7FFF; //Timer interupt is clear
8895
break;
@@ -97,7 +104,7 @@ DECLARE_INSTRUCTION(MTC0)
97104
ADD_TO_PC(1);
98105
check_interupt(state);
99106
state->interupt_unsafe_state = 1;
100-
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state);
107+
if (state->cycle_count >= 0) gen_interupt(state);
101108
state->interupt_unsafe_state = 0;
102109
ADD_TO_PC(-1);
103110
break;

r4300/interpreter_tlb.def

+1-1
Original file line numberDiff line numberDiff line change
@@ -246,5 +246,5 @@ DECLARE_INSTRUCTION(ERET)
246246
state->llbit = 0;
247247
check_interupt(state);
248248
state->last_addr = PCADDR;
249-
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state);
249+
if (state->cycle_count >= 0) gen_interupt(state);
250250
}

r4300/interupt.c

+42-50
Original file line numberDiff line numberDiff line change
@@ -131,30 +131,12 @@ static void clear_queue(usf_state_t * state)
131131

132132
static int before_event(usf_state_t * state, unsigned int evt1, unsigned int evt2, int type2)
133133
{
134-
if(evt1 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000)
135-
{
136-
if(evt2 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000)
137-
{
138-
if((evt1 - state->g_cp0_regs[CP0_COUNT_REG]) < (evt2 - state->g_cp0_regs[CP0_COUNT_REG])) return 1;
139-
else return 0;
140-
}
141-
else
142-
{
143-
if((state->g_cp0_regs[CP0_COUNT_REG] - evt2) < 0x10000000)
144-
{
145-
switch(type2)
146-
{
147-
case SPECIAL_INT:
148-
if(state->SPECIAL_done) return 1;
149-
else return 0;
150-
break;
151-
default:
152-
return 0;
153-
}
154-
}
155-
else return 1;
156-
}
157-
}
134+
int count = state->g_cp0_regs[CP0_COUNT_REG];
135+
136+
if (state->cycle_count > 0)
137+
count -= state->cycle_count;
138+
139+
if ((evt1 - count) < (evt2 - count)) return 1;
158140
else return 0;
159141
}
160142

@@ -167,19 +149,9 @@ void add_interupt_event_count(usf_state_t * state, int type, unsigned int count)
167149
{
168150
struct node* event;
169151
struct node* e;
170-
int special;
171-
172-
special = (type == SPECIAL_INT);
173-
174-
if(state->g_cp0_regs[CP0_COUNT_REG] > 0x80000000) state->SPECIAL_done = 0;
175152

176153
if (get_event(state, type)) {
177154
DebugMessage(state, M64MSG_WARNING, "two events of type 0x%x in interrupt queue", type);
178-
/* FIXME: hack-fix for freezing in Perfect Dark
179-
* http://code.google.com/p/mupen64plus/issues/detail?id=553
180-
* https://github.com/mupen64plus-ae/mupen64plus-ae/commit/802d8f81d46705d64694d7a34010dc5f35787c7d
181-
*/
182-
return;
183155
}
184156

185157
event = alloc_node(&state->q.pool);
@@ -197,18 +169,20 @@ void add_interupt_event_count(usf_state_t * state, int type, unsigned int count)
197169
state->q.first = event;
198170
event->next = NULL;
199171
state->next_interupt = state->q.first->data.count;
172+
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
200173
}
201-
else if (before_event(state, count, state->q.first->data.count, state->q.first->data.type) && !special)
174+
else if (before_event(state, count, state->q.first->data.count, state->q.first->data.type))
202175
{
203176
event->next = state->q.first;
204177
state->q.first = event;
205178
state->next_interupt = state->q.first->data.count;
179+
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
206180
}
207181
else
208182
{
209183
for(e = state->q.first;
210184
e->next != NULL &&
211-
(!before_event(state, count, e->next->data.count, e->next->data.type) || special);
185+
(!before_event(state, count, e->next->data.count, e->next->data.type));
212186
e = e->next);
213187

214188
if (e->next == NULL)
@@ -218,8 +192,7 @@ void add_interupt_event_count(usf_state_t * state, int type, unsigned int count)
218192
}
219193
else
220194
{
221-
if (!special)
222-
for(; e->next != NULL && e->next->data.count == count; e = e->next);
195+
for(; e->next != NULL && e->next->data.count == count; e = e->next);
223196

224197
event->next = e->next;
225198
e->next = event;
@@ -235,11 +208,13 @@ static void remove_interupt_event(usf_state_t * state)
235208
state->q.first = e->next;
236209
free_node(&state->q.pool, e);
237210

238-
state->next_interupt = (state->q.first != NULL
239-
&& (state->q.first->data.count > state->g_cp0_regs[CP0_COUNT_REG]
240-
|| (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count) < 0x80000000))
211+
state->next_interupt = (state->q.first != NULL)
241212
? state->q.first->data.count
242213
: 0;
214+
215+
state->cycle_count = (state->q.first != NULL)
216+
? (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count)
217+
: 0;
243218
}
244219

245220
unsigned int get_event(usf_state_t * state, int type)
@@ -303,8 +278,18 @@ void translate_event_queue(usf_state_t * state, unsigned int base)
303278
{
304279
e->data.count = (e->data.count - state->g_cp0_regs[CP0_COUNT_REG]) + base;
305280
}
281+
282+
state->g_cp0_regs[CP0_COUNT_REG] = base;
283+
add_interupt_event_count(state, SPECIAL_INT, ((state->g_cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000)));
284+
285+
/* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
286+
state->g_cp0_regs[CP0_COUNT_REG] += state->count_per_op;
287+
state->cycle_count += state->count_per_op;
306288
add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]);
307-
add_interupt_event_count(state, SPECIAL_INT, 0);
289+
state->g_cp0_regs[CP0_COUNT_REG] -= state->count_per_op;
290+
291+
/* Update next interrupt in case first event is COMPARE_INT */
292+
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
308293
}
309294

310295
int save_eventqueue_infos(usf_state_t * state, char *buf)
@@ -336,6 +321,8 @@ void load_eventqueue_infos(usf_state_t * state, char *buf)
336321
add_interupt_event_count(state, type, count);
337322
len += 8;
338323
}
324+
remove_event(state, SPECIAL_INT);
325+
add_interupt_event_count(state, SPECIAL_INT, ((state->g_cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000)));
339326
}
340327

341328
void init_interupt(usf_state_t * state)
@@ -346,7 +333,8 @@ void init_interupt(usf_state_t * state)
346333

347334
clear_queue(state);
348335
add_interupt_event_count(state, VI_INT, state->g_vi.next_vi);
349-
add_interupt_event_count(state, SPECIAL_INT, 0);
336+
add_interrupt_event_count(state, SPECIAL_INT, 0x80000000);
337+
add_interupt_event_count(state, COMPARE_INT, 0);
350338
}
351339

352340
void check_interupt(usf_state_t * state)
@@ -389,6 +377,7 @@ void check_interupt(usf_state_t * state)
389377

390378
event->data.count = state->next_interupt = state->g_cp0_regs[CP0_COUNT_REG];
391379
event->data.type = CHECK_INT;
380+
state->cycle_count = 0;
392381

393382
if (state->q.first == NULL)
394383
{
@@ -435,21 +424,21 @@ void raise_maskable_interrupt(usf_state_t * state, uint32_t cause)
435424

436425
static void special_int_handler(usf_state_t * state)
437426
{
438-
if (state->g_cp0_regs[CP0_COUNT_REG] > 0x10000000)
439-
return;
440-
441-
state->SPECIAL_done = 1;
442427
remove_interupt_event(state);
443-
add_interupt_event_count(state, SPECIAL_INT, 0);
428+
add_interupt_event_count(state, SPECIAL_INT, ((state->g_cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000)));
444429
}
445430

446431
static void compare_int_handler(usf_state_t * state)
447432
{
448433
remove_interupt_event(state);
449434
state->g_cp0_regs[CP0_COUNT_REG]+=state->count_per_op;
435+
state->cycle_count += state->count_per_op;
450436
add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]);
451437
state->g_cp0_regs[CP0_COUNT_REG]-=state->count_per_op;
452438

439+
/* Update next interrupt in case first event is COMPARE_INT */
440+
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
441+
453442
if (state->enablecompare)
454443
raise_maskable_interrupt(state, 0x8000);
455444
}
@@ -525,11 +514,14 @@ void osal_fastcall gen_interupt(usf_state_t * state)
525514
unsigned int dest = state->skip_jump;
526515
state->skip_jump = 0;
527516

528-
state->next_interupt = (state->q.first->data.count > state->g_cp0_regs[CP0_COUNT_REG]
529-
|| (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count) < 0x80000000)
517+
state->next_interupt = (state->q.first != NULL)
530518
? state->q.first->data.count
531519
: 0;
532520

521+
state->cycle_count = (state->q.first != NULL)
522+
? (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count)
523+
: 0;
524+
533525
state->last_addr = dest;
534526
generic_jump_to(state, dest);
535527
return;

r4300/mi_controller.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ int write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
105105

106106
check_interupt(r4300->state);
107107
update_count(r4300->state);
108-
if (r4300->state->next_interupt <= r4300->state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(r4300->state);
108+
if (r4300->state->cycle_count >= 0) gen_interupt(r4300->state);
109109
break;
110110
}
111111

r4300/pure_interp.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ static void InterpretOpcode(usf_state_t * state);
7676
update_count(state); \
7777
} \
7878
state->last_addr = state->interp_PC.addr; \
79-
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \
79+
if (state->cycle_count >= 0) gen_interupt(state); \
8080
} \
8181
static void name##_IDLE(usf_state_t * state, uint32_t op) \
8282
{ \
@@ -86,11 +86,13 @@ static void InterpretOpcode(usf_state_t * state);
8686
if (take_jump) \
8787
{ \
8888
update_count(state); \
89-
skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \
90-
if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \
91-
else name(state, op); \
89+
if(state->cycle_count < 0) \
90+
{ \
91+
state->g_cp0_regs[CP0_COUNT_REG] -= state->cycle_count; \
92+
state->cycle_count = 0; \
93+
} \
9294
} \
93-
else name(state, op); \
95+
name(state, op); \
9496
}
9597
#define CHECK_MEMORY()
9698

r4300/r4300.c

+2
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ void r4300_reset_hard(usf_state_t * state)
133133
state->g_cp0_regs[CP0_EPC_REG] = 0xFFFFFFFF;
134134
state->g_cp0_regs[CP0_BADVADDR_REG] = 0xFFFFFFFF;
135135
state->g_cp0_regs[CP0_ERROREPC_REG] = 0xFFFFFFFF;
136+
137+
state->cycle_count = 0;
136138

137139
state->rounding_mode = 0x33F;
138140
}

r4300/x86/assemble.h

+25
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ static osal_inline void test_reg32_imm32(usf_state_t * state, int reg32, unsigne
177177
put32(state, imm32);
178178
}
179179

180+
static osal_inline void test_reg32_reg32(usf_state_t * state, int reg1, int reg2)
181+
{
182+
put8(state, 0x85);
183+
put8(state, ((reg2 << 3) | reg1 | 0xC0);
184+
}
185+
180186
static osal_inline void test_m32_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32)
181187
{
182188
put8(state, 0xF7);
@@ -192,6 +198,13 @@ static osal_inline void add_m32_reg32(usf_state_t * state, unsigned int *m32, in
192198
put32(state, (unsigned int)(m32));
193199
}
194200

201+
static osal_inline void sub_m32_reg32(usf_state_t * state, unsigned int *m32, int reg32)
202+
{
203+
put8(state, 0x29);
204+
put8(state, (reg32 << 3) | 5);
205+
put32(state, (unsigned int)(m32));
206+
}
207+
195208
static osal_inline void sub_reg32_m32(usf_state_t * state, int reg32, unsigned int *m32)
196209
{
197210
put8(state, 0x2B);
@@ -290,6 +303,18 @@ static osal_inline void jp_rj(usf_state_t * state, unsigned char saut)
290303
put8(state, saut);
291304
}
292305

306+
static osal_inline void jns_rj(usf_state_t * state, unsigned char saut)
307+
{
308+
put8(state, 0x79);
309+
put8(state, saut);
310+
}
311+
312+
static osal_inline void js_rj(usf_state_t * state, unsigned char saut)
313+
{
314+
put8(state, 0x78);
315+
put8(state, saut);
316+
}
317+
293318
static osal_inline void je_near_rj(usf_state_t * state, unsigned int saut)
294319
{
295320
put8(state, 0x0F);

0 commit comments

Comments
 (0)