mos6530: Rewritten to support time travel. [Curt Coder]

This commit is contained in:
Curt Coder 2015-04-08 09:01:20 +03:00
parent d8795fe43c
commit 274078636e
3 changed files with 949 additions and 0 deletions

View File

@ -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
View 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
View 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