x68k: improve interrupt handling

This commit is contained in:
Patrick Mackinlay 2025-03-17 09:28:35 +07:00
parent 50d077c63e
commit 6b6d06bdae
2 changed files with 66 additions and 164 deletions

View File

@ -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 <unsigned N> 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<IOC_FDC_INT>(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<IOC_FDD_INT>(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<IOC_PRT_INT>(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<IOC_HDD_INT>(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 <int N>
@ -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 <int N>
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<IOC_FDD_INT>(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<IOC_FDC_INT>));
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<mb89352_device &>(*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<IOC_HDD_INT>));
spc.out_dreq_callback().set(m_hd63450, FUNC(hd63450_device::drq1_w));
});

View File

@ -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 <unsigned N> 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 <int N> void irq2_line(int state);
template <int N> void irq4_line(int state);
template <int N> 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<mb89352_device> m_scsictrl;