mirror of
https://github.com/holub/mame
synced 2025-10-05 08:41:31 +03:00
z80ctc: Make channels into subdevices
This commit is contained in:
parent
edd4afbe8f
commit
f6554879ce
@ -19,9 +19,7 @@
|
||||
//**************************************************************************
|
||||
|
||||
#define VERBOSE 0
|
||||
|
||||
#define VPRINTF(x) do { if (VERBOSE) logerror x; } while (0)
|
||||
#define VPRINTF_CHANNEL(x) do { if (VERBOSE) m_device->logerror x; } while (0)
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
|
||||
@ -30,40 +28,40 @@
|
||||
//**************************************************************************
|
||||
|
||||
// these are the bits of the incoming commands to the CTC
|
||||
const int INTERRUPT = 0x80;
|
||||
const int INTERRUPT_ON = 0x80;
|
||||
//const int INTERRUPT_OFF = 0x00;
|
||||
constexpr u16 INTERRUPT = 0x80;
|
||||
constexpr u16 INTERRUPT_ON = 0x80;
|
||||
//constexpr u16 INTERRUPT_OFF = 0x00;
|
||||
|
||||
const int MODE = 0x40;
|
||||
const int MODE_TIMER = 0x00;
|
||||
const int MODE_COUNTER = 0x40;
|
||||
constexpr u16 MODE = 0x40;
|
||||
constexpr u16 MODE_TIMER = 0x00;
|
||||
constexpr u16 MODE_COUNTER = 0x40;
|
||||
|
||||
const int PRESCALER = 0x20;
|
||||
//const int PRESCALER_256 = 0x20;
|
||||
const int PRESCALER_16 = 0x00;
|
||||
constexpr u16 PRESCALER = 0x20;
|
||||
//constexpr u16 PRESCALER_256 = 0x20;
|
||||
constexpr u16 PRESCALER_16 = 0x00;
|
||||
|
||||
const int EDGE = 0x10;
|
||||
const int EDGE_FALLING = 0x00;
|
||||
const int EDGE_RISING = 0x10;
|
||||
constexpr u16 EDGE = 0x10;
|
||||
constexpr u16 EDGE_FALLING = 0x00;
|
||||
constexpr u16 EDGE_RISING = 0x10;
|
||||
|
||||
const int TRIGGER = 0x08;
|
||||
const int TRIGGER_AUTO = 0x00;
|
||||
//const int TRIGGER_CLOCK = 0x08;
|
||||
constexpr u16 TRIGGER = 0x08;
|
||||
constexpr u16 TRIGGER_AUTO = 0x00;
|
||||
//constexpr u16 TRIGGER_CLOCK = 0x08;
|
||||
|
||||
const int CONSTANT = 0x04;
|
||||
const int CONSTANT_LOAD = 0x04;
|
||||
//const int CONSTANT_NONE = 0x00;
|
||||
constexpr u16 CONSTANT = 0x04;
|
||||
constexpr u16 CONSTANT_LOAD = 0x04;
|
||||
//constexpr u16 CONSTANT_NONE = 0x00;
|
||||
|
||||
const int RESET = 0x02;
|
||||
//const int RESET_CONTINUE = 0x00;
|
||||
const int RESET_ACTIVE = 0x02;
|
||||
constexpr u16 RESET = 0x02;
|
||||
//constexpr u16 RESET_CONTINUE = 0x00;
|
||||
constexpr u16 RESET_ACTIVE = 0x02;
|
||||
|
||||
const int CONTROL = 0x01;
|
||||
const int CONTROL_VECTOR = 0x00;
|
||||
const int CONTROL_WORD = 0x01;
|
||||
constexpr u16 CONTROL = 0x01;
|
||||
constexpr u16 CONTROL_VECTOR = 0x00;
|
||||
constexpr u16 CONTROL_WORD = 0x01;
|
||||
|
||||
// these extra bits help us keep things accurate
|
||||
const int WAITING_FOR_TRIG = 0x100;
|
||||
constexpr u16 WAITING_FOR_TRIG = 0x100;
|
||||
|
||||
|
||||
|
||||
@ -71,22 +69,21 @@ const int WAITING_FOR_TRIG = 0x100;
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
// device type definition
|
||||
// device type definitions
|
||||
DEFINE_DEVICE_TYPE(Z80CTC, z80ctc_device, "z80ctc", "Z80 CTC")
|
||||
DEFINE_DEVICE_TYPE(Z80CTC_CHANNEL, z80ctc_channel_device, "z80ctc_channel", "Z80 CTC Channel")
|
||||
|
||||
//-------------------------------------------------
|
||||
// z80ctc_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
z80ctc_device::z80ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
z80ctc_device::z80ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, Z80CTC, tag, owner, clock),
|
||||
device_z80daisy_interface(mconfig, *this),
|
||||
m_intr_cb(*this),
|
||||
m_zc0_cb(*this),
|
||||
m_zc1_cb(*this),
|
||||
m_zc2_cb(*this),
|
||||
m_zc3_cb(*this),
|
||||
m_vector(0)
|
||||
m_zc_cb{*this, *this, *this, *this},
|
||||
m_vector(0),
|
||||
m_channel(*this, "ch%u", 0U)
|
||||
{
|
||||
}
|
||||
|
||||
@ -97,7 +94,7 @@ z80ctc_device::z80ctc_device(const machine_config &mconfig, const char *tag, dev
|
||||
|
||||
READ8_MEMBER( z80ctc_device::read )
|
||||
{
|
||||
return m_channel[offset & 3].read();
|
||||
return m_channel[offset & 3]->read();
|
||||
}
|
||||
|
||||
|
||||
@ -107,7 +104,7 @@ READ8_MEMBER( z80ctc_device::read )
|
||||
|
||||
WRITE8_MEMBER( z80ctc_device::write )
|
||||
{
|
||||
m_channel[offset & 3].write(data);
|
||||
m_channel[offset & 3]->write(data);
|
||||
}
|
||||
|
||||
|
||||
@ -116,10 +113,43 @@ WRITE8_MEMBER( z80ctc_device::write )
|
||||
// trigger
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE_LINE_MEMBER( z80ctc_device::trg0 ) { m_channel[0].trigger(state); }
|
||||
WRITE_LINE_MEMBER( z80ctc_device::trg1 ) { m_channel[1].trigger(state); }
|
||||
WRITE_LINE_MEMBER( z80ctc_device::trg2 ) { m_channel[2].trigger(state); }
|
||||
WRITE_LINE_MEMBER( z80ctc_device::trg3 ) { m_channel[3].trigger(state); }
|
||||
WRITE_LINE_MEMBER( z80ctc_device::trg0 ) { m_channel[0]->trigger(state != 0); }
|
||||
WRITE_LINE_MEMBER( z80ctc_device::trg1 ) { m_channel[1]->trigger(state != 0); }
|
||||
WRITE_LINE_MEMBER( z80ctc_device::trg2 ) { m_channel[2]->trigger(state != 0); }
|
||||
WRITE_LINE_MEMBER( z80ctc_device::trg3 ) { m_channel[3]->trigger(state != 0); }
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_add_mconfig - add device-specific
|
||||
// machine configuration
|
||||
//-------------------------------------------------
|
||||
|
||||
MACHINE_CONFIG_START(z80ctc_device::device_add_mconfig)
|
||||
MCFG_DEVICE_ADD("ch0", Z80CTC_CHANNEL, 0)
|
||||
MCFG_DEVICE_ADD("ch1", Z80CTC_CHANNEL, 0)
|
||||
MCFG_DEVICE_ADD("ch2", Z80CTC_CHANNEL, 0)
|
||||
MCFG_DEVICE_ADD("ch3", Z80CTC_CHANNEL, 0)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_resolve_objects - resolve objects that
|
||||
// may be needed for other devices to set
|
||||
// initial conditions at start time
|
||||
//-------------------------------------------------
|
||||
|
||||
void z80ctc_device::device_resolve_objects()
|
||||
{
|
||||
// resolve callbacks
|
||||
m_intr_cb.resolve_safe();
|
||||
for (int ch = 0; ch < 4; ch++)
|
||||
{
|
||||
m_zc_cb[ch].resolve_safe();
|
||||
|
||||
// assign channel index
|
||||
m_channel[ch]->m_index = ch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -128,19 +158,6 @@ WRITE_LINE_MEMBER( z80ctc_device::trg3 ) { m_channel[3].trigger(state); }
|
||||
|
||||
void z80ctc_device::device_start()
|
||||
{
|
||||
// resolve callbacks
|
||||
m_intr_cb.resolve_safe();
|
||||
m_zc0_cb.resolve_safe();
|
||||
m_zc1_cb.resolve_safe();
|
||||
m_zc2_cb.resolve_safe();
|
||||
m_zc3_cb.resolve_safe();
|
||||
|
||||
// start each channel
|
||||
m_channel[0].start(this, 0);
|
||||
m_channel[1].start(this, 1);
|
||||
m_channel[2].start(this, 2);
|
||||
m_channel[3].start(this, 3);
|
||||
|
||||
// register for save states
|
||||
save_item(NAME(m_vector));
|
||||
}
|
||||
@ -150,17 +167,11 @@ void z80ctc_device::device_start()
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void z80ctc_device::device_reset()
|
||||
void z80ctc_device::device_reset_after_children()
|
||||
{
|
||||
// reset each channel
|
||||
m_channel[0].reset();
|
||||
m_channel[1].reset();
|
||||
m_channel[2].reset();
|
||||
m_channel[3].reset();
|
||||
|
||||
// check for interrupts
|
||||
interrupt_check();
|
||||
VPRINTF(("CTC Reset\n"));
|
||||
LOG("CTC Reset\n");
|
||||
}
|
||||
|
||||
|
||||
@ -176,19 +187,19 @@ void z80ctc_device::device_reset()
|
||||
|
||||
int z80ctc_device::z80daisy_irq_state()
|
||||
{
|
||||
VPRINTF(("CTC IRQ state = %d%d%d%d\n", m_channel[0].m_int_state, m_channel[1].m_int_state, m_channel[2].m_int_state, m_channel[3].m_int_state));
|
||||
LOG("CTC IRQ state = %d%d%d%d\n", m_channel[0]->m_int_state, m_channel[1]->m_int_state, m_channel[2]->m_int_state, m_channel[3]->m_int_state);
|
||||
|
||||
// loop over all channels
|
||||
int state = 0;
|
||||
for (auto & channel : m_channel)
|
||||
for (int ch = 0; ch < 4; ch++)
|
||||
{
|
||||
// if we're servicing a request, don't indicate more interrupts
|
||||
if (channel.m_int_state & Z80_DAISY_IEO)
|
||||
if (m_channel[ch]->m_int_state & Z80_DAISY_IEO)
|
||||
{
|
||||
state |= Z80_DAISY_IEO;
|
||||
break;
|
||||
}
|
||||
state |= channel.m_int_state;
|
||||
state |= m_channel[ch]->m_int_state;
|
||||
}
|
||||
|
||||
return state;
|
||||
@ -205,12 +216,12 @@ int z80ctc_device::z80daisy_irq_ack()
|
||||
// loop over all channels
|
||||
for (int ch = 0; ch < 4; ch++)
|
||||
{
|
||||
ctc_channel &channel = m_channel[ch];
|
||||
z80ctc_channel_device &channel = *m_channel[ch];
|
||||
|
||||
// find the first channel with an interrupt requested
|
||||
if (channel.m_int_state & Z80_DAISY_INT)
|
||||
{
|
||||
VPRINTF(("CTC IRQAck ch%d\n", ch));
|
||||
LOG("CTC IRQAck ch%d\n", ch);
|
||||
|
||||
// clear interrupt, switch to the IEO state, and update the IRQs
|
||||
channel.m_int_state = Z80_DAISY_IEO;
|
||||
@ -234,12 +245,12 @@ void z80ctc_device::z80daisy_irq_reti()
|
||||
// loop over all channels
|
||||
for (int ch = 0; ch < 4; ch++)
|
||||
{
|
||||
ctc_channel &channel = m_channel[ch];
|
||||
z80ctc_channel_device &channel = *m_channel[ch];
|
||||
|
||||
// find the first channel with an IEO pending
|
||||
if (channel.m_int_state & Z80_DAISY_IEO)
|
||||
{
|
||||
VPRINTF(("CTC IRQReti ch%d\n", ch));
|
||||
LOG("CTC IRQReti ch%d\n", ch);
|
||||
|
||||
// clear the IEO state and update the IRQs
|
||||
channel.m_int_state &= ~Z80_DAISY_IEO;
|
||||
@ -275,11 +286,12 @@ void z80ctc_device::interrupt_check()
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// ctc_channel - constructor
|
||||
// z80ctc_channel_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
z80ctc_device::ctc_channel::ctc_channel()
|
||||
: m_device(nullptr),
|
||||
z80ctc_channel_device::z80ctc_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, Z80CTC_CHANNEL, tag, owner, clock),
|
||||
m_device(*this, DEVICE_SELF_OWNER),
|
||||
m_index(0),
|
||||
m_mode(0),
|
||||
m_tconst(0),
|
||||
@ -292,30 +304,28 @@ z80ctc_device::ctc_channel::ctc_channel()
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// start - set up at device start time
|
||||
// device_start - set up at device start time
|
||||
//-------------------------------------------------
|
||||
|
||||
void z80ctc_device::ctc_channel::start(z80ctc_device *device, int index)
|
||||
void z80ctc_channel_device::device_start()
|
||||
{
|
||||
// initialize state
|
||||
m_device = device;
|
||||
m_index = index;
|
||||
m_timer = m_device->machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z80ctc_device::ctc_channel::timer_callback), this));
|
||||
m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z80ctc_channel_device::timer_callback), this));
|
||||
|
||||
// register for save states
|
||||
m_device->save_item(NAME(m_mode), m_index);
|
||||
m_device->save_item(NAME(m_tconst), m_index);
|
||||
m_device->save_item(NAME(m_down), m_index);
|
||||
m_device->save_item(NAME(m_extclk), m_index);
|
||||
m_device->save_item(NAME(m_int_state), m_index);
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_tconst));
|
||||
save_item(NAME(m_down));
|
||||
save_item(NAME(m_extclk));
|
||||
save_item(NAME(m_int_state));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// reset - reset the channel
|
||||
// device_reset - reset the channel
|
||||
//-------------------------------------------------
|
||||
|
||||
void z80ctc_device::ctc_channel::reset()
|
||||
void z80ctc_channel_device::device_reset()
|
||||
{
|
||||
m_mode = RESET_ACTIVE;
|
||||
m_tconst = 0x100;
|
||||
@ -328,7 +338,7 @@ void z80ctc_device::ctc_channel::reset()
|
||||
// period - return the current channel's period
|
||||
//-------------------------------------------------
|
||||
|
||||
attotime z80ctc_device::ctc_channel::period() const
|
||||
attotime z80ctc_channel_device::period() const
|
||||
{
|
||||
// if reset active, no period
|
||||
if ((m_mode & RESET) == RESET_ACTIVE)
|
||||
@ -337,7 +347,7 @@ attotime z80ctc_device::ctc_channel::period() const
|
||||
// if counter mode, no real period
|
||||
if ((m_mode & MODE) == MODE_COUNTER)
|
||||
{
|
||||
m_device->logerror("CTC %d is CounterMode : Can't calculate period\n", m_index);
|
||||
logerror("CounterMode : Can't calculate period\n");
|
||||
return attotime::zero;
|
||||
}
|
||||
|
||||
@ -351,7 +361,7 @@ attotime z80ctc_device::ctc_channel::period() const
|
||||
// read - read the channel's state
|
||||
//-------------------------------------------------
|
||||
|
||||
uint8_t z80ctc_device::ctc_channel::read()
|
||||
u8 z80ctc_channel_device::read()
|
||||
{
|
||||
// if we're in counter mode, just return the count
|
||||
if ((m_mode & MODE) == MODE_COUNTER || (m_mode & WAITING_FOR_TRIG))
|
||||
@ -362,7 +372,7 @@ uint8_t z80ctc_device::ctc_channel::read()
|
||||
{
|
||||
attotime period = m_device->clocks_to_attotime((m_mode & PRESCALER) == PRESCALER_16 ? 16 : 256);
|
||||
|
||||
VPRINTF_CHANNEL(("CTC clock %f\n",ATTOSECONDS_TO_HZ(period.attoseconds())));
|
||||
LOG("CTC clock %f\n",ATTOSECONDS_TO_HZ(period.attoseconds()));
|
||||
|
||||
if (m_timer != nullptr)
|
||||
return ((int)(m_timer->remaining().as_double() / period.as_double()) + 1) & 0xff;
|
||||
@ -376,12 +386,12 @@ uint8_t z80ctc_device::ctc_channel::read()
|
||||
// write - handle writes to a channel
|
||||
//-------------------------------------------------
|
||||
|
||||
void z80ctc_device::ctc_channel::write(uint8_t data)
|
||||
void z80ctc_channel_device::write(u8 data)
|
||||
{
|
||||
// if we're waiting for a time constant, this is it
|
||||
if ((m_mode & CONSTANT) == CONSTANT_LOAD)
|
||||
{
|
||||
VPRINTF_CHANNEL(("CTC ch.%d constant = %02x\n", m_index, data));
|
||||
LOG("Time constant = %02x\n", data);
|
||||
|
||||
// set the time constant (0 -> 0x100)
|
||||
m_tconst = data ? data : 0x100;
|
||||
@ -399,7 +409,7 @@ void z80ctc_device::ctc_channel::write(uint8_t data)
|
||||
if ((m_mode & TRIGGER) == TRIGGER_AUTO)
|
||||
{
|
||||
attotime curperiod = period();
|
||||
m_timer->adjust(curperiod, m_index, curperiod);
|
||||
m_timer->adjust(curperiod, 0, curperiod);
|
||||
}
|
||||
|
||||
// else set the bit indicating that we're waiting for the appropriate trigger
|
||||
@ -421,7 +431,7 @@ void z80ctc_device::ctc_channel::write(uint8_t data)
|
||||
#endif
|
||||
{
|
||||
m_device->m_vector = data & 0xf8;
|
||||
VPRINTF_CHANNEL(("CTC Vector = %02x\n", m_device->m_vector));
|
||||
LOG("Vector = %02x\n", m_device->m_vector);
|
||||
}
|
||||
|
||||
// this must be a control word
|
||||
@ -435,7 +445,7 @@ void z80ctc_device::ctc_channel::write(uint8_t data)
|
||||
|
||||
// set the new mode
|
||||
m_mode = data;
|
||||
VPRINTF_CHANNEL(("CTC ch.%d mode = %02x\n", m_index, data));
|
||||
LOG("Channel mode = %02x\n", data);
|
||||
|
||||
// if we're being reset, clear out any pending timers for this channel
|
||||
if ((data & RESET) == RESET_ACTIVE)
|
||||
@ -452,25 +462,22 @@ void z80ctc_device::ctc_channel::write(uint8_t data)
|
||||
// side-effects
|
||||
//-------------------------------------------------
|
||||
|
||||
void z80ctc_device::ctc_channel::trigger(uint8_t data)
|
||||
void z80ctc_channel_device::trigger(bool state)
|
||||
{
|
||||
// normalize data
|
||||
data = data ? 1 : 0;
|
||||
|
||||
// see if the trigger value has changed
|
||||
if (data != m_extclk)
|
||||
if (state != m_extclk)
|
||||
{
|
||||
m_extclk = data;
|
||||
m_extclk = state;
|
||||
|
||||
// see if this is the active edge of the trigger
|
||||
if (((m_mode & EDGE) == EDGE_RISING && data) || ((m_mode & EDGE) == EDGE_FALLING && !data))
|
||||
if (((m_mode & EDGE) == EDGE_RISING && state) || ((m_mode & EDGE) == EDGE_FALLING && !state))
|
||||
{
|
||||
// if we're waiting for a trigger, start the timer
|
||||
if ((m_mode & WAITING_FOR_TRIG) && (m_mode & MODE) == MODE_TIMER)
|
||||
{
|
||||
attotime curperiod = period();
|
||||
VPRINTF_CHANNEL(("CTC period %s\n", curperiod.as_string()));
|
||||
m_timer->adjust(curperiod, m_index, curperiod);
|
||||
LOG("Period = %s\n", curperiod.as_string());
|
||||
m_timer->adjust(curperiod, 0, curperiod);
|
||||
}
|
||||
|
||||
// we're no longer waiting
|
||||
@ -493,36 +500,19 @@ void z80ctc_device::ctc_channel::trigger(uint8_t data)
|
||||
// side-effects
|
||||
//-------------------------------------------------
|
||||
|
||||
TIMER_CALLBACK_MEMBER(z80ctc_device::ctc_channel::timer_callback)
|
||||
TIMER_CALLBACK_MEMBER(z80ctc_channel_device::timer_callback)
|
||||
{
|
||||
// down counter has reached zero - see if we should interrupt
|
||||
if ((m_mode & INTERRUPT) == INTERRUPT_ON)
|
||||
{
|
||||
m_int_state |= Z80_DAISY_INT;
|
||||
VPRINTF_CHANNEL(("CTC timer ch%d\n", m_index));
|
||||
LOG("Timer interrupt\n");
|
||||
m_device->interrupt_check();
|
||||
}
|
||||
|
||||
// generate the clock pulse
|
||||
switch (m_index)
|
||||
{
|
||||
case 0:
|
||||
m_device->m_zc0_cb(1);
|
||||
m_device->m_zc0_cb(0);
|
||||
break;
|
||||
case 1:
|
||||
m_device->m_zc1_cb(1);
|
||||
m_device->m_zc1_cb(0);
|
||||
break;
|
||||
case 2:
|
||||
m_device->m_zc2_cb(1);
|
||||
m_device->m_zc2_cb(0);
|
||||
break;
|
||||
case 3:
|
||||
m_device->m_zc3_cb(1);
|
||||
m_device->m_zc3_cb(0);
|
||||
break;
|
||||
}
|
||||
m_device->m_zc_cb[m_index](1);
|
||||
m_device->m_zc_cb[m_index](0);
|
||||
|
||||
// reset the down counter
|
||||
m_down = m_tconst;
|
||||
|
@ -39,33 +39,68 @@
|
||||
devcb = &downcast<z80ctc_device &>(*device).set_intr_callback(DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_Z80CTC_ZC0_CB(_devcb) \
|
||||
devcb = &downcast<z80ctc_device &>(*device).set_zc0_callback(DEVCB_##_devcb);
|
||||
devcb = &downcast<z80ctc_device &>(*device).set_zc_callback<0>(DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_Z80CTC_ZC1_CB(_devcb) \
|
||||
devcb = &downcast<z80ctc_device &>(*device).set_zc1_callback(DEVCB_##_devcb);
|
||||
devcb = &downcast<z80ctc_device &>(*device).set_zc_callback<1>(DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_Z80CTC_ZC2_CB(_devcb) \
|
||||
devcb = &downcast<z80ctc_device &>(*device).set_zc2_callback(DEVCB_##_devcb);
|
||||
devcb = &downcast<z80ctc_device &>(*device).set_zc_callback<2>(DEVCB_##_devcb);
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// forward declaration
|
||||
class z80ctc_device;
|
||||
|
||||
// ======================> z80ctc_channel_device
|
||||
|
||||
// a single channel within the CTC
|
||||
class z80ctc_channel_device : public device_t
|
||||
{
|
||||
friend class z80ctc_device;
|
||||
|
||||
public:
|
||||
// construction/destruction
|
||||
z80ctc_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
u8 read();
|
||||
void write(u8 data);
|
||||
|
||||
attotime period() const;
|
||||
void trigger(bool state);
|
||||
TIMER_CALLBACK_MEMBER(timer_callback);
|
||||
|
||||
required_device<z80ctc_device> m_device; // pointer back to our device
|
||||
int m_index; // our channel index
|
||||
u16 m_mode; // current mode
|
||||
u16 m_tconst; // time constant
|
||||
u16 m_down; // down counter (clock mode only)
|
||||
bool m_extclk; // current signal from the external clock
|
||||
emu_timer * m_timer; // array of active timers
|
||||
u8 m_int_state; // interrupt status (for daisy chain)
|
||||
};
|
||||
|
||||
// ======================> z80ctc_device
|
||||
|
||||
class z80ctc_device : public device_t,
|
||||
public device_z80daisy_interface
|
||||
{
|
||||
friend class z80ctc_channel_device;
|
||||
|
||||
public:
|
||||
// construction/destruction
|
||||
z80ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
z80ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
template <class Object> devcb_base &set_intr_callback(Object &&cb) { return m_intr_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_zc0_callback(Object &&cb) { return m_zc0_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_zc1_callback(Object &&cb) { return m_zc1_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_zc2_callback(Object &&cb) { return m_zc2_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <int Channel, class Object> devcb_base &set_zc_callback(Object &&cb) { return m_zc_cb[Channel].set_callback(std::forward<Object>(cb)); }
|
||||
|
||||
// read/write handlers
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
@ -75,12 +110,14 @@ public:
|
||||
DECLARE_WRITE_LINE_MEMBER( trg2 );
|
||||
DECLARE_WRITE_LINE_MEMBER( trg3 );
|
||||
|
||||
uint16_t get_channel_constant(uint8_t channel) { return m_channel[channel].m_tconst; }
|
||||
u16 get_channel_constant(u8 channel) const { return m_channel[channel]->m_tconst; }
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_resolve_objects() override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_reset_after_children() override;
|
||||
|
||||
// z80daisy_interface overrides
|
||||
virtual int z80daisy_irq_state() override;
|
||||
@ -91,46 +128,19 @@ private:
|
||||
// internal helpers
|
||||
void interrupt_check();
|
||||
|
||||
// a single channel within the CTC
|
||||
class ctc_channel
|
||||
{
|
||||
public:
|
||||
ctc_channel();
|
||||
|
||||
void start(z80ctc_device *device, int index);
|
||||
void reset();
|
||||
|
||||
uint8_t read();
|
||||
void write(uint8_t data);
|
||||
|
||||
attotime period() const;
|
||||
void trigger(uint8_t data);
|
||||
TIMER_CALLBACK_MEMBER(timer_callback);
|
||||
|
||||
z80ctc_device * m_device; // pointer back to our device
|
||||
int m_index; // our channel index
|
||||
uint16_t m_mode; // current mode
|
||||
uint16_t m_tconst; // time constant
|
||||
uint16_t m_down; // down counter (clock mode only)
|
||||
uint8_t m_extclk; // current signal from the external clock
|
||||
emu_timer * m_timer; // array of active timers
|
||||
uint8_t m_int_state; // interrupt status (for daisy chain)
|
||||
};
|
||||
|
||||
// internal state
|
||||
devcb_write_line m_intr_cb; // interrupt callback
|
||||
devcb_write_line m_zc0_cb; // channel 0 zero crossing callbacks
|
||||
devcb_write_line m_zc1_cb; // channel 1 zero crossing callbacks
|
||||
devcb_write_line m_zc2_cb; // channel 2 zero crossing callbacks
|
||||
devcb_write_line m_zc3_cb; // channel 3 zero crossing callbacks = nullptr ?
|
||||
devcb_write_line m_zc_cb[4]; // zero crossing/timer output callbacks
|
||||
|
||||
uint8_t m_vector; // interrupt vector
|
||||
ctc_channel m_channel[4]; // data for each channel
|
||||
u8 m_vector; // interrupt vector
|
||||
|
||||
// subdevice for each channel
|
||||
required_device_array<z80ctc_channel_device, 4> m_channel;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
// device type definitions
|
||||
DECLARE_DEVICE_TYPE(Z80CTC, z80ctc_device)
|
||||
|
||||
DECLARE_DEVICE_TYPE(Z80CTC_CHANNEL, z80ctc_channel_device)
|
||||
|
||||
#endif // MAME_MACHINE_Z80CTC_H
|
||||
|
Loading…
Reference in New Issue
Block a user