[mips] Fix CPSR store bug during IRQ
Similarly to 61ef776
, this fixes the bug for MIPS.
This commit is contained in:
parent
61ef776fed
commit
31451d16ff
|
@ -52,9 +52,6 @@ u32 execute_spsr_restore(u32 address);
|
|||
void execute_store_cpsr(u32 new_cpsr, u32 store_mask);
|
||||
void execute_store_spsr(u32 new_spsr, u32 store_mask);
|
||||
|
||||
u32 execute_spsr_restore_body(u32 address);
|
||||
u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address);
|
||||
|
||||
|
||||
#define reg_base mips_reg_s0
|
||||
#define reg_cycles mips_reg_s1
|
||||
|
@ -1222,21 +1219,17 @@ u32 execute_spsr_restore_body(u32 address)
|
|||
generate_function_call(execute_read_##psr_reg); \
|
||||
generate_store_reg(reg_rv, rd) \
|
||||
|
||||
u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address)
|
||||
u32 execute_store_cpsr_body(u32 _cpsr, u32 address)
|
||||
{
|
||||
reg[REG_CPSR] = _cpsr;
|
||||
if(store_mask & 0xFF)
|
||||
set_cpu_mode(cpu_modes[_cpsr & 0x1F]);
|
||||
if((io_registers[REG_IE] & io_registers[REG_IF]) &&
|
||||
io_registers[REG_IME] && ((_cpsr & 0x80) == 0))
|
||||
{
|
||||
set_cpu_mode(cpu_modes[_cpsr & 0x1F]);
|
||||
if((io_registers[REG_IE] & io_registers[REG_IF]) &&
|
||||
io_registers[REG_IME] && ((_cpsr & 0x80) == 0))
|
||||
{
|
||||
reg_mode[MODE_IRQ][6] = address + 4;
|
||||
spsr[MODE_IRQ] = _cpsr;
|
||||
reg[REG_CPSR] = 0xD2;
|
||||
set_cpu_mode(MODE_IRQ);
|
||||
return 0x00000018;
|
||||
}
|
||||
reg_mode[MODE_IRQ][6] = address + 4;
|
||||
spsr[MODE_IRQ] = _cpsr;
|
||||
reg[REG_CPSR] = 0xD2;
|
||||
set_cpu_mode(MODE_IRQ);
|
||||
return 0x00000018;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1250,8 +1243,8 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address)
|
|||
|
||||
#define arm_psr_store(op_type, psr_reg) \
|
||||
arm_psr_load_new_##op_type(); \
|
||||
generate_load_imm(reg_a1, psr_masks[psr_field]); \
|
||||
generate_load_pc(reg_a2, (pc + 4)); \
|
||||
generate_load_pc(reg_a1, (pc)); \
|
||||
generate_load_imm(reg_a2, psr_masks[psr_field]); \
|
||||
generate_function_call_swap_delay(execute_store_##psr_reg) \
|
||||
|
||||
#define arm_psr(op_type, transfer_type, psr_reg) \
|
||||
|
|
|
@ -445,31 +445,39 @@ no_spsr_restore:
|
|||
nop
|
||||
|
||||
# $4: new cpsr
|
||||
# $5: store mask
|
||||
# $6: current PC
|
||||
# $5: current PC
|
||||
# $6: store mask
|
||||
|
||||
defsymbl(execute_store_cpsr)
|
||||
and $1, $4, $5 # $1 = new_cpsr & store_mask
|
||||
and $1, $4, $6 # $1 = new_cpsr & store_mask
|
||||
lw $2, REG_CPSR($16) # $2 = current cpsr
|
||||
nor $4, $5, $0 # $4 = ~store_mask
|
||||
nor $4, $6, $0 # $4 = ~store_mask
|
||||
and $2, $2, $4 # $2 = (cpsr & (~store_mask))
|
||||
or $1, $1, $2 # $1 = new cpsr combined with old
|
||||
extract_flags_body # extract flags from $1
|
||||
|
||||
andi $6, $6, 0xff # Check whether we overwrote mode
|
||||
bnez $6, 1f
|
||||
sw $1, REG_CPSR($16) # Store new CPSR (delay slot)
|
||||
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
1:
|
||||
sw $ra, REG_SAVE3($16)
|
||||
save_registers
|
||||
addu $4, $1, $0 # load the new CPSR
|
||||
cfncall execute_store_cpsr_body, 7 # do the dirty work in this C function
|
||||
|
||||
bne $2, $0, changed_pc_cpsr # this could have changed the pc
|
||||
bnez $2, 2f # this could have changed the pc
|
||||
nop
|
||||
|
||||
restore_registers
|
||||
|
||||
lw $ra, REG_SAVE3($16)
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
changed_pc_cpsr:
|
||||
2:
|
||||
addu $4, $2, $0 # load new address in $4
|
||||
cfncall block_lookup_address_arm, 1 # GBA address is in $4
|
||||
restore_registers # restore registers
|
||||
|
@ -478,16 +486,17 @@ changed_pc_cpsr:
|
|||
|
||||
|
||||
# $4: new spsr
|
||||
# $5: store mask
|
||||
# $5: current PC (unused)
|
||||
# $6: store mask
|
||||
|
||||
defsymbl(execute_store_spsr)
|
||||
lw $1, CPU_MODE($16) # $1 = cpu_mode
|
||||
sll $1, $1, 2 # adjust to word offset size
|
||||
addu $1, $1, $16
|
||||
lw $2, SPSR_BASE($1) # $2 = spsr[cpu_mode]
|
||||
and $4, $4, $5 # $4 = new_spsr & store_mask
|
||||
nor $5, $5, $0 # $5 = ~store_mask
|
||||
and $2, $2, $5 # $2 = (spsr & (~store_mask))
|
||||
and $4, $4, $6 # $4 = new_spsr & store_mask
|
||||
nor $6, $6, $0 # $6 = ~store_mask
|
||||
and $2, $2, $6 # $2 = (spsr & (~store_mask))
|
||||
or $4, $4, $2 # $4 = new spsr combined with old
|
||||
jr $ra # return
|
||||
sw $4, SPSR_BASE($1) # spsr[cpu_mode] = $4 (delay slot)
|
||||
|
|
Loading…
Reference in New Issue