r4000: simplify branch state

This commit is contained in:
Patrick Mackinlay 2021-04-02 13:53:28 +07:00
parent 41a0233715
commit 33ac8ffd54
2 changed files with 70 additions and 125 deletions

View File

@ -281,7 +281,7 @@ std::unique_ptr<util::disasm_interface> r4000_base_device::create_disassembler()
void r4000_base_device::execute_run() void r4000_base_device::execute_run()
{ {
while (m_icount-- > 0) while (m_icount > 0)
{ {
debugger_instruction_hook(m_pc); debugger_instruction_hook(m_pc);
@ -298,35 +298,33 @@ void r4000_base_device::execute_run()
m_r[0] = 0; m_r[0] = 0;
}); });
if (m_hilo_delay)
m_hilo_delay--;
// update pc and branch state // update pc and branch state
switch (m_branch_state) switch (m_branch_state & STATE)
{ {
case NONE: case NONE:
m_pc += 4; m_pc += 4;
break; break;
case DELAY:
m_branch_state = NONE;
m_pc = m_branch_target;
break;
case BRANCH: case BRANCH:
m_branch_state = DELAY; m_pc = m_branch_state & TARGET;
m_pc += 4; m_branch_state = NONE;
break; break;
case EXCEPTION: case DELAY:
m_branch_state = NONE; m_pc += 4;
m_branch_state = (m_branch_state & TARGET) | BRANCH;
break; break;
case NULLIFY: case NULLIFY:
m_branch_state = NONE;
m_pc += 8; m_pc += 8;
m_branch_state = NONE;
break; break;
} }
if (m_hilo_delay)
m_hilo_delay--;
m_icount--;
} }
} }
@ -366,12 +364,12 @@ void r4000_base_device::cpu_execute(u32 const op)
m_r[RDREG] = s64(s32(m_r[RTREG]) >> (m_r[RSREG] & 31)); m_r[RDREG] = s64(s32(m_r[RTREG]) >> (m_r[RSREG] & 31));
break; break;
case 0x08: // JR case 0x08: // JR
m_branch_state = BRANCH; // FIXME: address error if low bits are set
m_branch_target = ADDR(m_r[RSREG], 0); m_branch_state = ADDR(m_r[RSREG], 0) | DELAY;
break; break;
case 0x09: // JALR case 0x09: // JALR
m_branch_state = BRANCH; // FIXME: address error if low bits are set
m_branch_target = ADDR(m_r[RSREG], 0); m_branch_state = ADDR(m_r[RSREG], 0) | DELAY;
m_r[RDREG] = ADDR(m_pc, 8); m_r[RDREG] = ADDR(m_pc, 8);
break; break;
//case 0x0a: // * //case 0x0a: // *
@ -656,33 +654,21 @@ void r4000_base_device::cpu_execute(u32 const op)
{ {
case 0x00: // BLTZ case 0x00: // BLTZ
if (s64(m_r[RSREG]) < 0) if (s64(m_r[RSREG]) < 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
break; break;
case 0x01: // BGEZ case 0x01: // BGEZ
if (s64(m_r[RSREG]) >= 0) if (s64(m_r[RSREG]) >= 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
break; break;
case 0x02: // BLTZL case 0x02: // BLTZL
if (s64(m_r[RSREG]) < 0) if (s64(m_r[RSREG]) < 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
break; break;
case 0x03: // BGEZL case 0x03: // BGEZL
if (s64(m_r[RSREG]) >= 0) if (s64(m_r[RSREG]) >= 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
break; break;
@ -718,36 +704,24 @@ void r4000_base_device::cpu_execute(u32 const op)
//case 0x0f: // * //case 0x0f: // *
case 0x10: // BLTZAL case 0x10: // BLTZAL
if (s64(m_r[RSREG]) < 0) if (s64(m_r[RSREG]) < 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
m_r[31] = ADDR(m_pc, 8); m_r[31] = ADDR(m_pc, 8);
break; break;
case 0x11: // BGEZAL case 0x11: // BGEZAL
if (s64(m_r[RSREG]) >= 0) if (s64(m_r[RSREG]) >= 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
m_r[31] = ADDR(m_pc, 8); m_r[31] = ADDR(m_pc, 8);
break; break;
case 0x12: // BLTZALL case 0x12: // BLTZALL
if (s64(m_r[RSREG]) < 0) if (s64(m_r[RSREG]) < 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
m_r[31] = ADDR(m_pc, 8); m_r[31] = ADDR(m_pc, 8);
break; break;
case 0x13: // BGEZALL case 0x13: // BGEZALL
if (s64(m_r[RSREG]) >= 0) if (s64(m_r[RSREG]) >= 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
m_r[31] = ADDR(m_pc, 8); m_r[31] = ADDR(m_pc, 8);
@ -774,41 +748,27 @@ void r4000_base_device::cpu_execute(u32 const op)
} }
break; break;
case 0x02: // J case 0x02: // J
m_branch_state = BRANCH; m_branch_state = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2) | DELAY;
m_branch_target = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2);
break; break;
case 0x03: // JAL case 0x03: // JAL
m_branch_state = BRANCH; m_branch_state = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2) | DELAY;
m_branch_target = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2);
m_r[31] = ADDR(m_pc, 8); m_r[31] = ADDR(m_pc, 8);
break; break;
case 0x04: // BEQ case 0x04: // BEQ
if (m_r[RSREG] == m_r[RTREG]) if (m_r[RSREG] == m_r[RTREG])
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
break; break;
case 0x05: // BNE case 0x05: // BNE
if (m_r[RSREG] != m_r[RTREG]) if (m_r[RSREG] != m_r[RTREG])
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
break; break;
case 0x06: // BLEZ case 0x06: // BLEZ
if (s64(m_r[RSREG]) <= 0) if (s64(m_r[RSREG]) <= 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
break; break;
case 0x07: // BGTZ case 0x07: // BGTZ
if (s64(m_r[RSREG]) > 0) if (s64(m_r[RSREG]) > 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
break; break;
case 0x08: // ADDI case 0x08: // ADDI
{ {
@ -856,37 +816,25 @@ void r4000_base_device::cpu_execute(u32 const op)
break; break;
case 0x14: // BEQL case 0x14: // BEQL
if (m_r[RSREG] == m_r[RTREG]) if (m_r[RSREG] == m_r[RTREG])
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
break; break;
case 0x15: // BNEL case 0x15: // BNEL
if (m_r[RSREG] != m_r[RTREG]) if (m_r[RSREG] != m_r[RTREG])
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
break; break;
case 0x16: // BLEZL case 0x16: // BLEZL
if (s64(m_r[RSREG]) <= 0) if (s64(m_r[RSREG]) <= 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
break; break;
case 0x17: // BGTZL case 0x17: // BGTZL
if (s64(m_r[RSREG]) > 0) if (s64(m_r[RSREG]) > 0)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
break; break;
@ -1205,8 +1153,8 @@ void r4000_base_device::cpu_exception(u32 exception, u16 const vector)
CAUSE = (CAUSE & CAUSE_IP) | exception; CAUSE = (CAUSE & CAUSE_IP) | exception;
// if in a branch delay slot, restart at the branch instruction // if executing a delay slot instruction, restart from the branch
if (m_branch_state == DELAY) if ((m_branch_state & STATE) == BRANCH)
{ {
m_cp0[CP0_EPC] -= 4; m_cp0[CP0_EPC] -= 4;
CAUSE |= CAUSE_BD; CAUSE |= CAUSE_BD;
@ -1217,10 +1165,20 @@ void r4000_base_device::cpu_exception(u32 exception, u16 const vector)
else else
CAUSE = (CAUSE & (CAUSE_BD | CAUSE_IP)) | exception; CAUSE = (CAUSE & (CAUSE_BD | CAUSE_IP)) | exception;
m_branch_state = EXCEPTION; m_branch_state = (((SR & SR_BEV) ? s64(s32(0xbfc00200)) : s64(s32(0x80000000))) + vector) | BRANCH;
m_pc = ((SR & SR_BEV) ? s64(s32(0xbfc00200)) : s64(s32(0x80000000))) + vector;
if (exception != EXCEPTION_INT) if (exception == EXCEPTION_INT)
{
if (machine().debug_flags & DEBUG_FLAG_ENABLED)
{
// notify the debugger of the first pending hardware interrupt
u32 const iphw = CAUSE & SR & CAUSE_IPHW;
if (iphw)
debug()->interrupt_hook(22 - count_leading_zeros((iphw - 1) & ~iphw));
}
}
else
debugger_exception_hook(exception); debugger_exception_hook(exception);
} }
@ -1395,14 +1353,12 @@ void r4000_base_device::cp0_execute(u32 const op)
case 0x18: // ERET case 0x18: // ERET
if (SR & SR_ERL) if (SR & SR_ERL)
{ {
m_branch_state = EXCEPTION; m_branch_state = m_cp0[CP0_ErrorEPC] | BRANCH;
m_pc = m_cp0[CP0_ErrorEPC];
SR &= ~SR_ERL; SR &= ~SR_ERL;
} }
else else
{ {
m_branch_state = EXCEPTION; m_branch_state = m_cp0[CP0_EPC] | BRANCH;
m_pc = m_cp0[CP0_EPC];
SR &= ~SR_EXL; SR &= ~SR_EXL;
} }
@ -2255,33 +2211,21 @@ void r4000_base_device::cp1_execute(u32 const op)
{ {
case 0x00: // BC1F case 0x00: // BC1F
if (!(m_fcr31 & FCR31_C)) if (!(m_fcr31 & FCR31_C))
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
break; break;
case 0x01: // BC1T case 0x01: // BC1T
if (m_fcr31 & FCR31_C) if (m_fcr31 & FCR31_C)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
break; break;
case 0x02: // BC1FL case 0x02: // BC1FL
if (!(m_fcr31 & FCR31_C)) if (!(m_fcr31 & FCR31_C))
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
break; break;
case 0x03: // BC1TL case 0x03: // BC1TL
if (m_fcr31 & FCR31_C) if (m_fcr31 & FCR31_C)
{ m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY;
m_branch_state = BRANCH;
m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2);
}
else else
m_branch_state = NULLIFY; m_branch_state = NULLIFY;
break; break;
@ -3133,8 +3077,7 @@ void r4000_base_device::cp1_execute(u32 const op)
break; break;
case 0x3d: // SDC1 case 0x3d: // SDC1
if ((SR & SR_FR) || !(RTREG & 1)) store<u64>(ADDR(m_r[RSREG], s16(op)), m_f[RTREG]);
store<u64>(ADDR(m_r[RSREG], s16(op)), m_f[RTREG]);
break; break;
} }
} }

View File

@ -368,7 +368,7 @@ protected:
void cp2_execute(u32 const op); void cp2_execute(u32 const op);
// address and memory handling // address and memory handling
enum translate_result { ERROR, MISS, UNCACHED, CACHED }; enum translate_result : unsigned { ERROR, MISS, UNCACHED, CACHED };
translate_result translate(int intention, u64 &address); translate_result translate(int intention, u64 &address);
void address_error(int intention, u64 const address); void address_error(int intention, u64 const address);
@ -400,6 +400,17 @@ protected:
std::function<void(offs_t offset, u32 data, u32 mem_mask)> write_dword; std::function<void(offs_t offset, u32 data, u32 mem_mask)> write_dword;
std::function<void(offs_t offset, u64 data, u64 mem_mask)> write_qword; std::function<void(offs_t offset, u64 data, u64 mem_mask)> write_qword;
enum branch_state : u64
{
STATE = 0x00000000'00000003,
TARGET = 0xffffffff'fffffffc,
NONE = 0,
BRANCH = 1, // retire delayed branch
DELAY = 2, // delay slot instruction
NULLIFY = 3, // next instruction nullified
};
// runtime state // runtime state
int m_icount; int m_icount;
@ -412,16 +423,7 @@ protected:
u64 m_r[32]; u64 m_r[32];
u64 m_hi; u64 m_hi;
u64 m_lo; u64 m_lo;
enum branch_state : unsigned u64 m_branch_state;
{
NONE = 0,
DELAY = 1, // delay slot instruction active
BRANCH = 2, // branch instruction active
EXCEPTION = 3, // exception triggered
NULLIFY = 4, // next instruction nullified
}
m_branch_state;
u64 m_branch_target;
// cp0 state // cp0 state
u64 m_cp0[32]; u64 m_cp0[32];