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
This commit is contained in:
Dirk Best 2021-08-04 19:29:32 +02:00
parent 68dbd42a24
commit 1e7d83cc4b
9 changed files with 897 additions and 45 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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<uint16_t[]>(0x8000);
// init gfxdecode
m_gfxdecode->set_gfx(0, std::make_unique<gfx_element>(m_palette, apricot_charlayout, reinterpret_cast<uint8_t *>(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);
}

View File

@ -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<hd6845s_device> m_crtc;
required_device<palette_device> m_palette;
required_device<gfxdecode_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<uint16_t[]> 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

View File

@ -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<device_apricot_video_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<apricot_video_slot_device *>(device.owner());
}
//-------------------------------------------------
// ~device_apricot_video_interface - destructor
//-------------------------------------------------
device_apricot_video_interface::~device_apricot_video_interface()
{
}

View File

@ -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<device_apricot_video_interface>
{
public:
// construction/destruction
template <typename T>
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

View File

@ -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<i80286_cpu_device> m_maincpu;
required_device<address_map_bank_device> m_mem;
required_device<address_map_bank_device> m_io;
required_device<eeprom_serial_93cxx_device> m_eeprom;
required_device_array<pic8259_device, 2> m_pic;
required_device<hd6845s_device> m_crtc;
required_device<palette_device> m_mono_palette;
required_device<xen_daisy_device> m_daisy;
required_device<pit8253_device> m_pit;
required_device<z8536_device> m_cio;
required_device<z80sio_device> m_sio;
required_device<apricot_video_slot_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 )
{
return 0;
m_apvid = bool(state);
}
MC6845_UPDATE_ROW( apxen_state::crtc_update_row )
//**************************************************************************
// 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)
{
if (!m_video->io_w(offset, data, mem_mask))
m_io->write16(offset, data, mem_mask);
}
//**************************************************************************
// 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);
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));
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
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));
APRICOT_VIDEO_SLOT(config, m_video, apricot_video_cards, "mono");
m_video->apvid_handler().set(FUNC(apxen_state::apvid_w));
PALETTE(config, m_mono_palette, palette_device::MONOCHROME_HIGHLIGHT);
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 )