From 1d1c7193725c8734738c857252a612d5f87d4f20 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 6 Sep 2023 00:48:37 +0200 Subject: [PATCH] Remove COMPLETED_FRAME flag to simplify things --- arm/arm64_stub.S | 10 ++++------ arm/arm_stub.S | 19 +++++++++---------- cpu.c | 22 +++++++++++++--------- cpu.h | 2 +- main.c | 10 +++++----- main.h | 3 ++- mips/mips_stub.S | 11 +++++------ savestate.c | 1 - x86/x86_stub.S | 26 ++++++++++++++------------ 9 files changed, 53 insertions(+), 51 deletions(-) diff --git a/arm/arm64_stub.S b/arm/arm64_stub.S index 724f348..84cf170 100644 --- a/arm/arm64_stub.S +++ b/arm/arm64_stub.S @@ -57,7 +57,7 @@ _##symbol: #define REG_Z_FLAG (21 * 4) #define REG_C_FLAG (22 * 4) #define REG_V_FLAG (23 * 4) -#define COMPLETED_FRAME (24 * 4) +#define REG_UNUSED_1 (24 * 4) #define OAM_UPDATED (25 * 4) #define REG_SAVE (26 * 4) @@ -153,14 +153,13 @@ defsymbl(a64_update_gba) mov w0, reg_cycles // load remaining cycles bl update_gba // update GBA state - ldr w1, [reg_base, #COMPLETED_FRAME] // return to main if new frame - cbnz w1, return_to_main + tbnz w0, #31, return_to_main // exit if a new frame is ready // Resume execution (perhaps from a new PC) and reg_cycles, w0, 0x7fff // load new cycle count extract_flags(w2) // reload flag cache bits - tbnz w0, #31, 1f // check if PC changed + tbnz w0, #30, 1f // check if PC changed ldr lr, [reg_base, #REG_SAVE] // Restore return point load_registers() // reload registers @@ -714,8 +713,7 @@ cpu_sleep_loop: mov w0, reg_cycles // load remaining cycles bl update_gba // update GBA until CPU isn't halted - ldr w1, [reg_base, #COMPLETED_FRAME] // Check whether a frame was completed - cbnz w1, return_to_main // and return to caller function. + tbnz w0, #31, return_to_main // a frame has been completed -> exit // At this point the CPU must be active, otherwise we sping in update_gba diff --git a/arm/arm_stub.S b/arm/arm_stub.S index 7362a8e..01078f7 100644 --- a/arm/arm_stub.S +++ b/arm/arm_stub.S @@ -39,7 +39,7 @@ _##symbol: #define REG_Z_FLAG (21 * 4) #define REG_C_FLAG (22 * 4) #define REG_V_FLAG (23 * 4) -#define COMPLETED_FRAME (24 * 4) +#define REG_UNUSED_1 (24 * 4) #define OAM_UPDATED (25 * 4) #define CPU_ALERT_HALT (1 << 0) @@ -195,14 +195,13 @@ defsymbl(arm_update_gba_##name) ;\ cycles_##return_op() /* remaining cycles in arg0 */;\ call_c_function(update_gba) /* update GBA state */;\ ;\ - ldr r1, [reg_base, #COMPLETED_FRAME] /* return if new frame */;\ - cmp r1, #0 ;\ - bne return_to_main ;\ + cmp r0, #0 /* check MSB for frame completion*/;\ + blt return_to_main ;\ ;\ - bic reg_cycles, r0, #0x80000000 /* clear MSB, not part of count */;\ + bic reg_cycles, r0, #0xF0000000 /* clear MSB, not part of count */;\ mvn reg_cycles, reg_cycles /* we count negative to zero */;\ ;\ - tst r0, #0x80000000 /* set if PC changed */;\ + tst r0, #0x40000000 /* set if PC changed */;\ bne 1f /* go jump/translate */;\ ;\ load_registers_##mode() /* reload registers */;\ @@ -698,11 +697,11 @@ write_epilogue: cpu_sleep_loop: call_c_function(update_gba) @ update GBA until CPU isn't halted - bic r0, r0, #0x80000000 @ clear MSB, not part of count - ldr r1, [reg_base, #COMPLETED_FRAME] @ Check whether a frame was completed - cmp r1, #0 - bne return_to_main + cmp r0, #0 + blt return_to_main @ New frame if bit 31 is set. Exit + + bic r0, r0, #0xF0000000 @ clear MSB, not part of count @ The cpu is active again, go ahead and resume execution at current PC mvn reg_cycles, r0 @ load new cycle count diff --git a/cpu.c b/cpu.c index de79b79..1c5d4c2 100644 --- a/cpu.c +++ b/cpu.c @@ -1535,6 +1535,7 @@ void execute_arm(u32 cycles) u8 *pc_address_block = memory_map_read[pc_region]; u32 new_pc_region; s32 cycles_remaining; + u32 update_ret; cpu_alert_type cpu_alert; u32 old_pc; @@ -1549,11 +1550,12 @@ void execute_arm(u32 cycles) while(1) { /* Do not execute until CPU is active */ - while(reg[CPU_HALT_STATE] != CPU_ACTIVE) { - cycles_remaining = update_gba_cycles(cycles_remaining); - - if (reg[COMPLETED_FRAME]) + if (reg[CPU_HALT_STATE] != CPU_ACTIVE) { + u32 ret = update_gba(cycles_remaining); + if (completed_frame(ret)) return; + + cycles_remaining = cycles_to_run(ret); } cpu_alert = CPU_ALERT_NONE; @@ -3146,9 +3148,10 @@ skip_instruction: } while(cycles_remaining > 0); collapse_flags(); - cycles_remaining = update_gba_cycles(cycles_remaining); - if (reg[COMPLETED_FRAME]) + update_ret = update_gba(cycles_remaining); + if (completed_frame(update_ret)) return; + cycles_remaining = cycles_to_run(update_ret); continue; do @@ -3665,9 +3668,10 @@ thumb_loop: } while(cycles_remaining > 0); collapse_flags(); - cycles_remaining = update_gba_cycles(cycles_remaining); - if (reg[COMPLETED_FRAME]) - return; + update_ret = update_gba(cycles_remaining); + if (completed_frame(update_ret)) + return; + cycles_remaining = cycles_to_run(update_ret); continue; alert: diff --git a/cpu.h b/cpu.h index 18d7944..99285ed 100644 --- a/cpu.h +++ b/cpu.h @@ -91,7 +91,7 @@ typedef enum REG_Z_FLAG = 21, REG_C_FLAG = 22, REG_V_FLAG = 23, - COMPLETED_FRAME = 24, + REG_UNUSED_1 = 24, OAM_UPDATED = 25, REG_SAVE = 26, REG_SAVE2 = 27, diff --git a/main.c b/main.c index f6e6475..f345894 100644 --- a/main.c +++ b/main.c @@ -107,6 +107,7 @@ void init_main(void) u32 function_cc update_gba(int remaining_cycles) { u32 changed_pc = 0; + u32 frame_complete = 0; irq_type irq_raised = IRQ_NONE; int dma_cycles; trace_update_gba(remaining_cycles); @@ -122,7 +123,6 @@ u32 function_cc update_gba(int remaining_cycles) cpu_ticks += completed_cycles; remaining_cycles = 0; - reg[COMPLETED_FRAME] = 0; // Timers can trigger DMA (usually sound) and consume cycles dma_cycles = update_timers(&irq_raised, completed_cycles); @@ -217,7 +217,7 @@ u32 function_cc update_gba(int remaining_cycles) render_gbc_sound(); // We completed a frame, tell the dynarec to exit to the main thread - reg[COMPLETED_FRAME] = 1; + frame_complete = 0x80000000; } // Vcount trigger (flag) and IRQ if enabled @@ -241,7 +241,7 @@ u32 function_cc update_gba(int remaining_cycles) // Raise any pending interrupts. This changes the CPU mode. if (check_and_raise_interrupts()) - changed_pc = 0x80000000; + changed_pc = 0x40000000; // Figure out when we need to stop CPU execution. The next event is // a video event or a timer event, whatever happens first. @@ -253,13 +253,13 @@ u32 function_cc update_gba(int remaining_cycles) timer[i].count < execute_cycles) execute_cycles = timer[i].count; } - } while(reg[CPU_HALT_STATE] != CPU_ACTIVE && !reg[COMPLETED_FRAME]); + } while(reg[CPU_HALT_STATE] != CPU_ACTIVE && !frame_complete); // We voluntarily limit this. It is not accurate but it would be much harder. dma_cycles = MIN(64, dma_cycles); dma_cycles = MIN(execute_cycles, dma_cycles); - return (execute_cycles - dma_cycles) | changed_pc; + return (execute_cycles - dma_cycles) | changed_pc | frame_complete; } void reset_gba(void) diff --git a/main.h b/main.h index 6b422cd..047a30f 100644 --- a/main.h +++ b/main.h @@ -77,7 +77,8 @@ extern u32 flush_ram_count; extern char main_path[512]; extern char save_path[512]; -#define update_gba_cycles(c) (update_gba(c) & 0x7FFF) +#define cycles_to_run(c) ((c) & 0x7FFF) +#define completed_frame(c) ((c) & 0x80000000) u32 function_cc update_gba(int remaining_cycles); void reset_gba(void); diff --git a/mips/mips_stub.S b/mips/mips_stub.S index 46e8269..c29f6ef 100644 --- a/mips/mips_stub.S +++ b/mips/mips_stub.S @@ -104,7 +104,7 @@ symbol: .equ REG_Z_FLAG, (21 * 4) .equ REG_C_FLAG, (22 * 4) .equ REG_V_FLAG, (23 * 4) -.equ COMPLETED_FRAME, (24 * 4) +.equ REG_UNUSED_1, (24 * 4) .equ OAM_UPDATED, (25 * 4) .equ REG_SAVE, (26 * 4) .equ REG_SAVE2, (27 * 4) @@ -248,12 +248,12 @@ defsymbl(mips_update_gba) move $4, reg_cycles # Remaining cycles as asg0 cfncall update_gba, 0 # process the next event - lw $1, COMPLETED_FRAME($16) # Check whether we completed a frame - bne $1, $0, return_to_main # Return to main thread now + bltz $2, return_to_main # Exit if a frame is complete (bit 31 is set) and reg_cycles, $2, 0x7FFF # update new cycle count (ret value) - bltz $2, lookup_pc + sll $1, $2, 1 # Check bit 30 now (PC changed) + bltz $1, lookup_pc lw $ra, REG_SAVE2($16) # restore return address restore_registers @@ -344,8 +344,7 @@ cpu_sleep_loop: move $4, reg_cycles # Remaining cycles as asg0 cfncall update_gba, 0 # process the next event - lw $1, COMPLETED_FRAME($16) # Check whether we completed a frame - bne $1, $0, return_to_main # Return to main thread now + bltz $2, return_to_main # Exit if a frame is complete (bit 31 is set) # since no frame was completed, this means CPU is active again. # Fall through to lookup_pc to resume execution diff --git a/savestate.c b/savestate.c index 7d3b539..36c64e8 100644 --- a/savestate.c +++ b/savestate.c @@ -107,7 +107,6 @@ bool gba_load_state(const void* src) #endif instruction_count = 0; - reg[COMPLETED_FRAME] = 0; reg[OAM_UPDATED] = 1; return true; diff --git a/x86/x86_stub.S b/x86/x86_stub.S index 1a96654..cbd2c94 100644 --- a/x86/x86_stub.S +++ b/x86/x86_stub.S @@ -95,7 +95,7 @@ _##symbol: .equ REG_Z_FLAG, (21 * 4) .equ REG_C_FLAG, (22 * 4) .equ REG_V_FLAG, (23 * 4) -.equ COMPLETED_FRAME, (24 * 4) +.equ REG_UNUSED_1, (24 * 4) .equ OAM_UPDATED, (25 * 4) .equ REG_SAVE, (26 * 4) @@ -170,17 +170,19 @@ defsymbl(x86_update_gba) mov REG_CYCLES, CARG1_REG # Load remaining cycles as arg0 CALL_FUNC(update_gba) # process the next event + + # did we just complete a frame? go back to main then + test %eax, %eax # Bit 31 set, means new frame completed + js return_to_main + + # Load new cycle counter mov %eax, REG_CYCLES # new cycle count and $0x7fff, REG_CYCLES # in the lowest bits - # did we just complete a frame? go back to main then - cmpl $0, COMPLETED_FRAME(REG_BASE) - jne return_to_main - - # did the PC change? - test %eax, %eax # Bit 31 set, means need to re-fetch - js lookup_pc - ret # otherwise, go back to caller + # did the PC change? Bit 30 will be set + test $0x40000000, %eax + jne lookup_pc + ret # otherwise, go back to caller (resume) # Perform this on an indirect branch that will definitely go to # ARM code, IE anything that changes the PC in ARM mode except @@ -265,9 +267,9 @@ cpu_sleep_loop: mov REG_CYCLES, CARG1_REG # Load remaining cycles as arg0 CALL_FUNC(update_gba) # process the next event - # did we just complete a frame? go back to main then - cmpl $0, COMPLETED_FRAME(REG_BASE) - jne return_to_main + # did we just complete a frame (MSB set)? go back to main then + test %eax, %eax + js return_to_main // if we are out of update_gba and did not complete a frame, cpu is active mov %eax, REG_CYCLES # load new cycle count