From 364c17fa3d62b4cf4973455f03c2edc78c89d26d Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Tue, 25 Feb 2020 20:38:00 +0700 Subject: romp: various improvements (nw) * corrected scr register names * some basic instruction cycle counts * some exceptions/interrupts * most flags --- src/devices/cpu/romp/romp.cpp | 696 +++++++++++++++++++++++++++----------- src/devices/cpu/romp/romp.h | 109 ++++-- src/devices/cpu/romp/rompdasm.cpp | 4 +- 3 files changed, 580 insertions(+), 229 deletions(-) diff --git a/src/devices/cpu/romp/romp.cpp b/src/devices/cpu/romp/romp.cpp index 61cdb27eaba..32f475d3722 100644 --- a/src/devices/cpu/romp/romp.cpp +++ b/src/devices/cpu/romp/romp.cpp @@ -8,13 +8,9 @@ * - http://bitsavers.org/pdf/ibm/pc/rt/6489893_RT_PC_Technical_Reference_Volume_1_Nov85.pdf * * TODO: - * - unimplemented instructions - * - condition codes - * - memory management unit - * - interrupts and exceptions + * - mmu/iocc exceptions + * - unimplemented instructions (multiply, divide, wait) * - timer/counter - * - assembler syntax - * - instruction clocks */ #include "emu.h" @@ -22,8 +18,10 @@ #include "rompdasm.h" #include "debugger.h" -#define LOG_GENERAL (1U << 0) -//#define VERBOSE (LOG_GENERAL) +#define LOG_GENERAL (1U << 0) +#define LOG_INTERRUPT (1U << 1) + +//#define VERBOSE (LOG_INTERRUPT) #include "logmacro.h" // instruction decode helpers @@ -38,28 +36,32 @@ romp_device::romp_device(machine_config const &mconfig, char const *tag, device_ : cpu_device(mconfig, ROMP, tag, owner, clock) , m_mem_config("memory", ENDIANNESS_BIG, 32, 32) , m_io_config("io", ENDIANNESS_BIG, 32, 24, -2) + , m_out_tm(*this) , m_icount(0) { } void romp_device::device_start() { + m_out_tm.resolve_safe(); + // set instruction counter set_icountptr(m_icount); // register state for the debugger state_add(STATE_GENPC, "GENPC", m_scr[IAR]).noshow(); state_add(STATE_GENPCBASE, "CURPC", m_scr[IAR]).noshow(); - - state_add(ROMP_SCR + IAR, "IAR", m_scr[IAR]); - state_add(ROMP_SCR + COS, "COS", m_scr[COS]); - state_add(ROMP_SCR + COU, "COU", m_scr[COU]); - state_add(ROMP_SCR + TS, "TS", m_scr[TS]); - state_add(ROMP_SCR + MQ, "MQ", m_scr[MQ]); - state_add(ROMP_SCR + MCS, "MCS", m_scr[MCS]); - state_add(ROMP_SCR + IRB, "IRB", m_scr[IRB]); - state_add(ROMP_SCR + ICS, "ICS", m_scr[ICS]); - state_add(ROMP_SCR + CS, "CS", m_scr[CS]); + state_add(STATE_GENFLAGS, "GENFLAGS", m_scr[CS]).formatstr("%6s").noshow(); + + state_add(ROMP_SCR + IAR, "IAR", m_scr[IAR]); + state_add(ROMP_SCR + COUS, "COUS", m_scr[COUS]); + state_add(ROMP_SCR + COU, "COU", m_scr[COU]); + state_add(ROMP_SCR + TS, "TS", m_scr[TS]); + state_add(ROMP_SCR + MQ, "MQ", m_scr[MQ]); + state_add(ROMP_SCR + MPCS, "MPCS", m_scr[MPCS]); + state_add(ROMP_SCR + IRB, "IRB", m_scr[IRB]); + state_add(ROMP_SCR + ICS, "ICS", m_scr[ICS]); + state_add(ROMP_SCR + CS, "CS", m_scr[CS]); for (unsigned i = 0; i < ARRAY_LENGTH(m_gpr); i++) state_add(ROMP_GPR + i, util::string_format("R%d", i).c_str(), m_gpr[i]); @@ -71,12 +73,36 @@ void romp_device::device_start() save_item(NAME(m_branch_target)); } +void romp_device::state_string_export(device_state_entry const &entry, std::string &str) const +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + str = string_format("%c%c%c%c%c%c", + (m_scr[CS] & CS_L) ? 'L' : '.', + (m_scr[CS] & CS_E) ? 'E' : '.', + (m_scr[CS] & CS_G) ? 'G' : '.', + (m_scr[CS] & CS_C) ? 'C' : '.', + (m_scr[CS] & CS_O) ? 'O' : '.', + (m_scr[CS] & CS_T) ? 'T' : '.'); + break; + } +} + void romp_device::device_reset() { + // TODO: assumed + for (u32 &scr : m_scr) + scr = 0; + m_out_tm(0); + + // TODO: assumed + for (u32 &gpr : m_gpr) + gpr = 0; + // initialize the state - // FIXME: should fetch initial address from 0 - m_scr[IAR] = space(AS_PROGRAM).read_dword(0x80'0000); - m_branch_state = NONE; + m_scr[IAR] = space(AS_PROGRAM).read_dword(0); + m_branch_state = DEFAULT; } void romp_device::execute_run() @@ -87,88 +113,125 @@ void romp_device::execute_run() // debugging debugger_instruction_hook(m_scr[IAR]); - // TODO: interrupts/exceptions + if (m_branch_state == DEFAULT) + interrupt_check(); // fetch instruction u16 const op = space(AS_PROGRAM).read_word(m_scr[IAR]); - m_scr[IAR] += 2; - - // TODO: program check for illegal branch subject instructions + u32 updated_iar = m_scr[IAR] + 2; switch (op >> 12) { case 0x0: // jb/jnb: jump on [not] condition bit - if (BIT(m_scr[CS], ((op >> 8) & 7) ^ 7) == BIT(op, 11)) - m_scr[IAR] = m_scr[IAR] - 2 + ji(op); + if (m_branch_state == BRANCH) + program_check(PCS_PCK | PCS_IOC); + else if (BIT(m_scr[CS], ((op >> 8) & 7) ^ 7) == BIT(op, 11)) + { + m_branch_target = m_scr[IAR] + ji(op); + m_branch_state = BRANCH; + m_icount -= 4; + } break; case 0x1: // stcs: store character short space(AS_PROGRAM).write_byte(r3_0(R3) + ((op >> 8) & 15), m_gpr[R2]); + m_icount -= 4; break; case 0x2: // sths: store half short space(AS_PROGRAM).write_word(r3_0(R3) + ((op >> 7) & 30), m_gpr[R2]); + m_icount -= 4; break; case 0x3: // sts: store short space(AS_PROGRAM).write_dword(r3_0(R3) + ((op >> 6) & 60), m_gpr[R2]); + m_icount -= 4; break; case 0x4: // lcs: load character short m_gpr[R2] = space(AS_PROGRAM).read_byte(r3_0(R3) + ((op >> 8) & 15)); + m_icount -= 4; break; case 0x5: // lhas: load half algebraic short m_gpr[R2] = s32(s16(space(AS_PROGRAM).read_word(r3_0(R3) + ((op >> 7) & 30)))); + m_icount -= 4; break; case 0x6: // cas: compute address short m_gpr[(op >> 8) & 15] = m_gpr[R2] + r3_0(R3); break; case 0x7: // ls: load short m_gpr[R2] = space(AS_PROGRAM).read_dword(r3_0(R3) + ((op >> 6) & 60)); + m_icount -= 4; break; case 0x8: // BI, BA format { - u16 const b = space(AS_PROGRAM).read_word(m_scr[IAR]); - m_scr[IAR] += 2; + u16 const b = space(AS_PROGRAM).read_word(updated_iar); + updated_iar += 2; + + if (m_branch_state == BRANCH) + { + program_check(PCS_PCK | PCS_IOC); + break; + } switch (op >> 8) { case 0x88: // bnb: branch on not condition bit immediate if (!BIT(m_scr[CS], R2 ^ 15)) - m_scr[IAR] = m_scr[IAR] - 4 + bi(op, b); + { + m_branch_target = m_scr[IAR] + bi(op, b); + m_branch_state = BRANCH; + m_icount -= 4; + } break; case 0x89: // bnbx: branch on not condition bit immediate with execute if (!BIT(m_scr[CS], R2 ^ 15)) { - m_branch_target = m_scr[IAR] - 4 + bi(op, b); - m_branch_state = BRANCH; + m_branch_target = m_scr[IAR] + bi(op, b); + m_branch_state = DELAY; + m_icount -= 4; } break; case 0x8a: // bala: branch and link absolute - m_gpr[15] = m_scr[IAR]; - m_scr[IAR] = ba(op, b); + m_gpr[15] = updated_iar; + m_branch_target = ba(op, b); + m_branch_state = BRANCH; + m_icount -= 4; break; case 0x8b: // balax: branch and link absolute with execute - m_gpr[15] = m_scr[IAR] + 4; + m_gpr[15] = updated_iar + 4; m_branch_target = ba(op, b); - m_branch_state = BRANCH; + m_branch_state = DELAY; + m_icount -= 4; break; case 0x8c: // bali: branch and link immediate - m_gpr[R2] = m_scr[IAR]; - m_scr[IAR] = m_scr[IAR] - 4 + bi(op, b); + m_gpr[R2] = updated_iar; + m_branch_target = m_scr[IAR] + bi(op, b); + m_branch_state = BRANCH; + m_icount -= 4; break; case 0x8d: // balix: branch and link immediate with execute - m_gpr[R2] = m_scr[IAR] + 4; - m_branch_target = m_scr[IAR] - 4 + bi(op, b); - m_branch_state = BRANCH; + m_gpr[R2] = updated_iar + 4; + m_branch_target = m_scr[IAR] + bi(op, b); + m_branch_state = DELAY; + m_icount -= 4; break; case 0x8e: // bb: branch on condition bit immediate if (BIT(m_scr[CS], R2 ^ 15)) - m_scr[IAR] = m_scr[IAR] - 4 + bi(op, b); + { + m_branch_target = m_scr[IAR] + bi(op, b); + m_branch_state = BRANCH; + m_icount -= 4; + } break; case 0x8f: // bbx: branch on condition bit immediate with execute if (BIT(m_scr[CS], R2 ^ 15)) { - m_branch_target = m_scr[IAR] - 4 + bi(op, b); - m_branch_state = BRANCH; + m_branch_target = m_scr[IAR] + bi(op, b); + m_branch_state = DELAY; + m_icount -= 4; } break; + + default: + program_check(PCS_PCK | PCS_IOC); + break; } } break; @@ -176,143 +239,172 @@ void romp_device::execute_run() case 0xc: case 0xd: // D format { - u16 const i = space(AS_PROGRAM).read_word(m_scr[IAR]); - m_scr[IAR] += 2; + u16 const i = space(AS_PROGRAM).read_word(updated_iar); + updated_iar += 2; u32 const r3 = R3 ? m_gpr[R3] : 0; switch (op >> 8) { - //case 0xc0: // svc: supervisor call + case 0xc0: // svc: supervisor call + if (m_branch_state != BRANCH) + { + interrupt_enter(9, r3 + i); + m_branch_state = EXCEPTION; + + m_icount -= 15; + } + else + program_check(PCS_PCK | PCS_IOC); + break; case 0xc1: // ai: add immediate - m_gpr[R2] = m_gpr[R3] + s16(i); - // TODO: LT, EQ, GT, C0, OV + flags_add(m_gpr[R3], s32(s16(i))); + m_gpr[R2] = m_gpr[R3] + s32(s16(i)); break; case 0xc2: // cal16: compute address lower half 16-bit m_gpr[R2] = (r3 & 0xffff'0000U) | u16(r3 + i); break; case 0xc3: // oiu: or immediate upper half m_gpr[R2] = (u32(i) << 16) | m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xc4: // oil: or immediate lower half m_gpr[R2] = u32(i) | m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xc5: // nilz: and immediate lower half extended zeroes m_gpr[R2] = u32(i) & m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xc6: // nilo: and immediate lower half extended ones m_gpr[R2] = (i | 0xffff'0000U) & m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xc7: // xil: exclusive or immediate lower half m_gpr[R2] = u32(i) ^ m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xc8: // cal: compute address lower half m_gpr[R2] = r3 + s16(i); break; case 0xc9: // lm: load multiple - for (unsigned reg = R2, offset = 0; reg < 16; reg++, offset += 4) - m_gpr[reg] = space(AS_PROGRAM).read_dword(r3 + s16(i) + offset); + for (unsigned reg = R2, offset = r3 + s16(i); reg < 16; reg++, offset += 4) + { + m_gpr[reg] = space(AS_PROGRAM).read_dword(offset); + m_icount -= 2; + } + m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 1; break; case 0xca: // lha: load half algebraic m_gpr[R2] = s32(s16(space(AS_PROGRAM).read_word(r3 + s16(i)))); + m_icount -= 4; break; case 0xcb: // ior: input/output read - m_gpr[R2] = space(2).read_dword(r3 + i); + if (r3 + i < 0x0100'0000U) + m_gpr[R2] = space(AS_IO).read_dword(r3 + i); + else + program_check(PCS_PCK | PCS_IOC); + break; + case 0xcc: // ti: trap on condition immediate + if (m_branch_state == BRANCH) + program_check(PCS_PCK | PCS_IOC); + else if ((BIT(op, 6) && (m_gpr[R3] < u32(s32(s16(i))))) + || (BIT(op, 5) && (m_gpr[R3] == u32(s32(s16(i))))) + || (BIT(op, 4) && (m_gpr[R3] > u32(s32(s16(i)))))) + program_check(PCS_PCK | PCS_PT); break; - //case 0xcc: // ti: trap on condition immediate case 0xcd: // l: load m_gpr[R2] = space(AS_PROGRAM).read_dword(r3 + s16(i)); + m_icount -= 4; break; case 0xce: // lc: load character m_gpr[R2] = space(AS_PROGRAM).read_byte(r3 + s16(i)); + m_icount -= 4; break; case 0xcf: // tsh: test and set half m_gpr[R2] = space(AS_PROGRAM).read_word(r3 + s16(i)); space(AS_PROGRAM).write_byte(r3 + s16(i), 0xff); + m_icount -= 4; break; case 0xd0: // lps: load program status - m_scr[IAR] = space(AS_PROGRAM).read_dword(r3 + s16(i) + 0); - m_scr[ICS] = space(AS_PROGRAM).read_word(r3 + s16(i) + 4); - m_scr[CS] = space(AS_PROGRAM).read_word(r3 + s16(i) + 6); - // TODO: clear MCS/PCS - // TODO: defer interrupt enable + if (m_branch_state != BRANCH) + { + m_branch_target = space(AS_PROGRAM).read_dword(r3 + s16(i) + 0); + m_branch_state = BRANCH; + m_scr[ICS] = space(AS_PROGRAM).read_word(r3 + s16(i) + 4); + m_scr[CS] = space(AS_PROGRAM).read_word(r3 + s16(i) + 6); + m_scr[MPCS] &= ~0xffff; + // TODO: defer interrupt enable + + m_icount -= 15; + } + else + program_check(PCS_PCK | PCS_IOC); break; case 0xd1: // aei: add extended immediate - m_gpr[R2] = s32(s16(i)) + m_gpr[R3] + BIT(m_scr[CS], C0); - // TODO: LT, EQ, GT, C0, OV + flags_add(m_gpr[R3], s32(s16(i)) + bool(m_scr[CS] & CS_C)); + m_gpr[R2] = m_gpr[R3] + s32(s16(i)) + bool(m_scr[CS] & CS_C); break; case 0xd2: // sfi: subtract from immediate + flags_sub(s32(s16(i)), m_gpr[R3]); m_gpr[R2] = s32(s16(i)) - m_gpr[R3]; - // TODO: LT, EQ, GT, C0, OV break; case 0xd3: // cli: compare logical immediate - { - // LT, EQ, GT - m_scr[CS] &= ~(7U << GT); - - if (m_gpr[R2] == u32(s32(s16(i)))) - m_scr[CS] |= (1U << EQ); - else - if (m_gpr[R2] < u32(s32(s16(i)))) - m_scr[CS] |= (1U << LT); - else - m_scr[CS] |= (1U << GT); - } + flags(m_gpr[R3] - u32(s32(s16(i)))); break; case 0xd4: // ci: compare immediate - { - // LT, EQ, GT - m_scr[CS] &= ~(7U << GT); - - if (m_gpr[R2] == s32(s16(i))) - m_scr[CS] |= (1U << EQ); - else - if (s32(m_gpr[R2]) < s16(i)) - m_scr[CS] |= (1U << LT); - else - m_scr[CS] |= (1U << GT); - } + flags(s32(m_gpr[R3]) - s32(s16(i))); break; case 0xd5: // niuz: and immediate upper half extended zeroes m_gpr[R2] = (u32(i) << 16) & m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xd6: // niuo: and immediate upper half extended ones m_gpr[R2] = ((u32(i) << 16) | 0x0000'ffffU) & m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xd7: // xiu: exclusive or immediate upper half m_gpr[R2] = (u32(i) << 16) ^ m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xd8: // cau: compute address upper half m_gpr[R2] = r3 + (u32(i) << 16); break; case 0xd9: // stm: store multiple - for (unsigned reg = R2, offset = 0; reg < 16; reg++, offset += 4) - space(AS_PROGRAM).write_dword(r3 + s16(i) + offset, m_gpr[reg]); + for (unsigned reg = R2, offset = r3 + s16(i); reg < 16; reg++, offset += 4) + { + space(AS_PROGRAM).write_dword(offset, m_gpr[reg]); + m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 2; + } + m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 2; break; case 0xda: // lh: load half m_gpr[R2] = space(AS_PROGRAM).read_word(r3 + s16(i)); + m_icount -= 4; break; case 0xdb: // iow: input/output write - // TODO: program check on upper address byte set - space(2).write_dword(r3 + i, m_gpr[R2]); + if (r3 + i < 0x0100'0000U) + space(AS_IO).write_dword(r3 + i, m_gpr[R2]); + else + program_check(PCS_PCK | PCS_IOC); + m_icount--; break; case 0xdc: // sth: store half space(AS_PROGRAM).write_word(r3 + s16(i), m_gpr[R2]); + m_icount -= 4; break; case 0xdd: // st: store space(AS_PROGRAM).write_dword(r3 + s16(i), m_gpr[R2]); + m_icount -= 4; break; case 0xde: // stc: store character space(AS_PROGRAM).write_byte(r3 + s16(i), m_gpr[R2]); + m_icount -= 4; + break; + + default: + program_check(PCS_PCK | PCS_IOC); break; } } @@ -326,92 +418,85 @@ void romp_device::execute_run() switch (op >> 8) { case 0x90: // ais: add immediate short + flags_add(m_gpr[R2], R3); m_gpr[R2] += R3; - // TODO: LT, EQ, GT, C0, OV break; case 0x91: // inc: increment m_gpr[R2] += R3; break; case 0x92: // sis: subtract immediate short + flags_sub(m_gpr[R2], R3); m_gpr[R2] -= R3; - // TODO: LT, EQ, GT, C0, OV break; case 0x93: // dec: decrement m_gpr[R2] -= R3; break; case 0x94: // cis: compare immediate short - { - // LT, EQ, GT - m_scr[CS] &= ~(7U << GT); - - if (m_gpr[R2] == R3) - m_scr[CS] |= (1U << EQ); - else - if (s32(m_gpr[R2]) < R3) - m_scr[CS] |= (1U << LT); - else - m_scr[CS] |= (1U << GT); - } + flags(m_gpr[R2] - R3); break; case 0x95: // clrsb: clear scr bit - m_scr[R2] &= ~(0x0000'8000U >> R3); - // TODO: side effects? + set_scr(R2, m_scr[R2] & ~(0x0000'8000U >> R3)); + m_icount -= 3; break; case 0x96: // mfs: move from scr - m_gpr[R3] = m_scr[R2]; + if (R2 == IAR) + m_gpr[R3] = updated_iar; + else + m_gpr[R3] = m_scr[R2]; + m_icount--; break; case 0x97: // setsb: set scr bit - m_scr[R2] |= (0x0000'8000U >> R3); - // TODO: side effects, reserved bits + set_scr(R2, m_scr[R2] | (0x0000'8000U >> R3)); + m_icount -= 3; break; case 0x98: // clrbu: clear bit upper half m_gpr[R2] &= ~(0x8000'0000U >> R3); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0x99: // clrbl: clear bit lower half m_gpr[R2] &= ~(0x0000'8000U >> R3); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0x9a: // setbu: set bit upper half m_gpr[R2] |= (0x8000'0000U >> R3); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0x9b: // setbl: set bit lower half m_gpr[R2] |= (0x0000'8000U >> R3); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0x9c: // mftbiu: move from test bit immediate upper half - if (BIT(m_scr[CS], TB)) + if (m_scr[CS] & CS_T) m_gpr[R2] |= (0x8000'0000U >> R3); else m_gpr[R2] &= ~(0x8000'0000U >> R3); break; case 0x9d: // mftbil: move from test bit immediate lower half - if (BIT(m_scr[CS], TB)) + if (m_scr[CS] & CS_T) m_gpr[R2] |= (0x0000'8000U >> R3); else m_gpr[R2] &= ~(0x0000'8000U >> R3); break; case 0x9e: // mttbiu: move to test bit immediate upper half if (m_gpr[R2] & (0x8000'0000U >> R3)) - m_scr[CS] |= (1U << TB); + m_scr[CS] |= CS_T; else - m_scr[CS] &= ~(1U << TB); + m_scr[CS] &= ~CS_T; break; case 0x9f: // mttbil: move to test bit immediate lower half if (m_gpr[R2] & (0x0000'8000U >> R3)) - m_scr[CS] |= (1U << TB); + m_scr[CS] |= CS_T; else - m_scr[CS] &= ~(1U << TB); + m_scr[CS] &= ~CS_T; break; case 0xa0: // sari: shift algebraic right immediate m_gpr[R2] = s32(m_gpr[R2]) >> R3; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xa1: // sari16: shift algebraic right immediate plus sixteen m_gpr[R2] = s32(m_gpr[R2]) >> (R3 + 16); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xa4: // lis: load immediate short @@ -420,111 +505,108 @@ void romp_device::execute_run() case 0xa8: // sri: shift right immediate m_gpr[R2] >>= R3; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xa9: // sri16: shift right immediate plus sixteen m_gpr[R2] >>= (R3 + 16); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xaa: // sli: shift left immediate m_gpr[R2] <<= R3; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xab: // sli16: shift left immediate plus sixteen m_gpr[R2] <<= (R3 + 16); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xac: // srpi: shift right paired immediate m_gpr[R2 ^ 1] = m_gpr[R2] >> R3; - // TODO: LT, EQ, GT + flags(m_gpr[R2 ^ 1]); break; case 0xad: // srpi16: shift right paired immediate plus sixteen m_gpr[R2 ^ 1] = m_gpr[R2] >> (R3 + 16); - // TODO: LT, EQ, GT + flags(m_gpr[R2 ^ 1]); break; case 0xae: // slpi: shift left paired immediate m_gpr[R2 ^ 1] = m_gpr[R2] << R3; - // TODO: LT, EQ, GT + flags(m_gpr[R2 ^ 1]); break; case 0xaf: // slpi16: shift left paired immediate plus sixteen m_gpr[R2 ^ 1] = m_gpr[R2] << (R3 + 16); - // TODO: LT, EQ, GT + flags(m_gpr[R2 ^ 1]); break; case 0xb0: // sar: shift algebraic right m_gpr[R2] = s32(m_gpr[R2]) >> (m_gpr[R3] & 63); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xb1: // exts: extend sign m_gpr[R2] = s16(m_gpr[R3]); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xb2: // sf: subtract from + flags_sub(m_gpr[R3], m_gpr[R2]); m_gpr[R2] = m_gpr[R3] - m_gpr[R2]; - // TODO: LT, EQ, GT, C0, OV break; case 0xb3: // cl: compare logical - { - // LT, EQ, GT - m_scr[CS] &= ~(7U << GT); - - if (m_gpr[R2] == m_gpr[R3]) - m_scr[CS] |= (1U << EQ); - else - if (m_gpr[R2] < m_gpr[R3]) - m_scr[CS] |= (1U << LT); - else - m_scr[CS] |= (1U << GT); - } + flags(m_gpr[R2] - m_gpr[R3]); break; case 0xb4: // c: compare - { - // LT, EQ, GT - m_scr[CS] &= ~(7U << GT); - - if (m_gpr[R2] == m_gpr[R3]) - m_scr[CS] |= (1U << EQ); - else - if (s32(m_gpr[R2]) < s32(m_gpr[R3])) - m_scr[CS] |= (1U << LT); - else - m_scr[CS] |= (1U << GT); - } + flags(s32(m_gpr[R2]) - s32(m_gpr[R3])); break; case 0xb5: // mts: move to scr - m_scr[R2] = m_gpr[R3]; + set_scr(R2, m_gpr[R3]); + m_icount -= 2; break; //case 0xb6: // d: divide step - + // m_icount -= 2; case 0xb8: // sr: shift right m_gpr[R2] >>= (m_gpr[R3] & 63); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xb9: // srp: shift right paired m_gpr[R2 ^ 1] = m_gpr[R2] >> (m_gpr[R3] & 63); - // TODO: LT, EQ, GT + flags(m_gpr[R2 ^ 1]); break; case 0xba: // sl: shift left m_gpr[R2] <<= (m_gpr[R3] & 63); - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xbb: // slp: shift left paired m_gpr[R2 ^ 1] = m_gpr[R2] << (m_gpr[R3] & 63); - // TODO: LT, EQ, GT + flags(m_gpr[R2 ^ 1]); break; case 0xbc: // mftb: move from test bit - if (BIT(m_scr[CS], TB)) + if (m_scr[CS] & CS_T) m_gpr[R2] |= (0x8000'0000U >> (m_gpr[R3] & 31)); else m_gpr[R2] &= ~(0x8000'0000U >> (m_gpr[R3] & 31)); break; - //case 0xbd: // tgte: trap if register greater than or equal - //case 0xbe: // tlt: trap if register less than + case 0xbd: // tgte: trap if register greater than or equal + if (m_branch_state == BRANCH) + program_check(PCS_PCK | PCS_IOC); + else if (m_gpr[R2] >= m_gpr[R3]) + { + program_check(PCS_PCK | PCS_PT); + m_icount -= 14; + } + m_icount--; + break; + case 0xbe: // tlt: trap if register less than + if (m_branch_state == BRANCH) + program_check(PCS_PCK | PCS_IOC); + else if (m_gpr[R2] < m_gpr[R3]) + { + program_check(PCS_PCK | PCS_PT); + m_icount -= 14; + } + m_icount--; + break; case 0xbf: // mttb: move to test bit if (m_gpr[R2] & (0x8000'0000U >> (m_gpr[R3] & 31))) - m_scr[CS] |= (1U << TB); + m_scr[CS] |= CS_T; else - m_scr[CS] &= ~(1U << TB); + m_scr[CS] &= ~CS_T; break; case 0xe0: // abs: absolute @@ -532,85 +614,119 @@ void romp_device::execute_run() m_gpr[R2] = -s32(m_gpr[R3]); else m_gpr[R2] = m_gpr[R3]; + 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]); m_gpr[R2] += m_gpr[R3]; - // TODO: LT, EQ, GT, C0, OV break; case 0xe2: // s: subtract + flags_sub(m_gpr[R2], m_gpr[R3]); m_gpr[R2] -= m_gpr[R3]; - // TODO: LT, EQ, GT, C0, OV break; case 0xe3: // o: or m_gpr[R2] |= m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xe4: // twoc: twos complement + flags_sub(0, m_gpr[R3]); m_gpr[R2] = -m_gpr[R3]; - // TODO: LT, EQ, GT, C0, OV break; case 0xe5: // n: and m_gpr[R2] &= m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; //case 0xe6: // m: multiply step + // m_icount -= 3; case 0xe7: // x: exclusive or m_gpr[R2] ^= m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xe8: // bnbr: branch on not condition bit - if (!BIT(m_scr[CS], R2 ^ 15)) - m_scr[IAR] = m_gpr[R3] & ~1; + if (m_branch_state == BRANCH) + program_check(PCS_PCK | PCS_IOC); + else if (!BIT(m_scr[CS], R2 ^ 15)) + { + m_branch_target = m_gpr[R3] & ~1; + m_branch_state = BRANCH; + } break; case 0xe9: // bnbrx: branch on not condition bit with execute - if (!BIT(m_scr[CS], R2 ^ 15)) + if (m_branch_state == BRANCH) + program_check(PCS_PCK | PCS_IOC); + else if (!BIT(m_scr[CS], R2 ^ 15)) { m_branch_target = m_gpr[R3] & ~1; - m_branch_state = BRANCH; + m_branch_state = DELAY; } break; case 0xeb: // lhs: load half short m_gpr[R2] = space(AS_PROGRAM).read_word(m_gpr[R3]); + m_icount -= 4; break; case 0xec: // balr: branch and link - m_gpr[R2] = m_scr[IAR]; - m_scr[IAR] = m_gpr[R3] & ~1; + if (m_branch_state != BRANCH) + { + m_gpr[R2] = updated_iar; + m_branch_target = m_gpr[R3] & ~1; + m_branch_state = BRANCH; + m_icount -= 4; + } + else + program_check(PCS_PCK | PCS_IOC); break; case 0xed: // balrx: branch and link with execute - m_gpr[R2] = m_scr[IAR] + 4; - m_branch_target = m_gpr[R3] & ~1; - m_branch_state = BRANCH; + if (m_branch_state != BRANCH) + { + m_gpr[R2] = updated_iar + 4; + m_branch_target = m_gpr[R3] & ~1; + m_branch_state = DELAY; + m_icount -= 4; + } + else + program_check(PCS_PCK | PCS_IOC); break; case 0xee: // bbr: branch on condition bit - if (BIT(m_scr[CS], R2 ^ 15)) - m_scr[IAR] = m_gpr[R3] & ~1; + if (m_branch_state == BRANCH) + program_check(PCS_PCK | PCS_IOC); + else if (BIT(m_scr[CS], R2 ^ 15)) + { + m_branch_target = m_gpr[R3] & ~1; + m_branch_state = BRANCH; + m_icount -= 4; + } break; case 0xef: // bbrx: branch on condition bit with execute - if (BIT(m_scr[CS], R2 ^ 15)) + if (m_branch_state == BRANCH) + program_check(PCS_PCK | PCS_IOC); + else if (BIT(m_scr[CS], R2 ^ 15)) { m_branch_target = m_gpr[R3] & ~1; - m_branch_state = BRANCH; + m_branch_state = DELAY; + m_icount -= 4; } break; //case 0xf0: // wait: wait + // if (m_branch_state == BRANCH) + // program_check(PCS_PCK | PCS_IOC); case 0xf1: // ae: add extended - m_gpr[R2] += m_gpr[R3] + BIT(m_scr[CS], C0); - // TODO: LT, EQ, GT, C0, OV + flags_add(m_gpr[R2], m_gpr[R3] + bool(m_scr[CS] & CS_C)); + m_gpr[R2] += m_gpr[R3] + bool(m_scr[CS] & CS_C); break; case 0xf2: // se: subtract extended - m_gpr[R2] -= m_gpr[R3] + BIT(m_scr[CS], C0); - // TODO: LT, EQ, GT, C0, OV + flags_sub(m_gpr[R2], m_gpr[R3] + bool(m_scr[CS] & CS_C)); + m_gpr[R2] -= m_gpr[R3] + bool(m_scr[CS] & CS_C); break; case 0xf3: // ca16: compute address 16-bit m_gpr[R2] = (m_gpr[R3] & 0xffff'0000U) | (u16(m_gpr[R2]) + u16(m_gpr[R3])); break; case 0xf4: // onec: ones complement m_gpr[R2] = ~m_gpr[R3]; - // TODO: LT, EQ, GT + flags(m_gpr[R2]); break; case 0xf5: // clz: count leading zeros m_gpr[R2] = count_leading_zeros(u16(m_gpr[R3])) - 16; @@ -637,6 +753,10 @@ void romp_device::execute_run() case 0xff: // mc32: move character three from two m_gpr[R2] = (m_gpr[R2] & 0xffff'ff00U) | u8(m_gpr[R3] >> 8); break; + + default: + program_check(PCS_PCK | PCS_IOC); + break; } break; } @@ -644,26 +764,62 @@ void romp_device::execute_run() // update iar and branch state switch (m_branch_state) { - case SUBJECT: - m_scr[IAR] = m_branch_target; - m_branch_state = NONE; + case DEFAULT: + m_scr[IAR] = updated_iar; break; case BRANCH: - m_branch_state = SUBJECT; + m_scr[IAR] = m_branch_target; + m_branch_state = DEFAULT; break; - default: + case DELAY: + m_scr[IAR] = updated_iar; + m_branch_state = BRANCH; + break; + + case EXCEPTION: + m_branch_state = DEFAULT; break; } } } +void romp_device::set_scr(unsigned scr, u32 data) +{ + static char const *const scr_names[16] = + { + "scr0", "scr1", "scr2", "scr3", "scr4", "scr5", "cous", "cou", + "ts", "scr9", "mq", "mpcs", "irb", "iar", "ics", "cs", + }; + + LOG("set_scr %s data 0x%08x (%s)\n", scr_names[scr], data, machine().describe_context()); + + switch (scr) + { + case ICS: + m_out_tm(bool(data & ICS_TM)); + break; + + default: + break; + } + + m_scr[scr] = data; +} + void romp_device::execute_set_input(int irqline, int state) { - // enable debugger interrupt breakpoints - if (state) + // interrupt lines are active low + if (!state) + { + m_scr[IRB] |= (IRB_L0 >> irqline); + + // enable debugger interrupt breakpoints standard_irq_callback(irqline); + } + else + m_scr[IRB] &= ~(IRB_L0 >> irqline); } device_memory_interface::space_config_vector romp_device::memory_space_config() const @@ -683,3 +839,133 @@ std::unique_ptr romp_device::create_disassembler() { return std::make_unique(); } + +void romp_device::flags(u32 const data) +{ + m_scr[CS] &= ~(CS_L | CS_E | CS_G); + + if (data == 0) + m_scr[CS] |= CS_E; + else + if (BIT(data, 31)) + m_scr[CS] |= CS_L; + else + m_scr[CS] |= CS_G; +} + +void romp_device::flags_add(u32 const op1, u32 const op2) +{ + u32 const result = op1 + op2; + + m_scr[CS] &= ~(CS_L | CS_E | CS_G | CS_C | CS_O); + + if (result == 0) + m_scr[CS] |= CS_E; + else + if (BIT(result, 31)) + m_scr[CS] |= CS_L; + else + m_scr[CS] |= CS_G; + + // carry + if ((BIT(op2, 31) && BIT(op1, 31)) || (!BIT(result, 31) && (BIT(op2, 31) || BIT(op1, 31)))) + m_scr[CS] |= CS_C; + + // overflow + if ((BIT(op2, 31) == BIT(op1, 31)) && (BIT(result, 31) != BIT(op2, 31))) + m_scr[CS] |= CS_O; +} + +void romp_device::flags_sub(u32 const op1, u32 const op2) +{ + u32 const result = op1 - op2; + + m_scr[CS] &= ~(CS_L | CS_E | CS_G | CS_C | CS_O); + + if (result == 0) + m_scr[CS] |= CS_E; + else + if (BIT(result, 31)) + m_scr[CS] |= CS_L; + else + m_scr[CS] |= CS_G; + + // carry + if ((!BIT(op2, 31) && BIT(op1, 31)) || (BIT(result, 31) && (!BIT(op2, 31) || BIT(op1, 31)))) + m_scr[CS] |= CS_C; + + // overflow + if ((BIT(op2, 31) != BIT(op1, 31)) && (BIT(result, 31) != BIT(op2, 31))) + m_scr[CS] |= CS_O; +} + +void romp_device::interrupt_check() +{ + // interrupts masked or no interrupts + if ((m_scr[ICS] & ICS_IM) || !(m_scr[IRB] & IRB_ALL)) + return; + + unsigned const priority = m_scr[ICS] & ICS_PP; + for (unsigned irl = 0; irl < priority; irl++) + { + if (BIT(m_scr[IRB], 15 - irl)) + { + LOGMASKED(LOG_INTERRUPT, "interrupt_check taking interrupt request level %d\n", irl); + interrupt_enter(irl); + + break; + } + } +} + +void romp_device::machine_check(u32 mcs) +{ + debugger_exception_hook(7); + + LOGMASKED(LOG_INTERRUPT, "machine_check mcs 0x%08x\n", mcs); + + m_scr[MPCS] &= ~MCS_ALL; + m_scr[MPCS] |= (mcs & MCS_ALL); + + interrupt_enter(7); + + m_branch_state = EXCEPTION; +} + +void romp_device::program_check(u32 pcs) +{ + debugger_exception_hook(8); + + LOGMASKED(LOG_INTERRUPT, "program_check pcs 0x%08x\n", pcs); + + m_scr[MPCS] &= ~PCS_ALL; + m_scr[MPCS] |= (pcs & PCS_ALL); + + interrupt_enter(8); + + m_branch_state = EXCEPTION; +} + +void romp_device::interrupt_enter(unsigned vector, u16 svc) +{ + // take interrupt + offs_t const address = 0x100 + vector * 16; + + // disable address translation + m_out_tm(0); + + // save old program status + space(AS_PROGRAM).write_dword(address + 0, m_scr[IAR]); + space(AS_PROGRAM).write_word(address + 4, u16(m_scr[ICS])); + space(AS_PROGRAM).write_word(address + 6, u16(m_scr[CS])); + if (vector == 9) + space(AS_PROGRAM).write_word(address + 14, svc); + + // load new program status + m_scr[IAR] = space(AS_PROGRAM).read_dword(address + 8); + m_scr[ICS] = space(AS_PROGRAM).read_word(address + 12); + if (vector < 7) + m_scr[CS] = space(AS_PROGRAM).read_word(address + 14); + + m_out_tm(bool(m_scr[ICS] & ICS_TM)); +} diff --git a/src/devices/cpu/romp/romp.h b/src/devices/cpu/romp/romp.h index bcbc163214d..c7b866c9a8e 100644 --- a/src/devices/cpu/romp/romp.h +++ b/src/devices/cpu/romp/romp.h @@ -11,6 +11,8 @@ class romp_device : public cpu_device public: romp_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + auto out_tm() { return m_out_tm.bind(); } + protected: enum registers : unsigned { @@ -20,28 +22,74 @@ protected: enum scr : unsigned { - COS = 6, // counter source - COU = 7, // counter - TS = 8, // timer status - MQ = 10, // multiplier quotient - MCS = 11, // machine check status - PCS = 11, // program check status - IRB = 12, // interrupt request buffer - IAR = 13, // instruction address register - ICS = 14, // interrupt control status - CS = 15, // condition status + COUS = 6, // counter source + COU = 7, // counter + TS = 8, // timer status + MQ = 10, // multiplier quotient + MPCS = 11, // machine/program check status + IRB = 12, // interrupt request buffer + IAR = 13, // instruction address register + ICS = 14, // interrupt control status + CS = 15, // condition status }; - enum cs : unsigned + enum mpcs_mask : u32 { - TB = 0, // test bit - OV = 1, // overflow - // reserved - C0 = 3, // carry zero - GT = 4, // greater than - EQ = 5, // equal - LT = 6, // less than - PZ = 7, // permanent zero + // reserved + PCS_DAE = 0x0000'0002, // data address exception + PCS_IAE = 0x0000'0004, // instruction address exception + PCS_IOC = 0x0000'0008, // illegal operation code + PCS_PIE = 0x0000'0010, // privileged instruction exception + PCS_PT = 0x0000'0020, // program trap + PCS_PCU = 0x0000'0040, // program check with unknown origin + PCS_PCK = 0x0000'0080, // program check with known origin + // reserved + MCS_IOT = 0x0000'0200, // i/o trap + MCS_PCT = 0x0000'0400, // processor channel timeout + MCS_DT = 0x0000'0800, // data timeout + MCS_IT = 0x0000'1000, // instruction timeout + MCS_PC = 0x0000'2000, // parity check + // reserved + MCS_PCC = 0x0000'8000, // processor channel check + + MCS_ALL = 0x0000'ff00, + PCS_ALL = 0x0000'00ff, + }; + + enum irb_mask : u16 + { + // reserved + IRB_L6 = 0x0200, // interrupt request level 6 + IRB_L5 = 0x0400, // interrupt request level 5 + IRB_L4 = 0x0800, // interrupt request level 4 + IRB_L3 = 0x1000, // interrupt request level 3 + IRB_L2 = 0x2000, // interrupt request level 2 + IRB_L1 = 0x4000, // interrupt request level 1 + IRB_L0 = 0x8000, // interrupt request level 0 + + IRB_ALL = 0xfe00, + }; + enum ics_mask : u32 + { + ICS_PP = 0x0000'0007, // processor priority + // reserved + ICS_RS = 0x0000'0070, // register set number + ICS_CS = 0x0000'0080, // check stop mask + ICS_IM = 0x0000'0100, // interrupt mask + ICS_TM = 0x0000'0200, // translate mode + ICS_US = 0x0000'0400, // unprivileged state + ICS_MP = 0x0000'0800, // memory protect + ICS_PE = 0x0000'1000, // parity error retry interrupt enable + }; + enum cs_mask : u32 + { + CS_T = 0x0000'0001, // test bit + CS_O = 0x0000'0002, // overflow + CS_C = 0x0000'0008, // carry + CS_G = 0x0000'0010, // greater than + CS_E = 0x0000'0020, // equal + CS_L = 0x0000'0040, // less than + CS_Z = 0x0000'0080, // permanent zero }; // device_t overrides @@ -59,6 +107,9 @@ protected: virtual space_config_vector memory_space_config() const override; virtual bool memory_translate(int spacenum, int intention, offs_t &address) override; + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + // device_disasm_interface overrides virtual std::unique_ptr create_disassembler() override; @@ -69,10 +120,23 @@ private: u32 ba(u16 hi, u16 lo) const { return ((u32(hi) << 16) | lo) & 0x00ff'fffeU; } s32 bi(u16 hi, u16 lo) const { return s32((u32(hi) << 16 | lo) << 12) >> 11; } + void flags(u32 const op1); + void flags_add(u32 const op1, u32 const op2); + void flags_sub(u32 const op1, u32 const op2); + + void set_scr(unsigned scr, u32 data); + + void interrupt_check(); + void machine_check(u32 mcs); + void program_check(u32 pcs); + void interrupt_enter(unsigned vector, u16 svc = 0); + // address spaces address_space_config const m_mem_config; address_space_config const m_io_config; + devcb_write_line m_out_tm; + // mame state int m_icount; @@ -83,9 +147,10 @@ private: // internal state enum branch_state : unsigned { - NONE = 0, - SUBJECT = 1, // branch subject instruction active - BRANCH = 2, // branch instruction active + DEFAULT = 0, + BRANCH = 1, // branch subject instruction active + DELAY = 2, // delayed branch instruction active + EXCEPTION = 3, } m_branch_state; u32 m_branch_target; diff --git a/src/devices/cpu/romp/rompdasm.cpp b/src/devices/cpu/romp/rompdasm.cpp index 02cc5c3a1bb..b658ee13dfc 100644 --- a/src/devices/cpu/romp/rompdasm.cpp +++ b/src/devices/cpu/romp/rompdasm.cpp @@ -196,8 +196,8 @@ offs_t romp_disassembler::disassemble(std::ostream &stream, offs_t pc, data_buff case 0xeb: util::stream_format(stream, "lhs %s,0(%s)", gpr[R2], gpr[R3]); break; // load half short case 0xec: util::stream_format(stream, "balr %s,%s", gpr[R2], gpr[R3]); flags |= STEP_OVER; break; // branch and link case 0xed: util::stream_format(stream, "balrx %s,%s", gpr[R2], gpr[R3]); flags |= STEP_OVER | step_over_extra(1); break; // branch and link with execute - case 0xee: util::stream_format(stream, "b%-5s %s,%s", util::string_format("%sr", cc[N]), gpr[R3]); break; // branch on condition bit - case 0xef: util::stream_format(stream, "b%-5s %s,%s", util::string_format("%srx", cc[N]), gpr[R3]); break; // branch on condition bit with execute + case 0xee: util::stream_format(stream, "b%-5s %s", util::string_format("%sr", cc[N]), gpr[R3]); break; // branch on condition bit + case 0xef: util::stream_format(stream, "b%-5s %s", util::string_format("%srx", cc[N]), gpr[R3]); break; // branch on condition bit with execute case 0xf0: util::stream_format(stream, "wait"); break; // wait case 0xf1: util::stream_format(stream, "ae %s,%s", gpr[R2], gpr[R3]); break; // add extended -- cgit v1.2.3