From b17cd1e0605892afecf8c2dd63557e544ecbd169 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Wed, 21 Dec 2022 16:41:46 +0700 Subject: 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 --- src/devices/cpu/romp/romp.cpp | 108 ++++++++++++++++++++++++++---------------- src/devices/cpu/romp/romp.h | 8 ++-- 2 files changed, 72 insertions(+), 44 deletions(-) diff --git a/src/devices/cpu/romp/romp.cpp b/src/devices/cpu/romp/romp.cpp index bd652f7adc2..37d73c4932b 100644 --- a/src/devices/cpu/romp/romp.cpp +++ b/src/devices/cpu/romp/romp.cpp @@ -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(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(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(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(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(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()); + } - 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, + }; 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 diff --git a/src/devices/cpu/romp/romp.h b/src/devices/cpu/romp/romp.h index 27a710f1d84..2d726bbcd4c 100644 --- a/src/devices/cpu/romp/romp.h +++ b/src/devices/cpu/romp/romp.h @@ -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) -- cgit v1.2.3