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.cpp188
1 files changed, 126 insertions, 62 deletions
diff --git a/src/devices/cpu/t11/t11.cpp b/src/devices/cpu/t11/t11.cpp
index a93f69ae90e..4ab5a587193 100644
--- a/src/devices/cpu/t11/t11.cpp
+++ b/src/devices/cpu/t11/t11.cpp
@@ -49,11 +49,18 @@ t11_device::t11_device(const machine_config &mconfig, device_type type, const ch
: cpu_device(mconfig, type, tag, owner, clock)
, m_program_config("program", ENDIANNESS_LITTLE, 16, 16, 0)
, c_initial_mode(0)
+ , m_cp_state(0)
+ , m_vec_active(false)
+ , m_pf_active(false)
+ , m_hlt_active(false)
, m_out_reset_func(*this)
+ , m_in_iack_func(*this)
{
m_program_config.m_is_octal = true;
- memset(m_reg, 0x00, sizeof(m_reg));
- memset(&m_psw, 0x00, sizeof(m_psw));
+ for (auto &reg : m_reg)
+ reg.d = 0;
+ m_psw.d = 0;
+ m_ppc.d = 0;
}
t11_device::t11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
@@ -177,58 +184,94 @@ struct irq_table_entry
static const struct irq_table_entry irq_table[] =
{
- { 0<<5, 0x00 },
- { 4<<5, 0x38 },
- { 4<<5, 0x34 },
- { 4<<5, 0x30 },
- { 5<<5, 0x5c },
- { 5<<5, 0x58 },
- { 5<<5, 0x54 },
- { 5<<5, 0x50 },
- { 6<<5, 0x4c },
- { 6<<5, 0x48 },
- { 6<<5, 0x44 },
- { 6<<5, 0x40 },
- { 7<<5, 0x6c },
- { 7<<5, 0x68 },
- { 7<<5, 0x64 },
- { 7<<5, 0x60 }
+ { 0<<5, 0000 },
+ { 4<<5, 0070 },
+ { 4<<5, 0064 },
+ { 4<<5, 0060 },
+ { 5<<5, 0134 },
+ { 5<<5, 0130 },
+ { 5<<5, 0124 },
+ { 5<<5, 0120 },
+ { 6<<5, 0114 },
+ { 6<<5, 0110 },
+ { 6<<5, 0104 },
+ { 6<<5, 0100 },
+ { 7<<5, 0154 },
+ { 7<<5, 0150 },
+ { 7<<5, 0144 },
+ { 7<<5, 0140 }
};
void t11_device::t11_check_irqs()
{
- const struct irq_table_entry *irq = &irq_table[m_irq_state & 15];
- int priority = PSW & 0xe0;
-
- /* compare the priority of the interrupt to the PSW */
- if (irq->priority > priority)
+ // HLT is nonmaskable
+ if (m_ext_halt)
{
- int vector = irq->vector;
- int new_pc, new_psw;
+ m_ext_halt = false;
- /* call the callback; if we don't get -1 back, use the return value as our vector */
- int new_vector = standard_irq_callback(m_irq_state & 15);
- if (new_vector != -1)
- vector = new_vector;
-
- /* fetch the new PC and PSW from that vector */
- assert((vector & 3) == 0);
- new_pc = RWORD(vector);
- new_psw = RWORD(vector + 2);
-
- /* push the old state, set the new one */
+ // push the old state, set the new one
PUSH(PSW);
PUSH(PC);
- PCD = new_pc;
- PSW = new_psw;
- //t11_check_irqs();
+ PCD = m_initial_pc + 4;
+ PSW = 0340;
- /* count cycles and clear the WAIT flag */
+ // count cycles and clear the WAIT flag
m_icount -= 114;
m_wait_state = 0;
+
+ return;
+ }
+
+ // PF has next-highest priority
+ int priority = PSW & 0340;
+ if (m_power_fail && priority != 0340)
+ {
+ m_power_fail = false;
+ take_interrupt(T11_PWRFAIL);
+ return;
+ }
+
+ // 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)
+ {
+ // call the callback
+ standard_irq_callback(m_cp_state & 15);
+
+ // T11 encodes the interrupt level on DAL<12:8>
+ uint8_t iaddr = bitswap<4>(~m_cp_state & 15, 0, 1, 2, 3);
+ if (!m_vec_active)
+ iaddr |= 16;
+
+ // vector is input on DAL<7:2>
+ uint8_t vector = m_in_iack_func(iaddr);
+
+ // nonvectored or vectored interrupt depending on VEC
+ if (BIT(iaddr, 4))
+ take_interrupt(irq->vector);
+ else
+ take_interrupt(vector & ~3);
}
}
+void t11_device::take_interrupt(uint8_t vector)
+{
+ // fetch the new PC and PSW from that vector
+ assert((vector & 3) == 0);
+ uint16_t new_pc = RWORD(vector);
+ uint16_t new_psw = RWORD(vector + 2);
+
+ // push the old state, set the new one
+ PUSH(PSW);
+ PUSH(PC);
+ PCD = new_pc;
+ PSW = new_psw;
+
+ // count cycles and clear the WAIT flag
+ m_icount -= 114;
+ m_wait_state = 0;
+}
+
/*************************************
@@ -263,6 +306,7 @@ void t11_device::device_start()
m_program = &space(AS_PROGRAM);
m_cache = m_program->cache<1, 0, ENDIANNESS_LITTLE>();
m_out_reset_func.resolve_safe();
+ m_in_iack_func.resolve_safe(0377);
save_item(NAME(m_ppc.w.l));
save_item(NAME(m_reg[0].w.l));
@@ -276,7 +320,12 @@ void t11_device::device_start()
save_item(NAME(m_psw.w.l));
save_item(NAME(m_initial_pc));
save_item(NAME(m_wait_state));
- save_item(NAME(m_irq_state));
+ save_item(NAME(m_cp_state));
+ save_item(NAME(m_vec_active));
+ save_item(NAME(m_pf_active));
+ save_item(NAME(m_hlt_active));
+ save_item(NAME(m_power_fail));
+ save_item(NAME(m_ext_halt));
// Register debugger state
state_add( T11_PC, "PC", m_reg[7].w.l).formatstr("%06O");
@@ -344,27 +393,18 @@ void k1801vm2_device::state_string_export(const device_state_entry &entry, std::
void t11_device::device_reset()
{
- /* initial SP is 376 octal, or 0xfe */
- SP = 0x00fe;
+ // initial SP is 376 octal, or 0xfe
+ SP = 0376;
- /* initial PC comes from the setup word */
+ // initial PC comes from the setup word
PC = m_initial_pc;
- /* PSW starts off at highest priority */
- PSW = 0xe0;
-
- /* initialize the IRQ state */
- m_irq_state = 0;
+ // PSW starts off at highest priority
+ PSW = 0340;
- /* reset the remaining state */
- REGD(0) = 0;
- REGD(1) = 0;
- REGD(2) = 0;
- REGD(3) = 0;
- REGD(4) = 0;
- REGD(5) = 0;
- m_ppc.d = 0;
m_wait_state = 0;
+ m_power_fail = false;
+ m_ext_halt = false;
}
void k1801vm2_device::device_reset()
@@ -384,11 +424,35 @@ void k1801vm2_device::device_reset()
void t11_device::execute_set_input(int irqline, int state)
{
- /* set the appropriate bit */
- if (state == CLEAR_LINE)
- m_irq_state &= ~(1 << irqline);
- else
- m_irq_state |= 1 << irqline;
+ switch (irqline)
+ {
+ case CP0_LINE:
+ case CP1_LINE:
+ case CP2_LINE:
+ case CP3_LINE:
+ // set the appropriate bit
+ if (state == CLEAR_LINE)
+ m_cp_state &= ~(1 << irqline);
+ else
+ m_cp_state |= 1 << irqline;
+ break;
+
+ case VEC_LINE:
+ m_vec_active = (state != CLEAR_LINE);
+ break;
+
+ case PF_LINE:
+ if (state != CLEAR_LINE && !m_pf_active)
+ m_power_fail = true;
+ m_pf_active = (state != CLEAR_LINE);
+ break;
+
+ case HLT_LINE:
+ if (state != CLEAR_LINE && !m_hlt_active)
+ m_ext_halt = true;
+ m_hlt_active = (state != CLEAR_LINE);
+ break;
+ }
}