Better cycle accounting, taking remainders partially into account
This commit is contained in:
parent
7b181cb6ff
commit
3a6ca8d941
|
@ -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); \
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
8
cpu.c
|
@ -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
19
main.c
|
@ -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
2
main.h
|
@ -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);
|
||||||
|
|
|
@ -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(); \
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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); \
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue