Skip to content

z80dma.cpp: Added UA858D variant; sinclair/spectrum.cpp: Added configurable DMA slot #13879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions scripts/src/bus.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4984,10 +4984,10 @@ end

---------------------------------------------------
--
--@src/devices/bus/spectrum/ay/slot.h,BUSES["AY_SLOT"] = true
--@src/devices/bus/spectrum/ay/slot.h,BUSES["SPECTRUM_AY"] = true
---------------------------------------------------

if (BUSES["AY_SLOT"]~=null) then
if (BUSES["SPECTRUM_AY"]~=null) then
files {
MAME_DIR .. "src/devices/bus/spectrum/ay/slot.cpp",
MAME_DIR .. "src/devices/bus/spectrum/ay/slot.h",
Expand All @@ -4998,10 +4998,24 @@ end

---------------------------------------------------
--
--@src/devices/bus/spectrum/zxbus/bus.h,BUSES["ZXBUS"] = true
--@src/devices/bus/spectrum/dma/slot.h,BUSES["SPECTRUM_DMA"] = true
---------------------------------------------------

if (BUSES["ZXBUS"]~=null) then
if (BUSES["SPECTRUM_DMA"]~=null) then
files {
MAME_DIR .. "src/devices/bus/spectrum/dma/slot.cpp",
MAME_DIR .. "src/devices/bus/spectrum/dma/slot.h",
MAME_DIR .. "src/devices/bus/spectrum/dma/cards.cpp",
MAME_DIR .. "src/devices/bus/spectrum/dma/cards.h",
}
end

---------------------------------------------------
--
--@src/devices/bus/spectrum/zxbus/bus.h,BUSES["SPECTRUM_ZXBUS"] = true
---------------------------------------------------

if (BUSES["SPECTRUM_ZXBUS"]~=null) then
files {
MAME_DIR .. "src/devices/bus/spectrum/zxbus/bus.cpp",
MAME_DIR .. "src/devices/bus/spectrum/zxbus/bus.h",
Expand Down
113 changes: 113 additions & 0 deletions src/devices/bus/spectrum/dma/cards.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub

#include "emu.h"
#include "cards.h"

namespace bus::spectrum::dma_slot {

namespace {

/**********************************************************************
DATAGEAR: UA858D, Port 0x6b
**********************************************************************/
class datagear_device : public dma_device
{
public:
datagear_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: dma_device(mconfig, DMA_SLOT_DATAGEAR, tag, owner, clock)
{ }

protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
};

void datagear_device::device_add_mconfig(machine_config &config)
{
UA858D(config, m_dma, clock());
m_dma_port = 0x6b;

dma_device::device_add_mconfig(config);
}


/**********************************************************************
DATAGEAR: ZILOG, Port 0x6b
**********************************************************************/
class datagear_zilog_device : public dma_device
{
public:
datagear_zilog_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: dma_device(mconfig, DMA_SLOT_DATAGEAR_ZILOG, tag, owner, clock)
{ }

protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
};


/**********************************************************************
DATAGEAR: UA858D, Port 0x6b
**********************************************************************/
void datagear_zilog_device::device_add_mconfig(machine_config &config)
{
Z80DMA(config, m_dma, clock());
m_dma_port = 0x6b;

dma_device::device_add_mconfig(config);
}


/**********************************************************************
MB02+: UA858D, Port 0x0b
**********************************************************************/
class mb02p_device : public dma_device
{
public:
mb02p_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: dma_device(mconfig, DMA_SLOT_MB02P, tag, owner, clock)
{ }

protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
};

void mb02p_device::device_add_mconfig(machine_config &config)
{
UA858D(config, m_dma, clock());
m_dma_port = 0x0b;

dma_device::device_add_mconfig(config);
}


/**********************************************************************
MB02+: ZILOG, Port 0x0b
**********************************************************************/
class mb02p_zilog_device : public dma_device
{
public:
mb02p_zilog_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: dma_device(mconfig, DMA_SLOT_MB02P_ZILOG, tag, owner, clock)
{ }

protected:
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
};

void mb02p_zilog_device::device_add_mconfig(machine_config &config)
{
Z80DMA(config, m_dma, clock());
m_dma_port = 0x0b;

dma_device::device_add_mconfig(config);
}

} // anonymous namespace

} // namespace bus::spectrum::dma_slot

DEFINE_DEVICE_TYPE_PRIVATE(DMA_SLOT_DATAGEAR, device_dma_card_interface, bus::spectrum::dma_slot::datagear_device, "dma_datagear", "DATEGEAR 107(#6b) UA858D")
DEFINE_DEVICE_TYPE_PRIVATE(DMA_SLOT_DATAGEAR_ZILOG, device_dma_card_interface, bus::spectrum::dma_slot::datagear_zilog_device, "dma_datagear_zilog", "DATEGEAR 107(#6b) ZILOG")
DEFINE_DEVICE_TYPE_PRIVATE(DMA_SLOT_MB02P, device_dma_card_interface, bus::spectrum::dma_slot::mb02p_device, "dma_mb02p", "MB02+ 11(#0b) UA858D")
DEFINE_DEVICE_TYPE_PRIVATE(DMA_SLOT_MB02P_ZILOG, device_dma_card_interface, bus::spectrum::dma_slot::mb02p_zilog_device, "dma_mb02p_zilog", "MB02+ 11(#0b) ZILOG")
17 changes: 17 additions & 0 deletions src/devices/bus/spectrum/dma/cards.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub

#ifndef MAME_BUS_SPECTRUM_DMA_CARDS_H
#define MAME_BUS_SPECTRUM_DMA_CARDS_H

#pragma once

#include "slot.h"


DECLARE_DEVICE_TYPE(DMA_SLOT_DATAGEAR, device_dma_card_interface)
DECLARE_DEVICE_TYPE(DMA_SLOT_DATAGEAR_ZILOG, device_dma_card_interface)
DECLARE_DEVICE_TYPE(DMA_SLOT_MB02P, device_dma_card_interface)
DECLARE_DEVICE_TYPE(DMA_SLOT_MB02P_ZILOG, device_dma_card_interface)

#endif // MAME_BUS_SPECTRUM_DMA_CARDS_H
118 changes: 118 additions & 0 deletions src/devices/bus/spectrum/dma/slot.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub
/**********************************************************************
DMA Slot for ZX Spectrum

DMA Controller mod is available in two variants:
- Data-Gear: uses I/O port 107 (0x6B)
- MB-02+: uses I/O port 11 (0x0B)

The most commonly used implementation was based on the UA858D chip, which differs in behavior from
the original Zilog DMA controller.
For example, several source code examples published in Czech magazines were written for the UA858D
and did not account for differences in control logic?such as the lack of automatic transfer enable
via WR3, a feature that is present in the Zilog chip.
As a result, there are two versions of the "DMA DEMO LEVEL 3" by Busysoft:
- The original, compatible with the UA858D
- A fixed version, modified to support the Zilog DMA controller

ref: https://web.archive.org/web/20250524155336/https://velesoft.speccy.cz/data-gear.htm

**********************************************************************/

#include "emu.h"
#include "slot.h"

DEFINE_DEVICE_TYPE(DMA_SLOT, dma_slot_device, "dma_slot", "Spectrum DMA Slot")

dma_slot_device::dma_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, DMA_SLOT, tag, owner, clock)
, device_single_card_slot_interface<device_dma_card_interface>(mconfig, *this)
, m_io(*this, finder_base::DUMMY_TAG, -1)
, m_out_busreq_cb(*this)
, m_out_int_cb(*this)
, m_in_mreq_cb(*this, 0)
, m_out_mreq_cb(*this)
, m_in_iorq_cb(*this, 0)
, m_out_iorq_cb(*this)
, m_card(nullptr)
{
}

dma_slot_device::~dma_slot_device()
{
}

void dma_slot_device::device_start()
{
m_card = get_card_device();
}

void dma_slot_device::busreq_w(int state) { m_out_busreq_cb(state); }
void dma_slot_device::int_w(int state) { m_out_int_cb(state); }
void dma_slot_device::mreq_w(int state) { m_out_mreq_cb(state); }
u8 dma_slot_device::mreq_r(offs_t offset) { return m_in_mreq_cb(offset); }
void dma_slot_device::iorq_w(int state) { m_out_iorq_cb(state); }
u8 dma_slot_device::iorq_r(offs_t offset) { return m_in_iorq_cb(offset); }
void dma_slot_device::bai_w(int state) { if(m_card) m_card->bai_w(state); };


device_dma_card_interface::device_dma_card_interface(const machine_config &mconfig, device_t &device)
: device_interface(device, "dma")
{
m_slot = dynamic_cast<dma_slot_device *>(device.owner());
}

device_dma_card_interface::~device_dma_card_interface()
{
}


dma_device::dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
, device_dma_card_interface(mconfig, *this)
, m_dma(*this, "dma")
, m_dma_port(0)
{
}

void dma_device::bai_w(int state)
{
m_dma->bai_w(state);
}

void dma_device::device_validity_check(validity_checker &valid) const
{
if (!m_dma_port)
osd_printf_error("DMA port is not configured\n");
}

void dma_device::device_add_mconfig(machine_config &config)
{
m_dma->out_busreq_callback().set([this](int state) { m_slot->busreq_w(state); } );
m_dma->out_int_callback().set([this](int state) { m_slot->int_w(state); } );
m_dma->in_mreq_callback().set([this](offs_t offset) { return m_slot->mreq_r(offset); });
m_dma->out_mreq_callback().set([this](int state) { m_slot->mreq_w(state); } );
m_dma->in_iorq_callback().set([this](offs_t offset) { return m_slot->iorq_r(offset); });
m_dma->out_iorq_callback().set([this](int state) { m_slot->iorq_w(state); } );
}


void dma_device::device_start()
{
m_slot->io().install_readwrite_handler(m_dma_port, m_dma_port, 0, 0xff00, 0, emu::rw_delegate(*m_dma, FUNC(z80dma_device::read)), emu::rw_delegate(*m_dma, FUNC(z80dma_device::write)));
}


#include "cards.h"

template class device_finder<device_dma_card_interface, false>;
template class device_finder<device_dma_card_interface, true>;

void default_dma_slot_devices(device_slot_interface &device)
{
device.option_add("datagear", DMA_SLOT_DATAGEAR);
device.option_add("datagear_zilog", DMA_SLOT_DATAGEAR_ZILOG);
device.option_add("mb02p", DMA_SLOT_MB02P);
device.option_add("mb02p_zilog", DMA_SLOT_MB02P_ZILOG);
}
101 changes: 101 additions & 0 deletions src/devices/bus/spectrum/dma/slot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub
#ifndef MAME_BUS_SPECTRUM_DMA_SLOT_H
#define MAME_BUS_SPECTRUM_DMA_SLOT_H

#include "emu.h"
#include "osdcomm.h"
#pragma once

#include "cpu/z80/z80.h"
#include "machine/z80dma.h"

class device_dma_card_interface;

class dma_slot_device : public device_t
, public device_single_card_slot_interface<device_dma_card_interface>
{
friend class device_dma_card_interface;

public:
dma_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
template <typename T>
dma_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&opts, const char *dflt)
: dma_slot_device(mconfig, tag, owner, clock)
{
option_reset();
opts(*this);
set_default_option(dflt);
set_fixed(false);
}
virtual ~dma_slot_device();

template <typename T> void set_io_space(T &&tag, int spacenum) { m_io.set_tag(std::forward<T>(tag), spacenum); }

auto out_busreq_callback() { return m_out_busreq_cb.bind(); }
auto out_int_callback() { return m_out_int_cb.bind(); }
auto in_mreq_callback() { return m_in_mreq_cb.bind(); }
auto out_mreq_callback() { return m_out_mreq_cb.bind(); }
auto in_iorq_callback() { return m_in_iorq_cb.bind(); }
auto out_iorq_callback() { return m_out_iorq_cb.bind(); }

void busreq_w(int state);
void int_w(int state);
void mreq_w(int state);
u8 mreq_r(offs_t offset);
void iorq_w(int state);
u8 iorq_r(offs_t offset);

void bai_w(int state);

address_space &io() const { return *m_io; }

protected:
virtual void device_start() override ATTR_COLD;

required_address_space m_io;

devcb_write_line m_out_busreq_cb;
devcb_write_line m_out_int_cb;
devcb_read8 m_in_mreq_cb;
devcb_write8 m_out_mreq_cb;
devcb_read8 m_in_iorq_cb;
devcb_write8 m_out_iorq_cb;

device_dma_card_interface *m_card;
};

class device_dma_card_interface : public device_interface
{
public:
virtual ~device_dma_card_interface();

virtual void bai_w(int state) {};

protected:
device_dma_card_interface(const machine_config &mconfig, device_t &device);

dma_slot_device *m_slot;
};

class dma_device : public device_t, public device_dma_card_interface
{
public:
virtual void bai_w(int state) override;

protected:
dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);

virtual void device_validity_check(validity_checker &valid) const override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
virtual void device_start() override ATTR_COLD;

required_device<z80dma_device> m_dma;
u8 m_dma_port;
};

DECLARE_DEVICE_TYPE(DMA_SLOT, dma_slot_device)

void default_dma_slot_devices(device_slot_interface &device);

#endif // MAME_BUS_SPECTRUM_DMA_SLOT_H
Loading
Loading