sinclair/spec128.cpp: added DMA mod

This commit is contained in:
Andrei Holub 2025-02-18 19:27:15 -05:00
parent fb7c1fde64
commit 56f03a541a
7 changed files with 136 additions and 115 deletions

View File

@ -445,10 +445,9 @@ void z80dma_device::do_write()
break;
}
m_byte_counter++;
m_addressA += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1;
m_addressB += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1;
m_byte_counter++;
}
/****************************************************************************
@ -674,6 +673,7 @@ void z80dma_device::write(u8 data)
if (BIT(data, 6))
{
// UA858D doesn't do enable() in this case
enable();
}
}
@ -875,7 +875,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);
}
/****************************************************************************

View File

@ -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();
@ -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);
@ -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();
@ -288,13 +288,80 @@ 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_QUOTE)
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);
@ -302,17 +369,25 @@ void spectrum_128_state::machine_start()
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)
{
// mod_dma & 2 ? ZILOG : 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) {
@ -329,13 +404,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 )
@ -358,26 +433,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");
}

View File

@ -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);
@ -55,12 +59,16 @@ private:
void spectrum_128_io(address_map &map) ATTR_COLD;
void spectrum_128_mem(address_map &map) ATTR_COLD;
void spectrum_128_fetch(address_map &map) ATTR_COLD;
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

View File

@ -80,7 +80,7 @@ public:
, m_view7(*this, "mem_view7")
, m_copper(*this, "copper")
, m_ctc(*this, "ctc")
, m_dma(*this, "ndma")
, m_dma(*this, "dma")
, m_i2cmem(*this, "i2cmem")
, m_sdcard(*this, "sdcard")
, m_ay(*this, "ay%u", 0U)
@ -2256,7 +2256,7 @@ void specnext_state::nr_1a_ula_clip_y2_w(u8 data)
static const z80_daisy_config z80_daisy_chain[] =
{
{ "ndma" },
{ "dma" },
{ "ctc" },
{ nullptr }
};

View File

@ -39,27 +39,16 @@ specnext_dma_device::specnext_dma_device(const machine_config &mconfig, const ch
void specnext_dma_device::write(u8 data)
{
z80dma_device::write(data);
if (num_follow() == 0)
if (!m_ndma_mode && data == COMMAND_ENABLE_DMA && num_follow() == 0)
{
if ((data & 0x83) == 0x83) // WR6
{
switch (data)
{
case COMMAND_ENABLE_DMA:
m_byte_counter = 0;
break;
default:
break;
}
}
m_byte_counter = 0;
}
z80dma_device::write(data);
}
void specnext_dma_device::do_write()
{
if (m_dma_mode)
if (m_ndma_mode)
{
z80dma_device::do_write();
return;
@ -101,12 +90,12 @@ void specnext_dma_device::device_start()
{
z80dma_device::device_start();
save_item(NAME(m_dma_mode));
save_item(NAME(m_ndma_mode));
}
void specnext_dma_device::device_reset()
{
z80dma_device::device_reset();
m_dma_mode = 0;
m_ndma_mode = 0;
}

View File

@ -12,7 +12,7 @@ class specnext_dma_device : public z80dma_device
public:
specnext_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
void dma_mode_w(bool dma_mode) { m_dma_mode = dma_mode; }
void dma_mode_w(bool dma_mode) { m_ndma_mode = dma_mode; }
virtual void write(u8 data) override;
@ -23,7 +23,7 @@ protected:
virtual void do_write() override;
private:
bool m_dma_mode; // 0 = zxn dma, 1 = z80 dma
bool m_ndma_mode; // 0 = zxn dma, 1 = z80 dma
};
DECLARE_DEVICE_TYPE(SPECNEXT_DMA, specnext_dma_device)

View File

@ -580,25 +580,7 @@ void spectrum_state::spectrum_clone_io(address_map &map)
/* Input ports */
/****************************************************************************************************/
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
/*
/****************************************************************************************************
Spectrum keyboard is quite complicate to emulate. Each key can have 5 or 6 different functions, depending on which input mode we are in:
-------------------------------------------------------------------------------------------------------------------
@ -693,48 +675,6 @@ INPUT_PORTS_START( spectrum )
PORT_BIT(0x7f, IP_ACTIVE_LOW, IPT_UNUSED)
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_QUOTE)
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 )
INPUT_PORTS_END
/* Machine initialization */
void spectrum_state::init_spectrum()
{