From 29c777f6429ee2d0b2943290025ce00816e79d7d Mon Sep 17 00:00:00 2001 From: AJR Date: Sat, 8 Dec 2018 23:18:42 -0500 Subject: z8: Register overhaul - Create address space for internal register file - Add port output registers to debug state - Lock out interrupts on reset until EI --- src/devices/cpu/z8/z8.cpp | 738 +++++++++++++++++++++++++------------------ src/devices/cpu/z8/z8.h | 94 ++++-- src/devices/cpu/z8/z8ops.hxx | 16 +- 3 files changed, 507 insertions(+), 341 deletions(-) diff --git a/src/devices/cpu/z8/z8.cpp b/src/devices/cpu/z8/z8.cpp index 52c2ee4627e..633a2252988 100644 --- a/src/devices/cpu/z8/z8.cpp +++ b/src/devices/cpu/z8/z8.cpp @@ -11,7 +11,6 @@ TODO: - strobed I/O - - expose register file to disassembler - timer Tin/Tout modes - serial - instruction pipeline @@ -28,30 +27,6 @@ CONSTANTS ***************************************************************************/ -enum -{ - Z8_REGISTER_P0 = 0, - Z8_REGISTER_P1, - Z8_REGISTER_P2, - Z8_REGISTER_P3, - Z8_REGISTER_SIO = 0xf0, - Z8_REGISTER_TMR, - Z8_REGISTER_T1, - Z8_REGISTER_PRE1, - Z8_REGISTER_T0, - Z8_REGISTER_PRE0, - Z8_REGISTER_P2M, - Z8_REGISTER_P3M, - Z8_REGISTER_P01M, - Z8_REGISTER_IPR, - Z8_REGISTER_IRQ, - Z8_REGISTER_IMR, - Z8_REGISTER_FLAGS, - Z8_REGISTER_RP, - Z8_REGISTER_SPH, - Z8_REGISTER_SPL -}; - #define Z8_P3_DAV0 0x04 /* not supported */ #define Z8_P3_DAV1 0x08 /* not supported */ #define Z8_P3_DAV2 0x02 /* not supported */ @@ -104,7 +79,7 @@ enum #define Z8_P01M_P0H_MODE_INPUT 0x40 #define Z8_P01M_P0H_MODE_A12_A15 0x80 -#define Z8_P3M_P2_ACTIVE_PULLUPS 0x01 /* not supported */ +#define Z8_P3M_P2_ACTIVE_PULLUPS 0x01 #define Z8_P3M_P0_STROBED 0x04 /* not supported */ #define Z8_P3M_P33_P34_MASK 0x18 #define Z8_P3M_P33_P34_INPUT_OUTPUT 0x00 @@ -119,12 +94,6 @@ enum #define Z8_IMR_RAM_PROTECT 0x40 /* not supported */ #define Z8_IRQ_MASK 0x3f -#define Z8_IRQ_FLAG_IRQ5 0x20 -#define Z8_IRQ_FLAG_IRQ4 0x10 -#define Z8_IRQ_FLAG_IRQ3 0x08 -#define Z8_IRQ_FLAG_IRQ2 0x04 -#define Z8_IRQ_FLAG_IRQ1 0x02 -#define Z8_IRQ_FLAG_IRQ0 0x01 #define Z8_FLAGS_F1 0x01 #define Z8_FLAGS_F2 0x02 @@ -145,15 +114,6 @@ enum MACROS ***************************************************************************/ -#define P01M m_r[Z8_REGISTER_P01M] -#define P2M m_r[Z8_REGISTER_P2M] -#define P3M m_r[Z8_REGISTER_P3M] -#define T0 m_r[Z8_REGISTER_T0] -#define T1 m_r[Z8_REGISTER_T1] -#define PRE0 m_r[Z8_REGISTER_PRE0] -#define PRE1 m_r[Z8_REGISTER_PRE1] - - DEFINE_DEVICE_TYPE(Z8601, z8601_device, "z8601", "Zilog Z8601") DEFINE_DEVICE_TYPE(UB8830D, ub8830d_device, "ub8830d", "UB8830D") DEFINE_DEVICE_TYPE(Z8611, z8611_device, "z8611", "Zilog Z8611") @@ -176,11 +136,37 @@ void z8_device::preprogrammed_map(address_map &map) map(0x0000, m_rom_size - 1).rom().region("internal", 0); } +void z8_device::register_map(address_map &map) +{ + 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)); + map(0x03, 0x03).rw(FUNC(z8_device::p3_read), FUNC(z8_device::p3_write)); + map(0x04, 0x7f).ram(); + map(0xf0, 0xf0).rw(FUNC(z8_device::sio_read), FUNC(z8_device::sio_write)); + map(0xf1, 0xf1).rw(FUNC(z8_device::tmr_read), FUNC(z8_device::tmr_write)); + map(0xf2, 0xf2).rw(FUNC(z8_device::t1_read), FUNC(z8_device::t1_write)); + map(0xf3, 0xf3).w(FUNC(z8_device::pre1_write)); + map(0xf4, 0xf4).rw(FUNC(z8_device::t0_read), FUNC(z8_device::t0_write)); + map(0xf5, 0xf5).w(FUNC(z8_device::pre0_write)); + map(0xf6, 0xf6).w(FUNC(z8_device::p2m_write)); + map(0xf7, 0xf7).w(FUNC(z8_device::p3m_write)); + map(0xf8, 0xf8).w(FUNC(z8_device::p01m_write)); + map(0xf9, 0xf9).w(FUNC(z8_device::ipr_write)); + map(0xfa, 0xfa).rw(FUNC(z8_device::irq_read), FUNC(z8_device::irq_write)); + map(0xfb, 0xfb).rw(FUNC(z8_device::imr_read), FUNC(z8_device::imr_write)); + map(0xfc, 0xfc).rw(FUNC(z8_device::flags_read), FUNC(z8_device::flags_write)); + map(0xfd, 0xfd).rw(FUNC(z8_device::rp_read), FUNC(z8_device::rp_write)); + map(0xfe, 0xfe).rw(FUNC(z8_device::sph_read), FUNC(z8_device::sph_write)); + map(0xff, 0xff).rw(FUNC(z8_device::spl_read), FUNC(z8_device::spl_write)); +} + z8_device::z8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t rom_size, bool preprogrammed) : cpu_device(mconfig, type, tag, owner, clock) , 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}, {*this}, {*this}, {*this}} , m_output_cb{{*this}, {*this}, {*this}, {*this}} , m_rom_size(rom_size) @@ -242,13 +228,15 @@ device_memory_interface::space_config_vector z8_device::memory_space_config() co { return space_config_vector { std::make_pair(AS_PROGRAM, &m_program_config), - std::make_pair(AS_DATA, &m_data_config) + std::make_pair(AS_DATA, &m_data_config), + std::make_pair(AS_IO, &m_register_config) }; } else { return space_config_vector { - std::make_pair(AS_PROGRAM, &m_program_config) + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_IO, &m_register_config) }; } } @@ -259,18 +247,18 @@ device_memory_interface::space_config_vector z8_device::memory_space_config() co uint16_t z8_device::mask_external_address(uint16_t addr) { - switch (P01M & (Z8_P01M_P0L_MODE_A8_A11 | Z8_P01M_P0H_MODE_A12_A15)) + switch (m_p01m & (Z8_P01M_P0L_MODE_A8_A11 | Z8_P01M_P0H_MODE_A12_A15)) { case 0: - addr = (addr & 0x00ff) | register_read(Z8_REGISTER_P0) << 8; + addr = (addr & 0x00ff) | p0_read() << 8; break; case Z8_P01M_P0L_MODE_A8_A11: - addr = (addr & 0x0fff) | (register_read(Z8_REGISTER_P0) & 0xf0) << 8; + addr = (addr & 0x0fff) | (p0_read() & 0xf0) << 8; break; case Z8_P01M_P0H_MODE_A12_A15: - addr = (addr & 0xf0ff) | (register_read(Z8_REGISTER_P0) & 0x0f) << 8; + addr = (addr & 0xf0ff) | (p0_read() & 0x0f) << 8; break; } return addr; @@ -311,218 +299,316 @@ uint16_t z8_device::fetch_word() } -uint8_t z8_device::register_read(uint8_t offset) +uint8_t z8_device::p0_read() { uint8_t data = 0xff; uint8_t mask = 0; - switch (offset) + switch (m_p01m & Z8_P01M_P0L_MODE_MASK) { - case Z8_REGISTER_P0: - switch (P01M & Z8_P01M_P0L_MODE_MASK) - { - case Z8_P01M_P0L_MODE_OUTPUT: - data = m_output[offset] & 0x0f; - break; - case Z8_P01M_P0L_MODE_INPUT: - mask = 0x0f; - break; - default: /* A8...A11 */ - data = 0x0f; - break; - } - - switch (P01M & Z8_P01M_P0H_MODE_MASK) - { - case Z8_P01M_P0H_MODE_OUTPUT: - data |= m_output[offset] & 0xf0; - break; - case Z8_P01M_P0H_MODE_INPUT: - mask |= 0xf0; - break; - default: /* A12...A15 */ - data |= 0xf0; - break; - } - - if (!(P3M & Z8_P3M_P0_STROBED)) - { - if (mask) m_input[offset] = m_input_cb[0](0, mask); - } + case Z8_P01M_P0L_MODE_OUTPUT: + data = m_output[0] & 0x0f; + break; + case Z8_P01M_P0L_MODE_INPUT: + mask = 0x0f; + break; + default: /* A8...A11 */ + data = 0x0f; + break; + } - data |= m_input[offset] & mask; + switch (m_p01m & Z8_P01M_P0H_MODE_MASK) + { + case Z8_P01M_P0H_MODE_OUTPUT: + data |= m_output[0] & 0xf0; break; + case Z8_P01M_P0H_MODE_INPUT: + mask |= 0xf0; + break; + default: /* A12...A15 */ + data |= 0xf0; + break; + } - case Z8_REGISTER_P1: - switch (P01M & Z8_P01M_P1_MODE_MASK) - { - case Z8_P01M_P1_MODE_OUTPUT: - data = m_output[offset]; - break; - case Z8_P01M_P1_MODE_INPUT: - mask = 0xff; - break; - default: /* AD0..AD7 */ - data = 0xff; - break; - } + if (!(m_p3m & Z8_P3M_P0_STROBED)) + { + if (mask) + m_input[0] = m_input_cb[0](0, mask); + } - if ((P3M & Z8_P3M_P33_P34_MASK) != Z8_P3M_P33_P34_DAV1_RDY1) - { - if (mask) m_input[offset] = m_input_cb[1](0, mask); - } + data |= m_input[0] & mask; + return data; +} - data |= m_input[offset] & mask; - break; +void z8_device::p0_write(uint8_t data) +{ + uint8_t mask = 0; - case Z8_REGISTER_P2: - mask = m_r[Z8_REGISTER_P2M]; + m_output[0] = data; + if ((m_p01m & Z8_P01M_P0L_MODE_MASK) == Z8_P01M_P0L_MODE_OUTPUT) + mask |= 0x0f; + if ((m_p01m & Z8_P01M_P0H_MODE_MASK) == Z8_P01M_P0H_MODE_OUTPUT) + mask |= 0xf0; + if (mask) + m_output_cb[0](0, data & mask, mask); +} - if (!(P3M & Z8_P3M_P2_STROBED)) - { - if (mask) m_input[offset] = m_input_cb[2](0, mask); - } +uint8_t z8_device::p1_read() +{ + uint8_t data = 0xff; + uint8_t mask = 0; - data = (m_input[offset] & mask) | (m_output[offset] & ~mask); + switch (m_p01m & Z8_P01M_P1_MODE_MASK) + { + case Z8_P01M_P1_MODE_OUTPUT: + data = m_output[1]; + break; + case Z8_P01M_P1_MODE_INPUT: + mask = 0xff; break; + default: /* AD0..AD7 */ + data = 0xff; + break; + } - case Z8_REGISTER_P3: - // TODO: special port 3 modes - //if (!(P3M & 0x7c)) - //{ - mask = 0x0f; - //} + if ((m_p3m & Z8_P3M_P33_P34_MASK) != Z8_P3M_P33_P34_DAV1_RDY1) + { + if (mask) + m_input[1] = m_input_cb[1](0, mask); + } - if (mask) m_input[offset] = m_input_cb[3](0, mask); + data |= m_input[1] & mask; + return data; +} - data = (m_input[offset] & mask) | (m_output[offset] & ~mask); - break; +void z8_device::p1_write(uint8_t data) +{ + uint8_t mask = 0; - case Z8_REGISTER_T0: - data = m_t0; - break; + m_output[1] = data; + if ((m_p01m & Z8_P01M_P1_MODE_MASK) == Z8_P01M_P1_MODE_OUTPUT) + mask = 0xff; + if (mask) + m_output_cb[1](0, data & mask, mask); +} - case Z8_REGISTER_T1: - data = m_t1; - break; +uint8_t z8_device::p2_read() +{ + uint8_t mask = m_p2m; - case Z8_REGISTER_PRE1: - case Z8_REGISTER_PRE0: - case Z8_REGISTER_P2M: - case Z8_REGISTER_P3M: - case Z8_REGISTER_P01M: - case Z8_REGISTER_IPR: - /* write only */ - break; + // open drain lines can be externally driven where data = 1 + if (!(m_p3m & Z8_P3M_P2_ACTIVE_PULLUPS)) + mask |= m_output[2]; - default: - data = m_r[offset]; - break; + if (!(m_p3m & Z8_P3M_P2_STROBED)) + { + if (mask) + m_input[2] = m_input_cb[2](0, mask); } - return data; + return (m_input[2] & mask) | (m_output[2] & ~mask); } -uint16_t z8_device::register_pair_read(uint8_t offset) +void z8_device::p2_write(uint8_t data) { - return (register_read(offset) << 8) | register_read(offset + 1); + uint8_t mask = m_p2m ^ 0xff; + + m_output[2] = data; + if (mask) + m_output_cb[2](0, data & mask, mask); } -void z8_device::register_write(uint8_t offset, uint8_t data) +uint8_t z8_device::p3_read() +{ + uint8_t mask = 0x0f; + + // 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); +} + +void z8_device::p3_write(uint8_t data) { uint8_t mask = 0; - switch (offset) + m_output[3] = data; + + // TODO: special port 3 modes + //if (!(m_p3m & 0x7c)) + //{ + mask = 0xf0; + //} + + if (mask) + m_output_cb[3](0, data & mask, mask); +} + +uint8_t z8_device::sio_read() +{ + return 0xff; +} + +void z8_device::sio_write(uint8_t data) +{ +} + +uint8_t z8_device::tmr_read() +{ + return m_tmr; +} + +void z8_device::tmr_write(uint8_t data) +{ + m_tmr = data; + + if (data & Z8_TMR_LOAD_T0) { - case Z8_REGISTER_P0: - m_output[offset] = data; - if ((P01M & Z8_P01M_P0L_MODE_MASK) == Z8_P01M_P0L_MODE_OUTPUT) mask |= 0x0f; - if ((P01M & Z8_P01M_P0H_MODE_MASK) == Z8_P01M_P0H_MODE_OUTPUT) mask |= 0xf0; - if (mask) m_output_cb[0](0, data & mask, mask); - break; + m_count[0] = m_t[0]; + m_t0_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((m_pre[0] >> 2) + 1))); + } - case Z8_REGISTER_P1: - m_output[offset] = data; - if ((P01M & Z8_P01M_P1_MODE_MASK) == Z8_P01M_P1_MODE_OUTPUT) mask = 0xff; - if (mask) m_output_cb[1](0, data & mask, mask); - break; + m_t0_timer->enable(data & Z8_TMR_ENABLE_T0); - case Z8_REGISTER_P2: - m_output[offset] = data; - mask = m_r[Z8_REGISTER_P2M] ^ 0xff; - if (mask) m_output_cb[2](0, data & mask, mask); - break; + if (data & Z8_TMR_LOAD_T1) + { + m_count[1] = m_t[1]; + m_t1_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((m_pre[1] >> 2) + 1))); + } - case Z8_REGISTER_P3: - m_output[offset] = data; + m_t1_timer->enable(data & Z8_TMR_ENABLE_T1); +} - // TODO: special port 3 modes - //if (!(P3M & 0x7c)) - //{ - mask = 0xf0; - //} +uint8_t z8_device::t0_read() +{ + return m_count[0]; +} - if (mask) m_output_cb[3](0, data & mask, mask); - break; +void z8_device::t0_write(uint8_t data) +{ + m_t[0] = data; +} - case Z8_REGISTER_SIO: - break; +uint8_t z8_device::t1_read() +{ + return m_count[1]; +} - case Z8_REGISTER_TMR: - if (data & Z8_TMR_LOAD_T0) - { - m_t0 = T0; - m_t0_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((PRE0 >> 2) + 1))); - } +void z8_device::t1_write(uint8_t data) +{ + m_t[1] = data; +} - m_t0_timer->enable(data & Z8_TMR_ENABLE_T0); +void z8_device::pre0_write(uint8_t data) +{ + m_pre[0] = data; +} - if (data & Z8_TMR_LOAD_T1) - { - m_t1 = T1; - m_t1_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((PRE1 >> 2) + 1))); - } +void z8_device::pre1_write(uint8_t data) +{ + m_pre[0] = data; +} - m_t1_timer->enable(data & Z8_TMR_ENABLE_T1); - break; +void z8_device::p01m_write(uint8_t data) +{ + m_p01m = data; +} - case Z8_REGISTER_P2M: - break; - case Z8_REGISTER_P3M: - break; - case Z8_REGISTER_P01M: - break; - case Z8_REGISTER_IPR: - break; - case Z8_REGISTER_IRQ: - break; - case Z8_REGISTER_IMR: - break; - case Z8_REGISTER_FLAGS: - break; - case Z8_REGISTER_RP: - break; - case Z8_REGISTER_SPH: - break; - case Z8_REGISTER_SPL: - break; - default: - // TODO ignore missing registers - break; - } +void z8_device::p2m_write(uint8_t data) +{ + m_p2m = data; +} + +void z8_device::p3m_write(uint8_t data) +{ + m_p3m = data; +} + +void z8_device::ipr_write(uint8_t data) +{ + m_ipr = data; +} + +uint8_t z8_device::irq_read() +{ + return m_irq; +} + +void z8_device::irq_write(uint8_t data) +{ + if (m_irq_initialized) + m_irq = data; +} - m_r[offset] = data; +uint8_t z8_device::imr_read() +{ + return m_imr; +} + +void z8_device::imr_write(uint8_t data) +{ + m_imr = data; +} + +uint8_t z8_device::flags_read() +{ + return m_flags; +} + +void z8_device::flags_write(uint8_t data) +{ + m_flags = data; +} + +uint8_t z8_device::rp_read() +{ + return m_rp; +} + +void z8_device::rp_write(uint8_t data) +{ + m_rp = data; +} + +uint8_t z8_device::sph_read() +{ + return m_sp.b.h; +} + +void z8_device::sph_write(uint8_t data) +{ + m_sp.b.h = data; +} + +uint8_t z8_device::spl_read() +{ + return m_sp.b.l; +} + +void z8_device::spl_write(uint8_t data) +{ + m_sp.b.l = data; +} + + +uint16_t z8_device::register_pair_read(uint8_t offset) +{ + return m_regs->read_word_unaligned(offset); } void z8_device::register_pair_write(uint8_t offset, uint16_t data) { - register_write(offset, data >> 8); - register_write(offset + 1, data & 0xff); + m_regs->write_word_unaligned(offset, data); } uint8_t z8_device::get_working_register(int offset) { - return (m_r[Z8_REGISTER_RP] & 0xf0) | (offset & 0x0f); + return (m_rp & 0xf0) | (offset & 0x0f); } uint8_t z8_device::get_register(uint8_t offset) @@ -540,11 +626,11 @@ uint8_t z8_device::get_intermediate_register(int offset) void z8_device::stack_push_byte(uint8_t src) { - if (P01M & Z8_P01M_INTERNAL_STACK) + if (m_p01m & Z8_P01M_INTERNAL_STACK) { // SP <- SP - 1 (predecrement) - uint8_t sp = register_read(Z8_REGISTER_SPL) - 1; - register_write(Z8_REGISTER_SPL, sp); + uint8_t sp = m_sp.b.l - 1; + m_sp.b.l = sp; // @SP <- src register_write(sp, src); @@ -552,8 +638,8 @@ void z8_device::stack_push_byte(uint8_t src) else { // SP <- SP - 1 (predecrement) - uint16_t sp = register_pair_read(Z8_REGISTER_SPH) - 1; - register_pair_write(Z8_REGISTER_SPH, sp); + uint16_t sp = m_sp.w - 1; + m_sp.w = sp; // @SP <- src m_data->write_byte(mask_external_address(sp), src); @@ -562,11 +648,11 @@ void z8_device::stack_push_byte(uint8_t src) void z8_device::stack_push_word(uint16_t src) { - if (P01M & Z8_P01M_INTERNAL_STACK) + if (m_p01m & Z8_P01M_INTERNAL_STACK) { // SP <- SP - 2 (predecrement) - uint8_t sp = register_read(Z8_REGISTER_SPL) - 2; - register_write(Z8_REGISTER_SPL, sp); + uint8_t sp = m_sp.b.l - 2; + m_sp.b.l = sp; // @SP <- src register_pair_write(sp, src); @@ -574,8 +660,8 @@ void z8_device::stack_push_word(uint16_t src) else { // SP <- SP - 2 (predecrement) - uint16_t sp = register_pair_read(Z8_REGISTER_SPH) - 2; - register_pair_write(Z8_REGISTER_SPH, sp); + uint16_t sp = m_sp.w - 2; + m_sp.w = sp; // @SP <- src m_data->write_word_unaligned(mask_external_address(sp), src); @@ -584,25 +670,25 @@ void z8_device::stack_push_word(uint16_t src) uint8_t z8_device::stack_pop_byte() { - if (P01M & Z8_P01M_INTERNAL_STACK) + if (m_p01m & Z8_P01M_INTERNAL_STACK) { // @SP <- src - uint8_t sp = register_read(Z8_REGISTER_SPL); + uint8_t sp = m_sp.b.l; uint8_t byte = register_read(sp); // SP <- SP + 1 (postincrement) - register_write(Z8_REGISTER_SPL, sp + 1); + m_sp.b.l = sp + 1; return byte; } else { // @SP <- src - uint16_t sp = register_pair_read(Z8_REGISTER_SPH); + uint16_t sp = m_sp.w; uint8_t byte = m_data->read_byte(mask_external_address(sp)); // SP <- SP + 1 (postincrement) - register_pair_write(Z8_REGISTER_SPH, sp + 1); + m_sp.w = sp + 1; return byte; } @@ -610,25 +696,25 @@ uint8_t z8_device::stack_pop_byte() uint16_t z8_device::stack_pop_word() { - if (P01M & Z8_P01M_INTERNAL_STACK) + if (m_p01m & Z8_P01M_INTERNAL_STACK) { // @SP <- src - uint8_t sp = register_read(Z8_REGISTER_SPL); + uint8_t sp = m_sp.b.l; uint16_t word = register_pair_read(sp); // SP <- SP + 2 (postincrement) - register_write(Z8_REGISTER_SPL, sp + 2); + m_sp.b.l = sp + 2; return word; } else { // @SP <- src - uint16_t sp = register_pair_read(Z8_REGISTER_SPH); + uint16_t sp = m_sp.w; uint16_t word = m_data->read_word_unaligned(mask_external_address(sp)); // SP <- SP + 2 (postincrement) - register_pair_write(Z8_REGISTER_SPH, sp + 2); + m_sp.w = sp + 2; return word; } @@ -637,9 +723,9 @@ uint16_t z8_device::stack_pop_word() void z8_device::set_flag(uint8_t flag, int state) { if (state) - m_r[Z8_REGISTER_FLAGS] |= flag; + m_flags |= flag; else - m_r[Z8_REGISTER_FLAGS] &= ~flag; + m_flags &= ~flag; } #define set_flag_h(state) set_flag(Z8_FLAGS_H, state); @@ -755,27 +841,27 @@ const z8_device::z8_opcode_map z8_device::Z8601_OPCODE_MAP[256] = TIMER_CALLBACK_MEMBER( z8_device::t0_tick ) { - m_t0--; + m_count[0]--; - if (m_t0 == 0) + if (m_count[0] == 0) { - m_t0 = T0; - m_t0_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((PRE0 >> 2) + 1))); - m_t0_timer->enable(PRE0 & Z8_PRE0_COUNT_MODULO_N); - m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ4; + 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_CALLBACK_MEMBER( z8_device::t1_tick ) { - m_t1--; + m_count[1]--; - if (m_t1 == 0) + if (m_count[1] == 0) { - m_t1 = T1; - m_t1_timer->adjust(attotime::zero, 0, cycles_to_attotime(4 * ((PRE1 >> 2) + 1))); - m_t1_timer->enable(PRE1 & Z8_PRE0_COUNT_MODULO_N); - m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ5; + 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); } } @@ -795,21 +881,26 @@ void z8_device::device_start() 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_fake_sp).callimport().callexport(); - state_add(STATE_GENSP, "GENSP", m_fake_sp).callimport().callexport().noshow(); - state_add(Z8_RP, "RP", m_r[Z8_REGISTER_RP]); - state_add(STATE_GENFLAGS, "GENFLAGS", m_r[Z8_REGISTER_FLAGS]).noshow().formatstr("%6s"); - state_add(Z8_IMR, "IMR", m_r[Z8_REGISTER_IMR]); - state_add(Z8_IRQ, "IRQ", m_r[Z8_REGISTER_IRQ]); - state_add(Z8_IPR, "IPR", m_r[Z8_REGISTER_IPR]); - state_add(Z8_P01M, "P01M", m_r[Z8_REGISTER_P01M]); - state_add(Z8_P3M, "P3M", m_r[Z8_REGISTER_P3M]); - state_add(Z8_P2M, "P2M", m_r[Z8_REGISTER_P2M]); - state_add(Z8_PRE0, "PRE0", m_r[Z8_REGISTER_PRE0]); - state_add(Z8_T0, "T0", m_t0); - state_add(Z8_PRE1, "PRE1", m_r[Z8_REGISTER_PRE1]); - state_add(Z8_T1, "T1", m_t1); - state_add(Z8_TMR, "TMR", m_r[Z8_REGISTER_TMR]); + 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); + state_add(Z8_IRQ, "IRQ", m_irq); + state_add(Z8_IPR, "IPR", m_ipr); + state_add(Z8_P0, "P0", m_output[0]); + if (m_rom_size > 0) + state_add(Z8_P1, "P1", m_output[1]); + state_add(Z8_P2, "P2", m_output[2]); + state_add(Z8_P3, "P3", m_output[3]).mask(0xf0); + state_add(Z8_P01M, "P01M", m_p01m); + state_add(Z8_P2M, "P2M", m_p2m); + state_add(Z8_P3M, "P3M", m_p3m); + state_add(Z8_PRE0, "PRE0", m_pre[0]); + state_add(Z8_T0, "T0", m_t[0]); + state_add(Z8_PRE1, "PRE1", m_pre[1]); + state_add(Z8_T1, "T1", m_t[1]); + state_add(Z8_TMR, "TMR", m_tmr); 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(); @@ -819,34 +910,50 @@ void z8_device::device_start() 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); /* 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)); /* Clear state */ - for (auto & elem : m_irq_line) - elem = CLEAR_LINE; - for (auto & elem : m_r) - elem = 0; - for ( int i = 0; i < 4; i++ ) - { - m_input[i] = 0; - m_output[i] = 0; - } - for (auto & elem : m_fake_r) - elem = 0; - m_fake_sp = 0; - m_t0 = 0; - m_t1 = 0; + 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_fake_r), std::end(m_fake_r), 0); + m_pc = 0; + m_ppc = 0; + m_sp.w = 0; + m_rp = 0; + m_flags = 0; + m_p01m = 0; + m_p2m = 0; + m_p3m = 0; + m_tmr = 0; + m_irq_taken = false; + m_irq_initialized = false; /* register for state saving */ save_item(NAME(m_pc)); - save_item(NAME(m_r)); + save_item(NAME(m_ppc)); + save_item(NAME(m_sp.w)); + save_item(NAME(m_rp)); + save_item(NAME(m_flags)); save_item(NAME(m_input)); save_item(NAME(m_output)); + save_item(NAME(m_p01m)); + save_item(NAME(m_p2m)); + save_item(NAME(m_p3m)); + save_item(NAME(m_tmr)); + save_item(NAME(m_t)); + save_item(NAME(m_count)); + save_item(NAME(m_pre)); save_item(NAME(m_irq_line)); save_item(NAME(m_irq_taken)); + save_item(NAME(m_irq_initialized)); set_icountptr(m_icount); } @@ -855,16 +962,24 @@ void z8_device::device_start() INTERRUPTS ***************************************************************************/ +void z8_device::request_interrupt(int irq) +{ + assert(irq >= 0 && irq < 6); + + if (m_irq_initialized) + m_irq |= 1 << irq; +} + void z8_device::take_interrupt(int irq) { //logerror("Taking IRQ%d (previous PC = %04X)\n", irq, m_pc); m_irq_taken = true; // disable interrupts - m_r[Z8_REGISTER_IMR] &= ~Z8_IMR_ENABLE; + m_imr &= ~Z8_IMR_ENABLE; // acknowledge the IRQ - m_r[Z8_REGISTER_IRQ] &= ~(1 << irq); + m_irq &= ~(1 << irq); // get the interrupt vector address uint16_t vector = irq * 2; @@ -873,7 +988,7 @@ void z8_device::take_interrupt(int irq) // push registers onto stack stack_push_word(m_pc); - stack_push_byte(m_r[Z8_REGISTER_FLAGS]); + stack_push_byte(m_flags); // branch to the vector m_pc = m_cache->read_byte(vector) << 8; @@ -883,22 +998,22 @@ void z8_device::take_interrupt(int irq) void z8_device::process_interrupts() { m_irq_taken = false; - uint8_t pending_irqs = m_r[Z8_REGISTER_IMR] & m_r[Z8_REGISTER_IRQ] & Z8_IRQ_MASK; - if (!(m_r[Z8_REGISTER_IMR] & Z8_IMR_ENABLE) || pending_irqs == 0) + uint8_t pending_irqs = m_imr & m_irq & Z8_IRQ_MASK; + if (!(m_imr & Z8_IMR_ENABLE) || pending_irqs == 0) return; int group_a[2] = { 5, 3 }; int group_b[2] = { 2, 0 }; int group_c[2] = { 1, 4 }; - if (BIT(m_r[Z8_REGISTER_IPR], 5)) + if (BIT(m_ipr, 5)) std::swap(group_a[0], group_a[1]); - if (BIT(m_r[Z8_REGISTER_IPR], 2)) + if (BIT(m_ipr, 2)) std::swap(group_b[0], group_b[1]); - if (BIT(m_r[Z8_REGISTER_IPR], 1)) + if (BIT(m_ipr, 1)) std::swap(group_c[0], group_c[1]); - switch ((m_r[Z8_REGISTER_IPR] & 0x18) >> 2 | (m_r[Z8_REGISTER_IPR] & 0x01)) + switch ((m_ipr & 0x18) >> 2 | (m_ipr & 0x01)) { case 0: // (000) reserved according to Zilog (but must process at least IRQ4) case 1: // (001) C > A > B @@ -1030,16 +1145,18 @@ void z8_device::execute_run() void z8_device::device_reset() { m_pc = 0x000c; - - register_write(Z8_REGISTER_TMR, 0x00); - register_write(Z8_REGISTER_PRE1, PRE1 & 0xfc); - register_write(Z8_REGISTER_PRE0, PRE0 & 0xfe); - register_write(Z8_REGISTER_P2M, 0xff); - register_write(Z8_REGISTER_P3M, 0x00); - register_write(Z8_REGISTER_P01M, 0x4d); - register_write(Z8_REGISTER_IRQ, 0x00); - register_write(Z8_REGISTER_IMR, 0x00); - register_write(Z8_REGISTER_RP, 0x00); + m_rp = 0x00; + m_irq = 0x00; + m_imr &= ~Z8_IMR_ENABLE; + m_irq_initialized = false; + + p01m_write(0x4d); + p2m_write(0xff); + p3m_write(0x00); + + m_pre[0] &= ~Z8_PRE0_COUNT_MODULO_N; + m_pre[1] &= ~(Z8_PRE1_COUNT_MODULO_N | Z8_PRE1_INTERNAL_CLOCK); + tmr_write(0x00); } @@ -1060,15 +1177,12 @@ void z8_device::state_import(const device_state_entry &entry) m_pc = m_ppc; break; - case Z8_SP: - case STATE_GENSP: - m_r[Z8_REGISTER_SPH] = m_fake_sp >> 8; - m_r[Z8_REGISTER_SPL] = m_fake_sp & 0xff; - break; - 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: - m_r[m_r[Z8_REGISTER_RP] + (entry.index() - Z8_R0)] = m_fake_r[entry.index() - Z8_R0]; + { + auto dis = machine().disable_side_effects(); + register_write(m_rp + (entry.index() - Z8_R0), m_fake_r[entry.index() - Z8_R0]); break; + } default: fatalerror("CPU_IMPORT_STATE(z8) called for unexpected value\n"); @@ -1079,14 +1193,12 @@ void z8_device::state_export(const device_state_entry &entry) { switch (entry.index()) { - case Z8_SP: - case STATE_GENSP: - m_fake_sp = (m_r[Z8_REGISTER_SPH] << 8) | m_r[Z8_REGISTER_SPL]; - break; - 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: - m_fake_r[entry.index() - Z8_R0] = m_r[m_r[Z8_REGISTER_RP] + (entry.index() - Z8_R0)]; + { + auto dis = machine().disable_side_effects(); + m_fake_r[entry.index() - Z8_R0] = register_read(m_rp + (entry.index() - Z8_R0)); break; + } default: fatalerror("CPU_EXPORT_STATE(z8) called for unexpected value\n"); @@ -1098,12 +1210,12 @@ void z8_device::state_string_export(const device_state_entry &entry, std::string switch (entry.index()) { case STATE_GENFLAGS: str = string_format("%c%c%c%c%c%c", - m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_C ? 'C' : '.', - m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_Z ? 'Z' : '.', - m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_S ? 'S' : '.', - m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_V ? 'V' : '.', - m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_D ? 'D' : '.', - m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_H ? 'H' : '.'); break; + m_flags & Z8_FLAGS_C ? 'C' : '.', + m_flags & Z8_FLAGS_Z ? 'Z' : '.', + m_flags & Z8_FLAGS_S ? 'S' : '.', + m_flags & Z8_FLAGS_V ? 'V' : '.', + m_flags & Z8_FLAGS_D ? 'D' : '.', + m_flags & Z8_FLAGS_H ? 'H' : '.'); break; } } @@ -1114,25 +1226,25 @@ void z8_device::execute_set_input(int inputnum, int state) { case INPUT_LINE_IRQ0: if (state != CLEAR_LINE && m_irq_line[0] == CLEAR_LINE) - m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ0; + request_interrupt(0); m_irq_line[0] = state; break; case INPUT_LINE_IRQ1: if (state != CLEAR_LINE && m_irq_line[1] == CLEAR_LINE) - m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ1; + request_interrupt(1); m_irq_line[1] = state; break; case INPUT_LINE_IRQ2: if (state != CLEAR_LINE && m_irq_line[2] == CLEAR_LINE) - m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ2; + request_interrupt(2); m_irq_line[2] = state; break; case INPUT_LINE_IRQ3: if (state != CLEAR_LINE && m_irq_line[3] == CLEAR_LINE) - m_r[Z8_REGISTER_IRQ] |= Z8_IRQ_FLAG_IRQ3; + request_interrupt(3); m_irq_line[3] = state; break; diff --git a/src/devices/cpu/z8/z8.h b/src/devices/cpu/z8/z8.h index a1119bb8afb..0bdd235d7c2 100644 --- a/src/devices/cpu/z8/z8.h +++ b/src/devices/cpu/z8/z8.h @@ -30,6 +30,7 @@ protected: { Z8_PC, Z8_SP, Z8_RP, 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, @@ -66,14 +67,17 @@ protected: void program_map(address_map &map); void preprogrammed_map(address_map &map); + void register_map(address_map &map); private: address_space_config m_program_config; address_space_config m_data_config; + address_space_config m_register_config; address_space *m_program; memory_access_cache<0, 0, ENDIANNESS_BIG> *m_cache; address_space *m_data; + address_space *m_regs; // callbacks devcb_read8 m_input_cb[4]; @@ -81,43 +85,93 @@ private: uint32_t m_rom_size; - /* registers */ - uint16_t m_pc; /* program counter */ - uint16_t m_ppc; /* program counter at last opcode fetch */ - uint8_t m_r[256]; /* register file */ - uint8_t m_input[4]; /* port input latches */ - uint8_t m_output[4]; /* port output latches */ - uint8_t m_t0; /* timer 0 current count */ - uint8_t m_t1; /* timer 1 current count */ - - /* fake registers */ - uint16_t m_fake_sp; /* fake stack pointer */ - uint8_t m_fake_r[16]; /* fake working registers */ - - /* interrupts */ - int m_irq_line[4]; /* IRQ line state */ + // basic registers + uint16_t m_pc; // program counter + uint16_t m_ppc; // program counter at last opcode fetch + PAIR16 m_sp; // stack pointer (8-bit for internal stack, 16-bit for external stack) + uint8_t m_rp; // register pointer + uint8_t m_flags; // condition flags + uint8_t m_imr; // interrupt mask + uint8_t m_irq; // interrupt request + uint8_t m_ipr; // interrupt priority + + // port registers + uint8_t m_input[4]; // port input latches + uint8_t m_output[4]; // port output latches + uint8_t m_p01m; // port 0/1 mode + uint8_t m_p2m; // port 2 mode + uint8_t m_p3m; // port 3 mode + + // 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 + + // fake registers + uint8_t m_fake_r[16]; // fake working registers + + // interrupts + int m_irq_line[4]; // IRQ line state bool m_irq_taken; + bool m_irq_initialized; // IRQ must be unlocked by EI after reset - /* execution logic */ - int m_icount; /* instruction counter */ + // execution logic + int32_t m_icount; // instruction counter - /* timers */ + // timers emu_timer *m_t0_timer; emu_timer *m_t1_timer; TIMER_CALLBACK_MEMBER( t0_tick ); TIMER_CALLBACK_MEMBER( t1_tick ); + void request_interrupt(int irq); void take_interrupt(int irq); void process_interrupts(); + uint8_t p0_read(); + void p0_write(uint8_t data); + uint8_t p1_read(); + void p1_write(uint8_t data); + uint8_t p2_read(); + void p2_write(uint8_t data); + uint8_t p3_read(); + void p3_write(uint8_t data); + uint8_t sio_read(); + void sio_write(uint8_t data); + uint8_t tmr_read(); + void tmr_write(uint8_t data); + uint8_t t0_read(); + void t0_write(uint8_t data); + uint8_t t1_read(); + void t1_write(uint8_t data); + void pre0_write(uint8_t data); + void pre1_write(uint8_t data); + void p01m_write(uint8_t data); + void p2m_write(uint8_t data); + void p3m_write(uint8_t data); + void ipr_write(uint8_t data); + uint8_t irq_read(); + void irq_write(uint8_t data); + uint8_t imr_read(); + void imr_write(uint8_t data); + uint8_t flags_read(); + void flags_write(uint8_t data); + uint8_t rp_read(); + void rp_write(uint8_t data); + uint8_t sph_read(); + void sph_write(uint8_t data); + uint8_t spl_read(); + void spl_write(uint8_t data); + inline uint16_t mask_external_address(uint16_t addr); inline uint8_t fetch(); inline uint8_t fetch_opcode(); inline uint16_t fetch_word(); - inline uint8_t register_read(uint8_t offset); + inline uint8_t register_read(uint8_t offset) { return m_regs->read_byte(offset); } inline uint16_t register_pair_read(uint8_t offset); - inline void register_write(uint8_t offset, uint8_t 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 uint8_t get_working_register(int offset); inline uint8_t get_register(uint8_t offset); diff --git a/src/devices/cpu/z8/z8ops.hxx b/src/devices/cpu/z8/z8ops.hxx index b08d051caf1..d80988029a5 100644 --- a/src/devices/cpu/z8/z8ops.hxx +++ b/src/devices/cpu/z8/z8ops.hxx @@ -17,7 +17,7 @@ #define IR get_intermediate_register(get_register(fetch())) #define RR get_intermediate_register(get_register(fetch())) #define IM fetch() -#define flag(_flag) ((m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS##_##_flag) ? 1 : 0) +#define flag(_flag) ((m_flags & Z8_FLAGS_##_flag) ? 1 : 0) #define mode_r1_r2(_func) \ uint8_t dst_src = fetch();\ @@ -37,7 +37,7 @@ _func(dst, src); #define mode_IR2_R1(_func) \ - uint8_t src = m_r[read(R)];\ + uint8_t src = register_read(read(R));\ uint8_t dst = R;\ _func(dst, src); @@ -550,14 +550,14 @@ INSTRUCTION( iret ) { /* FLAGS <- @SP SP <- SP + 1 */ - register_write(Z8_REGISTER_FLAGS, stack_pop_byte()); + flags_write(stack_pop_byte()); /* PC <- @SP SP <- SP + 2 */ m_pc = stack_pop_word(); /* IMR (7) <- 1 */ - m_r[Z8_REGISTER_IMR] |= Z8_IMR_ENABLE; + m_imr |= Z8_IMR_ENABLE; } INSTRUCTION( ret ) @@ -773,10 +773,10 @@ INSTRUCTION( swap_IR1 ) { mode_IR1(swap) } CPU CONTROL INSTRUCTIONS ***************************************************************************/ -INSTRUCTION( ccf ) { m_r[Z8_REGISTER_FLAGS] ^= Z8_FLAGS_C; } -INSTRUCTION( di ) { m_r[Z8_REGISTER_IMR] &= ~Z8_IMR_ENABLE; } -INSTRUCTION( ei ) { m_r[Z8_REGISTER_IMR] |= Z8_IMR_ENABLE; } +INSTRUCTION( ccf ) { m_flags ^= Z8_FLAGS_C; } +INSTRUCTION( di ) { m_imr &= ~Z8_IMR_ENABLE; } +INSTRUCTION( ei ) { m_imr |= Z8_IMR_ENABLE; m_irq_initialized = true; } INSTRUCTION( nop ) { /* no operation */ } INSTRUCTION( rcf ) { set_flag_c(0); } INSTRUCTION( scf ) { set_flag_c(1); } -INSTRUCTION( srp_IM ) { m_r[Z8_REGISTER_RP] = fetch(); } +INSTRUCTION( srp_IM ) { rp_write(fetch()); } -- cgit v1.2.3