hd63450: More accurate IRQ handling with a tidier interface

This commit is contained in:
AJR 2019-04-19 08:18:45 -04:00
parent 64b7857113
commit 7ad4b4d194
7 changed files with 112 additions and 112 deletions

View File

@ -242,12 +242,7 @@ void vme_fcscsi1_card_device::update_irq_to_maincpu() {
void vme_fcscsi1_card_device::cpu_space_map(address_map &map)
{
map(0xfffff0, 0xffffff).m(m_maincpu, FUNC(m68000_base_device::autovectors_map));
map(0xfffff4, 0xfffff5).lr16("dmac irq", [this]() -> u16 {
dmac_irq_state = 0;
u16 vector = B41 ? dmac_irq_vector : 0x18+2;
update_irq_to_maincpu();
return vector;
});
map(0xfffff5, 0xfffff5).r(m_dmac, FUNC(hd63450_device::iack));
}
FLOPPY_FORMATS_MEMBER( vme_fcscsi1_card_device::floppy_formats )
@ -301,8 +296,7 @@ void vme_fcscsi1_card_device::device_add_mconfig(machine_config &config)
HD63450(config, m_dmac, CPU_CRYSTAL / 2, "maincpu"); // MC68450 compatible
m_dmac->set_clocks(attotime::from_usec(32), attotime::from_nsec(450), attotime::from_usec(4), attotime::from_hz(15625/2));
m_dmac->set_burst_clocks(attotime::from_usec(32), attotime::from_nsec(450), attotime::from_nsec(50), attotime::from_nsec(50));
m_dmac->dma_end().set(FUNC(vme_fcscsi1_card_device::dma_end));
m_dmac->dma_error().set(FUNC(vme_fcscsi1_card_device::dma_error));
m_dmac->irq_callback().set(FUNC(vme_fcscsi1_card_device::dma_irq));
//m_dmac->dma_read<0>().set(FUNC(vme_fcscsi1_card_device::scsi_read_byte)); // ch 0 = SCSI
//m_dmac->dma_write<0>().set(FUNC(vme_fcscsi1_card_device::scsi_write_byte));
m_dmac->dma_read<1>().set(FUNC(vme_fcscsi1_card_device::fdc_read_byte)); // ch 1 = fdc
@ -420,12 +414,12 @@ WRITE8_MEMBER (vme_fcscsi1_card_device::led_w){
return;
}
WRITE8_MEMBER(vme_fcscsi1_card_device::dma_end)
WRITE_LINE_MEMBER(vme_fcscsi1_card_device::dma_irq)
{
if (data != 0)
if(state != CLEAR_LINE)
{
logerror("DMAC IRQ, vector = %x\n", m_dmac->iack());
dmac_irq_state = 1;
dmac_irq_vector = m_dmac->get_vector(offset);
}
else
{
@ -435,25 +429,9 @@ WRITE8_MEMBER(vme_fcscsi1_card_device::dma_end)
update_irq_to_maincpu();
}
WRITE8_MEMBER(vme_fcscsi1_card_device::dma_error)
WRITE_LINE_MEMBER(vme_fcscsi1_card_device::fdc_irq)
{
if(data != 0)
{
logerror("DMAC error, vector = %x\n", m_dmac->get_error_vector(offset));
dmac_irq_state = 1;
dmac_irq_vector = m_dmac->get_vector(offset);
}
else
{
dmac_irq_state = 0;
}
update_irq_to_maincpu();
}
WRITE8_MEMBER(vme_fcscsi1_card_device::fdc_irq)
{
if (data != 0)
if (state != 0)
{
fdc_irq_state = 1;
}

View File

@ -32,15 +32,13 @@ protected:
uint8_t fdc_irq_state;
uint8_t dmac_irq_state;
int dmac_irq_vector;
private:
//dmac
DECLARE_WRITE8_MEMBER(dma_end);
DECLARE_WRITE8_MEMBER(dma_error);
DECLARE_WRITE_LINE_MEMBER(dma_irq);
//fdc
DECLARE_WRITE8_MEMBER(fdc_irq);
DECLARE_WRITE_LINE_MEMBER(fdc_irq);
DECLARE_READ8_MEMBER(fdc_read_byte);
DECLARE_WRITE8_MEMBER(fdc_write_byte);
DECLARE_FLOPPY_FORMATS(floppy_formats);

View File

@ -16,8 +16,8 @@ DEFINE_DEVICE_TYPE(HD63450, hd63450_device, "hd63450", "Hitachi HD63450 DMAC")
hd63450_device::hd63450_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, HD63450, tag, owner, clock),
m_irq_callback(*this),
m_dma_end(*this),
m_dma_error(*this),
m_dma_read{{*this}, {*this}, {*this}, {*this}},
m_dma_write{{*this}, {*this}, {*this}, {*this}},
m_cpu(*this, finder_base::DUMMY_TAG)
@ -43,8 +43,8 @@ hd63450_device::hd63450_device(const machine_config &mconfig, const char *tag, d
void hd63450_device::device_start()
{
// resolve callbacks
m_dma_end.resolve();
m_dma_error.resolve_safe();
m_irq_callback.resolve_safe();
m_dma_end.resolve_safe();
for (auto &cb : m_dma_read)
cb.resolve();
for (auto &cb : m_dma_write)
@ -77,10 +77,13 @@ void hd63450_device::device_start()
save_item(NAME(m_transfer_size));
save_item(NAME(m_halted));
save_item(NAME(m_drq_state));
save_item(NAME(m_irq_channel));
}
void hd63450_device::device_reset()
{
// Device is reset by pulling /BEC0-/BEC2 all low for 10 clocks
for (int x = 0; x < 4; x++)
{
m_reg[x].niv = 0x0f;
@ -97,6 +100,9 @@ void hd63450_device::device_reset()
m_timer[x]->adjust(attotime::never);
m_halted[x] = 0;
}
m_irq_channel = -1;
m_irq_callback(CLEAR_LINE);
}
READ16_MEMBER(hd63450_device::read)
@ -166,6 +172,9 @@ WRITE16_MEMBER(hd63450_device::write)
// Clearing ERR also resets CER (which is otherwise read-only)
if ((data & 0x1000) != 0)
m_reg[channel].cer = 0;
if ((m_reg[channel].csr & 0xf2) == 0)
clear_irq(channel);
}
break;
case 0x02: // DCR / OCR
@ -317,11 +326,7 @@ void hd63450_device::dma_transfer_abort(int channel)
LOG("DMA#%i: Transfer aborted\n",channel);
m_timer[channel]->adjust(attotime::never);
m_reg[channel].csr |= 0x90; // channel error
m_reg[channel].csr &= ~0x08; // channel no longer active
m_reg[channel].cer = 0x11;
m_reg[channel].ccr &= ~0xc0;
m_dma_error((offs_t)3, m_reg[channel].ccr & 0x08);
set_error(channel, 0x11);
}
void hd63450_device::dma_transfer_halt(int channel)
@ -467,11 +472,21 @@ void hd63450_device::single_transfer(int x)
m_cpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
}
if (!m_dma_end.isnull())
m_dma_end((offs_t)x, m_reg[x].ccr & 0x08);
m_dma_end((offs_t)x, 0);
set_irq(x);
}
}
void hd63450_device::set_error(int channel, uint8_t code)
{
m_reg[channel].csr |= 0x90; // channel error
m_reg[channel].csr &= ~0x08; // channel no longer active
m_reg[channel].cer = code;
m_reg[channel].ccr &= ~0xc0;
set_irq(channel);
}
WRITE_LINE_MEMBER(hd63450_device::drq0_w)
{
bool ostate = m_drq_state[0];
@ -529,12 +544,52 @@ WRITE_LINE_MEMBER(hd63450_device::drq3_w)
m_timer[3]->adjust(attotime::never);
}
int hd63450_device::get_vector(int channel)
void hd63450_device::set_irq(int channel)
{
return m_reg[channel].niv;
if ((m_reg[channel].ccr & 0x08) == 0)
return;
if (m_irq_channel == -1)
{
m_irq_channel = channel;
m_irq_callback(ASSERT_LINE);
}
else if ((m_reg[channel].cpr & 0x03) < (m_reg[m_irq_channel].cpr & 0x03))
m_irq_channel = channel;
}
int hd63450_device::get_error_vector(int channel)
void hd63450_device::clear_irq(int channel)
{
return m_reg[channel].eiv;
if (m_irq_channel != channel)
return;
for (int pri = m_reg[channel].cpr & 0x03; pri <= 3; pri++)
{
for (int offset = 1; offset <= 3; offset++)
{
if ((m_reg[(channel + offset) & 3].ccr & 0x08) != 0 &&
(m_reg[(channel + offset) & 3].csr & 0xf2) != 0)
{
m_irq_channel = (channel + offset) & 3;
return;
}
}
}
m_irq_channel = -1;
m_irq_callback(CLEAR_LINE);
}
uint8_t hd63450_device::iack()
{
if (m_irq_channel != -1)
{
if ((m_reg[m_irq_channel].csr & 0x10) != 0)
return m_reg[m_irq_channel].eiv;
else
return m_reg[m_irq_channel].niv;
}
// Spurious interrupt (no response actually)
return 0x18;
}

