summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/z8/z8.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/z8/z8.cpp')
-rw-r--r--src/devices/cpu/z8/z8.cpp100
1 files changed, 70 insertions, 30 deletions
diff --git a/src/devices/cpu/z8/z8.cpp b/src/devices/cpu/z8/z8.cpp
index f958754537c..adf82562f04 100644
--- a/src/devices/cpu/z8/z8.cpp
+++ b/src/devices/cpu/z8/z8.cpp
@@ -15,12 +15,24 @@
- internal diagnostic ROM in data space (requires high voltage reset)
- what really happens when register pairs are unaligned?
+ Note that A8–A15 outputs are not enabled on Port 0 upon reset, except
+ on some later ROMless versions such as Z8691. This may redirect
+ external memory accesses, including program fetches, to FFxx until
+ P01M is written to. Z8681 is particularly affected by this.
+
*/
#include "emu.h"
#include "z8.h"
#include "z8dasm.h"
-#include "debugger.h"
+
+#define LOG_TIMER (1U << 1)
+#define LOG_RECEIVE (1U << 2)
+#define LOG_TRANSMIT (1U << 3)
+#define LOG_IRQ (1U << 4)
+
+#define VERBOSE 0
+#include "logmacro.h"
/***************************************************************************
CONSTANTS
@@ -119,6 +131,7 @@ 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")
+DEFINE_DEVICE_TYPE(Z86E02, z86e02_device, "z86e02", "Zilog Z86E02")
/***************************************************************************
@@ -138,6 +151,7 @@ void z8_device::preprogrammed_map(address_map &map)
void z8_device::register_map(address_map &map)
{
+ map.unmap_value_high();
map(0x00, 0x00).rw(FUNC(z8_device::p0_read), FUNC(z8_device::p0_write));
map(0x01, 0x01).rw(FUNC(z8_device::p1_read), FUNC(z8_device::p1_write));
map(0x02, 0x02).rw(FUNC(z8_device::p2_read), FUNC(z8_device::p2_write));
@@ -167,7 +181,7 @@ z8_device::z8_device(const machine_config &mconfig, device_type type, const char
, m_program_config("program", ENDIANNESS_BIG, 8, 16, 0, preprogrammed ? address_map_constructor(FUNC(z8_device::preprogrammed_map), this) : address_map_constructor(FUNC(z8_device::program_map), this))
, m_data_config("data", ENDIANNESS_BIG, 8, 16, 0)
, m_register_config("register", ENDIANNESS_BIG, 8, 8, 0, address_map_constructor(FUNC(z8_device::register_map), this))
- , m_input_cb(*this)
+ , m_input_cb(*this, 0xff)
, m_output_cb(*this)
, m_rom_size(rom_size)
, m_input{0xff, 0xff, 0xff, 0x0f}
@@ -233,6 +247,12 @@ const tiny_rom_entry *z8682_device::device_rom_region() const
}
+z86e02_device::z86e02_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : z8_device(mconfig, Z86E02, tag, owner, clock, 0x200, false)
+{
+}
+
+
std::unique_ptr<util::disasm_interface> z8_device::create_disassembler()
{
return std::make_unique<z8_disassembler>();
@@ -286,7 +306,7 @@ uint16_t z8_device::mask_external_address(uint16_t addr)
uint8_t z8_device::fetch()
{
uint16_t real_pc = (m_pc < m_rom_size) ? m_pc : mask_external_address(m_pc);
- uint8_t data = m_cache->read_byte(real_pc);
+ uint8_t data = m_cache.read_byte(real_pc);
m_pc++;
@@ -299,7 +319,7 @@ uint8_t z8_device::fetch_opcode()
m_ppc = (m_pc < m_rom_size) ? m_pc : mask_external_address(m_pc);
debugger_instruction_hook(m_ppc);
- uint8_t data = m_cache->read_byte(m_ppc);
+ uint8_t data = m_cache.read_byte(m_ppc);
m_pc++;
@@ -319,7 +339,7 @@ uint16_t z8_device::fetch_word()
uint8_t z8_device::p0_read()
{
- uint8_t data = 0xff;
+ uint8_t data = 0;
uint8_t mask = 0;
switch (m_p01m & Z8_P01M_P0L_MODE_MASK)
@@ -373,7 +393,7 @@ void z8_device::p0_write(uint8_t data)
uint8_t z8_device::p1_read()
{
- uint8_t data = 0xff;
+ uint8_t data = 0;
uint8_t mask = 0;
switch (m_p01m & Z8_P01M_P1_MODE_MASK)
@@ -496,6 +516,7 @@ void z8_device::sio_receive()
// start bit validated
m_receive_sr |= 1 << 9;
m_receive_parity = false;
+ LOGMASKED(LOG_RECEIVE, "Start bit validated\n");
}
else
{
@@ -518,6 +539,7 @@ void z8_device::sio_receive()
request_interrupt(3);
m_receive_started = false;
m_receive_count = 0;
+ LOGMASKED(LOG_RECEIVE, "Character received: %02X\n", m_receive_buffer);
}
else
{
@@ -527,11 +549,14 @@ void z8_device::sio_receive()
// parity replaces received bit 7 if selected
if (BIT(m_receive_sr, 1) && (m_p3m & Z8_P3M_PARITY) != 0)
{
+ LOGMASKED(LOG_RECEIVE, "%d parity bit shifted in\n", BIT(m_receive_sr, 9));
if (m_receive_parity)
m_receive_sr |= 1 << 9;
else
m_receive_sr &= ~(1 << 9);
}
+ else
+ LOGMASKED(LOG_RECEIVE, "%d data bit shifted in\n", BIT(m_receive_sr, 9));
}
}
}
@@ -544,6 +569,7 @@ void z8_device::sio_receive()
m_receive_sr |= 1 << 9;
else if (BIT(m_receive_sr, 8))
{
+ LOGMASKED(LOG_RECEIVE, "Start bit noticed\n");
m_receive_started = true;
m_receive_sr = 0;
m_receive_count = 0;
@@ -561,7 +587,10 @@ void z8_device::sio_transmit()
{
m_transmit_sr >>= 1;
if (m_transmit_sr == 0)
+ {
+ LOGMASKED(LOG_TRANSMIT, "Transmit register empty\n");
request_interrupt(4);
+ }
else
{
// parity replaces received bit 7 if selected
@@ -571,9 +600,15 @@ void z8_device::sio_transmit()
m_transmit_sr |= 1;
else
m_transmit_sr &= ~1;
+ LOGMASKED(LOG_TRANSMIT, "%d parity bit shifted out\n", BIT(m_transmit_sr, 0));
+ }
+ else
+ {
+ LOGMASKED(LOG_TRANSMIT, "%d %s bit shifted out\n", BIT(m_transmit_sr, 0),
+ BIT(m_transmit_sr, 10) ? "start" : m_transmit_sr > 3 ? "data" : "stop");
+ if (BIT(m_transmit_sr, 0))
+ m_transmit_parity = !m_transmit_parity;
}
- else if (BIT(m_transmit_sr, 0))
- m_transmit_parity = !m_transmit_parity;
// serial output
p3_update_output();
@@ -588,6 +623,8 @@ uint8_t z8_device::sio_read()
void z8_device::sio_write(uint8_t data)
{
+ LOGMASKED(LOG_TRANSMIT, "(%04X): Character to transmit: %02X\n", m_ppc, 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;
@@ -665,7 +702,7 @@ void z8_device::t1_trigger()
case Z8_TMR_TIN_TRIGGER:
if (m_internal_timer[1]->enabled())
break;
-
+ [[fallthrough]];
case Z8_TMR_TIN_RETRIGGER:
if ((m_tmr & Z8_TMR_ENABLE_T1) != 0)
{
@@ -721,7 +758,7 @@ void z8_device::tmr_write(uint8_t data)
{
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);
+ LOGMASKED(LOG_TIMER, "(%04X): Load T0 at %.2f Hz\n", m_ppc, clock() / 8.0 / count);
}
if ((data & Z8_TMR_TOUT_MASK) == Z8_TMR_TOUT_T0)
@@ -745,7 +782,7 @@ void z8_device::tmr_write(uint8_t data)
{
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);
+ LOGMASKED(LOG_TIMER, "(%04X): Load T1 at %.2f Hz\n", m_ppc, clock() / 8.0 / count);
}
if ((data & Z8_TMR_TOUT_MASK) == Z8_TMR_TOUT_T1)
@@ -912,12 +949,12 @@ void z8_device::spl_write(uint8_t data)
uint16_t z8_device::register_pair_read(uint8_t offset)
{
- return m_regs->read_word_unaligned(offset);
+ return m_regs.read_word_unaligned(offset);
}
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) const
@@ -956,7 +993,7 @@ void z8_device::stack_push_byte(uint8_t src)
m_sp.w = sp;
// @SP <- src
- m_data->write_byte(mask_external_address(sp), src);
+ m_data.write_byte(mask_external_address(sp), src);
}
}
@@ -978,7 +1015,7 @@ void z8_device::stack_push_word(uint16_t src)
m_sp.w = sp;
// @SP <- src
- m_data->write_word_unaligned(mask_external_address(sp), src);
+ m_data.write_word_unaligned(mask_external_address(sp), src);
}
}
@@ -999,7 +1036,7 @@ uint8_t z8_device::stack_pop_byte()
{
// @SP <- src
uint16_t sp = m_sp.w;
- uint8_t byte = m_data->read_byte(mask_external_address(sp));
+ uint8_t byte = m_data.read_byte(mask_external_address(sp));
// SP <- SP + 1 (postincrement)
m_sp.w = sp + 1;
@@ -1025,7 +1062,7 @@ uint16_t z8_device::stack_pop_word()
{
// @SP <- src
uint16_t sp = m_sp.w;
- uint16_t word = m_data->read_word_unaligned(mask_external_address(sp));
+ uint16_t word = m_data.read_word_unaligned(mask_external_address(sp));
// SP <- SP + 2 (postincrement)
m_sp.w = sp + 2;
@@ -1173,16 +1210,12 @@ TIMER_CALLBACK_MEMBER(z8_device::timeout)
void z8_device::device_start()
{
- m_input_cb.resolve_all_safe(0xff);
- m_output_cb.resolve_all_safe();
-
/* set up the state table */
{
state_add(Z8_PC, "PC", m_pc).callimport();
state_add(STATE_GENPC, "GENPC", m_pc).callimport().noshow();
state_add(STATE_GENPCBASE, "CURPC", m_ppc).callimport().noshow();
state_add(Z8_SP, "SP", m_sp.w);
- state_add(STATE_GENSP, "GENSP", m_sp.w).noshow();
state_add(Z8_RP, "RP", m_rp);
state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).noshow().formatstr("%6s");
state_add(Z8_IMR, "IMR", m_imr);
@@ -1219,14 +1252,14 @@ void z8_device::device_start()
}
/* find address spaces */
- m_program = &space(AS_PROGRAM);
- m_cache = m_program->cache<0, 0, ENDIANNESS_BIG>();
- m_data = has_space(AS_DATA) ? &space(AS_DATA) : m_program;
- m_regs = &space(AS_IO);
+ space(AS_PROGRAM).cache(m_cache);
+ space(AS_PROGRAM).specific(m_program);
+ space(has_space(AS_DATA) ? AS_DATA : AS_PROGRAM).specific(m_data);
+ space(AS_IO).specific(m_regs);
/* allocate timers */
- 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));
+ m_internal_timer[0] = timer_alloc(FUNC(z8_device::timeout<0>), this);
+ m_internal_timer[1] = timer_alloc(FUNC(z8_device::timeout<1>), this);
/* Clear state */
std::fill(std::begin(m_irq_line), std::end(m_irq_line), CLEAR_LINE);
@@ -1299,7 +1332,10 @@ void z8_device::request_interrupt(int irq)
assert(irq >= 0 && irq < 6);
if (m_irq_initialized)
+ {
m_irq |= 1 << irq;
+ LOGMASKED(LOG_IRQ, "%s: IRQ%d requested\n", machine().time().to_string(), irq);
+ }
}
void z8_device::take_interrupt(int irq)
@@ -1312,7 +1348,7 @@ void z8_device::take_interrupt(int irq)
// acknowledge the IRQ
m_irq &= ~(1 << irq);
- standard_irq_callback(irq);
+ standard_irq_callback(irq, m_pc);
// get the interrupt vector address
uint16_t vector = irq * 2;
@@ -1324,8 +1360,8 @@ void z8_device::take_interrupt(int irq)
stack_push_byte(m_flags);
// branch to the vector
- m_pc = m_cache->read_byte(vector) << 8;
- m_pc |= m_cache->read_byte(vector + 1);
+ m_pc = m_cache.read_byte(vector) << 8;
+ m_pc |= m_cache.read_byte(vector + 1);
}
void z8_device::process_interrupts()
@@ -1537,6 +1573,7 @@ void z8_device::execute_set_input(int inputnum, int state)
{
switch ( inputnum )
{
+ // IRQ0 input is P32 (also DAV0/RDY0 handshake, not emulated)
case INPUT_LINE_IRQ0:
if (state != CLEAR_LINE && m_irq_line[0] == CLEAR_LINE)
request_interrupt(0);
@@ -1549,6 +1586,7 @@ void z8_device::execute_set_input(int inputnum, int state)
break;
+ // IRQ1 input is P33
case INPUT_LINE_IRQ1:
if (state != CLEAR_LINE && m_irq_line[1] == CLEAR_LINE)
request_interrupt(1);
@@ -1561,6 +1599,7 @@ void z8_device::execute_set_input(int inputnum, int state)
break;
+ // IRQ2 input is P31 (also TIN and DAV2/RDY2 handshake, latter not emulated)
case INPUT_LINE_IRQ2:
if (state != CLEAR_LINE && m_irq_line[2] == CLEAR_LINE)
request_interrupt(2);
@@ -1581,6 +1620,7 @@ void z8_device::execute_set_input(int inputnum, int state)
break;
+ // IRQ3 input is P30 (also serial DI)
case INPUT_LINE_IRQ3:
if (state != CLEAR_LINE && m_irq_line[3] == CLEAR_LINE && (m_p3m & Z8_P3M_P3_SERIAL) == 0)
request_interrupt(3);