Skip to content
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

z80dma.cpp: add derivateves ZILOG, UA858D, SPEC_NEXT #12658

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
30 changes: 25 additions & 5 deletions src/devices/machine/z80dma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ enum
****************************************************************************/
DEFINE_DEVICE_TYPE(Z80DMA, z80dma_device, "z80dma", "Z80 DMA Controller")

ALLOW_SAVE_TYPE(z80dma_device::dma_mode);

/****************************************************************************
* z80dma_device - constructor
****************************************************************************/
Expand All @@ -150,6 +152,7 @@ z80dma_device::z80dma_device(const machine_config &mconfig, device_type type, co
, m_out_mreq_cb(*this)
, m_in_iorq_cb(*this, 0)
, m_out_iorq_cb(*this)
, m_dma_mode(dma_mode::ZILOG)
{
}

Expand All @@ -162,6 +165,7 @@ void z80dma_device::device_start()
m_timer = timer_alloc(FUNC(z80dma_device::clock_w), this);

// register for state saving
save_item(NAME(m_dma_mode));
save_item(NAME(m_regs));
save_item(NAME(m_regs_follow));
save_item(NAME(m_num_follow));
Expand Down Expand Up @@ -425,6 +429,11 @@ void z80dma_device::do_search()

void z80dma_device::do_write()
{
if (m_byte_counter && m_dma_mode == dma_mode::SPEC_NEXT)
{
m_addressB += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1;
}

switch(TRANSFER_MODE)
angelosa marked this conversation as resolved.
Show resolved Hide resolved
{
case TM_TRANSFER:
Expand All @@ -445,10 +454,17 @@ void z80dma_device::do_write()
break;
}

m_addressA += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1;
m_addressB += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1;

m_byte_counter++;
m_addressA += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1;
if (m_dma_mode == dma_mode::SPEC_NEXT)
{
if ((m_byte_counter + 1) == m_count)
m_byte_counter++;
}
else
{
m_addressB += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1;
}
}

/****************************************************************************
Expand Down Expand Up @@ -670,7 +686,7 @@ void z80dma_device::write(u8 data)
if (data & 0x10)
m_regs_follow[m_num_follow++] = GET_REGNUM(MATCH_BYTE);

if (BIT(data, 6))
if (BIT(data, 6) && m_dma_mode != dma_mode::UA858D)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not quite convinced that the base z80dma_device has to know it has children here, perhaps moving this logic to ua858d_device and make specnext_dma_device a subclass of that should be the play here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not quite convinced that the base z80dma_device has to know it has children here, perhaps moving this logic to ua858d_device and make specnext_dma_device a subclass of that should be the play here?

I did this on purpose for Next case. It needs to switch type preserving existing state of registers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, in the context of if somebody else went their own route in subclassing the arch.
Notice that even a // NOTE: or a // FIXME: is okay for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Let's assume we keep specnextdma how it was before this commit.
Regarding spectrum which select chip based on mashine config... do I need to add slot for dma now? Or are the other way to do this?

{
enable();
}
Expand Down Expand Up @@ -762,6 +778,10 @@ void z80dma_device::write(u8 data)
break;
case COMMAND_ENABLE_DMA:
LOG("Z80DMA Enable DMA\n");
if (num_follow() == 0 && m_dma_mode == dma_mode::SPEC_NEXT)
{
m_byte_counter = 0;
}
enable();
break;
case COMMAND_READ_MASK_FOLLOWS:
Expand Down Expand Up @@ -875,7 +895,7 @@ TIMER_CALLBACK_MEMBER(z80dma_device::rdy_write_callback)
void z80dma_device::rdy_w(int state)
{
LOG("Z80DMA RDY: %d Active High: %d\n", state, READY_ACTIVE_HIGH);
machine().scheduler().synchronize(timer_expired_delegate(FUNC(z80dma_device::rdy_write_callback),this), state);
machine().scheduler().synchronize(timer_expired_delegate(FUNC(z80dma_device::rdy_write_callback), this), state);
}

/****************************************************************************
Expand Down
9 changes: 9 additions & 0 deletions src/devices/machine/z80dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ class z80dma_device : public device_t,
public device_z80daisy_interface
{
public:
enum class dma_mode : u8
{
ZILOG = 0,
UA858D = 1,
SPEC_NEXT = 2
};

// construction/destruction
z80dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);

Expand All @@ -60,6 +67,7 @@ class z80dma_device : public device_t,
auto in_iorq_callback() { return m_in_iorq_cb.bind(); }
auto out_iorq_callback() { return m_out_iorq_cb.bind(); }

void set_dma_mode(dma_mode dma_mode) { m_dma_mode = dma_mode; }
u8 read();
virtual void write(u8 data);

Expand Down Expand Up @@ -138,6 +146,7 @@ class z80dma_device : public device_t,

emu_timer *m_timer;

dma_mode m_dma_mode;
u16 m_regs[(6 << 3) + 1 + 1];
u8 m_num_follow;
u8 m_cur_follow;
Expand Down
137 changes: 111 additions & 26 deletions src/mame/sinclair/spec128.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ resulting mess can be seen in the F4 viewer display.
#include "formats/tzx_cas.h"


/****************************************************************************************************/
/* Spectrum 128 specific functions */

/****************************************************************************
* Spectrum 128 specific functions
****************************************************************************/
void spectrum_128_state::video_start()
{
spectrum_state::video_start();
Expand Down Expand Up @@ -221,18 +221,18 @@ void spectrum_128_state::spectrum_128_port_7ffd_w(offs_t offset, uint8_t data)
if (is_contended(offset)) content_early();
content_early(1);

/* D0-D2: RAM page located at 0x0c000-0x0ffff */
/* D3 - Screen select (screen 0 in ram page 5, screen 1 in ram page 7 */
/* D4 - ROM select - which rom paged into 0x0000-0x03fff */
/* D5 - Disable paging */
// D0-D2: RAM page located at 0x0c000-0x0ffff
// D3 - Screen select (screen 0 in ram page 5, screen 1 in ram page 7
// D4 - ROM select - which rom paged into 0x0000-0x03fff
// D5 - Disable paging

/* disable paging? */
// disable paging?
if (m_port_7ffd_data & 0x20) return;

/* store new state */
// store new state
m_port_7ffd_data = data;

/* update memory */
// update memory
spectrum_128_update_memory();

m_exp->iorq_w(offset | 1, data);
Expand All @@ -241,7 +241,7 @@ void spectrum_128_state::spectrum_128_port_7ffd_w(offs_t offset, uint8_t data)
void spectrum_128_state::spectrum_128_update_memory()
{
m_bank_rom[0]->set_entry(BIT(m_port_7ffd_data, 4));
/* select ram at 0x0c000-0x0ffff */
// select ram at 0x0c000-0x0ffff
m_bank_ram[3]->set_entry(m_port_7ffd_data & 0x07);

m_screen->update_now();
Expand Down Expand Up @@ -288,31 +288,107 @@ void spectrum_128_state::spectrum_128_fetch(address_map &map)
map(0x0000, 0xffff).r(FUNC(spectrum_128_state::spectrum_128_pre_opcode_fetch_r));
}

static INPUT_PORTS_START( spec_plus_joys )
PORT_START("JOY2") // 0xF7FE
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_8WAY PORT_PLAYER(2) PORT_CODE(JOYCODE_X_LEFT_SWITCH)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_8WAY PORT_PLAYER(2) PORT_CODE(JOYCODE_X_RIGHT_SWITCH)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_8WAY PORT_PLAYER(2) PORT_CODE(JOYCODE_Y_DOWN_SWITCH)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY PORT_PLAYER(2) PORT_CODE(JOYCODE_Y_UP_SWITCH)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON1)

PORT_START("JOY1") // 0xEFFE
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(1) PORT_CODE(JOYCODE_BUTTON1)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY PORT_PLAYER(1) PORT_CODE(JOYCODE_Y_UP_SWITCH)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_8WAY PORT_PLAYER(1) PORT_CODE(JOYCODE_Y_DOWN_SWITCH)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_8WAY PORT_PLAYER(1) PORT_CODE(JOYCODE_X_RIGHT_SWITCH)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_8WAY PORT_PLAYER(1) PORT_CODE(JOYCODE_X_LEFT_SWITCH)
INPUT_PORTS_END

/* These keys need not to be mapped in natural mode because Spectrum+ supports both these and the Spectrum sequences above.
Hence, we can simply keep using such sequences in natural keyboard emulation */
INPUT_PORTS_START( spec128 )
PORT_INCLUDE( spectrum )

PORT_START("PLUS0") // Spectrum+ Keys (Same as CAPS + 1-5)
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("EDIT") PORT_CODE(KEYCODE_INSERT)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("TRUE VID") PORT_CODE(KEYCODE_HOME)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("INV VID") PORT_CODE(KEYCODE_END)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Cursor Left") PORT_CODE(KEYCODE_LEFT)
PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED)

