cpu/t11: Improved trace trap processing, and added basic interrupt processing to the K1801VM1. (#12151)

This commit is contained in:
shattered 2024-03-23 15:31:06 +00:00 committed by GitHub
parent 91c9b46710
commit 26ba3b1af9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 189 additions and 19 deletions

View File

@ -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();
}
}
}

View File

@ -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);
};

View File

@ -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)