View File

@ -20,8 +20,8 @@ public:
hd63450_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto irq_callback() { return m_irq_callback.bind(); }
auto dma_end() { return m_dma_end.bind(); }
auto dma_error() { return m_dma_error.bind(); }
template<int Ch> auto dma_read() { return m_dma_read[Ch].bind(); }
template<int Ch> auto dma_write() { return m_dma_write[Ch].bind(); }
@ -47,11 +47,10 @@ public:
DECLARE_WRITE_LINE_MEMBER(drq1_w);
DECLARE_WRITE_LINE_MEMBER(drq2_w);
DECLARE_WRITE_LINE_MEMBER(drq3_w);
uint8_t iack();
void single_transfer(int x);
void set_timer(int channel, const attotime &tm);
int get_vector(int channel);
int get_error_vector(int channel);
protected:
// device-level overrides
@ -81,8 +80,8 @@ private:
uint8_t gcr; // [3f] General Control Register (R/W)
};
devcb_write_line m_irq_callback;
devcb_write8 m_dma_end;
devcb_write8 m_dma_error;
devcb_read8 m_dma_read[4];
devcb_write8 m_dma_write[4];
@ -97,6 +96,8 @@ private:
required_device<cpu_device> m_cpu;
bool m_drq_state[4];
int8_t m_irq_channel;
// tell if a channel is in use
bool dma_in_progress(int channel) const { return (m_reg[channel].csr & 0x08) != 0; }
@ -105,6 +106,11 @@ private:
void dma_transfer_halt(int channel);
void dma_transfer_continue(int channel);
void dma_transfer_start(int channel);
void set_error(int channel, uint8_t code);
// interrupt helpers
void set_irq(int channel);
void clear_irq(int channel);
};
DECLARE_DEVICE_TYPE(HD63450, hd63450_device)

