From 1e7d83cc4bee4cba40853b271c06d724e25fbbcb Mon Sep 17 00:00:00 2001 From: Dirk Best Date: Wed, 4 Aug 2021 19:29:32 +0200 Subject: apxen: Checkpoint, get something on screen - Implement video slot and mono graphics video card - Hook up CIO, SIO, RTC, PIT, SN76489 - Add daisy chain for Z80 devices and hook it up to the PIC - Add system control ports --- scripts/src/bus.lua | 17 ++ scripts/target/mame/mess.lua | 1 + src/devices/bus/apricot/video/cards.cpp | 16 ++ src/devices/bus/apricot/video/cards.h | 16 ++ src/devices/bus/apricot/video/mono.cpp | 278 +++++++++++++++++++++++++ src/devices/bus/apricot/video/mono.h | 65 ++++++ src/devices/bus/apricot/video/video.cpp | 114 +++++++++++ src/devices/bus/apricot/video/video.h | 89 ++++++++ src/mame/drivers/apxen.cpp | 346 +++++++++++++++++++++++++++----- 9 files changed, 897 insertions(+), 45 deletions(-) create mode 100644 src/devices/bus/apricot/video/cards.cpp create mode 100644 src/devices/bus/apricot/video/cards.h create mode 100644 src/devices/bus/apricot/video/mono.cpp create mode 100644 src/devices/bus/apricot/video/mono.h create mode 100644 src/devices/bus/apricot/video/video.cpp create mode 100644 src/devices/bus/apricot/video/video.h diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index d889e7af294..10e37cdbae6 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -257,6 +257,23 @@ if (BUSES["APRICOT_KEYBOARD"]~=null) then end +--------------------------------------------------- +-- +--@src/devices/bus/apricot/video/video.h,BUSES["APRICOT_VIDEO"] = true +--------------------------------------------------- + +if (BUSES["APRICOT_VIDEO"]~=null) then + files { + MAME_DIR .. "src/devices/bus/apricot/video/video.cpp", + MAME_DIR .. "src/devices/bus/apricot/video/video.h", + MAME_DIR .. "src/devices/bus/apricot/video/cards.cpp", + MAME_DIR .. "src/devices/bus/apricot/video/cards.h", + MAME_DIR .. "src/devices/bus/apricot/video/mono.cpp", + MAME_DIR .. "src/devices/bus/apricot/video/mono.h", + } +end + + --------------------------------------------------- -- --@src/devices/bus/aquarius/slot.h,BUSES["AQUARIUS"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index ff4bea4f494..9bfcac1d17e 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -838,6 +838,7 @@ BUSES["AMIGA_KEYBOARD"] = true BUSES["APF"] = true BUSES["APRICOT_EXPANSION"] = true BUSES["APRICOT_KEYBOARD"] = true +BUSES["APRICOT_VIDEO"] = true BUSES["AQUARIUS"] = true BUSES["ARCADIA"] = true BUSES["ASTROCADE"] = true diff --git a/src/devices/bus/apricot/video/cards.cpp b/src/devices/bus/apricot/video/cards.cpp new file mode 100644 index 00000000000..7611be80abc --- /dev/null +++ b/src/devices/bus/apricot/video/cards.cpp @@ -0,0 +1,16 @@ +// license: GPL-2.0+ +// copyright-holders: Dirk Best +/*************************************************************************** + + ACT Apricot XEN Video Expansion Slot Devices + +***************************************************************************/ + +#include "emu.h" +#include "cards.h" +#include "mono.h" + +void apricot_video_cards(device_slot_interface &device) +{ + device.option_add("mono", APRICOT_MONO_DISPLAY); +} diff --git a/src/devices/bus/apricot/video/cards.h b/src/devices/bus/apricot/video/cards.h new file mode 100644 index 00000000000..61460b37064 --- /dev/null +++ b/src/devices/bus/apricot/video/cards.h @@ -0,0 +1,16 @@ +// license: GPL-2.0+ +// copyright-holders: Dirk Best +/*************************************************************************** + + ACT Apricot XEN Video Expansion Slot Devices + +***************************************************************************/ + +#ifndef MAME_BUS_APRICOT_VIDEO_CARDS_H +#define MAME_BUS_APRICOT_VIDEO_CARDS_H + +#pragma once + +void apricot_video_cards(device_slot_interface &device); + +#endif // MAME_BUS_APRICOT_VIDEO_CARDS_H diff --git a/src/devices/bus/apricot/video/mono.cpp b/src/devices/bus/apricot/video/mono.cpp new file mode 100644 index 00000000000..7254962193c --- /dev/null +++ b/src/devices/bus/apricot/video/mono.cpp @@ -0,0 +1,278 @@ +// license: GPL-2.0+ +// copyright-holders: Dirk Best +/*************************************************************************** + + ACT Apricot XEN Monochrome Display Option + + TODO: + - Support monitor selection + +***************************************************************************/ + +#include "emu.h" +#include "mono.h" +#include "screen.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(APRICOT_MONO_DISPLAY, apricot_mono_display_device, "apricot_mono_display", "Apricot Monochrome Display") + +//------------------------------------------------- +// character viewer +//------------------------------------------------- + +static const gfx_layout apricot_charlayout = +{ + 10, 16, + 1792, + 1, + { 0 }, + { 7, 6, 5, 4, 3, 2, 1, 0, 15, 14 }, + { STEP16(0, 16) }, + 16*16 +}; + +static GFXDECODE_START( gfx ) +GFXDECODE_END + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void apricot_mono_display_device::device_add_mconfig(machine_config &config) +{ + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_color(rgb_t::green()); + screen.set_size(800, 400); + screen.set_visarea(0, 800-1, 0, 400-1); + screen.set_refresh_hz(72); + screen.set_screen_update(FUNC(apricot_mono_display_device::screen_update)); + + PALETTE(config, m_palette, palette_device::MONOCHROME_HIGHLIGHT); + + HD6845S(config, m_crtc, 24_MHz_XTAL / 10); // actually MB89321B (15 MHz for white monitor, 24 MHz for green) + m_crtc->set_screen("screen"); + m_crtc->set_show_border_area(false); + m_crtc->set_char_width(10); + m_crtc->set_update_row_callback(FUNC(apricot_mono_display_device::crtc_update_row)); + m_crtc->out_de_callback().set(FUNC(apricot_mono_display_device::crtc_de_w)); + m_crtc->out_vsync_callback().set(FUNC(apricot_mono_display_device::crtc_vsync_w)); + + GFXDECODE(config, m_gfxdecode, m_palette, gfx); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// apricot_mono_display_device - constructor +//------------------------------------------------- + +apricot_mono_display_device::apricot_mono_display_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, APRICOT_MONO_DISPLAY, tag, owner, clock), + device_apricot_video_interface(mconfig, *this), + m_crtc(*this, "crtc"), + m_palette(*this, "palette"), + m_gfxdecode(*this, "gfxdecode") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void apricot_mono_display_device::device_start() +{ + // allocate 64k vram + m_vram = std::make_unique(0x8000); + + // init gfxdecode + m_gfxdecode->set_gfx(0, std::make_unique(m_palette, apricot_charlayout, reinterpret_cast(m_vram.get()), 0, 1, 0)); + + // register for save states + save_pointer(NAME(m_vram), 0x8000); + save_item(NAME(m_portb)); + save_item(NAME(m_portc)); + save_item(NAME(m_portx)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void apricot_mono_display_device::device_reset() +{ + // a reset forces all bits to a logic high + m_portb = 0xff; + m_portc = 0xff; + m_portx = 0xff; +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +bool apricot_mono_display_device::mem_r(offs_t offset, uint16_t &data, uint16_t mem_mask) +{ + data = m_vram[offset]; + return true; +} + +bool apricot_mono_display_device::mem_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + m_vram[offset] = data; + return true; +} + +bool apricot_mono_display_device::io_r(offs_t offset, uint16_t &data, uint16_t mem_mask) +{ + offset <<= 1; + + if (BIT(m_portx, 0) == 0) + { + // apricot pc/xi compatible + switch (offset) + { + case 0x4a: data = 0xff00 | m_portb; return true; + case 0x4c: data = 0xff00 | m_portc; return true; + case 0x6a: data = 0xff00 | m_crtc->register_r(); return true; + } + } + else + { + // xen mode + switch (offset) + { + case 0x80: data = 0xff00 | m_portb; return true; + case 0x82: data = 0xff00 | m_portc; return true; + case 0x8a: data = 0xff00 | m_crtc->register_r(); return true; + } + } + + return false; +} + +bool apricot_mono_display_device::io_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + offset <<= 1; + + // only 8-bit writes + if (mem_mask != 0x00ff) + return false; + + if (BIT(m_portx, 0) == 0) + { + // apricot pc/xi compatible + switch (offset) + { + case 0x4a: portb_w(data); return true; + case 0x68: m_crtc->address_w(data); return true; + case 0x6a: m_crtc->register_w(data); return true; + case 0x6c: portx_w(data); return true; + } + } + else + { + // xen mode + switch (offset) + { + case 0x6c: portx_w(data); return true; + case 0x80: portb_w(data); return true; + case 0x88: m_crtc->address_w(data); return true; + case 0x8a: m_crtc->register_w(data); return true; + } + } + + return false; +} + +void apricot_mono_display_device::portb_w(uint8_t data) +{ + logerror("portb_w: %02x\n", data); + + // 765----- not used + // ---4---- video mode (alphanumeric/graphics) + // ----3--- display on + // -----21- not used + // -------0 crtc reset + + m_portb = data; + + if (BIT(m_portb, 0) == 0) + m_crtc->reset(); +} + +void apricot_mono_display_device::portx_w(uint8_t data) +{ + logerror("portx_w: %02x\n", data); + + // 765432-- not used + // ------1- reverse video + // -------0 mode (compatible or xen) + + m_portx = data; + + // forward mode to host + m_slot->apvid_w(BIT(m_portx, 0)); +} + +uint32_t apricot_mono_display_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + m_gfxdecode->gfx(0)->mark_all_dirty(); + m_crtc->screen_update(screen, bitmap, cliprect); + return 0; +} + +// see drivers/apricot.cpp +MC6845_UPDATE_ROW( apricot_mono_display_device::crtc_update_row ) +{ + const pen_t *pen = m_palette->pens(); + + for (int i = 0; i < x_count; i++) + { + uint16_t code = m_vram[(0xe000 >> 1) | (ma + i)]; + uint16_t offset = ((code & 0x7ff) << 5) | (ra << 1); + uint16_t data = m_vram[offset >> 1]; + + if (BIT(m_portb, 4)) + { + int fill = 0; + + if (i == cursor_x) fill = 1; // cursor? + if (BIT(code, 12) && BIT(data, 14)) fill = 1; // strike-through? + if (BIT(code, 13) && BIT(data, 15)) fill = 1; // underline? + + // draw 10 pixels of the character + for (int x = 0; x <= 10; x++) + { + int color = fill ? 1 : BIT(data, x); + color ^= BIT(code, 15); // reverse? + bitmap.pix(y, x + i*10) = pen[color ? 1 + BIT(code, 14) : 0]; + } + } + else + { + // draw 16 pixels of the cell + for (int x = 0; x <= 16; x++) + bitmap.pix(y, x + i*16) = pen[BIT(data, x)]; + } + } +} + +void apricot_mono_display_device::crtc_de_w(int state) +{ + m_portc &= 0xf7; + m_portc |= (state << 3); +} + +void apricot_mono_display_device::crtc_vsync_w(int state) +{ + m_portc &= 0x7f; + m_portc |= (state << 7); +} diff --git a/src/devices/bus/apricot/video/mono.h b/src/devices/bus/apricot/video/mono.h new file mode 100644 index 00000000000..36885bcb768 --- /dev/null +++ b/src/devices/bus/apricot/video/mono.h @@ -0,0 +1,65 @@ +// license: GPL-2.0+ +// copyright-holders: Dirk Best +/*************************************************************************** + + ACT Apricot XEN Monochrome Display Option + +***************************************************************************/ + +#ifndef MAME_BUS_APRICOT_VIDEO_MONO_H +#define MAME_BUS_APRICOT_VIDEO_MONO_H + +#pragma once + +#include "video.h" +#include "video/mc6845.h" +#include "emupal.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> apricot_mono_display_device + +class apricot_mono_display_device : public device_t, public device_apricot_video_interface +{ +public: + // construction/destruction + apricot_mono_display_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; + + virtual bool mem_r(offs_t offset, uint16_t &data, uint16_t mem_mask) override; + virtual bool mem_w(offs_t offset, uint16_t data, uint16_t mem_mask) override; + virtual bool io_r(offs_t offset, uint16_t &data, uint16_t mem_mask) override; + virtual bool io_w(offs_t offset, uint16_t data, uint16_t mem_mask) override; + +private: + required_device m_crtc; + required_device m_palette; + required_device m_gfxdecode; + + void portb_w(uint8_t data); + void portx_w(uint8_t data); + + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + MC6845_UPDATE_ROW(crtc_update_row); + void crtc_de_w(int state); + void crtc_vsync_w(int state); + + std::unique_ptr m_vram; + + uint8_t m_portb; + uint8_t m_portc; + uint8_t m_portx; +}; + +// device type definition +DECLARE_DEVICE_TYPE(APRICOT_MONO_DISPLAY, apricot_mono_display_device) + +#endif // MAME_BUS_APRICOT_VIDEO_MONO_H diff --git a/src/devices/bus/apricot/video/video.cpp b/src/devices/bus/apricot/video/video.cpp new file mode 100644 index 00000000000..fbb33ba83bf --- /dev/null +++ b/src/devices/bus/apricot/video/video.cpp @@ -0,0 +1,114 @@ +// license: GPL-2.0+ +// copyright-holders: Dirk Best +/*************************************************************************** + + ACT Apricot XEN Video Expansion Slot + +***************************************************************************/ + +#include "emu.h" +#include "video.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(APRICOT_VIDEO_SLOT, apricot_video_slot_device, "apricot_video", "Apricot XEN Video Slot") + + +//************************************************************************** +// SLOT DEVICE +//************************************************************************** + +//------------------------------------------------- +// apricot_video_slot_device - constructor +//------------------------------------------------- + +apricot_video_slot_device::apricot_video_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, APRICOT_VIDEO_SLOT, tag, owner, clock), + device_single_card_slot_interface(mconfig, *this), + m_apvid_handler(*this), + m_card(nullptr) +{ +} + +//------------------------------------------------- +// apricot_video_slot_device - destructor +//------------------------------------------------- + +apricot_video_slot_device::~apricot_video_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void apricot_video_slot_device::device_start() +{ + // get inserted module + m_card = get_card_device(); + + // resolve callbacks + m_apvid_handler.resolve_safe(); +} + +//------------------------------------------------- +// host to module interface +//------------------------------------------------- + +bool apricot_video_slot_device::mem_r(offs_t offset, uint16_t &data, uint16_t mem_mask) +{ + if (m_card) + return m_card->mem_r(offset, data, mem_mask); + + return false; +} + +bool apricot_video_slot_device::mem_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (m_card) + return m_card->mem_w(offset, data, mem_mask); + + return false; +} + +bool apricot_video_slot_device::io_r(offs_t offset, uint16_t &data, uint16_t mem_mask) +{ + if (m_card) + return m_card->io_r(offset, data, mem_mask); + + return false; +} + +bool apricot_video_slot_device::io_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (m_card) + return m_card->io_w(offset, data, mem_mask); + + return false; +} + + +//************************************************************************** +// MODULE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_apricot_video_interface - constructor +//------------------------------------------------- + +device_apricot_video_interface::device_apricot_video_interface(const machine_config &mconfig, device_t &device) : + device_interface(device, "apricotvid") +{ + m_slot = dynamic_cast(device.owner()); +} + +//------------------------------------------------- +// ~device_apricot_video_interface - destructor +//------------------------------------------------- + +device_apricot_video_interface::~device_apricot_video_interface() +{ +} diff --git a/src/devices/bus/apricot/video/video.h b/src/devices/bus/apricot/video/video.h new file mode 100644 index 00000000000..5b1a8b322f8 --- /dev/null +++ b/src/devices/bus/apricot/video/video.h @@ -0,0 +1,89 @@ +// license: GPL-2.0+ +// copyright-holders: Dirk Best +/*************************************************************************** + + ACT Apricot XEN Video Expansion Slot + + Large identical to the standard Apricot PC/Xi expansion slot. + +***************************************************************************/ + +#ifndef MAME_BUS_APRICOT_VIDEO_VIDEO_H +#define MAME_BUS_APRICOT_VIDEO_VIDEO_H + +#pragma once + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class device_apricot_video_interface; + +// ======================> apricot_video_slot_device + +class apricot_video_slot_device : public device_t, public device_single_card_slot_interface +{ +public: + // construction/destruction + template + apricot_video_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, const char *dflt) + : apricot_video_slot_device(mconfig, tag, owner, uint32_t(0)) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + } + + apricot_video_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + virtual ~apricot_video_slot_device(); + + // callbacks + auto apvid_handler() { return m_apvid_handler.bind(); } + + // called from cart device + DECLARE_WRITE_LINE_MEMBER( apvid_w ) { m_apvid_handler(state); } + + // called from host + bool mem_r(offs_t offset, uint16_t &data, uint16_t mem_mask); + bool mem_w(offs_t offset, uint16_t data, uint16_t mem_mask); + bool io_r(offs_t offset, uint16_t &data, uint16_t mem_mask); + bool io_w(offs_t offset, uint16_t data, uint16_t mem_mask); + +protected: + // device-level overrides + virtual void device_start() override; + +private: + devcb_write_line m_apvid_handler; + + device_apricot_video_interface *m_card; +}; + +// ======================> device_apricot_video_interface + +class device_apricot_video_interface : public device_interface +{ +public: + // construction/destruction + virtual ~device_apricot_video_interface(); + + virtual bool mem_r(offs_t offset, uint16_t &data, uint16_t mem_mask) { return false; } + virtual bool mem_w(offs_t offset, uint16_t data, uint16_t mem_mask) { return false; } + virtual bool io_r(offs_t offset, uint16_t &data, uint16_t mem_mask) { return false; } + virtual bool io_w(offs_t offset, uint16_t data, uint16_t mem_mask) { return false; } + +protected: + device_apricot_video_interface(const machine_config &mconfig, device_t &device); + + apricot_video_slot_device *m_slot; +}; + +// device type definition +DECLARE_DEVICE_TYPE(APRICOT_VIDEO_SLOT, apricot_video_slot_device) + +// include here so drivers don't need to +#include "cards.h" + +#endif // MAME_BUS_APRICOT_VIDEO_VIDEO_H diff --git a/src/mame/drivers/apxen.cpp b/src/mame/drivers/apxen.cpp index 2727a1d1a7d..32b2f896872 100644 --- a/src/mame/drivers/apxen.cpp +++ b/src/mame/drivers/apxen.cpp @@ -13,7 +13,15 @@ - XEN WS (1 MB RAM, no drives) TODO: - - Everything + - Boot ROM disable, wrap around mode + - Floppy + - DMA + - Harddisk + - Keyboard + - RS232 + - Printer + - Colour graphics board + - Make xen_daisy_device generic? Notes: - Two graphics cards: Mono and colour boards @@ -22,14 +30,63 @@ #include "emu.h" #include "cpu/i86/i286.h" +#include "machine/bankdev.h" +#include "machine/eepromser.h" +#include "machine/mm58274c.h" #include "machine/pic8259.h" +#include "machine/pit8253.h" #include "machine/wd_fdc.h" +#include "machine/z80daisy.h" #include "machine/z80sio.h" -#include "video/mc6845.h" +#include "machine/z8536.h" +#include "sound/sn76496.h" #include "imagedev/floppy.h" #include "formats/apridisk.h" -#include "emupal.h" -#include "screen.h" +#include "bus/apricot/video/video.h" +#include "speaker.h" + + +//************************************************************************** +// XEN DAISY CHAIN ABSTRACTION +//************************************************************************** + +class xen_daisy_device : public device_t, public z80_daisy_chain_interface +{ +public: + xen_daisy_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); + + uint8_t acknowledge(); + IRQ_CALLBACK_MEMBER(inta_cb); + +protected: + virtual void device_start() override; +}; + +DEFINE_DEVICE_TYPE(XEN_DAISY, xen_daisy_device, "xen_daisy", "Apricot XEN daisy chain abstraction") + +xen_daisy_device::xen_daisy_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, XEN_DAISY, tag, owner, clock) + , z80_daisy_chain_interface(mconfig, *this) +{ +} + +void xen_daisy_device::device_start() +{ +} + +uint8_t xen_daisy_device::acknowledge() +{ + device_z80daisy_interface *intf = daisy_get_irq_device(); + if (intf != nullptr) + return intf->z80daisy_irq_ack(); + else + return 0xff; +} + +IRQ_CALLBACK_MEMBER(xen_daisy_device::inta_cb) +{ + return acknowledge(); +} namespace { @@ -45,9 +102,15 @@ public: apxen_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), + m_mem(*this, "mem"), + m_io(*this, "io"), + m_eeprom(*this, "eeprom"), m_pic(*this, "pic%u", 0U), - m_crtc(*this, "crtc"), - m_mono_palette(*this, "mono_palette") + m_daisy(*this, "daisy"), + m_pit(*this, "pit"), + m_cio(*this, "cio"), + m_sio(*this, "sio"), + m_video(*this, "video") { } void apxen(machine_config &config); @@ -58,17 +121,40 @@ protected: private: required_device m_maincpu; + required_device m_mem; + required_device m_io; + required_device m_eeprom; required_device_array m_pic; - required_device m_crtc; - required_device m_mono_palette; + required_device m_daisy; + required_device m_pit; + required_device m_cio; + required_device m_sio; + required_device m_video; + void mem_map_base(address_map &map); void mem_map(address_map &map); + void io_map_base(address_map &map); void io_map(address_map &map); - uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - MC6845_UPDATE_ROW(crtc_update_row); + DECLARE_WRITE_LINE_MEMBER(apvid_w); + + uint16_t mem_r(offs_t offset, uint16_t mem_mask); + void mem_w(offs_t offset, uint16_t data, uint16_t mem_mask); + uint16_t io_r(offs_t offset, uint16_t mem_mask); + void io_w(offs_t offset, uint16_t data, uint16_t mem_mask); uint8_t get_slave_ack(offs_t offset); + void leds_w(uint8_t data); + uint8_t cpu_control_r(); + void cpu_control_w(uint8_t data); + void cpu_reset_w(uint8_t data); + + void cio_porta_w(uint8_t data); + void cio_portb_w(uint8_t data); + void cio_portc_w(uint8_t data); + + bool m_apvid; + uint8_t m_cpu_control; }; @@ -76,32 +162,42 @@ private: // ADDRESS MAPS //************************************************************************** +void apxen_state::mem_map_base(address_map &map) +{ + map(0x000000, 0xffffff).rw(FUNC(apxen_state::mem_r), FUNC(apxen_state::mem_w)); +} + void apxen_state::mem_map(address_map &map) { map(0x000000, 0x07ffff).ram(); + map(0x080000, 0x0effff).noprw(); // silence memory test map(0x0f0000, 0x0fffff).rom().region("bios", 0); map(0xff0000, 0xffffff).rom().region("bios", 0); } +void apxen_state::io_map_base(address_map &map) +{ + map(0x0000, 0xffff).rw(FUNC(apxen_state::io_r), FUNC(apxen_state::io_w)); +} + void apxen_state::io_map(address_map &map) { - map(0x068, 0x068).w(m_crtc, FUNC(hd6845s_device::address_w)); - map(0x06a, 0x06a).rw(m_crtc, FUNC(hd6845s_device::register_r), FUNC(hd6845s_device::register_w)); -// map(0xc00, 0xc00) leds + map.unmap_value_high(); + map(0xc00, 0xc00).w(FUNC(apxen_state::leds_w)); // map(0xc20, 0xc20) printer -// map(0xc30, 0xc31) SN76489 -// map(0xc40, 0xc47) CIO -// map(0xc50, 0xc57) SIO -// map(0xc60, 0xc6f) MM5827 RTC + map(0xc30, 0xc30).w("sn", FUNC(sn76489_device::write)); + map(0xc40, 0xc47).rw(m_cio, FUNC(z8536_device::read), FUNC(z8536_device::write)).umask16(0x00ff); + map(0xc50, 0xc57).rw(m_sio, FUNC(z80sio_device::ba_cd_r), FUNC(z80sio_device::ba_cd_w)).umask16(0x00ff); + map(0xc60, 0xc7f).rw("rtc", FUNC(mm58274c_device::read), FUNC(mm58274c_device::write)).umask16(0x00ff); // map(0xc80, 0xc87) FDC // map(0xc90, 0xc93) uPD7261 HDC map(0xca0, 0xca3).rw(m_pic[0], FUNC(pic8259_device::read), FUNC(pic8259_device::write)).umask16(0x00ff); map(0xca4, 0xca7).rw(m_pic[1], FUNC(pic8259_device::read), FUNC(pic8259_device::write)).umask16(0x00ff); -// map(0xcb0, 0xcb7) PIT -// map(0xcc0, 0xccd) uPD71071 DMA 1 -// map(0xcd0, 0xcdd) uPD71071 DMA 2 -// map(0xce0, 0xce0) cpu control -// map(0xcf0, 0xcf0) cpu reset + map(0xcb0, 0xcb7).rw(m_pit, FUNC(pit8253_device::read), FUNC(pit8253_device::write)).umask16(0x00ff); +// map(0xcc0, 0xccf) uPD71071 DMA 1 +// map(0xcd0, 0xcdf) uPD71071 DMA 2 + map(0xce0, 0xce0).rw(FUNC(apxen_state::cpu_control_r), FUNC(apxen_state::cpu_control_w)); + map(0xcf0, 0xcf0).w(FUNC(apxen_state::cpu_reset_w)); } @@ -117,13 +213,97 @@ INPUT_PORTS_END // VIDEO EMULATION //************************************************************************** -uint32_t apxen_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +WRITE_LINE_MEMBER( apxen_state::apvid_w ) +{ + m_apvid = bool(state); +} + + +//************************************************************************** +// MEMORY +//************************************************************************** + +uint16_t apxen_state::mem_r(offs_t offset, uint16_t mem_mask) +{ + uint16_t data = 0xffff; + + // pc/xi compatible mode vram + if ((offset << 1) < 0x10000 && !m_apvid) + m_video->mem_r(offset & (0xffff >> 1), data, mem_mask); + + // pc/xi video pointer mirror + else if ((offset << 1) >= 0xf0000 && (offset << 1) <= 0xf0fff && !m_apvid) + m_video->mem_r((offset & (0xffff >> 1)) | (0x0e000 >> 1), data, mem_mask); + + // xen mode vram + else if ((offset << 1) >= 0xe0000 && (offset << 1) <= 0xeffff && m_apvid) + m_video->mem_r(offset & (0xffff >> 1), data, mem_mask); + + // normal access + else + data &= m_mem->read16(offset, mem_mask); + + return data; +} + +void apxen_state::mem_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + // pc/xi compatible mode vram + if ((offset << 1) < 0x10000 && !m_apvid) + m_video->mem_w(offset & (0xffff >> 1), data, mem_mask); + + // pc/xi video pointer mirror + else if ((offset << 1) >= 0xf0000 && (offset << 1) <= 0xf0fff && !m_apvid) + m_video->mem_w((offset & (0xffff >> 1)) | (0x0e000 >> 1), data, mem_mask); + + // xen mode vram + else if ((offset << 1) >= 0xe0000 && (offset << 1) <= 0xeffff && m_apvid) + m_video->mem_w(offset & (0xffff >> 1), data, mem_mask); + + // normal access + else + m_mem->write16(offset, data, mem_mask); +} + +uint16_t apxen_state::io_r(offs_t offset, uint16_t mem_mask) +{ + uint16_t data = 0xffff; + + if (!m_video->io_r(offset, data, mem_mask)) + data &= m_io->read16(offset, mem_mask); + + return data; +} + +void apxen_state::io_w(offs_t offset, uint16_t data, uint16_t mem_mask) { - return 0; + if (!m_video->io_w(offset, data, mem_mask)) + m_io->write16(offset, data, mem_mask); } -MC6845_UPDATE_ROW( apxen_state::crtc_update_row ) + +//************************************************************************** +// INTERRUPT HANDLING +//************************************************************************** + +static const z80_daisy_config xen_daisy_chain[] = { + { "cio" }, + { "sio" }, + { nullptr } +}; + +uint8_t apxen_state::get_slave_ack(offs_t offset) +{ + // z80 daisy chain + if (offset == 1) + return m_daisy->acknowledge(); + + // slave pic + if (offset == 2) + return m_pic[1]->acknowledge(); + + return 0x00; } @@ -137,14 +317,61 @@ void apxen_state::machine_start() void apxen_state::machine_reset() { + // boot rom enabled, hard reset + m_cpu_control = 0x00; } -uint8_t apxen_state::get_slave_ack(offs_t offset) +void apxen_state::leds_w(uint8_t data) { - if (offset == 2) - return m_pic[1]->acknowledge(); + logerror("leds_w: %02x\n", data); - return 0x00; + // 76543--- not used + // -----2-- hdd led + // ------1- fdd led + // -------0 voice led +} + +uint8_t apxen_state::cpu_control_r() +{ + // only bits 0 and 1 can be read back + return m_cpu_control & 0x03; +} + +void apxen_state::cpu_control_w(uint8_t data) +{ + logerror("cpu_control_w: %02x\n", data); + + // 76543--- not used + // -----2-- full memory (virtual mode) or 1 mb wraparound (real mode) + // ------1- hard/soft reset + // -------0 boot rom enabled + + m_cpu_control = data; +} + +void apxen_state::cpu_reset_w(uint8_t data) +{ + logerror("cpu_reset_w: %02x\n", data); + + // data written doesn't matter + m_maincpu->reset(); +} + +void apxen_state::cio_porta_w(uint8_t data) +{ + logerror("cio_porta_w: %02x\n", data); +} + +void apxen_state::cio_portb_w(uint8_t data) +{ + logerror("cio_portb_w: %02x\n", data); +} + +void apxen_state::cio_portc_w(uint8_t data) +{ + logerror("cio_portc_w: %02x\n", data); + + m_eeprom->clk_write(BIT(data, 2)); } @@ -155,10 +382,23 @@ uint8_t apxen_state::get_slave_ack(offs_t offset) void apxen_state::apxen(machine_config &config) { I80286(config, m_maincpu, 15_MHz_XTAL / 2); - m_maincpu->set_addrmap(AS_PROGRAM, &apxen_state::mem_map); - m_maincpu->set_addrmap(AS_IO, &apxen_state::io_map); + m_maincpu->set_addrmap(AS_PROGRAM, &apxen_state::mem_map_base); + m_maincpu->set_addrmap(AS_IO, &apxen_state::io_map_base); m_maincpu->set_irq_acknowledge_callback(m_pic[0], FUNC(pic8259_device::inta_cb)); + ADDRESS_MAP_BANK(config, m_mem); + m_mem->set_addrmap(AS_PROGRAM, &apxen_state::mem_map); + m_mem->set_data_width(16); + m_mem->set_addr_width(24); + + ADDRESS_MAP_BANK(config, m_io); + m_io->set_addrmap(AS_PROGRAM, &apxen_state::io_map); + m_io->set_data_width(16); + m_io->set_addr_width(16); + + EEPROM_93C06_16BIT(config, m_eeprom); // NMC9306 + m_eeprom->do_callback().set(m_sio, FUNC(z80sio_device::ctsb_w)); + PIC8259(config, m_pic[0], 0); m_pic[0]->out_int_callback().set_inputline(m_maincpu, 0); m_pic[0]->in_sp_callback().set_constant(1); @@ -168,21 +408,37 @@ void apxen_state::apxen(machine_config &config) m_pic[1]->out_int_callback().set(m_pic[0], FUNC(pic8259_device::ir2_w)); m_pic[1]->in_sp_callback().set_constant(0); - // video hardware - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_color(rgb_t::green()); - screen.set_size(800, 400); - screen.set_visarea(0, 800-1, 0, 400-1); - screen.set_refresh_hz(72); - screen.set_screen_update(FUNC(apxen_state::screen_update)); + XEN_DAISY(config, m_daisy); + m_daisy->set_daisy_config(xen_daisy_chain); + + PIT8253(config, m_pit, 0); + m_pit->set_clk<0>(2000000); + m_pit->out_handler<0>().set(m_sio, FUNC(z80sio_device::rxca_w)); + m_pit->set_clk<1>(2000000); + m_pit->out_handler<1>().set(m_sio, FUNC(z80sio_device::txca_w)); + m_pit->set_clk<2>(2000000); + m_pit->out_handler<2>().set(m_sio, FUNC(z80sio_device::rxtxcb_w)); + + Z8536(config, m_cio, 4000000); + m_cio->irq_wr_cb().set(m_pic[0], FUNC(pic8259_device::ir1_w)); + m_cio->pa_wr_cb().set(FUNC(apxen_state::cio_porta_w)); + m_cio->pb_wr_cb().set(FUNC(apxen_state::cio_portb_w)); + m_cio->pc_wr_cb().set(FUNC(apxen_state::cio_portc_w)); - PALETTE(config, m_mono_palette, palette_device::MONOCHROME_HIGHLIGHT); + Z80SIO(config, m_sio, 4000000); + m_sio->out_dtrb_callback().set(m_eeprom, FUNC(eeprom_serial_93cxx_device::di_write)); + m_sio->out_rtsb_callback().set(m_eeprom, FUNC(eeprom_serial_93cxx_device::cs_write)); + // channel a rs232, b keyboard + + MM58274C(config, "rtc", 32.768_kHz_XTAL); + + // video hardware + APRICOT_VIDEO_SLOT(config, m_video, apricot_video_cards, "mono"); + m_video->apvid_handler().set(FUNC(apxen_state::apvid_w)); - HD6845S(config, m_crtc, 24_MHz_XTAL / 20); // actually MB89321B - m_crtc->set_screen("screen"); - m_crtc->set_show_border_area(false); - m_crtc->set_char_width(10); - m_crtc->set_update_row_callback(FUNC(apxen_state::crtc_update_row)); + // sound hardware + SPEAKER(config, "mono").front_center(); + SN76489(config, "sn", 2000000).add_route(ALL_OUTPUTS, "mono", 1.0); } @@ -211,4 +467,4 @@ ROM_END //************************************************************************** // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1985, apxen, 0, 0, apxen, apxen, apxen_state, empty_init, "ACT", "Apricot XEN", MACHINE_IS_SKELETON ) +COMP( 1985, apxen, 0, 0, apxen, apxen, apxen_state, empty_init, "ACT", "Apricot XEN", MACHINE_NOT_WORKING ) -- cgit v1.2.3