lastfght.cpp, subsino2.cpp: Create new device for I/O ports

This commit is contained in:
AJR 2023-05-14 07:58:08 -04:00
parent 4e0876c1e0
commit 43c8466fed
4 changed files with 679 additions and 563 deletions

View File

@ -70,6 +70,7 @@ Notes:
*********************************************************************************************************************/
#include "emu.h"
#include "subsino_io.h"
#include "cpu/h8/h83048.h"
#include "machine/ds2430a.h"
#include "machine/nvram.h"
@ -90,8 +91,7 @@ public:
m_maincpu(*this,"maincpu"),
m_eeprom(*this, "eeprom"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_inputs(*this, "IN%u", 0U)
m_palette(*this, "palette")
{ }
void lastfght(machine_config &config);
@ -115,11 +115,9 @@ private:
void sd_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void blit_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void dest_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t c00000_r();
uint16_t c00002_r();
uint16_t c00004_r();
uint16_t c00006_r();
void c00006_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint8_t c00000_r();
uint8_t c00002_r();
void c00007_w(uint8_t data);
uint16_t sound_r();
void sound_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
@ -148,15 +146,11 @@ private:
int m_view_roms = 0;
#endif
/* misc */
uint16_t m_c00006 = 0;
/* devices */
required_device<cpu_device> m_maincpu;
required_device<ds2430a_device> m_eeprom;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_ioport_array<3> m_inputs;
};
@ -366,41 +360,22 @@ void lastfght_state::dest_w(offs_t offset, uint16_t data, uint16_t mem_mask)
m_dest ^= 1;
}
uint16_t lastfght_state::c00000_r()
uint8_t lastfght_state::c00000_r()
{
// high byte:
// bit 7 = blitter busy
// bit 6 = blitter?
return 0x4000;
return 0x40;
}
uint16_t lastfght_state::c00002_r()
uint8_t lastfght_state::c00002_r()
{
// high byte:
// mask 0x1c: from sound?
return (machine().rand() & 0x1c00) | m_inputs[0]->read();
return (machine().rand() & 0x1c) | 0x03;
}
uint16_t lastfght_state::c00004_r()
void lastfght_state::c00007_w(uint8_t data)
{
return m_inputs[1]->read();
}
uint16_t lastfght_state::c00006_r()
{
// low byte:
// bit 7 = protection?
// bit 5 = blitter?
return (m_c00006 & 0x005f) | (m_inputs[2]->read() & 0xffa0);
}
void lastfght_state::c00006_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_c00006);
// popmessage("%04x", m_c00006);
m_eeprom->data_w(!BIT(m_c00006, 6));
m_eeprom->data_w(!BIT(data, 6));
}
uint16_t lastfght_state::sound_r()
@ -448,10 +423,7 @@ void lastfght_state::lastfght_map(address_map &map)
map(0x800014, 0x800015).w(FUNC(lastfght_state::dest_w));
map(0xc00000, 0xc00001).r(FUNC(lastfght_state::c00000_r));
map(0xc00002, 0xc00003).r(FUNC(lastfght_state::c00002_r));
map(0xc00004, 0xc00005).r(FUNC(lastfght_state::c00004_r));
map(0xc00006, 0xc00007).rw(FUNC(lastfght_state::c00006_r), FUNC(lastfght_state::c00006_w));
map(0xc00000, 0xc0001f).rw("io", FUNC(ss9802_device::read), FUNC(ss9802_device::write));
}
void lastfght_state::ramdac_map(address_map &map)
@ -464,57 +436,50 @@ void lastfght_state::ramdac_map(address_map &map)
***************************************************************************/
static INPUT_PORTS_START( lastfght )
PORT_START("IN0") /* IN0 - c00002&3 */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_SERVICE1 )
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F1)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_SERVICE )
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F1)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0400, IP_ACTIVE_HIGH,IPT_CUSTOM )
PORT_BIT( 0x0800, IP_ACTIVE_HIGH,IPT_CUSTOM )
PORT_BIT( 0x1000, IP_ACTIVE_HIGH,IPT_CUSTOM )
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_START("IN1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_START("IN1") /* IN1 - c00004&5 */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON2 )
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_UP )
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN )
PORT_START("IN2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN )
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT )
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT )
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_START("IN3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
PORT_START("IN2") /* IN2 - c00006&7 */
PORT_START("PROT")
PORT_BIT( 0x005f, IP_ACTIVE_HIGH, IPT_UNUSED ) // outputs
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNKNOWN ) // blitter?
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("eeprom", ds2430a_device, data_r)
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
INPUT_PORTS_END
@ -538,7 +503,6 @@ void lastfght_state::machine_start()
save_item(NAME(m_y));
save_item(NAME(m_w));
save_item(NAME(m_h));
save_item(NAME(m_c00006));
}
void lastfght_state::machine_reset()
@ -557,7 +521,6 @@ void lastfght_state::machine_reset()
m_y = 0;
m_w = 0;
m_h = 0;
m_c00006 = 0;
}
void lastfght_state::lastfght(machine_config &config)
@ -569,6 +532,16 @@ void lastfght_state::lastfght(machine_config &config)
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
ss9802_device &io(SS9802(config, "io"));
io.in_port_callback<0>().set(FUNC(lastfght_state::c00000_r));
io.in_port_callback<2>().set(FUNC(lastfght_state::c00002_r));
io.in_port_callback<3>().set_ioport("IN0");
io.in_port_callback<4>().set_ioport("IN1");
io.in_port_callback<5>().set_ioport("IN2");
io.in_port_callback<6>().set_ioport("IN3");
io.in_port_callback<7>().set_ioport("PROT");
io.out_port_callback<7>().set(FUNC(lastfght_state::c00007_w));
DS2430A(config, m_eeprom).set_timing_scale(0.16);
/* video hardware */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,179 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
Subsino SS9602 & SS9802 I/O emulation
These are QFP100 gate arrays custom-programmed as GPI/O port
expanders. Outputs are ULN2003A compatible; inputs may be 74LS244
buffered due to electrical requirements. Much like Sega 315-5296,
some weak protection is provided by making several bytes spell out
the game manufacturer's name.
One port on each IC does not appear to have a separate direction
register, and often has the same value written into both nibbles.
The implementation here is a bit conjectural.
TBD: are the separate direction registers write-only, or can they
be read back?
**********************************************************************/
#include "emu.h"
#include "subsino_io.h"
#define LOG_SETUP (1U << 1)
//#define VERBOSE (LOG_SETUP)
#include "logmacro.h"
// device type definitions
DEFINE_DEVICE_TYPE(SS9602, ss9602_device, "ss9602", "Subsino SS9602 I/O")
DEFINE_DEVICE_TYPE(SS9802, ss9802_device, "ss9802", "Subsino SS9802 I/O")
subsino_io_device::subsino_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
, m_in_port_callback(*this)
, m_out_port_callback(*this)
, m_port_data{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
, m_port_dir{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
{
}
ss9602_device::ss9602_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: subsino_io_device(mconfig, SS9602, tag, owner, clock)
{
}
ss9802_device::ss9802_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: subsino_io_device(mconfig, SS9802, tag, owner, clock)
{
}
void subsino_io_device::device_resolve_objects()
{
// resolve read/write callbacks
m_in_port_callback.resolve_all();
m_out_port_callback.resolve_all_safe();
}
void subsino_io_device::device_start()
{
// save state
save_item(NAME(m_port_data));
save_item(NAME(m_port_dir));
}
void subsino_io_device::device_reset()
{
std::fill(std::begin(m_port_data), std::end(m_port_data), 0);
std::fill(std::begin(m_port_dir), std::end(m_port_dir), 0);
}
u8 subsino_io_device::read_port_data(unsigned port)
{
const u8 dir = m_port_dir[port];
u8 data = m_port_data[port] & dir;
if (dir != 0xff)
{
if (!m_in_port_callback[port].isnull())
data |= m_in_port_callback[port]() & ~dir;
else if (!machine().side_effects_disabled())
logerror("%s: Reading from undefined P%u input\n", machine().describe_context(), port);
}
return data;
}
void subsino_io_device::write_port_data(unsigned port, u8 data)
{
const u8 dir = m_port_dir[port];
if ((dir & (data ^ m_port_data[port])) != 0)
{
LOG("%s: Writing %02Xh to P%u output\n", machine().describe_context(), data, port);
m_out_port_callback[port](data & dir);
}
m_port_data[port] = data;
}
void subsino_io_device::write_port_dir(unsigned port, u8 dir)
{
LOGMASKED(LOG_SETUP, "%s: Writing %02Xh to P%u direction register (previous data = %02Xh)\n", machine().describe_context(), dir, port, m_port_data[port]);
if (m_port_dir[port] != dir)
{
m_port_dir[port] = dir;
m_out_port_callback[port](m_port_data[port] & dir);
}
}
void subsino_io_device::write_port_data_and_dir(unsigned port, u8 data, u8 dir)
{
if (m_port_dir[port] != dir || (dir & (data ^ m_port_data[port])) != 0)
{
LOG("%s: Writing %02Xh & %02Xh to P%u output\n", machine().describe_context(), data, dir, port);
m_port_dir[port] = dir;
m_out_port_callback[port](data & dir);
}
m_port_data[port] = data;
}
u8 ss9602_device::read(offs_t offset)
{
offset &= 0x1f;
if (offset <= 0x08)
return read_port_data(offset);
else if (offset == 0x12)
return read_port_data(9) & 0x0f;
else if (offset >= 0x18 && offset <= 0x1e)
return "SUBSION"[offset];
else
{
if (!machine().side_effects_disabled())
logerror("%s: Reading data from unknown/write-only register %02Xh\n", machine().describe_context(), offset);
return 0;
}
}
void ss9602_device::write(offs_t offset, u8 data)
{
offset &= 0x1f;
if (offset <= 0x08)
write_port_data(offset, data);
else if (offset <= 0x11)
write_port_dir(offset - 0x09, data);
else if (offset == 0x12)
write_port_data_and_dir(9, data & 0x0f, (data & 0xf0) >> 4);
else if (offset == 0x13)
LOGMASKED(LOG_SETUP, "%s: Writing %02Xh to reset register\n", machine().describe_context(), data);
else
logerror("%s: Writing %02Xh to unknown register %02Xh\n", machine().describe_context(), data, offset);
}
u8 ss9802_device::read(offs_t offset)
{
offset &= 0x1f;
if (offset == 0x00)
return (read_port_data(0) & 0xf0) | (m_port_dir[0] >> 4);
else if (offset <= 0x09)
return read_port_data(offset);
else if (offset >= 0x13 && offset <= 0x19)
return "SUBSINO"[offset]; // for xtrain
else
{
if (!machine().side_effects_disabled())
logerror("%s: Reading data from unknown/write-only register %02Xh\n", machine().describe_context(), offset);
return 0;
}
}
void ss9802_device::write(offs_t offset, u8 data)
{
offset &= 0x1f;
if (offset == 0x00)
write_port_data_and_dir(0, data & 0xf0, (data & 0x0f) << 4);
else if (offset <= 0x09)
write_port_data(offset, data);
else if (offset <= 0x12)
write_port_dir(offset - 0x09, data);
else
logerror("%s: Writing %02Xh to unknown register %02Xh\n", machine().describe_context(), data, offset);
}

View File

@ -0,0 +1,65 @@
// license:BSD-3-Clause
// copyright-holders:AJR
#ifndef MAME_SUBSINO_SUBSINO_IO_H
#define MAME_SUBSINO_SUBSINO_IO_H
#pragma once
class subsino_io_device : public device_t
{
public:
// callback configuration
template <int P> auto in_port_callback() { return m_in_port_callback[P].bind(); }
template <int P> auto out_port_callback() { return m_out_port_callback[P].bind(); }
protected:
subsino_io_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
// device_t overrides
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
// port read/write helpers
u8 read_port_data(unsigned port);
void write_port_data(unsigned port, u8 data);
void write_port_dir(unsigned port, u8 dir);
void write_port_data_and_dir(unsigned port, u8 data, u8 dir);
// callback objects
devcb_read8::array<10> m_in_port_callback;
devcb_write8::array<10> m_out_port_callback;
// internal state
u8 m_port_data[10];
u8 m_port_dir[10];
};
class ss9602_device : public subsino_io_device
{
public:
// device type constructor
ss9602_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
// CPU read/write handlers
u8 read(offs_t offset);
void write(offs_t offset, u8 data);
};
class ss9802_device : public subsino_io_device
{
public:
// device type constructor
ss9802_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
// CPU read/write handlers
u8 read(offs_t offset);
void write(offs_t offset, u8 data);
};
// device type declarations
DECLARE_DEVICE_TYPE(SS9602, ss9602_device)
DECLARE_DEVICE_TYPE(SS9802, ss9802_device)
#endif // MAME_SUBSINO_SUBSINO_IO_H