PORT_START("PLUS1") // Spectrum+ Keys (Same as CAPS + 6-0)
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("GRAPH") PORT_CODE(KEYCODE_LALT)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Cursor Right") PORT_CODE(KEYCODE_RIGHT)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Cursor Up") PORT_CODE(KEYCODE_UP)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Cursor Down") PORT_CODE(KEYCODE_DOWN)
PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED)

PORT_START("PLUS2") // Spectrum+ Keys (Same as CAPS + SPACE and CAPS + SYMBOL)
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("BREAK") PORT_CODE(KEYCODE_PAUSE)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("EXT MODE") PORT_CODE(KEYCODE_LCONTROL)
PORT_BIT(0xfc, IP_ACTIVE_LOW, IPT_UNUSED)

PORT_START("PLUS3") // Spectrum+ Keys (Same as SYMBOL SHIFT + O/P)
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\"") PORT_CODE(KEYCODE_F4)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(";") PORT_CODE(KEYCODE_COLON)
PORT_BIT(0xfc, IP_ACTIVE_LOW, IPT_UNUSED)

PORT_START("PLUS4") // Spectrum+ Keys (Same as SYMBOL SHIFT + N/M)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA)
PORT_BIT(0xf3, IP_ACTIVE_LOW, IPT_UNUSED)
INPUT_PORTS_END