View File

@ -229,9 +229,7 @@ private:
uint8_t m_duart_io;
uint8_t otis_irq_state;
uint8_t dmac_irq_state;
int dmac_irq_vector;
uint8_t duart_irq_state;
int duart_irq_vector;
void update_irq_to_maincpu();
@ -246,8 +244,7 @@ private:
uint16_t m_analog_values[8];
//dmac
DECLARE_WRITE8_MEMBER(dma_end);
DECLARE_WRITE8_MEMBER(dma_error);
DECLARE_WRITE_LINE_MEMBER(dma_irq);
};
FLOPPY_FORMATS_MEMBER( esq5505_state::floppy_formats )
@ -257,8 +254,8 @@ FLOPPY_FORMATS_END
void esq5505_state::cpu_space_map(address_map &map)
{
map(0xfffff0, 0xffffff).m(m_maincpu, FUNC(m68000_base_device::autovectors_map));
map(0xfffff4, 0xfffff5).lr16("dmac irq", [this]() -> u16 { return dmac_irq_vector; });
map(0xfffff6, 0xfffff7).lr16("duart irq", [this]() -> u16 { return duart_irq_vector; });
map(0xfffff5, 0xfffff5).r(m_dmac, FUNC(hd63450_device::iack));
map(0xfffff7, 0xfffff7).r(m_duart, FUNC(mc68681_device::get_irq_vector));
}
void esq5505_state::machine_start()
@ -448,7 +445,6 @@ WRITE_LINE_MEMBER(esq5505_state::duart_irq_handler)
// printf("\nDUART IRQ: state %d vector %d\n", state, vector);
if (state == ASSERT_LINE)
{
duart_irq_vector = m_duart->get_irq_vector();
duart_irq_state = 1;
}
else
@ -524,30 +520,12 @@ WRITE_LINE_MEMBER(esq5505_state::duart_tx_b)
m_panel->rx_w(state);
}
WRITE8_MEMBER(esq5505_state::dma_end)
WRITE_LINE_MEMBER(esq5505_state::dma_irq)
{
if (data != 0)
if (state != CLEAR_LINE)
{
//printf("DMAC IRQ, vector = %x\n", m_dmac->get_vector(offset));
logerror("DMAC error, vector = %x\n", m_dmac->iack());
dmac_irq_state = 1;
dmac_irq_vector = m_dmac->get_vector(offset);
}
else
{
dmac_irq_state = 0;
}
// printf("IRQ update from DMAC: have OTIS=%d, DMAC=%d, DUART=%d\n", otis_irq_state, dmac_irq_state, duart_irq_state);
update_irq_to_maincpu();
}
WRITE8_MEMBER(esq5505_state::dma_error)
{
if(data != 0)
{
logerror("DMAC error, vector = %x\n", m_dmac->get_error_vector(offset));
dmac_irq_state = 1;
dmac_irq_vector = m_dmac->get_vector(offset);
}
else
{
@ -683,8 +661,7 @@ void esq5505_state::eps(machine_config &config)
m_dmac->set_cpu_tag(m_maincpu);
m_dmac->set_clocks(attotime::from_usec(32), attotime::from_nsec(450), attotime::from_usec(4), attotime::from_hz(15625/2));
m_dmac->set_burst_clocks(attotime::from_usec(32), attotime::from_nsec(450), attotime::from_nsec(50), attotime::from_nsec(50));
m_dmac->dma_end().set(FUNC(esq5505_state::dma_end));
m_dmac->dma_error().set(FUNC(esq5505_state::dma_error));
m_dmac->irq_callback().set(FUNC(esq5505_state::dma_irq));
m_dmac->dma_read<0>().set(m_fdc, FUNC(wd1772_device::data_r)); // ch 0 = fdc, ch 1 = 340001 (ADC?)
m_dmac->dma_write<0>().set(m_fdc, FUNC(wd1772_device::data_w));
}

View File

@ -313,7 +313,7 @@ TIMER_CALLBACK_MEMBER(x68k_state::scc_ack)
{
m_mouse.irqactive = 1;
m_current_vector[5] = 0x54;
m_current_irq_line = 5;
//m_current_irq_line = 5;
m_maincpu->set_input_line(5,ASSERT_LINE);
}
}
@ -680,7 +680,7 @@ WRITE_LINE_MEMBER( x68k_state::fdc_irq )
{
m_current_vector[1] = m_ioc.fdcvector;
m_ioc.irqstatus |= 0x80;
m_current_irq_line = 1;
//m_current_irq_line = 1;
LOGMASKED(LOG_FDC, "FDC: IRQ triggered\n");
m_maincpu->set_input_line(1, ASSERT_LINE);
}
@ -998,37 +998,24 @@ WRITE16_MEMBER(x68k_state::exp_w)
set_bus_error((offset << 1) + 0xeafa00, 1, mem_mask);
}
void x68k_state::dma_irq(int channel)
WRITE_LINE_MEMBER(x68k_state::dma_irq)
{
m_current_vector[3] = m_hd63450->get_vector(channel);
m_current_irq_line = 3;
LOGMASKED(LOG_SYS, "DMA#%i: DMA End (vector 0x%02x)\n",channel,m_current_vector[3]);
m_maincpu->set_input_line(3,ASSERT_LINE);
if (state != CLEAR_LINE)
{
//m_current_irq_line = 3;
LOGMASKED(LOG_SYS, "DMA IRQ (vector 0x%02x)\n", m_hd63450->iack());
}
m_maincpu->set_input_line(3, state);
}
WRITE8_MEMBER(x68k_state::dma_end)
{
if(data != 0)
{
dma_irq(offset);
}
if(offset == 0)
{
m_fdc_tc->adjust(attotime::from_usec(1), 0, attotime::never);
}
}
WRITE8_MEMBER(x68k_state::dma_error)
{
if(data != 0)
{
m_current_vector[3] = m_hd63450->get_error_vector(offset);
m_current_irq_line = 3;
LOGMASKED(LOG_SYS, "DMA#%i: DMA Error (vector 0x%02x)\n",offset,m_current_vector[3]);
m_maincpu->set_input_line(3,ASSERT_LINE);
}
}
WRITE_LINE_MEMBER(x68k_state::fm_irq)
{
if(state == CLEAR_LINE)
@ -1104,7 +1091,7 @@ void x68k_state::cpu_space_map(address_map &map)
map.global_mask(0xffffff);
map(0xfffff3, 0xfffff3).r(FUNC(x68k_state::int_ack<1>));
map(0xfffff5, 0xfffff5).r(FUNC(x68k_state::int_ack<2>));
map(0xfffff7, 0xfffff7).r(FUNC(x68k_state::int_ack<3>));
map(0xfffff7, 0xfffff7).r(m_hd63450, FUNC(hd63450_device::iack));
map(0xfffff9, 0xfffff9).r(FUNC(x68k_state::int_ack<4>));
map(0xfffffb, 0xfffffb).r(FUNC(x68k_state::int_ack<5>));
map(0xfffffd, 0xfffffd).r(FUNC(x68k_state::mfp_ack));
@ -1117,7 +1104,7 @@ WRITE_LINE_MEMBER(x68ksupr_state::scsi_irq)
if(state != 0)
{
m_current_vector[1] = 0x6c;
m_current_irq_line = 1;
//m_current_irq_line = 1;
m_maincpu->set_input_line(1,ASSERT_LINE);
}
}
@ -1383,7 +1370,7 @@ void x68k_state::floppy_load_unload(bool load, floppy_image_device *dev)
{
m_current_vector[1] = 0x61;
m_ioc.irqstatus |= 0x40;
m_current_irq_line = 1;
//m_current_irq_line = 1;
m_maincpu->set_input_line(1,ASSERT_LINE); // Disk insert/eject interrupt
LOGMASKED(LOG_FDC, "IOC: Disk image inserted\n");
}
@ -1403,7 +1390,7 @@ void x68k_state::floppy_unload(floppy_image_device *dev)
TIMER_CALLBACK_MEMBER(x68k_state::net_irq)
{
m_current_vector[2] = 0xf9;
m_current_irq_line = 2;
//m_current_irq_line = 2;
m_maincpu->set_input_line(2,ASSERT_LINE);
}
@ -1594,8 +1581,8 @@ 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(50), attotime::from_nsec(50));
m_hd63450->irq_callback().set(FUNC(x68k_state::dma_irq));
m_hd63450->dma_end().set(FUNC(x68k_state::dma_end));
m_hd63450->dma_error().set(FUNC(x68k_state::dma_error));
m_hd63450->dma_read<0>().set("upd72065", FUNC(upd72065_device::dma_r));
m_hd63450->dma_write<0>().set("upd72065", FUNC(upd72065_device::dma_w));

View File

@ -229,7 +229,7 @@ protected:
} m_mdctrl;
uint8_t m_ppi_port[3];
int m_current_vector[8];
uint8_t m_current_irq_line;
//uint8_t m_current_irq_line;
int m_led_state;
emu_timer* m_mouse_timer;
emu_timer* m_led_timer;
@ -270,9 +270,8 @@ protected:
DECLARE_WRITE_LINE_MEMBER(mfp_irq_callback);
//dmac
void dma_irq(int channel);
DECLARE_WRITE_LINE_MEMBER(dma_irq);
DECLARE_WRITE8_MEMBER(dma_end);
DECLARE_WRITE8_MEMBER(dma_error);
int read_mouse();
void set_adpcm();