Updated lazyusf2 with fixes from Josh W for cases where some USF rips would cause the internal counter variable to take a full 32 bit loop before producing more audio, having all the appearances of temporarily locking up

CQTexperiment
Christopher Snowhill 2021-01-06 00:52:09 -08:00
parent 97fee7e486
commit d070dffdbe
18 changed files with 196 additions and 129 deletions

View File

@ -53,12 +53,15 @@ static uint32_t get_remaining_dma_length(struct ai_controller* ai)
if (next_ai_event == 0) if (next_ai_event == 0)
return 0; return 0;
if ((int)(ai->r4300->state->g_cp0_regs[CP0_COUNT_REG] - next_ai_event) >= 0)
return 0;
remaining_dma_duration = next_ai_event - ai->r4300->state->g_cp0_regs[CP0_COUNT_REG]; remaining_dma_duration = next_ai_event - ai->r4300->state->g_cp0_regs[CP0_COUNT_REG];
if (remaining_dma_duration >= 0x80000000) if (remaining_dma_duration >= 0x80000000)
return 0; return 0;
return (uint32_t)((uint64_t)remaining_dma_duration * ai->fifo[0].length / ai->fifo[0].duration); return (uint32_t)((uint64_t)remaining_dma_duration * ai->fifo[0].length / ai->fifo[0].duration) & ~7;
} }
static unsigned int get_dma_duration(struct ai_controller* ai) static unsigned int get_dma_duration(struct ai_controller* ai)

View File

@ -422,6 +422,8 @@ static int savestates_load_pj64(usf_state_t * state, unsigned char * ptr, unsign
load_eventqueue_infos(state, buffer); load_eventqueue_infos(state, buffer);
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
// FPCR // FPCR
state->FCR0 = GETDATA(curr, int); state->FCR0 = GETDATA(curr, int);
curr += 30 * 4; // FCR1...FCR30 not supported curr += 30 * 4; // FCR1...FCR30 not supported

View File

@ -76,7 +76,7 @@
update_count(state); \ update_count(state); \
} \ } \
state->last_addr = state->PC->addr; \ state->last_addr = state->PC->addr; \
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \ if (state->cycle_count >=0) gen_interupt(state); \
} \ } \
static void osal_fastcall name##_OUT(usf_state_t * state) \ static void osal_fastcall name##_OUT(usf_state_t * state) \
{ \ { \
@ -108,21 +108,21 @@
update_count(state); \ update_count(state); \
} \ } \
state->last_addr = state->PC->addr; \ state->last_addr = state->PC->addr; \
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \ if (state->cycle_count >=0) gen_interupt(state); \
} \ } \
static void osal_fastcall name##_IDLE(usf_state_t * state) \ static void osal_fastcall name##_IDLE(usf_state_t * state) \
{ \ { \
const int take_jump = (condition); \ const int take_jump = (condition); \
int skip; \
if (cop1 && check_cop1_unusable(state)) return; \ if (cop1 && check_cop1_unusable(state)) return; \
if (take_jump) \ if (take_jump) \
{ \ { \
update_count(state); \ if (state->cycle_count < 0) \
skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \ { \
if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \ state->g_cp0_regs[CP0_COUNT_REG] -= state->cycle_count; \
else name(state); \ state->cycle_count = 0; \
} \ } \
else name(state); \ } \
name(state); \
} }
#define CHECK_MEMORY() \ #define CHECK_MEMORY() \

View File

@ -56,7 +56,9 @@ void update_count(usf_state_t * state)
if (r4300emu != CORE_DYNAREC) if (r4300emu != CORE_DYNAREC)
{ {
#endif #endif
state->g_cp0_regs[CP0_COUNT_REG] += ((state->PC->addr - state->last_addr) >> 2) * state->count_per_op; uint32_t count = ((state->PC->addr - state->last_addr) >> 2) * state->count_per_op;
state->g_cp0_regs[CP0_COUNT_REG] += count;
state->cycle_count += count;
state->last_addr = state->PC->addr; state->last_addr = state->PC->addr;
#ifdef NEW_DYNAREC #ifdef NEW_DYNAREC
} }

View File