INPUT_PORTS_START( spec_plus )
PORT_INCLUDE( spec128 )
PORT_INCLUDE( spec_plus_joys )

PORT_START("MOD_DMA")
PORT_CONFNAME( 0x03, 0x00, "DMA")
PORT_CONFSETTING( 0x00, DEF_STR( No ))
PORT_CONFSETTING( 0x01, "UA858D")
PORT_CONFSETTING( 0x03, "Zilog")
PORT_CONFNAME( 0x04, 0x00, "DMA Port") PORT_CONDITION("MOD_DMA", 0x01, EQUALS, 0x01)
PORT_CONFSETTING( 0x00, "11: MB02+")
PORT_CONFSETTING( 0x04, "107: DATAGEAR")
INPUT_PORTS_END

void spectrum_128_state::machine_start()
{
spectrum_state::machine_start();

save_item(NAME(m_port_7ffd_data));

/* rom 0 is 128K rom, rom 1 is 48 BASIC */
// rom 0 is 128K rom, rom 1 is 48 BASIC
memory_region *rom = memregion("maincpu");
m_bank_rom[0]->configure_entries(0, 2, rom->base() + 0x10000, 0x4000);

auto ram_entries = m_ram->size() / 0x4000;
for (auto i = 1; i < 4; i++)
m_bank_ram[i]->configure_entries(0, ram_entries, m_ram->pointer(), 0x4000);

m_bank_ram[1]->set_entry(ram_entries > 5 ? 5 : (ram_entries - 1)); /* Bank 5 is always in 0x4000 - 0x7fff */
m_bank_ram[2]->set_entry(2); /* Bank 2 is always in 0x8000 - 0xbfff */
m_bank_ram[1]->set_entry(ram_entries > 5 ? 5 : (ram_entries - 1)); // Bank 5 is always in 0x4000 - 0x7fff
m_bank_ram[2]->set_entry(2); // Bank 2 is always in 0x8000 - 0xbfff
}

void spectrum_128_state::machine_reset()
{
spectrum_state::machine_reset();

/* set initial ram config */
// set initial ram config
m_port_7ffd_data = 0;
spectrum_128_update_memory();

const u8 mod_dma = m_mod_dma.read_safe(0);
if (mod_dma & 1)
{
m_dma->set_dma_mode(mod_dma & 2 ? z80dma_device::dma_mode::ZILOG : z80dma_device::dma_mode::UA858D);

const u8 port = mod_dma & 4 ? 0x6b : 0x0b;
m_maincpu->space(AS_IO).install_readwrite_handler(port, port, 0, 0xff00, 0, read8smo_delegate(*m_dma, FUNC(z80dma_device::read)), write8smo_delegate(*m_dma, FUNC(z80dma_device::write)));
}
}

