diff options
Diffstat (limited to 'src/devices/cpu/romp/romp.cpp')
-rw-r--r-- | src/devices/cpu/romp/romp.cpp | 127 |
1 files changed, 76 insertions, 51 deletions
diff --git a/src/devices/cpu/romp/romp.cpp b/src/devices/cpu/romp/romp.cpp index 94e3da8591c..0f65659ae60 100644 --- a/src/devices/cpu/romp/romp.cpp +++ b/src/devices/cpu/romp/romp.cpp @@ -5,7 +5,7 @@ * IBM Research and Office Products Division Microprocessor (ROMP). * * Sources: - * - http://bitsavers.org/pdf/ibm/pc/rt/75X0232_RT_PC_Technical_Reference_Volume_1_Jun87.pdf + * - IBM RT PC Hardware Technical Reference Volume I, 75X0232, March 1987 * * TODO: * - configurable storage channel @@ -17,9 +17,7 @@ #include "emu.h" #include "romp.h" #include "rompdasm.h" -#include "debugger.h" -#define LOG_GENERAL (1U << 0) #define LOG_INTERRUPT (1U << 1) //#define VERBOSE (LOG_INTERRUPT) @@ -76,6 +74,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 @@ -105,6 +104,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; }); @@ -115,7 +115,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) @@ -145,7 +147,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]); @@ -181,7 +183,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; } @@ -274,7 +276,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))); @@ -307,9 +309,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; } @@ -320,7 +321,7 @@ void romp_device::execute_run() m_icount -= 4; break; case 0xcb: // ior: input/output read - if (((r3 + i) & 0xff00'0000U) || !m_mmu->ior(r3 + i, m_gpr[R2])) + if (((r3 + i) & 0xff00'0000U) || !m_mmu->pio_load(r3 + i, m_gpr[R2])) program_check(PCS_PCK | PCS_DAE); break; case 0xcc: // ti: trap on condition immediate @@ -332,7 +333,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; }); @@ -365,12 +366,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); @@ -417,9 +420,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; } @@ -430,7 +432,7 @@ void romp_device::execute_run() m_icount -= 4; break; case 0xdb: // iow: input/output write - if (((r3 + i) & 0xff00'0000U) || !m_mmu->iow(r3 + i, m_gpr[R2])) + if (((r3 + i) & 0xff00'0000U) || !m_mmu->pio_store(r3 + i, m_gpr[R2])) program_check(PCS_PCK | PCS_DAE); m_icount--; break; @@ -687,7 +689,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) @@ -701,7 +703,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))) @@ -711,13 +713,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]); @@ -789,7 +796,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) @@ -802,7 +809,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 @@ -818,7 +825,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) @@ -830,7 +837,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) @@ -843,7 +850,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) @@ -857,7 +864,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 @@ -866,7 +873,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); @@ -935,6 +942,7 @@ void romp_device::execute_run() case DELAY: m_scr[IAR] = updated_iar; m_branch_state = BRANCH; + m_defer_int = true; break; case EXCEPTION: @@ -952,22 +960,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()); + } - if (!(m_scr[ICS] & ICS_US) || scr == MQ || scr == CS) + static u32 const scr_mask[16] = { - if (scr == ICS) - // TODO: only SGP is emulated - m_scr[scr] = data & 0x1ff7U; - else - m_scr[scr] = data; - } + 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) + m_scr[scr] = data & scr_mask[scr]; else program_check(PCS_PCK | PCS_PIE); } @@ -984,12 +1003,7 @@ void romp_device::execute_set_input(int irqline, int state) default: // interrupt lines are active low if (!state) - { m_reqi |= 1U << irqline; - - // enable debugger interrupt breakpoints - standard_irq_callback(irqline); - } else m_reqi &= ~(1U << irqline); break; @@ -1001,8 +1015,9 @@ device_memory_interface::space_config_vector romp_device::memory_space_config() return space_config_vector { std::make_pair(AS_PROGRAM, &m_mem_config) }; } -bool romp_device::memory_translate(int spacenum, int intention, offs_t &address) +bool romp_device::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) { + target_space = &space(spacenum); return true; } @@ -1082,8 +1097,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; @@ -1091,6 +1106,9 @@ void romp_device::interrupt_check() { if (BIT(m_reqi, irl) || BIT(m_scr[IRB], 15 - irl)) { + // enable debugger interrupt breakpoints + standard_irq_callback(irl, m_scr[IAR]); + LOGMASKED(LOG_INTERRUPT, "interrupt_check taking interrupt request level %d\n", irl); interrupt_enter(irl, m_scr[IAR]); @@ -1111,7 +1129,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); @@ -1120,14 +1138,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 |