@ -111,6 +111,7 @@ void TLB_refill_exception(usf_state_t * state, unsigned int address, int w)
{ {
state->skip_jump = state->PC->addr; state->skip_jump = state->PC->addr;
state->next_interupt = 0; state->next_interupt = 0;
state->cycle_count = 0;
} }
} }
} }
@ -147,6 +148,7 @@ void osal_fastcall exception_general(usf_state_t * state)
{ {
state->skip_jump = state->PC->addr; state->skip_jump = state->PC->addr;
state->next_interupt = 0; state->next_interupt = 0;
state->cycle_count = 0;
} }
} }
} }

View File

@ -71,7 +71,7 @@ DECLARE_INSTRUCTION(MTC0)
case CP0_COUNT_REG: case CP0_COUNT_REG:
update_count(state); update_count(state);
state->interupt_unsafe_state = 1; state->interupt_unsafe_state = 1;
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); if (state->cycle_count >= 0) gen_interupt(state);
state->interupt_unsafe_state = 0; state->interupt_unsafe_state = 0;
translate_event_queue(state, (unsigned int) rrt & 0xFFFFFFFF); translate_event_queue(state, (unsigned int) rrt & 0xFFFFFFFF);
state->g_cp0_regs[CP0_COUNT_REG] = (unsigned int) rrt & 0xFFFFFFFF; state->g_cp0_regs[CP0_COUNT_REG] = (unsigned int) rrt & 0xFFFFFFFF;
@ -82,7 +82,14 @@ DECLARE_INSTRUCTION(MTC0)
case CP0_COMPARE_REG: case CP0_COMPARE_REG:
update_count(state); update_count(state);
remove_event(state, COMPARE_INT); remove_event(state, COMPARE_INT);
add_interupt_event_count(state, COMPARE_INT, (unsigned int)rrt); /* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
state->g_cp0_regs[CP0_COUNT_REG] += state->count_per_op;
state->cycle_count += state->count_per_op;
add_interupt_event_count(state, COMPARE_INT, rrt);
state->g_cp0_regs[CP0_COUNT_REG] -= state->count_per_op;
/* Update next interrupt in case first event is COMPARE_INT */
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
state->g_cp0_regs[CP0_COMPARE_REG] = (unsigned int) rrt; state->g_cp0_regs[CP0_COMPARE_REG] = (unsigned int) rrt;
state->g_cp0_regs[CP0_CAUSE_REG] &= 0xFFFF7FFF; //Timer interupt is clear state->g_cp0_regs[CP0_CAUSE_REG] &= 0xFFFF7FFF; //Timer interupt is clear
break; break;
@ -97,7 +104,7 @@ DECLARE_INSTRUCTION(MTC0)
ADD_TO_PC(1); ADD_TO_PC(1);
check_interupt(state); check_interupt(state);
state->interupt_unsafe_state = 1; state->interupt_unsafe_state = 1;
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); if (state->cycle_count >= 0) gen_interupt(state);
state->interupt_unsafe_state = 0; state->interupt_unsafe_state = 0;
ADD_TO_PC(-1); ADD_TO_PC(-1);
break; break;

View File

@ -404,5 +404,7 @@ DECLARE_INSTRUCTION(DSRA32)
DECLARE_INSTRUCTION(BREAK) DECLARE_INSTRUCTION(BREAK)
{ {
state->g_cp0_regs[CP0_COUNT_REG] = state->next_interupt; state->g_cp0_regs[CP0_COUNT_REG] = state->next_interupt;
state->cycle_count = 0;
ADD_TO_PC(1); ADD_TO_PC(1);
} }

View File

@ -246,5 +246,5 @@ DECLARE_INSTRUCTION(ERET)
state->llbit = 0; state->llbit = 0;
check_interupt(state); check_interupt(state);
state->last_addr = PCADDR; state->last_addr = PCADDR;
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); if (state->cycle_count >= 0) gen_interupt(state);
} }

View File

