mirror of
https://github.com/holub/mame
synced 2025-04-19 23:12:11 +03:00
mos6530: Rewritten to support time travel. [Curt Coder]
This commit is contained in:
parent
d8795fe43c
commit
274078636e
@ -1385,6 +1385,7 @@ end
|
||||
if (MACHINES["MIOT6530"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/emu/machine/mos6530.c",
|
||||
MAME_DIR .. "src/emu/machine/mos6530n.c",
|
||||
}
|
||||
end
|
||||
|
||||
|
596
src/emu/machine/mos6530n.c
Normal file
596
src/emu/machine/mos6530n.c
Normal file
@ -0,0 +1,596 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Curt Coder
|
||||
/**********************************************************************
|
||||
|
||||
MOS Technology 6530 Memory, I/O, Timer Array emulation
|
||||
|
||||
Copyright MESS Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "mos6530n.h"
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// MACROS / CONSTANTS
|
||||
//**************************************************************************
|
||||
|
||||
#define LOG 0
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
const device_type MOS6530n = &device_creator<mos6530_t>;
|
||||
|
||||
|
||||
DEVICE_ADDRESS_MAP_START( rom_map, 8, mos6530_t )
|
||||
AM_RANGE(0x000, 0x3ff) AM_READ(rom_r)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
DEVICE_ADDRESS_MAP_START( ram_map, 8, mos6530_t )
|
||||
AM_RANGE(0x00, 0x3f) AM_READWRITE(ram_r, ram_w)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
DEVICE_ADDRESS_MAP_START( io_map, 8, mos6530_t )
|
||||
AM_RANGE(0x00, 0x00) AM_READWRITE(pa_data_r, pa_data_w)
|
||||
AM_RANGE(0x01, 0x01) AM_READWRITE(pa_ddr_r, pa_ddr_w)
|
||||
AM_RANGE(0x02, 0x02) AM_READWRITE(pb_data_r, pb_data_w)
|
||||
AM_RANGE(0x03, 0x03) AM_READWRITE(pb_ddr_r, pb_ddr_w)
|
||||
AM_RANGE(0x04, 0x0f) AM_READ(timer_r)
|
||||
AM_RANGE(0x04, 0x0f) AM_WRITE(timer_w)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// mos6530_t - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
mos6530_t::mos6530_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
device_t(mconfig, MOS6530n, "MOS6530n", tag, owner, clock, "mos6530n", __FILE__),
|
||||
m_ram(*this),
|
||||
m_irq_cb(*this),
|
||||
m_in_pa_cb(*this),
|
||||
m_out_pa_cb(*this),
|
||||
m_in_pb_cb(*this),
|
||||
m_out_pb_cb(*this),
|
||||
m_in_pa0_cb(*this),
|
||||
m_in_pa1_cb(*this),
|
||||
m_in_pa2_cb(*this),
|
||||
m_in_pa3_cb(*this),
|
||||
m_in_pa4_cb(*this),
|
||||
m_in_pa5_cb(*this),
|
||||
m_in_pa6_cb(*this),
|
||||
m_in_pa7_cb(*this),
|
||||
m_out_pa0_cb(*this),
|
||||
m_out_pa1_cb(*this),
|
||||
m_out_pa2_cb(*this),
|
||||
m_out_pa3_cb(*this),
|
||||
m_out_pa4_cb(*this),
|
||||
m_out_pa5_cb(*this),
|
||||
m_out_pa6_cb(*this),
|
||||
m_out_pa7_cb(*this),
|
||||
m_in_pb0_cb(*this),
|
||||
m_in_pb1_cb(*this),
|
||||
m_in_pb2_cb(*this),
|
||||
m_in_pb3_cb(*this),
|
||||
m_in_pb4_cb(*this),
|
||||
m_in_pb5_cb(*this),
|
||||
m_in_pb6_cb(*this),
|
||||
m_in_pb7_cb(*this),
|
||||
m_out_pb0_cb(*this),
|
||||
m_out_pb1_cb(*this),
|
||||
m_out_pb2_cb(*this),
|
||||
m_out_pb3_cb(*this),
|
||||
m_out_pb4_cb(*this),
|
||||
m_out_pb5_cb(*this),
|
||||
m_out_pb6_cb(*this),
|
||||
m_out_pb7_cb(*this),
|
||||
m_pa_in(0),
|
||||
m_pb_in(0)
|
||||
{
|
||||
cur_live.tm = attotime::never;
|
||||
cur_live.state = IDLE;
|
||||
cur_live.next_state = -1;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void mos6530_t::device_start()
|
||||
{
|
||||
// resolve callbacks
|
||||
m_irq_cb.resolve_safe();
|
||||
m_in_pa_cb.resolve_safe(0xff);
|
||||
m_out_pa_cb.resolve_safe();
|
||||
m_in_pb_cb.resolve_safe(0xff);
|
||||
m_out_pb_cb.resolve_safe();
|
||||
m_in_pa0_cb.resolve_safe(1);
|
||||
m_in_pa1_cb.resolve_safe(1);
|
||||
m_in_pa2_cb.resolve_safe(1);
|
||||
m_in_pa3_cb.resolve_safe(1);
|
||||
m_in_pa4_cb.resolve_safe(1);
|
||||
m_in_pa5_cb.resolve_safe(1);
|
||||
m_in_pa6_cb.resolve_safe(1);
|
||||
m_in_pa7_cb.resolve_safe(1);
|
||||
m_out_pa0_cb.resolve_safe();
|
||||
m_out_pa1_cb.resolve_safe();
|
||||
m_out_pa2_cb.resolve_safe();
|
||||
m_out_pa3_cb.resolve_safe();
|
||||
m_out_pa4_cb.resolve_safe();
|
||||
m_out_pa5_cb.resolve_safe();
|
||||
m_out_pa6_cb.resolve_safe();
|
||||
m_out_pa7_cb.resolve_safe();
|
||||
m_in_pb0_cb.resolve_safe(1);
|
||||
m_in_pb1_cb.resolve_safe(1);
|
||||
m_in_pb2_cb.resolve_safe(1);
|
||||
m_in_pb3_cb.resolve_safe(1);
|
||||
m_in_pb4_cb.resolve_safe(1);
|
||||
m_in_pb5_cb.resolve_safe(1);
|
||||
m_in_pb6_cb.resolve_safe(1);
|
||||
m_in_pb7_cb.resolve_safe(1);
|
||||
m_out_pb0_cb.resolve_safe();
|
||||
m_out_pb1_cb.resolve_safe();
|
||||
m_out_pb2_cb.resolve_safe();
|
||||
m_out_pb3_cb.resolve_safe();
|
||||
m_out_pb4_cb.resolve_safe();
|
||||
m_out_pb5_cb.resolve_safe();
|
||||
m_out_pb6_cb.resolve_safe();
|
||||
m_out_pb7_cb.resolve_safe();
|
||||
|
||||
// allocate timer
|
||||
t_gen = timer_alloc(0);
|
||||
|
||||
// allocate RAM
|
||||
m_ram.allocate(0x40);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void mos6530_t::device_reset()
|
||||
{
|
||||
m_ie = false;
|
||||
m_irq = true;
|
||||
|
||||
m_pa_out = 0;
|
||||
m_pa_ddr = 0;
|
||||
m_pb_out = 0;
|
||||
m_pb_ddr = 0;
|
||||
|
||||
update_pa();
|
||||
update_pb();
|
||||
|
||||
live_abort();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_timer - handler timer events
|
||||
//-------------------------------------------------
|
||||
|
||||
void mos6530_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
live_sync();
|
||||
live_run();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// update_pa -
|
||||
//-------------------------------------------------
|
||||
|
||||
void mos6530_t::update_pa()
|
||||
{
|
||||
UINT8 out = m_pa_out;
|
||||
UINT8 ddr = m_pa_ddr;
|
||||
UINT8 data = (out & ddr) | (ddr ^ 0xff);
|
||||
|
||||
m_out_pa_cb(data);
|
||||
|
||||
m_out_pa0_cb(BIT(data, 0));
|
||||
m_out_pa1_cb(BIT(data, 1));
|
||||
m_out_pa2_cb(BIT(data, 2));
|
||||
m_out_pa3_cb(BIT(data, 3));
|
||||
m_out_pa4_cb(BIT(data, 4));
|
||||
m_out_pa5_cb(BIT(data, 5));
|
||||
m_out_pa6_cb(BIT(data, 6));
|
||||
m_out_pa7_cb(BIT(data, 7));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// update_pb -
|
||||
//-------------------------------------------------
|
||||
|
||||
void mos6530_t::update_pb()
|
||||
{
|
||||
UINT8 out = m_pb_out;
|
||||
UINT8 ddr = m_pb_ddr;
|
||||
UINT8 data = (out & ddr) | (ddr ^ 0xff);
|
||||
|
||||
if (m_ie)
|
||||
{
|
||||
data &= ~IRQ_TIMER;
|
||||
data |= m_irq ? 0x00 : IRQ_TIMER;
|
||||
m_irq_cb(m_irq ? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
|
||||
m_out_pb_cb(data);
|
||||
|
||||
m_out_pb0_cb(BIT(data, 0));
|
||||
m_out_pb1_cb(BIT(data, 1));
|
||||
m_out_pb2_cb(BIT(data, 2));
|
||||
m_out_pb3_cb(BIT(data, 3));
|
||||
m_out_pb4_cb(BIT(data, 4));
|
||||
m_out_pb5_cb(BIT(data, 5));
|
||||
m_out_pb6_cb(BIT(data, 6));
|
||||
m_out_pb7_cb(BIT(data, 7));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// pa_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
void mos6530_t::pa_w(int bit, int state)
|
||||
{
|
||||
m_pa_in &= ~(2 << bit);
|
||||
|
||||
if (state) m_pa_in |= (2 << bit);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// pb_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
void mos6530_t::pb_w(int bit, int state)
|
||||
{
|
||||
m_pb_in &= ~(2 << bit);
|
||||
|
||||
if (state) m_pb_in |= (2 << bit);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// pa_data_r -
|
||||
//-------------------------------------------------
|
||||
|
||||
READ8_MEMBER( mos6530_t::pa_data_r )
|
||||
{
|
||||
UINT8 in = 0;
|
||||
|
||||
if (m_in_pa_cb.isnull())
|
||||
{
|
||||
in |= m_in_pa0_cb.isnull() ? BIT(m_pa_in, 0) : m_in_pa0_cb() << 0;
|
||||
in |= m_in_pa1_cb.isnull() ? BIT(m_pa_in, 1) : m_in_pa1_cb() << 1;
|
||||
in |= m_in_pa2_cb.isnull() ? BIT(m_pa_in, 2) : m_in_pa2_cb() << 2;
|
||||
in |= m_in_pa3_cb.isnull() ? BIT(m_pa_in, 3) : m_in_pa3_cb() << 3;
|
||||
in |= m_in_pa4_cb.isnull() ? BIT(m_pa_in, 4) : m_in_pa4_cb() << 4;
|
||||
in |= m_in_pa5_cb.isnull() ? BIT(m_pa_in, 5) : m_in_pa5_cb() << 5;
|
||||
in |= m_in_pa6_cb.isnull() ? BIT(m_pa_in, 6) : m_in_pa6_cb() << 6;
|
||||
in |= m_in_pa7_cb.isnull() ? BIT(m_pa_in, 7) : m_in_pa7_cb() << 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
in = m_in_pa_cb();
|
||||
}
|
||||
|
||||
UINT8 out = m_pa_out;
|
||||
UINT8 ddr = m_pa_ddr;
|
||||
|
||||
return (out & ddr) | (in & (ddr ^ 0xff));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// pa_data_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( mos6530_t::pa_data_w )
|
||||
{
|
||||
m_pa_out = data;
|
||||
|
||||
if (LOG) logerror("%s %s MOS6530 '%s' Port A data %02x\n", machine().time().as_string(), machine().describe_context(), tag(), data);
|
||||
|
||||
update_pa();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// pa_ddr_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( mos6530_t::pa_ddr_w )
|
||||
{
|
||||
m_pa_ddr = data;
|
||||
|
||||
if (LOG) logerror("%s %s MOS6530 '%s' Port A DDR %02x\n", machine().time().as_string(), machine().describe_context(), tag(), data);
|
||||
|
||||
update_pa();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// pb_data_r -
|
||||
//-------------------------------------------------
|
||||
|
||||
READ8_MEMBER( mos6530_t::pb_data_r )
|
||||
{
|
||||
UINT8 in = 0;
|
||||
|
||||
if (m_in_pb_cb.isnull())
|
||||
{
|
||||
in |= m_in_pb0_cb.isnull() ? BIT(m_pb_in, 0) : m_in_pb0_cb() << 0;
|
||||
in |= m_in_pb1_cb.isnull() ? BIT(m_pb_in, 1) : m_in_pb1_cb() << 1;
|
||||
in |= m_in_pb2_cb.isnull() ? BIT(m_pb_in, 2) : m_in_pb2_cb() << 2;
|
||||
in |= m_in_pb3_cb.isnull() ? BIT(m_pb_in, 3) : m_in_pb3_cb() << 3;
|
||||
in |= m_in_pb4_cb.isnull() ? BIT(m_pb_in, 4) : m_in_pb4_cb() << 4;
|
||||
in |= m_in_pb5_cb.isnull() ? BIT(m_pb_in, 5) : m_in_pb5_cb() << 5;
|
||||
in |= m_in_pb6_cb.isnull() ? BIT(m_pb_in, 6) : m_in_pb6_cb() << 6;
|
||||
in |= m_in_pb7_cb.isnull() ? BIT(m_pb_in, 7) : m_in_pb7_cb() << 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
in = m_in_pb_cb();
|
||||
}
|
||||
|
||||
UINT8 out = m_pb_out;
|
||||
UINT8 ddr = m_pb_ddr;
|
||||
|
||||
return (out & ddr) | (in & (ddr ^ 0xff));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// pb_data_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( mos6530_t::pb_data_w )
|
||||
{
|
||||
m_pb_out = data;
|
||||
|
||||
if (LOG) logerror("%s %s MOS6530 '%s' Port B data %02x\n", machine().time().as_string(), machine().describe_context(), tag(), data);
|
||||
|
||||
update_pb();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// pb_ddr_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( mos6530_t::pb_ddr_w )
|
||||
{
|
||||
m_pb_ddr = data;
|
||||
|
||||
if (LOG) logerror("%s %s MOS6530 '%s' Port B DDR %02x\n", machine().time().as_string(), machine().describe_context(), tag(), data);
|
||||
|
||||
update_pb();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// timer_r -
|
||||
//-------------------------------------------------
|
||||
|
||||
READ8_MEMBER( mos6530_t::timer_r )
|
||||
{
|
||||
UINT8 data = 0;
|
||||
|
||||
if (offset & 0x01)
|
||||
{
|
||||
data = m_irq ? 0x80 : 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
live_sync();
|
||||
|
||||
data = cur_live.value;
|
||||
|
||||
checkpoint();
|
||||
live_run();
|
||||
|
||||
m_ie = BIT(offset, 3) ? true : false;
|
||||
}
|
||||
|
||||
if (m_irq) {
|
||||
m_irq = false;
|
||||
update_pb();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// timer_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( mos6530_t::timer_w )
|
||||
{
|
||||
live_sync();
|
||||
|
||||
m_timer = data;
|
||||
|
||||
switch (offset & 0x03) {
|
||||
case 0: m_shift = 1; break;
|
||||
case 1: m_shift = 8; break;
|
||||
case 2: m_shift = 64; break;
|
||||
case 3: m_shift = 1024; break;
|
||||
}
|
||||
|
||||
m_ie = BIT(offset, 3) ? true : false;
|
||||
|
||||
if (LOG) logerror("%s %s MOS6530 '%s' Timer value %02x shift %u IE %u\n", machine().time().as_string(), machine().describe_context(), tag(), data, m_shift, m_ie ? 1 : 0);
|
||||
|
||||
if (m_irq) {
|
||||
m_irq = false;
|
||||
update_pb();
|
||||
}
|
||||
|
||||
checkpoint();
|
||||
|
||||
if (cur_live.state != IDLE) {
|
||||
live_abort();
|
||||
}
|
||||
|
||||
live_start();
|
||||
live_run();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// live_start -
|
||||
//-------------------------------------------------
|
||||
|
||||
void mos6530_t::live_start()
|
||||
{
|
||||
cur_live.period = attotime::from_hz(clock() / m_shift);
|
||||
cur_live.tm = machine().time() + cur_live.period;
|
||||
cur_live.state = RUNNING;
|
||||
cur_live.next_state = -1;
|
||||
|
||||
cur_live.value = m_timer;
|
||||
cur_live.irq = false;
|
||||
|
||||
checkpoint_live = cur_live;
|
||||
|
||||
live_run();
|
||||
}
|
||||
|
||||
void mos6530_t::checkpoint()
|
||||
{
|
||||
checkpoint_live = cur_live;
|
||||
}
|
||||
|
||||
void mos6530_t::rollback()
|
||||
{
|
||||
cur_live = checkpoint_live;
|
||||
}
|
||||
|
||||
void mos6530_t::live_delay(int state)
|
||||
{
|
||||
cur_live.next_state = state;
|
||||
if(cur_live.tm != machine().time())
|
||||
t_gen->adjust(cur_live.tm - machine().time());
|
||||
else
|
||||
live_sync();
|
||||
}
|
||||
|
||||
void mos6530_t::live_sync()
|
||||
{
|
||||
if(!cur_live.tm.is_never()) {
|
||||
if(cur_live.tm > machine().time()) {
|
||||
rollback();
|
||||
live_run(machine().time());
|
||||
} else {
|
||||
if(cur_live.next_state != -1) {
|
||||
cur_live.state = cur_live.next_state;
|
||||
cur_live.next_state = -1;
|
||||
}
|
||||
if(cur_live.state == IDLE) {
|
||||
cur_live.tm = attotime::never;
|
||||
}
|
||||
}
|
||||
cur_live.next_state = -1;
|
||||
checkpoint();
|
||||
}
|
||||
}
|
||||
|
||||
void mos6530_t::live_abort()
|
||||
{
|
||||
if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) {
|
||||
rollback();
|
||||
live_run(machine().time());
|
||||
}
|
||||
|
||||
cur_live.tm = attotime::never;
|
||||
cur_live.state = IDLE;
|
||||
cur_live.next_state = -1;
|
||||
|
||||
cur_live.irq = false;
|
||||
}
|
||||
|
||||
void mos6530_t::live_run(const attotime &limit)
|
||||
{
|
||||
if(cur_live.state == IDLE || cur_live.next_state != -1)
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
switch(cur_live.state) {
|
||||
case RUNNING: {
|
||||
if (cur_live.tm > limit)
|
||||
return;
|
||||
|
||||
cur_live.value--;
|
||||
|
||||
if (LOG) logerror("%s MOS6530 '%s' timer %02x IRQ 1\n", cur_live.tm.as_string(), tag(), cur_live.value);
|
||||
|
||||
if (!cur_live.value) {
|
||||
cur_live.period = attotime::from_hz(clock());
|
||||
cur_live.state = RUNNING_INTERRUPT;
|
||||
}
|
||||
|
||||
cur_live.tm += cur_live.period;
|
||||
break;
|
||||
}
|
||||
|
||||
case RUNNING_INTERRUPT: {
|
||||
if (cur_live.tm > limit)
|
||||
return;
|
||||
|
||||
cur_live.value--;
|
||||
cur_live.irq = true;
|
||||
|
||||
if (LOG) logerror("%s MOS6530 '%s' timer %02x IRQ 0\n", cur_live.tm.as_string(), tag(), cur_live.value);
|
||||
|
||||
live_delay(RUNNING_SYNCPOINT);
|
||||
|
||||
cur_live.tm += cur_live.period;
|
||||
return;
|
||||
}
|
||||
|
||||
case RUNNING_SYNCPOINT: {
|
||||
logerror("%s MOS6530 '%s' IRQ\n", machine().time().as_string(), tag());
|
||||
|
||||
m_irq = true;
|
||||
update_pb();
|
||||
|
||||
cur_live.state = RUNNING_AFTER_INTERRUPT;
|
||||
checkpoint();
|
||||
break;
|
||||
}
|
||||
|
||||
case RUNNING_AFTER_INTERRUPT: {
|
||||
if (cur_live.tm > limit)
|
||||
return;
|
||||
|
||||
cur_live.value--;
|
||||
|
||||
if (LOG) logerror("%s MOS6530 '%s' timer %02x IRQ 0\n", cur_live.tm.as_string(), tag(), cur_live.value);
|
||||
|
||||
if (!cur_live.value) {
|
||||
live_abort();
|
||||
return;
|
||||
}
|
||||
|
||||
cur_live.tm += cur_live.period;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
352
src/emu/machine/mos6530n.h
Normal file
352
src/emu/machine/mos6530n.h
Normal file
@ -0,0 +1,352 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Curt Coder
|
||||
/**********************************************************************
|
||||
|
||||
MOS Technology 6530 Memory, I/O, Timer Array emulation
|
||||
|
||||
Copyright MESS Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
**********************************************************************
|
||||
_____ _____
|
||||
Vss 1 |* \_/ | 40 PA1
|
||||
PA0 2 | | 39 PA2
|
||||
phi2 3 | | 38 PA3
|
||||
RS0 4 | | 37 PA4
|
||||
A9 5 | | 36 PA5
|
||||
A8 6 | | 35 PA6
|
||||
A7 7 | | 34 PA7
|
||||
A6 8 | | 33 DB0
|
||||
R/W 9 | | 32 DB1
|
||||
A5 10 | MCS6530 | 31 DB2
|
||||
A4 11 | | 30 DB3
|
||||
A3 12 | | 29 DB4
|
||||
A2 13 | | 28 DB5
|
||||
A1 14 | | 27 DB6
|
||||
A0 15 | | 26 DB7
|
||||
_RES 16 | | 25 PB0
|
||||
IRQ/PB7 17 | | 24 PB1
|
||||
CS1/PB6 18 | | 23 PB2
|
||||
CS2/PB5 19 | | 22 PB3
|
||||
Vcc 20 |_____________| 21 PB4
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __MOS6530n__
|
||||
#define __MOS6530n__
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// INTERFACE CONFIGURATION MACROS
|
||||
//**************************************************************************
|
||||
|
||||
#define MCFG_MOS6530n_IRQ_CB(_write) \
|
||||
devcb = &mos6530_t::set_irq_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PA_CB(_read) \
|
||||
devcb = &mos6530_t::set_pa_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PA_CB(_write) \
|
||||
devcb = &mos6530_t::set_pa_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PB_CB(_read) \
|
||||
devcb = &mos6530_t::set_pb_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PB_CB(_write) \
|
||||
devcb = &mos6530_t::set_pb_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PA0_CB(_read) \
|
||||
devcb = &mos6530_t::set_pa0_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PA1_CB(_read) \
|
||||
devcb = &mos6530_t::set_pa1_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PA2_CB(_read) \
|
||||
devcb = &mos6530_t::set_pa2_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PA3_CB(_read) \
|
||||
devcb = &mos6530_t::set_pa3_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PA4_CB(_read) \
|
||||
devcb = &mos6530_t::set_pa4_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PA5_CB(_read) \
|
||||
devcb = &mos6530_t::set_pa5_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PA6_CB(_read) \
|
||||
devcb = &mos6530_t::set_pa6_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PA7_CB(_read) \
|
||||
devcb = &mos6530_t::set_pa7_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PA0_CB(_write) \
|
||||
devcb = &mos6530_t::set_pa0_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PA1_CB(_write) \
|
||||
devcb = &mos6530_t::set_pa1_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PA2_CB(_write) \
|
||||
devcb = &mos6530_t::set_pa2_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PA3_CB(_write) \
|
||||
devcb = &mos6530_t::set_pa3_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PA4_CB(_write) \
|
||||
devcb = &mos6530_t::set_pa4_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PA5_CB(_write) \
|
||||
devcb = &mos6530_t::set_pa5_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PA6_CB(_write) \
|
||||
devcb = &mos6530_t::set_pa6_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PA7_CB(_write) \
|
||||
devcb = &mos6530_t::set_pa7_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PB0_CB(_read) \
|
||||
devcb = &mos6530_t::set_pb0_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PB1_CB(_read) \
|
||||
devcb = &mos6530_t::set_pb1_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PB2_CB(_read) \
|
||||
devcb = &mos6530_t::set_pb2_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PB3_CB(_read) \
|
||||
devcb = &mos6530_t::set_pb3_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PB4_CB(_read) \
|
||||
devcb = &mos6530_t::set_pb4_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PB5_CB(_read) \
|
||||
devcb = &mos6530_t::set_pb5_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PB6_CB(_read) \
|
||||
devcb = &mos6530_t::set_pb6_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_IN_PB7_CB(_read) \
|
||||
devcb = &mos6530_t::set_pb7_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PB0_CB(_write) \
|
||||
devcb = &mos6530_t::set_pb0_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PB1_CB(_write) \
|
||||
devcb = &mos6530_t::set_pb1_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PB2_CB(_write) \
|
||||
devcb = &mos6530_t::set_pb2_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PB3_CB(_write) \
|
||||
devcb = &mos6530_t::set_pb3_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PB4_CB(_write) \
|
||||
devcb = &mos6530_t::set_pb4_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PB5_CB(_write) \
|
||||
devcb = &mos6530_t::set_pb5_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PB6_CB(_write) \
|
||||
devcb = &mos6530_t::set_pb6_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MOS6530n_OUT_PB7_CB(_write) \
|
||||
devcb = &mos6530_t::set_pb7_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> mos6530_t
|
||||
|
||||
class mos6530_t : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
mos6530_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
template<class _Object> static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_irq_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pa_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pa_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pb_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pb_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa0_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pa0_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa1_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pa1_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa2_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pa2_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa3_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pa3_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa4_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pa4_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa5_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pa5_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa6_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pa6_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa7_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pa7_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa0_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pa0_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa1_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pa1_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa2_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pa2_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa3_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pa3_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa4_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pa4_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa5_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pa5_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa6_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pa6_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pa7_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pa7_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb0_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pb0_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb1_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pb1_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb2_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pb2_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb3_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pb3_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb4_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pb4_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb5_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pb5_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb6_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pb6_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb7_rd_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_in_pb7_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb0_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pb0_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb1_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pb1_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb2_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pb2_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb3_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pb3_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb4_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pb4_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb5_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pb5_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb6_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pb6_cb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &set_pb7_wr_callback(device_t &device, _Object object) { return downcast<mos6530_t &>(device).m_out_pb7_cb.set_callback(object); }
|
||||
|
||||
virtual DECLARE_ADDRESS_MAP(rom_map, 8);
|
||||
virtual DECLARE_ADDRESS_MAP(ram_map, 8);
|
||||
virtual DECLARE_ADDRESS_MAP(io_map, 8);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( pa0_w ) { pa_w(0, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pa1_w ) { pa_w(1, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pa2_w ) { pa_w(2, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pa3_w ) { pa_w(3, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pa4_w ) { pa_w(4, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pa5_w ) { pa_w(5, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pa6_w ) { pa_w(6, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pa7_w ) { pa_w(7, state); }
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( pb0_w ) { pb_w(0, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pb1_w ) { pb_w(1, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pb2_w ) { pb_w(2, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pb3_w ) { pb_w(3, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pb4_w ) { pb_w(4, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pb5_w ) { pb_w(5, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pb6_w ) { pb_w(6, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( pb7_w ) { pb_w(7, state); }
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
|
||||
enum
|
||||
{
|
||||
IRQ_TIMER = 0x80
|
||||
};
|
||||
|
||||
void update_pa();
|
||||
void update_pb();
|
||||
void pa_w(int bit, int state);
|
||||
void pb_w(int bit, int state);
|
||||
|
||||
DECLARE_READ8_MEMBER( rom_r ) { return m_region->base()[offset]; }
|
||||
DECLARE_READ8_MEMBER( ram_r ) { return m_ram[offset]; }
|
||||
DECLARE_WRITE8_MEMBER( ram_w ) { m_ram[offset] = data; }
|
||||
DECLARE_READ8_MEMBER( pa_data_r );
|
||||
DECLARE_WRITE8_MEMBER( pa_data_w );
|
||||
DECLARE_READ8_MEMBER( pb_data_r );
|
||||
DECLARE_WRITE8_MEMBER( pb_data_w );
|
||||
DECLARE_READ8_MEMBER( pa_ddr_r ) { return m_pa_ddr; }
|
||||
DECLARE_WRITE8_MEMBER( pa_ddr_w );
|
||||
DECLARE_READ8_MEMBER( pb_ddr_r ) { return m_pb_ddr; }
|
||||
DECLARE_WRITE8_MEMBER( pb_ddr_w );
|
||||
DECLARE_READ8_MEMBER( irq_r ) { return m_irq ? 0x80 : 0x00; }
|
||||
DECLARE_READ8_MEMBER( timer_r );
|
||||
DECLARE_WRITE8_MEMBER( timer_w );
|
||||
|
||||
optional_shared_ptr<UINT8> m_ram;
|
||||
|
||||
devcb_write_line m_irq_cb;
|
||||
devcb_read8 m_in_pa_cb;
|
||||
devcb_write8 m_out_pa_cb;
|
||||
devcb_read8 m_in_pb_cb;
|
||||
devcb_write8 m_out_pb_cb;
|
||||
devcb_read_line m_in_pa0_cb;
|
||||
devcb_read_line m_in_pa1_cb;
|
||||
devcb_read_line m_in_pa2_cb;
|
||||
devcb_read_line m_in_pa3_cb;
|
||||
devcb_read_line m_in_pa4_cb;
|
||||
devcb_read_line m_in_pa5_cb;
|
||||
devcb_read_line m_in_pa6_cb;
|
||||
devcb_read_line m_in_pa7_cb;
|
||||
devcb_write_line m_out_pa0_cb;
|
||||
devcb_write_line m_out_pa1_cb;
|
||||
devcb_write_line m_out_pa2_cb;
|
||||
devcb_write_line m_out_pa3_cb;
|
||||
devcb_write_line m_out_pa4_cb;
|
||||
devcb_write_line m_out_pa5_cb;
|
||||
devcb_write_line m_out_pa6_cb;
|
||||
devcb_write_line m_out_pa7_cb;
|
||||
devcb_read_line m_in_pb0_cb;
|
||||
devcb_read_line m_in_pb1_cb;
|
||||
devcb_read_line m_in_pb2_cb;
|
||||
devcb_read_line m_in_pb3_cb;
|
||||
devcb_read_line m_in_pb4_cb;
|
||||
devcb_read_line m_in_pb5_cb;
|
||||
devcb_read_line m_in_pb6_cb;
|
||||
devcb_read_line m_in_pb7_cb;
|
||||
devcb_write_line m_out_pb0_cb;
|
||||
devcb_write_line m_out_pb1_cb;
|
||||
devcb_write_line m_out_pb2_cb;
|
||||
devcb_write_line m_out_pb3_cb;
|
||||
devcb_write_line m_out_pb4_cb;
|
||||
devcb_write_line m_out_pb5_cb;
|
||||
devcb_write_line m_out_pb6_cb;
|
||||
devcb_write_line m_out_pb7_cb;
|
||||
|
||||
UINT8 m_pa_in;
|
||||
UINT8 m_pa_out;
|
||||
UINT8 m_pa_ddr;
|
||||
|
||||
UINT8 m_pb_in;
|
||||
UINT8 m_pb_out;
|
||||
UINT8 m_pb_ddr;
|
||||
|
||||
bool m_ie;
|
||||
bool m_irq;
|
||||
|
||||
int m_shift;
|
||||
UINT8 m_timer;
|
||||
|
||||
enum {
|
||||
IDLE,
|
||||
RUNNING,
|
||||
RUNNING_INTERRUPT,
|
||||
RUNNING_SYNCPOINT,
|
||||
RUNNING_AFTER_INTERRUPT
|
||||
};
|
||||
|
||||
struct live_info {
|
||||
attotime tm;
|
||||
attotime period;
|
||||
int state, next_state;
|
||||
UINT8 value;
|
||||
bool irq;
|
||||
};
|
||||
|
||||
live_info cur_live, checkpoint_live;
|
||||
emu_timer *t_gen;
|
||||
|
||||
void live_start();
|
||||
void checkpoint();
|
||||
void rollback();
|
||||
void live_delay(int state);
|
||||
void live_sync();
|
||||
void live_abort();
|
||||
void live_run(const attotime &limit = attotime::never);
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type MOS6530n;
|
||||
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user