mirror of
https://github.com/holub/mame
synced 2025-04-22 00:11:58 +03:00
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.
This commit is contained in:
parent
f74ad668aa
commit
2af742e9d1
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user