@ -131,30 +131,12 @@ static void clear_queue(usf_state_t * state)
static int before_event(usf_state_t * state, unsigned int evt1, unsigned int evt2, int type2) static int before_event(usf_state_t * state, unsigned int evt1, unsigned int evt2, int type2)
{ {
if(evt1 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000) int count = state->g_cp0_regs[CP0_COUNT_REG];
{
if(evt2 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000) if (state->cycle_count > 0)
{ count -= state->cycle_count;
if((evt1 - state->g_cp0_regs[CP0_COUNT_REG]) < (evt2 - state->g_cp0_regs[CP0_COUNT_REG])) return 1;
else return 0; if ((evt1 - count) < (evt2 - count)) return 1;
}
else
{
if((state->g_cp0_regs[CP0_COUNT_REG] - evt2) < 0x10000000)
{
switch(type2)
{
case SPECIAL_INT:
if(state->SPECIAL_done) return 1;
else return 0;
break;
default:
return 0;
}
}
else return 1;
}
}
else return 0; else return 0;
} }
@ -167,19 +149,9 @@ void add_interupt_event_count(usf_state_t * state, int type, unsigned int count)
{ {
struct node* event; struct node* event;
struct node* e; struct node* e;
int special;
special = (type == SPECIAL_INT);
if(state->g_cp0_regs[CP0_COUNT_REG] > 0x80000000) state->SPECIAL_done = 0;
if (get_event(state, type)) { if (get_event(state, type)) {
DebugMessage(state, M64MSG_WARNING, "two events of type 0x%x in interrupt queue", type); DebugMessage(state, M64MSG_WARNING, "two events of type 0x%x in interrupt queue", type);
/* FIXME: hack-fix for freezing in Perfect Dark
* http://code.google.com/p/mupen64plus/issues/detail?id=553
* https://github.com/mupen64plus-ae/mupen64plus-ae/commit/802d8f81d46705d64694d7a34010dc5f35787c7d
*/
return;
} }
event = alloc_node(&state->q.pool); event = alloc_node(&state->q.pool);
@ -197,18 +169,20 @@ void add_interupt_event_count(usf_state_t * state, int type, unsigned int count)
state->q.first = event; state->q.first = event;
event->next = NULL; event->next = NULL;
state->next_interupt = state->q.first->data.count; state->next_interupt = state->q.first->data.count;
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
} }
else if (before_event(state, count, state->q.first->data.count, state->q.first->data.type) && !special) else if (before_event(state, count, state->q.first->data.count, state->q.first->data.type))
{ {
event->next = state->q.first; event->next = state->q.first;
state->q.first = event; state->q.first = event;
state->next_interupt = state->q.first->data.count; state->next_interupt = state->q.first->data.count;
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
} }
else else
{ {
for(e = state->q.first; for(e = state->q.first;
e->next != NULL && e->next != NULL &&
(!before_event(state, count, e->next->data.count, e->next->data.type) || special); (!before_event(state, count, e->next->data.count, e->next->data.type));
e = e->next); e = e->next);
if (e->next == NULL) if (e->next == NULL)
@ -218,7 +192,6 @@ void add_interupt_event_count(usf_state_t * state, int type, unsigned int count)
} }
else else
{ {
if (!special)
for(; e->next != NULL && e->next->data.count == count; e = e->next); for(; e->next != NULL && e->next->data.count == count; e = e->next);
event->next = e->next; event->next = e->next;
@ -235,11 +208,13 @@ static void remove_interupt_event(usf_state_t * state)
state->q.first = e->next; state->q.first = e->next;
free_node(&state->q.pool, e); free_node(&state->q.pool, e);
state->next_interupt = (state->q.first != NULL state->next_interupt = (state->q.first != NULL)
&& (state->q.first->data.count > state->g_cp0_regs[CP0_COUNT_REG]
|| (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count) < 0x80000000))
? state->q.first->data.count ? state->q.first->data.count
: 0; : 0;
state->cycle_count = (state->q.first != NULL)
? (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count)
: 0;
} }
unsigned int get_event(usf_state_t * state, int type) 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)
{ {
e->data.count = (e->data.count - state->g_cp0_regs[CP0_COUNT_REG]) + base; e->data.count = (e->data.count - state->g_cp0_regs[CP0_COUNT_REG]) + base;
} }
state->g_cp0_regs[CP0_COUNT_REG] = base;
add_interupt_event_count(state, SPECIAL_INT, ((state->g_cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000)));
/* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
state->g_cp0_regs[CP0_COUNT_REG] += state->count_per_op;
state->cycle_count += state->count_per_op;
add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]); add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]);
add_interupt_event_count(state, SPECIAL_INT, 0); state->g_cp0_regs[CP0_COUNT_REG] -= state->count_per_op;
/* Update next interrupt in case first event is COMPARE_INT */
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
} }
int save_eventqueue_infos(usf_state_t * state, char *buf) int save_eventqueue_infos(usf_state_t * state, char *buf)
@ -336,6 +321,8 @@ void load_eventqueue_infos(usf_state_t * state, char *buf)
add_interupt_event_count(state, type, count); add_interupt_event_count(state, type, count);
len += 8; len += 8;
} }
remove_event(state, SPECIAL_INT);
add_interupt_event_count(state, SPECIAL_INT, ((state->g_cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000)));
} }
void init_interupt(usf_state_t * state) void init_interupt(usf_state_t * state)
@ -346,7 +333,8 @@ void init_interupt(usf_state_t * state)
clear_queue(state); clear_queue(state);
add_interupt_event_count(state, VI_INT, state->g_vi.next_vi); add_interupt_event_count(state, VI_INT, state->g_vi.next_vi);
add_interupt_event_count(state, SPECIAL_INT, 0); add_interupt_event_count(state, SPECIAL_INT, 0x80000000);
add_interupt_event_count(state, COMPARE_INT, 0);
} }
void check_interupt(usf_state_t * state) void check_interupt(usf_state_t * state)
@ -388,6 +376,7 @@ void check_interupt(usf_state_t * state)
event->data.count = state->next_interupt = state->g_cp0_regs[CP0_COUNT_REG]; event->data.count = state->next_interupt = state->g_cp0_regs[CP0_COUNT_REG];
event->data.type = CHECK_INT; event->data.type = CHECK_INT;
state->cycle_count = 0;
if (state->q.first == NULL) if (state->q.first == NULL)
{ {
@ -434,21 +423,21 @@ void raise_maskable_interrupt(usf_state_t * state, uint32_t cause)
static void special_int_handler(usf_state_t * state) static void special_int_handler(usf_state_t * state)
{ {
if (state->g_cp0_regs[CP0_COUNT_REG] > 0x10000000)
return;
state->SPECIAL_done = 1;
remove_interupt_event(state); remove_interupt_event(state);
add_interupt_event_count(state, SPECIAL_INT, 0); add_interupt_event_count(state, SPECIAL_INT, ((state->g_cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000)));
} }
static void compare_int_handler(usf_state_t * state) static void compare_int_handler(usf_state_t * state)
{ {
remove_interupt_event(state); remove_interupt_event(state);
state->g_cp0_regs[CP0_COUNT_REG]+=state->count_per_op; state->g_cp0_regs[CP0_COUNT_REG]+=state->count_per_op;
state->cycle_count += state->count_per_op;
add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]); add_interupt_event_count(state, COMPARE_INT, state->g_cp0_regs[CP0_COMPARE_REG]);
state->g_cp0_regs[CP0_COUNT_REG]-=state->count_per_op; state->g_cp0_regs[CP0_COUNT_REG]-=state->count_per_op;
/* Update next interrupt in case first event is COMPARE_INT */
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
if (state->enablecompare) if (state->enablecompare)
raise_maskable_interrupt(state, 0x8000); raise_maskable_interrupt(state, 0x8000);
} }
@ -526,11 +515,14 @@ void osal_fastcall gen_interupt(usf_state_t * state)
unsigned int dest = state->skip_jump; unsigned int dest = state->skip_jump;
state->skip_jump = 0; state->skip_jump = 0;
state->next_interupt = (state->q.first->data.count > state->g_cp0_regs[CP0_COUNT_REG] state->next_interupt = (state->q.first != NULL)
|| (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count) < 0x80000000)
? state->q.first->data.count ? state->q.first->data.count
: 0; : 0;
state->cycle_count = (state->q.first != NULL)
? (state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count)
: 0;
state->last_addr = dest; state->last_addr = dest;
generic_jump_to(state, dest); generic_jump_to(state, dest);
return; return;

