diff options
Diffstat (limited to 'src/devices/cpu/rw5000/rw5000base.cpp')
-rw-r--r-- | src/devices/cpu/rw5000/rw5000base.cpp | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/devices/cpu/rw5000/rw5000base.cpp b/src/devices/cpu/rw5000/rw5000base.cpp new file mode 100644 index 00000000000..ad5745f4e94 --- /dev/null +++ b/src/devices/cpu/rw5000/rw5000base.cpp @@ -0,0 +1,222 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Rockwell A/B5000 family MCU cores + +This MCU series is right before the more publicly available PPS4/1. +Known part numbers: A/B5000, A5300, A/B5500, A/B5900, B6000, B6100. +The latter two were manufactured for Mattel, with small modifications +useful for making handheld games. In fact, the programmer of the first +Mattel handheld games was a circuit designer at Rockwell. + +The main difference between Axxxx and Bxxxx is that B runs on low power, +there's also a small change with the way they output LEDs. + +A5300 might not be in this series, the page size is 0x3f instead of 0x40. + +A4000 series came out around the same time (possibly even after A5000). +It is similar, but too many differences to emulate in this device, probably. + +*/ + +#include "emu.h" +#include "rw5000base.h" + + +rw5000_base_device::rw5000_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data) : + cpu_device(mconfig, type, tag, owner, clock), + m_program_config("program", ENDIANNESS_LITTLE, 8, prgwidth, 0, program), + m_data_config("data", ENDIANNESS_LITTLE, 8, datawidth, 0, data), + m_prgwidth(prgwidth), + m_datawidth(datawidth), + m_read_kb(*this, 0), + m_read_din(*this, 0), + m_write_str(*this), + m_write_seg(*this), + m_write_spk(*this) +{ } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rw5000_base_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_prgmask = (1 << m_prgwidth) - 1; + m_datamask = (1 << m_datawidth) - 1; + + // zerofill + m_pc = 0; + m_prev_pc = 0; + m_s = 0; + m_op = 0; + m_prev_op = 0; + + m_a = 0; + m_bl = 0; + m_bu = 0; + m_prev_bl = 0; + m_prev_bu = 0; + m_bl_delay = false; + m_bu_delay = false; + m_ram_addr = 0; + m_c = 0; + m_prev_c = 0; + m_prev2_c = 0; + m_prev3_c = 0; + m_sr = false; + m_skip = false; + m_seg = 0; + m_suppress0 = false; + + m_atb_step = 0; + m_mtd_step = 0; + m_tra_step = 0; + m_ret_step = 0; + + // register for savestates + save_item(NAME(m_pc)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_s)); + save_item(NAME(m_op)); + save_item(NAME(m_prev_op)); + + save_item(NAME(m_a)); + save_item(NAME(m_bl)); + save_item(NAME(m_bu)); + save_item(NAME(m_prev_bl)); + save_item(NAME(m_prev_bu)); + save_item(NAME(m_bl_delay)); + save_item(NAME(m_bu_delay)); + save_item(NAME(m_ram_addr)); + save_item(NAME(m_c)); + save_item(NAME(m_prev_c)); + save_item(NAME(m_prev2_c)); + save_item(NAME(m_prev3_c)); + save_item(NAME(m_sr)); + save_item(NAME(m_skip)); + save_item(NAME(m_seg)); + save_item(NAME(m_suppress0)); + + save_item(NAME(m_atb_step)); + save_item(NAME(m_mtd_step)); + save_item(NAME(m_tra_step)); + save_item(NAME(m_ret_step)); + + // register state for debugger + state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%03X").noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_prev_pc).formatstr("%03X").noshow(); + + m_state_count = 0; + state_add(++m_state_count, "PC", m_pc).formatstr("%03X"); // 1 + state_add(++m_state_count, "S", m_s).formatstr("%03X"); // 2 + state_add(++m_state_count, "A", m_a).formatstr("%01X"); // 3 + state_add(++m_state_count, "C", m_c).formatstr("%01X"); // 4 + state_add(++m_state_count, "B", m_ram_addr).formatstr("%02X"); // 5 + state_add(++m_state_count, "BU", m_bu).formatstr("%01X").noshow(); // 6 + state_add(++m_state_count, "BL", m_bl).formatstr("%01X").noshow(); // 7 + + set_icountptr(m_icount); +} + +device_memory_interface::space_config_vector rw5000_base_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_program_config), + std::make_pair(AS_DATA, &m_data_config) + }; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void rw5000_base_device::device_reset() +{ + reset_pc(); + m_prev_pc = m_pc; + m_s = m_pc; + m_op = 0; + m_prev_op = 0; + + m_bl_delay = false; + m_bu_delay = false; + m_sr = false; + m_skip = false; + + m_atb_step = 0; + m_mtd_step = 0; + m_tra_step = 0; + m_ret_step = 0; +} + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void rw5000_base_device::increment_pc() +{ + // low part is LFSR + int feed = ((m_pc & 0x3e) == 0) ? 1 : 0; + feed ^= (m_pc >> 1 ^ m_pc) & 1; + m_pc = (m_pc & ~0x3f) | (m_pc >> 1 & 0x1f) | (feed << 5); +} + +void rw5000_base_device::execute_run() +{ + while (m_icount > 0) + { + // remember previous state + m_prev_op = m_op; + m_prev_pc = m_pc; + + m_prev_bl = m_bl; + m_prev_bu = m_bu; + m_prev3_c = m_prev2_c; + m_prev2_c = m_prev_c; + m_prev_c = m_c; + + // fetch next opcode + m_op = m_program->read_byte(m_pc); + bool skip = m_skip && op_canskip(m_op); + m_skip = false; + + if (!skip) + debugger_instruction_hook(m_pc); + increment_pc(); + m_icount--; + + // handle opcode if it's not skipped + if (skip) + m_op = 0; // fake nop + else + execute_one(); + + // some opcodes have multiple steps and will run in parallel with next ones, + // eg. it may fetch in order A,B and parts executed in order B,A + if (m_atb_step) op_atb_step(); + if (m_mtd_step) op_mtd_step(); + if (m_tra_step) op_tra_step(); + if (m_ret_step) op_ret_step(); + + // some opcodes delay RAM address adjustment for 1 cycle + m_ram_addr = (m_bu << 4 & 0x30) | (m_bl & 0xf); + + if (m_bl_delay) + { + m_ram_addr = (m_ram_addr & ~0xf) | (m_prev_bl & 0xf); + m_bl_delay = false; + } + if (m_bu_delay) + { + m_ram_addr = (m_ram_addr & 0xf) | (m_prev_bu << 4 & 0x30); + m_bu_delay = false; + } + } +} |