From 34b7c397c14bc03760e2f45814a5df0bcc6746a1 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Mon, 1 Apr 2024 12:39:16 +0700 Subject: [PATCH] palm: improve interrupt handling * fix debugger register access * consolidate internal state * add ros selection and bus out callbacks * add internal control instruction handler --- src/devices/cpu/palm/palm.cpp | 96 ++++++++++++++++++++++++++--------- src/devices/cpu/palm/palm.h | 12 ++++- 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/src/devices/cpu/palm/palm.cpp b/src/devices/cpu/palm/palm.cpp index 4e7558770d6..0febe5b3793 100644 --- a/src/devices/cpu/palm/palm.cpp +++ b/src/devices/cpu/palm/palm.cpp @@ -8,7 +8,7 @@ * - IBM 5100 Maintenance Information Manual, SY31-0405-3, Fourth Edition (October 1979), International Business Machines Corporation * * TODO: - * - machine check/interrupts + * - machine check * - instruction timing */ @@ -30,6 +30,8 @@ template constexpr T IBIT(T x, U n, V w) return BIT(x, sizeof(T) * 8 - n - w, w); } +static u8 constexpr il_priority[] = { 0, 1, 2, 2, 3, 3, 3, 3 }; + DEFINE_DEVICE_TYPE(PALM, palm_device, "palm", "IBM PALM") palm_device::palm_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) @@ -38,29 +40,41 @@ palm_device::palm_device(machine_config const &mconfig, char const *tag, device_ , m_rws_config("rws", ENDIANNESS_BIG, 16, 16) , m_ioc_config("ioc", ENDIANNESS_BIG, 8, 4) , m_iod_config("iod", ENDIANNESS_BIG, 8, 4) + , m_getb_bus(*this) + , m_select_ros(*this) , m_icount(0) , m_r{} - , m_il(0) - , m_il_pending(0) - , m_irpt_req(0) { } +enum ff_mask : u8 +{ + FF_IPL = 0x80, // initial program load + FF_MSS = 0x40, // microprogram storage switch + + FF_IE = 0x08, // interrupt enable + FF_IR3 = 0x04, // interrupt request 3 + FF_IR2 = 0x02, // interrupt request 2 + FF_IR1 = 0x01, // interrupt request 1 + + FF_IR = 0x07, // interrupt request +}; + void palm_device::device_start() { set_icountptr(m_icount); - state_add(STATE_GENPC, "GENPC", m_r[m_il][0]).mask(0xfffe).noshow(); - state_add(STATE_GENPCBASE, "CURPC", m_r[m_il][0]).mask(0xfffe); + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "CURPC", [this]() { return m_r[m_il][0] & 0xfffeU; }); state_add(0, "IL", m_il); for (unsigned i = 0; i < std::size(m_r[m_il]); i++) - state_add(i + 1, util::string_format("R%d", i).c_str(), m_r[m_il][i]); + state_add(i + 1, util::string_format("R%d", i).c_str(), [this, i]() { return m_r[m_il][i]; }, [this, i](u16 data) { m_r[m_il][i] = data; }); + save_item(NAME(m_pc)); save_item(NAME(m_r)); save_item(NAME(m_il)); - save_item(NAME(m_il_pending)); - save_item(NAME(m_irpt_req)); + save_item(NAME(m_ff)); space(AS_ROS).specific(m_ros); space(AS_RWS).specific(m_rws); @@ -72,10 +86,13 @@ void palm_device::device_reset() { space(AS_RWS).install_ram(0, sizeof(m_r) - 1, m_r); - m_il = 0; + // select instruction source + m_ff = FF_IPL | FF_MSS; + m_select_ros((m_ff & FF_MSS) && !(m_ff & FF_IPL)); // read initial PC from ROS - m_r[m_il][0] = m_ros.read_word(0); + m_il = 0; + m_pc = m_r[m_il][0] = m_ros.read_word(0); } #define Rx r[IBIT(op, 4, 4)] @@ -88,13 +105,14 @@ void palm_device::execute_run() { while (m_icount > 0) { - // immediately switch to highest pending interrupt level - if (m_il != m_il_pending) + // handle pending interrupts + u8 const il = il_priority[m_ff & FF_IR]; + if ((m_ff & FF_IE) && m_il != il) { - m_il = m_il_pending; + m_il = il; // notify the debugger - if (m_il && machine().debug_flags & DEBUG_FLAG_ENABLED) + if (m_il && (machine().debug_flags & DEBUG_FLAG_ENABLED)) debug()->interrupt_hook(m_il - 1, m_r[m_il][0] & ~1); } @@ -133,7 +151,13 @@ void palm_device::execute_run() case 0xf: Ry += (7 - count_leading_ones_32(u32(m_iod.read_byte(DA)) << 24)) * 2; break; // get to register and add } break; - case 0x1: m_ioc.write_byte(DA, IMM); break; // control + case 0x1: + // control + if (DA == 0) + control(IMM); + + m_ioc.write_byte(DA, IMM); + break; case 0x2: Rx = m_rws.read_word(IMM * 2); break; // load halfword direct case 0x3: m_rws.write_word(IMM * 2, Rx); break; // store halfword direct case 0x4: @@ -185,6 +209,8 @@ void palm_device::execute_run() } else { + m_getb_bus(DA, Ry); + if (MOD < 0xc) { // get byte @@ -201,13 +227,12 @@ void palm_device::execute_run() // TODO: average instruction time quoted as 1.75µs (~27 machine cycles) m_icount -= 27; + m_pc = r[0]; } } void palm_device::execute_set_input(int irqline, int state) { - u8 const il_priority[] = { 0, 1, 2, 3, 3, 3, 3, 3 }; - switch (irqline) { case INPUT_LINE_NMI: @@ -217,12 +242,9 @@ void palm_device::execute_set_input(int irqline, int state) default: // interrupt lines are active low if (!state) - m_irpt_req |= 1U << irqline; + m_ff |= 1U << irqline; else - m_irpt_req &= ~(1U << irqline); - - // update pending interrupt level - m_il_pending = il_priority[m_irpt_req & 7]; + m_ff &= ~(1U << irqline); break; } } @@ -278,3 +300,31 @@ s16 palm_device::modifier(unsigned const modifier) const else return 0; } + +void palm_device::control(u8 data) +{ + LOG("control 0x%02x (%s)\n", data, machine().describe_context()); + + // 0 reset controller errors + + // 1: 0=disable interrupts + // 2: 0=enable interrupts + if (!IBIT(data, 1)) + m_ff &= ~FF_IE; + else if (!IBIT(data, 2)) + m_ff |= FF_IE; + + // TODO: 3 not used? + // 4 not used (0:display & select frame on) + + // 5 state transition + if (!IBIT(data, 5)) + { + m_ff &= ~FF_IPL; + m_ff ^= FF_MSS; + + m_select_ros((m_ff & FF_MSS) && !(m_ff & FF_IPL)); + } + + // TODO: 6..7 not used (frame bit #1,2?) +} diff --git a/src/devices/cpu/palm/palm.h b/src/devices/cpu/palm/palm.h index ff2bc0c6d08..bd1a1c15974 100644 --- a/src/devices/cpu/palm/palm.h +++ b/src/devices/cpu/palm/palm.h @@ -20,6 +20,9 @@ public: static unsigned constexpr AS_IOC = AS_IO; static unsigned constexpr AS_IOD = 4; + auto getb_bus() { return m_getb_bus.bind(); } + auto select_ros() { return m_select_ros.bind(); } + palm_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); protected: @@ -43,6 +46,8 @@ protected: bool condition(unsigned const modifier, u16 const data, u8 const mask) const; s16 modifier(unsigned const modifier) const; + void control(u8 data); + private: // address spaces address_space_config const m_ros_config; @@ -55,13 +60,16 @@ private: memory_access<4, 0, 0, ENDIANNESS_BIG>::specific m_ioc; memory_access<4, 0, 0, ENDIANNESS_BIG>::specific m_iod; + devcb_write8 m_getb_bus; + devcb_write_line m_select_ros; + // mame state int m_icount; + u16 m_pc; u16 m_r[4][16]; // registers u8 m_il; // interrupt level - u8 m_il_pending; // pending interrupt level - u8 m_irpt_req; // interrupt line state + u8 m_ff; // controller flip-flops }; DECLARE_DEVICE_TYPE(PALM, palm_device)