diff options
author | 2019-09-25 11:48:22 -0400 | |
---|---|---|
committer | 2019-09-25 11:57:56 -0400 | |
commit | a24caaede8da2f17d6f8d28d6ea2292b07f044bf (patch) | |
tree | 2c0b0031e015893b22615be1581eab0d97dc0432 /src | |
parent | a73d55f52edf0abcba904cd1939beb3dfc81ac02 (diff) |
rii: Many updates
- Identify CPU type used by vreadere as ePG3231
- Add preliminary port I/O handlers and callbacks
- Add stub handlers and state variables for interrupt controller, timers, synthesizer, UART and SPI
- Fix TBRD addressing of external data memory
- Fix calculation of carry flag for normal additive operations
- Implement multi-byte carry/borrow for applicable registers
- Implement signed multiplication option
- Add internal stack buffer for saving PCH during calls/interrupts
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/cpu/rii/riidasm.cpp | 8 | ||||
-rw-r--r-- | src/devices/cpu/rii/riidasm.h | 12 | ||||
-rw-r--r-- | src/devices/cpu/rii/riscii.cpp | 879 | ||||
-rw-r--r-- | src/devices/cpu/rii/riscii.h | 211 | ||||
-rw-r--r-- | src/mame/drivers/vtech_eu3a12.cpp | 8 | ||||
-rw-r--r-- | src/tools/unidasm.cpp | 2 |
6 files changed, 1043 insertions, 77 deletions
diff --git a/src/devices/cpu/rii/riidasm.cpp b/src/devices/cpu/rii/riidasm.cpp index cad53e121c9..aa8087c6fcc 100644 --- a/src/devices/cpu/rii/riidasm.cpp +++ b/src/devices/cpu/rii/riidasm.cpp @@ -16,8 +16,8 @@ using osd::u32; using util::BIT; using offs_t = u32; -// FIXME: this set is an amalgam of ePG3231-EM202, EPD3332 and EPD3338 -const char *const riscii_disassembler::s_regs[0x60] = +// TODO: add register sets for other models +const char *const epg3231_disassembler::s_regs[0x60] = { "INDF0", "FSR0", "PCL", "PCM", "PCH", "BSR", "STKPTR", "BSR1", "INDF1", "FSR1", "ACC", "TABPTRL", "TABPTRM", "TABPTRH", "CPUCON", "STATUS", @@ -27,8 +27,8 @@ const char *const riscii_disassembler::s_regs[0x60] = "TR2CON", "TRLIR", nullptr, "POST_ID", "ADCON", "PAINTEN", "PAINTSTA", "PAWAKE", "UARTCON", "UARTSTA", "PORTJ", "PORTK", "DCRB", "DCRC", "DCRDE", "DCRFG", "DCRHI", "DCRJK", "PBCON", "PCCON", "PLLF", "T0CL", "T0CH", "SPICON", - "SPISTA", "SPRL", "SPRM", "SPRH", "SFCR", "ADDL1~ADDL4", "ADDM1~ADDM4", "ADDH1~ADDH4", - "ENV1~4/SPHDR", "MTCON1~4/SPHTCON", "MTRL1~4/SPHTRL", "VOCON", "TR1C", "TR2C", "ADCF", nullptr, + "SPISTA", "SPRL", "SPRM", "SPRH", "SFCR", "ADDL", "ADDM", "ADDH", + "ENV/SPHDR", "MTCON/SPHTCON", "MTRL/SPHTRL", "VOCON", "TR1C", "TR2C", "ADCF", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; diff --git a/src/devices/cpu/rii/riidasm.h b/src/devices/cpu/rii/riidasm.h index 7c2ffb80bff..c2b5c81f7a6 100644 --- a/src/devices/cpu/rii/riidasm.h +++ b/src/devices/cpu/rii/riidasm.h @@ -8,9 +8,6 @@ class riscii_disassembler : public util::disasm_interface { -public: - riscii_disassembler() : riscii_disassembler(s_regs) { } - protected: // construction/destruction riscii_disassembler(const char *const regs[]); @@ -31,4 +28,13 @@ private: const char *const *m_regs; }; +class epg3231_disassembler : public riscii_disassembler +{ +public: + epg3231_disassembler() : riscii_disassembler(s_regs) { } + +private: + static const char *const s_regs[0x60]; +}; + #endif // MAME_CPU_RII_RIIDASM_H diff --git a/src/devices/cpu/rii/riscii.cpp b/src/devices/cpu/rii/riscii.cpp index c7b158bf3e0..0317c5c9c4b 100644 --- a/src/devices/cpu/rii/riscii.cpp +++ b/src/devices/cpu/rii/riscii.cpp @@ -11,7 +11,7 @@ 13-bit opcodes.) Currently the execution core is mostly complete, though interrupts and - on-chip peripherals are completely unemulated. + on-chip peripherals are mostly unemulated. ***************************************************************************/ @@ -20,7 +20,7 @@ #include "riidasm.h" // device type definitions -DEFINE_DEVICE_TYPE(RISCII, riscii_series_device, "riscii", "Elan RISC II") +DEFINE_DEVICE_TYPE(EPG3231, epg3231_device, "epg3231", "Elan ePG3231") ALLOW_SAVE_TYPE(riscii_series_device::exec_state); @@ -29,17 +29,18 @@ ALLOW_SAVE_TYPE(riscii_series_device::exec_state); // DEVICE CONSTRUCTION AND INITIALIZATION //************************************************************************** -void riscii_series_device::regs_map(address_map &map) +void riscii_series_device::core_regs_map(address_map &map) { - // 0x00 (INDF0) is not physically implemented + // INDF0 (R00h) is not physically implemented map(0x0001, 0x0001).rw(FUNC(riscii_series_device::fsr0_r), FUNC(riscii_series_device::fsr0_w)); map(0x0002, 0x0002).rw(FUNC(riscii_series_device::pcl_r), FUNC(riscii_series_device::pcl_w)); map(0x0003, 0x0003).rw(FUNC(riscii_series_device::pcm_r), FUNC(riscii_series_device::pcm_w)); - map(0x0004, 0x0004).rw(FUNC(riscii_series_device::pch_r), FUNC(riscii_series_device::pch_w)); + if (m_pcmask > 0xffff) + map(0x0004, 0x0004).rw(FUNC(riscii_series_device::pch_r), FUNC(riscii_series_device::pch_w)); map(0x0005, 0x0005).rw(FUNC(riscii_series_device::bsr_r), FUNC(riscii_series_device::bsr_w)); map(0x0006, 0x0006).rw(FUNC(riscii_series_device::stkptr_r), FUNC(riscii_series_device::stkptr_w)); map(0x0007, 0x0007).rw(FUNC(riscii_series_device::bsr1_r), FUNC(riscii_series_device::bsr1_w)); - // 0x08 (INDF1) is not physically implemented + // INDF1 (R08h) is not physically implemented map(0x0009, 0x0009).rw(FUNC(riscii_series_device::fsr1_r), FUNC(riscii_series_device::fsr1_w)); map(0x000a, 0x000a).rw(FUNC(riscii_series_device::acc_r), FUNC(riscii_series_device::acc_w)); map(0x000b, 0x000b).rw(FUNC(riscii_series_device::tabptrl_r), FUNC(riscii_series_device::tabptrl_w)); @@ -47,31 +48,31 @@ void riscii_series_device::regs_map(address_map &map) map(0x000d, 0x000d).rw(FUNC(riscii_series_device::tabptrh_r), FUNC(riscii_series_device::tabptrh_w)); map(0x000e, 0x000e).rw(FUNC(riscii_series_device::cpucon_r), FUNC(riscii_series_device::cpucon_w)); map(0x000f, 0x000f).rw(FUNC(riscii_series_device::status_r), FUNC(riscii_series_device::status_w)); - map(0x0010, 0x0010).ram(); // TODO: TRL2 - map(0x0011, 0x0011).rw(FUNC(riscii_series_device::prodl_r), FUNC(riscii_series_device::prodl_w)); - map(0x0012, 0x0012).rw(FUNC(riscii_series_device::prodh_r), FUNC(riscii_series_device::prodh_w)); - map(0x0013, 0x0029).ram(); // TODO: other special function registers - map(0x002b, 0x002b).rw(FUNC(riscii_series_device::post_id_r), FUNC(riscii_series_device::post_id_w)); - map(0x002c, 0x007f).ram(); // TODO: other special function registers for (unsigned b = 0; b <= m_maxbank; b++) map(0x0080 | (b << 8), 0x00ff | (b << 8)).ram(); } -std::unique_ptr<util::disasm_interface> riscii_series_device::create_disassembler() +std::unique_ptr<util::disasm_interface> epg3231_device::create_disassembler() { - return std::make_unique<riscii_disassembler>(); + return std::make_unique<epg3231_disassembler>(); } -riscii_series_device::riscii_series_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, unsigned prgbits, unsigned bankbits, uint8_t maxbank) +riscii_series_device::riscii_series_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, unsigned addrbits, unsigned pcbits, u32 datastart, unsigned bankbits, u8 maxbank, u8 post_id_mask, address_map_constructor regs) : cpu_device(mconfig, type, tag, owner, clock) - , m_program_config("program", ENDIANNESS_LITTLE, 16, prgbits, -1) - , m_regs_config("register", ENDIANNESS_LITTLE, 8, 8 + bankbits, 0, address_map_constructor(FUNC(riscii_series_device::regs_map), this)) + , m_program_config("program", ENDIANNESS_LITTLE, 16, addrbits, -1) + , m_regs_config("register", ENDIANNESS_LITTLE, 8, 8 + bankbits, 0, regs) , m_program(nullptr) , m_regs(nullptr) , m_cache(nullptr) - , m_prgbits(prgbits) + , m_porta_in_cb(*this) + , m_port_in_cb{{*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}} + , m_port_out_cb{{*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}, {*this}} + , m_pcmask((1 << pcbits) - 1) + , m_datastart(datastart) + , m_tbptmask(((1 << (addrbits + 1)) - 1) | (datastart != 0 ? 0x800000 : 0)) , m_bankmask((1 << bankbits) - 1) , m_maxbank(maxbank) + , m_post_id_mask(post_id_mask) , m_pc(0) , m_acc(0) , m_fsr{0, 0} @@ -81,7 +82,36 @@ riscii_series_device::riscii_series_device(const machine_config &mconfig, device , m_cpucon(0) , m_status(0) , m_prod(0) + , m_pfs(0) + , m_intcon(0) + , m_intsta(0) , m_post_id(0) + , m_port_data{0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , m_port_dcr{0, 0, 0, 0, 0, 0} + , m_port_control{0, 0} + , m_stbcon(0) + , m_painten(0) + , m_paintsta(0) + , m_pawake(0) + , m_uartcon(0) + , m_uartsta(0) + , m_spicon(0) + , m_spista(0) + , m_trl0(0) + , m_trl1(0) + , m_trl2(0) + , m_tr01con(0) + , m_tr2con(0) + , m_trlir(0) + , m_sfcr(0) + , m_add{0, 0, 0, 0} + , m_env{0, 0, 0, 0} + , m_mtcon{0, 0, 0, 0} + , m_mtrl{0, 0, 0, 0} + , m_sphdr(0) + , m_sphtcon(0) + , m_sphtrl(0) + , m_vocon(0) , m_icount(0) , m_exec_state(EXEC_CYCLE1) , m_repeat(0) @@ -89,8 +119,64 @@ riscii_series_device::riscii_series_device(const machine_config &mconfig, device { } -riscii_series_device::riscii_series_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : riscii_series_device(mconfig, RISCII, tag, owner, clock, 18, 5, 0x1f) +void epg3231_device::regs_map(address_map &map) +{ + core_regs_map(map); + map(0x0010, 0x0010).rw(FUNC(epg3231_device::trl2_r), FUNC(epg3231_device::trl2_w)); + map(0x0011, 0x0011).rw(FUNC(epg3231_device::prodl_r), FUNC(epg3231_device::prodl_w)); + map(0x0012, 0x0012).rw(FUNC(epg3231_device::prodh_r), FUNC(epg3231_device::prodh_w)); + // TODO: ADOTL (R13h), ADOTH (R14h) + map(0x0015, 0x0015).w(FUNC(epg3231_device::uarttx_w)); + map(0x0016, 0x0016).r(FUNC(epg3231_device::uartrx_r)); + map(0x0017, 0x0017).r(FUNC(epg3231_device::porta_r)); + map(0x0018, 0x001f).rw(FUNC(epg3231_device::port_r), FUNC(epg3231_device::port_w)); + map(0x0020, 0x0020).rw(FUNC(epg3231_device::pfs_r), FUNC(epg3231_device::pfs_w)); + map(0x0021, 0x0021).rw(FUNC(epg3231_device::stbcon_r), FUNC(epg3231_device::stbcon_w)); + map(0x0022, 0x0022).rw(FUNC(epg3231_device::intcon_r), FUNC(epg3231_device::intcon_w)); + map(0x0023, 0x0023).rw(FUNC(epg3231_device::intsta_r), FUNC(epg3231_device::intsta_w)); + map(0x0024, 0x0024).rw(FUNC(epg3231_device::trl0l_r), FUNC(epg3231_device::trl0l_w)); + map(0x0025, 0x0025).rw(FUNC(epg3231_device::trl0h_r), FUNC(epg3231_device::trl0h_w)); + map(0x0026, 0x0026).rw(FUNC(epg3231_device::trl1_r), FUNC(epg3231_device::trl1_w)); + map(0x0027, 0x0027).rw(FUNC(epg3231_device::tr01con_r), FUNC(epg3231_device::tr01con_w)); + map(0x0028, 0x0028).rw(FUNC(epg3231_device::tr2con_r), FUNC(epg3231_device::tr2con_w)); + map(0x0028, 0x0028).rw(FUNC(epg3231_device::trlir_r), FUNC(epg3231_device::trlir_w)); + // R2Ah is reserved + map(0x002b, 0x002b).rw(FUNC(epg3231_device::post_id_r), FUNC(epg3231_device::post_id_w)); + // TODO: ADCON (R2Ch) + map(0x002d, 0x002d).rw(FUNC(epg3231_device::painten_r), FUNC(epg3231_device::painten_w)); + map(0x002e, 0x002e).rw(FUNC(epg3231_device::paintsta_r), FUNC(epg3231_device::paintsta_w)); + map(0x002f, 0x002f).rw(FUNC(epg3231_device::pawake_r), FUNC(epg3231_device::pawake_w)); + map(0x0030, 0x0030).rw(FUNC(epg3231_device::uartcon_r), FUNC(epg3231_device::uartcon_w)); + map(0x0031, 0x0031).rw(FUNC(epg3231_device::uartsta_r), FUNC(epg3231_device::uartsta_w)); + map(0x0032, 0x0033).rw(FUNC(epg3231_device::portjk_r), FUNC(epg3231_device::portjk_w)); + map(0x0034, 0x0039).rw(FUNC(epg3231_device::dcr_r), FUNC(epg3231_device::dcr_w)); + map(0x003a, 0x003b).rw(FUNC(epg3231_device::pcon_r), FUNC(epg3231_device::pcon_w)); + // TODO: PLLF (R3Ch) + map(0x003d, 0x003d).r(FUNC(epg3231_device::t0cl_r)); + map(0x003e, 0x003e).r(FUNC(epg3231_device::t0ch_r)); + map(0x003f, 0x003f).rw(FUNC(epg3231_device::spicon_r), FUNC(epg3231_device::spicon_w)); + map(0x0040, 0x0040).rw(FUNC(epg3231_device::spista_r), FUNC(epg3231_device::spista_w)); + map(0x0041, 0x0041).rw(FUNC(epg3231_device::sprl_r), FUNC(epg3231_device::sprl_w)); + map(0x0042, 0x0042).rw(FUNC(epg3231_device::sprm_r), FUNC(epg3231_device::sprm_w)); + map(0x0043, 0x0043).rw(FUNC(epg3231_device::sprh_r), FUNC(epg3231_device::sprh_w)); + map(0x0044, 0x0044).rw(FUNC(epg3231_device::sfcr_r), FUNC(epg3231_device::sfcr_w)); + map(0x0045, 0x0045).rw(FUNC(epg3231_device::addl_r), FUNC(epg3231_device::addl_w)); + map(0x0046, 0x0046).rw(FUNC(epg3231_device::addm_r), FUNC(epg3231_device::addm_w)); + map(0x0047, 0x0047).rw(FUNC(epg3231_device::addh_r), FUNC(epg3231_device::addh_w)); + map(0x0048, 0x0048).rw(FUNC(epg3231_device::env_sphdr_r), FUNC(epg3231_device::env_sphdr_w)); + map(0x0049, 0x0049).rw(FUNC(epg3231_device::mtcon_sphtcon_r), FUNC(epg3231_device::mtcon_sphtcon_w)); + map(0x004a, 0x004a).rw(FUNC(epg3231_device::mtrl_sphtrl_r), FUNC(epg3231_device::mtrl_sphtrl_w)); + map(0x004b, 0x004b).rw(FUNC(epg3231_device::vocon_r), FUNC(epg3231_device::vocon_w)); + map(0x004c, 0x004c).r(FUNC(epg3231_device::tr1c_r)); + map(0x004d, 0x004d).r(FUNC(epg3231_device::tr2c_r)); + // TODO: ADCF (R4Eh) + // R4Fh is reserved + map(0x0050, 0x007f).ram(); +} + +epg3231_device::epg3231_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : riscii_series_device(mconfig, EPG3231, tag, owner, clock, 22, 18, 0x40000, 5, 0x1f, 0xbb, + address_map_constructor(FUNC(epg3231_device::regs_map), this)) { } @@ -102,30 +188,84 @@ device_memory_interface::space_config_vector riscii_series_device::memory_space_ }; } +void riscii_series_device::device_resolve_objects() +{ + m_porta_in_cb.resolve_safe(0xff); + for (auto &cb : m_port_in_cb) + cb.resolve_safe(0xff); + for (auto &cb : m_port_out_cb) + cb.resolve_safe(); +} + void riscii_series_device::device_start() { m_program = &space(AS_PROGRAM); m_regs = &space(AS_DATA); m_cache = m_program->cache<1, -1, ENDIANNESS_LITTLE>(); + if (m_pcmask > 0xffff) + m_pchstack = make_unique_clear<u8[]>(128); + set_icountptr(m_icount); - state_add(RII_PC, "PC", m_pc).mask((1 << m_prgbits) - 1); - state_add(STATE_GENPC, "GENPC", m_pc).mask((1 << m_prgbits) - 1).noshow(); - state_add(STATE_GENPCBASE, "CURPC", m_ppc).mask((1 << m_prgbits) - 1).noshow(); + state_add<u32>(RII_PC, "PC", [this]() { return m_pc; }, [this](u32 pc) { debug_set_pc(pc); }).mask(m_pcmask); + state_add<u32>(STATE_GENPC, "GENPC", [this]() { return m_pc; }, [this](u32 pc) { debug_set_pc(pc); }).mask(m_pcmask).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_ppc).mask(m_pcmask).noshow(); state_add(RII_REPEAT, "REPEAT", m_repeat); state_add(RII_ACC, "ACC", m_acc); state_add(RII_BSR, "BSR", m_bsr[0]).mask(m_bankmask); state_add(RII_FSR0, "FSR0", m_fsr[0]); state_add(RII_BSR1, "BSR1", m_bsr[1]).mask(m_bankmask); - state_add(RII_FSR1, "FSR1", m_fsr[1]); // TODO: high bit forced to 1 - state_add(RII_TABPTR, "TABPTR", m_tabptr).mask(0x800000 + (1 << (m_prgbits + 1)) - 1); + state_add<u8>(RII_FSR1, "FSR1", [this]() { return m_fsr[1]; }, [this](u8 data) { m_fsr[1] = data | 0x80; }); + state_add(RII_TABPTR, "TABPTR", m_tabptr).mask(m_tbptmask); state_add(RII_STKPTR, "STKPTR", m_stkptr); state_add(RII_CPUCON, "CPUCON", m_cpucon).mask(0x9f); state_add(RII_STATUS, "STATUS", m_status); state_add(STATE_GENFLAGS, "CURFLAGS", m_status).noshow().formatstr("%8s"); state_add(RII_PROD, "PROD", m_prod); - state_add(RII_POST_ID, "POST_ID", m_post_id); + state_add(RII_PFS, "PFS", m_pfs); + state_add(RII_INTCON, "INTCON", m_intcon); + state_add(RII_INTSTA, "INTSTA", m_intsta); + state_add(RII_POST_ID, "POST_ID", m_post_id).mask(m_post_id_mask); + state_add(RII_STBCON, "STBCON", m_stbcon); + state_add(RII_PAINTEN, "PAINTEN", m_painten); + state_add(RII_PAINTSTA, "PAINTSTA", m_paintsta); + state_add(RII_PAWAKE, "PAWAKE", m_pawake); + for (int i = 0; i < 2; i++) + { + state_add(RII_PORTB + i, string_format("PORT%c", i + 'B').c_str(), m_port_data[i]); + state_add(RII_DCRB + i, string_format("DCR%c", i + 'B').c_str(), m_port_dcr[i]); + state_add(RII_PBCON + i, string_format("P%cCON", i + 'B').c_str(), m_port_control[i]); + } + for (int i = 2; i < 6; i++) + { + int p = i * 2 - 2; + state_add(RII_PORTB + p, string_format("PORT%c", p + 'B').c_str(), m_port_data[p]); + state_add(RII_PORTB + p + 1, string_format("PORT%c", p + 'C').c_str(), m_port_data[p + 1]); + state_add(RII_DCRB + i, string_format("DCR%c%c", p + 'B', p + 'C').c_str(), m_port_dcr[i]); + } + state_add(RII_UARTCON, "UARTCON", m_uartcon); + state_add(RII_UARTSTA, "UARTSTA", m_uartsta); + state_add(RII_SPICON, "SPICON", m_spicon); + state_add(RII_SPISTA, "SPISTA", m_spista).mask(0xbf); + state_add(RII_TRL0, "TRL0", m_trl0); + state_add(RII_TRL1, "TRL1", m_trl1); + state_add(RII_TR01CON, "TR01CON", m_tr01con); + state_add(RII_TRL2, "TRL2", m_trl2); + state_add(RII_TR2CON, "TR2CON", m_tr2con); + state_add(RII_TRLIR, "TRLIR", m_trlir); + state_add(RII_SFCR, "SFCR", m_sfcr); + for (int i = 0; i < 4; i++) + { + state_add(RII_ADD1 + i, string_format("ADD%d", i + 1).c_str(), m_add[i]).mask(0xffffff); + state_add(RII_ENV1 + i, string_format("ENV%d", i + 1).c_str(), m_env[i]); + state_add(RII_MTCON1 + i, string_format("MTCON%d", i + 1).c_str(), m_mtcon[i]); + state_add(RII_MTRL1 + i, string_format("MTRL%d", i + 1).c_str(), m_mtrl[i]); + } + state_add(RII_SPHDR, "SPHDR", m_sphdr); + state_add(RII_SPHTCON, "SPHTCON", m_sphtcon); + state_add(RII_SPHTRL, "SPHTRL", m_sphtrl); + state_add(RII_VOCON, "VOCON", m_vocon); save_item(NAME(m_pc)); save_item(NAME(m_ppc)); @@ -136,8 +276,36 @@ void riscii_series_device::device_start() save_item(NAME(m_stkptr)); save_item(NAME(m_cpucon)); save_item(NAME(m_status)); + if (m_pcmask > 0xffff) + save_pointer(NAME(m_pchstack), 128); save_item(NAME(m_prod)); + save_item(NAME(m_pfs)); + save_item(NAME(m_intcon)); + save_item(NAME(m_intsta)); save_item(NAME(m_post_id)); + save_item(NAME(m_port_data)); + save_item(NAME(m_port_dcr)); + save_item(NAME(m_port_control)); + save_item(NAME(m_stbcon)); + save_item(NAME(m_painten)); + save_item(NAME(m_paintsta)); + save_item(NAME(m_pawake)); + save_item(NAME(m_uartcon)); + save_item(NAME(m_uartsta)); + save_item(NAME(m_spicon)); + save_item(NAME(m_spista)); + save_item(NAME(m_trl0)); + save_item(NAME(m_trl1)); + save_item(NAME(m_trl2)); + save_item(NAME(m_tr01con)); + save_item(NAME(m_tr2con)); + save_item(NAME(m_trlir)); + save_item(NAME(m_sfcr)); + save_item(NAME(m_add)); + save_item(NAME(m_env)); + save_item(NAME(m_mtcon)); + save_item(NAME(m_mtrl)); + save_item(NAME(m_vocon)); save_item(NAME(m_exec_state)); save_item(NAME(m_repeat)); save_item(NAME(m_curreg)); @@ -154,9 +322,48 @@ void riscii_series_device::device_reset() m_stkptr = 0x00; m_cpucon &= 0x01; m_status |= 0xc0; - m_post_id = 0xf0; + m_pfs = 0x20; + m_intcon = 0x00; + m_intsta = 0x00; + m_post_id = 0xf0 & m_post_id_mask; m_exec_state = EXEC_CYCLE1; m_repeat = 0x00; + + // reset ports (input mode, no pullups) + std::fill_n(&m_port_dcr[0], 2, 0xff); + std::fill_n(&m_port_dcr[2], 4, 0x33); + std::fill_n(&m_port_control[0], 2, 0x00); + m_stbcon = 0x40; + m_painten = 0x00; + m_paintsta = 0x00; + m_pawake = 0x00; + + // reset UART + m_uartcon = 0x02; + m_uartsta = 0x00; + + // reset SPI + m_spicon = 0x00; + m_spista = 0x00; + + // reset timers + m_tr01con = 0x00; + m_tr2con = 0x00; + m_sfcr = 0x00; + + // reset synthesizer + std::fill_n(&m_env[0], 4, 0x00); + std::fill_n(&m_mtcon[0], 4, 0x00); + std::fill_n(&m_mtrl[0], 4, 0x00); + m_sphdr = 0x00; + m_sphtcon = 0x00; + m_sphtrl = 0x00; + m_vocon = 0x07; +} + +void riscii_series_device::debug_set_pc(u32 pc) +{ + m_ppc = m_pc = pc; } @@ -221,7 +428,7 @@ u8 riscii_series_device::pcm_r() void riscii_series_device::pcm_w(u8 data) { - m_pc = (m_pc & 0xf00ff) | u32(data) << 8; + m_pc = (m_pc & 0xf00ff) | ((u32(data) << 8) & m_pcmask); } u8 riscii_series_device::pch_r() @@ -231,8 +438,7 @@ u8 riscii_series_device::pch_r() void riscii_series_device::pch_w(u8 data) { - if (m_prgbits > 16) - m_pc = (m_pc & 0x0ffff) | u32(data & ((1 << (m_prgbits - 16)) - 1)) << 16; + m_pc = (m_pc & 0x0ffff) | ((u32(data) << 16) & m_pcmask); } u8 riscii_series_device::tabptrl_r() @@ -262,7 +468,7 @@ u8 riscii_series_device::tabptrh_r() void riscii_series_device::tabptrh_w(u8 data) { - m_tabptr = (m_tabptr & 0x00ffff) | u32(data & (0x80 | ((1 << (m_prgbits - 15)) - 1))) << 16; + m_tabptr = (m_tabptr & 0x00ffff) | ((u32(data) << 16) & m_tbptmask); } u8 riscii_series_device::acc_r() @@ -302,6 +508,7 @@ u8 riscii_series_device::status_r() void riscii_series_device::status_w(u8 data) { + // TO and PD are read-only m_status = (m_status & 0xc0) | (data & 0x3f); } @@ -325,6 +532,36 @@ void riscii_series_device::prodh_w(u8 data) m_prod = (m_prod & 0x00ff) | u16(data) << 8; } +u8 riscii_series_device::pfs_r() +{ + return m_pfs; +} + +void riscii_series_device::pfs_w(u8 data) +{ + m_pfs = data; +} + +u8 riscii_series_device::intcon_r() +{ + return m_intcon; +} + +void riscii_series_device::intcon_w(u8 data) +{ + m_intcon = data; +} + +u8 riscii_series_device::intsta_r() +{ + return m_intsta; +} + +void riscii_series_device::intsta_w(u8 data) +{ + m_intsta = data; +} + u8 riscii_series_device::post_id_r() { return m_post_id; @@ -332,7 +569,426 @@ u8 riscii_series_device::post_id_r() void riscii_series_device::post_id_w(u8 data) { - m_post_id = data; + m_post_id = data & m_post_id_mask; +} + + +//************************************************************************** +// PORT REGISTER HANDLERS +//************************************************************************** + +u8 riscii_series_device::porta_r() +{ + // Port A is read-only + return m_porta_in_cb(); +} + +u8 riscii_series_device::port_r(offs_t offset) +{ + if (offset < 2) + { + u8 dc = m_port_dcr[offset]; + u8 pu = ~dc & m_port_control[offset]; + if (pu == 0xff) + return m_port_data[offset]; + else + return (m_port_data[offset] | dc) & (m_port_in_cb[offset](0, ~pu) | pu); + } + else + { + u8 control = (m_port_dcr[(offset >> 1) + 1] >> (BIT(offset, 0) ? 4 : 0)) & 0xf; + if (control == 0xc) + return m_port_data[offset]; + else + { + u8 dc = (BIT(control, 0) ? 0x0f : 0x00) | (BIT(control, 1) ? 0xf0 : 0x00); + u8 pu = ~dc & ((BIT(control, 2) ? 0x0f : 0x00) | (BIT(control, 3) ? 0xf0 : 0x00)); + return (m_port_data[offset] | dc) & (m_port_in_cb[offset](0, ~pu) | pu); + } + } +} + +void riscii_series_device::port_w(offs_t offset, u8 data) +{ + m_port_data[offset] = data; + if (offset < 2) + { + u8 dc = m_port_dcr[offset]; + if (dc != 0xff) + m_port_out_cb[offset](0, data, ~dc); + } + else + { + u8 control = (m_port_dcr[(offset >> 1) + 1] >> (BIT(offset, 0) ? 4 : 0)) & 0xf; + u8 dc = (BIT(control, 0) ? 0x0f : 0x00) | (BIT(control, 1) ? 0xf0 : 0x00); + if (dc != 0xff) + m_port_out_cb[offset](0, data, ~dc); + } +} + +u8 riscii_series_device::stbcon_r() +{ + return m_stbcon; +} + +void riscii_series_device::stbcon_w(u8 data) +{ + m_stbcon = data; +} + +u8 riscii_series_device::painten_r() +{ + return m_painten; +} + +void riscii_series_device::painten_w(u8 data) +{ + m_painten = data; +} + +u8 riscii_series_device::paintsta_r() +{ + return m_paintsta; +} + +void riscii_series_device::paintsta_w(u8 data) +{ + m_paintsta = data; +} + +u8 riscii_series_device::pawake_r() +{ + return m_pawake; +} + +void riscii_series_device::pawake_w(u8 data) +{ + m_pawake = data; +} + +u8 riscii_series_device::portjk_r(offs_t offset) +{ + return port_r(offset + 8); +} + +void riscii_series_device::portjk_w(offs_t offset, u8 data) +{ + port_w(offset + 8, data); +} + +u8 riscii_series_device::dcr_r(offs_t offset) +{ + return m_port_dcr[offset]; +} + +void riscii_series_device::dcr_w(offs_t offset, u8 data) +{ + m_port_dcr[offset] = data; +} + +u8 riscii_series_device::pcon_r(offs_t offset) +{ + return m_port_control[offset]; +} + +void riscii_series_device::pcon_w(offs_t offset, u8 data) +{ + m_port_control[offset] = data; +} + + +//************************************************************************** +// UART HANDLERS +//************************************************************************** + +void riscii_series_device::uarttx_w(u8 data) +{ + logerror("%05X: UARTTX = %02X\n", m_ppc, data); +} + +u8 riscii_series_device::uartrx_r() +{ + return 0; +} + +u8 riscii_series_device::uartcon_r() +{ + // TB8 is write-only + return m_uartcon & 0x7f; +} + +void riscii_series_device::uartcon_w(u8 data) +{ + // UTBE is read-only + m_uartcon = (data & 0xfd) | (m_uartcon & 0x02); +} + +u8 riscii_series_device::uartsta_r() +{ + return m_uartsta; +} + +void riscii_series_device::uartsta_w(u8 data) +{ + // RB8 and URBF are read-only + m_uartsta = (data & 0x7d) | (m_uartsta & 0x82); +} + + +//************************************************************************** +// SPI HANDLERS +//************************************************************************** + +u8 riscii_series_device::spicon_r() +{ + return m_spicon; +} + +void riscii_series_device::spicon_w(u8 data) +{ + m_spicon = data; +} + +u8 riscii_series_device::spista_r() +{ + return m_spista; +} + +void riscii_series_device::spista_w(u8 data) +{ + // RBF is read-only + m_spista = (data & 0xbe) | (m_spista & 0x01); +} + +u8 riscii_series_device::sprl_r() +{ + return 0; +} + +void riscii_series_device::sprl_w(u8 data) +{ + logerror("%05X: SPRL = %02X\n", m_ppc, data); +} + +u8 riscii_series_device::sprm_r() +{ + return 0; +} + +void riscii_series_device::sprm_w(u8 data) +{ + logerror("%05X: SPRM = %02X\n", m_ppc, data); +} + +u8 riscii_series_device::sprh_r() +{ + return 0; +} + +void riscii_series_device::sprh_w(u8 data) +{ + logerror("%05X: SPRH = %02X\n", m_ppc, data); +} + + +//************************************************************************** +// TIMER HANDLERS +//************************************************************************** + +u8 riscii_series_device::trl0l_r() +{ + return m_trl0 & 0x00ff; +} + +void riscii_series_device::trl0l_w(u8 data) +{ + m_trl0 = (m_trl0 & 0xff00) | data; +} + +u8 riscii_series_device::trl0h_r() +{ + return (m_trl0 & 0xff00) >> 8; +} + +void riscii_series_device::trl0h_w(u8 data) +{ + m_trl0 = u8(data) << 8 | (m_trl0 & 0x00ff); +} + +u8 riscii_series_device::trl1_r() +{ + return m_trl1; +} + +void riscii_series_device::trl1_w(u8 data) +{ + m_trl1 = data; +} + +u8 riscii_series_device::trl2_r() +{ + return m_trl2; +} + +void riscii_series_device::trl2_w(u8 data) +{ + m_trl2 = data; +} + +u8 riscii_series_device::tr01con_r() +{ + return m_tr01con; +} + +void riscii_series_device::tr01con_w(u8 data) +{ + m_tr01con = data; +} + +u8 riscii_series_device::tr2con_r() +{ + return m_tr2con; +} + +void riscii_series_device::tr2con_w(u8 data) +{ + m_tr2con = data; +} + +u8 riscii_series_device::trlir_r() +{ + return m_trlir; +} + +void riscii_series_device::trlir_w(u8 data) +{ + m_trlir = data; +} + +u8 riscii_series_device::t0cl_r() +{ + return 0x00; +} + +u8 riscii_series_device::t0ch_r() +{ + return 0x00; +} + +u8 riscii_series_device::tr1c_r() +{ + return 0xff; +} + +u8 riscii_series_device::tr2c_r() +{ + return 0xff; +} + +u8 riscii_series_device::sfcr_r() +{ + return m_sfcr; +} + +void riscii_series_device::sfcr_w(u8 data) +{ + m_sfcr = data; +} + + +//************************************************************************** +// MUSIC/SPEECH SYNTHESIZER +//************************************************************************** + +u8 riscii_series_device::addl_r() +{ + return m_add[BIT(m_sfcr, 2) ? 3 : m_sfcr & 0x03] & 0x0000ff; +} + +void riscii_series_device::addl_w(u8 data) +{ + u32 &add = m_add[BIT(m_sfcr, 2) ? 3 : m_sfcr & 0x03]; + add = (add & 0xffff00) | data; +} + +u8 riscii_series_device::addm_r() +{ + return (m_add[BIT(m_sfcr, 2) ? 3 : m_sfcr & 0x03] & 0x00ff00) >> 8; +} + +void riscii_series_device::addm_w(u8 data) +{ + u32 &add = m_add[BIT(m_sfcr, 2) ? 3 : m_sfcr & 0x03]; + add = (add & 0xff00ff) | u32(data) << 8; +} + +u8 riscii_series_device::addh_r() +{ + return (m_add[BIT(m_sfcr, 2) ? 3 : m_sfcr & 0x03] & 0xff0000) >> 8; +} + +void riscii_series_device::addh_w(u8 data) +{ + u32 &add = m_add[BIT(m_sfcr, 2) ? 3 : m_sfcr & 0x03]; + add = (add & 0x00ffff) | u32(data) << 16; +} + +u8 riscii_series_device::env_sphdr_r() +{ + if (BIT(m_sfcr, 2)) + return m_sphdr; + else + return m_env[m_sfcr & 0x03]; +} + +void riscii_series_device::env_sphdr_w(u8 data) +{ + if (BIT(m_sfcr, 2)) + m_sphdr = data; + else + m_env[m_sfcr & 0x03] = data; +} + +u8 riscii_series_device::mtcon_sphtcon_r() +{ + if (BIT(m_sfcr, 2)) + return m_sphtcon; + else + return m_mtcon[m_sfcr & 0x03]; +} + +void riscii_series_device::mtcon_sphtcon_w(u8 data) +{ + if (BIT(m_sfcr, 2)) + m_sphtcon = data; + else + m_mtcon[m_sfcr & 0x03] = data; +} + +u8 riscii_series_device::mtrl_sphtrl_r() +{ + if (BIT(m_sfcr, 2)) + return m_sphtrl; + else + return m_mtrl[m_sfcr & 0x03]; +} + +void riscii_series_device::mtrl_sphtrl_w(u8 data) +{ + if (BIT(m_sfcr, 2)) + m_sphtrl = data; + else + m_mtrl[m_sfcr & 0x03] = data; +} + +u8 riscii_series_device::vocon_r() +{ + return m_vocon; +} + +void riscii_series_device::vocon_w(u8 data) +{ + m_vocon = data; } @@ -340,6 +996,11 @@ void riscii_series_device::post_id_w(u8 data) // MEMORY HELPERS //************************************************************************** +u16 riscii_series_device::fetch_program_word() +{ + return m_cache->read_word(std::exchange(m_pc, (m_pc + 1) & m_pcmask)); +} + u16 riscii_series_device::get_banked_address(u8 reg) { if (reg == 0x00) @@ -367,13 +1028,13 @@ u16 riscii_series_device::get_banked_address(u8 reg) { m_fsr[1] = (m_fsr[1] + 1) | 0x80; if (m_fsr[1] == 0x80) - ++m_bsr[1]; + m_bsr[1] = (m_bsr[1] + 1) & m_bankmask; } else { m_fsr[1] = (m_fsr[1] - 1) | 0x80; if (m_fsr[1] == 0xff) - --m_bsr[1]; + m_bsr[1] = (m_bsr[1] - 1) & m_bankmask; } } return bfsr1; @@ -386,7 +1047,61 @@ u16 riscii_series_device::get_banked_address(u8 reg) u32 riscii_series_device::tabptr_offset(int offset) const { - return (m_tabptr & 0x800000) | ((m_tabptr + offset) & ((1 << (m_prgbits + 1)) - 1)); + return (m_tabptr + offset) & m_tbptmask; +} + +void riscii_series_device::multi_byte_carry(u16 addr, bool cy) +{ + if (addr == 0x0002) + m_exec_state = EXEC_ADCPCM; + else if (addr == 0x0009 && cy) + { + // FSR1 can carry into BSR1 + bsr1_w(bsr1_r() + 1); + } + else if (addr == 0x000b && cy) + { + // TABPTRL can carry into TABPTRM and TABPTRH + u8 midbyte = tabptrm_r() + 1; + tabptrm_w(midbyte); + if (midbyte == 0) + tabptrh_w(tabptrh_r() + 1); + } + else if (addr == 0x001c && cy) + { + // PORTF can carry into PORTE and PORTD + u8 midbyte = port_r(3); + port_w(3, midbyte); + if (midbyte == 0) + port_w(2, port_r(2) + 1); + } +} + +void riscii_series_device::multi_byte_borrow(u16 addr, bool cy) +{ + if (addr == 0x0002) + m_exec_state = EXEC_SBCPCM; + else if (addr == 0x0009 && !cy) + { + // FSR1 can borrow from BSR1 + bsr1_w(bsr1_r() - 1); + } + else if (addr == 0x000b && !cy) + { + // TABPTRL can borrow from TABPTRM and TABPTRH + u8 midbyte = tabptrm_r() - 1; + tabptrm_w(midbyte); + if (midbyte == 0xff) + tabptrh_w(tabptrh_r() - 1); + } + else if (addr == 0x001c && !cy) + { + // PORTF can borrow from PORTE and PORTD + u8 midbyte = port_r(3) - 1; + port_w(3, midbyte); + if (midbyte == 0xff) + port_w(2, port_r(2) + 1); + } } @@ -405,13 +1120,17 @@ void riscii_series_device::execute_add(u8 reg, bool a, bool c) u16 addr = get_banked_address(reg); s8 data = m_regs->read_byte(addr); s16 tmp = s16(data) + s8(m_acc) + (c ? m_status & 0x01 : 0); + bool cy = u16(data) + m_acc + (c ? m_status & 0x01 : 0) >= 0x100; bool dc = (data & 0x0f) + (m_acc & 0x0f) + (c ? m_status & 0x01 : 0) >= 0x10; if (a) acc_w(tmp & 0xff); else + { m_regs->write_byte(addr, tmp & 0xff); + multi_byte_carry(addr, cy); + } m_status = (m_status & 0xc0) - | (BIT(tmp, 8) ? 0x01 : 0x00) + | (cy ? 0x01 : 0x00) | (dc ? 0x02 : 0x00) | ((tmp & 0xff) == 0 ? 0x04 : 0x00) | ((tmp < 0) != BIT(tmp, 7) ? 0x08 : 0x00) @@ -424,13 +1143,17 @@ void riscii_series_device::execute_sub(u8 reg, bool a, bool c) u16 addr = get_banked_address(reg); s8 data = m_regs->read_byte(addr); s16 tmp = s16(data) - s8(m_acc) - (c ? ~m_status & 0x01 : 0); + bool cy = u8(data) >= m_acc + (c ? m_status & 0x01 : 0); // borrow is inverted bool dc = (data & 0x0f) >= (m_acc & 0x0f) + (c ? ~m_status & 0x01 : 0); if (a) acc_w(tmp & 0xff); else + { m_regs->write_byte(addr, tmp & 0xff); + multi_byte_borrow(addr, cy); + } m_status = (m_status & 0xc0) - | (BIT(tmp, 8) ? 0x00 : 0x01) // borrow is inverted + | (cy ? 0x01 : 0x00) | (dc ? 0x02 : 0x00) | ((tmp & 0xff) == 0 ? 0x04 : 0x00) | ((tmp < 0) != BIT(tmp, 7) ? 0x08 : 0x00) @@ -441,10 +1164,11 @@ void riscii_series_device::execute_sub(u8 reg, bool a, bool c) void riscii_series_device::execute_add_imm(u8 data, bool c) { s16 tmp = s16(s8(data)) + s8(m_acc) + (c ? m_status & 0x01 : 0); + bool cy = u16(data) + m_acc + (c ? m_status & 0x01 : 0) >= 0x100; bool dc = (data & 0x0f) + (m_acc & 0x0f) + (c ? m_status & 0x01 : 0) >= 0x10; acc_w(tmp & 0xff); m_status = (m_status & 0xc0) - | (BIT(tmp, 8) ? 0x01 : 0x00) + | (cy ? 0x01 : 0x00) | (dc ? 0x02 : 0x00) | ((tmp & 0xff) == 0 ? 0x04 : 0x00) | ((tmp < 0) != BIT(tmp, 7) ? 0x08 : 0x00) @@ -455,10 +1179,11 @@ void riscii_series_device::execute_add_imm(u8 data, bool c) void riscii_series_device::execute_sub_imm(u8 data, bool c) { s16 tmp = s16(s8(data)) - s8(m_acc) - (c ? ~m_status & 0x01 : 0); + bool cy = u8(data) >= m_acc + (c ? m_status & 0x01 : 0); // borrow is inverted bool dc = (data & 0x0f) + (m_acc & 0x0f) + (c ? ~m_status & 0x01 : 0) >= 0x10; acc_w(tmp & 0xff); m_status = (m_status & 0xc0) - | (BIT(tmp, 8) ? 0x00 : 0x01) // borrow is inverted + | (cy ? 0x01 : 0x00) | (dc ? 0x02 : 0x00) | ((tmp & 0xff) == 0 ? 0x04 : 0x00) | ((tmp < 0) != BIT(tmp, 7) ? 0x08 : 0x00) @@ -508,12 +1233,14 @@ void riscii_series_device::execute_subdb(u8 reg, bool a) void riscii_series_device::execute_mul(u8 reg) { - m_prod = u16(m_acc) * m_regs->read_byte(get_banked_address(reg)); + execute_mul_imm(m_regs->read_byte(get_banked_address(reg))); } void riscii_series_device::execute_mul_imm(u8 data) { - m_prod = u16(m_acc) * data; + int mier = BIT(m_cpucon, 3) ? int(s8(m_acc)) : int(m_acc); + int mcand = BIT(m_cpucon, 4) ? int(s8(data)) : int(data); + m_prod = u16(mier * mcand); } void riscii_series_device::execute_or(u8 reg, bool a) @@ -619,9 +1346,15 @@ void riscii_series_device::execute_jump(u32 addr) void riscii_series_device::execute_call(u32 addr) { + // Push PC to the stack region at the end of banked RAM m_stkptr -= 2; u16 stkaddr = u16(m_maxbank - (BIT(m_stkptr, 7) ? 0 : 1)) << 8 | 0x80 | (m_stkptr & 0x7e); m_regs->write_word(stkaddr, swapendian_int16(m_pc & 0xffff)); + + // PCH (on relevant models) must be saved somewhere. This implementation assumes a private buffer is used. + if (m_pcmask > 0xffff) + m_pchstack[m_stkptr >> 1] = (m_pc & 0xff0000) >> 16; + execute_jump(addr); } @@ -640,7 +1373,10 @@ void riscii_series_device::execute_jdnz(u8 reg, bool a) if (a) acc_w(tmp); else + { m_regs->write_byte(addr, tmp); + multi_byte_borrow(addr, tmp != 0xff); + } execute_jcc(tmp != 0); } @@ -651,7 +1387,10 @@ void riscii_series_device::execute_jinz(u8 reg, bool a) if (a) acc_w(tmp); else + { m_regs->write_byte(addr, tmp); + multi_byte_carry(addr, tmp == 0); + } execute_jcc(tmp != 0); } @@ -731,7 +1470,10 @@ void riscii_series_device::execute_inc(u8 reg, bool a) if (a) acc_w(tmp & 0xff); else + { m_regs->write_byte(addr, tmp & 0xff); + multi_byte_carry(addr, (tmp >> 8) != 0); + } m_status = (m_status & 0xfa) | ((tmp & 0xff) == 0 ? 0x04 : 0x00) | (tmp >> 8); } @@ -742,7 +1484,10 @@ void riscii_series_device::execute_dec(u8 reg, bool a) if (a) acc_w(tmp & 0xff); else + { m_regs->write_byte(addr, tmp & 0xff); + multi_byte_borrow(addr, (tmp >> 8) != 0); + } m_status = (m_status & 0xfa) | ((tmp & 0xff) == 0 ? 0x04 : 0x00) | (tmp >> 8); } @@ -753,21 +1498,27 @@ void riscii_series_device::execute_rpt(u8 reg) void riscii_series_device::execute_ret(bool inte) { + // Pop PC from the stack region at the end of banked RAM u16 stkaddr = u16(m_maxbank - (BIT(m_stkptr, 7) ? 0 : 1)) << 8 | 0x80 | (m_stkptr & 0x7e); - execute_jump((m_pc & 0xf0000) | swapendian_int16(m_regs->read_word(stkaddr))); + u32 dest = swapendian_int16(m_regs->read_word(stkaddr)); + if (m_pcmask > 0xffff) + dest |= u32(m_pchstack[m_stkptr >> 1]) << 16; + execute_jump(dest); m_stkptr += 2; + + // RETI also sets the global interrupt enable flag if (inte) m_cpucon |= 0x04; } void riscii_series_device::execute_wdtc() { - logerror("WDTC (PC = %05X)\n", m_ppc); + logerror("Watchdog timer reset (PC = %05X)\n", m_ppc); } void riscii_series_device::execute_slep() { - logerror("SLEP (PC = %05X)\n", m_ppc); + logerror("%s mode entered (PC = %05X)\n", BIT(m_cpucon, 1) ? "Idle" : "Sleep", m_ppc); } void riscii_series_device::execute_undef(u16 opcode) @@ -1058,9 +1809,13 @@ void riscii_series_device::execute_cycle1(u16 opcode) void riscii_series_device::execute_tbrd(u32 ptr) { - // TODO: "Bit 23 is used to select the internal/external memory" u16 addr = get_banked_address(m_curreg); - u16 data = m_program->read_word(ptr >> 1); + u32 memaddr = (ptr & 0x7ffffe) >> 1; + if (BIT(ptr, 23)) + memaddr += m_datastart; + else + memaddr &= m_pcmask; + u16 data = m_program->read_word(memaddr); if (BIT(ptr, 0)) m_regs->write_byte(addr, data >> 8); else @@ -1082,7 +1837,7 @@ void riscii_series_device::execute_run() debugger_instruction_hook(m_pc); if (m_repeat != 0) { - execute_cycle1(m_cache->read_word(m_pc++)); + execute_cycle1(fetch_program_word()); if (m_exec_state == EXEC_CYCLE1) { --m_repeat; @@ -1090,7 +1845,29 @@ void riscii_series_device::execute_run() } } else - execute_cycle1(m_cache->read_word(m_pc++)); + execute_cycle1(fetch_program_word()); + break; + + case EXEC_ADCPCM: + if (BIT(m_status, 0)) + { + u8 pcm = pcm_r() + 1; + pcm_w(pcm); + if (pcm == 0x00 && m_pcmask > 0xffff) + pch_w(pch_r() + 1); + } + m_exec_state = EXEC_CYCLE1; + break; + + case EXEC_SBCPCM: + if (!BIT(m_status, 0)) + { + u8 pcm = pcm_r() - 1; + pcm_w(pcm); + if (pcm == 0xff && m_pcmask > 0xffff) + pch_w(pch_r() - 1); + } + m_exec_state = EXEC_CYCLE1; break; case EXEC_TBRD0: @@ -1113,7 +1890,7 @@ void riscii_series_device::execute_run() case EXEC_L4JMP: case EXEC_L5JMP: case EXEC_L6JMP: case EXEC_L7JMP: case EXEC_L8JMP: case EXEC_L9JMP: case EXEC_LAJMP: case EXEC_LBJMP: case EXEC_LCJMP: case EXEC_LDJMP: case EXEC_LEJMP: case EXEC_LFJMP: - execute_jump(u32(m_exec_state - EXEC_L0JMP) << 16 | m_cache->read_word(m_pc++)); + execute_jump(u32(m_exec_state - EXEC_L0JMP) << 16 | fetch_program_word()); m_exec_state = EXEC_CYCLE1; break; @@ -1121,12 +1898,12 @@ void riscii_series_device::execute_run() case EXEC_L4CALL: case EXEC_L5CALL: case EXEC_L6CALL: case EXEC_L7CALL: case EXEC_L8CALL: case EXEC_L9CALL: case EXEC_LACALL: case EXEC_LBCALL: case EXEC_LCCALL: case EXEC_LDCALL: case EXEC_LECALL: case EXEC_LFCALL: - execute_call(u32(m_exec_state - EXEC_L0CALL) << 16 | m_cache->read_word(m_pc++)); + execute_call(u32(m_exec_state - EXEC_L0CALL) << 16 | fetch_program_word()); m_exec_state = EXEC_CYCLE1; break; case EXEC_NOJMP: - (void)m_cache->read_word(m_pc++); + (void)fetch_program_word(); m_exec_state = EXEC_CYCLE1; break; } diff --git a/src/devices/cpu/rii/riscii.h b/src/devices/cpu/rii/riscii.h index 835d9469f46..c670c1ea813 100644 --- a/src/devices/cpu/rii/riscii.h +++ b/src/devices/cpu/rii/riscii.h @@ -30,16 +30,60 @@ public: RII_CPUCON, RII_STATUS, RII_PROD, - RII_POST_ID + RII_PFS, + RII_INTCON, + RII_INTSTA, + RII_POST_ID, + RII_PORTB, RII_PORTC, RII_PORTD, RII_PORTE, RII_PORTF, RII_PORTG, RII_PORTH, RII_PORTI, RII_PORTJ, RII_PORTK, + RII_STBCON, + RII_PAINTEN, RII_PAINTSTA, RII_PAWAKE, + RII_DCRB, RII_DCRC, RII_DCRDE, RII_DCRFG, RII_DCRHI, RII_DCRJK, + RII_PBCON, RII_PCCON, + RII_UARTCON, RII_UARTSTA, + RII_SPICON, RII_SPISTA, + RII_TRL0, RII_TRL1, RII_TRL2, + RII_TR01CON, + RII_TR2CON, + RII_TRLIR, + RII_SFCR, + RII_ADD1, RII_ADD2, RII_ADD3, RII_ADD4, + RII_ENV1, RII_ENV2, RII_ENV3, RII_ENV4, + RII_MTCON1, RII_MTCON2, RII_MTCON3, RII_MTCON4, + RII_MTRL1, RII_MTRL2, RII_MTRL3, RII_MTRL4, + RII_SPHDR, + RII_SPHTCON, + RII_SPHTRL, + RII_VOCON }; - // construction/destruction - riscii_series_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + // callback configuration + auto in_porta_cb() { return m_porta_in_cb.bind(); } + auto in_portb_cb() { return m_port_in_cb[0].bind(); } + auto out_portb_cb() { return m_port_out_cb[0].bind(); } + auto in_portc_cb() { return m_port_in_cb[1].bind(); } + auto out_portc_cb() { return m_port_out_cb[1].bind(); } + auto in_portd_cb() { return m_port_in_cb[2].bind(); } + auto out_portd_cb() { return m_port_out_cb[2].bind(); } + auto in_porte_cb() { return m_port_in_cb[3].bind(); } + auto out_porte_cb() { return m_port_out_cb[3].bind(); } + auto in_portf_cb() { return m_port_in_cb[4].bind(); } + auto out_portf_cb() { return m_port_out_cb[4].bind(); } + auto in_portg_cb() { return m_port_in_cb[5].bind(); } + auto out_portg_cb() { return m_port_out_cb[5].bind(); } + auto in_porth_cb() { return m_port_in_cb[6].bind(); } + auto out_porth_cb() { return m_port_out_cb[6].bind(); } + auto in_porti_cb() { return m_port_in_cb[7].bind(); } + auto out_porti_cb() { return m_port_out_cb[7].bind(); } + auto in_portj_cb() { return m_port_in_cb[8].bind(); } + auto out_portj_cb() { return m_port_out_cb[8].bind(); } + auto in_portk_cb() { return m_port_in_cb[9].bind(); } + auto out_portk_cb() { return m_port_out_cb[9].bind(); } protected: - riscii_series_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, unsigned prgbits, unsigned bankbits, uint8_t maxbank); + riscii_series_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, unsigned addrbits, unsigned pcbits, u32 datastart, unsigned bankbits, u8 maxbank, u8 post_id_mask, address_map_constructor regs); // device-level overrides + virtual void device_resolve_objects() override; virtual void device_start() override; virtual void device_reset() override; @@ -47,16 +91,14 @@ protected: virtual void execute_run() override; virtual void execute_set_input(int inputnum, int state) override; - // device_disasm_interface overrides - virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; - // device_memory_interface overrides virtual space_config_vector memory_space_config() const override; // device_state_interface overrides virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; -private: + void core_regs_map(address_map &map); + // register handlers u8 fsr0_r(); void fsr0_w(u8 data); @@ -90,12 +132,92 @@ private: void prodl_w(u8 data); u8 prodh_r(); void prodh_w(u8 data); + u8 pfs_r(); + void pfs_w(u8 data); + u8 intcon_r(); + void intcon_w(u8 data); + u8 intsta_r(); + void intsta_w(u8 data); u8 post_id_r(); void post_id_w(u8 data); + u8 porta_r(); + u8 port_r(offs_t offset); + void port_w(offs_t offset, u8 data); + u8 stbcon_r(); + void stbcon_w(u8 data); + u8 painten_r(); + void painten_w(u8 data); + u8 paintsta_r(); + void paintsta_w(u8 data); + u8 pawake_r(); + void pawake_w(u8 data); + u8 portjk_r(offs_t offset); + void portjk_w(offs_t offset, u8 data); + u8 dcr_r(offs_t offset); + void dcr_w(offs_t offset, u8 data); + u8 pcon_r(offs_t offset); + void pcon_w(offs_t offset, u8 data); + void uarttx_w(u8 data); + u8 uartrx_r(); + u8 uartcon_r(); + void uartcon_w(u8 data); + u8 uartsta_r(); + void uartsta_w(u8 data); + u8 spicon_r(); + void spicon_w(u8 data); + u8 spista_r(); + void spista_w(u8 data); + u8 sprl_r(); + void sprl_w(u8 data); + u8 sprm_r(); + void sprm_w(u8 data); + u8 sprh_r(); + void sprh_w(u8 data); + u8 trl0l_r(); + void trl0l_w(u8 data); + u8 trl0h_r(); + void trl0h_w(u8 data); + u8 trl1_r(); + void trl1_w(u8 data); + u8 trl2_r(); + void trl2_w(u8 data); + u8 tr01con_r(); + void tr01con_w(u8 data); + u8 tr2con_r(); + void tr2con_w(u8 data); + u8 trlir_r(); + void trlir_w(u8 data); + u8 t0cl_r(); + u8 t0ch_r(); + u8 tr1c_r(); + u8 tr2c_r(); + u8 sfcr_r(); + void sfcr_w(u8 data); + u8 addl_r(); + void addl_w(u8 data); + u8 addm_r(); + void addm_w(u8 data); + u8 addh_r(); + void addh_w(u8 data); + u8 env_sphdr_r(); + void env_sphdr_w(u8 data); + u8 mtcon_sphtcon_r(); + void mtcon_sphtcon_w(u8 data); + u8 mtrl_sphtrl_r(); + void mtrl_sphtrl_w(u8 data); + u8 vocon_r(); + void vocon_w(u8 data); + +private: + // debugging helpers + void debug_set_pc(u32 pc); // memory helpers + u16 fetch_program_word(); u16 get_banked_address(u8 reg); u32 tabptr_offset(int offset) const; + void multi_byte_carry(u16 addr, bool cy); + void multi_byte_borrow(u16 addr, bool cy); // execution void execute_move(u8 dstreg, u8 srcreg); @@ -143,6 +265,7 @@ private: enum exec_state : u8 { EXEC_CYCLE1, + EXEC_ADCPCM, EXEC_SBCPCM, EXEC_TBRD0, EXEC_TBRD1, EXEC_TBRD2, EXEC_TBRDA, EXEC_NOJMP, EXEC_L0JMP, EXEC_L1JMP, EXEC_L2JMP, EXEC_L3JMP, @@ -155,8 +278,6 @@ private: EXEC_LCCALL, EXEC_LDCALL, EXEC_LECALL, EXEC_LFCALL }; - void regs_map(address_map &map); - // address spaces address_space_config m_program_config; address_space_config m_regs_config; @@ -164,10 +285,18 @@ private: address_space *m_regs; memory_access_cache<1, -1, ENDIANNESS_LITTLE> *m_cache; + // device callbacks + devcb_read8 m_porta_in_cb; + devcb_read8 m_port_in_cb[10]; + devcb_write8 m_port_out_cb[10]; + // model-specific parameters - const unsigned m_prgbits; - const uint8_t m_bankmask; - const uint8_t m_maxbank; + const u32 m_pcmask; + const u32 m_datastart; + const u32 m_tbptmask; + const u8 m_bankmask; + const u8 m_maxbank; + const u8 m_post_id_mask; // internal state u32 m_pc; @@ -177,11 +306,51 @@ private: u8 m_bsr[2]; u32 m_tabptr; u8 m_stkptr; + std::unique_ptr<u8[]> m_pchstack; u8 m_cpucon; u8 m_status; u16 m_prod; + u8 m_pfs; + u8 m_intcon; + u8 m_intsta; u8 m_post_id; + // port state + u8 m_port_data[10]; + u8 m_port_dcr[6]; + u8 m_port_control[2]; + u8 m_stbcon; + u8 m_painten; + u8 m_paintsta; + u8 m_pawake; + + // UART state + u8 m_uartcon; + u8 m_uartsta; + + // SPI state + u8 m_spicon; + u8 m_spista; + + // timer state + u16 m_trl0; + u8 m_trl1; + u8 m_trl2; + u8 m_tr01con; + u8 m_tr2con; + u8 m_trlir; + u8 m_sfcr; + + // synthesizer state + u32 m_add[4]; + u8 m_env[4]; + u8 m_mtcon[4]; + u8 m_mtrl[4]; + u8 m_sphdr; + u8 m_sphtcon; + u8 m_sphtrl; + u8 m_vocon; + // execution sequencing s32 m_icount; exec_state m_exec_state; @@ -189,6 +358,20 @@ private: u8 m_curreg; }; -DECLARE_DEVICE_TYPE(RISCII, riscii_series_device) +class epg3231_device : public riscii_series_device +{ +public: + // construction/destruction + epg3231_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + // device_disasm_interface overrides + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + +private: + void regs_map(address_map &map); +}; + +DECLARE_DEVICE_TYPE(EPG3231, epg3231_device) #endif // MAME_CPU_RII_RISCII_H diff --git a/src/mame/drivers/vtech_eu3a12.cpp b/src/mame/drivers/vtech_eu3a12.cpp index f60f3ffc1bc..c3e75f39378 100644 --- a/src/mame/drivers/vtech_eu3a12.cpp +++ b/src/mame/drivers/vtech_eu3a12.cpp @@ -1,7 +1,7 @@ // license:BSD-3-Clause // copyright-holders:Sandro Ronco -// CPU die is an Elan EU3A12 (Elan "RISC II Series" quasi-PIC with 16-bit opcodes) +// CPU die (epoxy blob) is an Elan EU3A12 (Elan "RISC II Series" quasi-PIC with 16-bit opcodes) #include "emu.h" #include "cpu/rii/riscii.h" @@ -22,7 +22,7 @@ private: void prog_map(address_map &map); - required_device<cpu_device> m_maincpu; + required_device<riscii_series_device> m_maincpu; }; uint32_t vreadere_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) @@ -32,7 +32,7 @@ uint32_t vreadere_state::screen_update(screen_device &screen, bitmap_rgb32 &bitm void vreadere_state::prog_map(address_map &map) { - map(0x00000, 0x3ffff).rom().region("maincpu", 0); + map(0x000000, 0x1fffff).rom().region("maincpu", 0); } static INPUT_PORTS_START( vreadere ) @@ -40,7 +40,7 @@ INPUT_PORTS_END void vreadere_state::vreadere(machine_config &config) { - RISCII(config, m_maincpu, 10'000'000); // CPU type is unknown, epoxy blob + EPG3231(config, m_maincpu, 10'000'000); m_maincpu->set_addrmap(AS_PROGRAM, &vreadere_state::prog_map); /* video hardware */ diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index b2361ff7ffd..cd164db7776 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -354,6 +354,7 @@ static const dasm_table_entry dasm_table[] = { "dsp32c", le, 0, []() -> util::disasm_interface * { return new dsp32c_disassembler; } }, { "dsp56156", le, -1, []() -> util::disasm_interface * { return new dsp56156_disassembler; } }, { "e0c6200", be, -1, []() -> util::disasm_interface * { return new e0c6200_disassembler; } }, + { "epg3231", le, -1, []() -> util::disasm_interface * { return new epg3231_disassembler; } }, // { "es5510", be, 0, []() -> util::disasm_interface * { return new es5510_disassembler; } }, // Currently does nothing { "esrip", be, 0, []() -> util::disasm_interface * { return new esrip_disassembler; } }, { "f2mc16", le, 0, []() -> util::disasm_interface * { return new f2mc16_disassembler; } }, @@ -448,7 +449,6 @@ static const dasm_table_entry dasm_table[] = { "pps4", le, 0, []() -> util::disasm_interface * { return new pps4_disassembler; } }, { "psxcpu", le, 0, []() -> util::disasm_interface * { return new psxcpu_disassembler; } }, { "r65c02", le, 0, []() -> util::disasm_interface * { return new r65c02_disassembler; } }, - { "rii", le, -1, []() -> util::disasm_interface * { return new riscii_disassembler; } }, { "rsp", le, 0, []() -> util::disasm_interface * { return new rsp_disassembler; } }, { "s2650", le, 0, []() -> util::disasm_interface * { return new s2650_disassembler(&s2650_unidasm); } }, { "saturn", le, 0, []() -> util::disasm_interface * { return new saturn_disassembler(&saturn_unidasm); } }, |