diff options
-rw-r--r-- | src/devices/cpu/mips/r4000.cpp | 169 | ||||
-rw-r--r-- | src/devices/cpu/mips/r4000.h | 24 |
2 files changed, 69 insertions, 124 deletions
diff --git a/src/devices/cpu/mips/r4000.cpp b/src/devices/cpu/mips/r4000.cpp index 059dfb47540..eb2cff471d2 100644 --- a/src/devices/cpu/mips/r4000.cpp +++ b/src/devices/cpu/mips/r4000.cpp @@ -281,7 +281,7 @@ std::unique_ptr<util::disasm_interface> r4000_base_device::create_disassembler() void r4000_base_device::execute_run() { - while (m_icount-- > 0) + while (m_icount > 0) { debugger_instruction_hook(m_pc); @@ -298,35 +298,33 @@ void r4000_base_device::execute_run() m_r[0] = 0; }); - if (m_hilo_delay) - m_hilo_delay--; - // update pc and branch state - switch (m_branch_state) + switch (m_branch_state & STATE) { case NONE: m_pc += 4; break; - case DELAY: + case BRANCH: + m_pc = m_branch_state & TARGET; m_branch_state = NONE; - m_pc = m_branch_target; break; - case BRANCH: - m_branch_state = DELAY; + case DELAY: m_pc += 4; - break; - - case EXCEPTION: - m_branch_state = NONE; + m_branch_state = (m_branch_state & TARGET) | BRANCH; break; case NULLIFY: - m_branch_state = NONE; m_pc += 8; + m_branch_state = NONE; 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)); break; case 0x08: // JR - m_branch_state = BRANCH; - m_branch_target = ADDR(m_r[RSREG], 0); + // FIXME: address error if low bits are set + m_branch_state = ADDR(m_r[RSREG], 0) | DELAY; break; case 0x09: // JALR - m_branch_state = BRANCH; - m_branch_target = ADDR(m_r[RSREG], 0); + // FIXME: address error if low bits are set + m_branch_state = ADDR(m_r[RSREG], 0) | DELAY; m_r[RDREG] = ADDR(m_pc, 8); break; //case 0x0a: // * @@ -656,33 +654,21 @@ void r4000_base_device::cpu_execute(u32 const op) { case 0x00: // BLTZ if (s64(m_r[RSREG]) < 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; break; case 0x01: // BGEZ if (s64(m_r[RSREG]) >= 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; break; case 0x02: // BLTZL if (s64(m_r[RSREG]) < 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; break; case 0x03: // BGEZL if (s64(m_r[RSREG]) >= 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; break; @@ -718,36 +704,24 @@ void r4000_base_device::cpu_execute(u32 const op) //case 0x0f: // * case 0x10: // BLTZAL if (s64(m_r[RSREG]) < 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; m_r[31] = ADDR(m_pc, 8); break; case 0x11: // BGEZAL if (s64(m_r[RSREG]) >= 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; m_r[31] = ADDR(m_pc, 8); break; case 0x12: // BLTZALL if (s64(m_r[RSREG]) < 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; m_r[31] = ADDR(m_pc, 8); break; case 0x13: // BGEZALL if (s64(m_r[RSREG]) >= 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; m_r[31] = ADDR(m_pc, 8); @@ -774,41 +748,27 @@ void r4000_base_device::cpu_execute(u32 const op) } break; case 0x02: // J - m_branch_state = BRANCH; - m_branch_target = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2); + m_branch_state = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2) | DELAY; break; case 0x03: // JAL - m_branch_state = BRANCH; - m_branch_target = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2); + m_branch_state = (ADDR(m_pc, 4) & ~0x0fffffffULL) | ((op & 0x03ffffffU) << 2) | DELAY; m_r[31] = ADDR(m_pc, 8); break; case 0x04: // BEQ if (m_r[RSREG] == m_r[RTREG]) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; break; case 0x05: // BNE if (m_r[RSREG] != m_r[RTREG]) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; break; case 0x06: // BLEZ if (s64(m_r[RSREG]) <= 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; break; case 0x07: // BGTZ if (s64(m_r[RSREG]) > 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; break; case 0x08: // ADDI { @@ -856,37 +816,25 @@ void r4000_base_device::cpu_execute(u32 const op) break; case 0x14: // BEQL if (m_r[RSREG] == m_r[RTREG]) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; break; case 0x15: // BNEL if (m_r[RSREG] != m_r[RTREG]) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; break; case 0x16: // BLEZL if (s64(m_r[RSREG]) <= 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; break; case 0x17: // BGTZL if (s64(m_r[RSREG]) > 0) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; break; @@ -1205,8 +1153,8 @@ void r4000_base_device::cpu_exception(u32 exception, u16 const vector) CAUSE = (CAUSE & CAUSE_IP) | exception; - // if in a branch delay slot, restart at the branch instruction - if (m_branch_state == DELAY) + // if executing a delay slot instruction, restart from the branch + if ((m_branch_state & STATE) == BRANCH) { m_cp0[CP0_EPC] -= 4; CAUSE |= CAUSE_BD; @@ -1217,10 +1165,20 @@ void r4000_base_device::cpu_exception(u32 exception, u16 const vector) else CAUSE = (CAUSE & (CAUSE_BD | CAUSE_IP)) | exception; - m_branch_state = EXCEPTION; - m_pc = ((SR & SR_BEV) ? s64(s32(0xbfc00200)) : s64(s32(0x80000000))) + vector; + m_branch_state = (((SR & SR_BEV) ? s64(s32(0xbfc00200)) : s64(s32(0x80000000))) + vector) | BRANCH; - 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); } @@ -1395,14 +1353,12 @@ void r4000_base_device::cp0_execute(u32 const op) case 0x18: // ERET if (SR & SR_ERL) { - m_branch_state = EXCEPTION; - m_pc = m_cp0[CP0_ErrorEPC]; + m_branch_state = m_cp0[CP0_ErrorEPC] | BRANCH; SR &= ~SR_ERL; } else { - m_branch_state = EXCEPTION; - m_pc = m_cp0[CP0_EPC]; + m_branch_state = m_cp0[CP0_EPC] | BRANCH; SR &= ~SR_EXL; } @@ -2255,33 +2211,21 @@ void r4000_base_device::cp1_execute(u32 const op) { case 0x00: // BC1F if (!(m_fcr31 & FCR31_C)) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; break; case 0x01: // BC1T if (m_fcr31 & FCR31_C) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; break; case 0x02: // BC1FL if (!(m_fcr31 & FCR31_C)) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; break; case 0x03: // BC1TL if (m_fcr31 & FCR31_C) - { - m_branch_state = BRANCH; - m_branch_target = ADDR(m_pc + 4, s32(s16(op)) << 2); - } + m_branch_state = ADDR(m_pc + 4, s32(s16(op)) << 2) | DELAY; else m_branch_state = NULLIFY; break; @@ -3133,8 +3077,7 @@ void r4000_base_device::cp1_execute(u32 const op) break; 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; } } diff --git a/src/devices/cpu/mips/r4000.h b/src/devices/cpu/mips/r4000.h index 18012d2a546..90398b15803 100644 --- a/src/devices/cpu/mips/r4000.h +++ b/src/devices/cpu/mips/r4000.h @@ -368,7 +368,7 @@ protected: void cp2_execute(u32 const op); // 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); 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, 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 int m_icount; @@ -412,16 +423,7 @@ protected: u64 m_r[32]; u64 m_hi; u64 m_lo; - enum branch_state : unsigned - { - 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; + u64 m_branch_state; // cp0 state u64 m_cp0[32]; |