Better cycle accounting, taking remainders partially into account

This commit is contained in:
David Guillen Fandos 2021-12-21 19:59:33 +01:00
parent 7b181cb6ff
commit 3a6ca8d941
10 changed files with 40 additions and 28 deletions

View File

@ -259,6 +259,7 @@ u32 arm_to_a64_reg[] =
#define generate_branch_no_cycle_update(writeback_location, new_pc) \ #define generate_branch_no_cycle_update(writeback_location, new_pc) \
if(pc == idle_loop_target_pc) \ if(pc == idle_loop_target_pc) \
{ \ { \
generate_load_imm(reg_cycles, 0); \
generate_load_pc(reg_a0, new_pc); \ generate_load_pc(reg_a0, new_pc); \
generate_function_call(a64_update_gba); \ generate_function_call(a64_update_gba); \
emit_branch_filler(writeback_location); \ emit_branch_filler(writeback_location); \

View File

@ -149,6 +149,7 @@ defsymbl(a64_update_gba)
consolidate_flags(w0) // update the CPSR consolidate_flags(w0) // update the CPSR
store_registers() // save out registers store_registers() // save out registers
mov w0, reg_cycles // load remaining cycles
bl update_gba // update GBA state bl update_gba // update GBA state
ldr w1, [reg_base, #COMPLETED_FRAME] // return to main if new frame ldr w1, [reg_base, #COMPLETED_FRAME] // return to main if new frame
@ -682,7 +683,9 @@ write_epilogue:
beq smc_write // if so, goto SMC handler beq smc_write // if so, goto SMC handler
alert_loop: alert_loop:
mov w0, reg_cycles // load remaining cycles
bl update_gba // update GBA until CPU isn't halted bl update_gba // update GBA until CPU isn't halted
mov reg_cycles, w0 // load new cycle count
ldr w1, [reg_base, #COMPLETED_FRAME] // Check whether a frame was completed ldr w1, [reg_base, #COMPLETED_FRAME] // Check whether a frame was completed
cbnz w1, return_to_main // and return to caller function. cbnz w1, return_to_main // and return to caller function.
@ -690,7 +693,6 @@ alert_loop:
ldr w1, [reg_base, #CPU_HALT_STATE] // Check whether the CPU is halted ldr w1, [reg_base, #CPU_HALT_STATE] // Check whether the CPU is halted
cbnz w1, alert_loop // and keep looping until it is cbnz w1, alert_loop // and keep looping until it is
mov reg_cycles, w0 // load new cycle count
ldr w0, [reg_base, #REG_PC] // load new PC ldr w0, [reg_base, #REG_PC] // load new PC
b lookup_pc // Resume execution at that PC b lookup_pc // Resume execution at that PC

View File

@ -163,18 +163,14 @@ _##symbol:
@ Input: @ Input:
@ r0: current PC @ r0: current PC
#define return_straight() ;\ #define return_straight() bx lr
bx lr ;\ #define return_add() add pc, lr, #4
#define return_add() ;\ #define load_pc_straight() ldr r0, [lr, #-12]
add pc, lr, #4 ;\ #define load_pc_add() ldr r0, [lr]
#define load_pc_straight() ;\
ldr r0, [lr, #-12] ;\
#define load_pc_add() ;\
ldr r0, [lr] ;\
#define cycles_straight() mvn r0, reg_cycles
#define cycles_add() mov r0, #0
#define arm_update_gba_builder(name, mode, return_op) ;\ #define arm_update_gba_builder(name, mode, return_op) ;\
;\ ;\
@ -186,6 +182,7 @@ defsymbl(arm_update_gba_##name) ;\
collapse_flags(r0) /* update the flags */;\ collapse_flags(r0) /* update the flags */;\
;\ ;\
store_registers_##mode() /* save out registers */;\ store_registers_##mode() /* save out registers */;\
cycles_##return_op() /* remaining cycles in arg0 */;\
call_c_function(update_gba) /* update GBA state */;\ call_c_function(update_gba) /* update GBA state */;\
;\ ;\
ldr r1, [reg_base, #COMPLETED_FRAME] /* return if new frame */;\ ldr r1, [reg_base, #COMPLETED_FRAME] /* return if new frame */;\

8
cpu.c
View File

@ -1635,7 +1635,7 @@ void execute_arm(u32 cycles)
{ {
/* Do not execute until CPU is active */ /* Do not execute until CPU is active */
while(reg[CPU_HALT_STATE] != CPU_ACTIVE) { while(reg[CPU_HALT_STATE] != CPU_ACTIVE) {
cycles_remaining = update_gba(); cycles_remaining = update_gba(cycles_remaining);
if (reg[COMPLETED_FRAME]) if (reg[COMPLETED_FRAME])
return; return;
@ -3225,7 +3225,7 @@ skip_instruction:
} while(cycles_remaining > 0); } while(cycles_remaining > 0);
collapse_flags(); collapse_flags();
cycles_remaining = update_gba(); cycles_remaining = update_gba(cycles_remaining);
if (reg[COMPLETED_FRAME]) if (reg[COMPLETED_FRAME])
return; return;
continue; continue;
@ -3738,7 +3738,7 @@ thumb_loop:
} while(cycles_remaining > 0); } while(cycles_remaining > 0);
collapse_flags(); collapse_flags();
cycles_remaining = update_gba(); cycles_remaining = update_gba(cycles_remaining);
if (reg[COMPLETED_FRAME]) if (reg[COMPLETED_FRAME])
return; return;
continue; continue;
@ -3749,7 +3749,7 @@ thumb_loop:
collapse_flags(); collapse_flags();
while(reg[CPU_HALT_STATE] != CPU_ACTIVE) { while(reg[CPU_HALT_STATE] != CPU_ACTIVE) {
cycles_remaining = update_gba(); cycles_remaining = update_gba(cycles_remaining);
if (reg[COMPLETED_FRAME]) if (reg[COMPLETED_FRAME])
return; return;
} }

19
main.c
View File

@ -39,7 +39,7 @@ char save_path[512];
void trigger_ext_event(void); void trigger_ext_event(void);
static void update_timers(irq_type *irq_raised) static void update_timers(irq_type *irq_raised, unsigned completed_cycles)
{ {
unsigned i; unsigned i;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
@ -49,7 +49,7 @@ static void update_timers(irq_type *irq_raised)
if(timer[i].status != TIMER_CASCADE) if(timer[i].status != TIMER_CASCADE)
{ {
timer[i].count -= execute_cycles; timer[i].count -= completed_cycles;
/* io_registers accessors range: REG_TM0D, REG_TM1D, REG_TM2D, REG_TM3D */ /* io_registers accessors range: REG_TM0D, REG_TM1D, REG_TM2D, REG_TM3D */
write_ioreg(REG_TM0D + (i * 2), -(timer[i].count > timer[i].prescale)); write_ioreg(REG_TM0D + (i * 2), -(timer[i].count > timer[i].prescale));
} }
@ -106,15 +106,20 @@ void init_main(void)
#endif #endif
} }
u32 update_gba(void) u32 update_gba(int remaining_cycles)
{ {
irq_type irq_raised = IRQ_NONE; irq_type irq_raised = IRQ_NONE;
remaining_cycles = MAX(remaining_cycles, -64);
do do
{ {
unsigned i; unsigned i;
cpu_ticks += execute_cycles; // Number of cycles we ask to run - cycles that we did not execute
// (remaining_cycles can be negative and should be close to zero)
unsigned completed_cycles = execute_cycles - remaining_cycles;
cpu_ticks += completed_cycles;
remaining_cycles = 0;
reg[CHANGED_PC_STATUS] = 0; reg[CHANGED_PC_STATUS] = 0;
reg[COMPLETED_FRAME] = 0; reg[COMPLETED_FRAME] = 0;
@ -125,9 +130,9 @@ u32 update_gba(void)
gbc_sound_update = 0; gbc_sound_update = 0;
} }
update_timers(&irq_raised); update_timers(&irq_raised, completed_cycles);
video_count -= execute_cycles; video_count -= completed_cycles;
if(video_count <= 0) if(video_count <= 0)
{ {
@ -235,7 +240,7 @@ u32 update_gba(void)
if(irq_raised) if(irq_raised)
raise_interrupt(irq_raised); raise_interrupt(irq_raised);
execute_cycles = video_count; execute_cycles = MAX(video_count, 0);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {

2
main.h
View File

@ -76,7 +76,7 @@ extern u32 flush_ram_count;
extern char main_path[512]; extern char main_path[512];
extern char save_path[512]; extern char save_path[512];
u32 update_gba(void); u32 update_gba(int remaining_cycles);
void reset_gba(void); void reset_gba(void);
void init_main(void); void init_main(void);

View File

@ -231,6 +231,7 @@ u32 arm_to_mips_reg[] =
if(pc == idle_loop_target_pc) \ if(pc == idle_loop_target_pc) \
{ \ { \
generate_load_pc(reg_a0, new_pc); \ generate_load_pc(reg_a0, new_pc); \
mips_emit_lui(reg_cycles, 0); \
generate_function_call_swap_delay(mips_update_gba); \ generate_function_call_swap_delay(mips_update_gba); \
mips_emit_j_filler(writeback_location); \ mips_emit_j_filler(writeback_location); \
mips_emit_nop(); \ mips_emit_nop(); \

View File

@ -119,6 +119,8 @@ symbol:
.equ FNPTRS_MEMOPS, (REGMODE_BASE + 196) .equ FNPTRS_MEMOPS, (REGMODE_BASE + 196)
.equ FNPTRS_BASE, (FNPTRS_MEMOPS + 960*2) .equ FNPTRS_BASE, (FNPTRS_MEMOPS + 960*2)
#define reg_cycles $17
.set noat .set noat
.set noreorder .set noreorder
@ -240,12 +242,13 @@ defsymbl(mips_update_gba)
collapse_flags # update cpsr collapse_flags # update cpsr
save_registers # save registers save_registers # save registers
sw $0, CHANGED_PC_STATUS($16) sw $0, CHANGED_PC_STATUS($16)
move $4, reg_cycles # Remaining cycles as asg0
cfncall update_gba, 0 # process the next event cfncall update_gba, 0 # process the next event
lw $1, COMPLETED_FRAME($16) # Check whether we completed a frame lw $1, COMPLETED_FRAME($16) # Check whether we completed a frame
bne $1, $0, return_to_main # Return to main thread now bne $1, $0, return_to_main # Return to main thread now
addu $17, $2, $0 # $17 = new cycle count (ret value) move reg_cycles, $2 # update new cycle count (ret value)
lw $ra, REG_SAVE2($16) # restore return address lw $ra, REG_SAVE2($16) # restore return address
@ -327,7 +330,9 @@ defsymbl(write_io_epilogue)
alert_loop: alert_loop:
move $4, reg_cycles # Remaining cycles as asg0
cfncall update_gba, 0 # process the next event cfncall update_gba, 0 # process the next event
move reg_cycles, $2 # update new cycle count (ret value)
lw $1, COMPLETED_FRAME($16) # Check whether we completed a frame lw $1, COMPLETED_FRAME($16) # Check whether we completed a frame
bne $1, $0, return_to_main # Return to main thread now bne $1, $0, return_to_main # Return to main thread now
@ -336,7 +341,6 @@ alert_loop:
bne $1, $0, alert_loop # see if it hasn't changed bne $1, $0, alert_loop # see if it hasn't changed
nop nop
addu $17, $2, $0 # $17 = new cycle counter
lw $4, REG_PC($16) # $4 = new PC lw $4, REG_PC($16) # $4 = new PC
j lookup_pc j lookup_pc
@ -522,7 +526,7 @@ defsymbl(execute_arm_translate_internal)
move $16, $5 move $16, $5
REG_S $28, GP_SAVE($16) REG_S $28, GP_SAVE($16)
addu $17, $4, $0 # load cycle counter register move reg_cycles, $4 # load cycle counter register
extract_flags # load flag variables extract_flags # load flag variables

View File

@ -585,6 +585,7 @@ typedef enum
#define generate_branch_no_cycle_update(writeback_location, new_pc) \ #define generate_branch_no_cycle_update(writeback_location, new_pc) \
if(pc == idle_loop_target_pc) \ if(pc == idle_loop_target_pc) \
{ \ { \
generate_load_imm(cycles, 0); \
x86_emit_mov_reg_imm(eax, new_pc); \ x86_emit_mov_reg_imm(eax, new_pc); \
generate_function_call(x86_update_gba); \ generate_function_call(x86_update_gba); \
x86_emit_jmp_filler(writeback_location); \ x86_emit_jmp_filler(writeback_location); \

View File

@ -166,8 +166,8 @@ defsymbl(x86_update_gba)
mov %eax, REG_PC(REG_BASE) # current PC = eax mov %eax, REG_PC(REG_BASE) # current PC = eax
collapse_flags # update cpsr, trashes ecx and edx collapse_flags # update cpsr, trashes ecx and edx
mov REG_CYCLES, CARG1_REG # Load remaining cycles as arg0
CALL_FUNC(update_gba) # process the next event CALL_FUNC(update_gba) # process the next event
mov %eax, REG_CYCLES # new cycle count mov %eax, REG_CYCLES # new cycle count
# did we just complete a frame? go back to main then # did we just complete a frame? go back to main then
@ -246,7 +246,9 @@ write_epilogue:
je smc_write je smc_write
alert_loop: alert_loop:
mov REG_CYCLES, CARG1_REG # Load remaining cycles as arg0
CALL_FUNC(update_gba) # process the next event CALL_FUNC(update_gba) # process the next event
mov %eax, REG_CYCLES # load new cycle count
# did we just complete a frame? go back to main then # did we just complete a frame? go back to main then
cmpl $0, COMPLETED_FRAME(REG_BASE) cmpl $0, COMPLETED_FRAME(REG_BASE)
@ -258,7 +260,6 @@ alert_loop:
cmp $0, %edx # 0 means it has cmp $0, %edx # 0 means it has
jnz alert_loop # if not go again jnz alert_loop # if not go again
mov %eax, REG_CYCLES # load new cycle count
jmp lookup_pc # pc has definitely changed jmp lookup_pc # pc has definitely changed
no_alert: no_alert: