summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/z8
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/z8')
-rw-r--r--src/devices/cpu/z8/z8.cpp542
-rw-r--r--src/devices/cpu/z8/z8.h56
-rw-r--r--src/devices/cpu/z8/z8dasm.cpp5
3 files changed, 500 insertions, 103 deletions
diff --git a/src/devices/cpu/z8/z8.cpp b/src/devices/cpu/z8/z8.cpp
index d5e19fe831f..1359fea831f 100644
--- a/src/devices/cpu/z8/z8.cpp
+++ b/src/devices/cpu/z8/z8.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Curt Coder
+// copyright-holders:Curt Coder, AJR
/**********************************************************************
Zilog Z8 Single-Chip MCU emulation
@@ -11,8 +11,6 @@
TODO:
- strobed I/O
- - timer Tin/Tout modes
- - serial
- instruction pipeline
- internal diagnostic ROM in data space (requires high voltage reset)
@@ -33,14 +31,14 @@
#define Z8_P3_RDY0 0x20 /* not supported */
#define Z8_P3_RDY1 0x10 /* not supported */
#define Z8_P3_RDY2 0x40 /* not supported */
-#define Z8_P3_IRQ0 0x04 /* not supported */
-#define Z8_P3_IRQ1 0x08 /* not supported */
-#define Z8_P3_IRQ2 0x02 /* not supported */
-#define Z8_P3_IRQ3 0x01 /* not supported */
-#define Z8_P3_DI 0x01 /* not supported */
-#define Z8_P3_DO 0x80 /* not supported */
-#define Z8_P3_TIN 0x02 /* not supported */
-#define Z8_P3_TOUT 0x40 /* not supported */
+#define Z8_P3_IRQ0 0x04
+#define Z8_P3_IRQ1 0x08
+#define Z8_P3_IRQ2 0x02
+#define Z8_P3_IRQ3 0x01
+#define Z8_P3_SIN 0x01
+#define Z8_P3_SOUT 0x80
+#define Z8_P3_TIN 0x02
+#define Z8_P3_TOUT 0x40
#define Z8_P3_DM 0x10 /* not supported */
#define Z8_PRE0_COUNT_MODULO_N 0x01
@@ -52,15 +50,15 @@
#define Z8_TMR_ENABLE_T0 0x02
#define Z8_TMR_LOAD_T1 0x04
#define Z8_TMR_ENABLE_T1 0x08
-#define Z8_TMR_TIN_MASK 0x30 /* not supported */
-#define Z8_TMR_TIN_EXTERNAL_CLK 0x00 /* not supported */
-#define Z8_TMR_TIN_GATE 0x10 /* not supported */
-#define Z8_TMR_TIN_TRIGGER 0x20 /* not supported */
-#define Z8_TMR_TIN_RETRIGGER 0x30 /* not supported */
-#define Z8_TMR_TOUT_MASK 0xc0 /* not supported */
-#define Z8_TMR_TOUT_OFF 0x00 /* not supported */
-#define Z8_TMR_TOUT_T0 0x40 /* not supported */
-#define Z8_TMR_TOUT_T1 0x80 /* not supported */
+#define Z8_TMR_TIN_MASK 0x30
+#define Z8_TMR_TIN_EXTERNAL_CLK 0x00
+#define Z8_TMR_TIN_GATE 0x10
+#define Z8_TMR_TIN_TRIGGER 0x20
+#define Z8_TMR_TIN_RETRIGGER 0x30
+#define Z8_TMR_TOUT_MASK 0xc0
+#define Z8_TMR_TOUT_OFF 0x00
+#define Z8_TMR_TOUT_T0 0x40
+#define Z8_TMR_TOUT_T1 0x80
#define Z8_TMR_TOUT_INTERNAL_CLK 0xc0 /* not supported */
#define Z8_P01M_P0L_MODE_MASK 0x03
@@ -119,6 +117,7 @@ DEFINE_DEVICE_TYPE(UB8830D, ub8830d_device, "ub8830d", "UB8830D")
DEFINE_DEVICE_TYPE(Z8611, z8611_device, "z8611", "Zilog Z8611")
DEFINE_DEVICE_TYPE(Z8671, z8671_device, "z8671", "Zilog Z8671")
DEFINE_DEVICE_TYPE(Z8681, z8681_device, "z8681", "Zilog Z8681")
+DEFINE_DEVICE_TYPE(Z8682, z8682_device, "z8682", "Zilog Z8682")
/***************************************************************************
@@ -170,6 +169,7 @@ z8_device::z8_device(const machine_config &mconfig, device_type type, const char
, m_input_cb{{*this}, {*this}, {*this}, {*this}}
, m_output_cb{{*this}, {*this}, {*this}, {*this}}
, m_rom_size(rom_size)
+ , m_input{0xff, 0xff, 0xff, 0x0f}
{
assert(((rom_size - 1) & rom_size) == 0);
}
@@ -215,6 +215,23 @@ z8681_device::z8681_device(const machine_config &mconfig, const char *tag, devic
}
+z8682_device::z8682_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : z8_device(mconfig, Z8682, tag, owner, clock, 0x800, true)
+{
+}
+
+ROM_START(z8682)
+ // Zilog admits that this nominally ROMless type uses a "small internal ROM"
+ ROM_REGION(0x0800, "internal", ROMREGION_ERASEFF)
+ ROM_LOAD("testrom.bin", 0x0000, 0x0038, CRC(b2239f28) SHA1(9d27957ba0f15657eac5a7295157af6ee51cb261) BAD_DUMP) // typed in from "Z8 MCU Test Mode" application note
+ROM_END
+
+const tiny_rom_entry *z8682_device::device_rom_region() const
+{
+ return ROM_NAME(z8682);
+}
+
+
std::unique_ptr<util::disasm_interface> z8_device::create_disassembler()
{
return std::make_unique<z8_disassembler>();
@@ -418,43 +435,257 @@ void z8_device::p2_write(uint8_t data)
m_output_cb[2](0, data & mask, mask);
}
+void z8_device::p3_update_output()
+{
+ uint8_t output = m_output[3] & 0xf0;
+
+ if ((m_tmr & Z8_TMR_TOUT_MASK) != Z8_TMR_TOUT_OFF)
+ output = (output & ~Z8_P3_TOUT) | (m_tout ? Z8_P3_TOUT : 0);
+ if ((m_p3m & Z8_P3M_P3_SERIAL) != 0)
+ output = (output & ~Z8_P3_SOUT) | ((m_transmit_sr == 0 || BIT(m_transmit_sr, 0)) ? Z8_P3_SOUT : 0);
+
+ if (m_p3_output != output)
+ {
+ m_output_cb[3](0, output, output ^ m_p3_output);
+ m_p3_output = output;
+ }
+}
+
uint8_t z8_device::p3_read()
{
uint8_t mask = 0x0f;
+ uint8_t inputs = m_input[3] & m_input_cb[3](0, mask);
// TODO: special port 3 modes
//if (!(m_p3m & 0x7c))
//{
//}
- if (mask)
- m_input[3] = m_input_cb[3](0, mask);
-
- return (m_input[3] & mask) | (m_output[3] & ~mask);
+ return (inputs & mask) | (m_p3_output & ~mask);
}
void z8_device::p3_write(uint8_t data)
{
- uint8_t mask = 0xf0;
-
- m_output[3] = data;
+ m_output[3] = data & 0xf0;
// TODO: special port 3 modes
//if (!(m_p3m & 0x7c))
//{
//}
- if (mask)
- m_output_cb[3](0, data & mask, mask);
+ p3_update_output();
+}
+
+bool z8_device::get_serial_in()
+{
+ return (m_input[3] & Z8_P3_SIN) != 0;
+}
+
+void z8_device::sio_receive()
+{
+ if (m_receive_started)
+ {
+ m_receive_count = (m_receive_count + 1) & 15;
+ if (m_receive_count == 8)
+ {
+ if (m_receive_sr == 0)
+ {
+ if (!get_serial_in())
+ {
+ // start bit validated
+ m_receive_sr |= 1 << 9;
+ m_receive_parity = false;
+ }
+ else
+ {
+ // false start bit
+ m_receive_started = false;
+ m_receive_count = 0;
+ }
+ }
+ else
+ {
+ // shift in data, parity or stop bit
+ m_receive_sr >>= 1;
+ if (get_serial_in())
+ m_receive_sr |= 1 << 9;
+
+ if (BIT(m_receive_sr, 0))
+ {
+ // received full character
+ m_receive_buffer = (m_receive_sr & 0x1fe) >> 1;
+ request_interrupt(3);
+ m_receive_started = false;
+ m_receive_count = 0;
+ }
+ else
+ {
+ if (BIT(m_receive_sr, 9))
+ m_receive_parity = !m_receive_parity;
+
+ // parity replaces received bit 7 if selected
+ if (BIT(m_receive_sr, 1) && (m_p3m & Z8_P3M_PARITY) != 0)
+ {
+ if (m_receive_parity)
+ m_receive_sr |= 1 << 9;
+ else
+ m_receive_sr &= ~(1 << 9);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // start bit is high-low transition
+ m_receive_sr >>= 1;
+ if (get_serial_in())
+ m_receive_sr |= 1 << 9;
+ else if (BIT(m_receive_sr, 8))
+ {
+ m_receive_started = true;
+ m_receive_sr = 0;
+ m_receive_count = 0;
+ }
+ }
+}
+
+void z8_device::sio_transmit()
+{
+ if (m_transmit_sr == 0)
+ return;
+
+ m_transmit_count = (m_transmit_count + 1) & 15;
+ if (m_transmit_count == 0)
+ {
+ m_transmit_sr >>= 1;
+ if (m_transmit_sr == 0)
+ request_interrupt(4);
+ else
+ {
+ // parity replaces received bit 7 if selected
+ if ((m_transmit_sr >> 1) == 3 && (m_p3m & Z8_P3M_PARITY) != 0)
+ {
+ if (m_transmit_parity)
+ m_transmit_sr |= 1;
+ else
+ m_transmit_sr &= ~1;
+ }
+ else if (BIT(m_transmit_sr, 0))
+ m_transmit_parity = !m_transmit_parity;
+
+ // serial output
+ p3_update_output();
+ }
+ }
}
uint8_t z8_device::sio_read()
{
- return 0xff;
+ return m_receive_buffer;
}
void z8_device::sio_write(uint8_t data)
{
+ // overwrite shift register with data + 1 start bit + 2 stop bits
+ m_transmit_sr = (m_transmit_sr & 1) | (uint16_t(data) << 2) | (3 << 10);
+ m_transmit_parity = false;
+
+ // synchronize the shift clock
+ m_transmit_count = 15;
+}
+
+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_receive();
+ sio_transmit();
+ }
+ 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;
+ p3_update_output();
+}
+
+void z8_device::tout_toggle()
+{
+ m_tout = !m_tout;
+ p3_update_output();
}
uint8_t z8_device::tmr_read()
@@ -464,28 +695,80 @@ uint8_t z8_device::tmr_read()
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
+
+ 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 (data & Z8_TMR_LOAD_T0)
+ 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_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_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()
{
- 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)
@@ -495,7 +778,13 @@ void z8_device::t0_write(uint8_t data)
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)
@@ -505,12 +794,28 @@ void z8_device::t1_write(uint8_t data)
void z8_device::pre0_write(uint8_t data)
{
- m_pre[0] = data;
+ if (m_internal_timer[0]->enabled())
+ {
+ timer_stop<0>();
+ m_pre[0] = data;
+ timer_start<0>();
+ }
+ else
+ m_pre[0] = data;
}
void z8_device::pre1_write(uint8_t data)
{
+ bool was_enabled = m_internal_timer[1]->enabled();
+ if (was_enabled)
+ timer_stop<1>();
+
m_pre[1] = data;
+
+ if ((data & Z8_PRE1_INTERNAL_CLOCK) != 0
+ ? (m_tmr & Z8_TMR_ENABLE_T1) != 0
+ : was_enabled && (m_tmr & Z8_TMR_TIN_MASK) != Z8_TMR_TIN_EXTERNAL_CLK)
+ timer_start<1>();
}
void z8_device::p01m_write(uint8_t data)
@@ -525,7 +830,16 @@ void z8_device::p2m_write(uint8_t data)
void z8_device::p3m_write(uint8_t data)
{
+ if ((data & Z8_P3M_P3_SERIAL) == 0)
+ {
+ m_transmit_sr = 0;
+ m_transmit_count = 0;
+ m_receive_started = false;
+ m_receive_count = 0;
+ }
+
m_p3m = data;
+ p3_update_output();
}
void z8_device::ipr_write(uint8_t data)
@@ -605,12 +919,12 @@ void z8_device::register_pair_write(uint8_t offset, uint16_t 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);
}
-uint8_t z8_device::get_register(uint8_t offset)
+uint8_t z8_device::get_register(uint8_t offset) const
{
if ((offset & 0xf0) == 0xe0)
return get_working_register(offset & 0x0f);
@@ -838,29 +1152,17 @@ const z8_device::z8_opcode_map z8_device::Z8601_OPCODE_MAP[256] =
TIMER CALLBACKS
***************************************************************************/
-TIMER_CALLBACK_MEMBER( z8_device::t0_tick )
+template <int T>
+TIMER_CALLBACK_MEMBER(z8_device::timeout)
{
- m_count[0]--;
-
- if (m_count[0] == 0)
- {
- m_count[0] = m_t[0];
- m_t0_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((m_pre[0] >> 2) + 1)));
- m_t0_timer->enable(m_pre[0] & Z8_PRE0_COUNT_MODULO_N);
- request_interrupt(4);
- }
-}
+ timer_end<T>();
-TIMER_CALLBACK_MEMBER( z8_device::t1_tick )
-{
- m_count[1]--;
-
- if (m_count[1] == 0)
+ if (m_pre[T] & Z8_PRE0_COUNT_MODULO_N)
+ timer_start<T>();
+ else
{
- m_count[1] = m_t[1];
- m_t1_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((m_pre[1] >> 2) + 1)));
- m_t1_timer->enable(m_pre[1] & Z8_PRE0_COUNT_MODULO_N);
- request_interrupt(5);
+ m_count[T] = 0;
+ m_internal_timer[T]->enable(false);
}
}
@@ -900,6 +1202,7 @@ void z8_device::device_start()
state_add(Z8_PRE1, "PRE1", m_pre[1]);
state_add(Z8_T1, "T1", m_t[1]);
state_add(Z8_TMR, "TMR", m_tmr);
+ state_add(Z8_TOUT, "TOUT", m_tout);
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();
@@ -912,16 +1215,16 @@ void z8_device::device_start()
m_regs = &space(AS_IO);
/* allocate timers */
- m_t0_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::t0_tick), this));
- m_t1_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::t1_tick), this));
+ m_internal_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::timeout<0>), this));
+ m_internal_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::timeout<1>), this));
/* Clear state */
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_t), std::end(m_t), 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_count), std::end(m_pre_count), 0);
std::fill(std::begin(m_fake_r), std::end(m_fake_r), 0);
m_pc = 0;
m_ppc = 0;
@@ -931,7 +1234,17 @@ void z8_device::device_start()
m_p01m = 0;
m_p2m = 0;
m_p3m = 0;
+ m_p3_output = 0;
m_tmr = 0;
+ m_tout = true;
+ m_transmit_sr = 0;
+ m_transmit_count = 0;
+ m_transmit_parity = false;
+ m_receive_buffer = 0;
+ m_receive_sr = 0;
+ m_receive_count = 0;
+ m_receive_parity = false;
+ m_receive_started = false;
m_irq_taken = false;
m_irq_initialized = false;
@@ -946,10 +1259,21 @@ void z8_device::device_start()
save_item(NAME(m_p01m));
save_item(NAME(m_p2m));
save_item(NAME(m_p3m));
+ save_item(NAME(m_p3_output));
save_item(NAME(m_tmr));
save_item(NAME(m_t));
+ save_item(NAME(m_tout));
+ save_item(NAME(m_transmit_sr));
+ save_item(NAME(m_transmit_count));
+ save_item(NAME(m_transmit_parity));
+ save_item(NAME(m_receive_buffer));
+ save_item(NAME(m_receive_sr));
+ save_item(NAME(m_receive_count));
+ save_item(NAME(m_receive_parity));
+ save_item(NAME(m_receive_started));
save_item(NAME(m_count));
save_item(NAME(m_pre));
+ save_item(NAME(m_pre_count));
save_item(NAME(m_irq_line));
save_item(NAME(m_irq_taken));
save_item(NAME(m_irq_initialized));
@@ -979,6 +1303,7 @@ void z8_device::take_interrupt(int irq)
// acknowledge the IRQ
m_irq &= ~(1 << irq);
+ standard_irq_callback(irq);
// get the interrupt vector address
uint16_t vector = irq * 2;
@@ -1149,14 +1474,16 @@ void z8_device::device_reset()
m_imr &= ~Z8_IMR_ENABLE;
m_irq_initialized = false;
+ m_pre[0] &= ~Z8_PRE0_COUNT_MODULO_N;
+ m_pre[1] &= ~(Z8_PRE1_COUNT_MODULO_N | Z8_PRE1_INTERNAL_CLOCK);
+ m_tmr = 0x00;
+ timer_stop<0>();
+ timer_stop<1>();
+
+ m_output[3] = 0xf0;
p01m_write(0x4d);
p2m_write(0xff);
p3m_write(0x00);
- p3_write(m_output[3] | 0xf0);
-
- m_pre[0] &= ~Z8_PRE0_COUNT_MODULO_N;
- m_pre[1] &= ~(Z8_PRE1_COUNT_MODULO_N | Z8_PRE1_INTERNAL_CLOCK);
- tmr_write(0x00);
}
@@ -1180,7 +1507,7 @@ void z8_device::state_import(const device_state_entry &entry)
case Z8_R0: case Z8_R1: case Z8_R2: case Z8_R3: case Z8_R4: case Z8_R5: case Z8_R6: case Z8_R7: case Z8_R8: case Z8_R9: case Z8_R10: case Z8_R11: case Z8_R12: case Z8_R13: case Z8_R14: case Z8_R15:
{
auto dis = machine().disable_side_effects();
- register_write(m_rp + (entry.index() - Z8_R0), m_fake_r[entry.index() - Z8_R0]);
+ register_write((m_rp & 0xf0) + (entry.index() - Z8_R0), m_fake_r[entry.index() - Z8_R0]);
break;
}
@@ -1196,7 +1523,7 @@ void z8_device::state_export(const device_state_entry &entry)
case Z8_R0: case Z8_R1: case Z8_R2: case Z8_R3: case Z8_R4: case Z8_R5: case Z8_R6: case Z8_R7: case Z8_R8: case Z8_R9: case Z8_R10: case Z8_R11: case Z8_R12: case Z8_R13: case Z8_R14: case Z8_R15:
{
auto dis = machine().disable_side_effects();
- m_fake_r[entry.index() - Z8_R0] = register_read(m_rp + (entry.index() - Z8_R0));
+ m_fake_r[entry.index() - Z8_R0] = register_read((m_rp & 0xf0) + (entry.index() - Z8_R0));
break;
}
@@ -1224,29 +1551,60 @@ void z8_device::execute_set_input(int inputnum, int state)
{
switch ( inputnum )
{
- case INPUT_LINE_IRQ0:
- if (state != CLEAR_LINE && m_irq_line[0] == CLEAR_LINE)
- request_interrupt(0);
- m_irq_line[0] = state;
- break;
+ case INPUT_LINE_IRQ0:
+ if (state != CLEAR_LINE && m_irq_line[0] == CLEAR_LINE)
+ request_interrupt(0);
+ m_irq_line[0] = state;
- case INPUT_LINE_IRQ1:
- if (state != CLEAR_LINE && m_irq_line[1] == CLEAR_LINE)
- request_interrupt(1);
- m_irq_line[1] = state;
- break;
+ if (state != CLEAR_LINE && (m_input[3] & Z8_P3_IRQ0) != 0)
+ m_input[3] &= ~Z8_P3_IRQ0;
+ else if (state == CLEAR_LINE && (m_input[3] & Z8_P3_IRQ0) == 0)
+ m_input[3] |= Z8_P3_IRQ0;
- case INPUT_LINE_IRQ2:
- if (state != CLEAR_LINE && m_irq_line[2] == CLEAR_LINE)
- request_interrupt(2);
- m_irq_line[2] = state;
- break;
+ break;
- case INPUT_LINE_IRQ3:
- if (state != CLEAR_LINE && m_irq_line[3] == CLEAR_LINE)
- request_interrupt(3);
- m_irq_line[3] = state;
- break;
+ case INPUT_LINE_IRQ1:
+ if (state != CLEAR_LINE && m_irq_line[1] == CLEAR_LINE)
+ request_interrupt(1);
+ m_irq_line[1] = state;
+ 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;
}
}
diff --git a/src/devices/cpu/z8/z8.h b/src/devices/cpu/z8/z8.h
index 0bdd235d7c2..c74f3ec839f 100644
--- a/src/devices/cpu/z8/z8.h
+++ b/src/devices/cpu/z8/z8.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Curt Coder
+// copyright-holders:Curt Coder, AJR
/**********************************************************************
Zilog Z8 Single-Chip MCU emulation
@@ -32,7 +32,7 @@ protected:
Z8_IMR, Z8_IRQ, Z8_IPR,
Z8_P0, Z8_P1, Z8_P2, Z8_P3,
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
};
@@ -101,18 +101,33 @@ private:
uint8_t m_p01m; // port 0/1 mode
uint8_t m_p2m; // port 2 mode
uint8_t m_p3m; // port 3 mode
+ uint8_t m_p3_output; // port 3 output (alternate functions included)
// timer registers
uint8_t m_tmr; // timer mode
uint8_t m_t[2]; // initial values
uint8_t m_count[2]; // current counts
uint8_t m_pre[2]; // prescalers
+ uint8_t m_pre_count[2]; // prescaler counts
+ bool m_tout; // toggle output
+
+ // serial transmitter registers
+ uint16_t m_transmit_sr; // transmitter shift register
+ uint8_t m_transmit_count; // counter for transmitter timing
+ bool m_transmit_parity; // transmitter parity calculation
+
+ // serial receiver registers
+ uint8_t m_receive_buffer; // received character
+ uint16_t m_receive_sr; // receiver shift register
+ uint8_t m_receive_count; // counter for receiver timing
+ bool m_receive_parity; // receiver parity calculation
+ bool m_receive_started; // true if receiver has seen start bit
// fake registers
uint8_t m_fake_r[16]; // fake working registers
// interrupts
- int m_irq_line[4]; // IRQ line state
+ int m_irq_line[4];
bool m_irq_taken;
bool m_irq_initialized; // IRQ must be unlocked by EI after reset
@@ -120,11 +135,20 @@ private:
int32_t m_icount; // instruction counter
// timers
- emu_timer *m_t0_timer;
- emu_timer *m_t1_timer;
+ emu_timer *m_internal_timer[2];
+
+ bool get_serial_in();
+ void sio_receive();
+ void sio_transmit();
+
+ 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();
- TIMER_CALLBACK_MEMBER( t0_tick );
- TIMER_CALLBACK_MEMBER( t1_tick );
+ template <int T> TIMER_CALLBACK_MEMBER(timeout);
void request_interrupt(int irq);
void take_interrupt(int irq);
@@ -138,6 +162,7 @@ private:
void p2_write(uint8_t data);
uint8_t p3_read();
void p3_write(uint8_t data);
+ void p3_update_output();
uint8_t sio_read();
void sio_write(uint8_t data);
uint8_t tmr_read();
@@ -173,8 +198,8 @@ private:
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_pair_write(uint8_t offset, uint16_t data);
- inline uint8_t get_working_register(int offset);
- inline uint8_t get_register(uint8_t offset);
+ inline uint8_t get_working_register(int offset) const;
+ inline uint8_t get_register(uint8_t offset) const;
inline uint8_t get_intermediate_register(int offset);
inline void stack_push_byte(uint8_t src);
inline void stack_push_word(uint16_t src);
@@ -396,6 +421,16 @@ public:
};
+class z8682_device : public z8_device
+{
+public:
+ z8682_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ const tiny_rom_entry *device_rom_region() const override;
+};
+
+
// Zilog Z8601
DECLARE_DEVICE_TYPE(Z8601, z8601_device)
@@ -411,4 +446,7 @@ DECLARE_DEVICE_TYPE(Z8671, z8671_device)
// Zilog Z8681 ROMless
DECLARE_DEVICE_TYPE(Z8681, z8681_device)
+// Zilog Z8682 ROMless (boot to 0812H)
+DECLARE_DEVICE_TYPE(Z8682, z8682_device)
+
#endif // MAME_CPU_Z8_Z8_H
diff --git a/src/devices/cpu/z8/z8dasm.cpp b/src/devices/cpu/z8/z8dasm.cpp
index 35d18fab880..08e50ca1eae 100644
--- a/src/devices/cpu/z8/z8dasm.cpp
+++ b/src/devices/cpu/z8/z8dasm.cpp
@@ -39,6 +39,7 @@ const char *const z8_disassembler::CONDITION_CODE[16] =
***************************************************************************/
#define r "R%u"
+#define rr "RR%u"
#define Ir "@R%u"
#define R "%02Xh"
#define RR "%02Xh"
@@ -64,7 +65,7 @@ const char *const z8_disassembler::CONDITION_CODE[16] =
#define arg_Ir(_value) ARG(Ir, _value)
#define arg_Irr(_value) ARG(Irr, _value & 0x0f)
#define arg_R(_value) if ((_value & 0xf0) == 0xe0) ARG(r, _value & 0x0f) else if ((_value < 4) || (_value >= 0xf0)) arg_name(_value) else ARG(R, _value)
-#define arg_RR(_value) if ((_value & 0xf0) == 0xe0) ARG(r, _value & 0x0f) else ARG(R, _value)
+#define arg_RR(_value) if ((_value & 0xf0) == 0xe0) ARG(rr, _value & 0x0f) else ARG(R, _value)
#define arg_IR(_value) if ((_value & 0xf0) == 0xe0) ARG(Ir, _value & 0x0f) else ARG(IR, _value)
#define arg_IRR(_value) if ((_value & 0xf0) == 0xe0) ARG(Irr, _value & 0x0f) else ARG(IRR, _value)
#define arg_IM(_value) ARG(IM, _value)
@@ -366,7 +367,7 @@ offs_t z8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0xf2: illegal; break;
case 0xf3: mnemonic("LD"); arg_Ir(B0H); arg_r(B0L); bytes(2); break;
case 0xf4: illegal; break;
- case 0xf5: mnemonic("LD"); arg_IR(B0); arg_R(B1); bytes(3); break;
+ case 0xf5: mnemonic("LD"); arg_IR(B1); arg_R(B0); bytes(3); break;
case 0xf6: illegal; break;
case 0xf7: illegal; break;
case 0xf8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break;