diff options
Diffstat (limited to 'src/devices/machine/applepic.cpp')
-rw-r--r-- | src/devices/machine/applepic.cpp | 104 |
1 files changed, 88 insertions, 16 deletions
diff --git a/src/devices/machine/applepic.cpp b/src/devices/machine/applepic.cpp index feb122140d4..a523b690e34 100644 --- a/src/devices/machine/applepic.cpp +++ b/src/devices/machine/applepic.cpp @@ -19,6 +19,18 @@ DEFINE_DEVICE_TYPE(APPLEPIC, applepic_device, "applepic", "Apple 343S1021 PIC") const std::string_view applepic_device::s_interrupt_names[8] = { "0", "DMA 1", "DMA 2", "peripheral", "host", "timer", "6", "7" }; +static constexpr int IRQ_DMA1 = 1; +static constexpr int IRQ_DMA2 = 2; +static constexpr int IRQ_PERIPHERAL = 3; +static constexpr int IRQ_HOST = 4; +static constexpr int IRQ_TIMER = 5; + +static constexpr u8 DMAEN = 0x01; // 1 = channel enabled +static constexpr u8 DREQ = 0x02; // 1 = DREQ line for this channel is active +static constexpr u8 DMADIR = 0x04; // 1 = I/O to RAM, 0 = RAM to I/O +static constexpr u8 DENxONx = 0x08; // 1 = enable this channel when the other channel completes a transfer +static constexpr int DIOASHIFT = 0x04; // right shift amount for I/O offset bits + applepic_device::applepic_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, APPLEPIC, tag, owner, clock) , m_iopcpu(*this, "iopcpu") @@ -28,6 +40,7 @@ applepic_device::applepic_device(const machine_config &mconfig, const char *tag, , m_gpin_callback(*this, 0) , m_gpout_callback(*this) , m_timer1(nullptr) + , m_dma_timer(nullptr) , m_timer_last_expired(attotime::zero) , m_ram_address(0) , m_status_reg(0x80) @@ -43,6 +56,7 @@ applepic_device::applepic_device(const machine_config &mconfig, const char *tag, channel.control = 0; channel.map = 0; channel.tc = 0; + channel.req = false; } } @@ -73,6 +87,9 @@ void applepic_device::device_start() // Initialize timer m_timer1 = timer_alloc(FUNC(applepic_device::timer1_callback), this); + // get a timer for the DMA + m_dma_timer = timer_alloc(FUNC(applepic_device::dma_timer_callback), this); + // Save internal state save_item(NAME(m_timer_last_expired)); save_item(NAME(m_ram_address)); @@ -96,6 +113,13 @@ void applepic_device::device_reset() m_iopcpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, CLEAR_LINE); m_hint_callback(CLEAR_LINE); + + for (dma_channel &channel : m_dma_channel) + { + channel.control = 0; + } + + m_dma_timer->adjust(attotime::zero, 0, clocks_to_attotime(8)); } u8 applepic_device::host_r(offs_t offset) @@ -154,7 +178,7 @@ void applepic_device::host_w(offs_t offset, u8 data) m_iopcpu->set_input_line(INPUT_LINE_RESET, BIT(data, 2) ? CLEAR_LINE : ASSERT_LINE); } if (BIT(data, 3)) - set_interrupt(4); + set_interrupt(IRQ_HOST); if ((m_status_reg & data & 0x30) != 0) { m_status_reg &= ~(data & 0x30); @@ -178,30 +202,40 @@ void applepic_device::pint_w(int state) { m_status_reg |= 0x40; if (!BIT(m_scc_control, 0)) - set_interrupt(3); + set_interrupt(IRQ_PERIPHERAL); } else { m_status_reg &= 0xbf; if (!BIT(m_scc_control, 0)) - reset_interrupt(3); + reset_interrupt(IRQ_PERIPHERAL); } } void applepic_device::reqa_w(int state) { - if (state == ASSERT_LINE) - m_dma_channel[0].control |= 0x02; + m_dma_channel[0].req = state; + if (state) + { + m_dma_channel[0].control |= DREQ; + } else - m_dma_channel[0].control &= 0xfd; + { + m_dma_channel[0].control &= ~DREQ; + } } void applepic_device::reqb_w(int state) { - if (state == ASSERT_LINE) - m_dma_channel[1].control |= 0x02; + m_dma_channel[1].req = state; + if (state) + { + m_dma_channel[1].control |= DREQ; + } else - m_dma_channel[1].control &= 0xfd; + { + m_dma_channel[1].control &= ~DREQ; + } } u8 applepic_device::timer_r(offs_t offset) @@ -212,7 +246,7 @@ u8 applepic_device::timer_r(offs_t offset) else { if (offset == 0 && !machine().side_effects_disabled()) - reset_interrupt(5); + reset_interrupt(IRQ_TIMER); return reg & 0x00ff; } } @@ -224,7 +258,7 @@ void applepic_device::timer_w(offs_t offset, u8 data) m_timer_latch = u16(data) << 8 | (m_timer_latch & 0x00ff); if (offset == 1) { - reset_interrupt(5); + reset_interrupt(IRQ_TIMER); m_timer1->adjust(clocks_to_attotime(m_timer_latch * 8 + 12)); } } @@ -242,7 +276,7 @@ u16 applepic_device::get_timer_count() const TIMER_CALLBACK_MEMBER(applepic_device::timer1_callback) { - set_interrupt(5); + set_interrupt(IRQ_TIMER); if (BIT(m_timer_dpll_control, 0)) m_timer1->adjust(clocks_to_attotime((m_timer_latch + 2) * 8)); else @@ -284,7 +318,7 @@ void applepic_device::dma_channel_w(offs_t offset, u8 data) switch (offset & 7) { case 0: - channel.control = (data & 0xfd) | (channel.control & 0x02); + channel.control = ((data & ~DREQ) | (channel.control & DREQ)); break; case 1: @@ -300,7 +334,7 @@ void applepic_device::dma_channel_w(offs_t offset, u8 data) break; case 4: - channel.tc = (data & 0x07) | (channel.tc & 0x0ff); + channel.tc = ((data & 0x07) << 8) | (channel.tc & 0x0ff); break; default: @@ -309,6 +343,44 @@ void applepic_device::dma_channel_w(offs_t offset, u8 data) } } +TIMER_CALLBACK_MEMBER(applepic_device::dma_timer_callback) +{ + for (int ch = 0; ch < 2; ch++) + { + auto &channel = m_dma_channel[ch]; + auto other_channel = m_dma_channel[ch ^ 1]; + + if ((channel.control & DMAEN) && (channel.req) && (channel.tc > 0)) + { + if (channel.control & DMADIR) + { + const u8 xfer = m_prd_callback(channel.control >> DIOASHIFT); + m_iopcpu->space(AS_PROGRAM).write_byte(channel.map, xfer); + } + else + { + const u8 xfer = m_iopcpu->space(AS_PROGRAM).read_byte(channel.map); + m_pwr_callback(channel.control >> DIOASHIFT, xfer); + } + + channel.map++; + channel.tc--; + + // if this channel completed, handle the DEN1ON2/DEN2ON1 alternating transfer bits and IRQ + if (channel.tc == 0) + { + channel.control &= ~DMAEN; + if (other_channel.control & DENxONx) + { + other_channel.control |= DMAEN; + } + + set_interrupt(IRQ_DMA1 + ch); + } + } + } +} + u8 applepic_device::scc_control_r() { return m_scc_control; @@ -318,9 +390,9 @@ void applepic_device::scc_control_w(u8 data) { m_scc_control = data; if (!BIT(data, 0) && BIT(m_status_reg, 6)) - set_interrupt(3); + set_interrupt(IRQ_PERIPHERAL); else - reset_interrupt(3); + reset_interrupt(IRQ_PERIPHERAL); m_gpout_callback[1](BIT(data, 7)); } |