summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2019-09-25 11:48:22 -0400
committer AJR <ajrhacker@users.noreply.github.com>2019-09-25 11:57:56 -0400
commita24caaede8da2f17d6f8d28d6ea2292b07f044bf (patch)
tree2c0b0031e015893b22615be1581eab0d97dc0432 /src
parenta73d55f52edf0abcba904cd1939beb3dfc81ac02 (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.cpp8
-rw-r--r--src/devices/cpu/rii/riidasm.h12
-rw-r--r--src/devices/cpu/rii/riscii.cpp879
-rw-r--r--src/devices/cpu/rii/riscii.h211
-rw-r--r--src/mame/drivers/vtech_eu3a12.cpp8
-rw-r--r--src/tools/unidasm.cpp2
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); } },