summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/t11/t11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/t11/t11.cpp')
-rw-r--r--src/devices/cpu/t11/t11.cpp200
1 files changed, 189 insertions, 11 deletions
diff --git a/src/devices/cpu/t11/t11.cpp b/src/devices/cpu/t11/t11.cpp
index c4f22b93732..487a7a57003 100644
--- a/src/devices/cpu/t11/t11.cpp
+++ b/src/devices/cpu/t11/t11.cpp
@@ -14,7 +14,6 @@
#include "emu.h"
#include "t11.h"
#include "t11dasm.h"
-#include "debugger.h"
/*************************************
@@ -37,12 +36,20 @@
DEFINE_DEVICE_TYPE(T11, t11_device, "t11", "DEC T11")
+DEFINE_DEVICE_TYPE(K1801VM1, k1801vm1_device, "k1801vm1", "K1801VM1")
DEFINE_DEVICE_TYPE(K1801VM2, k1801vm2_device, "k1801vm2", "K1801VM2")
+k1801vm1_device::k1801vm1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : t11_device(mconfig, K1801VM1, tag, owner, clock)
+{
+ c_insn_set = IS_LEIS | IS_MXPS | IS_VM1;
+}
+
k1801vm2_device::k1801vm2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: t11_device(mconfig, K1801VM2, tag, owner, clock)
{
+ c_insn_set = IS_LEIS | IS_EIS | IS_MXPS | IS_VM2;
}
t11_device::t11_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
@@ -52,9 +59,10 @@ t11_device::t11_device(const machine_config &mconfig, device_type type, const ch
, m_cp_state(0)
, m_vec_active(false)
, m_pf_active(false)
+ , m_berr_active(false)
, m_hlt_active(false)
, m_out_reset_func(*this)
- , m_in_iack_func(*this)
+ , m_in_iack_func(*this, 0) // default vector (T-11 User's Guide, p. A-11)
{
m_program_config.m_is_octal = true;
for (auto &reg : m_reg)
@@ -66,6 +74,7 @@ t11_device::t11_device(const machine_config &mconfig, device_type type, const ch
t11_device::t11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: t11_device(mconfig, T11, tag, owner, clock)
{
+ c_insn_set = IS_LEIS | IS_MFPT | IS_MXPS | IS_T11;
}
device_memory_interface::space_config_vector t11_device::memory_space_config() const
@@ -84,8 +93,7 @@ device_memory_interface::space_config_vector t11_device::memory_space_config() c
int t11_device::ROPCODE()
{
- PC &= 0xfffe;
- int val = m_cache.read_word(PC);
+ int val = m_cache.read_word(PC & 0xfffe);
PC += 2;
return val;
}
@@ -155,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)
@@ -202,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
@@ -222,9 +348,14 @@ void t11_device::t11_check_irqs()
return;
}
- // PF has next-highest priority
- int priority = PSW & 0340;
- if (m_power_fail && priority != 0340)
+ // non-maskable hardware traps
+ if (m_bus_error)
+ {
+ m_bus_error = false;
+ take_interrupt(T11_TIMEOUT);
+ return;
+ }
+ else if (m_power_fail)
{
m_power_fail = false;
take_interrupt(T11_PWRFAIL);
@@ -233,10 +364,10 @@ void t11_device::t11_check_irqs()
// compare the priority of the CP interrupt to the PSW
const struct irq_table_entry *irq = &irq_table[m_cp_state & 15];
- if (irq->priority > priority)
+ if (irq->priority > (PSW & 0340))
{
// call the callback
- standard_irq_callback(m_cp_state & 15);
+ standard_irq_callback(m_cp_state & 15, PC);
// T11 encodes the interrupt level on DAL<12:8>
uint8_t iaddr = bitswap<4>(~m_cp_state & 15, 0, 1, 2, 3);
@@ -305,8 +436,6 @@ void t11_device::device_start()
m_initial_pc = initial_pc[c_initial_mode >> 13];
space(AS_PROGRAM).cache(m_cache);
space(AS_PROGRAM).specific(m_program);
- m_out_reset_func.resolve_safe();
- m_in_iack_func.resolve_safe(0); // default vector (T-11 User's Guide, p. A-11)
save_item(NAME(m_ppc.w.l));
save_item(NAME(m_reg[0].w.l));
@@ -326,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");
@@ -364,6 +497,25 @@ void t11_device::state_string_export(const device_state_entry &entry, std::strin
}
}
+void k1801vm1_device::state_string_export(const device_state_entry &entry, std::string &str) const
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ str = string_format("%c%c%c%c%c%c%c%c",
+ m_psw.b.l & 0x80 ? 'I':'.',
+ m_psw.b.l & 0x40 ? '?':'.',
+ m_psw.b.l & 0x20 ? '?':'.',
+ m_psw.b.l & 0x10 ? 'T':'.',
+ m_psw.b.l & 0x08 ? 'N':'.',
+ m_psw.b.l & 0x04 ? 'Z':'.',
+ m_psw.b.l & 0x02 ? 'V':'.',
+ m_psw.b.l & 0x01 ? 'C':'.'
+ );
+ break;
+ }
+}
+
void k1801vm2_device::state_string_export(const device_state_entry &entry, std::string &str) const
{
switch (entry.index())
@@ -404,7 +556,21 @@ void t11_device::device_reset()
m_wait_state = 0;
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()
+{
+ t11_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()
@@ -447,6 +613,12 @@ void t11_device::execute_set_input(int irqline, int state)
m_pf_active = (state != CLEAR_LINE);
break;
+ case BUS_ERROR:
+ if (state != CLEAR_LINE && !m_berr_active)
+ m_bus_error = true;
+ m_berr_active = (state != CLEAR_LINE);
+ break;
+
case HLT_LINE:
if (state != CLEAR_LINE && !m_hlt_active)
m_ext_halt = true;
@@ -483,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();
+ }
}
}