diff --git a/Frameworks/lazyusf2/lazyusf2/ai/ai_controller.c b/Frameworks/lazyusf2/lazyusf2/ai/ai_controller.c index 22d590867..548c27128 100644 --- a/Frameworks/lazyusf2/lazyusf2/ai/ai_controller.c +++ b/Frameworks/lazyusf2/lazyusf2/ai/ai_controller.c @@ -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) diff --git a/Frameworks/lazyusf2/lazyusf2/main/savestates.c b/Frameworks/lazyusf2/lazyusf2/main/savestates.c index fb96622ae..c329d5c55 100644 --- a/Frameworks/lazyusf2/lazyusf2/main/savestates.c +++ b/Frameworks/lazyusf2/lazyusf2/main/savestates.c @@ -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 diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/cached_interp.c b/Frameworks/lazyusf2/lazyusf2/r4300/cached_interp.c index 7f2acbf37..c19b08c43 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/cached_interp.c +++ b/Frameworks/lazyusf2/lazyusf2/r4300/cached_interp.c @@ -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() \ diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/cp0.c b/Frameworks/lazyusf2/lazyusf2/r4300/cp0.c index 3fa87a9e8..7c262d508 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/cp0.c +++ b/Frameworks/lazyusf2/lazyusf2/r4300/cp0.c @@ -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 } diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/exception.c b/Frameworks/lazyusf2/lazyusf2/r4300/exception.c index 47e3e198c..ab44e7151 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/exception.c +++ b/Frameworks/lazyusf2/lazyusf2/r4300/exception.c @@ -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; } } } diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_cop0.def b/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_cop0.def index c219aad81..482ccb0aa 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_cop0.def +++ b/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_cop0.def @@ -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; diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_special.def b/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_special.def index 29fc1f0a0..7f6cf4388 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_special.def +++ b/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_special.def @@ -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); } diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_tlb.def b/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_tlb.def index 0d181184d..7b66e6c81 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_tlb.def +++ b/Frameworks/lazyusf2/lazyusf2/r4300/interpreter_tlb.def @@ -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); } diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/interupt.c b/Frameworks/lazyusf2/lazyusf2/r4300/interupt.c index f740b537d..4a3b28fd5 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/interupt.c +++ b/Frameworks/lazyusf2/lazyusf2/r4300/interupt.c @@ -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; diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/mi_controller.c b/Frameworks/lazyusf2/lazyusf2/r4300/mi_controller.c index bc8f54855..2dbf831d5 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/mi_controller.c +++ b/Frameworks/lazyusf2/lazyusf2/r4300/mi_controller.c @@ -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; } diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/pure_interp.c b/Frameworks/lazyusf2/lazyusf2/r4300/pure_interp.c index 1009bb16c..87cfbf256 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/pure_interp.c +++ b/Frameworks/lazyusf2/lazyusf2/r4300/pure_interp.c @@ -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() diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/r4300.c b/Frameworks/lazyusf2/lazyusf2/r4300/r4300.c index 790088ba8..fdd2151e0 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/r4300.c +++ b/Frameworks/lazyusf2/lazyusf2/r4300/r4300.c @@ -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; } diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/x86/assemble.h b/Frameworks/lazyusf2/lazyusf2/r4300/x86/assemble.h index 83ca56672..a3b99c893 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/x86/assemble.h +++ b/Frameworks/lazyusf2/lazyusf2/r4300/x86/assemble.h @@ -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); diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/x86/gr4300.c b/Frameworks/lazyusf2/lazyusf2/r4300/x86/gr4300.c index 81f879952..8e69199b1 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/x86/gr4300.c +++ b/Frameworks/lazyusf2/lazyusf2/r4300/x86/gr4300.c @@ -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); } diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/x86_64/assemble.h b/Frameworks/lazyusf2/lazyusf2/r4300/x86_64/assemble.h index d2aec168c..44a0b0453 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/x86_64/assemble.h +++ b/Frameworks/lazyusf2/lazyusf2/r4300/x86_64/assemble.h @@ -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); diff --git a/Frameworks/lazyusf2/lazyusf2/r4300/x86_64/gr4300.c b/Frameworks/lazyusf2/lazyusf2/r4300/x86_64/gr4300.c index 7e517adb6..627ef8205 100644 --- a/Frameworks/lazyusf2/lazyusf2/r4300/x86_64/gr4300.c +++ b/Frameworks/lazyusf2/lazyusf2/r4300/x86_64/gr4300.c @@ -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); diff --git a/Frameworks/lazyusf2/lazyusf2/ri/rdram.c b/Frameworks/lazyusf2/lazyusf2/ri/rdram.c index 0ea027b6f..8328485e3 100644 --- a/Frameworks/lazyusf2/lazyusf2/ri/rdram.c +++ b/Frameworks/lazyusf2/lazyusf2/ri/rdram.c @@ -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); diff --git a/Frameworks/lazyusf2/lazyusf2/usf/usf_internal.h b/Frameworks/lazyusf2/lazyusf2/usf/usf_internal.h index 3fe2755ff..740c18c46 100644 --- a/Frameworks/lazyusf2/lazyusf2/usf/usf_internal.h +++ b/Frameworks/lazyusf2/lazyusf2/usf/usf_internal.h @@ -409,6 +409,8 @@ struct usf_state int init_length; + int cycle_count; + #ifdef DYNAREC #ifdef _MSC_VER #define __i386__