diff options
Diffstat (limited to 'src/devices/bus/apricot/expansion')
-rw-r--r-- | src/devices/bus/apricot/expansion/cards.cpp | 2 | ||||
-rw-r--r-- | src/devices/bus/apricot/expansion/expansion.cpp | 25 | ||||
-rw-r--r-- | src/devices/bus/apricot/expansion/expansion.h | 33 | ||||
-rw-r--r-- | src/devices/bus/apricot/expansion/winchester.cpp | 254 | ||||
-rw-r--r-- | src/devices/bus/apricot/expansion/winchester.h | 66 |
5 files changed, 344 insertions, 36 deletions
diff --git a/src/devices/bus/apricot/expansion/cards.cpp b/src/devices/bus/apricot/expansion/cards.cpp index d2c35366e42..ef0243bf412 100644 --- a/src/devices/bus/apricot/expansion/cards.cpp +++ b/src/devices/bus/apricot/expansion/cards.cpp @@ -9,10 +9,12 @@ #include "emu.h" #include "cards.h" #include "ram.h" +#include "winchester.h" void apricot_expansion_cards(device_slot_interface &device) { device.option_add("128k", APRICOT_128K_RAM); device.option_add("256k", APRICOT_256K_RAM); device.option_add("512k", APRICOT_512K_RAM); + device.option_add("winchester", APRICOT_WINCHESTER); } diff --git a/src/devices/bus/apricot/expansion/expansion.cpp b/src/devices/bus/apricot/expansion/expansion.cpp index 98141860782..5a89c9a8868 100644 --- a/src/devices/bus/apricot/expansion/expansion.cpp +++ b/src/devices/bus/apricot/expansion/expansion.cpp @@ -59,18 +59,16 @@ DEFINE_DEVICE_TYPE(APRICOT_EXPANSION_BUS, apricot_expansion_bus_device, "apricot apricot_expansion_bus_device::apricot_expansion_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, APRICOT_EXPANSION_BUS, tag, owner, clock), - m_program(nullptr), - m_io(nullptr), - m_program_iop(nullptr), - m_io_iop(nullptr), + m_program(*this, finder_base::DUMMY_TAG, -1), + m_io(*this, finder_base::DUMMY_TAG, -1), + m_program_iop(*this, finder_base::DUMMY_TAG, -1), + m_io_iop(*this, finder_base::DUMMY_TAG, -1), m_dma1_handler(*this), m_dma2_handler(*this), m_ext1_handler(*this), m_ext2_handler(*this), m_int2_handler(*this), - m_int3_handler(*this), - m_cpu(*this, finder_base::DUMMY_TAG), - m_iop(*this, finder_base::DUMMY_TAG) + m_int3_handler(*this) { } @@ -99,19 +97,6 @@ void apricot_expansion_bus_device::device_start() } //------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- - -void apricot_expansion_bus_device::device_reset() -{ - m_program = &m_cpu->space(AS_PROGRAM); - m_io = &m_cpu->space(AS_IO); - - m_program_iop = &m_iop->space(AS_PROGRAM); - m_io_iop = &m_iop->space(AS_IO); -} - -//------------------------------------------------- // add_card - add new card to our bus //------------------------------------------------- diff --git a/src/devices/bus/apricot/expansion/expansion.h b/src/devices/bus/apricot/expansion/expansion.h index 85b0e47dc5e..93c529f24e3 100644 --- a/src/devices/bus/apricot/expansion/expansion.h +++ b/src/devices/bus/apricot/expansion/expansion.h @@ -89,16 +89,14 @@ class apricot_expansion_bus_device : public device_t { public: // construction/destruction - template <typename T, typename U> - apricot_expansion_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu_tag, U &&iop_tag) - : apricot_expansion_bus_device(mconfig, tag, owner, (uint32_t)0) - { - m_cpu.set_tag(std::forward<T>(cpu_tag)); - m_iop.set_tag(std::forward<U>(iop_tag)); - } apricot_expansion_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual ~apricot_expansion_bus_device(); + template <typename T> void set_program_space(T &&tag, int spacenum) { m_program.set_tag(std::forward<T>(tag), spacenum); } + template <typename T> void set_io_space(T &&tag, int spacenum) { m_io.set_tag(std::forward<T>(tag), spacenum); } + template <typename T> void set_program_iop_space(T &&tag, int spacenum) { m_program_iop.set_tag(std::forward<T>(tag), spacenum); } + template <typename T> void set_io_iop_space(T &&tag, int spacenum) { m_io_iop.set_tag(std::forward<T>(tag), spacenum); } + auto dma1() { return m_dma1_handler.bind(); } auto dma2() { return m_dma2_handler.bind(); } auto ext1() { return m_ext1_handler.bind(); } @@ -118,19 +116,26 @@ public: void install_ram(offs_t addrstart, offs_t addrend, void *baseptr); + template<typename T> void install_io_device(offs_t addrstart, offs_t addrend, T &device, void (T::*map)(class address_map &map), uint64_t unitmask = ~u64(0)) + { + m_io->install_device(addrstart, addrend, device, map, unitmask); + + if (m_io_iop) + m_io_iop->install_device(addrstart, addrend, device, map, unitmask); + } + protected: // device-level overrides virtual void device_start() override; - virtual void device_reset() override; private: simple_list<device_apricot_expansion_card_interface> m_dev; // address spaces we have access to - address_space *m_program; - address_space *m_io; - address_space *m_program_iop; - address_space *m_io_iop; + required_address_space m_program; + required_address_space m_io; + optional_address_space m_program_iop; + optional_address_space m_io_iop; devcb_write_line m_dma1_handler; devcb_write_line m_dma2_handler; @@ -138,10 +143,6 @@ private: devcb_write_line m_ext2_handler; devcb_write_line m_int2_handler; devcb_write_line m_int3_handler; - - // configuration - required_device<cpu_device> m_cpu; - required_device<cpu_device> m_iop; }; // device type definition diff --git a/src/devices/bus/apricot/expansion/winchester.cpp b/src/devices/bus/apricot/expansion/winchester.cpp new file mode 100644 index 00000000000..f16752b3ede --- /dev/null +++ b/src/devices/bus/apricot/expansion/winchester.cpp @@ -0,0 +1,254 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + ACT Apricot Winchester Controller + + Version Rev 9 + +***************************************************************************/ + +#include "emu.h" +#include "winchester.h" +#include "imagedev/harddriv.h" + +//#define LOG_GENERAL (1U << 0) +#define LOG_REGS (1U << 1) +#define LOG_DATA (1U << 2) + +//#define VERBOSE (LOG_REGS) +//#define LOG_OUTPUT_STREAM std::cout + +#include "logmacro.h" + +#define LOGREGS(...) LOGMASKED(LOG_REGS, __VA_ARGS__) +#define LOGDATA(...) LOGMASKED(LOG_DATA, __VA_ARGS__) + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(APRICOT_WINCHESTER, apricot_winchester_device, "apricot_winchester", "Apricot Winchester Controller Board") + +//------------------------------------------------- +// regs - controller register i/o map +//------------------------------------------------- + +void apricot_winchester_device::regs(address_map &map) +{ + map(0x0e0, 0x0ef).rw(m_hdc, FUNC(wd1010_device::read), FUNC(wd1010_device::write)).umask16(0x00ff); + map(0x1e0, 0x1e0).rw(FUNC(apricot_winchester_device::int_r), FUNC(apricot_winchester_device::head_w<0>)).umask16(0x00ff); + map(0x1e2, 0x1e2).w(FUNC(apricot_winchester_device::head_w<1>)).umask16(0x00ff); + map(0x1e4, 0x1e4).w(FUNC(apricot_winchester_device::head_w<2>)).umask16(0x00ff); + map(0x1e6, 0x1e6).w(FUNC(apricot_winchester_device::drive_w<0>)).umask16(0x00ff); + map(0x1e8, 0x1e8).w(FUNC(apricot_winchester_device::xferd_w)).umask16(0x00ff); // transferred + map(0x1ea, 0x1ea).w(FUNC(apricot_winchester_device::hbcr_w)).umask16(0x00ff); // host buffer clear register + map(0x1ec, 0x1ec).w(FUNC(apricot_winchester_device::clksel_w)).umask16(0x00ff); // buffer chip read/write clock select (host or wdc) + map(0x1ee, 0x1ee).w(FUNC(apricot_winchester_device::drive_w<1>)).umask16(0x00ff); + map(0x1f0, 0x1f0).rw(FUNC(apricot_winchester_device::data_r), FUNC(apricot_winchester_device::data_w)).umask16(0x00ff); +} + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void apricot_winchester_device::device_add_mconfig(machine_config &config) +{ + WD1010(config, m_hdc, 5000000); + m_hdc->out_intrq_callback().set(FUNC(apricot_winchester_device::hdc_intrq_w)); + m_hdc->in_data_callback().set(FUNC(apricot_winchester_device::hdc_data_r)); + m_hdc->out_data_callback().set(FUNC(apricot_winchester_device::hdc_data_w)); + + HARDDISK(config, "hdc:0", 0); + HARDDISK(config, "hdc:1", 0); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// apricot_winchester_device - constructor +//------------------------------------------------- + +apricot_winchester_device::apricot_winchester_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, APRICOT_WINCHESTER, tag, owner, clock), + device_apricot_expansion_card_interface(mconfig, *this), + m_hdc(*this, "hdc"), + m_ram_ptr(0), + m_int(0), + m_drive(0), + m_head(0), + m_hbcr(0), + m_clksel(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void apricot_winchester_device::device_start() +{ + // allocate 8-bit buffer ram (8k) + m_ram = std::make_unique<uint8_t[]>(0x2000); + + // register for save states + save_pointer(NAME(m_ram), 0x2000); + save_item(NAME(m_ram_ptr)); + save_item(NAME(m_int)); + save_item(NAME(m_drive)); + save_item(NAME(m_head)); + save_item(NAME(m_hbcr)); + save_item(NAME(m_clksel)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void apricot_winchester_device::device_reset() +{ + m_bus->install_io_device(0x000, 0xfff, *this, &apricot_winchester_device::regs); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +WRITE_LINE_MEMBER( apricot_winchester_device::hdc_intrq_w ) +{ + LOGREGS("hdc_intrq_w: %d\n", state); + + m_int = state; + m_bus->int2_w(state); +} + +READ8_MEMBER( apricot_winchester_device::hdc_data_r ) +{ + uint8_t data = 0xff; + + if (m_clksel == 1) + { + LOGDATA("hdc_data_r[%04x]\n", m_ram_ptr); + + data = m_ram[m_ram_ptr]; + if (m_ram_ptr < 0x1fff) + m_ram_ptr++; + } + + return data; +} + +WRITE8_MEMBER( apricot_winchester_device::hdc_data_w ) +{ + if (m_clksel == 1) + { + LOGDATA("hdc_data_w[%04x] = %02x\n", m_ram_ptr, data); + + m_ram[m_ram_ptr] = data; + if (m_ram_ptr < 0x1fff) + m_ram_ptr++; + } +} + +READ8_MEMBER( apricot_winchester_device::int_r ) +{ + return m_int; +} + +template<int N> +WRITE8_MEMBER( apricot_winchester_device::head_w ) +{ + m_head = (m_head & ~(1 << N)) | (BIT(data, 0) << N); + LOGREGS("Select head: %d\n", m_head); +} + +template<int N> +WRITE8_MEMBER( apricot_winchester_device::drive_w ) +{ + m_drive = (m_drive & ~(1 << N)) | (BIT(data, 0) << N); + LOGREGS("Select drive: %d\n", m_drive); + + // forward drive status to the hdc + harddisk_image_device *drive = nullptr; + + switch (m_drive) + { + case 0: + drive = nullptr; + break; + case 1: + drive = m_hdc->subdevice<harddisk_image_device>("0"); + break; + case 2: + drive = m_hdc->subdevice<harddisk_image_device>("1"); + break; + case 3: + // both (invalid?) + drive = nullptr; + break; + } + + m_hdc->drdy_w(drive != nullptr && drive->exists()); +} + +WRITE8_MEMBER( apricot_winchester_device::xferd_w ) +{ + LOGREGS("xferd_w: %02x\n", data); + + m_hdc->brdy_w(BIT(data, 0)); +} + +WRITE8_MEMBER( apricot_winchester_device::hbcr_w ) +{ + LOGREGS("hbcr_w: %02x\n", data); + + // reset ram pointer on high->low transition + if (m_hbcr == 1 && data == 0) + m_ram_ptr = 0; + + m_hbcr = BIT(data, 0); +} + +WRITE8_MEMBER( apricot_winchester_device::clksel_w ) +{ + LOGREGS("clksel_w: %02x\n", data); + + m_clksel = BIT(data, 0); +} + +READ8_MEMBER( apricot_winchester_device::data_r ) +{ + uint8_t data = 0xff; + + if (m_clksel == 0) + { + LOGDATA("data_r[%04x]\n", m_ram_ptr); + + data = m_ram[m_ram_ptr]; + + // wrap or stop at end? + if (m_ram_ptr < 0x1fff) + m_ram_ptr++; + } + + return data; +} + +WRITE8_MEMBER( apricot_winchester_device::data_w ) +{ + if (m_clksel == 0) + { + LOGDATA("data_w[%04x] = %02x\n", m_ram_ptr, data); + + m_ram[m_ram_ptr] = data; + + // wrap or stop at end? + if (m_ram_ptr < 0x1fff) + m_ram_ptr++; + } +} diff --git a/src/devices/bus/apricot/expansion/winchester.h b/src/devices/bus/apricot/expansion/winchester.h new file mode 100644 index 00000000000..c4c82ab0585 --- /dev/null +++ b/src/devices/bus/apricot/expansion/winchester.h @@ -0,0 +1,66 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + ACT Apricot Winchester Controller + +***************************************************************************/ + +#ifndef MAME_BUS_APRICOT_WINCHESTER_H +#define MAME_BUS_APRICOT_WINCHESTER_H + +#pragma once + +#include "expansion.h" +#include "machine/wd1010.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> apricot_winchester_device + +class apricot_winchester_device : public device_t, public device_apricot_expansion_card_interface +{ +public: + // construction/destruction + apricot_winchester_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + // device-level overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + +private: + DECLARE_WRITE_LINE_MEMBER(hdc_intrq_w); + DECLARE_READ8_MEMBER(hdc_data_r); + DECLARE_WRITE8_MEMBER(hdc_data_w); + DECLARE_READ8_MEMBER(int_r); + template<int N> DECLARE_WRITE8_MEMBER(head_w); + template<int N> DECLARE_WRITE8_MEMBER(drive_w); + DECLARE_WRITE8_MEMBER(xferd_w); + DECLARE_WRITE8_MEMBER(hbcr_w); + DECLARE_WRITE8_MEMBER(clksel_w); + DECLARE_WRITE8_MEMBER(drvsel2_w); + DECLARE_READ8_MEMBER(data_r); + DECLARE_WRITE8_MEMBER(data_w); + + void regs(address_map &map); + + required_device<wd1010_device> m_hdc; + + std::unique_ptr<uint8_t[]> m_ram; + unsigned m_ram_ptr; + int m_int; + int m_drive; + int m_head; + int m_hbcr; + int m_clksel; +}; + +// device type definition +DECLARE_DEVICE_TYPE(APRICOT_WINCHESTER, apricot_winchester_device) + +#endif // MAME_BUS_APRICOT_WINCHESTER_H |