diff options
author | 2020-05-02 22:28:06 -0400 | |
---|---|---|
committer | 2020-05-02 22:36:50 -0400 | |
commit | e3be834780cedab2f16f8b5b057b2290c8885537 (patch) | |
tree | 5cba5f3ab3cacbb141ec670e6844e3f90ecc0986 | |
parent | 1daa2a1f24b2854f33924d9610c0775e61618be9 (diff) |
t11: More accurate emulation of interrupt acknowledgment; add PF and HLT interrupts
(nw) This is accurate behavior for the T11, but it makes some of the driver changes a bit more awkward than they probably should be, given that one device is standing in for every CPU vaguely related to the PDP-11 family. Galaxy Game obviously wasn't written for a T11, and the BK-0010's K1801VM1 doesn't look like a lot like the T11 either.
-rw-r--r-- | src/devices/cpu/t11/t11.cpp | 188 | ||||
-rw-r--r-- | src/devices/cpu/t11/t11.h | 53 | ||||
-rw-r--r-- | src/mame/drivers/atarisy2.cpp | 16 | ||||
-rw-r--r-- | src/mame/drivers/bk.cpp | 4 | ||||
-rw-r--r-- | src/mame/drivers/galgame.cpp | 10 | ||||
-rw-r--r-- | src/mame/drivers/ms0515.cpp | 8 | ||||
-rw-r--r-- | src/mame/drivers/vt240.cpp | 8 | ||||
-rw-r--r-- | src/mame/includes/bk.h | 2 | ||||
-rw-r--r-- | src/mame/machine/bk.cpp | 6 |
9 files changed, 193 insertions, 102 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 ® : 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; + } } diff --git a/src/devices/cpu/t11/t11.h b/src/devices/cpu/t11/t11.h index 5b4c4921dad..2b54933ba94 100644 --- a/src/devices/cpu/t11/t11.h +++ b/src/devices/cpu/t11/t11.h @@ -18,27 +18,42 @@ enum #define T11_IRQ2 2 /* IRQ2 */ #define T11_IRQ3 3 /* IRQ3 */ -#define T11_RESERVED 0x000 /* Reserved vector */ -#define T11_TIMEOUT 0x004 /* Time-out/system error vector */ -#define T11_ILLINST 0x008 /* Illegal and reserved instruction vector */ -#define T11_BPT 0x00C /* BPT instruction vector */ -#define T11_IOT 0x010 /* IOT instruction vector */ -#define T11_PWRFAIL 0x014 /* Power fail vector */ -#define T11_EMT 0x018 /* EMT instruction vector */ -#define T11_TRAP 0x01C /* TRAP instruction vector */ - class t11_device : public cpu_device { public: + enum + { + CP0_LINE = 0, // -AI4 (at PI time) + CP1_LINE = 1, // -AI3 (at PI time) + CP2_LINE = 2, // -AI2 (at PI time) + CP3_LINE = 3, // -AI1 (at PI time) + VEC_LINE = 4, // -AI5 (at PI time) + PF_LINE = 5, // -AI6 (at PI time) + HLT_LINE = 6 // -AI7 (at PI time) + }; + // construction/destruction t11_device(const machine_config &mconfig, const char *_tag, device_t *_owner, uint32_t _clock); // configuration helpers void set_initial_mode(const uint16_t mode) { c_initial_mode = mode; } auto out_reset() { return m_out_reset_func.bind(); } + auto in_iack() { return m_in_iack_func.bind(); } protected: + enum + { + T11_RESERVED = 000, // Reserved vector + T11_TIMEOUT = 004, // Time-out/system error vector + T11_ILLINST = 010, // Illegal and reserved instruction vector + T11_BPT = 014, // BPT instruction vector + 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_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); // device-level overrides @@ -48,10 +63,10 @@ protected: // device_execute_interface overrides virtual uint32_t execute_min_cycles() const noexcept override { return 12; } virtual uint32_t execute_max_cycles() const noexcept override { return 114; } - virtual uint32_t execute_input_lines() const noexcept override { return 4; } + virtual uint32_t execute_input_lines() const noexcept override { return 7; } + virtual bool execute_input_edge_triggered(int inputnum) const noexcept override { return inputnum == PF_LINE || inputnum == HLT_LINE; } virtual void execute_run() override; virtual void execute_set_input(int inputnum, int state) override; - virtual uint32_t execute_default_irq_vector(int inputnum) const noexcept override { return -1; } // device_memory_interface overrides virtual space_config_vector memory_space_config() const override; @@ -69,13 +84,20 @@ protected: PAIR m_ppc; /* previous program counter */ PAIR m_reg[8]; PAIR m_psw; - uint16_t m_initial_pc; - uint8_t m_wait_state; - uint8_t m_irq_state; + uint16_t m_initial_pc; + uint8_t m_wait_state; + uint8_t m_cp_state; + bool m_vec_active; + bool m_pf_active; + bool m_hlt_active; + bool m_power_fail; + bool m_ext_halt; int m_icount; address_space *m_program; memory_access_cache<1, 0, ENDIANNESS_LITTLE> *m_cache; - devcb_write_line m_out_reset_func; + + devcb_write_line m_out_reset_func; + devcb_read8 m_in_iack_func; inline int ROPCODE(); inline int RBYTE(int addr); @@ -85,6 +107,7 @@ protected: inline void PUSH(int val); inline int POP(); void t11_check_irqs(); + void take_interrupt(uint8_t vector); typedef void ( t11_device::*opcode_func )(uint16_t op); static const opcode_func s_opcode_table[65536 >> 3]; diff --git a/src/mame/drivers/atarisy2.cpp b/src/mame/drivers/atarisy2.cpp index bec71345faa..c40f954d2aa 100644 --- a/src/mame/drivers/atarisy2.cpp +++ b/src/mame/drivers/atarisy2.cpp @@ -148,24 +148,24 @@ void atarisy2_state::update_interrupts() { if (m_video_int_state) - m_maincpu->set_input_line(3, ASSERT_LINE); + m_maincpu->set_input_line(t11_device::CP3_LINE, ASSERT_LINE); else - m_maincpu->set_input_line(3, CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP3_LINE, CLEAR_LINE); if (m_scanline_int_state) - m_maincpu->set_input_line(2, ASSERT_LINE); + m_maincpu->set_input_line(t11_device::CP2_LINE, ASSERT_LINE); else - m_maincpu->set_input_line(2, CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP2_LINE, CLEAR_LINE); if (m_p2portwr_state) - m_maincpu->set_input_line(1, ASSERT_LINE); + m_maincpu->set_input_line(t11_device::CP1_LINE, ASSERT_LINE); else - m_maincpu->set_input_line(1, CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP1_LINE, CLEAR_LINE); if (m_p2portrd_state) - m_maincpu->set_input_line(0, ASSERT_LINE); + m_maincpu->set_input_line(t11_device::CP0_LINE, ASSERT_LINE); else - m_maincpu->set_input_line(0, CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP0_LINE, CLEAR_LINE); } diff --git a/src/mame/drivers/bk.cpp b/src/mame/drivers/bk.cpp index 1990e6d0dff..32dc0fabff7 100644 --- a/src/mame/drivers/bk.cpp +++ b/src/mame/drivers/bk.cpp @@ -166,10 +166,10 @@ INPUT_PORTS_END void bk_state::bk0010(machine_config &config) { /* basic machine hardware */ - T11(config, m_maincpu, 3000000); + T11(config, m_maincpu, 3000000); // FIXME: actually K1801VM1 m_maincpu->set_initial_mode(0x36ff); /* initial mode word has DAL15,14,11,8 pulled low */ m_maincpu->set_addrmap(AS_PROGRAM, &bk_state::bk0010_mem); - m_maincpu->set_irq_acknowledge_callback(FUNC(bk_state::bk0010_irq_callback)); + m_maincpu->in_iack().set(FUNC(bk_state::bk0010_irq_callback)); /* video hardware */ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); diff --git a/src/mame/drivers/galgame.cpp b/src/mame/drivers/galgame.cpp index 5c87b3d2d03..ad9a4f604be 100644 --- a/src/mame/drivers/galgame.cpp +++ b/src/mame/drivers/galgame.cpp @@ -59,7 +59,7 @@ private: virtual void machine_reset() override; uint32_t screen_update_galaxygame(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); INTERRUPT_GEN_MEMBER(galaxygame_irq); - IRQ_CALLBACK_MEMBER(galaxygame_irq_callback); + uint8_t galaxygame_irq_callback(offs_t offset); required_device<t11_device> m_maincpu; required_device<palette_device> m_palette; void galaxygame_map(address_map &map); @@ -303,9 +303,9 @@ void galaxygame_state::galaxygame_map(address_map &map) } -IRQ_CALLBACK_MEMBER(galaxygame_state::galaxygame_irq_callback) +uint8_t galaxygame_state::galaxygame_irq_callback(offs_t offset) { - device.execute().set_input_line(0, CLEAR_LINE); + m_maincpu->set_input_line(0, CLEAR_LINE); return 0x40; } @@ -320,6 +320,8 @@ INTERRUPT_GEN_MEMBER(galaxygame_state::galaxygame_irq) void galaxygame_state::machine_reset() { + m_maincpu->set_input_line(t11_device::VEC_LINE, ASSERT_LINE); + m_clk = 0x00; m_point_work_list_index = 0; m_point_display_list_index = 0; @@ -331,7 +333,7 @@ void galaxygame_state::galaxygame(machine_config &config) T11(config, m_maincpu, 3000000); m_maincpu->set_addrmap(AS_PROGRAM, &galaxygame_state::galaxygame_map); m_maincpu->set_initial_mode(5 << 13); - m_maincpu->set_irq_acknowledge_callback(FUNC(galaxygame_state::galaxygame_irq_callback)); + m_maincpu->in_iack().set(FUNC(galaxygame_state::galaxygame_irq_callback)); m_maincpu->set_periodic_int(FUNC(galaxygame_state::galaxygame_irq), attotime::from_hz(60)); /* video hardware */ diff --git a/src/mame/drivers/ms0515.cpp b/src/mame/drivers/ms0515.cpp index 86e77dcba66..ef6487b86bb 100644 --- a/src/mame/drivers/ms0515.cpp +++ b/src/mame/drivers/ms0515.cpp @@ -478,10 +478,10 @@ void ms0515_state::irq_encoder(int irq, int state) { if (m_irqs & (1 << i)) break; } - m_maincpu->set_input_line(3, (i & 8) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(2, (i & 4) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(1, (i & 2) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(0, (i & 1) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP3_LINE, (i & 8) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP2_LINE, (i & 4) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP1_LINE, (i & 2) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP0_LINE, (i & 1) ? ASSERT_LINE : CLEAR_LINE); } /* diff --git a/src/mame/drivers/vt240.cpp b/src/mame/drivers/vt240.cpp index 667f2142c79..8262b6c96f9 100644 --- a/src/mame/drivers/vt240.cpp +++ b/src/mame/drivers/vt240.cpp @@ -137,10 +137,10 @@ void vt240_state::irq_encoder(int irq, int state) if(m_irqs & (1 << i)) break; } - m_maincpu->set_input_line(3, (i & 8) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(2, (i & 4) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(1, (i & 2) ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(0, (i & 1) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP3_LINE, (i & 8) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP2_LINE, (i & 4) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP1_LINE, (i & 2) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(t11_device::CP0_LINE, (i & 1) ? ASSERT_LINE : CLEAR_LINE); } WRITE_LINE_MEMBER(vt240_state::irq7_w) diff --git a/src/mame/includes/bk.h b/src/mame/includes/bk.h index b216893627e..91e7a4463d9 100644 --- a/src/mame/includes/bk.h +++ b/src/mame/includes/bk.h @@ -52,7 +52,7 @@ private: virtual void video_start() override; uint32_t screen_update_bk0010(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); TIMER_CALLBACK_MEMBER(keyboard_callback); - IRQ_CALLBACK_MEMBER(bk0010_irq_callback); + uint8_t bk0010_irq_callback(offs_t offset); required_device<t11_device> m_maincpu; required_device<cassette_image_device> m_cassette; required_ioport_array<12> m_io_keyboard; diff --git a/src/mame/machine/bk.cpp b/src/mame/machine/bk.cpp index 3314c9f69f6..7fa379cfbd7 100644 --- a/src/mame/machine/bk.cpp +++ b/src/mame/machine/bk.cpp @@ -56,13 +56,15 @@ TIMER_CALLBACK_MEMBER(bk_state::keyboard_callback) void bk_state::machine_start() { + m_maincpu->set_input_line(t11_device::VEC_LINE, ASSERT_LINE); + m_kbd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bk_state::keyboard_callback), this)); m_kbd_timer->adjust(attotime::from_hz(2400), 0, attotime::from_hz(2400)); } -IRQ_CALLBACK_MEMBER(bk_state::bk0010_irq_callback) +uint8_t bk_state::bk0010_irq_callback(offs_t offset) { - device.execute().set_input_line(0, CLEAR_LINE); + m_maincpu->set_input_line(0, CLEAR_LINE); return m_key_irq_vector; } |