View File

@ -105,7 +105,7 @@ int write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
check_interupt(r4300->state); check_interupt(r4300->state);
update_count(r4300->state); update_count(r4300->state);
if (r4300->state->next_interupt <= r4300->state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(r4300->state); if (r4300->state->cycle_count >= 0) gen_interupt(r4300->state);
break; break;
} }

View File

@ -76,7 +76,7 @@ static void InterpretOpcode(usf_state_t * state);
update_count(state); \ update_count(state); \
} \ } \
state->last_addr = state->interp_PC.addr; \ state->last_addr = state->interp_PC.addr; \
if (state->next_interupt <= state->g_cp0_regs[CP0_COUNT_REG]) gen_interupt(state); \ if (state->cycle_count >= 0) gen_interupt(state); \
} \ } \
static void name##_IDLE(usf_state_t * state, uint32_t op) \ static void name##_IDLE(usf_state_t * state, uint32_t op) \
{ \ { \
@ -86,11 +86,13 @@ static void InterpretOpcode(usf_state_t * state);
if (take_jump) \ if (take_jump) \
{ \ { \
update_count(state); \ update_count(state); \
skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \ if(state->cycle_count < 0) \
if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \ { \
else name(state, op); \ state->g_cp0_regs[CP0_COUNT_REG] -= state->cycle_count; \
state->cycle_count = 0; \
} \ } \
else name(state, op); \ } \
name(state, op); \
} }
#define CHECK_MEMORY() #define CHECK_MEMORY()

