summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2021-04-27 14:06:19 -0400
committer AJR <ajrhacker@users.noreply.github.com>2021-04-27 14:06:19 -0400
commite9e66e0224b86d0383643f7a52ce2639421d2a23 (patch)
treee64bf46c1a878fdfd531723bf15c10885708b548
parent6b420210335ddefbc04de81cf8ca33f03858f316 (diff)
mn1880: Add preliminary CPU emulation
-rw-r--r--src/devices/cpu/mn1880/mn1880.cpp2299
-rw-r--r--src/devices/cpu/mn1880/mn1880.h169
-rw-r--r--src/mame/drivers/basssta.cpp32
-rw-r--r--src/mame/drivers/drumsta.cpp10
-rw-r--r--src/mame/drivers/macpci.cpp24
-rw-r--r--src/mame/includes/macpci.h1
6 files changed, 2474 insertions, 61 deletions
diff --git a/src/devices/cpu/mn1880/mn1880.cpp b/src/devices/cpu/mn1880/mn1880.cpp
index cf837a53d28..f967e9a9853 100644
--- a/src/devices/cpu/mn1880/mn1880.cpp
+++ b/src/devices/cpu/mn1880/mn1880.cpp
@@ -2,9 +2,58 @@
// copyright-holders:AJR
/***************************************************************************
- Panasonic MN1880 family
+ Panasonic MN1880 series
- Currently this device is just a stub with no actual execution core.
+ This is a cycle-by-cycle emulation of the "8-Bit Dual Microcomputer"
+ architecture, which has two independent CPUs sharing the same memory
+ spaces and execution core, with execution phases interleaved when both
+ CPUs are operating. Pipelining permits operand fetches to overlap with
+ data writes.
+
+ Known issues:
+ * Only one generic device type has been provided, with no internal
+ RAM or ROM. Though the broad functional descriptions of many actual
+ models are known, more detailed documentation is not easy to find.
+ * Almost no internal special function registers have been emulated,
+ again owing to lack of documentation. It is unknown to what extent
+ their mapping differs between models.
+ * Instruction timings are based mostly on those documented for the
+ MN1870, which lacks a number of MN1880 instructions and differs in
+ some other important ways. Many have been guessed at.
+ * Some instruction behavior, especially for repeated cases, has been
+ guessed at and may not be strictly correct.
+ * No interrupts have been emulated. It remains unclear exactly how
+ MN1880 interrupts are enabled and prioritized, or what their sources
+ might be, though they are obviously internally vectored through the
+ table at the start of the program space.
+ * The PI (software interrupt) instruction is likewise unemulated,
+ since its vector is uncertain; though possibly implicitly inserted
+ when an interrupt is acknowledged, explicit uses of it are
+ nonexistent in extant code.
+ * The output queue has been implemented only for memory writes, even
+ though the MN1870 documentation shows it as applicable for
+ instructions that do none of those.
+ * Every cycle fetches a byte from the instruction space, whether it
+ is needed for execution or not. This fetching may not happen quite
+ so continuously on actual hardware (a few dummy fetches may be
+ unavoidable), but it is more or less continuous on some other
+ microcontrollers with Harvard-like architectures such as MCS-51.
+ * Data writes occur simultaneously with program fetches. Harvard
+ architecture makes instruction and data spaces independent from the
+ code's perspective, but simultaneous access is obviously impossible
+ when both addresses are external since there is at most one external
+ address bus. Contention should slow prefetching and execution down.
+ * Additional wait states for external memory, if any, are not emulated.
+ * When execution is stopped in the debugger, IP already points to the
+ byte following the opcode which has been loaded into IR. This at
+ least seems consistent with the prefetch model and the handling of
+ repeated instructions.
+ * There is no way to focus on one of the two CPUs in the debugger when
+ both are executing. This is not an issue on systems that simply
+ disable CPUb from the start.
+ * The debugger will not single-step through repeated instructions.
+ Making MAME's context-insensitive disassembler produce any sensible
+ output for these would be very difficult.
***************************************************************************/
@@ -15,20 +64,43 @@
// device type definitions
DEFINE_DEVICE_TYPE(MN1880, mn1880_device, "mn1880", "Panasonic MN1880")
-mn1880_device::mn1880_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : cpu_device(mconfig, MN1880, tag, owner, clock)
+ALLOW_SAVE_TYPE(mn1880_device::microstate)
+
+mn1880_device::mn1880_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor data_map)
+ : cpu_device(mconfig, type, tag, owner, clock)
, m_program_config("program", ENDIANNESS_BIG, 8, 16, 0)
- , m_data_config("data", ENDIANNESS_LITTLE, 8, 16, 0)
- , m_ip(0)
- , m_fs(0)
- , m_xp(0)
- , m_yp(0)
- , m_sp(0)
- , m_lp(0)
+ , m_data_config("data", ENDIANNESS_LITTLE, 8, 16, 0, data_map)
+ , m_cpu_select(false)
+ , m_cpum(0)
+ , m_ustate(microstate::UNKNOWN)
+ , m_da(0)
+ , m_tmp1(0)
+ , m_tmp2(0)
+ , m_output_queued(false)
, m_icount(0)
{
}
+mn1880_device::mn1880_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : mn1880_device(mconfig, MN1880, tag, owner, clock, address_map_constructor(FUNC(mn1880_device::internal_data_map), this))
+{
+}
+
+u8 mn1880_device::cpum_r()
+{
+ return m_cpum;
+}
+
+void mn1880_device::cpum_w(u8 data)
+{
+ m_cpum = data;
+}
+
+void mn1880_device::internal_data_map(address_map &map)
+{
+ map(0x0016, 0x0016).rw(FUNC(mn1880_device::cpum_r), FUNC(mn1880_device::cpum_w));
+}
+
std::unique_ptr<util::disasm_interface> mn1880_device::create_disassembler()
{
return std::make_unique<mn1880_disassembler>();
@@ -48,54 +120,2178 @@ void mn1880_device::device_start()
space(AS_DATA).specific(m_data);
set_icountptr(m_icount);
- state_add(MN1880_IP, "IP", m_ip);
- state_add(STATE_GENPC, "GENPC", m_ip).noshow();
- state_add(STATE_GENPCBASE, "CURPC", m_ip).noshow();
- state_add(MN1880_FS, "FS", m_fs);
- state_add(STATE_GENFLAGS, "FLAGS", m_fs).formatstr("%10s").noshow();
- state_add(MN1880_XP, "XP", m_xp);
- state_add(MN1880_YP, "YP", m_yp);
+ using namespace std::placeholders;
+ state_add<u16>(MN1880_IP, "IP",
+ [this] () { return m_cpu[int(m_cpu_select)].ip; },
+ [this] (u16 data) { m_cpu[int(m_cpu_select)].ip = data; }
+ ).noshow();
+ state_add<u16>(STATE_GENPC, "GENPC",
+ [this] () { return m_cpu[int(m_cpu_select)].ip; },
+ [this] (u16 data) { m_cpu[int(m_cpu_select)].ip = data; }
+ ).noshow();
+ state_add<u16>(STATE_GENPCBASE, "CURPC",
+ [this] () { return m_cpu[int(m_cpu_select)].irp; },
+ [this] (u16 data) { m_cpu[int(m_cpu_select)].irp = data; }
+ ).noshow();
+ state_add<u8>(MN1880_IR, "IR",
+ [this] () { return m_cpu[int(m_cpu_select)].ir; },
+ [this] (u8 data) { m_cpu[int(m_cpu_select)].ir = data; }
+ ).noshow();
+ state_add<u8>(MN1880_FS, "FS",
+ [this] () { return m_cpu[int(m_cpu_select)].fs; },
+ [this] (u8 data) { m_cpu[int(m_cpu_select)].fs = data; }
+ ).noshow();
+ state_add<u8>(STATE_GENFLAGS, "FLAGS",
+ [this] () { return m_cpu[int(m_cpu_select)].fs; },
+ [this] (u8 data) { m_cpu[int(m_cpu_select)].fs = data; }
+ ).formatstr("%10s").noshow();
+ state_add<u16>(MN1880_XP, "XP",
+ [this] () { return m_cpu[int(m_cpu_select)].xp; },
+ [this] (u16 data) { m_cpu[int(m_cpu_select)].xp = data; }
+ ).noshow();
+ state_add<u16>(MN1880_YP, "YP",
+ [this] () { return m_cpu[int(m_cpu_select)].yp; },
+ [this] (u16 data) { m_cpu[int(m_cpu_select)].yp = data; }
+ ).noshow();
state_add<u8>(MN1880_XPL, "XPl",
- [this] () { return m_xp & 0x00ff; },
- [this] (u8 data) { m_xp = (m_xp & 0xff00) | data; }
+ [this] () { return m_cpu[int(m_cpu_select)].xp & 0x00ff; },
+ [this] (u8 data) { setl(m_cpu[int(m_cpu_select)].xp, data); }
).noshow();
state_add<u8>(MN1880_XPH, "XPh",
- [this] () { return (m_xp & 0xff00) >> 8; },
- [this] (u8 data) { m_xp = (m_xp & 0x00ff) | u16(data) << 8; }
+ [this] () { return (m_cpu[int(m_cpu_select)].xp & 0xff00 >> 8); },
+ [this] (u8 data) { seth(m_cpu[int(m_cpu_select)].xp, data); }
).noshow();
state_add<u8>(MN1880_YPL, "YPl",
- [this] () { return m_yp & 0x00ff; },
- [this] (u8 data) { m_yp = (m_yp & 0xff00) | data; }
+ [this] () { return m_cpu[int(m_cpu_select)].yp & 0x00ff; },
+ [this] (u8 data) { setl(m_cpu[int(m_cpu_select)].yp, data); }
).noshow();
state_add<u8>(MN1880_YPH, "YPh",
- [this] () { return (m_yp & 0xff00) >> 8; },
- [this] (u8 data) { m_yp = (m_yp & 0x00ff) | u16(data) << 8; }
+ [this] () { return (m_cpu[int(m_cpu_select)].yp & 0xff00 >> 8); },
+ [this] (u8 data) { seth(m_cpu[int(m_cpu_select)].yp, data); }
+ ).noshow();
+ state_add<u16>(MN1880_SP, "SP",
+ [this] () { return m_cpu[int(m_cpu_select)].sp; },
+ [this] (u16 data) { m_cpu[int(m_cpu_select)].sp = data; }
+ ).noshow();
+ state_add<u16>(MN1880_LP, "LP",
+ [this] () { return m_cpu[int(m_cpu_select)].lp; },
+ [this] (u16 data) { m_cpu[int(m_cpu_select)].lp = data; }
).noshow();
- state_add(MN1880_SP, "SP", m_sp);
- state_add(MN1880_LP, "LP", m_lp);
- save_item(NAME(m_ip));
- save_item(NAME(m_fs));
- save_item(NAME(m_xp));
- save_item(NAME(m_yp));
- save_item(NAME(m_sp));
- save_item(NAME(m_lp));
+ for (int i = 0; i < 2; i++)
+ {
+ state_add(MN1880_IPA + i, util::string_format("IP%c", 'a' + i).c_str(), m_cpu[i].ip).formatstr("%5s");
+ state_add(MN1880_IRA + i, util::string_format("IR%c", 'a' + i).c_str(), m_cpu[i].ir);
+ state_add(MN1880_FSA + i, util::string_format("FS%c", 'a' + i).c_str(), m_cpu[i].fs);
+ state_add(MN1880_XPA + i, util::string_format("XP%c", 'a' + i).c_str(), m_cpu[i].xp);
+ state_add(MN1880_YPA + i, util::string_format("YP%c", 'a' + i).c_str(), m_cpu[i].yp);
+ state_add(MN1880_SPA + i, util::string_format("SP%c", 'a' + i).c_str(), m_cpu[i].sp);
+ state_add(MN1880_LPA + i, util::string_format("LP%c", 'a' + i).c_str(), m_cpu[i].lp);
+ state_add_divider(MN1880_DIVIDER1 + i);
+ }
+
+ state_add(MN1880_CPUM, "CPUM", m_cpum);
+
+ save_item(STRUCT_MEMBER(m_cpu, ip));
+ save_item(STRUCT_MEMBER(m_cpu, irp));
+ save_item(STRUCT_MEMBER(m_cpu, ir));
+ save_item(STRUCT_MEMBER(m_cpu, fs));
+ save_item(STRUCT_MEMBER(m_cpu, xp));
+ save_item(STRUCT_MEMBER(m_cpu, yp));
+ save_item(STRUCT_MEMBER(m_cpu, sp));
+ save_item(STRUCT_MEMBER(m_cpu, lp));
+ save_item(NAME(m_cpu_select));
+ save_item(NAME(m_cpum));
+ save_item(NAME(m_ustate));
+ save_item(NAME(m_da));
+ save_item(NAME(m_tmp1));
+ save_item(NAME(m_tmp2));
+ save_item(NAME(m_output_queued));
}
void mn1880_device::device_reset()
{
- m_fs &= 0xc0; // CF & ZF might or might not be cleared as well
- m_sp = 0x0100;
- // TBD: is LP also initialized at reset?
+ for (cpu_registers &cpu : m_cpu)
+ {
+ cpu.fs &= 0xc0; // CF & ZF might or might not be cleared as well
+ cpu.fs |= 0x10; // HACK: skip fake first instruction in debugger
+ cpu.ir = 0xf6;
+ cpu.wait = 0;
+ }
+ m_cpu[0].ip = 0x0000;
+ m_cpu[1].ip = 0x0020;
+
+ // TBD: exactly what are SP and LP initialized to for each CPU?
+ m_cpu[0].sp = 0x0100;
+ m_cpu[0].lp = 0x0060;
+ m_cpu[1].sp = 0x0200;
+ m_cpu[1].lp = 0x0160;
+
+ m_cpum = 0x0c;
+ m_ustate = microstate::NEXT;
+ m_output_queued = false;
+}
+
+const mn1880_device::microstate mn1880_device::s_decode_map[256] =
+{
+ microstate::NOP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1,
+ microstate::REP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1, microstate::REP_1,
+ microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1,
+ microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1, microstate::CLRSET_1,
+ microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1,
+ microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1, microstate::T1B_1,
+ microstate::UNKNOWN, microstate::MOVL31_1, microstate::UNKNOWN, microstate::MOVL31_1, microstate::MOVL34_1, microstate::MOVL35_1, microstate::MOV36_1, microstate::MOV37_1,
+ microstate::MOVL38_1, microstate::MOVL39_1, microstate::MOVL38_1, microstate::MOVL39_1, microstate::ASL_1, microstate::ASL_1, microstate::ASR_1, microstate::ASR_1,
+ microstate::DEC40_1, microstate::DEC40_1, microstate::NOT_1, microstate::NOT_1, microstate::CMPM44_1, microstate::CMPM45_1, microstate::XCH4_1, microstate::XCH4_1,
+ microstate::INC48_1, microstate::INC48_1, microstate::CLR4A_1, microstate::CLR4A_1, microstate::ROL_1, microstate::ROL_1, microstate::ROR_1, microstate::ROR_1,
+ microstate::CMPM50_1, microstate::DIV51_1, microstate::CMPM52_1, microstate::MOVDA_1, microstate::MOV54_1, microstate::MOV55_1, microstate::MOV56_1, microstate::MOV56_1,
+ microstate::XCH58_1, microstate::MUL59_1, microstate::XCH58_1, microstate::UNKNOWN, microstate::MOVL5C_1, microstate::MOVL5D_1, microstate::MOVL5E_1, microstate::MOVL5F_1,
+ microstate::CMP_1, microstate::CMP_1, microstate::CMP_1, microstate::CMP_1, microstate::AND_1, microstate::AND_1, microstate::AND_1, microstate::AND_1,
+ microstate::XOR_1, microstate::XOR_1, microstate::XOR_1, microstate::XOR_1, microstate::OR_1, microstate::OR_1, microstate::OR_1, microstate::OR_1,
+ microstate::SUBC_1, microstate::SUBC_1, microstate::SUBC_1, microstate::SUBC_1, microstate::SUBD_1, microstate::SUBD_1, microstate::SUBD_1, microstate::SUBD_1,
+ microstate::ADDC_1, microstate::ADDC_1, microstate::ADDC_1, microstate::ADDC_1, microstate::ADDD_1, microstate::ADDD_1, microstate::ADDD_1, microstate::ADDD_1,
+ microstate::BR80_1, microstate::BR80_1, microstate::BR80_1, microstate::BR80_1, microstate::CMPL_1, microstate::CLRFS_1, microstate::CMPL_1, microstate::CLRFS_1,
+ microstate::BR88_1, microstate::BR88_1, microstate::BR88_1, microstate::BR88_1, microstate::UNKNOWN, microstate::SETFS_1, microstate::UNKNOWN, microstate::SETFS_1,
+ microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1,
+ microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1, microstate::CALL90_1,
+ microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1,
+ microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1, microstate::BRA0_1,
+ microstate::UNKNOWN, microstate::POPFS_1, microstate::UNKNOWN, microstate::POPFS_1, microstate::POPB4_1, microstate::POPB5_1, microstate::POPB4_1, microstate::POPB7_1,
+ microstate::UNKNOWN, microstate::PUSHFS_1, microstate::UNKNOWN, microstate::PUSHFS_1, microstate::PUSHBC_1, microstate::PUSHBD_1, microstate::PUSHBC_1, microstate::PUSHBF_1,
+ microstate::SUBCL_1, microstate::DIVC1_1, microstate::SUBCL_1, microstate::UNKNOWN, microstate::XCHC4_1, microstate::XCHC5_1, microstate::XCHC4_1, microstate::XCHC5_1,
+ microstate::ADDCL_1, microstate::MULC9_1, microstate::ADDCL_1, microstate::UNKNOWN, microstate::MOVCC_1, microstate::MOVCD_1, microstate::MOVCC_1, microstate::MOVCD_1,
+ microstate::CMPD0_1, microstate::CMPD1_1, microstate::CMPD0_1, microstate::CMPD1_1, microstate::XCHD4_1, microstate::XCHD4_1, microstate::UNKNOWN, microstate::XCHD7_1,
+ microstate::MOVD8_1, microstate::MOVD9_1, microstate::MOVD8_1, microstate::MOVD9_1, microstate::MOVDC_1, microstate::MOVDD_1, microstate::MOVDC_1, microstate::MOVDD_1,
+ microstate::LOOP_1, microstate::LOOP_1, microstate::LOOP_1, microstate::LOOP_1, microstate::DECE4_1, microstate::INCE5_1, microstate::DECE4_1, microstate::INCE5_1,
+ microstate::ADDRE8_1, microstate::ADDRE9_1, microstate::ADDRE8_1, microstate::ADDRE9_1, microstate::ADDREC_1, microstate::ADDRED_1, microstate::ADDREC_1, microstate::ADDRED_1,
+ microstate::CMPBF0_1, microstate::CMPBF1_1, microstate::MOV1_1, microstate::WAIT_1, microstate::RET_1, microstate::RETI_1, microstate::BR_1, microstate::CALL_1,
+ microstate::CMPBF0_1, microstate::CMPBF1_1, microstate::MOV1_1, microstate::PUSHFB_1, microstate::BRFC_1, microstate::CALLFD_1, microstate::RDTBL_1, microstate::PI_1
+};
+
+const u16 mn1880_device::s_input_queue_map[16] =
+{
+ //FEDCBA9876543210
+ 0b0000000000000000, // 0x
+ 0b1111111111111111, // 1x
+ 0b1111111111111111, // 2x
+ 0b1010010101111010, // 3x
+ 0b1010101010111010, // 4x
+ 0b1110010011101101, // 5x
+ 0b1110111011101110, // 6x
+ 0b1110111011101110, // 7x
+ 0b0000111101001111, // 8x
+ 0b0000000000000000, // 9x
+ 0b1111111111111111, // Ax
+ 0b0000000000000000, // Bx
+ 0b1111111010101110, // Cx
+ 0b0000111100001111, // Dx
+ 0b1010111100000000, // Ex
+ 0b0000111101001111 // Fx
+};
+
+const u8 mn1880_device::s_branch_fs[4] =
+{
+ 0x00, 0x80, 0x40, 0xc0
+};
+
+u8 mn1880_device::cpu_registers::addcz(u8 data1, u8 data2, bool carry, bool holdz)
+{
+ if ((data1 + data2 + (carry ? 1 : 0)) >= 0x100)
+ fs |= 0x80;
+ else
+ fs &= 0x7f;
+ data1 += data2 + (carry ? 1 : 0);
+ if (u8(data1) != 0)
+ fs &= 0xbf;
+ else if (!holdz)
+ fs |= 0x40;
+ return data1;
+}
+
+u8 mn1880_device::cpu_registers::adddcz(u8 data1, u8 data2, bool carry)
+{
+ if (((data1 & 0x0f) + (data2 & 0x0f) + (carry ? 1 : 0)) >= 0x0a)
+ fs |= 0x80;
+ else
+ fs &= 0x7f;
+ data1 = (data1 & 0xf0) | ((data1 + data2 + (carry ? 1 : 0)) & 0x0f);
+ if (u8(data1 & 0x0f) == 0)
+ fs |= 0x40;
+ else
+ fs &= 0xbf;
+ return data1;
+}
+
+u8 mn1880_device::cpu_registers::subcz(u8 data1, u8 data2, bool carry, bool holdz)
+{
+ if (data1 < data2 + (carry ? 1 : 0))
+ fs |= 0x80;
+ else
+ fs &= 0x7f;
+ data1 -= data2 + (carry ? 1 : 0);
+ if (u8(data1) != 0)
+ fs &= 0xbf;
+ else if (!holdz)
+ fs |= 0x40;
+ return data1;
+}
+
+u8 mn1880_device::cpu_registers::subdcz(u8 data1, u8 data2, bool carry)
+{
+ if ((data1 & 0x0f) < (data2 & 0x0f) + (carry ? 1 : 0))
+ fs |= 0x80;
+ else
+ fs &= 0x7f;
+ data1 = (data1 & 0xf0) | ((data1 - data2 - (carry ? 1 : 0)) & 0x0f);
+ if (u8(data1 & 0x0f) == 0)
+ fs |= 0x40;
+ else
+ fs &= 0xbf;
+ return data1;
+}
+
+u8 mn1880_device::cpu_registers::rolc(u8 data)
+{
+ if (BIT(fs, 7))
+ {
+ if (!BIT(data, 7))
+ fs &= 0x7f;
+ return (data << 1) | 0x01;
+ }
+ else
+ {
+ if (BIT(data, 7))
+ fs |= 0x80;
+ return data << 1;
+ }
+}
+
+u8 mn1880_device::cpu_registers::rorc(u8 data)
+{
+ if (BIT(fs, 7))
+ {
+ if (!BIT(data, 0))
+ fs &= 0x7f;
+ return (data >> 1) | 0x80;
+ }
+ else
+ {
+ if (BIT(data, 0))
+ fs |= 0x80;
+ return data >> 1;
+ }
+}
+
+u8 mn1880_device::cpu_registers::asrc(u8 data)
+{
+ if (BIT(data, 7))
+ {
+ if (!BIT(data, 0))
+ fs &= 0x7f;
+ return (data >> 1) | 0x80;
+ }
+ else
+ {
+ if (BIT(data, 0))
+ fs |= 0x80;
+ return data >> 1;
+ }
+}
+
+void mn1880_device::cpu_registers::branch(u16 label)
+{
+ ip = label;
+ fs &= 0xe0;
+}
+
+void mn1880_device::swap_cpus()
+{
+ if ((m_cpum & 0x03) != (m_cpu_select ? 0x01 : 0x02))
+ m_cpu_select = !m_cpu_select;
+}
+
+void mn1880_device::next_instruction(u8 input)
+{
+ cpu_registers &cpu = m_cpu[int(m_cpu_select)];
+ if ((cpu.fs & 0x0f) != 0)
+ cpu.fs = (cpu.fs - 1) | 0x10;
+ else
+ {
+ cpu.fs &= 0xe0;
+ cpu.irp = cpu.ip++;
+ cpu.ir = input;
+ }
+
+ m_ustate = microstate::NEXT;
+ swap_cpus();
}
void mn1880_device::execute_run()
{
- m_ip = m_cache.read_word(0);
+ while (m_icount-- > 0)
+ {
+ cpu_registers &cpu = m_cpu[int(m_cpu_select)];
+
+ if (m_ustate == microstate::NEXT && cpu.wait == 0)
+ {
+ if (!BIT(cpu.fs, 4))
+ debugger_instruction_hook(cpu.irp);
+ if (!m_output_queued && !BIT(s_input_queue_map[cpu.ir >> 4], cpu.ir & 0x0f))
+ m_ustate = s_decode_map[cpu.ir];
+ }
+
+ u8 input = m_cache.read_byte(cpu.ip);
+ switch (m_ustate)
+ {
+ case microstate::NEXT:
+ if (cpu.wait != 0)
+ {
+ --cpu.wait;
+ swap_cpus();
+ }
+ else
+ {
+ if (m_output_queued)
+ {
+ m_data.write_byte(m_da, m_tmp1 & 0x00ff);
+ m_output_queued = false;
+ }
+ if (BIT(s_input_queue_map[cpu.ir >> 4], cpu.ir & 0x0f))
+ {
+ ++cpu.ip;
+ m_da = input;
+ }
+ m_ustate = s_decode_map[cpu.ir];
+ }
+ break;
+
+ case microstate::NOP_1:
+ next_instruction(input);
+ break;
+
+ case microstate::REP_1:
+ cpu.fs = (cpu.fs & 0xe0) | (cpu.ir & 0x0f);
+ cpu.irp = cpu.ip++;
+ cpu.ir = input;
+ m_ustate = microstate::NEXT;
+ break;
+
+ case microstate::CLRSET_1:
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_tmp1 = m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ if (BIT(cpu.ir, 3))
+ m_tmp1 |= 1 << (cpu.ir & 0x07);
+ else
+ m_tmp1 &= ~(1 << (cpu.ir & 0x07));
+ m_ustate = microstate::MOV56_2;
+ break;
+
+ case microstate::T1B_1:
+ ++cpu.ip;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_tmp1 = m_data.read_byte(m_da) & (1 << (cpu.ir & 0x07));
+ m_tmp2 = cpu.ip + s8(input);
+ m_ustate = microstate::CMPBF1_3;
+ break;
+
+ case microstate::MOVL31_1:
+ ++cpu.ip;
+ m_tmp1 = (m_da & 0xff) | u16(input) << 8;
+ m_ustate = microstate::MOVL31_2;
+ break;
+
+ case microstate::MOVL31_2:
+ if (BIT(cpu.ir, 1))
+ cpu.yp = m_tmp1;
+ else
+ cpu.xp = m_tmp1;
+ next_instruction(input);
+ break;
+
+ case microstate::MOVL34_1:
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ m_ustate = microstate::MOVL34_2;
+ break;
+
+ case microstate::MOVL34_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_tmp2 = m_da + 1;
+ m_da = cpu.xp;
+ m_ustate = microstate::MOVL34_3;
+ break;
+
+ case microstate::MOVL34_3:
+ m_data.write_byte(m_da, m_tmp1);
+ m_da = m_tmp2;
+ ++cpu.xp;
+ m_ustate = microstate::MOVL34_4;
+ break;
+
+ case microstate::MOVL34_4:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::MOVL35_1:
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_tmp2 = m_da;
+ m_da = cpu.yp;
+ m_ustate = microstate::MOVL35_2;
+ break;
+
+ case microstate::MOVL35_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_da = m_tmp2;
+ ++cpu.yp;
+ m_ustate = microstate::MOVL35_3;
+ break;
+
+ case microstate::MOVL35_3:
+ m_data.write_byte(m_da, m_tmp1);
+ m_da = cpu.yp;
+ m_ustate = microstate::MOVL35_4;
+ break;
+
+ case microstate::MOVL35_4:
+ m_tmp1 = m_data.read_byte(cpu.yp);
+ m_da = m_tmp2 + 1;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::MOV36_1:
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_ustate = microstate::MOV36_2;
+ break;
+
+ case microstate::MOV36_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::MOV37_1:
+ ++cpu.ip;
+ m_da = cpu.yp;
+ m_tmp1 = m_data.read_byte(m_da);
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ m_ustate = microstate::MOV56_2;
+ break;
+
+ case microstate::MOVL38_1:
+ if (BIT(cpu.fs, 5))
+ m_da |= (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0xff00;
+ m_ustate = microstate::MOVL38_2;
+ break;
+
+ case microstate::MOVL38_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ ++m_da;
+ m_ustate = microstate::MOVL38_3;
+ break;
+
+ case microstate::MOVL38_3:
+ m_tmp1 |= m_data.read_byte(m_da) << 8;
+ m_ustate = microstate::MOVL31_2; // TODO: output queue
+ break;
+
+ case microstate::MOVL39_1:
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0xff00;
+ m_ustate = microstate::MOVL39_2;
+ break;
+
+ case microstate::MOVL39_2:
+ m_tmp1 = BIT(cpu.ir, 1) ? cpu.yp : cpu.xp;
+ m_ustate = microstate::MOVL39_3;
+ break;
+
+ case microstate::MOVL39_3:
+ m_data.write_byte(m_da, m_tmp1 & 0x00ff);
+ ++m_da;
+ m_tmp1 >>= 8;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::ASL_1:
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ m_da = cpu.xp;
+ m_ustate = microstate::ASL_2;
+ break;
+
+ case microstate::ASL_2:
+ m_tmp1 = m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ cpu.fs = (m_tmp1 & 0x80) | (cpu.fs & 0x7f);
+ m_tmp1 <<= 1;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::ASR_1:
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ m_da = cpu.xp;
+ m_ustate = microstate::ASR_2;
+ break;
+
+ case microstate::ASR_2:
+ m_tmp1 = cpu.asrc(m_data.read_byte(m_da)); // TODO: read latch instead of terminal
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::DEC40_1:
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_tmp1 = 0;
+ if (!BIT(cpu.fs, 4))
+ cpu.fs |= 0x80;
+ m_ustate = microstate::SUBC_3;
+ break;
+
+ case microstate::NOT_1:
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ m_da = cpu.xp;
+ m_tmp1 = 0xff;
+ m_ustate = microstate::XOR_3;
+ break;
+
+ case microstate::CMPM44_1:
+ m_tmp1 = m_da & 0x00ff;
+ m_da = cpu.xp;
+ m_ustate = microstate::CMPM44_2;
+ break;
+
+ case microstate::CMPM44_2:
+ ++cpu.ip;
+ m_tmp1 &= m_data.read_byte(m_da);
+ m_tmp2 = input;
+ m_ustate = microstate::CMPM44_3;
+ break;
+
+ case microstate::CMPM44_3:
+ (void)cpu.subcz(m_tmp1, m_tmp2, false, false);
+ m_ustate = microstate::NOP_1; // TODO: output queue (but what?)
+ break;
+
+ case microstate::CMPM45_1:
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_ustate = microstate::CMPM45_2;
+ break;
+
+ case microstate::CMPM45_2:
+ ++cpu.ip;
+ m_tmp1 = input;
+ m_ustate = microstate::CMPM44_2;
+ break;
+
+ case microstate::CMPM50_1:
+ m_tmp2 = m_data.read_byte(cpu.yp);
+ m_tmp1 = m_da & 0x00ff;
+ m_da = cpu.xp;
+ m_ustate = microstate::CMPM50_2;
+ break;
+
+ case microstate::CMPM50_2:
+ m_tmp2 &= m_tmp1;
+ m_ustate = microstate::CMPM50_3;
+ break;
+
+ case microstate::CMPM50_3:
+ m_tmp1 &= m_data.read_byte(m_da);
+ m_ustate = microstate::CMPM44_3;
+ break;
+
+ case microstate::CMPM52_1:
+ ++cpu.ip;
+ m_tmp1 = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ m_ustate = microstate::CMPM50_2;
+ break;
+
+ case microstate::CMPM52_2:
+ ++cpu.ip;
+ m_tmp2 = m_data.read_byte(m_da);
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_ustate = microstate::CMPM50_2;
+ break;
+
+ case microstate::XCH4_1:
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::XCH4_2;
+ break;
+
+ case microstate::XCH4_2:
+ m_tmp1 = m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ m_tmp1 = (m_tmp1 << 4) | (m_tmp1 >> 4);
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::INC48_1:
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_tmp1 = 0;
+ if (!BIT(cpu.fs, 4))
+ cpu.fs |= 0x80;
+ m_ustate = microstate::ADDC_3;
+ break;
+
+ case microstate::CLR4A_1:
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_tmp1 = 0;
+ m_ustate = microstate::AND_3;
+ break;
+
+ case microstate::ROL_1:
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::ROL_2;
+ break;
+
+ case microstate::ROL_2:
+ m_tmp1 = cpu.rolc(m_data.read_byte(m_da)); // TODO: read latch instead of terminal
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::ROR_1:
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::ROR_2;
+ break;
+
+ case microstate::ROR_2:
+ m_tmp1 = cpu.rorc(m_data.read_byte(m_da)); // TODO: read latch instead of terminal
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::DIV51_1:
+ m_da = cpu.yp;
+ m_ustate = microstate::DIV51_2;
+ break;
+
+ case microstate::DIV51_2:
+ m_tmp2 = m_data.read_byte(m_da);
+ m_da = cpu.xp;
+ m_ustate = microstate::DIV51_3;
+ break;
+
+ case microstate::DIV51_3:
+ m_tmp1 = m_data.read_byte(m_da);
+ ++m_da;
+ m_ustate = microstate::DIV51_4;
+ break;
+
+ case microstate::DIV51_4:
+ m_tmp1 |= m_data.read_byte(m_da) << 8;
+ --m_da;
+ m_ustate = microstate::DIV51_5;
+ break;
+
+ case microstate::DIV51_5:
+ m_ustate = microstate::DIV51_6;
+ break;
+
+ case microstate::DIV51_6:
+ m_ustate = microstate::DIV51_7;
+ break;
+
+ case microstate::DIV51_7:
+ m_ustate = microstate::DIV51_8;
+ break;
+
+ case microstate::DIV51_8:
+ m_ustate = microstate::DIV51_9;
+ break;
+
+ case microstate::DIV51_9:
+ if (m_tmp2 == 0)
+ {
+ // TBD: documentation doesn't define what happens when the divisor is zero
+ logerror("%04X: %04X divided by zero (XP = %04X, YP = %04X)\n", cpu.irp, m_tmp1, cpu.xp, cpu.yp);
+ m_tmp1 = 0xff;
+ m_tmp2 = 0xff;
+ }
+ else
+ m_tmp1 /= std::exchange(m_tmp2, m_tmp1 % m_tmp2);
+ m_ustate = microstate::DIV51_10;
+ break;
+
+ case microstate::DIV51_10:
+ m_data.write_byte(m_da, m_tmp1 & 0x00ff);
+ ++m_da;
+ cpu.xp = m_da;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::MOVDA_1:
+ ++cpu.ip;
+ m_da = (m_da << 8) | input;
+ m_ustate = microstate::MOVDA_2;
+ break;
+
+ case microstate::MOVDA_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ ++cpu.ip;
+ m_da = input;
+ m_ustate = microstate::MOVDA_3;
+ break;
+
+ case microstate::MOVDA_3:
+ ++cpu.ip;
+ m_da = (m_da << 8) | input;
+ m_ustate = microstate::MOV56_2;
+ break;
+
+ case microstate::MOV54_1:
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ m_ustate = microstate::MOV36_2;
+ break;
+
+ case microstate::MOV55_1:
+ m_data.write_byte(cpu.xp, m_da & 0x00ff);
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ next_instruction(input);
+ break;
+
+ case microstate::MOV56_1:
+ ++cpu.ip;
+ if (BIT(cpu.ir, 0))
+ m_tmp1 = m_da & 0x00ff;
+ else
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ m_tmp1 = m_data.read_byte(m_da);
+ }
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_ustate = microstate::MOV56_2;
+ break;
+
+ case microstate::MOV56_2:
+ m_data.write_byte(m_da, m_tmp1);
+ next_instruction(input);
+ break;
+
+ case microstate::XCH58_1:
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_tmp2 = input;
+ }
+ else
+ {
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ }
+ m_ustate = microstate::XCH58_2;
+ break;
+
+ case microstate::XCH58_2:
+ m_tmp1 = m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ if (BIT(cpu.ir, 1))
+ {
+ std::swap(m_da, m_tmp2);
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_tmp2 = cpu.yp;
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::XCH58_3;
+ break;
+
+ case microstate::XCH58_3:
+ m_tmp1 |= u16(m_data.read_byte(m_da)) << 8; // TODO: read latch instead of terminal
+ m_ustate = microstate::XCH58_4;
+ break;
+
+ case microstate::XCH58_4:
+ m_data.write_byte(m_da, m_tmp1 & 0x00ff);
+ m_tmp1 >>= 8;
+ m_da = m_tmp2;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::MUL59_1:
+ m_da = cpu.xp;
+ m_ustate = microstate::MUL59_2;
+ break;
- debugger_instruction_hook(m_ip);
+ case microstate::MUL59_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ ++m_da;
+ m_ustate = microstate::MUL59_3;
+ break;
- m_icount = 0;
+ case microstate::MUL59_3:
+ m_tmp2 = m_data.read_byte(m_da);
+ m_ustate = microstate::MUL59_4;
+ break;
+
+ case microstate::MUL59_4:
+ m_ustate = microstate::MUL59_5;
+ break;
+
+ case microstate::MUL59_5:
+ m_ustate = microstate::MUL59_6;
+ break;
+
+ case microstate::MUL59_6:
+ m_ustate = microstate::MUL59_7;
+ break;
+
+ case microstate::MUL59_7:
+ m_tmp1 *= m_tmp2;
+ m_da = cpu.xp;
+ ++cpu.xp;
+ m_ustate = microstate::MUL59_8;
+ break;
+
+ case microstate::MUL59_8:
+ m_data.write_byte(m_da, m_tmp1 & 0x00ff);
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ m_tmp1 >>= 8;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::MOVL5C_1:
+ m_da = cpu.yp;
+ ++cpu.yp;
+ m_ustate = microstate::MOVL5C_2;
+ break;
+
+ case microstate::MOVL5C_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_da = cpu.xp;
+ ++cpu.xp;
+ m_ustate = microstate::MOVL5C_3;
+ break;
+
+ case microstate::MOVL5C_3:
+ m_data.write_byte(m_da, m_tmp1);
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ m_ustate = microstate::MOVL34_4;
+ break;
+
+ case microstate::MOVL5D_1:
+ ++cpu.ip;
+ m_data.write_byte(cpu.xp, m_da & 0x00ff);
+ ++cpu.xp;
+ m_tmp1 = input;
+ m_ustate = microstate::MOVL5D_2;
+ break;
+
+ case microstate::MOVL5D_2:
+ m_data.write_byte(cpu.xp, m_tmp1);
+ ++cpu.xp;
+ next_instruction(input);
+ break;
+
+ case microstate::MOVL5E_1:
+ ++cpu.ip;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ m_tmp2 = input;
+ if (BIT(cpu.fs, 5))
+ m_tmp2 |= cpu.xp & 0xff00;
+ m_ustate = microstate::MOVL5E_2;
+ break;
+
+ case microstate::MOVL5E_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ std::swap(m_da, m_tmp2);
+ m_ustate = microstate::MOVL5E_3;
+ break;
+
+ case microstate::MOVL5E_3:
+ m_data.write_byte(m_da, m_tmp1);
+ std::swap(m_da, m_tmp2);
+ ++m_da;
+ m_ustate = microstate::MOVL5E_4;
+ break;
+
+ case microstate::MOVL5E_4:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_da = m_tmp2 + 1;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::MOVL5F_1:
+ ++cpu.ip;
+ m_tmp1 = m_da & 0x00ff;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_ustate = microstate::MOVL5F_2;
+ break;
+
+ case microstate::MOVL5F_2:
+ ++cpu.ip;
+ m_data.write_byte(m_da, m_tmp1);
+ m_tmp1 = input;
+ ++m_da;
+ m_ustate = microstate::MOV56_2;
+ break;
+
+ case microstate::CMP_1:
+ if (BIT(cpu.ir, 0))
+ m_tmp1 = m_da & 0x00ff;
+ else
+ {
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ }
+ }
+ m_ustate = microstate::CMP_2;
+ break;
+
+ case microstate::CMP_2:
+ if (!BIT(cpu.ir, 0))
+ m_tmp1 = m_data.read_byte(m_da);
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ m_da = cpu.xp;
+ }
+ m_ustate = microstate::CMP_3;
+ if (!BIT(cpu.fs, 4))
+ cpu.fs &= 0x7f;
+ break;
+
+ case microstate::CMP_3:
+ (void)cpu.subcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7), BIT(cpu.fs, 4));
+ m_ustate = microstate::NOP_1; // TODO: output queue (but just what is the output?)
+ break;
+
+ case microstate::AND_1:
+ if (BIT(cpu.ir, 0))
+ m_tmp1 = m_da & 0x00ff;
+ else
+ {
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ }
+ }
+ m_ustate = microstate::AND_2;
+ break;
+
+ case microstate::AND_2:
+ if (!BIT(cpu.ir, 0))
+ m_tmp1 = m_data.read_byte(m_da);
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::AND_3;
+ break;
+
+ case microstate::AND_3:
+ m_tmp1 &= m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ if (u8(m_tmp1) == 0)
+ cpu.fs |= 0x40;
+ else
+ cpu.fs &= 0xbf;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::XOR_1:
+ if (BIT(cpu.ir, 0))
+ m_tmp1 = m_da & 0x00ff;
+ else
+ {
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ }
+ }
+ m_ustate = microstate::XOR_2;
+ break;
+
+ case microstate::XOR_2:
+ if (!BIT(cpu.ir, 0))
+ m_tmp1 = m_data.read_byte(m_da);
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::XOR_3;
+ break;
+
+ case microstate::XOR_3:
+ m_tmp1 ^= m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ if (u8(m_tmp1) == 0)
+ cpu.fs |= 0x40;
+ else
+ cpu.fs &= 0xbf;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::OR_1:
+ if (BIT(cpu.ir, 0))
+ m_tmp1 = m_da & 0x00ff;
+ else
+ {
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ }
+ }
+ m_ustate = microstate::OR_2;
+ break;
+
+ case microstate::OR_2:
+ if (!BIT(cpu.ir, 0))
+ m_tmp1 = m_data.read_byte(m_da);
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::OR_3;
+ break;
+
+ case microstate::OR_3:
+ m_tmp1 |= m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ if (u8(m_tmp1) == 0)
+ cpu.fs |= 0x40;
+ else
+ cpu.fs &= 0xbf;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::SUBC_1:
+ if (BIT(cpu.ir, 0))
+ m_tmp1 = m_da & 0x00ff;
+ else
+ {
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ }
+ }
+ m_ustate = microstate::SUBC_2;
+ break;
+
+ case microstate::SUBC_2:
+ if (!BIT(cpu.ir, 0))
+ m_tmp1 = m_data.read_byte(m_da);
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::SUBC_3;
+ break;
+
+ case microstate::SUBC_3:
+ m_tmp1 = cpu.subcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7), BIT(cpu.fs, 4)); // TODO: read latch instead of terminal
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::SUBD_1:
+ if (BIT(cpu.ir, 0))
+ m_tmp1 = m_da & 0x00ff;
+ else
+ {
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ }
+ }
+ m_ustate = microstate::SUBD_2;
+ break;
+
+ case microstate::SUBD_2:
+ if (!BIT(cpu.ir, 0))
+ m_tmp1 = m_data.read_byte(m_da);
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::SUBD_3;
+ break;
+
+ case microstate::SUBD_3:
+ m_tmp1 = cpu.subdcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7)); // TODO: read latch instead of terminal
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::SUBD_4:
+ // Decimal adjust
+ if (BIT(cpu.fs, 7))
+ {
+ m_tmp1 = (m_tmp1 & 0xf0) | ((m_tmp1 - 0x06) & 0x0f);
+ if ((m_tmp1 & 0x0f) == 0)
+ cpu.fs |= 0x40;
+ else
+ cpu.fs &= 0xbf;
+ }
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::ADDC_1:
+ if (BIT(cpu.ir, 0))
+ m_tmp1 = m_da & 0x00ff;
+ else
+ {
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ }
+ }
+ m_ustate = microstate::ADDC_2;
+ break;
+
+ case microstate::ADDC_2:
+ if (!BIT(cpu.ir, 0))
+ m_tmp1 = m_data.read_byte(m_da);
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::ADDC_3;
+ break;
+
+ case microstate::ADDC_3:
+ m_tmp1 = cpu.addcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7), BIT(cpu.fs, 4)); // TODO: read latch instead of terminal
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::ADDD_1:
+ if (BIT(cpu.ir, 0))
+ m_tmp1 = m_da & 0x00ff;
+ else
+ {
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.yp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ }
+ }
+ m_ustate = microstate::ADDD_2;
+ break;
+
+ case microstate::ADDD_2:
+ if (!BIT(cpu.ir, 0))
+ m_tmp1 = m_data.read_byte(m_da);
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ {
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ }
+ m_ustate = microstate::ADDD_3;
+ break;
+
+ case microstate::ADDD_3:
+ m_tmp1 = cpu.adddcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7)); // TODO: read latch instead of terminal
+ m_ustate = microstate::ADDD_4;
+ break;
+
+ case microstate::ADDD_4:
+ // Decimal adjust
+ if (BIT(cpu.fs, 7))
+ {
+ m_tmp1 = (m_tmp1 & 0xf0) | ((m_tmp1 + 0x06) & 0x0f);
+ if ((m_tmp1 & 0x0f) == 0)
+ cpu.fs |= 0x40;
+ else
+ cpu.fs &= 0xbf;
+ }
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::BR80_1:
+ if ((cpu.fs & s_branch_fs[cpu.ir & 0x03]) != 0)
+ cpu.branch(cpu.ip + s8(m_da & 0x00ff));
+ m_ustate = microstate::BR_2;
+ break;
+
+ case microstate::CMPL_1:
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ m_da = cpu.yp;
+ m_ustate = microstate::CMPL_2;
+ break;
+
+ case microstate::CMPL_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_tmp2 = m_da;
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ m_da = cpu.xp;
+ m_ustate = microstate::CMPL_3;
+ if (!BIT(cpu.fs, 4))
+ cpu.fs &= 0x7f;
+ break;
+
+ case microstate::CMPL_3:
+ (void)cpu.subcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7), BIT(cpu.fs, 4));
+ std::swap(m_da, m_tmp2);
+ ++m_da;
+ m_ustate = microstate::CMPL_4;
+ break;
+
+ case microstate::CMPL_4:
+ m_tmp1 = m_data.read_byte(m_da);
+ if (!BIT(cpu.ir, 1))
+ cpu.yp = m_da + 1;
+ m_da = m_tmp2 + 1;
+ m_ustate = microstate::CMPL_5;
+ break;
+
+ case microstate::CMPL_5:
+ (void)cpu.subcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7), true);
+ if (!BIT(cpu.ir, 1))
+ cpu.xp = m_da + 1;
+ m_ustate = microstate::NOP_1; // TODO: output queue (if any...)
+ break;
+
+ case microstate::CLRFS_1:
+ cpu.fs &= ~(1 << (cpu.ir & 0x07));
+ next_instruction(input);
+ break;
+
+ case microstate::BR88_1:
+ if ((cpu.fs & s_branch_fs[cpu.ir & 0x03]) == 0)
+ cpu.branch(cpu.ip + s8(m_da & 0x00ff));
+ m_ustate = microstate::BR_2;
+ break;
+
+ case microstate::SETFS_1:
+ cpu.fs |= 1 << (cpu.ir & 0x07);
+ next_instruction(input);
+ break;
+
+ case microstate::SUBCL_1:
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ m_da = cpu.yp;
+ m_ustate = microstate::SUBCL_2;
+ break;
+
+ case microstate::SUBCL_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_tmp2 = m_da;
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ m_da = cpu.xp;
+ m_ustate = microstate::SUBCL_3;
+ break;
+
+ case microstate::SUBCL_3:
+ m_tmp1 = cpu.subcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7), BIT(cpu.fs, 4)); // TODO: read latch instead of terminal
+ ++m_tmp2;
+ m_ustate = microstate::SUBCL_4;
+ break;
+
+ case microstate::SUBCL_4:
+ m_data.write_byte(m_da, m_tmp1);
+ std::swap(m_da, m_tmp2);
+ m_ustate = microstate::SUBCL_5;
+ break;
+
+ case microstate::SUBCL_5:
+ m_tmp1 = m_data.read_byte(m_da);
+ if (!BIT(cpu.ir, 1))
+ cpu.yp = m_da + 1;
+ m_da = m_tmp2 + 1;
+ m_ustate = microstate::SUBCL_6;
+ break;
+
+ case microstate::SUBCL_6:
+ m_tmp1 = cpu.subcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7), true); // TODO: read latch instead of terminal
+ if (!BIT(cpu.ir, 1))
+ cpu.xp = m_da + 1;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::ADDCL_1:
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ }
+ else
+ m_da = cpu.yp;
+ m_ustate = microstate::ADDCL_2;
+ break;
+
+ case microstate::ADDCL_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_tmp2 = m_da;
+ if (BIT(cpu.ir, 1))
+ {
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ }
+ else
+ m_da = cpu.xp;
+ m_ustate = microstate::ADDCL_3;
+ break;
+
+ case microstate::ADDCL_3:
+ m_tmp1 = cpu.addcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7), BIT(cpu.fs, 4)); // TODO: read latch instead of terminal
+ ++m_tmp2;
+ m_ustate = microstate::ADDCL_4;
+ break;
+
+ case microstate::ADDCL_4:
+ m_data.write_byte(m_da, m_tmp1);
+ std::swap(m_da, m_tmp2);
+ m_ustate = microstate::ADDCL_5;
+ break;
+
+ case microstate::ADDCL_5:
+ m_tmp1 = m_data.read_byte(m_da);
+ if (!BIT(cpu.ir, 1))
+ cpu.yp = m_da + 1;
+ m_da = m_tmp2 + 1;
+ m_ustate = microstate::ADDCL_6;
+ break;
+
+ case microstate::ADDCL_6:
+ m_tmp1 = cpu.addcz(m_data.read_byte(m_da), m_tmp1, BIT(cpu.fs, 7), true); // TODO: read latch instead of terminal
+ if (!BIT(cpu.ir, 1))
+ cpu.xp = m_da + 1;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::CALL90_1:
+ ++cpu.ip;
+ m_tmp1 = (cpu.ip & 0xf000) | u16(cpu.ir & 0x0f) << 8 | input;
+ m_tmp2 = cpu.ip;
+ m_da = cpu.sp - 1;
+ m_ustate = microstate::CALL90_2;
+ break;
+
+ case microstate::CALL90_2:
+ m_data.write_byte(m_da, m_tmp2 >> 8);
+ --m_da;
+ cpu.branch(m_tmp1);
+ m_ustate = microstate::CALL_3;
+ break;
+
+ case microstate::BRA0_1:
+ cpu.branch((cpu.ip & 0xf000) | u16(cpu.ir & 0x0f) << 8 | (m_da & 0x00ff));
+ m_ustate = microstate::BR_2;
+ break;
+
+ case microstate::POPFS_1:
+ m_da = cpu.sp;
+ m_ustate = microstate::POPFS_2;
+ break;
+
+ case microstate::POPFS_2:
+ cpu.fs = m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ cpu.sp = m_da + 1;
+ m_ustate = microstate::NOP_1; // TODO: output queue (only FS?)
+ break;
+
+ case microstate::POPB4_1:
+ m_da = cpu.sp;
+ m_ustate = microstate::POPB4_2;
+ break;
+
+ case microstate::POPB4_2:
+ (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) = m_data.read_byte(m_da);
+ ++m_da;
+ m_ustate = microstate::POPB4_3;
+ break;
+
+ case microstate::POPB4_3:
+ (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) |= m_data.read_byte(m_da) << 8;
+ cpu.sp = m_da + 1;
+ m_ustate = microstate::NOP_1; // TODO: output queue (only XP/YP?)
+ break;
+
+ case microstate::POPB5_1:
+ ++cpu.ip;
+ m_da = cpu.sp;
+ m_tmp2 = input;
+ if (BIT(cpu.fs, 5))
+ m_tmp2 |= cpu.xp & 0xff00;
+ m_ustate = microstate::POPB5_2;
+ break;
+
+ case microstate::POPB5_2:
+ m_tmp1 = m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ cpu.sp = m_da + 1;
+ m_da = m_tmp2;
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::POPB7_1:
+ m_da = cpu.sp;
+ m_tmp2 = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ m_ustate = microstate::POPB5_2;
+ break;
+
+ case microstate::PUSHFS_1:
+ m_da = cpu.sp - 1;
+ m_tmp1 = cpu.fs;
+ m_ustate = microstate::PUSHBC_3;
+ break;
+
+ case microstate::PUSHBC_1:
+ m_da = cpu.sp - 1;
+ m_tmp1 = BIT(cpu.ir, 1) ? cpu.yp : cpu.xp;
+ m_ustate = microstate::PUSHBC_2;
+ break;
+
+ case microstate::PUSHBC_2:
+ m_data.write_byte(m_da, m_tmp1 >> 8);
+ --m_da;
+ m_ustate = microstate::PUSHBC_3;
+ break;
+
+ case microstate::PUSHBC_3:
+ m_data.write_byte(m_da, m_tmp1 & 0x00ff);
+ cpu.sp = m_da;
+ m_ustate = microstate::NOP_1; // TODO: output queue (only SP?)
+ break;
+
+ case microstate::PUSHBD_1:
+ ++cpu.ip;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_ustate = microstate::PUSHBD_2;
+ break;
+
+ case microstate::PUSHBD_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_da = cpu.sp - 1;
+ m_ustate = microstate::PUSHBD_3;
+ break;
+
+ case microstate::PUSHBD_3:
+ m_data.write_byte(m_da, m_tmp1 & 0x00ff);
+ cpu.sp = m_da;
+ m_ustate = microstate::NOP_1; // TODO: output queue (only SP?)
+ break;
+
+ case microstate::PUSHBF_1:
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ --cpu.xp;
+ m_ustate = microstate::PUSHBD_2;
+ break;
+
+ case microstate::DIVC1_1:
+ m_tmp2 = m_da & 0x00ff;
+ m_ustate = microstate::DIVC1_2;
+ break;
+
+ case microstate::DIVC1_2:
+ m_da = cpu.xp;
+ m_ustate = microstate::DIV51_3;
+ break;
+
+ case microstate::XCHC4_1:
+ if (BIT(cpu.ir, 1))
+ cpu.yp = (cpu.yp >> 8) | (cpu.yp << 8);
+ else
+ cpu.xp = (cpu.xp >> 8) | (cpu.xp << 8);
+ m_ustate = microstate::XCHC4_2;
+ break;
+
+ case microstate::XCHC4_2:
+ m_ustate = microstate::NOP_1; // TODO: output queue (only XPl/YPl?)
+ break;
+
+ case microstate::XCHC5_1:
+ if (BIT(cpu.fs, 5))
+ m_da |= (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0xff00;
+ m_tmp2 = m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ m_tmp1 = (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0x00ff;
+ m_ustate = microstate::XCHC5_2;
+ break;
+
+ case microstate::XCHC5_2:
+ m_data.write_byte(m_da, m_tmp1);
+ setl(BIT(cpu.ir, 1) ? cpu.yp : cpu.xp, m_tmp2);
+ next_instruction(input);
+ break;
+
+ case microstate::MOVCC_1:
+ if (BIT(cpu.ir, 1))
+ {
+ if (BIT(cpu.ir, 5))
+ m_da |= cpu.yp & 0xff00;
+ setl(cpu.yp, m_data.read_byte(m_da));
+ }
+ else
+ {
+ if (BIT(cpu.ir, 5))
+ m_da |= cpu.xp & 0xff00;
+ setl(cpu.xp, m_data.read_byte(m_da));
+ }
+ next_instruction(input);
+ break;
+
+ case microstate::MOVCD_1:
+ if (BIT(cpu.fs, 5))
+ m_da |= (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0xff00;
+ m_ustate = microstate::MOVCD_2;
+ break;
+
+ case microstate::MOVCD_2:
+ setl(BIT(cpu.ir, 1) ? cpu.yp : cpu.xp, m_data.read_byte(m_da));
+ next_instruction(input); // TODO: output queue
+ break;
+
+ case microstate::MULC9_1:
+ m_tmp2 = m_da & 0x00ff;
+ m_da = cpu.xp;
+ m_ustate = microstate::MULC9_2;
+ break;
+
+ case microstate::MULC9_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_ustate = microstate::MULC9_3;
+ break;
+
+ case microstate::MULC9_3:
+ m_ustate = microstate::MUL59_4;
+ break;
+
+ case microstate::CMPD0_1:
+ if (BIT(cpu.fs, 5))
+ m_da |= (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0xff00;
+ m_ustate = microstate::CMPD0_2;
+ break;
+
+ case microstate::CMPD0_2:
+ (void)cpu.subcz((BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0x00ff, m_data.read_byte(m_da), false, false);
+ m_ustate = microstate::CMPD1_2;
+ break;
+
+ case microstate::CMPD1_1:
+ (void)cpu.subcz((BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0x00ff, m_da & 0x00ff, false, false);
+ m_ustate = microstate::CMPD1_2;
+ break;
+
+ case microstate::CMPD1_2:
+ next_instruction(input);
+ break;
+
+ case microstate::XCHD4_1:
+ m_tmp1 = std::exchange(BIT(cpu.ir, 0) ? cpu.sp : cpu.lp, cpu.xp);
+ m_ustate = microstate::XCHD4_2;
+ break;
+
+ case microstate::XCHD4_2:
+ cpu.xp = m_tmp1;
+ next_instruction(input);
+ break;
+
+ case microstate::XCHD7_1:
+ m_tmp1 = std::exchange(cpu.yp, cpu.xp);
+ m_ustate = microstate::XCHD4_2;
+ break;
+
+ case microstate::MOVD8_1:
+ setl(BIT(cpu.ir, 1) ? cpu.yp : cpu.xp, m_da & 0x00ff);
+ next_instruction(input);
+ break;
+
+ case microstate::MOVD9_1:
+ seth(BIT(cpu.ir, 1) ? cpu.yp : cpu.xp, m_da & 0x00ff);
+ next_instruction(input);
+ break;
+
+ case microstate::MOVDC_1:
+ if (BIT(cpu.ir, 1))
+ cpu.yp = cpu.xp;
+ else
+ cpu.sp = cpu.xp;
+ next_instruction(input);
+ break;
+
+ case microstate::MOVDD_1:
+ if (BIT(cpu.ir, 1))
+ cpu.xp = cpu.yp;
+ else
+ cpu.xp = cpu.sp;
+ next_instruction(input);
+ break;
+
+ case microstate::LOOP_1:
+ ++cpu.ip;
+ if (BIT(cpu.ir, 0))
+ {
+ if (BIT(cpu.ir, 1))
+ ++cpu.yp;
+ else
+ ++cpu.xp;
+ }
+ m_da = cpu.sp;
+ m_tmp2 = cpu.ip + s8(input);
+ m_ustate = microstate::LOOP_2;
+ break;
+
+ case microstate::LOOP_2:
+ m_tmp1 = m_data.read_byte(m_da) - 1; // TODO: read latch instead of terminal
+ if (m_tmp1 != 0)
+ cpu.branch(m_tmp2);
+ else
+ cpu.sp = m_da + 1;
+ m_ustate = microstate::MOV56_2;
+ break;
+
+ case microstate::DECE4_1:
+ if (BIT(cpu.ir, 1))
+ --cpu.yp;
+ else
+ --cpu.xp;
+ next_instruction(input);
+ break;
+
+ case microstate::INCE5_1:
+ if (BIT(cpu.ir, 1))
+ ++cpu.yp;
+ else
+ ++cpu.xp;
+ next_instruction(input);
+ break;
+
+ case microstate::ADDRE8_1:
+ ++cpu.ip;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0x00ff;
+ m_tmp2 = input;
+ m_ustate = microstate::ADDRE8_2;
+ break;
+
+ case microstate::ADDRE8_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_da = m_tmp2;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0x00ff;
+ m_ustate = microstate::ADDRE8_3;
+ break;
+
+ case microstate::ADDRE8_3:
+ if (BIT(cpu.ir, 1))
+ setl(cpu.yp, cpu.addcz(cpu.yp & 0x00ff, m_data.read_byte(m_da), false, false));
+ else
+ setl(cpu.xp, cpu.addcz(cpu.xp & 0x00ff, m_data.read_byte(m_da), false, false));
+ m_ustate = microstate::NOP_1; // TODO: output queue (XPl only?)
+ break;
+
+ case microstate::ADDRE9_1:
+ ++cpu.ip;
+ m_tmp2 = m_da & 0x00ff;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0x00ff;
+ m_ustate = microstate::ADDRE9_2;
+ break;
+
+ case microstate::ADDRE9_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ m_ustate = microstate::ADDRE9_3;
+ break;
+
+ case microstate::ADDRE9_3:
+ setl(BIT(cpu.ir, 1) ? cpu.yp : cpu.xp, cpu.addcz(m_tmp1, m_tmp2, false, false));
+ m_ustate = microstate::NOP_1; // TODO: output queue (XPl/YPl only?)
+ break;
+
+ case microstate::ADDREC_1:
+ m_tmp1 = (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0x00ff;
+ m_tmp2 = (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) >> 8;
+ m_ustate = microstate::ADDRE9_3;
+ break;
+
+ case microstate::ADDRED_1:
+ m_tmp1 = (BIT(cpu.ir, 1) ? cpu.yp : cpu.xp) & 0x00ff;
+ m_tmp2 = m_da & 0x00ff;
+ m_ustate = microstate::ADDRE9_3;
+ break;
+
+ case microstate::CMPBF0_1:
+ ++cpu.ip;
+ m_tmp1 = m_data.read_byte(cpu.xp) ^ (m_da & 0x00ff);
+ m_tmp2 = cpu.ip + s8(input);
+ m_ustate = microstate::CMPBF1_3;
+ break;
+
+ case microstate::CMPBF1_1:
+ ++cpu.ip;
+ m_tmp1 = m_da & 0x00ff;
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_ustate = microstate::CMPBF1_2;
+ break;
+
+ case microstate::CMPBF1_2:
+ ++cpu.ip;
+ m_tmp1 ^= m_data.read_byte(m_da);
+ m_tmp2 = cpu.ip + s8(input);
+ m_ustate = microstate::CMPBF1_3;
+ break;
+
+ case microstate::CMPBF1_3:
+ if (BIT(cpu.ir, 3) ? m_tmp1 == 0 : m_tmp1 != 0)
+ cpu.branch(m_tmp2);
+ m_ustate = microstate::BR_2;
+ break;
+
+ case microstate::MOV1_1:
+ ++cpu.ip;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.yp & 0xff00;
+ m_tmp2 = input;
+ m_tmp1 = 1 << (m_tmp2 & 0x07);
+ m_ustate = microstate::MOV1_2;
+ break;
+
+ case microstate::MOV1_2:
+ ++cpu.ip;
+ m_tmp1 &= m_data.read_byte(m_da);
+ m_da = input;
+ if (BIT(cpu.fs, 5))
+ m_da |= cpu.xp & 0xff00;
+ m_ustate = microstate::MOV1_3;
+ break;
+
+ case microstate::MOV1_3:
+ if (BIT(cpu.ir, 3) ? m_tmp1 == 0 : m_tmp1 != 0)
+ m_ustate = microstate::MOV1_4;
+ else
+ m_ustate = microstate::MOV1N_4;
+ m_tmp1 = 1 << ((m_tmp2 >> 4) & 0x07);
+ break;
+
+ case microstate::MOV1_4:
+ m_tmp1 |= m_data.read_byte(m_da); // TODO: read latch instead of terminal
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::MOV1N_4:
+ m_tmp1 = m_data.read_byte(m_da) & ~m_tmp1; // TODO: read latch instead of terminal
+ m_output_queued = true;
+ next_instruction(input);
+ break;
+
+ case microstate::WAIT_1:
+ ++cpu.ip;
+ m_tmp1 = (m_da << 8) | input;
+ m_ustate = microstate::WAIT_2;
+ break;
+
+ case microstate::WAIT_2:
+ cpu.wait = m_tmp1;
+ next_instruction(input);
+ break;
+
+ case microstate::RET_1:
+ m_da = cpu.sp;
+ m_ustate = microstate::RET_2;
+ break;
+
+ case microstate::RET_2:
+ m_tmp1 = m_data.read_byte(m_da);
+ ++m_da;
+ m_ustate = microstate::RET_3;
+ break;
+
+ case microstate::RET_3:
+ cpu.branch(u16(m_data.read_byte(m_da)) << 8 | m_tmp1);
+ cpu.sp = m_da + 1;
+ m_ustate = microstate::BR_2;
+ break;
+
+ case microstate::RETI_1:
+ m_da = cpu.sp;
+ m_ustate = microstate::RETI_2;
+ break;
+
+ case microstate::RETI_2:
+ cpu.fs = m_data.read_byte(m_da);
+ ++m_da;
+ m_ustate = microstate::RETI_3;
+ break;
+
+ case microstate::RETI_3:
+ m_tmp1 = m_data.read_byte(m_da);
+ ++m_da;
+ m_ustate = microstate::RETI_4;
+ break;
+
+ case microstate::RETI_4:
+ cpu.ip = u16(m_data.read_byte(m_da)) << 8 | m_tmp1;
+ if ((cpu.fs & 0x1f) != 0)
+ {
+ ++m_da;
+ m_ustate = microstate::RETI_5;
+ }
+ else
+ {
+ cpu.sp = m_da + 1;
+ m_ustate = microstate::BR_2;
+ }
+ break;
+
+ case microstate::RETI_5:
+ cpu.ir = m_data.read_byte(m_da);
+ cpu.sp = m_da + 1;
+ m_ustate = microstate::NEXT;
+ swap_cpus();
+ break;
+
+ case microstate::BR_1:
+ cpu.branch((m_da & 0x00ff) << 8 | input);
+ m_ustate = microstate::BR_2;
+ break;
+
+ case microstate::BR_2:
+ next_instruction(input);
+ break;
+
+ case microstate::CALL_1:
+ ++cpu.ip;
+ m_tmp1 = input;
+ m_tmp2 = cpu.ip + 1;
+ m_da = cpu.sp - 1;
+ m_ustate = microstate::CALL_2;
+ break;
+
+ case microstate::CALL_2:
+ m_data.write_byte(m_da, m_tmp2 >> 8);
+ --m_da;
+ cpu.branch(m_tmp1 << 8 | input);
+ m_ustate = microstate::CALL_3;
+ break;
+
+ case microstate::CALL_3:
+ m_data.write_byte(m_da, m_tmp2 & 0x00ff);
+ cpu.sp = m_da;
+ next_instruction(input);
+ break;
+
+ case microstate::PUSHFB_1:
+ m_tmp1 = m_da & 0x00ff;
+ m_da = cpu.sp - 1;
+ m_ustate = microstate::PUSHBC_3;
+ break;
+
+ case microstate::BRFC_1:
+ cpu.branch(cpu.xp);
+ m_ustate = microstate::BR_2;
+ break;
+
+ case microstate::CALLFD_1:
+ m_tmp1 = cpu.xp;
+ m_tmp2 = cpu.ip;
+ m_da = cpu.sp - 1;
+ m_ustate = microstate::CALL90_2;
+ break;
+
+ case microstate::RDTBL_1:
+ m_ustate = microstate::RDTBL_2;
+ break;
+
+ case microstate::RDTBL_2:
+ m_tmp2 = std::exchange(cpu.ip, cpu.yp);
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.yp;
+ m_ustate = microstate::RDTBL_3;
+ break;
+
+ case microstate::RDTBL_3:
+ m_tmp1 = input;
+ m_da = cpu.xp;
+ if ((cpu.fs & 0x1f) != 0)
+ ++cpu.xp;
+ cpu.ip = m_tmp2;
+ m_ustate = microstate::MOV56_2;
+ break;
+
+ case microstate::PI_1:
+ case microstate::UNKNOWN:
+ logerror("%04X: Unknown or unemulated instruction %02X encountered\n", cpu.irp, cpu.ir);
+ next_instruction(input);
+ break;
+ }
+ }
}
void mn1880_device::state_string_export(const device_state_entry &entry, std::string &str) const
@@ -103,12 +2299,23 @@ void mn1880_device::state_string_export(const device_state_entry &entry, std::st
switch (entry.index())
{
case STATE_GENFLAGS:
- str = string_format("%c%c%c%c:RC=%-2d",
- BIT(m_fs, 7) ? 'C' : '.', // Carry flag
- BIT(m_fs, 6) ? 'Z' : '.', // Zero flag
- BIT(m_fs, 5) ? 'D' : '.', // Direct flag
- BIT(m_fs, 4) ? 'A' : '.', // Auto-repeat flag
- m_fs & 0x0f);
+ {
+ u8 fs = m_cpu[int(m_cpu_select)].fs;
+ str = string_format("%c%c%c%c RC=%-2d",
+ BIT(fs, 7) ? 'C' : '.', // Carry flag
+ BIT(fs, 6) ? 'Z' : '.', // Zero flag
+ BIT(fs, 5) ? 'D' : '.', // Direct flag
+ BIT(fs, 4) ? 'A' : '.', // Auto-repeat flag
+ fs & 0x0f);
+ break;
+ }
+
+ case MN1880_IPA:
+ str = string_format("%04X%c", m_cpu[0].ip, m_cpu_select ? ' ' : '*');
+ break;
+
+ case MN1880_IPB:
+ str = string_format("%04X%c", m_cpu[1].ip, m_cpu_select ? '*' : ' ');
break;
}
}
diff --git a/src/devices/cpu/mn1880/mn1880.h b/src/devices/cpu/mn1880/mn1880.h
index e4ab2427f46..c1cb5415e3c 100644
--- a/src/devices/cpu/mn1880/mn1880.h
+++ b/src/devices/cpu/mn1880/mn1880.h
@@ -12,19 +12,30 @@ public:
mn1880_device(const machine_config &config, const char *tag, device_t *owner, u32 clock);
enum {
- MN1880_IP, MN1880_FS,
- MN1880_XP, MN1880_YP,
- MN1880_XPL, MN1880_XPH, MN1880_YPL, MN1880_YPH,
- MN1880_SP, MN1880_LP
+ MN1880_IP, MN1880_IPA, MN1880_IPB,
+ MN1880_IR, MN1880_IRA, MN1880_IRB,
+ MN1880_FS, MN1880_FSA, MN1880_FSB,
+ MN1880_XP, MN1880_XPA, MN1880_XPB,
+ MN1880_YP, MN1880_YPA, MN1880_YPB,
+ MN1880_XPL, MN1880_XPH,
+ MN1880_YPL, MN1880_YPH,
+ MN1880_SP, MN1880_SPA, MN1880_SPB,
+ MN1880_LP, MN1880_LPA, MN1880_LPB,
+ MN1880_DIVIDER1, MN1880_DIVIDER2,
+ MN1880_CPUM
};
protected:
+ mn1880_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor data_map);
+
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
// device_execute_interface overrides
virtual void execute_run() override;
+ virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const noexcept override { return (clocks + 4 - 1) / 4; }
+ virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const noexcept override { return (cycles * 4); }
// device_disasm_interface overrides
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
@@ -36,6 +47,142 @@ protected:
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
private:
+ struct cpu_registers
+ {
+ cpu_registers() : ip(0), irp(0), ir(0), fs(0), xp(0), yp(0), sp(0), lp(0), wait(0) { }
+
+ u8 addcz(u8 data1, u8 data2, bool carry, bool holdz);
+ u8 adddcz(u8 data1, u8 data2, bool carry);
+ u8 subcz(u8 data1, u8 data2, bool carry, bool holdz);
+ u8 subdcz(u8 data1, u8 data2, bool carry);
+ u8 rolc(u8 data);
+ u8 rorc(u8 data);
+ u8 asrc(u8 data);
+ void branch(u16 label);
+
+ u16 ip;
+ u16 irp;
+ u8 ir;
+ u8 fs;
+ u16 xp;
+ u16 yp;
+ u16 sp;
+ u16 lp;
+ u16 wait;
+ };
+
+ enum class microstate : u8 {
+ NEXT,
+ NOP_1,
+ REP_1,
+ CLRSET_1,
+ T1B_1,
+ MOVL31_1, MOVL31_2,
+ MOVL34_1, MOVL34_2, MOVL34_3, MOVL34_4,
+ MOVL35_1, MOVL35_2, MOVL35_3, MOVL35_4,
+ MOV36_1, MOV36_2,
+ MOV37_1,
+ MOVL38_1, MOVL38_2, MOVL38_3,
+ MOVL39_1, MOVL39_2, MOVL39_3,
+ ASL_1, ASL_2,
+ ASR_1, ASR_2,
+ DEC40_1,
+ NOT_1,
+ CMPM44_1, CMPM44_2, CMPM44_3,
+ CMPM45_1, CMPM45_2,
+ XCH4_1, XCH4_2,
+ INC48_1,
+ CLR4A_1,
+ ROL_1, ROL_2,
+ ROR_1, ROR_2,
+ CMPM50_1, CMPM50_2, CMPM50_3,
+ CMPM52_1, CMPM52_2,
+ DIV51_1, DIV51_2, DIV51_3, DIV51_4, DIV51_5, DIV51_6, DIV51_7, DIV51_8, DIV51_9, DIV51_10,
+ MOVDA_1, MOVDA_2, MOVDA_3,
+ MOV54_1,
+ MOV55_1,
+ MOV56_1, MOV56_2,
+ XCH58_1, XCH58_2, XCH58_3, XCH58_4,
+ MUL59_1, MUL59_2, MUL59_3, MUL59_4, MUL59_5, MUL59_6, MUL59_7, MUL59_8,
+ MOVL5C_1, MOVL5C_2, MOVL5C_3,
+ MOVL5D_1, MOVL5D_2,
+ MOVL5E_1, MOVL5E_2, MOVL5E_3, MOVL5E_4,
+ MOVL5F_1, MOVL5F_2,
+ CMP_1, CMP_2, CMP_3,
+ AND_1, AND_2, AND_3,
+ XOR_1, XOR_2, XOR_3,
+ OR_1, OR_2, OR_3,
+ SUBC_1, SUBC_2, SUBC_3,
+ SUBD_1, SUBD_2, SUBD_3, SUBD_4,
+ ADDC_1, ADDC_2, ADDC_3,
+ ADDD_1, ADDD_2, ADDD_3, ADDD_4,
+ BR80_1, BR88_1,
+ CMPL_1, CMPL_2, CMPL_3, CMPL_4, CMPL_5,
+ CLRFS_1, SETFS_1,
+ CALL90_1, CALL90_2,
+ BRA0_1,
+ POPFS_1, POPFS_2,
+ POPB4_1, POPB4_2, POPB4_3,
+ POPB5_1, POPB5_2,
+ POPB7_1,
+ PUSHFS_1,
+ PUSHBC_1, PUSHBC_2, PUSHBC_3,
+ PUSHBD_1, PUSHBD_2, PUSHBD_3,
+ PUSHBF_1,
+ SUBCL_1, SUBCL_2, SUBCL_3, SUBCL_4, SUBCL_5, SUBCL_6,
+ DIVC1_1, DIVC1_2,
+ XCHC4_1, XCHC4_2,
+ XCHC5_1, XCHC5_2,
+ ADDCL_1, ADDCL_2, ADDCL_3, ADDCL_4, ADDCL_5, ADDCL_6,
+ MULC9_1, MULC9_2, MULC9_3,
+ MOVCC_1,
+ MOVCD_1, MOVCD_2,
+ CMPD0_1, CMPD0_2,
+ CMPD1_1, CMPD1_2,
+ XCHD4_1, XCHD4_2,
+ XCHD7_1,
+ MOVD8_1,
+ MOVD9_1,
+ MOVDC_1,
+ MOVDD_1,
+ LOOP_1, LOOP_2,
+ DECE4_1,
+ INCE5_1,
+ ADDRE8_1, ADDRE8_2, ADDRE8_3,
+ ADDRE9_1, ADDRE9_2, ADDRE9_3,
+ ADDREC_1,
+ ADDRED_1,
+ CMPBF0_1,
+ CMPBF1_1, CMPBF1_2, CMPBF1_3,
+ MOV1_1, MOV1_2, MOV1_3, MOV1_4, MOV1N_4,
+ WAIT_1, WAIT_2,
+ RET_1, RET_2, RET_3,
+ RETI_1, RETI_2, RETI_3, RETI_4, RETI_5,
+ BR_1, BR_2,
+ CALL_1, CALL_2, CALL_3,
+ PUSHFB_1,
+ BRFC_1,
+ CALLFD_1,
+ RDTBL_1, RDTBL_2, RDTBL_3,
+ PI_1,
+ UNKNOWN
+ };
+
+ static void setl(u16 &pr, u8 data) { pr = (pr & 0xff00) | data; }
+ static void seth(u16 &pr, u8 data) { pr = (pr & 0x00ff) | (data << 8); }
+
+ u8 cpum_r();
+ void cpum_w(u8 data);
+
+ void internal_data_map(address_map &map);
+
+ void swap_cpus();
+ void next_instruction(u8 input);
+
+ static const microstate s_decode_map[256];
+ static const u16 s_input_queue_map[16];
+ static const u8 s_branch_fs[4];
+
// address spaces
address_space_config m_program_config;
address_space_config m_data_config;
@@ -43,12 +190,14 @@ private:
memory_access<16, 0, 0, ENDIANNESS_LITTLE>::specific m_data;
// internal state
- u16 m_ip;
- u8 m_fs;
- u16 m_xp;
- u16 m_yp;
- u16 m_sp;
- u16 m_lp;
+ cpu_registers m_cpu[2];
+ bool m_cpu_select;
+ u8 m_cpum;
+ microstate m_ustate;
+ u16 m_da;
+ u16 m_tmp1;
+ u16 m_tmp2;
+ bool m_output_queued;
s32 m_icount;
};
diff --git a/src/mame/drivers/basssta.cpp b/src/mame/drivers/basssta.cpp
index e2b043b43e2..c6aa1bea917 100644
--- a/src/mame/drivers/basssta.cpp
+++ b/src/mame/drivers/basssta.cpp
@@ -8,7 +8,7 @@
#include "emu.h"
#include "cpu/mn1880/mn1880.h"
-//#include "machine/eeprompar.h"
+#include "machine/eeprompar.h"
class basssta_state : public driver_device
{
@@ -44,10 +44,34 @@ void basssta_state::sbasssta_prog(address_map &map)
void basssta_state::bassstr_data(address_map &map)
{
+ map(0x0001, 0x0001).noprw();
+ map(0x0003, 0x0003).noprw();
+ map(0x000f, 0x000f).noprw();
+ map(0x0015, 0x0015).noprw();
+ map(0x001f, 0x001f).noprw();
+ map(0x0060, 0x03cf).ram();
+ map(0x8000, 0x87ff).rw("eeprom", FUNC(eeprom_parallel_28xx_device::read), FUNC(eeprom_parallel_28xx_device::write));
}
void basssta_state::sbasssta_data(address_map &map)
{
+ map(0x0000, 0x0003).nopr();
+ map(0x0001, 0x0001).nopw();
+ map(0x0003, 0x0003).nopw();
+ map(0x000f, 0x000f).noprw();
+ map(0x0012, 0x0015).noprw();
+ map(0x001c, 0x001c).nopr();
+ map(0x001e, 0x001e).nopw();
+ map(0x001f, 0x001f).noprw();
+ map(0x0030, 0x0030).nopw();
+ map(0x0032, 0x0032).nopw();
+ map(0x0034, 0x0034).nopw();
+ map(0x0036, 0x0036).nopw();
+ map(0x005d, 0x005d).noprw();
+ map(0x0060, 0x07ff).ram(); // TODO: probably internal to CPU
+ map(0x6000, 0x7fff).rw("eeprom", FUNC(eeprom_parallel_28xx_device::read), FUNC(eeprom_parallel_28xx_device::write));
+ map(0x8001, 0x8004).nopw();
+ map(0xc000, 0xc000).nopr();
}
@@ -56,9 +80,11 @@ INPUT_PORTS_END
void basssta_state::bassstr(machine_config &config)
{
- MN1880(config, m_maincpu, 8000000); // type and clock unknown (custom silkscreen)
+ MN1880(config, m_maincpu, 8000000); // type and clock unknown (custom silkscreen; might be MN18P83220)
m_maincpu->set_addrmap(AS_PROGRAM, &basssta_state::bassstr_prog);
m_maincpu->set_addrmap(AS_DATA, &basssta_state::bassstr_data);
+
+ EEPROM_2816(config, "eeprom");
}
void basssta_state::sbasssta(machine_config &config)
@@ -67,7 +93,7 @@ void basssta_state::sbasssta(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &basssta_state::sbasssta_prog);
m_maincpu->set_addrmap(AS_DATA, &basssta_state::sbasssta_data);
- // TODO: Microchip 28C64AF EEPROM
+ EEPROM_2864(config, "eeprom"); // Microchip 28C64AF-15I/L
}
ROM_START(bassstr)
diff --git a/src/mame/drivers/drumsta.cpp b/src/mame/drivers/drumsta.cpp
index 6906ab24d83..8eadf95c9ea 100644
--- a/src/mame/drivers/drumsta.cpp
+++ b/src/mame/drivers/drumsta.cpp
@@ -9,7 +9,7 @@
#include "emu.h"
#include "cpu/adsp2100/adsp2100.h"
#include "cpu/mn1880/mn1880.h"
-//#include "machine/eeprompar.h"
+#include "machine/eeprompar.h"
class drumsta_state : public driver_device
{
@@ -39,6 +39,12 @@ void drumsta_state::drumsta_prog(address_map &map)
void drumsta_state::drumsta_data(address_map &map)
{
+ map(0x0001, 0x0001).noprw();
+ map(0x0003, 0x0003).noprw();
+ map(0x000e, 0x000f).noprw();
+ map(0x0015, 0x0015).noprw();
+ map(0x0060, 0x031f).ram();
+ map(0xb000, 0xb7ff).rw("eeprom", FUNC(eeprom_parallel_28xx_device::read), FUNC(eeprom_parallel_28xx_device::write));
}
@@ -53,7 +59,7 @@ void drumsta_state::drumsta(machine_config &config)
ADSP2181(config, m_dsp, 16000000).set_disable(); // clock unknown
- // TODO: Atmel AT28C64 EEPROM
+ EEPROM_2864(config, "eeprom"); // Atmel AT28C64
}
ROM_START(drumsta)
diff --git a/src/mame/drivers/macpci.cpp b/src/mame/drivers/macpci.cpp
index 269b4b19568..d68d1cc7511 100644
--- a/src/mame/drivers/macpci.cpp
+++ b/src/mame/drivers/macpci.cpp
@@ -87,6 +87,29 @@ void macpci_state::cdmcu_mem(address_map &map)
map(0x0000, 0xffff).rom().region("cdrom", 0);
}
+void macpci_state::cdmcu_data(address_map &map)
+{
+ map(0x0000, 0x0001).noprw();
+ map(0x0003, 0x0003).noprw();
+ map(0x0004, 0x0008).nopw();
+ map(0x0008, 0x0008).nopr();
+ map(0x0009, 0x0009).noprw();
+ map(0x000f, 0x000f).noprw();
+ map(0x0012, 0x0013).ram();
+ map(0x0015, 0x0015).noprw();
+ map(0x001f, 0x0021).nopw();
+ map(0x0031, 0x0031).noprw();
+ map(0x0033, 0x0033).nopw();
+ map(0x0036, 0x0036).noprw();
+ map(0x0060, 0x031f).ram();
+ map(0x802a, 0x802a).nopw();
+ map(0x802f, 0x8034).nopw();
+ map(0x8032, 0x8032).nopr();
+ map(0x8035, 0x8035).lr8(NAME([]() { return 0x40; }));
+ map(0x8037, 0x8037).noprw();
+ map(0x8038, 0x8039).nopw();
+}
+
/* Input ports */
static INPUT_PORTS_START( pippin )
INPUT_PORTS_END
@@ -149,6 +172,7 @@ void macpci_state::pippin(machine_config &config)
mn1880_device &cdmcu(MN1880(config, "cdmcu", 8388608)); // type and clock unknown
cdmcu.set_addrmap(AS_PROGRAM, &macpci_state::cdmcu_mem);
+ cdmcu.set_addrmap(AS_DATA, &macpci_state::cdmcu_data);
}
/* ROM definition */
diff --git a/src/mame/includes/macpci.h b/src/mame/includes/macpci.h
index 22823aeb53f..bc7e6e53293 100644
--- a/src/mame/includes/macpci.h
+++ b/src/mame/includes/macpci.h
@@ -146,6 +146,7 @@ private:
void init_pippin();
void pippin_mem(address_map &map);
void cdmcu_mem(address_map &map);
+ void cdmcu_data(address_map &map);
// wait states for accessing the VIA
int m_via_cycles;