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
parent
97fee7e486
commit
d070dffdbe
|
@ -53,12 +53,15 @@ static uint32_t get_remaining_dma_length(struct ai_controller* ai)
|
|||
if (next_ai_event == 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];
|
||||
|
||||
if (remaining_dma_duration >= 0x80000000)
|
||||
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)
|
||||
|
|
|
@ -422,6 +422,8 @@ static int savestates_load_pj64(usf_state_t * state, unsigned char * ptr, unsign
|
|||
|
||||
load_eventqueue_infos(state, buffer);
|
||||
|
||||
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
|
||||
|
||||
// FPCR
|
||||
state->FCR0 = GETDATA(curr, int);
|
||||
curr += 30 * 4; // FCR1...FCR30 not supported
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
update_count(state); \
|
||||
} \
|
||||
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) \
|
||||
{ \
|
||||
|
@ -108,21 +108,21 @@
|
|||
update_count(state); \
|
||||
} \
|
||||
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) \
|
||||
{ \
|
||||
const int take_jump = (condition); \
|
||||
int skip; \
|
||||
if (cop1 && check_cop1_unusable(state)) return; \
|
||||
if (take_jump) \
|
||||
{ \
|
||||
update_count(state); \
|
||||
skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \
|
||||
if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \
|
||||
else name(state); \
|
||||
if (state->cycle_count < 0) \
|
||||
{ \
|
||||
state->g_cp0_regs[CP0_COUNT_REG] -= state->cycle_count; \
|
||||
state->cycle_count = 0; \
|
||||
} \
|
||||
} \
|
||||
else name(state); \
|
||||
name(state); \
|
||||
}
|
||||
|
||||
#define CHECK_MEMORY() \
|
||||
|
|
|
@ -56,7 +56,9 @@ void update_count(usf_state_t * state)
|
|||
if (r4300emu != CORE_DYNAREC)
|
||||
{
|
||||
#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;
|
||||
#ifdef NEW_DYNAREC
|
||||
}
|
||||
|
|
|
@ -111,6 +111,7 @@ void TLB_refill_exception(usf_state_t * state, unsigned int address, int w)
|
|||
{
|
||||
state->skip_jump = state->PC->addr;
|
||||
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->next_interupt = 0;
|
||||
state->cycle_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ DECLARE_INSTRUCTION(MTC0)
|
|||
case CP0_COUNT_REG:
|
||||
update_count(state);
|
||||
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;
|
||||
translate_event_queue(state, (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:
|
||||
update_count(state);
|
||||
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_CAUSE_REG] &= 0xFFFF7FFF; //Timer interupt is clear
|
||||
break;
|
||||
|
@ -97,7 +104,7 @@ DECLARE_INSTRUCTION(MTC0)
|
|||
ADD_TO_PC(1);
|
||||
check_interupt(state);
|
||||
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;
|
||||
ADD_TO_PC(-1);
|
||||
break;
|
||||
|
|
|
@ -404,5 +404,7 @@ DECLARE_INSTRUCTION(DSRA32)
|
|||
DECLARE_INSTRUCTION(BREAK)
|
||||
{
|
||||
state->g_cp0_regs[CP0_COUNT_REG] = state->next_interupt;
|
||||
state->cycle_count = 0;
|
||||
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
|
|
@ -246,5 +246,5 @@ DECLARE_INSTRUCTION(ERET)
|
|||
state->llbit = 0;
|
||||
check_interupt(state);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
if(evt1 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000)
|
||||
{
|
||||
if(evt2 - state->g_cp0_regs[CP0_COUNT_REG] < 0x80000000)
|
||||
{
|
||||
if((evt1 - state->g_cp0_regs[CP0_COUNT_REG]) < (evt2 - state->g_cp0_regs[CP0_COUNT_REG])) return 1;
|
||||
else return 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
int count = state->g_cp0_regs[CP0_COUNT_REG];
|
||||
|
||||
if (state->cycle_count > 0)
|
||||
count -= state->cycle_count;
|
||||
|
||||
if ((evt1 - count) < (evt2 - count)) return 1;
|
||||
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* 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)) {
|
||||
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);
|
||||
|
@ -197,18 +169,20 @@ void add_interupt_event_count(usf_state_t * state, int type, unsigned int count)
|
|||
state->q.first = event;
|
||||
event->next = NULL;
|
||||
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;
|
||||
state->q.first = event;
|
||||
state->next_interupt = state->q.first->data.count;
|
||||
state->cycle_count = state->g_cp0_regs[CP0_COUNT_REG] - state->q.first->data.count;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(e = state->q.first;
|
||||
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);
|
||||
|
||||
if (e->next == NULL)
|
||||
|
@ -218,8 +192,7 @@ void add_interupt_event_count(usf_state_t * state, int type, unsigned int count)
|
|||
}
|
||||
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;
|
||||
e->next = event;
|
||||
|
@ -235,11 +208,13 @@ static void remove_interupt_event(usf_state_t * state)
|
|||
state->q.first = e->next;
|
||||
free_node(&state->q.pool, e);
|
||||
|
||||
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->next_interupt = (state->q.first != NULL)
|
||||
? state->q.first->data.count
|
||||
: 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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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, 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)
|
||||
|
@ -336,6 +321,8 @@ void load_eventqueue_infos(usf_state_t * state, char *buf)
|
|||
add_interupt_event_count(state, type, count);
|
||||
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)
|
||||
|
@ -346,7 +333,8 @@ void init_interupt(usf_state_t * state)
|
|||
|
||||
clear_queue(state);
|
||||
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)
|
||||
|
@ -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.type = CHECK_INT;
|
||||
state->cycle_count = 0;
|
||||
|
||||
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)
|
||||
{
|
||||
if (state->g_cp0_regs[CP0_COUNT_REG] > 0x10000000)
|
||||
return;
|
||||
|
||||
state->SPECIAL_done = 1;
|
||||
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)
|
||||
{
|
||||
remove_interupt_event(state);
|
||||
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]);
|
||||
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)
|
||||
raise_maskable_interrupt(state, 0x8000);
|
||||
}
|
||||
|
@ -526,11 +515,14 @@ void osal_fastcall gen_interupt(usf_state_t * state)
|
|||
unsigned int dest = state->skip_jump;
|
||||
state->skip_jump = 0;
|
||||
|
||||
state->next_interupt = (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->next_interupt = (state->q.first != NULL)
|
||||
? state->q.first->data.count
|
||||
: 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;
|
||||
generic_jump_to(state, dest);
|
||||
return;
|
||||
|
|
|
@ -105,7 +105,7 @@ int write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
|
|||
|
||||
check_interupt(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ static void InterpretOpcode(usf_state_t * state);
|
|||
update_count(state); \
|
||||
} \
|
||||
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) \
|
||||
{ \
|
||||
|
@ -86,11 +86,13 @@ static void InterpretOpcode(usf_state_t * state);
|
|||
if (take_jump) \
|
||||
{ \
|
||||
update_count(state); \
|
||||
skip = state->next_interupt - state->g_cp0_regs[CP0_COUNT_REG]; \
|
||||
if (skip > 3) state->g_cp0_regs[CP0_COUNT_REG] += (skip & 0xFFFFFFFC); \
|
||||
else name(state, op); \
|
||||
if(state->cycle_count < 0) \
|
||||
{ \
|
||||
state->g_cp0_regs[CP0_COUNT_REG] -= state->cycle_count; \
|
||||
state->cycle_count = 0; \
|
||||
} \
|
||||
} \
|
||||
else name(state, op); \
|
||||
name(state, op); \
|
||||
}
|
||||
#define CHECK_MEMORY()
|
||||
|
||||
|
|
|
@ -133,6 +133,8 @@ void r4300_reset_hard(usf_state_t * state)
|
|||
state->g_cp0_regs[CP0_EPC_REG] = 0xFFFFFFFF;
|
||||
state->g_cp0_regs[CP0_BADVADDR_REG] = 0xFFFFFFFF;
|
||||
state->g_cp0_regs[CP0_ERROREPC_REG] = 0xFFFFFFFF;
|
||||
|
||||
state->cycle_count = 0;
|
||||
|
||||
state->rounding_mode = 0x33F;
|
||||
}
|
||||
|
|
|
@ -177,6 +177,12 @@ static osal_inline void test_reg32_imm32(usf_state_t * state, int reg32, unsigne
|
|||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
put8(state, 0x2B);
|
||||
|
@ -290,6 +303,18 @@ static osal_inline void jp_rj(usf_state_t * state, unsigned char 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)
|
||||
{
|
||||
put8(state, 0x0F);
|
||||
|
|
|
@ -44,14 +44,15 @@ static void genupdate_count(usf_state_t * state, unsigned int addr)
|
|||
mov_reg32_m32(state, EDX, &state->count_per_op);
|
||||
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->cycle_count), EAX);
|
||||
}
|
||||
|
||||
static void gencheck_interupt(usf_state_t * state, unsigned int instr_structure)
|
||||
{
|
||||
free_register(state, EBX);
|
||||
mov_eax_memoffs32(state, &state->next_interupt);
|
||||
cmp_reg32_m32(state, EAX, &state->g_cp0_regs[CP0_COUNT_REG]);
|
||||
ja_rj(state, 19);
|
||||
mov_eax_memoffs32(state, &state->cycle_count);
|
||||
test_reg32_reg32(state, EAX, EAX);
|
||||
js_rj(state, 19);
|
||||
mov_m32_imm32(state, (unsigned int*)(&state->PC), instr_structure); // 10
|
||||
mov_reg32_imm32(state, EBX, (unsigned int)gen_interupt); // 5
|
||||
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)
|
||||
{
|
||||
free_register(state, EBX);
|
||||
mov_eax_memoffs32(state, &state->next_interupt);
|
||||
cmp_reg32_m32(state, EAX, &state->g_cp0_regs[CP0_COUNT_REG]);
|
||||
ja_rj(state, 29);
|
||||
mov_eax_memoffs32(state, &state->cycle_count);
|
||||
test_reg32_reg32(state, EAX, EAX);
|
||||
js_rj(state, 29);
|
||||
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_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
|
||||
{
|
||||
free_register(state, ECX);
|
||||
mov_reg32_m32(state, EBX, &state->next_interupt);
|
||||
cmp_reg32_m32(state, EBX, &state->g_cp0_regs[CP0_COUNT_REG]);
|
||||
ja_rj(state, 24);
|
||||
mov_reg32_m32(state, EBX, &state->cycle_count);
|
||||
test_reg32_reg32(state, EBX, EBX);
|
||||
js_rj(state, 24);
|
||||
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_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)
|
||||
{
|
||||
|
||||
#ifdef INTERPRET_J_IDLE
|
||||
gencallinterp(state, (unsigned int)state->current_instruction_table.J_IDLE, 1);
|
||||
#else
|
||||
|
@ -436,14 +438,13 @@ void genj_idle(usf_state_t * state)
|
|||
gencallinterp(state, (unsigned int)state->current_instruction_table.J_IDLE, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
mov_eax_memoffs32(state, (unsigned int *)(&state->cycle_count));
|
||||
test_reg32_reg32(state, EAX, EAX);
|
||||
js_rj(state, 16);
|
||||
|
||||
mov_eax_memoffs32(state, (unsigned int *)(&state->next_interupt));
|
||||
sub_reg32_m32(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]));
|
||||
cmp_reg32_imm8(state, EAX, 3);
|
||||
jbe_rj(state, 11);
|
||||
|
||||
and_eax_imm32(state, 0xFFFFFFFC); // 5
|
||||
add_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX); // 6
|
||||
sub_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);
|
||||
#endif
|
||||
|
@ -527,13 +528,12 @@ void genjal_idle(usf_state_t * state)
|
|||
return;
|
||||
}
|
||||
|
||||
mov_eax_memoffs32(state, (unsigned int *)(&state->next_interupt));
|
||||
sub_reg32_m32(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]));
|
||||
cmp_reg32_imm8(state, EAX, 3);
|
||||
jbe_rj(state, 11);
|
||||
mov_eax_memoffs32(state, (unsigned int *)(&state->cycle_count));
|
||||
test_reg32_reg32(state, EAX, EAX);
|
||||
jns_rj(state, 16);
|
||||
|
||||
and_eax_imm32(state, 0xFFFFFFFC);
|
||||
add_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), EAX);
|
||||
sub_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
|
||||
|
||||
genjal(state);
|
||||
#endif
|
||||
|
@ -629,14 +629,12 @@ void gentest_idle(usf_state_t * state)
|
|||
|
||||
jump_start_rel32(state);
|
||||
|
||||
mov_reg32_m32(state, reg, (unsigned int *)(&state->next_interupt));
|
||||
sub_reg32_m32(state, reg, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]));
|
||||
cmp_reg32_imm8(state, reg, 3);
|
||||
jbe_rj(state, 12);
|
||||
|
||||
//sub_reg32_imm32(state, reg, 2); // 6
|
||||
and_reg32_imm32(state, reg, 0xFFFFFFFC); // 6
|
||||
add_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), reg); // 6
|
||||
mov_reg32_m32(state, reg, (unsigned int *)(&state->cycle_count));
|
||||
test_reg32_reg32(state, reg, reg);
|
||||
jns_rj(state, 16);
|
||||
|
||||
sub_m32_reg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), reg); // 6
|
||||
mov_m32_imm32(state, (unsigned int *)(&state->cycle_count), 0); //10
|
||||
|
||||
jump_end_rel32(state);
|
||||
}
|
||||
|
|
|
@ -347,6 +347,12 @@ static inline void test_m32rel_imm32(usf_state_t * state, unsigned int *m32, uns
|
|||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
put8(state, 0x0F);
|
||||
|
|
|
@ -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);
|
||||
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->cycle_count), EAX);
|
||||
}
|
||||
|
||||
static void gencheck_interupt(usf_state_t * state, unsigned long long instr_structure)
|
||||
{
|
||||
mov_xreg32_m32rel(state, EAX, (void*)(&state->next_interupt));
|
||||
cmp_xreg32_m32rel(state, EAX, (void*)&state->g_cp0_regs[CP0_COUNT_REG]);
|
||||
ja_rj(state, 0);
|
||||
mov_xreg32_m32rel(state, EAX, (void*)(&state->cycle_count));
|
||||
test_reg32_reg32(state, EAX, EAX);
|
||||
js_rj(state, 0);
|
||||
jump_start_rel8(state);
|
||||
|
||||
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)
|
||||
{
|
||||
mov_xreg32_m32rel(state, EAX, (void*)(&state->next_interupt));
|
||||
cmp_xreg32_m32rel(state, EAX, (void*)&state->g_cp0_regs[CP0_COUNT_REG]);
|
||||
ja_rj(state, 0);
|
||||
mov_xreg32_m32rel(state, EAX, (void*)(&state->cycle_count));
|
||||
test_reg32_reg32(state, EAX, EAX);
|
||||
js_rj(state, 0);
|
||||
jump_start_rel8(state);
|
||||
|
||||
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
|
||||
{
|
||||
mov_xreg32_m32rel(state, EBX, (void*)&state->next_interupt);
|
||||
cmp_xreg32_m32rel(state, EBX, (void*)&state->g_cp0_regs[CP0_COUNT_REG]);
|
||||
ja_rj(state, 0);
|
||||
mov_xreg32_m32rel(state, EBX, (void*)(&state->cycle_count));
|
||||
test_reg32_reg32(state, EBX, EBX);
|
||||
js_rj(state, 0);
|
||||
jump_start_rel8(state);
|
||||
|
||||
mov_m32rel_xreg32(state, (unsigned int*)(&state->fake_instr.addr), EAX);
|
||||
|
@ -416,13 +417,13 @@ void genj_idle(usf_state_t * state)
|
|||
return;
|
||||
}
|
||||
|
||||
mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->next_interupt));
|
||||
sub_xreg32_m32rel(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]));
|
||||
cmp_reg32_imm8(state, EAX, 3);
|
||||
jbe_rj(state, 12);
|
||||
mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->cycle_count));
|
||||
test_reg32_reg32(state, EAX, EAX);
|
||||
jns_rj(state, 18);
|
||||
|
||||
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);
|
||||
#endif
|
||||
|
@ -515,13 +516,12 @@ void genjal_idle(usf_state_t * state)
|
|||
return;
|
||||
}
|
||||
|
||||
mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->next_interupt));
|
||||
sub_xreg32_m32rel(state, EAX, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]));
|
||||
cmp_reg32_imm8(state, EAX, 3);
|
||||
jbe_rj(state, 12);
|
||||
mov_xreg32_m32rel(state, EAX, (unsigned int *)(&state->cycle_count));
|
||||
test_reg32_reg32(state, EAX, EAX);
|
||||
jns_rj(state, 18);
|
||||
|
||||
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
|
||||
|
||||
genjal(state);
|
||||
#endif
|
||||
|
@ -619,14 +619,14 @@ void gentest_idle(usf_state_t * state)
|
|||
je_near_rj(state, 0);
|
||||
jump_start_rel32(state);
|
||||
|
||||
mov_xreg32_m32rel(state, reg, (unsigned int *)(&state->next_interupt));
|
||||
sub_xreg32_m32rel(state, reg, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]));
|
||||
cmp_reg32_imm8(state, reg, 3);
|
||||
jbe_rj(state, 0);
|
||||
mov_xreg32_m32rel(state, reg, (unsigned int *)(&state->cycle_count));
|
||||
test_reg32_reg32(state, reg, reg);
|
||||
jns_rj(state, 0);
|
||||
|
||||
jump_start_rel8(state);
|
||||
|
||||
and_reg32_imm32(state, reg, 0xFFFFFFFC);
|
||||
add_m32rel_xreg32(state, (unsigned int *)(&state->g_cp0_regs[CP0_COUNT_REG]), reg);
|
||||
sub_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_rel32(state);
|
||||
|
|
|
@ -93,7 +93,7 @@ int read_rdram_dram_tracked(void* opaque, uint32_t address, uint32_t* value)
|
|||
usf_state_t* state = (usf_state_t*) opaque;
|
||||
struct ri_controller* ri = &state->g_ri;
|
||||
uint32_t addr = rdram_dram_address(address);
|
||||
|
||||
|
||||
if (!bit_array_test(state->barray_ram_written_first, addr))
|
||||
bit_array_set(state->barray_ram_read, addr);
|
||||
|
||||
|
@ -107,7 +107,7 @@ int write_rdram_dram_tracked(void* opaque, uint32_t address, uint32_t value, uin
|
|||
usf_state_t* state = (usf_state_t*) opaque;
|
||||
struct ri_controller* ri = &state->g_ri;
|
||||
uint32_t addr = rdram_dram_address(address);
|
||||
|
||||
|
||||
if (mask == 0xFFFFFFFFU && !bit_array_test(state->barray_ram_read, addr))
|
||||
bit_array_set(state->barray_ram_written_first, addr);
|
||||
|
||||
|
|
|
@ -409,6 +409,8 @@ struct usf_state
|
|||
|
||||
int init_length;
|
||||
|
||||
int cycle_count;
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef _MSC_VER
|
||||
#define __i386__
|
||||
|
|
Loading…
Reference in New Issue