View File

@ -134,6 +134,8 @@ void r4300_reset_hard(usf_state_t * state)
state->g_cp0_regs[CP0_BADVADDR_REG] = 0xFFFFFFFF; state->g_cp0_regs[CP0_BADVADDR_REG] = 0xFFFFFFFF;
state->g_cp0_regs[CP0_ERROREPC_REG] = 0xFFFFFFFF; state->g_cp0_regs[CP0_ERROREPC_REG] = 0xFFFFFFFF;
state->cycle_count = 0;
state->rounding_mode = 0x33F; state->rounding_mode = 0x33F;
} }

View File

@ -177,6 +177,12 @@ static osal_inline void test_reg32_imm32(usf_state_t * state, int reg32, unsigne
put32(state, imm32); put32(state, imm32);
} }
static osal_inline void test_reg32_reg32(usf_state_t * state, int reg1, int reg2)
{
put8(state, 0x85);
put8(state, ((reg2 << 3) | reg1 | 0xC0));
}
static osal_inline void test_m32_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32) static osal_inline void test_m32_imm32(usf_state_t * state, unsigned int *m32, unsigned int imm32)
{ {
put8(state, 0xF7); put8(state, 0xF7);
@ -192,6 +198,13 @@ static osal_inline void add_m32_reg32(usf_state_t * state, unsigned int *m32, in
put32(state, (unsigned int)(m32)); put32(state, (unsigned int)(m32));
} }
static osal_inline void sub_m32_reg32(usf_state_t * state, unsigned int *m32, int reg32)
{
put8(state, 0x29);
put8(state, (reg32 << 3) | 5);
put32(state, (unsigned int)(m32));
}
static osal_inline void sub_reg32_m32(usf_state_t * state, int reg32, unsigned int *m32) static osal_inline void sub_reg32_m32(usf_state_t * state, int reg32, unsigned int *m32)
{ {
put8(state, 0x2B); put8(state, 0x2B);
@ -290,6 +303,18 @@ static osal_inline void jp_rj(usf_state_t * state, unsigned char saut)
put8(state, saut); put8(state, saut);
} }
static osal_inline void jns_rj(usf_state_t * state, unsigned char saut)
{
put8(state, 0x79);
put8(state, saut);
}
static osal_inline void js_rj(usf_state_t * state, unsigned char saut)
{
put8(state, 0x78);
put8(state, saut);
}
static osal_inline void je_near_rj(usf_state_t * state, unsigned int saut) static osal_inline void je_near_rj(usf_state_t * state, unsigned int saut)
{ {
put8(state, 0x0F); put8(state, 0x0F);

View File

@ -44,14 +44,15 @@ static void genupdate_count(usf_state_t * state, unsigned int addr)
mov_reg32_m32(state, EDX, &state->count_per_op); mov_reg32_m32(state, EDX, &state->count_per_op);
mul_reg32(state, EDX); mul_reg32(state, EDX);
add_m32_reg32(state, (unsigned int*)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); add_m32_reg32(state, (unsigned int*)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX);
add_m32_reg32(state, (unsigned int*)(&state->cycle_count), EAX);
} }
static void gencheck_interupt(usf_state_t * state, unsigned int instr_structure) static void gencheck_interupt(usf_state_t * state, unsigned int instr_structure)
{ {
free_register(state, EBX); free_register(state, EBX);
mov_eax_memoffs32(state, &state->next_interupt); mov_eax_memoffs32(state, &state->cycle_count);
cmp_reg32_m32(state, EAX, &state->g_cp0_regs[CP0_COUNT_REG]); test_reg32_reg32(state, EAX, EAX);
ja_rj(state, 19); js_rj(state, 19);
mov_m32_imm32(state, (unsigned int*)(&state->PC), instr_structure); // 10 mov_m32_imm32(state, (unsigned int*)(&state->PC), instr_structure); // 10
mov_reg32_imm32(state, EBX, (unsigned int)gen_interupt); // 5 mov_reg32_imm32(state, EBX, (unsigned int)gen_interupt); // 5
mov_reg32_reg32(state, RP0, ESI); // 2 mov_reg32_reg32(state, RP0, ESI); // 2
@ -61,9 +62,9 @@ static void gencheck_interupt(usf_state_t * state, unsigned int instr_structure)
static void gencheck_interupt_out(usf_state_t * state, unsigned int addr) static void gencheck_interupt_out(usf_state_t * state, unsigned int addr)
{ {
free_register(state, EBX); free_register(state, EBX);
mov_eax_memoffs32(state, &state->next_interupt); mov_eax_memoffs32(state, &state->cycle_count);
cmp_reg32_m32(state, EAX, &state->g_cp0_regs[CP0_COUNT_REG]); test_reg32_reg32(state, EAX, EAX);
ja_rj(state, 29); js_rj(state, 29);
mov_m32_imm32(state, (unsigned int*)(&state->fake_instr.addr), addr); // 10 mov_m32_imm32(state, (unsigned int*)(&state->fake_instr.addr), addr); // 10
mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(&state->fake_instr)); // 10 mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(&state->fake_instr)); // 10
mov_reg32_imm32(state, EBX, (unsigned int)gen_interupt); // 5 mov_reg32_imm32(state, EBX, (unsigned int)gen_interupt); // 5
@ -359,9 +360,9 @@ void genfin_block(usf_state_t * state)
void gencheck_interupt_reg(usf_state_t * state) // addr is in EAX void gencheck_interupt_reg(usf_state_t * state) // addr is in EAX
{ {
free_register(state, ECX); free_register(state, ECX);
mov_reg32_m32(state, EBX, &state->next_interupt); mov_reg32_m32(state, EBX, &state->cycle_count);
cmp_reg32_m32(state, EBX, &state->g_cp0_regs[CP0_COUNT_REG]); test_reg32_reg32(state, EBX, EBX);
ja_rj(state, 24); js_rj(state, 24);
mov_memoffs32_eax(state, (unsigned int*)(&state->fake_instr.addr)); // 5 mov_memoffs32_eax(state, (unsigned int*)(&state->fake_instr.addr)); // 5
mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(&state->fake_instr)); // 10 mov_m32_imm32(state, (unsigned int*)(&state->PC), (unsigned int)(&state->fake_instr)); // 10
mov_reg32_imm32(state, EBX, (unsigned int)gen_interupt); // 5 mov_reg32_imm32(state, EBX, (unsigned int)gen_interupt); // 5
@ -427,6 +428,7 @@ void genj_out(usf_state_t * state)
void genj_idle(usf_state_t * state) void genj_idle(usf_state_t * state)
{ {
#ifdef INTERPRET_J_IDLE #ifdef INTERPRET_J_IDLE
gencallinterp(state, (unsigned int)state->current_instruction_table.J_IDLE, 1); gencallinterp(state, (unsigned int)state->current_instruction_table.J_IDLE, 1);
#else #else
@ -437,13 +439,12 @@ void genj_idle(usf_state_t * state)
return; return;
} }
mov_eax_memoffs32(state, (unsigned int *)(&state->next_interupt)); mov_eax_memoffs32(state, (unsigned int *)(&state->cycle_count));
sub_reg32_m32(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); test_reg32_reg32(state, EAX, EAX);
cmp_reg32_imm8(state, EAX, 3); js_rj(state, 16);
jbe_rj(state, 11);
and_eax_imm32(state, 0xFFFFFFFC); // 5 sub_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 6
add_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 6 mov_m32_imm32(state, (unsigned int *)(&state->cycle_count), 0); //10
genj(state); genj(state);
#endif #endif
@ -527,13 +528,12 @@ void genjal_idle(usf_state_t * state)
return; return;
} }
mov_eax_memoffs32(state, (unsigned int *)(&state->next_interupt)); mov_eax_memoffs32(state, (unsigned int *)(&state->cycle_count));
sub_reg32_m32(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); test_reg32_reg32(state, EAX, EAX);
cmp_reg32_imm8(state, EAX, 3); jns_rj(state, 16);
jbe_rj(state, 11);
and_eax_imm32(state, 0xFFFFFFFC); sub_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 6
add_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); mov_m32_imm32(state, (unsigned int *)(&state->cycle_count), 0); //10
genjal(state); genjal(state);
#endif #endif
@ -629,14 +629,12 @@ void gentest_idle(usf_state_t * state)
jump_start_rel32(state); jump_start_rel32(state);
mov_reg32_m32(state, reg, (unsigned int *)(&state->next_interupt)); mov_reg32_m32(state, reg, (unsigned int *)(&state->cycle_count));
sub_reg32_m32(state, reg, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); test_reg32_reg32(state, reg, reg);
cmp_reg32_imm8(state, reg, 3); jns_rj(state, 16);
jbe_rj(state, 12);
//sub_reg32_imm32(state, reg, 2); // 6 sub_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), reg); // 6
and_reg32_imm32(state, reg, 0xFFFFFFFC); // 6 mov_m32_imm32(state, (unsigned int *)(&state->cycle_count), 0); //10
add_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), reg); // 6
jump_end_rel32(state); jump_end_rel32(state);
} }

