mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
romp: various improvements
* record branch with execute address for exception caused by branch subject * optionally defer interrupt recognition after lps * halt lm/stm on exception * implement condition codes for abs * tighten up system control register reserved bits
This commit is contained in:
parent
0daa43b832
commit
b17cd1e060
@ -75,6 +75,7 @@ void romp_device::device_start()
|
||||
save_item(NAME(m_branch_state));
|
||||
save_item(NAME(m_branch_source));
|
||||
save_item(NAME(m_branch_target));
|
||||
save_item(NAME(m_defer_int));
|
||||
}
|
||||
|
||||
void romp_device::state_string_export(device_state_entry const &entry, std::string &str) const
|
||||
@ -104,6 +105,7 @@ void romp_device::device_reset()
|
||||
// initialize the state
|
||||
m_trap = false;
|
||||
m_branch_state = DEFAULT;
|
||||
m_defer_int = false;
|
||||
|
||||
// fetch initial iar
|
||||
load<u32>(0, [this](u32 data) { m_scr[IAR] = data; });
|
||||
@ -114,7 +116,9 @@ void romp_device::execute_run()
|
||||
// core execution loop
|
||||
while (m_icount-- > 0)
|
||||
{
|
||||
if (m_branch_state != BRANCH)
|
||||
if (m_defer_int)
|
||||
m_defer_int = false;
|
||||
else
|
||||
interrupt_check();
|
||||
|
||||
if (m_branch_state == WAIT)
|
||||
@ -144,7 +148,7 @@ void romp_device::execute_run()
|
||||
}
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
case 0x1: // stcs: store character short
|
||||
store<u8>(r3_0(R3) + ((op >> 8) & 15), m_gpr[R2]);
|
||||
@ -180,7 +184,7 @@ void romp_device::execute_run()
|
||||
|
||||
if (m_branch_state == BRANCH)
|
||||
{
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -273,7 +277,7 @@ void romp_device::execute_run()
|
||||
m_icount -= 15;
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
case 0xc1: // ai: add immediate
|
||||
flags_add(m_gpr[R3], s32(s16(i)));
|
||||
@ -306,9 +310,8 @@ void romp_device::execute_run()
|
||||
m_gpr[R2] = r3 + s16(i);
|
||||
break;
|
||||
case 0xc9: // lm: load multiple
|
||||
for (unsigned reg = R2, offset = r3 + s16(i); reg < 16; reg++, offset += 4)
|
||||
for (unsigned reg = R2, offset = r3 + s16(i); (reg < 16) && m_branch_state != EXCEPTION; reg++, offset += 4)
|
||||
{
|
||||
// FIXME: multiple exceptions
|
||||
load<u32>(offset, [this, reg](u32 data) { m_gpr[reg] = data; });
|
||||
m_icount -= 2;
|
||||
}
|
||||
@ -331,7 +334,7 @@ void romp_device::execute_run()
|
||||
program_check(PCS_PCK | PCS_PT);
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
case 0xcd: // l: load
|
||||
load<u32>(r3 + s16(i), [this, op](u32 data) { m_gpr[R2] = data; });
|
||||
@ -364,12 +367,14 @@ void romp_device::execute_run()
|
||||
m_scr[MPCS] &= ~MCS_ALL;
|
||||
else
|
||||
m_scr[MPCS] &= ~PCS_ALL;
|
||||
// TODO: defer interrupt enable
|
||||
|
||||
// optionally defer interrupts
|
||||
m_defer_int = BIT(op, 4);
|
||||
|
||||
m_icount -= 15;
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_PIE);
|
||||
@ -416,9 +421,8 @@ void romp_device::execute_run()
|
||||
m_gpr[R2] = r3 + (u32(i) << 16);
|
||||
break;
|
||||
case 0xd9: // stm: store multiple
|
||||
for (unsigned reg = R2, offset = r3 + s16(i); reg < 16; reg++, offset += 4)
|
||||
for (unsigned reg = R2, offset = r3 + s16(i); (reg < 16) && m_branch_state != EXCEPTION; reg++, offset += 4)
|
||||
{
|
||||
// FIXME: multiple exceptions
|
||||
store<u32>(offset, m_gpr[reg]);
|
||||
m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 2;
|
||||
}
|
||||
@ -686,7 +690,7 @@ void romp_device::execute_run()
|
||||
m_icount--;
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
case 0xbe: // tlt: trap if register less than
|
||||
if (m_branch_state != BRANCH)
|
||||
@ -700,7 +704,7 @@ void romp_device::execute_run()
|
||||
m_icount--;
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
case 0xbf: // mttb: move to test bit
|
||||
if (m_gpr[R2] & (0x8000'0000U >> (m_gpr[R3] & 31)))
|
||||
@ -710,13 +714,18 @@ void romp_device::execute_run()
|
||||
break;
|
||||
|
||||
case 0xe0: // abs: absolute
|
||||
if (s32(m_gpr[R3]) < 0)
|
||||
m_scr[CS] &= ~(CS_C | CS_O);
|
||||
if (m_gpr[R3] == 0x8000'0000U)
|
||||
{
|
||||
m_gpr[R2] = m_gpr[R3];
|
||||
m_scr[CS] |= CS_O;
|
||||
}
|
||||
else if (s32(m_gpr[R3]) < 0)
|
||||
m_gpr[R2] = -s32(m_gpr[R3]);
|
||||
else
|
||||
m_gpr[R2] = m_gpr[R3];
|
||||
flags_log(m_gpr[R2]);
|
||||
m_icount--;
|
||||
// TODO: test for maximum negative
|
||||
// TODO: LT, EQ, GT, C0, OV
|
||||
break;
|
||||
case 0xe1: // a: add
|
||||
flags_add(m_gpr[R2], m_gpr[R3]);
|
||||
@ -788,7 +797,7 @@ void romp_device::execute_run()
|
||||
}
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
case 0xe9: // bnbrx: branch on not condition bit with execute
|
||||
if (m_branch_state != BRANCH)
|
||||
@ -801,7 +810,7 @@ void romp_device::execute_run()
|
||||
}
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
|
||||
case 0xeb: // lhs: load half short
|
||||
@ -817,7 +826,7 @@ void romp_device::execute_run()
|
||||
m_icount -= 4;
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
case 0xed: // balrx: branch and link with execute
|
||||
if (m_branch_state != BRANCH)
|
||||
@ -829,7 +838,7 @@ void romp_device::execute_run()
|
||||
m_icount -= 4;
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
case 0xee: // bbr: branch on condition bit
|
||||
if (m_branch_state != BRANCH)
|
||||
@ -842,7 +851,7 @@ void romp_device::execute_run()
|
||||
}
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
case 0xef: // bbrx: branch on condition bit with execute
|
||||
if (m_branch_state != BRANCH)
|
||||
@ -856,7 +865,7 @@ void romp_device::execute_run()
|
||||
}
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
break;
|
||||
|
||||
case 0xf0: // wait: wait
|
||||
@ -865,7 +874,7 @@ void romp_device::execute_run()
|
||||
if (m_branch_state != BRANCH)
|
||||
m_branch_state = WAIT;
|
||||
else
|
||||
program_check(PCS_PCK | PCS_IOC, m_branch_source);
|
||||
program_check(PCS_PCK | PCS_IOC);
|
||||
}
|
||||
else
|
||||
program_check(PCS_PCK | PCS_PIE);
|
||||
@ -934,6 +943,7 @@ void romp_device::execute_run()
|
||||
case DELAY:
|
||||
m_scr[IAR] = updated_iar;
|
||||
m_branch_state = BRANCH;
|
||||
m_defer_int = true;
|
||||
break;
|
||||
|
||||
case EXCEPTION:
|
||||
@ -951,22 +961,33 @@ void romp_device::execute_run()
|
||||
|
||||
void romp_device::set_scr(unsigned scr, u32 data)
|
||||
{
|
||||
static char const *const scr_names[16] =
|
||||
if (VERBOSE & LOG_GENERAL)
|
||||
{
|
||||
"scr0", "scr1", "scr2", "scr3", "scr4", "scr5", "cous", "cou",
|
||||
"ts", "ecr", "mq", "mpcs", "irb", "iar", "ics", "cs",
|
||||
static char const *const scr_names[16] =
|
||||
{
|
||||
"scr0", "scr1", "scr2", "scr3", "scr4", "scr5", "cous", "cou",
|
||||
"ts", "ecr", "mq", "mpcs", "irb", "iar", "ics", "cs",
|
||||
};
|
||||
|
||||
LOG("set_scr %s data 0x%08x (%s)\n", scr_names[scr], data, machine().describe_context());
|
||||
}
|
||||
|
||||
static u32 const scr_mask[16] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, // reserved
|
||||
0xffff'ffffU, 0xffff'ffffU, // counter source and counter
|
||||
TS_E | TS_I | TS_O | TS_P,
|
||||
0, // reserved
|
||||
0xffff'ffffU, // multiplier quotient
|
||||
MCS_ALL | PCS_ALL,
|
||||
IRB_ALL,
|
||||
0xffff'fffeU, // instruction address
|
||||
ICS_PE | ICS_MP | ICS_US | ICS_TM | ICS_IM | ICS_CS | ICS_PP,
|
||||
CS_L | CS_E | CS_G | CS_C | CS_O | CS_T,
|
||||
};
|
||||
|
||||
LOG("set_scr %s data 0x%08x (%s)\n", scr_names[scr], data, machine().describe_context());
|
||||
|
||||
if (!(m_scr[ICS] & ICS_US) || scr == MQ || scr == CS)
|
||||
{
|
||||
if (scr == ICS)
|
||||
// TODO: only SGP is emulated
|
||||
m_scr[scr] = data & 0x1ff7U;
|
||||
else
|
||||
m_scr[scr] = data;
|
||||
}
|
||||
m_scr[scr] = data & scr_mask[scr];
|
||||
else
|
||||
program_check(PCS_PCK | PCS_PIE);
|
||||
}
|
||||
@ -1081,8 +1102,8 @@ void romp_device::interrupt_check()
|
||||
return;
|
||||
}
|
||||
|
||||
// interrupts masked or no interrupts
|
||||
if ((m_scr[ICS] & ICS_IM) || !(m_reqi || (m_scr[IRB] & IRB_ALL)))
|
||||
// interrupts masked, machine/program check, or no interrupts
|
||||
if ((m_scr[ICS] & ICS_IM) || m_scr[MPCS] || !(m_reqi || (m_scr[IRB] & IRB_ALL)))
|
||||
return;
|
||||
|
||||
unsigned const priority = m_scr[ICS] & ICS_PP;
|
||||
@ -1110,7 +1131,7 @@ void romp_device::machine_check(u32 mcs)
|
||||
interrupt_enter(7, m_scr[IAR]);
|
||||
}
|
||||
|
||||
void romp_device::program_check(u32 pcs, u32 iar)
|
||||
void romp_device::program_check(u32 pcs)
|
||||
{
|
||||
debugger_exception_hook(8);
|
||||
|
||||
@ -1119,14 +1140,21 @@ void romp_device::program_check(u32 pcs, u32 iar)
|
||||
m_scr[MPCS] &= ~PCS_ALL;
|
||||
m_scr[MPCS] |= (pcs & PCS_ALL);
|
||||
|
||||
interrupt_enter(8, iar);
|
||||
/*
|
||||
* Old program status reflects the address of a branch with execute
|
||||
* instruction when a program-check error occurs due to either a invalid
|
||||
* subject instruction or a data address exception caused by a subject
|
||||
* instruction.
|
||||
*/
|
||||
// TODO: what about program check caused by subject instruction fetch?
|
||||
interrupt_enter(8, m_branch_state == BRANCH ? m_branch_source : m_scr[IAR]);
|
||||
|
||||
m_branch_state = EXCEPTION;
|
||||
}
|
||||
|
||||
void romp_device::interrupt_enter(unsigned vector, u32 iar, u16 svc)
|
||||
{
|
||||
// take interrupt
|
||||
// compute program status pair address
|
||||
u32 const address = 0x100 + vector * 16;
|
||||
|
||||
// save old program status
|
||||
|
@ -65,8 +65,8 @@ protected:
|
||||
// reserved
|
||||
MCS_PCC = 0x0000'8000, // processor channel check
|
||||
|
||||
MCS_ALL = 0x0000'ff00,
|
||||
PCS_ALL = 0x0000'00ff,
|
||||
MCS_ALL = 0x0000'be00,
|
||||
PCS_ALL = 0x0000'00fe,
|
||||
};
|
||||
|
||||
enum irb_mask : u16
|
||||
@ -142,8 +142,7 @@ private:
|
||||
|
||||
void interrupt_check();
|
||||
void machine_check(u32 mcs);
|
||||
void program_check(u32 pcs, u32 iar);
|
||||
void program_check(u32 pcs) { program_check(pcs, m_scr[IAR]); }
|
||||
void program_check(u32 pcs);
|
||||
void interrupt_enter(unsigned vector, u32 iar, u16 svc = 0);
|
||||
|
||||
using rsc_mode = rsc_bus_interface::rsc_mode;
|
||||
@ -289,6 +288,7 @@ private:
|
||||
m_branch_state;
|
||||
u32 m_branch_source;
|
||||
u32 m_branch_target;
|
||||
bool m_defer_int;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(ROMP, romp_device)
|
||||
|
Loading…
Reference in New Issue
Block a user