mirror of
https://github.com/holub/mame
synced 2025-07-01 08:18:59 +03:00
z8: Rewrite timer emulation, including support for most TIN and TOUT modes
This commit is contained in:
parent
0bd20c8d14
commit
830f9927f1
@ -1,5 +1,5 @@
|
|||||||
// license:BSD-3-Clause
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:Curt Coder
|
// copyright-holders:Curt Coder, AJR
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|
||||||
Zilog Z8 Single-Chip MCU emulation
|
Zilog Z8 Single-Chip MCU emulation
|
||||||
@ -33,14 +33,14 @@
|
|||||||
#define Z8_P3_RDY0 0x20 /* not supported */
|
#define Z8_P3_RDY0 0x20 /* not supported */
|
||||||
#define Z8_P3_RDY1 0x10 /* not supported */
|
#define Z8_P3_RDY1 0x10 /* not supported */
|
||||||
#define Z8_P3_RDY2 0x40 /* not supported */
|
#define Z8_P3_RDY2 0x40 /* not supported */
|
||||||
#define Z8_P3_IRQ0 0x04 /* not supported */
|
#define Z8_P3_IRQ0 0x04
|
||||||
#define Z8_P3_IRQ1 0x08 /* not supported */
|
#define Z8_P3_IRQ1 0x08
|
||||||
#define Z8_P3_IRQ2 0x02 /* not supported */
|
#define Z8_P3_IRQ2 0x02
|
||||||
#define Z8_P3_IRQ3 0x01 /* not supported */
|
#define Z8_P3_IRQ3 0x01
|
||||||
#define Z8_P3_DI 0x01 /* not supported */
|
#define Z8_P3_DI 0x01 /* not supported */
|
||||||
#define Z8_P3_DO 0x80 /* not supported */
|
#define Z8_P3_DO 0x80 /* not supported */
|
||||||
#define Z8_P3_TIN 0x02 /* not supported */
|
#define Z8_P3_TIN 0x02
|
||||||
#define Z8_P3_TOUT 0x40 /* not supported */
|
#define Z8_P3_TOUT 0x40
|
||||||
#define Z8_P3_DM 0x10 /* not supported */
|
#define Z8_P3_DM 0x10 /* not supported */
|
||||||
|
|
||||||
#define Z8_PRE0_COUNT_MODULO_N 0x01
|
#define Z8_PRE0_COUNT_MODULO_N 0x01
|
||||||
@ -52,15 +52,15 @@
|
|||||||
#define Z8_TMR_ENABLE_T0 0x02
|
#define Z8_TMR_ENABLE_T0 0x02
|
||||||
#define Z8_TMR_LOAD_T1 0x04
|
#define Z8_TMR_LOAD_T1 0x04
|
||||||
#define Z8_TMR_ENABLE_T1 0x08
|
#define Z8_TMR_ENABLE_T1 0x08
|
||||||
#define Z8_TMR_TIN_MASK 0x30 /* not supported */
|
#define Z8_TMR_TIN_MASK 0x30
|
||||||
#define Z8_TMR_TIN_EXTERNAL_CLK 0x00 /* not supported */
|
#define Z8_TMR_TIN_EXTERNAL_CLK 0x00
|
||||||
#define Z8_TMR_TIN_GATE 0x10 /* not supported */
|
#define Z8_TMR_TIN_GATE 0x10
|
||||||
#define Z8_TMR_TIN_TRIGGER 0x20 /* not supported */
|
#define Z8_TMR_TIN_TRIGGER 0x20
|
||||||
#define Z8_TMR_TIN_RETRIGGER 0x30 /* not supported */
|
#define Z8_TMR_TIN_RETRIGGER 0x30
|
||||||
#define Z8_TMR_TOUT_MASK 0xc0 /* not supported */
|
#define Z8_TMR_TOUT_MASK 0xc0
|
||||||
#define Z8_TMR_TOUT_OFF 0x00 /* not supported */
|
#define Z8_TMR_TOUT_OFF 0x00
|
||||||
#define Z8_TMR_TOUT_T0 0x40 /* not supported */
|
#define Z8_TMR_TOUT_T0 0x40
|
||||||
#define Z8_TMR_TOUT_T1 0x80 /* not supported */
|
#define Z8_TMR_TOUT_T1 0x80
|
||||||
#define Z8_TMR_TOUT_INTERNAL_CLK 0xc0 /* not supported */
|
#define Z8_TMR_TOUT_INTERNAL_CLK 0xc0 /* not supported */
|
||||||
|
|
||||||
#define Z8_P01M_P0L_MODE_MASK 0x03
|
#define Z8_P01M_P0L_MODE_MASK 0x03
|
||||||
@ -171,6 +171,7 @@ z8_device::z8_device(const machine_config &mconfig, device_type type, const char
|
|||||||
, m_input_cb{{*this}, {*this}, {*this}, {*this}}
|
, m_input_cb{{*this}, {*this}, {*this}, {*this}}
|
||||||
, m_output_cb{{*this}, {*this}, {*this}, {*this}}
|
, m_output_cb{{*this}, {*this}, {*this}, {*this}}
|
||||||
, m_rom_size(rom_size)
|
, m_rom_size(rom_size)
|
||||||
|
, m_input{0xff, 0xff, 0xff, 0x0f}
|
||||||
{
|
{
|
||||||
assert(((rom_size - 1) & rom_size) == 0);
|
assert(((rom_size - 1) & rom_size) == 0);
|
||||||
}
|
}
|
||||||
@ -439,16 +440,21 @@ void z8_device::p2_write(uint8_t data)
|
|||||||
uint8_t z8_device::p3_read()
|
uint8_t z8_device::p3_read()
|
||||||
{
|
{
|
||||||
uint8_t mask = 0x0f;
|
uint8_t mask = 0x0f;
|
||||||
|
uint8_t inputs = m_input[3] & m_input_cb[3](0, mask);
|
||||||
|
|
||||||
// TODO: special port 3 modes
|
// TODO: special port 3 modes
|
||||||
//if (!(m_p3m & 0x7c))
|
//if (!(m_p3m & 0x7c))
|
||||||
//{
|
//{
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if (mask)
|
if ((m_tmr & Z8_TMR_TOUT_MASK) != Z8_TMR_TOUT_OFF)
|
||||||
m_input[3] = m_input_cb[3](0, mask);
|
{
|
||||||
|
mask |= Z8_P3_TOUT;
|
||||||
|
if (m_tout)
|
||||||
|
inputs |= Z8_P3_TOUT;
|
||||||
|
}
|
||||||
|
|
||||||
return (m_input[3] & mask) | (m_output[3] & ~mask);
|
return (inputs & mask) | (m_output[3] & ~mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void z8_device::p3_write(uint8_t data)
|
void z8_device::p3_write(uint8_t data)
|
||||||
@ -462,10 +468,17 @@ void z8_device::p3_write(uint8_t data)
|
|||||||
//{
|
//{
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
if ((m_tmr & Z8_TMR_TOUT_MASK) != Z8_TMR_TOUT_OFF)
|
||||||
|
data = (data & ~Z8_P3_TOUT) | (m_tout ? Z8_P3_TOUT : 0);
|
||||||
|
|
||||||
if (mask)
|
if (mask)
|
||||||
m_output_cb[3](0, data & mask, mask);
|
m_output_cb[3](0, data & mask, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void z8_device::sio_tick()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t z8_device::sio_read()
|
uint8_t z8_device::sio_read()
|
||||||
{
|
{
|
||||||
return 0xff;
|
return 0xff;
|
||||||
@ -475,6 +488,96 @@ void z8_device::sio_write(uint8_t data)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <int T>
|
||||||
|
void z8_device::timer_start()
|
||||||
|
{
|
||||||
|
unsigned prescaler = (m_pre[T] >> 2) ? (m_pre[T] >> 2) : 64;
|
||||||
|
unsigned full_count = (m_count[T] ? m_count[T] - 1 : 255) * prescaler + (m_pre_count[T] ? m_pre_count[T] : 64);
|
||||||
|
m_internal_timer[T]->adjust(cycles_to_attotime(4 * full_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int T>
|
||||||
|
void z8_device::timer_stop()
|
||||||
|
{
|
||||||
|
if (!m_internal_timer[T]->enabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned prescaler = (m_pre[T] >> 2) ? (m_pre[T] >> 2) : 64;
|
||||||
|
unsigned remaining = attotime_to_cycles(m_internal_timer[T]->remaining() / 4);
|
||||||
|
|
||||||
|
m_count[T] = remaining / prescaler + 1;
|
||||||
|
m_pre_count[T] = (remaining % prescaler + 1) & 0x3f;
|
||||||
|
|
||||||
|
m_internal_timer[T]->enable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int T>
|
||||||
|
void z8_device::timer_end()
|
||||||
|
{
|
||||||
|
if ((m_tmr & Z8_TMR_TOUT_MASK) == (T == 0 ? Z8_TMR_TOUT_T0 : Z8_TMR_TOUT_T1))
|
||||||
|
tout_toggle();
|
||||||
|
|
||||||
|
if (T == 0 && (m_p3m & Z8_P3M_P3_SERIAL) != 0)
|
||||||
|
sio_tick();
|
||||||
|
else
|
||||||
|
request_interrupt(4 + T);
|
||||||
|
|
||||||
|
m_pre_count[T] = m_pre[T] >> 2;
|
||||||
|
if (m_pre[T] & Z8_PRE0_COUNT_MODULO_N)
|
||||||
|
m_count[T] = m_t[T];
|
||||||
|
else
|
||||||
|
m_tmr &= ~(T == 0 ? Z8_TMR_ENABLE_T0 : Z8_TMR_ENABLE_T1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void z8_device::t1_trigger()
|
||||||
|
{
|
||||||
|
switch (m_tmr & Z8_TMR_TIN_MASK)
|
||||||
|
{
|
||||||
|
case Z8_TMR_TIN_EXTERNAL_CLK:
|
||||||
|
m_pre_count[1]--;
|
||||||
|
if (m_pre_count[1] == 0)
|
||||||
|
{
|
||||||
|
m_pre_count[1] = m_pre[1];
|
||||||
|
if ((m_tmr & Z8_TMR_ENABLE_T1) != 0)
|
||||||
|
{
|
||||||
|
m_count[1]--;
|
||||||
|
if (m_count[1] == 0)
|
||||||
|
timer_end<1>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Z8_TMR_TIN_GATE:
|
||||||
|
timer_stop<1>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Z8_TMR_TIN_TRIGGER:
|
||||||
|
if (m_internal_timer[1]->enabled())
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Z8_TMR_TIN_RETRIGGER:
|
||||||
|
if ((m_tmr & Z8_TMR_ENABLE_T1) != 0)
|
||||||
|
{
|
||||||
|
m_count[1] = m_t[1];
|
||||||
|
m_pre_count[1] = m_pre[1] >> 2;
|
||||||
|
timer_start<1>();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void z8_device::tout_init()
|
||||||
|
{
|
||||||
|
m_tout = true;
|
||||||
|
m_output_cb[3](0, (m_output[3] & ~Z8_P3_TOUT) | (m_tout ? Z8_P3_TOUT : 0), Z8_P3_TOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void z8_device::tout_toggle()
|
||||||
|
{
|
||||||
|
m_tout = !m_tout;
|
||||||
|
m_output_cb[3](0, (m_output[3] & ~Z8_P3_TOUT) | (m_tout ? Z8_P3_TOUT : 0), Z8_P3_TOUT);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t z8_device::tmr_read()
|
uint8_t z8_device::tmr_read()
|
||||||
{
|
{
|
||||||
return m_tmr;
|
return m_tmr;
|
||||||
@ -482,28 +585,80 @@ uint8_t z8_device::tmr_read()
|
|||||||
|
|
||||||
void z8_device::tmr_write(uint8_t data)
|
void z8_device::tmr_write(uint8_t data)
|
||||||
{
|
{
|
||||||
m_tmr = data;
|
m_tmr = data & ~(Z8_TMR_LOAD_T0 | Z8_TMR_LOAD_T1); // actually reset on next internal clock
|
||||||
|
|
||||||
if (data & Z8_TMR_LOAD_T0)
|
bool t1_internal = (m_pre[1] & Z8_PRE1_INTERNAL_CLOCK) != 0;
|
||||||
|
bool t0_load = (data & Z8_TMR_LOAD_T0) != 0;
|
||||||
|
bool t1_load = (data & Z8_TMR_LOAD_T1) != 0;
|
||||||
|
bool t0_enable = (data & Z8_TMR_ENABLE_T0) != 0;
|
||||||
|
bool t1_enable = (data & Z8_TMR_ENABLE_T1) != 0;
|
||||||
|
|
||||||
|
if (!t1_internal && ((data & Z8_TMR_TIN_MASK) == Z8_TMR_TIN_GATE))
|
||||||
|
{
|
||||||
|
if ((m_input[3] & Z8_P3_TIN) != 0)
|
||||||
|
t1_internal = true;
|
||||||
|
else
|
||||||
|
t1_enable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t0_load)
|
||||||
{
|
{
|
||||||
m_count[0] = m_t[0];
|
m_count[0] = m_t[0];
|
||||||
m_t0_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((m_pre[0] >> 2) + 1)));
|
m_pre_count[0] = m_pre[0] >> 2;
|
||||||
|
|
||||||
|
if ((m_pre[0] & Z8_PRE0_COUNT_MODULO_N) != 0)
|
||||||
|
{
|
||||||
|
unsigned prescaler = (m_pre[0] >> 2) ? (m_pre[0] >> 2) : 64;
|
||||||
|
unsigned count = (m_t[0] ? m_t[0] : 256) * prescaler;
|
||||||
|
logerror("(%04X): Load T0 at %.2f Hz\n", m_ppc, clock() / 8.0 / count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((data & Z8_TMR_TOUT_MASK) == Z8_TMR_TOUT_T0)
|
||||||
|
tout_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_t0_timer->enable(data & Z8_TMR_ENABLE_T0);
|
if (t0_enable)
|
||||||
|
{
|
||||||
|
if (t0_load || !m_internal_timer[0]->enabled())
|
||||||
|
timer_start<0>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
timer_stop<0>();
|
||||||
|
|
||||||
if (data & Z8_TMR_LOAD_T1)
|
if (t1_load)
|
||||||
{
|
{
|
||||||
m_count[1] = m_t[1];
|
m_count[1] = m_t[1];
|
||||||
m_t1_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((m_pre[1] >> 2) + 1)));
|
m_pre_count[1] = m_pre[1] >> 2;
|
||||||
|
|
||||||
|
if (t1_internal && (m_pre[1] & Z8_PRE0_COUNT_MODULO_N) != 0)
|
||||||
|
{
|
||||||
|
unsigned prescaler = (m_pre[1] >> 2) ? (m_pre[1] >> 2) : 64;
|
||||||
|
unsigned count = (m_t[1] ? m_t[1] : 256) * prescaler;
|
||||||
|
logerror("(%04X): Load T1 at %.2f Hz\n", m_ppc, clock() / 8.0 / count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((data & Z8_TMR_TOUT_MASK) == Z8_TMR_TOUT_T1)
|
||||||
|
tout_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_t1_timer->enable(data & Z8_TMR_ENABLE_T1);
|
if (t1_enable)
|
||||||
|
{
|
||||||
|
if (t1_internal && (t1_load || !m_internal_timer[1]->enabled()))
|
||||||
|
timer_start<1>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
timer_stop<1>();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t z8_device::t0_read()
|
uint8_t z8_device::t0_read()
|
||||||
{
|
{
|
||||||
return m_count[0];
|
if (!m_internal_timer[0]->enabled())
|
||||||
|
return m_count[0];
|
||||||
|
|
||||||
|
unsigned prescaler = (m_pre[0] >> 2) ? (m_pre[0] >> 2) : 64;
|
||||||
|
unsigned remaining = attotime_to_cycles(m_internal_timer[0]->remaining() / 4);
|
||||||
|
|
||||||
|
return remaining / prescaler + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void z8_device::t0_write(uint8_t data)
|
void z8_device::t0_write(uint8_t data)
|
||||||
@ -513,7 +668,13 @@ void z8_device::t0_write(uint8_t data)
|
|||||||
|
|
||||||
uint8_t z8_device::t1_read()
|
uint8_t z8_device::t1_read()
|
||||||
{
|
{
|
||||||
return m_count[1];
|
if (!m_internal_timer[1]->enabled())
|
||||||
|
return m_count[1];
|
||||||
|
|
||||||
|
unsigned prescaler = (m_pre[1] >> 2) ? (m_pre[1] >> 2) : 64;
|
||||||
|
unsigned remaining = attotime_to_cycles(m_internal_timer[1]->remaining() / 4);
|
||||||
|
|
||||||
|
return remaining / prescaler + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void z8_device::t1_write(uint8_t data)
|
void z8_device::t1_write(uint8_t data)
|
||||||
@ -623,12 +784,12 @@ void z8_device::register_pair_write(uint8_t offset, uint16_t data)
|
|||||||
m_regs->write_word_unaligned(offset, data);
|
m_regs->write_word_unaligned(offset, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t z8_device::get_working_register(int offset)
|
uint8_t z8_device::get_working_register(int offset) const
|
||||||
{
|
{
|
||||||
return (m_rp & 0xf0) | (offset & 0x0f);
|
return (m_rp & 0xf0) | (offset & 0x0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t z8_device::get_register(uint8_t offset)
|
uint8_t z8_device::get_register(uint8_t offset) const
|
||||||
{
|
{
|
||||||
if ((offset & 0xf0) == 0xe0)
|
if ((offset & 0xf0) == 0xe0)
|
||||||
return get_working_register(offset & 0x0f);
|
return get_working_register(offset & 0x0f);
|
||||||
@ -856,31 +1017,17 @@ const z8_device::z8_opcode_map z8_device::Z8601_OPCODE_MAP[256] =
|
|||||||
TIMER CALLBACKS
|
TIMER CALLBACKS
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
TIMER_CALLBACK_MEMBER( z8_device::t0_tick )
|
template <int T>
|
||||||
|
TIMER_CALLBACK_MEMBER(z8_device::timeout)
|
||||||
{
|
{
|
||||||
m_count[0]--;
|
timer_end<T>();
|
||||||
|
|
||||||
if (m_count[0] == 0)
|
if (m_pre[T] & Z8_PRE0_COUNT_MODULO_N)
|
||||||
|
timer_start<T>();
|
||||||
|
else
|
||||||
{
|
{
|
||||||
m_count[0] = m_t[0];
|
m_count[T] = 0;
|
||||||
attotime period = cycles_to_attotime(4 * ((m_pre[0] >> 2) + 1));
|
m_internal_timer[T]->enable(false);
|
||||||
m_t0_timer->adjust(period, 0, period);
|
|
||||||
m_t0_timer->enable(m_pre[0] & Z8_PRE0_COUNT_MODULO_N);
|
|
||||||
request_interrupt(4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TIMER_CALLBACK_MEMBER( z8_device::t1_tick )
|
|
||||||
{
|
|
||||||
m_count[1]--;
|
|
||||||
|
|
||||||
if (m_count[1] == 0)
|
|
||||||
{
|
|
||||||
m_count[1] = m_t[1];
|
|
||||||
attotime period = cycles_to_attotime(4 * ((m_pre[1] >> 2) + 1));
|
|
||||||
m_t1_timer->adjust(period, 0, period);
|
|
||||||
m_t1_timer->enable(m_pre[1] & Z8_PRE1_COUNT_MODULO_N);
|
|
||||||
request_interrupt(5);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -920,6 +1067,7 @@ void z8_device::device_start()
|
|||||||
state_add(Z8_PRE1, "PRE1", m_pre[1]);
|
state_add(Z8_PRE1, "PRE1", m_pre[1]);
|
||||||
state_add(Z8_T1, "T1", m_t[1]);
|
state_add(Z8_T1, "T1", m_t[1]);
|
||||||
state_add(Z8_TMR, "TMR", m_tmr);
|
state_add(Z8_TMR, "TMR", m_tmr);
|
||||||
|
state_add(Z8_TOUT, "TOUT", m_tout);
|
||||||
|
|
||||||
for (int regnum = 0; regnum < 16; regnum++)
|
for (int regnum = 0; regnum < 16; regnum++)
|
||||||
state_add(Z8_R0 + regnum, string_format("R%d", regnum).c_str(), m_fake_r[regnum]).callimport().callexport();
|
state_add(Z8_R0 + regnum, string_format("R%d", regnum).c_str(), m_fake_r[regnum]).callimport().callexport();
|
||||||
@ -932,16 +1080,16 @@ void z8_device::device_start()
|
|||||||
m_regs = &space(AS_IO);
|
m_regs = &space(AS_IO);
|
||||||
|
|
||||||
/* allocate timers */
|
/* allocate timers */
|
||||||
m_t0_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::t0_tick), this));
|
m_internal_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::timeout<0>), this));
|
||||||
m_t1_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::t1_tick), this));
|
m_internal_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::timeout<1>), this));
|
||||||
|
|
||||||
/* Clear state */
|
/* Clear state */
|
||||||
std::fill(std::begin(m_irq_line), std::end(m_irq_line), CLEAR_LINE);
|
std::fill(std::begin(m_irq_line), std::end(m_irq_line), CLEAR_LINE);
|
||||||
std::fill(std::begin(m_input), std::end(m_input), 0);
|
|
||||||
std::fill(std::begin(m_output), std::end(m_output), 0);
|
std::fill(std::begin(m_output), std::end(m_output), 0);
|
||||||
std::fill(std::begin(m_t), std::end(m_t), 0);
|
std::fill(std::begin(m_t), std::end(m_t), 0);
|
||||||
std::fill(std::begin(m_count), std::end(m_count), 0);
|
std::fill(std::begin(m_count), std::end(m_count), 0);
|
||||||
std::fill(std::begin(m_pre), std::end(m_pre), 0);
|
std::fill(std::begin(m_pre), std::end(m_pre), 0);
|
||||||
|
std::fill(std::begin(m_pre_count), std::end(m_pre_count), 0);
|
||||||
std::fill(std::begin(m_fake_r), std::end(m_fake_r), 0);
|
std::fill(std::begin(m_fake_r), std::end(m_fake_r), 0);
|
||||||
m_pc = 0;
|
m_pc = 0;
|
||||||
m_ppc = 0;
|
m_ppc = 0;
|
||||||
@ -952,6 +1100,7 @@ void z8_device::device_start()
|
|||||||
m_p2m = 0;
|
m_p2m = 0;
|
||||||
m_p3m = 0;
|
m_p3m = 0;
|
||||||
m_tmr = 0;
|
m_tmr = 0;
|
||||||
|
m_tout = true;
|
||||||
m_irq_taken = false;
|
m_irq_taken = false;
|
||||||
m_irq_initialized = false;
|
m_irq_initialized = false;
|
||||||
|
|
||||||
@ -968,8 +1117,10 @@ void z8_device::device_start()
|
|||||||
save_item(NAME(m_p3m));
|
save_item(NAME(m_p3m));
|
||||||
save_item(NAME(m_tmr));
|
save_item(NAME(m_tmr));
|
||||||
save_item(NAME(m_t));
|
save_item(NAME(m_t));
|
||||||
|
save_item(NAME(m_tout));
|
||||||
save_item(NAME(m_count));
|
save_item(NAME(m_count));
|
||||||
save_item(NAME(m_pre));
|
save_item(NAME(m_pre));
|
||||||
|
save_item(NAME(m_pre_count));
|
||||||
save_item(NAME(m_irq_line));
|
save_item(NAME(m_irq_line));
|
||||||
save_item(NAME(m_irq_taken));
|
save_item(NAME(m_irq_taken));
|
||||||
save_item(NAME(m_irq_initialized));
|
save_item(NAME(m_irq_initialized));
|
||||||
@ -1176,7 +1327,9 @@ void z8_device::device_reset()
|
|||||||
|
|
||||||
m_pre[0] &= ~Z8_PRE0_COUNT_MODULO_N;
|
m_pre[0] &= ~Z8_PRE0_COUNT_MODULO_N;
|
||||||
m_pre[1] &= ~(Z8_PRE1_COUNT_MODULO_N | Z8_PRE1_INTERNAL_CLOCK);
|
m_pre[1] &= ~(Z8_PRE1_COUNT_MODULO_N | Z8_PRE1_INTERNAL_CLOCK);
|
||||||
tmr_write(0x00);
|
m_tmr = 0x00;
|
||||||
|
timer_stop<0>();
|
||||||
|
timer_stop<1>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1244,29 +1397,60 @@ void z8_device::execute_set_input(int inputnum, int state)
|
|||||||
{
|
{
|
||||||
switch ( inputnum )
|
switch ( inputnum )
|
||||||
{
|
{
|
||||||
case INPUT_LINE_IRQ0:
|
case INPUT_LINE_IRQ0:
|
||||||
if (state != CLEAR_LINE && m_irq_line[0] == CLEAR_LINE)
|
if (state != CLEAR_LINE && m_irq_line[0] == CLEAR_LINE)
|
||||||
request_interrupt(0);
|
request_interrupt(0);
|
||||||
m_irq_line[0] = state;
|
m_irq_line[0] = state;
|
||||||
break;
|
|
||||||
|
|
||||||
case INPUT_LINE_IRQ1:
|
if (state != CLEAR_LINE && (m_input[3] & Z8_P3_IRQ0) != 0)
|
||||||
if (state != CLEAR_LINE && m_irq_line[1] == CLEAR_LINE)
|
m_input[3] &= ~Z8_P3_IRQ0;
|
||||||
request_interrupt(1);
|
else if (state == CLEAR_LINE && (m_input[3] & Z8_P3_IRQ0) == 0)
|
||||||
m_irq_line[1] = state;
|
m_input[3] |= Z8_P3_IRQ0;
|
||||||
break;
|
|
||||||
|
|
||||||
case INPUT_LINE_IRQ2:
|
break;
|
||||||
if (state != CLEAR_LINE && m_irq_line[2] == CLEAR_LINE)
|
|
||||||
request_interrupt(2);
|
|
||||||
m_irq_line[2] = state;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INPUT_LINE_IRQ3:
|
case INPUT_LINE_IRQ1:
|
||||||
if (state != CLEAR_LINE && m_irq_line[3] == CLEAR_LINE)
|
if (state != CLEAR_LINE && m_irq_line[1] == CLEAR_LINE)
|
||||||
request_interrupt(3);
|
request_interrupt(1);
|
||||||
m_irq_line[3] = state;
|
m_irq_line[1] = state;
|
||||||
break;
|
|
||||||
|
|
||||||
|
if (state != CLEAR_LINE && (m_input[3] & Z8_P3_IRQ1) != 0)
|
||||||
|
m_input[3] &= ~Z8_P3_IRQ1;
|
||||||
|
else if (state == CLEAR_LINE && (m_input[3] & Z8_P3_IRQ1) == 0)
|
||||||
|
m_input[3] |= Z8_P3_IRQ1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INPUT_LINE_IRQ2:
|
||||||
|
if (state != CLEAR_LINE && m_irq_line[2] == CLEAR_LINE)
|
||||||
|
request_interrupt(2);
|
||||||
|
m_irq_line[2] = state;
|
||||||
|
|
||||||
|
if (state != CLEAR_LINE && (m_input[3] & Z8_P3_IRQ2) != 0)
|
||||||
|
{
|
||||||
|
m_input[3] &= ~Z8_P3_IRQ2;
|
||||||
|
if ((m_pre[1] & Z8_PRE1_INTERNAL_CLOCK) == 0)
|
||||||
|
t1_trigger();
|
||||||
|
}
|
||||||
|
else if (state == CLEAR_LINE && (m_input[3] & Z8_P3_IRQ2) == 0)
|
||||||
|
{
|
||||||
|
m_input[3] |= Z8_P3_IRQ2;
|
||||||
|
if ((m_pre[1] & Z8_PRE1_INTERNAL_CLOCK) == 0 && (m_tmr & Z8_TMR_TIN_MASK) == Z8_TMR_TIN_GATE)
|
||||||
|
timer_start<1>();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INPUT_LINE_IRQ3:
|
||||||
|
if (state != CLEAR_LINE && m_irq_line[3] == CLEAR_LINE && (m_p3m & Z8_P3M_P3_SERIAL) == 0)
|
||||||
|
request_interrupt(3);
|
||||||
|
m_irq_line[3] = state;
|
||||||
|
|
||||||
|
if (state != CLEAR_LINE && (m_input[3] & Z8_P3_IRQ3) != 0)
|
||||||
|
m_input[3] &= ~Z8_P3_IRQ3;
|
||||||
|
else if (state == CLEAR_LINE && (m_input[3] & Z8_P3_IRQ3) == 0)
|
||||||
|
m_input[3] |= Z8_P3_IRQ3;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// license:BSD-3-Clause
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:Curt Coder
|
// copyright-holders:Curt Coder, AJR
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|
||||||
Zilog Z8 Single-Chip MCU emulation
|
Zilog Z8 Single-Chip MCU emulation
|
||||||
@ -32,7 +32,7 @@ protected:
|
|||||||
Z8_IMR, Z8_IRQ, Z8_IPR,
|
Z8_IMR, Z8_IRQ, Z8_IPR,
|
||||||
Z8_P0, Z8_P1, Z8_P2, Z8_P3,
|
Z8_P0, Z8_P1, Z8_P2, Z8_P3,
|
||||||
Z8_P01M, Z8_P3M, Z8_P2M,
|
Z8_P01M, Z8_P3M, Z8_P2M,
|
||||||
Z8_PRE0, Z8_T0, Z8_PRE1, Z8_T1, Z8_TMR,
|
Z8_PRE0, Z8_T0, Z8_PRE1, Z8_T1, Z8_TMR, Z8_TOUT,
|
||||||
|
|
||||||
Z8_R0, Z8_R1, Z8_R2, Z8_R3, Z8_R4, Z8_R5, Z8_R6, Z8_R7, Z8_R8, Z8_R9, Z8_R10, Z8_R11, Z8_R12, Z8_R13, Z8_R14, Z8_R15
|
Z8_R0, Z8_R1, Z8_R2, Z8_R3, Z8_R4, Z8_R5, Z8_R6, Z8_R7, Z8_R8, Z8_R9, Z8_R10, Z8_R11, Z8_R12, Z8_R13, Z8_R14, Z8_R15
|
||||||
};
|
};
|
||||||
@ -107,12 +107,14 @@ private:
|
|||||||
uint8_t m_t[2]; // initial values
|
uint8_t m_t[2]; // initial values
|
||||||
uint8_t m_count[2]; // current counts
|
uint8_t m_count[2]; // current counts
|
||||||
uint8_t m_pre[2]; // prescalers
|
uint8_t m_pre[2]; // prescalers
|
||||||
|
uint8_t m_pre_count[2]; // prescaler counts
|
||||||
|
bool m_tout; // toggle output
|
||||||
|
|
||||||
// fake registers
|
// fake registers
|
||||||
uint8_t m_fake_r[16]; // fake working registers
|
uint8_t m_fake_r[16]; // fake working registers
|
||||||
|
|
||||||
// interrupts
|
// interrupts
|
||||||
int m_irq_line[4]; // IRQ line state
|
int m_irq_line[4];
|
||||||
bool m_irq_taken;
|
bool m_irq_taken;
|
||||||
bool m_irq_initialized; // IRQ must be unlocked by EI after reset
|
bool m_irq_initialized; // IRQ must be unlocked by EI after reset
|
||||||
|
|
||||||
@ -120,11 +122,18 @@ private:
|
|||||||
int32_t m_icount; // instruction counter
|
int32_t m_icount; // instruction counter
|
||||||
|
|
||||||
// timers
|
// timers
|
||||||
emu_timer *m_t0_timer;
|
emu_timer *m_internal_timer[2];
|
||||||
emu_timer *m_t1_timer;
|
|
||||||
|
|
||||||
TIMER_CALLBACK_MEMBER( t0_tick );
|
void sio_tick();
|
||||||
TIMER_CALLBACK_MEMBER( t1_tick );
|
|
||||||
|
template <int T> void timer_start();
|
||||||
|
template <int T> void timer_stop();
|
||||||
|
template <int T> void timer_end();
|
||||||
|
void t1_trigger();
|
||||||
|
void tout_init();
|
||||||
|
void tout_toggle();
|
||||||
|
|
||||||
|
template <int T> TIMER_CALLBACK_MEMBER(timeout);
|
||||||
|
|
||||||
void request_interrupt(int irq);
|
void request_interrupt(int irq);
|
||||||
void take_interrupt(int irq);
|
void take_interrupt(int irq);
|
||||||
@ -173,8 +182,8 @@ private:
|
|||||||
inline uint16_t register_pair_read(uint8_t offset);
|
inline uint16_t register_pair_read(uint8_t offset);
|
||||||
inline void register_write(uint8_t offset, uint8_t data) { m_regs->write_byte(offset, data); }
|
inline void register_write(uint8_t offset, uint8_t data) { m_regs->write_byte(offset, data); }
|
||||||
inline void register_pair_write(uint8_t offset, uint16_t data);
|
inline void register_pair_write(uint8_t offset, uint16_t data);
|
||||||
inline uint8_t get_working_register(int offset);
|
inline uint8_t get_working_register(int offset) const;
|
||||||
inline uint8_t get_register(uint8_t offset);
|
inline uint8_t get_register(uint8_t offset) const;
|
||||||
inline uint8_t get_intermediate_register(int offset);
|
inline uint8_t get_intermediate_register(int offset);
|
||||||
inline void stack_push_byte(uint8_t src);
|
inline void stack_push_byte(uint8_t src);
|
||||||
inline void stack_push_word(uint16_t src);
|
inline void stack_push_word(uint16_t src);
|
||||||
|
Loading…
Reference in New Issue
Block a user