From 26ba3b1af9e37ac7766bdbb806efe4743bfd9cbe Mon Sep 17 00:00:00 2001 From: shattered Date: Sat, 23 Mar 2024 15:31:06 +0000 Subject: [PATCH] cpu/t11: Improved trace trap processing, and added basic interrupt processing to the K1801VM1. (#12151) --- src/devices/cpu/t11/t11.cpp | 133 +++++++++++++++++++++++++++++++++ src/devices/cpu/t11/t11.h | 25 ++++++- src/devices/cpu/t11/t11ops.hxx | 50 +++++++++---- 3 files changed, 189 insertions(+), 19 deletions(-) diff --git a/src/devices/cpu/t11/t11.cpp b/src/devices/cpu/t11/t11.cpp index 448dec30feb..487a7a57003 100644 --- a/src/devices/cpu/t11/t11.cpp +++ b/src/devices/cpu/t11/t11.cpp @@ -163,6 +163,8 @@ int t11_device::POP() #define GET_V (PSW & VFLAG) #define GET_Z (PSW & ZFLAG) #define GET_N (PSW & NFLAG) +#define GET_T (PSW & (1 << 4)) +#define GET_I (PSW & (1 << 7)) /* clears flags */ #define CLR_C (PSW &= ~CFLAG) @@ -210,6 +212,122 @@ static const struct irq_table_entry irq_table[] = { 7<<5, 0140 } }; +// PSW7 masks external interrupts (except IRQ1) -- IRQ2, IRQ3, VIRQ +// PSW11 also masks IRQ1. PSW10 also masks ACLO. +void k1801vm1_device::t11_check_irqs() +{ + // 2. bus error on vector fetch; nm, vec 160012 + // 3. double bus error; nm, vec 160006 + // 4. bus error; PSW11, PSW10 + if (m_bus_error) + { + m_bus_error = false; + m_mcir = MCIR_IRQ; + m_vsel = T11_TIMEOUT; + } + // 5. illegal insn; nm + else if (m_mcir == MCIR_ILL) + { + WWORD(VM1_SEL1, RWORD(VM1_SEL1) & ~SEL1_HALT); + PUSH(PSW); + PUSH(PC); + PC = RWORD(m_vsel); + PSW = RWORD(m_vsel + 2); + } + // 6. trace trap; WCPU + else if (m_trace_trap && m_mcir == MCIR_NONE) // allow trap_to() to execute first + { + if (GET_T) + { + m_mcir = MCIR_IRQ; + m_vsel = T11_BPT; + } + else + m_trace_trap = false; + } + else if (GET_T) + { + m_trace_trap = true; + } + // 7. power fail (ACLO pin); PSW10 + else if (m_power_fail) + { + m_mcir = MCIR_IRQ; + m_vsel = T11_PWRFAIL; + } + // 8. external HALT (nIRQ1 pin); PSW11, PSW10 + else if (m_hlt_active) + { + m_mcir = MCIR_HALT; + m_vsel = VM1_HALT; + } + // 9. internal timer, vector 0270; PSW7, PSW10 + // 10. line clock (nIRQ2 pin); PSW7, PSW10 + else if (BIT(m_cp_state, 2) && !GET_I) + { + m_mcir = MCIR_IRQ; + m_vsel = VM1_EVNT; + } + // 11. nIRQ3 pin; PSW7, PSW10 + else if (BIT(m_cp_state, 3) && !GET_I) + { + m_mcir = MCIR_IRQ; + m_vsel = VM1_IRQ3; + } + // 12. nVIRQ pin; PSW7, PSW10 + else if (m_vec_active && !GET_I) + { + int vec = m_in_iack_func(0); + if (vec == -1 || vec == 0) + { + m_vec_active = 0; + return; + } + m_mcir = MCIR_IRQ; + m_vsel = vec; + } + + switch (m_mcir) + { + case MCIR_SET: + if (m_vsel >= 0160000) // FIXME + WWORD(VM1_SEL1, RWORD(VM1_SEL1) | SEL1_HALT); + else + WWORD(VM1_SEL1, RWORD(VM1_SEL1) & ~SEL1_HALT); + PUSH(PSW); + PUSH(PC); + PC = RWORD(m_vsel); + PSW = RWORD(m_vsel + 2); + break; + + case MCIR_IRQ: + take_interrupt(m_vsel); + break; + + case MCIR_HALT: + take_interrupt_halt(m_vsel); + break; + } + + m_mcir = MCIR_NONE; +} + +void k1801vm1_device::take_interrupt_halt(uint16_t vector) +{ + // enter HALT mode + WWORD(VM1_SEL1, RWORD(VM1_SEL1) | SEL1_HALT); + + // push the old state, set the new one + WWORD(VM1_STACK, PC); + WWORD(VM1_STACK + 2, PSW); + PCD = RWORD(vector); + PSW = RWORD(vector + 2); + + // count cycles and clear the WAIT flag + m_icount -= 114; + m_wait_state = 0; +} + void t11_device::t11_check_irqs() { // HLT is nonmaskable @@ -337,6 +455,10 @@ void t11_device::device_start() save_item(NAME(m_hlt_active)); save_item(NAME(m_power_fail)); save_item(NAME(m_ext_halt)); + save_item(NAME(m_trace_trap)); + save_item(NAME(m_check_irqs)); + save_item(NAME(m_mcir)); + save_item(NAME(m_vsel)); // Register debugger state state_add( T11_PC, "PC", m_reg[7].w.l).formatstr("%06O"); @@ -436,6 +558,8 @@ void t11_device::device_reset() m_power_fail = false; m_bus_error = false; m_ext_halt = false; + m_trace_trap = false; + m_check_irqs = false; } void k1801vm1_device::device_reset() @@ -444,6 +568,9 @@ void k1801vm1_device::device_reset() PC = RWORD(VM1_SEL1) & 0177400; WWORD(VM1_SEL1, RWORD(VM1_SEL1) | SEL1_HALT); + + m_mcir = MCIR_NONE; + m_vsel = 0; } void k1801vm2_device::device_reset() @@ -528,6 +655,12 @@ void t11_device::execute_run() op = ROPCODE(); (this->*s_opcode_table[op >> 3])(op); + + if (m_check_irqs || m_trace_trap || GET_T) + { + m_check_irqs = false; + t11_check_irqs(); + } } } diff --git a/src/devices/cpu/t11/t11.h b/src/devices/cpu/t11/t11.h index b4e8032d165..cb4c2d477c8 100644 --- a/src/devices/cpu/t11/t11.h +++ b/src/devices/cpu/t11/t11.h @@ -51,14 +51,25 @@ protected: T11_IOT = 020, // IOT instruction vector T11_PWRFAIL = 024, // Power fail vector T11_EMT = 030, // EMT instruction vector - T11_TRAP = 034 // TRAP instruction vector + T11_TRAP = 034, // TRAP instruction vector + // K1801 vectors + VM1_EVNT = 0100, // EVNT pin vector + VM1_IRQ3 = 0270, // IRQ3 pin vector + VM1_HALT = 0160002, // HALT instruction vector + VM2_HALT = 0170 // HALT instruction vector }; // K1801 microcode constants enum { VM1_STACK = 0177674, // start of HALT mode save area VM1_SEL1 = 0177716, // DIP switch register (read) and HALT mode selector (write) - SEL1_HALT = 010 + SEL1_HALT = 010, + MCIR_ILL = -2, + MCIR_SET = -1, + MCIR_WAIT = 0, + MCIR_NONE = 1, + MCIR_HALT = 2, + MCIR_IRQ = 3 }; enum { @@ -106,6 +117,8 @@ protected: PAIR m_psw; uint16_t m_initial_pc; uint8_t m_wait_state; + int8_t m_mcir; + uint16_t m_vsel; uint8_t m_cp_state; bool m_vec_active; bool m_pf_active; @@ -114,6 +127,8 @@ protected: bool m_power_fail; bool m_bus_error; bool m_ext_halt; + bool m_check_irqs; + bool m_trace_trap; int m_icount; memory_access<16, 1, 0, ENDIANNESS_LITTLE>::cache m_cache; memory_access<16, 1, 0, ENDIANNESS_LITTLE>::specific m_program; @@ -128,7 +143,8 @@ protected: inline void WWORD(int addr, int data); inline void PUSH(int val); inline int POP(); - void t11_check_irqs(); + + virtual void t11_check_irqs(); void take_interrupt(uint8_t vector); void trap_to(uint16_t vector); @@ -1190,6 +1206,9 @@ protected: // device_state_interface overrides virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + + virtual void t11_check_irqs() override; + void take_interrupt_halt(uint16_t vector); }; diff --git a/src/devices/cpu/t11/t11ops.hxx b/src/devices/cpu/t11/t11ops.hxx index ea7471e1fd9..cdcfedb8ced 100644 --- a/src/devices/cpu/t11/t11ops.hxx +++ b/src/devices/cpu/t11/t11ops.hxx @@ -224,8 +224,8 @@ #define MOVB_X(s,d) int sreg, dreg, source, result, ea; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DW_##d((signed char)result) #define MOVB_M(s,d) int sreg, dreg, source, result, ea; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DBT_##d(result) /* MTPS: flags = src */ -#define MTPS_R(d) int dreg, dest; GET_DB_##d; PSW = (PSW & ~0xef) | (dest & 0xef); t11_check_irqs() -#define MTPS_M(d) int dreg, dest, ea; GET_DB_##d; PSW = (PSW & ~0xef) | (dest & 0xef); t11_check_irqs() +#define MTPS_R(d) int dreg, dest; GET_DB_##d; PSW = (PSW & ~0xef) | (dest & 0xef); m_check_irqs = true +#define MTPS_M(d) int dreg, dest, ea; GET_DB_##d; PSW = (PSW & ~0xef) | (dest & 0xef); m_check_irqs = true /* NEG: dst = -dst */ #define NEG_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = -dest; SETW_NZ; if (dest == 0x8000) SET_V; if (result) SET_C; PUT_DW_DREG(result) #define NEG_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = -dest; SETW_NZ; if (dest == 0x8000) SET_V; if (result) SET_C; PUT_DW_EA(result) @@ -273,11 +273,22 @@ void t11_device::trap_to(uint16_t vector) { - PUSH(PSW); - PUSH(PC); - PC = RWORD(vector); - PSW = RWORD(vector + 2); - t11_check_irqs(); + if (c_insn_set & IS_VM1) + { + m_vsel = vector; + if (vector == T11_ILLINST || vector == T11_TIMEOUT) + m_mcir = MCIR_ILL; + else + m_mcir = MCIR_SET; + } + else + { + PUSH(PSW); + PUSH(PC); + PC = RWORD(vector); + PSW = RWORD(vector + 2); + } + m_check_irqs = true; } void t11_device::op_0000(uint16_t op) @@ -286,11 +297,11 @@ void t11_device::op_0000(uint16_t op) { case 0x00: /* HALT */ halt(op); break; case 0x01: /* WAIT */ m_icount = 0; m_wait_state = 1; break; - case 0x02: /* RTI */ m_icount -= 24; PC = POP(); PSW = POP(); t11_check_irqs(); break; - case 0x03: /* BPT */ m_icount -= 48; trap_to(0x0c); break; - case 0x04: /* IOT */ m_icount -= 48; trap_to(0x10); break; + case 0x02: /* RTI */ m_icount -= 24; PC = POP(); PSW = POP(); if (GET_T) m_trace_trap = true; m_check_irqs = true; break; + case 0x03: /* BPT */ m_icount -= 48; trap_to(T11_BPT); break; + case 0x04: /* IOT */ m_icount -= 48; trap_to(T11_IOT); break; case 0x05: /* RESET */ m_out_reset_func(ASSERT_LINE); m_out_reset_func(CLEAR_LINE); m_icount -= 110; break; - case 0x06: /* RTT */ if (c_insn_set & IS_LEIS) { m_icount -= 33; PC = POP(); PSW = POP(); t11_check_irqs(); } else illegal(op); break; + case 0x06: /* RTT */ if (c_insn_set & IS_LEIS) { m_icount -= 33; PC = POP(); PSW = POP(); m_check_irqs = true; } else illegal(op); break; case 0x07: /* MFPT */ if (c_insn_set & IS_MFPT) REGB(0) = 4; else illegal(op); break; default: illegal(op); break; @@ -324,11 +335,18 @@ void t11_device::op_0001(uint16_t op) void t11_device::halt(uint16_t op) { m_icount -= 48; - PUSH(PSW); - PUSH(PC); - PC = m_initial_pc + 4; - PSW = 0340; - t11_check_irqs(); + if (c_insn_set & IS_VM1) + { + trap_to(VM1_HALT); + } + else + { + PUSH(PSW); + PUSH(PC); + PC = m_initial_pc + 4; + PSW = 0340; + } + m_check_irqs = true; } void t11_device::illegal(uint16_t op)