bool spectrum_128_state::is_vram_write(offs_t offset) {
Expand All @@ -329,13 +405,13 @@ bool spectrum_128_state::is_contended(offs_t offset) {

static const gfx_layout spectrum_charlayout =
{
8, 8, /* 8 x 8 characters */
96, /* 96 characters */
1, /* 1 bits per pixel */
{ 0 }, /* no bitplanes */
{STEP8(0, 1)}, /* x offsets */
{STEP8(0, 8)}, /* y offsets */
8*8 /* every char takes 8 bytes */
8, 8, // 8 x 8 characters
96, // 96 characters
1, // 1 bits per pixel
{ 0 }, // no bitplanes
{STEP8(0, 1)}, // x offsets
{STEP8(0, 8)}, // y offsets
8*8 // every char takes 8 bytes
};

static GFXDECODE_START( spec128 )
Expand All @@ -358,26 +434,35 @@ void spectrum_128_state::spectrum_128(machine_config &config)
m_maincpu->set_m1_map(&spectrum_128_state::spectrum_128_fetch);
m_maincpu->set_vblank_int("screen", FUNC(spectrum_128_state::spec_interrupt));
m_maincpu->nomreq_cb().set(FUNC(spectrum_128_state::spectrum_nomreq));
m_maincpu->busack_cb().set(m_dma, FUNC(z80dma_device::bai_w));

config.set_maximum_quantum(attotime::from_hz(60));

/* video hardware */
Z80DMA(config, m_dma, X1_128_SINCLAIR / 10);
m_dma->out_busreq_callback().set_inputline(m_maincpu, Z80_INPUT_LINE_BUSRQ);
m_dma->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
m_dma->in_mreq_callback().set([this](offs_t offset) { return m_maincpu->space(AS_PROGRAM).read_byte(offset); });
m_dma->out_mreq_callback().set([this](offs_t offset, u8 data) { m_maincpu->space(AS_PROGRAM).write_byte(offset, data); });
m_dma->in_iorq_callback().set([this](offs_t offset) { return m_maincpu->space(AS_IO).read_byte(offset); });
m_dma->out_iorq_callback().set([this](offs_t offset, u8 data) { m_maincpu->space(AS_IO).write_byte(offset, data); });

// video hardware
rectangle visarea = { get_screen_area().left() - SPEC_LEFT_BORDER, get_screen_area().right() + SPEC_RIGHT_BORDER,
get_screen_area().top() - SPEC_TOP_BORDER, get_screen_area().bottom() + SPEC_BOTTOM_BORDER };
m_screen->set_raw(X1_128_SINCLAIR / 5, SPEC128_CYCLES_PER_LINE * 2, SPEC128_UNSEEN_LINES + SPEC_SCREEN_HEIGHT, visarea);

subdevice<gfxdecode_device>("gfxdecode")->set_info(spec128);

/* sound hardware */
// sound hardware
AY8912(config, "ay8912", X1_128_SINCLAIR / 20).add_route(ALL_OUTPUTS, "mono", 0.25);

/* expansion port */
// expansion port
SPECTRUM_EXPANSION_SLOT(config.replace(), m_exp, spec128_expansion_devices, nullptr);
m_exp->irq_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
m_exp->nmi_handler().set_inputline(m_maincpu, INPUT_LINE_NMI);
m_exp->fb_r_handler().set(FUNC(spectrum_128_state::floating_bus_r));

/* internal ram */
// internal ram
m_ram->set_default_size("128K");
}

Expand Down
16 changes: 12 additions & 4 deletions src/mame/sinclair/spec128.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@

#include "spectrum.h"

#include "machine/z80dma.h"


class spectrum_128_state : public spectrum_state
{
public:
spectrum_128_state(const machine_config &mconfig, device_type type, const char *tag) :
spectrum_state(mconfig, type, tag),
m_bank_rom(*this, "bank_rom%u", 0U),
m_bank_ram(*this, "bank_ram%u", 0U)
spectrum_state(mconfig, type, tag)
, m_bank_rom(*this, "bank_rom%u", 0U)
, m_bank_ram(*this, "bank_ram%u", 0U)
, m_dma(*this, "dma_ext")
, m_mod_dma(*this, "MOD_DMA")
{ }

void spectrum_128(machine_config &config);
Expand Down Expand Up @@ -55,12 +59,16 @@ class spectrum_128_state : public spectrum_state
void spectrum_128_io(address_map &map);
void spectrum_128_mem(address_map &map);
void spectrum_128_fetch(address_map &map);

optional_device<z80dma_device> m_dma;

optional_ioport m_mod_dma;
};

#define X1_128_AMSTRAD 35'469'000 // Main clock (Amstrad 128K model, +2A?)
#define X1_128_SINCLAIR 35.469_MHz_XTAL // Main clock (Sinclair 128K model)

/* 128K machines take an extra 4 cycles per scan line - add this to retrace */
// 128K machines take an extra 4 cycles per scan line - add this to retrace
#define SPEC128_UNSEEN_LINES 15
#define SPEC128_RETRACE_CYCLES 52
#define SPEC128_CYCLES_PER_LINE 228
Expand Down
Loading
Loading