From 6b6d06bdaefe07176ef4a75e327560edc5ea5073 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Mon, 17 Mar 2025 09:28:35 +0700 Subject: [PATCH] x68k: improve interrupt handling --- src/mame/sharp/x68k.cpp | 207 ++++++++++++---------------------------- src/mame/sharp/x68k.h | 23 +---- 2 files changed, 66 insertions(+), 164 deletions(-) diff --git a/src/mame/sharp/x68k.cpp b/src/mame/sharp/x68k.cpp index 3a49c788a9f..561459555db 100644 --- a/src/mame/sharp/x68k.cpp +++ b/src/mame/sharp/x68k.cpp @@ -121,6 +121,7 @@ #include "x68k_kbd.h" #include "x68k_mouse.h" +#include "machine/input_merger.h" #include "machine/nvram.h" #include "bus/x68k/x68k_neptunex.h" @@ -328,21 +329,6 @@ uint16_t x68k_state::fdc_r(offs_t offset) return 0xff; } -void x68k_state::fdc_irq(int state) -{ - if((m_ioc.irqstatus & 0x04) && state) - { - m_ioc.irqstatus |= 0x80; - LOGMASKED(LOG_FDC, "FDC: IRQ triggered\n"); - update_ipl(); - } - else - { - m_ioc.irqstatus &= 0x7f; - update_ipl(); - } -} - void x68k_state::ct_w(uint8_t data) { // CT1 and CT2 bits from YM2151 port 0x1b @@ -361,6 +347,33 @@ void x68k_state::ct_w(uint8_t data) m_okim6258->set_unscaled_clock(adpcm_clock[m_adpcm.clock]); } +enum ioc_irq_number : unsigned +{ + IOC_FDC_INT = 7, + IOC_FDD_INT = 6, + IOC_PRT_INT = 5, + IOC_HDD_INT = 4, + IOC_HDD_IEN = 3, + IOC_FDC_IEN = 2, + IOC_FDD_IEN = 1, + IOC_PRT_IEN = 0, +}; +template void x68k_state::ioc_irq(int state) +{ + if (state) + m_ioc.irqstatus |= 1U << N; + else + m_ioc.irqstatus &= ~(1U << N); + + bool const irq_state = + BIT(m_ioc.irqstatus, IOC_HDD_INT) && BIT(m_ioc.irqstatus, IOC_HDD_IEN) || + BIT(m_ioc.irqstatus, IOC_PRT_INT) && BIT(m_ioc.irqstatus, IOC_PRT_IEN) || + BIT(m_ioc.irqstatus, IOC_FDD_INT) && BIT(m_ioc.irqstatus, IOC_FDD_IEN) || + BIT(m_ioc.irqstatus, IOC_FDC_INT) && BIT(m_ioc.irqstatus, IOC_FDC_IEN); + + m_maincpu->set_input_line(INPUT_LINE_IRQ1, irq_state ? ASSERT_LINE : CLEAR_LINE); +} + /* Custom I/O controller at 0xe9c000 0xe9c001 (R) - Interrupt status @@ -377,39 +390,22 @@ void x68k_state::ct_w(uint8_t data) - bits 7-2 = vector - bits 1,0 = device (00 = FDC, 01 = FDD, 10 = HDD, 11 = Printer) */ -void x68k_state::ioc_w(offs_t offset, uint16_t data) +void x68k_state::ioc_w(offs_t offset, uint8_t data) { switch(offset) { case 0x00: - m_ioc.irqstatus = data & 0x0f; + m_ioc.irqstatus = (m_ioc.irqstatus & 0xf0) | (data & 0x0f); LOGMASKED(LOG_SYS, "I/O: Status register write %02x\n",data); break; case 0x01: - switch(data & 0x03) - { - case 0x00: - m_ioc.fdcvector = data & 0xfc; - LOGMASKED(LOG_IRQ, "IOC: FDC IRQ vector = 0x%02x\n",data & 0xfc); - break; - case 0x01: - m_ioc.fddvector = data & 0xfc; - LOGMASKED(LOG_IRQ, "IOC: FDD IRQ vector = 0x%02x\n",data & 0xfc); - break; - case 0x02: - m_ioc.hdcvector = data & 0xfc; - LOGMASKED(LOG_IRQ, "IOC: HDD IRQ vector = 0x%02x\n",data & 0xfc); - break; - case 0x03: - m_ioc.prnvector = data & 0xfc; - LOGMASKED(LOG_IRQ, "IOC: Printer IRQ vector = 0x%02x\n",data & 0xfc); - break; - } + LOGMASKED(LOG_IRQ, "IOC: IRQ vector = 0x%02x\n", data & 0xfc); + m_ioc.vector = data & 0xfc; break; } } -uint16_t x68k_state::ioc_r(offs_t offset) +uint8_t x68k_state::ioc_r(offs_t offset) { switch(offset) { @@ -661,12 +657,6 @@ void x68k_state::exp_w(offs_t offset, uint16_t data, uint16_t mem_mask) set_bus_error((offset << 1) + 0xeafa00, 1, mem_mask); } -void x68k_state::dma_irq(int state) -{ - m_dmac_int = state != CLEAR_LINE; - update_ipl(); -} - void x68k_state::dma_end(offs_t offset, uint8_t data) { if(offset == 0) @@ -700,79 +690,33 @@ void x68k_state::adpcm_w(offs_t offset, uint8_t data) } } -void x68k_state::mfp_irq_callback(int state) -{ - m_mfp_int = state; - update_ipl(); -} - -void x68k_state::update_ipl() -{ - uint8_t new_ipl = 0; - if (m_exp_nmi[0] || m_exp_nmi[1]) - new_ipl = 7; - else if (m_mfp_int) - new_ipl = 6; - else if (m_scc_int) - new_ipl = 5; - else if (m_exp_irq4[0] || m_exp_irq4[1]) - new_ipl = 4; - else if (m_dmac_int) - new_ipl = 3; - else if (m_exp_irq2[0] || m_exp_irq2[1]) - new_ipl = 2; - else if ((m_ioc.irqstatus & 0xf0) != 0) - new_ipl = 1; - - if (m_current_ipl != new_ipl) - { - if (m_current_ipl != 0) - m_maincpu->set_input_line(m_current_ipl, CLEAR_LINE); - LOGMASKED(LOG_IRQ, "Changing interrupt level from %d to %d\n", m_current_ipl, new_ipl); - m_current_ipl = new_ipl; - if (m_current_ipl != 0) - m_maincpu->set_input_line(m_current_ipl, ASSERT_LINE); - } -} - uint8_t x68k_state::iack1() { uint8_t vector = 0x18; - if (BIT(m_ioc.irqstatus, 7)) + if (BIT(m_ioc.irqstatus, IOC_FDC_INT) && BIT(m_ioc.irqstatus, IOC_FDC_IEN)) { - vector = m_ioc.fdcvector; + vector = m_ioc.vector | 0; if (!machine().side_effects_disabled()) - { - m_ioc.irqstatus &= 0x7f; - update_ipl(); - } + ioc_irq(0); } - else if (BIT(m_ioc.irqstatus, 6)) + else if (BIT(m_ioc.irqstatus, IOC_FDD_INT) && BIT(m_ioc.irqstatus, IOC_FDD_IEN)) { - vector = 0x61 /*m_ioc.fddvector*/; + vector = m_ioc.vector | 1; if (!machine().side_effects_disabled()) - { - m_ioc.irqstatus &= 0xbf; - update_ipl(); - } + ioc_irq(0); } - else if (BIT(m_ioc.irqstatus, 5)) + else if (BIT(m_ioc.irqstatus, IOC_PRT_INT) && BIT(m_ioc.irqstatus, IOC_PRT_IEN)) { - vector = m_ioc.prnvector; + vector = m_ioc.vector | 3; if (!machine().side_effects_disabled()) - { - m_ioc.irqstatus &= 0xdf; - update_ipl(); - } + ioc_irq(0); } - else if (BIT(m_ioc.irqstatus, 4)) + else if (BIT(m_ioc.irqstatus, IOC_HDD_INT) && BIT(m_ioc.irqstatus, IOC_HDD_IEN)) { - vector = 0x6c /*m_ioc.hdcvector*/; + // TODO: Internal SCSI IRQ vector 0x6c, External SCSI IRQ vector 0xf6 (really?) + vector = m_ioc.vector | 2; if (!machine().side_effects_disabled()) - { - m_ioc.irqstatus &= 0xef; - update_ipl(); - } + ioc_irq(0); } if (!machine().side_effects_disabled()) @@ -785,7 +729,7 @@ void x68k_state::irq2_line(int state) { m_exp_irq2[N] = (state != CLEAR_LINE); LOGMASKED(LOG_IRQ, "IRQ2-%d %s\n", N + 1, m_exp_irq2[N] ? "asserted" : "cleared"); - update_ipl(); + m_maincpu->set_input_line(INPUT_LINE_IRQ2, (m_exp_irq2[0] || m_exp_irq2[1]) ? ASSERT_LINE : CLEAR_LINE) } template @@ -793,15 +737,7 @@ void x68k_state::irq4_line(int state) { m_exp_irq4[N] = (state != CLEAR_LINE); LOGMASKED(LOG_IRQ, "IRQ4-%d %s\n", N + 1, m_exp_irq4[N] ? "asserted" : "cleared"); - update_ipl(); -} - -template -void x68k_state::nmi_line(int state) -{ - m_exp_nmi[N] = (state != CLEAR_LINE); - LOGMASKED(LOG_IRQ, "EXNMI %s on expansion %d\n", m_exp_nmi[N] ? "asserted" : "cleared", N + 1); - update_ipl(); + m_maincpu->set_input_line(INPUT_LINE_IRQ4, (m_exp_irq4[0] || m_exp_irq4[1]) ? ASSERT_LINE : CLEAR_LINE) } uint8_t x68k_state::iack2() @@ -838,18 +774,6 @@ void x68k_state::cpu_space_map(address_map &map) map(0xffffff, 0xffffff).lr8(NAME([] () { return m68000_base_device::autovector(7); })); } -void x68ksupr_state::scsi_irq(int state) -{ - LOGMASKED(LOG_IRQ, "SCSI IRQ %s\n", state ? "asserted" : "cleared"); - - // TODO : Internal SCSI IRQ vector 0x6c, External SCSI IRQ vector 0xf6, IRQs go through the IOSC (IRQ line 1) - if(state != 0) - { - m_ioc.irqstatus |= 0x10; - update_ipl(); - } -} - void x68ksupr_state::scsi_unknown_w(uint8_t data) { // Documentation claims SSTS register is read-only, but x68030 boot code writes #$05 to this address anyway. @@ -875,7 +799,7 @@ void x68k_state::x68k_base_map(address_map &map) map(0xe94004, 0xe94007).rw(FUNC(x68k_state::fdc_r), FUNC(x68k_state::fdc_w)); map(0xe98000, 0xe99fff).rw(m_scc, FUNC(scc8530_device::ab_dc_r), FUNC(scc8530_device::ab_dc_w)).umask16(0x00ff); map(0xe9a000, 0xe9bfff).rw(FUNC(x68k_state::ppi_r), FUNC(x68k_state::ppi_w)); - map(0xe9c000, 0xe9dfff).rw(FUNC(x68k_state::ioc_r), FUNC(x68k_state::ioc_w)); + map(0xe9c000, 0xe9dfff).rw(FUNC(x68k_state::ioc_r), FUNC(x68k_state::ioc_w)).umask16(0x00ff); map(0xe9e000, 0xe9e3ff).rw(FUNC(x68k_state::exp_r), FUNC(x68k_state::exp_w)); // FPU (Optional) map(0xeafa00, 0xeafa1f).rw(FUNC(x68k_state::exp_r), FUNC(x68k_state::exp_w)); map(0xeb0000, 0xeb7fff).rw(FUNC(x68k_state::spritereg_r), FUNC(x68k_state::spritereg_w)); @@ -941,12 +865,8 @@ INPUT_PORTS_END void x68k_state::floppy_load_unload(bool load, floppy_image_device *dev) { dev->mon_w(!(m_fdc.motor && load)); - if(m_ioc.irqstatus & 0x02) - { - m_ioc.irqstatus |= 0x40; // Disk insert/eject interrupt - LOGMASKED(LOG_FDC, "IOC: Disk image inserted\n"); - update_ipl(); - } + + ioc_irq(1); } void x68k_state::floppy_load(floppy_image_device *dev) @@ -992,9 +912,6 @@ void x68k_state::machine_reset() std::fill(std::begin(m_ctrl_drv_out), std::end(m_ctrl_drv_out), 1); std::fill(std::begin(m_access_drv_out), std::end(m_access_drv_out), 1); m_fdc.select_drive = 0; - - m_ioc.irqstatus &= 0x0f; - update_ipl(); } void x68k_state::machine_start() @@ -1025,14 +942,9 @@ void x68k_state::machine_start() } m_fdc.motor = 0; - m_dmac_int = false; - m_mfp_int = false; - m_scc_int = false; m_exp_irq2[0] = m_exp_irq2[1] = false; m_exp_irq4[0] = m_exp_irq4[1] = false; - m_exp_nmi[0] = m_exp_nmi[1] = false; m_ioc.irqstatus = 0; - m_current_ipl = 0; m_adpcm.rate = 0; m_adpcm.clock = 0; m_sysport.sram_writeprotect = 0; @@ -1114,7 +1026,7 @@ void x68k_state::x68000_base(machine_config &config) /* device hardware */ MC68901(config, m_mfpdev, 16_MHz_XTAL / 4); m_mfpdev->set_timer_clock(16_MHz_XTAL / 4); - m_mfpdev->out_irq_cb().set(FUNC(x68k_state::mfp_irq_callback)); + m_mfpdev->out_irq_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ6); m_mfpdev->out_tbo_cb().set(m_mfpdev, FUNC(mc68901_device::tc_w)); m_mfpdev->out_tbo_cb().append(m_mfpdev, FUNC(mc68901_device::rc_w)); m_mfpdev->out_so_cb().set("keyboard", FUNC(rs232_port_device::write_txd)); @@ -1134,13 +1046,13 @@ void x68k_state::x68000_base(machine_config &config) HD63450(config, m_hd63450, 40_MHz_XTAL / 4, "maincpu"); m_hd63450->set_clocks(attotime::from_usec(2), attotime::from_nsec(450), attotime::from_usec(4), attotime::from_hz(15625/2)); m_hd63450->set_burst_clocks(attotime::from_usec(2), attotime::from_nsec(450), attotime::from_nsec(450), attotime::from_nsec(50)); - m_hd63450->irq_callback().set(FUNC(x68k_state::dma_irq)); + m_hd63450->irq_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ3); m_hd63450->dma_end().set(FUNC(x68k_state::dma_end)); m_hd63450->dma_read<0>().set("upd72065", FUNC(upd72065_device::dma_r)); m_hd63450->dma_write<0>().set("upd72065", FUNC(upd72065_device::dma_w)); SCC8530(config, m_scc, 40_MHz_XTAL / 8); - m_scc->out_int_callback().set([this](int state) { m_scc_int = state; update_ipl(); }); + m_scc->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ5); rs232_port_device &mouse(RS232_PORT(config, "mouse_port", mouse_devices, "x68k")); mouse.rxd_handler().set(m_scc, FUNC(scc8530_device::rxb_w)); @@ -1182,7 +1094,7 @@ void x68k_state::x68000_base(machine_config &config) FILTER_VOLUME(config, m_adpcm_out[1]).add_route(ALL_OUTPUTS, "rspeaker", 1.0); UPD72065(config, m_upd72065, 16_MHz_XTAL / 2, true, false); // clocked through SED9420CAC - m_upd72065->intrq_wr_callback().set(FUNC(x68k_state::fdc_irq)); + m_upd72065->intrq_wr_callback().set(FUNC(x68k_state::ioc_irq)); m_upd72065->drq_wr_callback().set(m_hd63450, FUNC(hd63450_device::drq0_w)); FLOPPY_CONNECTOR(config, "upd72065:0", x68k_floppies, "525hd", x68k_state::floppy_formats); FLOPPY_CONNECTOR(config, "upd72065:1", x68k_floppies, "525hd", x68k_state::floppy_formats); @@ -1191,17 +1103,20 @@ void x68k_state::x68000_base(machine_config &config) SOFTWARE_LIST(config, "flop_list").set_original("x68k_flop"); + input_merger_any_high_device &nmi(INPUT_MERGER_ANY_HIGH(config, "nmi")); + nmi.output_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ7); + X68K_EXPANSION_SLOT(config, m_expansion[0], x68000_exp_cards, nullptr); m_expansion[0]->set_space(m_maincpu, AS_PROGRAM); m_expansion[0]->out_irq2_callback().set(FUNC(x68k_state::irq2_line<0>)); m_expansion[0]->out_irq4_callback().set(FUNC(x68k_state::irq4_line<0>)); - m_expansion[0]->out_nmi_callback().set(FUNC(x68k_state::nmi_line<0>)); + m_expansion[0]->out_nmi_callback().set(nmi, FUNC(input_merger_any_high_device::in_w<0>)); X68K_EXPANSION_SLOT(config, m_expansion[1], x68000_exp_cards, nullptr); m_expansion[1]->set_space(m_maincpu, AS_PROGRAM); m_expansion[1]->out_irq2_callback().set(FUNC(x68k_state::irq2_line<1>)); m_expansion[1]->out_irq4_callback().set(FUNC(x68k_state::irq4_line<1>)); - m_expansion[1]->out_nmi_callback().set(FUNC(x68k_state::nmi_line<1>)); + m_expansion[1]->out_nmi_callback().set(nmi, FUNC(input_merger_any_high_device::in_w<1>)); /* internal ram */ RAM(config, m_ram).set_default_size("4M").set_extra_options("1M,2M,3M,5M,6M,7M,8M,9M,10M,11M,12M"); @@ -1253,7 +1168,7 @@ void x68ksupr_state::x68ksupr_base(machine_config &config) mb89352_device &spc = downcast(*device); spc.set_clock(40_MHz_XTAL / 8); - spc.out_irq_callback().set(*this, FUNC(x68ksupr_state::scsi_irq)); + spc.out_irq_callback().set(*this, FUNC(x68ksupr_state::ioc_irq)); spc.out_dreq_callback().set(m_hd63450, FUNC(hd63450_device::drq1_w)); }); diff --git a/src/mame/sharp/x68k.h b/src/mame/sharp/x68k.h index 70554ee8328..25a92a4112f 100644 --- a/src/mame/sharp/x68k.h +++ b/src/mame/sharp/x68k.h @@ -167,22 +167,13 @@ protected: struct { uint8_t irqstatus = 0; - uint8_t fdcvector = 0; - uint8_t fddvector = 0; - uint8_t hdcvector = 0; - uint8_t prnvector = 0; + uint8_t vector = 0; } m_ioc; uint8_t m_ppi_portc = 0; - bool m_dmac_int = false; - bool m_mfp_int = false; - bool m_scc_int = false; bool m_exp_irq2[2]{}; bool m_exp_irq4[2]{}; - bool m_exp_nmi[2]{}; - uint8_t m_current_ipl = 0; int m_led_state = 0; emu_timer* m_led_timer = nullptr; - unsigned char m_scc_prev = 0; emu_timer* m_fdc_tc = nullptr; emu_timer* m_adpcm_timer = nullptr; emu_timer* m_bus_error_timer = nullptr; @@ -209,13 +200,12 @@ protected: uint8_t ppi_port_b_r(); uint8_t ppi_port_c_r(); void ppi_port_c_w(uint8_t data); - void fdc_irq(int state); void ct_w(uint8_t data); void adpcm_w(offs_t offset, uint8_t data); - void mfp_irq_callback(int state); + + template void ioc_irq(int state); //dmac - void dma_irq(int state); void dma_end(offs_t offset, uint8_t data); void set_adpcm(); @@ -223,12 +213,11 @@ protected: void fm_irq(int state); template void irq2_line(int state); template void irq4_line(int state); - template void nmi_line(int state); void fdc_w(offs_t offset, uint16_t data); uint16_t fdc_r(offs_t offset); - void ioc_w(offs_t offset, uint16_t data); - uint16_t ioc_r(offs_t offset); + void ioc_w(offs_t offset, uint8_t data); + uint8_t ioc_r(offs_t offset); void sysport_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); uint16_t sysport_r(offs_t offset); void ppi_w(offs_t offset, uint16_t data); @@ -256,7 +245,6 @@ protected: uint16_t gvram_read(offs_t offset); void gvram_write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - void update_ipl(); uint8_t iack1(); uint8_t iack2(); uint8_t iack4(); @@ -300,7 +288,6 @@ public: virtual void driver_start() override; protected: - void scsi_irq(int state); void scsi_unknown_w(uint8_t data); required_device m_scsictrl;