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:
Patrick Mackinlay 2022-12-21 16:41:46 +07:00
parent 0daa43b832
commit b17cd1e060
2 changed files with 72 additions and 44 deletions

View File

@ -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

View File

@ -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)