From aa78efa47faaeedec17d4c663e30b7a3fc9a12ea Mon Sep 17 00:00:00 2001 From: AJR Date: Thu, 29 Jul 2021 23:46:05 -0400 Subject: applepic: Add device files missing from 918da8411db59ec376d800ae2a424344a6736a25 --- src/devices/machine/applepic.cpp | 406 +++++++++++++++++++++++++++++++++++++++ src/devices/machine/applepic.h | 105 ++++++++++ 2 files changed, 511 insertions(+) create mode 100644 src/devices/machine/applepic.cpp create mode 100644 src/devices/machine/applepic.h diff --git a/src/devices/machine/applepic.cpp b/src/devices/machine/applepic.cpp new file mode 100644 index 00000000000..ea959534b96 --- /dev/null +++ b/src/devices/machine/applepic.cpp @@ -0,0 +1,406 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + + Apple Computer 343S1021 PIC (Peripheral Interface Controller) + + NCR standard cell ASIC, 65CX02 CPU core + +**********************************************************************/ + +#include "emu.h" +#include "applepic.h" + +// device type definition +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" }; + +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") + , m_prd_callback(*this) + , m_pwr_callback(*this) + , m_hint_callback(*this) + , m_gpout_callback(*this) + , m_ram_address(0) + , m_status_reg(0x80) + , m_timer_counter(0) + , m_timer_latch(0) + , m_scc_control(0) + , m_io_control(0) + , m_timer_dpll_control(0) + , m_int_mask(0) + , m_int_reg(0) +{ + for (dma_channel &channel : m_dma_channel) + { + channel.control = 0; + channel.map = 0; + channel.tc = 0; + } +} + +void applepic_device::internal_map(address_map &map) +{ + map(0x0000, 0x6fff).mirror(0x8000).ram(); + map(0x7000, 0x77ff).ram(); + map(0x7800, 0x7fff).mirror(0x8000).ram(); + map(0xf010, 0xf013).rw(FUNC(applepic_device::timer_r), FUNC(applepic_device::timer_w)); + map(0xf020, 0xf02f).rw(FUNC(applepic_device::dma_channel_r), FUNC(applepic_device::dma_channel_w)); + map(0xf030, 0xf030).rw(FUNC(applepic_device::scc_control_r), FUNC(applepic_device::scc_control_w)); + map(0xf031, 0xf031).rw(FUNC(applepic_device::io_control_r), FUNC(applepic_device::io_control_w)); + map(0xf032, 0xf032).rw(FUNC(applepic_device::timer_dpll_control_r), FUNC(applepic_device::timer_dpll_control_w)); + map(0xf033, 0xf033).rw(FUNC(applepic_device::int_mask_r), FUNC(applepic_device::int_mask_w)); + map(0xf034, 0xf034).rw(FUNC(applepic_device::int_reg_r), FUNC(applepic_device::int_reg_w)); + map(0xf035, 0xf035).rw(FUNC(applepic_device::host_reg_r), FUNC(applepic_device::host_reg_w)); + map(0xf040, 0xf04f).rw(FUNC(applepic_device::device_reg_r), FUNC(applepic_device::device_reg_w)); +} + +void applepic_device::device_add_mconfig(machine_config &config) +{ + R65C02(config, m_iopcpu, DERIVED_CLOCK(1, 8)); + m_iopcpu->set_addrmap(AS_PROGRAM, &applepic_device::internal_map); +} + +void applepic_device::device_resolve_objects() +{ + // Resolve callbacks + m_prd_callback.resolve_safe(0); + m_pwr_callback.resolve_safe(); + m_hint_callback.resolve_safe(); + m_gpout_callback.resolve_all_safe(); +} + +void applepic_device::device_start() +{ + // Save internal state + save_item(NAME(m_ram_address)); + save_item(NAME(m_status_reg)); + save_item(NAME(m_timer_counter)); + save_item(NAME(m_timer_latch)); + save_item(STRUCT_MEMBER(m_dma_channel, control)); + save_item(STRUCT_MEMBER(m_dma_channel, map)); + save_item(STRUCT_MEMBER(m_dma_channel, tc)); + save_item(NAME(m_scc_control)); + save_item(NAME(m_io_control)); + save_item(NAME(m_timer_dpll_control)); + save_item(NAME(m_int_mask)); + save_item(NAME(m_int_reg)); +} + +void applepic_device::device_reset() +{ + m_status_reg &= 0xc3; + m_int_mask = 0; + + 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); +} + +u8 applepic_device::host_r(offs_t offset) +{ + if (BIT(offset, 4)) + { + if (BIT(m_scc_control, 0)) + return m_prd_callback(offset & 0x0f); + else + { + if (!machine().side_effects_disabled()) + logerror("%s: Read from device register $%X in non-bypass mode\n", machine().describe_context(), offset & 0x0f); + return 0; + } + } + else if (BIT(offset, 2)) + { + // Shared RAM read access + u8 data = m_iopcpu->space(AS_PROGRAM).read_byte(m_ram_address); + if (BIT(m_status_reg, 1) && !machine().side_effects_disabled()) + ++m_ram_address; + return data; + } + else if (BIT(offset, 1)) + { + // PINT (D6) and /REQ (D7) are used in bypass mode only + return BIT(m_scc_control, 0) ? m_status_reg | 0x01 : (m_status_reg & 0x3f) | 0x80; + } + else if (BIT(offset, 0)) + return m_ram_address & 0x00ff; + else + return (m_ram_address & 0xff00) >> 8; +} + +void applepic_device::host_w(offs_t offset, u8 data) +{ + if (BIT(offset, 4)) + { + if (BIT(m_scc_control, 0)) + m_pwr_callback(offset & 0x0f, data); + else + logerror("%s: Write $%02X to device register $%X in non-bypass mode\n", machine().describe_context(), data, offset & 0x0f); + } + else if (BIT(offset, 2)) + { + // Shared RAM write access + m_iopcpu->space(AS_PROGRAM).write_byte(m_ram_address, data); + if (BIT(m_status_reg, 1)) + ++m_ram_address; + } + else if (BIT(offset, 1)) + { + if (BIT(m_status_reg, 2) != BIT(data, 2)) + { + logerror("%s: /RSTPIC %dactive\n", machine().describe_context(), BIT(data, 2) ? "in" : ""); + m_iopcpu->set_input_line(INPUT_LINE_RESET, BIT(data, 2) ? CLEAR_LINE : ASSERT_LINE); + } + if (BIT(data, 3)) + set_interrupt(4); + if ((m_status_reg & data & 0x30) != 0) + { + m_status_reg &= ~(data & 0x30); + if ((m_status_reg & 0x30) == 0) + { + logerror("%s: Host interrupts acknowledged\n", machine().describe_context()); + m_hint_callback(CLEAR_LINE); + } + } + m_status_reg = (data & 0x06) | (m_status_reg & 0xf0); + } + else if (BIT(offset, 0)) + m_ram_address = (m_ram_address & 0xff00) | data; + else + m_ram_address = u16(data) << 8 | (m_ram_address & 0x00ff); +} + +WRITE_LINE_MEMBER(applepic_device::pint_w) +{ + if (state == ASSERT_LINE) + { + m_status_reg |= 0x40; + if (!BIT(m_scc_control, 0)) + set_interrupt(3); + } + else + { + m_status_reg &= 0xbf; + if (!BIT(m_scc_control, 0)) + reset_interrupt(3); + } +} + +WRITE_LINE_MEMBER(applepic_device::reqa_w) +{ +} + +WRITE_LINE_MEMBER(applepic_device::reqb_w) +{ +} + +u8 applepic_device::timer_r(offs_t offset) +{ + u16 reg = BIT(offset, 1) ? m_timer_latch : m_timer_counter; + if (BIT(offset, 0)) + return (reg & 0xff00) >> 8; + else + { + if (offset == 0 && !machine().side_effects_disabled()) + reset_interrupt(5); + return reg & 0x00ff; + } +} + +void applepic_device::timer_w(offs_t offset, u8 data) +{ + if (BIT(offset, 0)) + { + m_timer_latch = u16(data) << 8 | (m_timer_latch & 0xff00); + if (offset == 1) + reset_interrupt(5); + } + else + m_timer_latch = (m_timer_latch & 0xff00) | data; +} + +u8 applepic_device::dma_channel_r(offs_t offset) +{ + dma_channel &channel = m_dma_channel[BIT(offset, 3)]; + + switch (offset & 7) + { + case 0: + return channel.control; + + case 1: + return channel.map & 0x00ff; + + case 2: + return (channel.map & 0xff00) >> 8; + + case 3: + return channel.tc & 0x0ff; + + case 4: + return (channel.tc & 0x700) >> 8; + + default: + if (!machine().side_effects_disabled()) + logerror("%s: Read from undefined DMA register $%02X\n", machine().describe_context(), 0x20 + offset); + return 0; + } +} + +void applepic_device::dma_channel_w(offs_t offset, u8 data) +{ + dma_channel &channel = m_dma_channel[BIT(offset, 3)]; + + switch (offset & 7) + { + case 0: + channel.control = data; + break; + + case 1: + channel.map = (channel.map & 0xff00) | data; + break; + + case 2: + channel.map = u16(data) << 8 | (channel.map & 0x00ff); + break; + + case 3: + channel.tc = (channel.tc & 0x700) | data; + break; + + case 4: + channel.tc = (data & 0x07) | (channel.tc & 0x0ff); + break; + + default: + logerror("%s: Write $%02X to undefined DMA register $%02X\n", machine().describe_context(), data, 0x20 + offset); + break; + } +} + +u8 applepic_device::scc_control_r() +{ + return m_scc_control; +} + +void applepic_device::scc_control_w(u8 data) +{ + m_scc_control = data; + if (!BIT(data, 0) && BIT(m_status_reg, 6)) + set_interrupt(3); + else + reset_interrupt(3); + m_gpout_callback[1](BIT(data, 7)); +} + +u8 applepic_device::io_control_r() +{ + return m_io_control; +} + +void applepic_device::io_control_w(u8 data) +{ + m_io_control = data; +} + +u8 applepic_device::timer_dpll_control_r() +{ + return m_timer_dpll_control; +} + +void applepic_device::timer_dpll_control_w(u8 data) +{ + m_timer_dpll_control = data; +} + +u8 applepic_device::int_mask_r() +{ + return m_int_mask; +} + +void applepic_device::int_mask_w(u8 data) +{ + for (int which = 1; which <= 5; which++) + if (BIT(m_int_mask, which) != BIT(data, which)) + logerror("%s: %sabling %s interrupt\n", machine().describe_context(), BIT(data, which) ? "En" : "Dis", s_interrupt_names[which]); + + m_int_mask = data & 0x3e; + m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, (m_int_mask & m_int_reg) != 0 ? ASSERT_LINE : CLEAR_LINE); +} + +u8 applepic_device::int_reg_r() +{ + return m_int_reg; +} + +void applepic_device::int_reg_w(u8 data) +{ + if ((m_int_reg & data) != 0) + { + m_int_reg &= ~data; + if ((m_int_mask & m_int_reg) == 0) + { + logerror("%s: 6502 interrupts acknowledged\n", machine().describe_context()); + m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, CLEAR_LINE); + } + } +} + +void applepic_device::set_interrupt(int which) +{ + if (!BIT(m_int_reg, which)) + { + logerror("%s: Setting %s interrupt\n", machine().describe_context(), s_interrupt_names[which]); + m_int_reg |= (1 << which); + if ((m_int_reg & m_int_mask) == (1 << which)) + m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, ASSERT_LINE); + } +} + +void applepic_device::reset_interrupt(int which) +{ + if (BIT(m_int_reg, which)) + { + logerror("%s: Resetting %s interrupt\n", machine().describe_context(), s_interrupt_names[which]); + if ((m_int_reg & m_int_mask) == (1 << which)) + m_iopcpu->set_input_line(r65c02_device::IRQ_LINE, CLEAR_LINE); + m_int_reg &= ~(1 << which); + } +} + +u8 applepic_device::host_reg_r() +{ + return (m_status_reg & 0x30) >> 2; +} + +void applepic_device::host_reg_w(u8 data) +{ + logerror("%s: INTHST0 %srequested, INTHST1 %srequested\n", machine().describe_context(), BIT(data, 2) ? "" : "not ", BIT(data, 3) ? "" : "not "); + m_status_reg |= (data & 0x0c) << 2; + if ((data & 0x0c) != 0) + m_hint_callback(ASSERT_LINE); +} + +u8 applepic_device::device_reg_r(offs_t offset) +{ + if (BIT(m_scc_control, 0)) + { + if (!machine().side_effects_disabled()) + logerror("%s: Read from device register $%X in bypass mode\n", machine().describe_context(), offset & 0x0f); + return 0; + } + else + return m_prd_callback(offset & 0x0f); +} + +void applepic_device::device_reg_w(offs_t offset, u8 data) +{ + if (BIT(m_scc_control, 0)) + logerror("%s: Read from device register $%X in bypass mode\n", machine().describe_context(), offset & 0x0f); + else + m_pwr_callback(offset & 0x0f, data); +} diff --git a/src/devices/machine/applepic.h b/src/devices/machine/applepic.h new file mode 100644 index 00000000000..1bd3a2983bb --- /dev/null +++ b/src/devices/machine/applepic.h @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_DEVICES_MACHINE_APPLEPIC_H +#define MAME_DEVICES_MACHINE_APPLEPIC_H + +#pragma once + +#include "cpu/m6502/r65c02.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> applepic_device + +class applepic_device : public device_t +{ +public: + // construction/destruction + applepic_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + // callback configuration + auto prd_callback() { return m_prd_callback.bind(); } + auto pwr_callback() { return m_pwr_callback.bind(); } + auto hint_callback() { return m_hint_callback.bind(); } + auto gpout0_callback() { return m_gpout_callback[0].bind(); } + auto gpout1_callback() { return m_gpout_callback[1].bind(); } + + // host interface + u8 host_r(offs_t offset); + void host_w(offs_t offset, u8 data); + + // peripheral device requests + DECLARE_WRITE_LINE_MEMBER(pint_w); + DECLARE_WRITE_LINE_MEMBER(reqa_w); + DECLARE_WRITE_LINE_MEMBER(reqb_w); + +protected: + // device-level overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; + +private: + static const std::string_view s_interrupt_names[8]; + + struct dma_channel + { + u8 control; + u16 map; + u16 tc; + }; + + u8 timer_r(offs_t offset); + void timer_w(offs_t offset, u8 data); + void reset_timer_interrupt(); + u8 dma_channel_r(offs_t offset); + void dma_channel_w(offs_t offset, u8 data); + u8 scc_control_r(); + void scc_control_w(u8 data); + u8 io_control_r(); + void io_control_w(u8 data); + u8 timer_dpll_control_r(); + void timer_dpll_control_w(u8 data); + u8 int_mask_r(); + void int_mask_w(u8 data); + u8 int_reg_r(); + void int_reg_w(u8 data); + void set_interrupt(int which); + void reset_interrupt(int which); + u8 host_reg_r(); + void host_reg_w(u8 data); + u8 device_reg_r(offs_t offset); + void device_reg_w(offs_t offset, u8 data); + + void internal_map(address_map &map); + + // internal CPU + required_device m_iopcpu; + + // callbacks for peripheral and host + devcb_read8 m_prd_callback; + devcb_write8 m_pwr_callback; + devcb_write_line m_hint_callback; + devcb_write_line::array<2> m_gpout_callback; + + // internal state + u16 m_ram_address; + u8 m_status_reg; + u16 m_timer_counter; + u16 m_timer_latch; + dma_channel m_dma_channel[2]; + u8 m_scc_control; + u8 m_io_control; + u8 m_timer_dpll_control; + u8 m_int_mask; + u8 m_int_reg; +}; + +// device type declaration +DECLARE_DEVICE_TYPE(APPLEPIC, applepic_device) + +#endif // MAME_DEVICES_MACHINE_APPLEPIC_H -- cgit v1.2.3