View File

@ -347,6 +347,12 @@ static inline void test_m32rel_imm32(usf_state_t * state, unsigned int *m32, uns
put32(state, imm32); put32(state, imm32);
} }
static osal_inline void test_reg32_reg32(usf_state_t * state, unsigned int reg1, unsigned int reg2)
{
put8(state, 0x85);
put8(state, 0xC0 | (reg2 << 3) | reg1);
}
static inline void add_m32rel_xreg32(usf_state_t * state, unsigned int *m32, int xreg32) static inline void add_m32rel_xreg32(usf_state_t * state, unsigned int *m32, int xreg32)
{ {
int offset = rel_r15_offset(state, m32, "add_m32rel_xreg32"); int offset = rel_r15_offset(state, m32, "add_m32rel_xreg32");
@ -357,6 +363,16 @@ static inline void add_m32rel_xreg32(usf_state_t * state, unsigned int *m32, int
put32(state, offset); put32(state, offset);
} }
static osal_inline void sub_m32rel_xreg32(usf_state_t * state, unsigned int *m32, int xreg32)
{
int offset = rel_r15_offset(state, m32, "sub_m32rel_xreg32");
put8(state, 0x41 | ((xreg32 & 8) >> 1));
put8(state, 0x29);
put8(state, 0x87 | ((xreg32 & 7) << 3));
put32(state, offset);
}
static inline void sub_xreg32_m32rel(usf_state_t * state, int xreg32, unsigned int *m32) static inline void sub_xreg32_m32rel(usf_state_t * state, int xreg32, unsigned int *m32)
{ {
int offset = rel_r15_offset(state, m32, "sub_xreg32_m32rel"); int offset = rel_r15_offset(state, m32, "sub_xreg32_m32rel");
@ -436,6 +452,18 @@ static inline void jp_rj(usf_state_t * state, unsigned char saut)
put8(state, saut); put8(state, saut);
} }
static osal_inline void jns_rj(usf_state_t * state, unsigned char saut)
{
put8(state, 0x79);
put8(state, saut);
}
static osal_inline void js_rj(usf_state_t * state, unsigned char saut)
{
put8(state, 0x78);
put8(state, saut);
}
static inline void je_near_rj(usf_state_t * state, unsigned int saut) static inline void je_near_rj(usf_state_t * state, unsigned int saut)
{ {
put8(state, 0x0F); put8(state, 0x0F);

View File

@ -58,13 +58,14 @@ static void genupdate_count(usf_state_t * state, unsigned int addr)
mov_xreg32_m32rel(state, EDX, (void*)&state->count_per_op); mov_xreg32_m32rel(state, EDX, (void*)&state->count_per_op);
mul_reg32(state, EDX); mul_reg32(state, EDX);
add_m32rel_xreg32(state, (unsigned int*)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); add_m32rel_xreg32(state, (unsigned int*)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX);
add_m32rel_xreg32(state, (unsigned int*)(&state->cycle_count), EAX);
} }
static void gencheck_interupt(usf_state_t * state, unsigned long long instr_structure) static void gencheck_interupt(usf_state_t * state, unsigned long long instr_structure)
{ {
mov_xreg32_m32rel(state, EAX, (void*)(&state->next_interupt)); mov_xreg32_m32rel(state, EAX, (void*)(&state->cycle_count));
cmp_xreg32_m32rel(state, EAX, (void*)&state->g_cp0_regs[CP0_COUNT_REG]); test_reg32_reg32(state, EAX, EAX);
ja_rj(state, 0); js_rj(state, 0);
jump_start_rel8(state); jump_start_rel8(state);
mov_reg64_imm64(state, RAX, (unsigned long long) instr_structure); mov_reg64_imm64(state, RAX, (unsigned long long) instr_structure);
@ -79,9 +80,9 @@ static void gencheck_interupt(usf_state_t * state, unsigned long long instr_stru
static void gencheck_interupt_out(usf_state_t * state, unsigned int addr) static void gencheck_interupt_out(usf_state_t * state, unsigned int addr)
{ {
mov_xreg32_m32rel(state, EAX, (void*)(&state->next_interupt)); mov_xreg32_m32rel(state, EAX, (void*)(&state->cycle_count));
cmp_xreg32_m32rel(state, EAX, (void*)&state->g_cp0_regs[CP0_COUNT_REG]); test_reg32_reg32(state, EAX, EAX);
ja_rj(state, 0); js_rj(state, 0);
jump_start_rel8(state); jump_start_rel8(state);
mov_m32rel_imm32(state, (unsigned int*)(&state->fake_instr.addr), addr); mov_m32rel_imm32(state, (unsigned int*)(&state->fake_instr.addr), addr);
@ -322,9 +323,9 @@ void genfin_block(usf_state_t * state)
void gencheck_interupt_reg(usf_state_t * state) // addr is in EAX void gencheck_interupt_reg(usf_state_t * state) // addr is in EAX
{ {
mov_xreg32_m32rel(state, EBX, (void*)&state->next_interupt); mov_xreg32_m32rel(state, EBX, (void*)(&state->cycle_count));
cmp_xreg32_m32rel(state, EBX, (void*)&state->g_cp0_regs[CP0_COUNT_REG]); test_reg32_reg32(state, EBX, EBX);
ja_rj(state, 0); js_rj(state, 0);
jump_start_rel8(state); jump_start_rel8(state);
mov_m32rel_xreg32(state, (unsigned int*)(&state->fake_instr.addr), EAX); mov_m32rel_xreg32(state, (unsigned int*)(&state->fake_instr.addr), EAX);
@ -416,13 +417,13 @@ void genj_idle(usf_state_t * state)
return; return;
} }
mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->next_interupt)); mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->cycle_count));
sub_xreg32_m32rel(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); test_reg32_reg32(state, EAX, EAX);
cmp_reg32_imm8(state, EAX, 3); jns_rj(state, 18);
jbe_rj(state, 12);
and_eax_imm32(state, 0xFFFFFFFC); // 5
add_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 7 sub_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 7
mov_m32rel_imm32(state, (unsigned int *)(&state->cycle_count), 0); // 11
genj(state); genj(state);
#endif #endif
@ -515,13 +516,12 @@ void genjal_idle(usf_state_t * state)
return; return;
} }
mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->next_interupt)); mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->cycle_count));
sub_xreg32_m32rel(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); test_reg32_reg32(state, EAX, EAX);
cmp_reg32_imm8(state, EAX, 3); jns_rj(state, 18);
jbe_rj(state, 12);
and_eax_imm32(state, 0xFFFFFFFC); // 5 sub_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 7
add_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 7 mov_m32rel_imm32(state, (unsigned int *)(&state->cycle_count), 0); // 11
genjal(state); genjal(state);
#endif #endif
@ -619,14 +619,14 @@ void gentest_idle(usf_state_t * state)
je_near_rj(state, 0); je_near_rj(state, 0);
jump_start_rel32(state); jump_start_rel32(state);
mov_xreg32_m32rel(state, reg, (unsigned int *)(&state->next_interupt)); mov_xreg32_m32rel(state, reg, (unsigned int *)(&state->cycle_count));
sub_xreg32_m32rel(state, reg, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG])); test_reg32_reg32(state, reg, reg);
cmp_reg32_imm8(state, reg, 3); jns_rj(state, 0);
jbe_rj(state, 0);
jump_start_rel8(state); jump_start_rel8(state);
and_reg32_imm32(state, reg, 0xFFFFFFFC); sub_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), reg);
add_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), reg); mov_m32rel_imm32(state, (unsigned int *)(&state->cycle_count), 0);
jump_end_rel8(state); jump_end_rel8(state);
jump_end_rel32(state); jump_end_rel32(state);

View File

@ -409,6 +409,8 @@ struct usf_state
int init_length; int init_length;
int cycle_count;
#ifdef DYNAREC #ifdef DYNAREC
#ifdef _MSC_VER #ifdef _MSC_VER
#define __i386__ #define __i386__