diff options
author | Patrick Mackinlay <pmackinlay@hotmail.com> | 2018-12-18 18:21:19 +0700 |
---|---|---|
committer | Patrick Mackinlay <pmackinlay@hotmail.com> | 2018-12-18 18:21:19 +0700 |
commit | 2af742e9d111a4148ab93fce68f779d618052161 (patch) | |
tree | 0374476bd5c4fca4bd52d8a6060fdc5873c9c59f | |
parent | f74ad668aa0272df0867f5533e4a9dd35c4c7d6b (diff) |
mips1: handle exceptions in delay slot instructions (nw)
I introduced this error when adding tlb support and modifying the exception code previously. This resolves the error, cleans up delayed branch handling and fixes a panic in the mips rx2030 and rx3230 driver.
-rw-r--r-- | src/devices/cpu/mips/mips1.cpp | 66 | ||||
-rw-r--r-- | src/devices/cpu/mips/mips1.h | 62 |
2 files changed, 70 insertions, 58 deletions
diff --git a/src/devices/cpu/mips/mips1.cpp b/src/devices/cpu/mips/mips1.cpp index b2988470a94..a2a4f94ef06 100644 --- a/src/devices/cpu/mips/mips1.cpp +++ b/src/devices/cpu/mips/mips1.cpp @@ -39,12 +39,12 @@ #define UIMMVAL u16(op) #define LIMMVAL (op & 0x03ffffff) -#define ADDPC(x) do { m_nextpc = m_pc + ((x) << 2); } while (0) -#define ADDPCL(x,l) do { m_nextpc = m_pc + ((x) << 2); m_r[l] = m_pc + 4; } while (0) -#define ABSPC(x) do { m_nextpc = (m_pc & 0xf0000000) | ((x) << 2); } while (0) -#define ABSPCL(x,l) do { m_nextpc = (m_pc & 0xf0000000) | ((x) << 2); m_r[l] = m_pc + 4; } while (0) -#define SETPC(x) do { m_nextpc = (x); } while (0) -#define SETPCL(x,l) do { m_nextpc = (x); m_r[l] = m_pc + 4; } while (0) +#define ADDPC(x) do { m_branch_state = BRANCH; m_branch_target = m_pc + 4 + ((x) << 2); } while (0) +#define ADDPCL(x,l) do { m_branch_state = BRANCH; m_branch_target = m_pc + 4 + ((x) << 2); m_r[l] = m_pc + 8; } while (0) +#define ABSPC(x) do { m_branch_state = BRANCH; m_branch_target = ((m_pc + 4) & 0xf0000000) | ((x) << 2); } while (0) +#define ABSPCL(x,l) do { m_branch_state = BRANCH; m_branch_target = ((m_pc + 4) & 0xf0000000) | ((x) << 2); m_r[l] = m_pc + 8; } while (0) +#define SETPC(x) do { m_branch_state = BRANCH; m_branch_target = (x); } while (0) +#define SETPCL(x,l) do { m_branch_state = BRANCH; m_branch_target = (x); m_r[l] = m_pc + 8; } while (0) #define SR m_cpr[0][COP0_Status] #define CAUSE m_cpr[0][COP0_Cause] @@ -61,6 +61,8 @@ DEFINE_DEVICE_TYPE(R3071, r3071_device, "r3071", "IDT R3071") DEFINE_DEVICE_TYPE(R3081, r3081_device, "r3081", "IDT R3081") DEFINE_DEVICE_TYPE(SONYPS2_IOP, iop_device, "sonyiop", "Sony Playstation 2 IOP") +ALLOW_SAVE_TYPE(mips1core_device_base::branch_state_t); + mips1core_device_base::mips1core_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size) : cpu_device(mconfig, type, tag, owner, clock) , m_program_config_be("program", ENDIANNESS_BIG, 32, 32) @@ -71,9 +73,6 @@ mips1core_device_base::mips1core_device_base(const machine_config &mconfig, devi , m_hasfpu(false) , m_fpurev(0) , m_endianness(ENDIANNESS_BIG) - , m_pc(0) - , m_nextpc(0) - , m_ppc(0) , m_icount(0) , m_icache_size(icache_size) , m_dcache_size(dcache_size) @@ -177,7 +176,7 @@ void mips1core_device_base::device_start() // register our state for the debugger state_add(STATE_GENPC, "GENPC", m_pc).noshow(); - state_add(STATE_GENPCBASE, "CURPC", m_ppc).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow(); state_add(STATE_GENSP, "GENSP", m_r[31]).noshow(); state_add(STATE_GENFLAGS, "GENFLAGS", m_cpr[0][COP0_Status]).noshow(); @@ -195,13 +194,13 @@ void mips1core_device_base::device_start() // register our state for saving save_item(NAME(m_pc)); - save_item(NAME(m_nextpc)); save_item(NAME(m_hi)); save_item(NAME(m_lo)); save_item(NAME(m_r)); save_item(NAME(m_cpr)); save_item(NAME(m_ccr)); - save_item(NAME(m_ppc)); + save_item(NAME(m_branch_state)); + save_item(NAME(m_branch_target)); // initialise cpu and fpu id registers m_cpr[0][COP0_PRId] = m_cpurev; @@ -239,7 +238,7 @@ void mips1core_device_base::device_reset() { // initialize the state m_pc = 0xbfc00000; - m_nextpc = ~0; + m_branch_state = NONE; // non-tlb devices have tlb shut down m_cpr[0][COP0_Status] = SR_BEV | SR_TS; @@ -274,18 +273,18 @@ std::unique_ptr<util::disasm_interface> mips1core_device_base::create_disassembl void mips1core_device_base::generate_exception(int exception) { // set the exception PC - m_cpr[0][COP0_EPC] = (exception == EXCEPTION_INTERRUPT) ? m_pc : m_ppc; + m_cpr[0][COP0_EPC] = m_pc; // put the cause in the low 8 bits and clear the branch delay flag CAUSE = (CAUSE & ~0x800000ff) | (exception << 2); - // if we were in a branch delay slot, adjust - if (m_nextpc != ~0) + // if in a branch delay slot, restart the branch + if (m_branch_state == DELAY) { - m_nextpc = ~0; m_cpr[0][COP0_EPC] -= 4; CAUSE |= 0x80000000; } + m_branch_state = NONE; // shift the exception bits SR = (SR & 0xffffffc0) | ((SR << 2) & 0x3c); @@ -552,7 +551,6 @@ void mips1core_device_base::execute_run() do { // debugging - m_ppc = m_pc; debugger_instruction_hook(m_pc); #if ENABLE_IOP_KPUTS @@ -575,16 +573,6 @@ void mips1core_device_base::execute_run() // fetch and execute instruction fetch(m_pc, [this](u32 const op) { - { - // adjust for next PC - if (m_nextpc != ~0) - { - m_pc = m_nextpc; - m_nextpc = ~0; - } - else - m_pc += 4; - // parse the instruction switch (op >> 26) { @@ -784,11 +772,28 @@ void mips1core_device_base::execute_run() case 0x3f: /* SDC3 */ generate_exception(EXCEPTION_INVALIDOP); break; default: /* ??? */ generate_exception(EXCEPTION_INVALIDOP); break; } + + // update pc and branch state + switch (m_branch_state) + { + case NONE: + m_pc += 4; + break; + + case DELAY: + m_branch_state = NONE; + m_pc = m_branch_target; + break; + + case BRANCH: + m_branch_state = DELAY; + m_pc += 4; + break; } }); m_icount--; - } while (m_icount > 0 || m_nextpc != ~0); + } while (m_icount > 0 || m_branch_state); } void mips1core_device_base::lwl(u32 const op) @@ -995,7 +1000,8 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad if (!(intention & TRANSLATE_DEBUG_MASK)) { if ((VERBOSE & LOG_TLB) && !dirty) - LOGMASKED(LOG_TLB, "tlb miss address 0x%08x\n", address); + LOGMASKED(LOG_TLB, "tlb miss %s address 0x%08x (%s)\n", + (intention & TRANSLATE_WRITE) ? "store" : "load", address, machine().describe_context()); // exception m_cpr[0][COP0_BadVAddr] = address; diff --git a/src/devices/cpu/mips/mips1.h b/src/devices/cpu/mips/mips1.h index a64521b1bf6..123a8ec2ae1 100644 --- a/src/devices/cpu/mips/mips1.h +++ b/src/devices/cpu/mips/mips1.h @@ -101,32 +101,32 @@ protected: enum sr_mask : u32 { - SR_IEc = 0x00000001, - SR_KUc = 0x00000002, - SR_IEp = 0x00000004, - SR_KUp = 0x00000008, - SR_IEo = 0x00000010, - SR_KUo = 0x00000020, - SR_IMSW0 = 0x00000100, - SR_IMSW1 = 0x00000200, - SR_IMEX0 = 0x00000400, - SR_IMEX1 = 0x00000800, - SR_IMEX2 = 0x00001000, - SR_IMEX3 = 0x00002000, - SR_IMEX4 = 0x00004000, - SR_IMEX5 = 0x00008000, - SR_IsC = 0x00010000, - SR_SwC = 0x00020000, - SR_PZ = 0x00040000, - SR_CM = 0x00080000, - SR_PE = 0x00100000, - SR_TS = 0x00200000, - SR_BEV = 0x00400000, - SR_RE = 0x02000000, - SR_COP0 = 0x10000000, - SR_COP1 = 0x20000000, - SR_COP2 = 0x40000000, - SR_COP3 = 0x80000000, + SR_IEc = 0x00000001, // interrupt enable + SR_KUc = 0x00000002, // kernel mode + SR_IEp = 0x00000004, // interrupt enable (previous) + SR_KUp = 0x00000008, // kernel mode (previous) + SR_IEo = 0x00000010, // interrupt enable (old) + SR_KUo = 0x00000020, // kernel mode (old) + SR_IMSW0 = 0x00000100, // software interrupt 0 enable + SR_IMSW1 = 0x00000200, // software interrupt 1 enable + SR_IMEX0 = 0x00000400, // external interrupt 0 enable + SR_IMEX1 = 0x00000800, // external interrupt 1 enable + SR_IMEX2 = 0x00001000, // external interrupt 2 enable + SR_IMEX3 = 0x00002000, // external interrupt 3 enable + SR_IMEX4 = 0x00004000, // external interrupt 4 enable + SR_IMEX5 = 0x00008000, // external interrupt 5 enable + SR_IsC = 0x00010000, // isolate (data) cache + SR_SwC = 0x00020000, // swap caches + SR_PZ = 0x00040000, // cache parity zero + SR_CM = 0x00080000, // cache match + SR_PE = 0x00100000, // cache parity error + SR_TS = 0x00200000, // tlb shutdown + SR_BEV = 0x00400000, // boot exception vectors + SR_RE = 0x02000000, // reverse endianness in user mode + SR_COP0 = 0x10000000, // coprocessor 0 usable + SR_COP1 = 0x20000000, // coprocessor 1 usable + SR_COP2 = 0x40000000, // coprocessor 2 usable + SR_COP3 = 0x80000000, // coprocessor 3 usable }; enum entryhi_mask : u32 @@ -213,7 +213,6 @@ protected: // core registers u32 m_pc; - u32 m_nextpc; u32 m_hi; u32 m_lo; u32 m_r[32]; @@ -223,8 +222,15 @@ protected: u32 m_ccr[4][32]; // internal stuff - u32 m_ppc; int m_icount; + enum branch_state_t : unsigned + { + NONE = 0, + DELAY = 1, // delay slot instruction active + BRANCH = 2, // branch instruction active + } + m_branch_state; + u32 m_branch_target; // cache memory size_t const m_icache_size; |