summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/cpu.lua4
-rw-r--r--src/devices/cpu/xtensa/xtensa.cpp2242
-rw-r--r--src/devices/cpu/xtensa/xtensa.h165
-rw-r--r--src/devices/cpu/xtensa/xtensa_helper.cpp230
-rw-r--r--src/devices/cpu/xtensa/xtensa_helper.h33
-rw-r--r--src/devices/cpu/xtensa/xtensad.cpp347
-rw-r--r--src/devices/cpu/xtensa/xtensad.h7
-rw-r--r--src/mame/skeleton/hudson_poems.cpp636
8 files changed, 3346 insertions, 318 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index 52ba899263b..2e76666aee0 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -3919,10 +3919,14 @@ if CPUS["XTENSA"] then
files {
MAME_DIR .. "src/devices/cpu/xtensa/xtensa.cpp",
MAME_DIR .. "src/devices/cpu/xtensa/xtensa.h",
+ MAME_DIR .. "src/devices/cpu/xtensa/xtensa_helper.cpp",
+ MAME_DIR .. "src/devices/cpu/xtensa/xtensa_helper.h",
}
end
if opt_tool(CPUS, "XTENSA") then
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/xtensa/xtensad.cpp")
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/xtensa/xtensad.h")
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/xtensa/xtensa_helper.cpp")
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/xtensa/xtensa_helper.h")
end
diff --git a/src/devices/cpu/xtensa/xtensa.cpp b/src/devices/cpu/xtensa/xtensa.cpp
index 2559ebcfb0e..42967c6ed74 100644
--- a/src/devices/cpu/xtensa/xtensa.cpp
+++ b/src/devices/cpu/xtensa/xtensa.cpp
@@ -1,10 +1,10 @@
// license:BSD-3-Clause
-// copyright-holders:AJR
+// copyright-holders:AJR, David Haywood
/***************************************************************************
Tensilica Xtensa
- Currently this device is just a stub with no actual execution core.
+ preliminary core, many extensions not supported
***************************************************************************/
@@ -12,14 +12,31 @@
#include "xtensa.h"
#include "xtensad.h"
+#include "xtensa_helper.h"
+
+#define LOG_UNHANDLED_OPS (1U << 1)
+#define LOG_UNHANDLED_CACHE_OPS (1U << 3)
+#define LOG_UNHANDLED_SYNC_OPS (1U << 4)
+#define LOG_EXTREG_OPS (1U << 8)
+#define LOG_NAMED_REGS (1U << 10)
+#define LOG_TIMER_REGS (1U << 11)
+
+#define VERBOSE (LOG_UNHANDLED_OPS)
+#include "logmacro.h"
+
// device type definitions
DEFINE_DEVICE_TYPE(XTENSA, xtensa_device, "xtensa", "Tensilica Xtensa core")
xtensa_device::xtensa_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: cpu_device(mconfig, XTENSA, tag, owner, clock)
, m_space_config("program", ENDIANNESS_LITTLE, 32, 32, 0)
+ , m_extregs_config("extregs", ENDIANNESS_LITTLE, 32, 8, -2, address_map_constructor(FUNC(xtensa_device::ext_regs), this))
, m_pc(0)
{
+ for (int i = 0; i < 32; i++)
+ m_irq_vectors[i] = 0x00000000;
+
+ m_startupvector = 0x00000000;
}
std::unique_ptr<util::disasm_interface> xtensa_device::create_disassembler()
@@ -29,11 +46,310 @@ std::unique_ptr<util::disasm_interface> xtensa_device::create_disassembler()
device_memory_interface::space_config_vector xtensa_device::memory_space_config() const
{
- return space_config_vector {
+ return space_config_vector{
std::make_pair(AS_PROGRAM, &m_space_config),
+ std::make_pair(AS_EXTREGS, &m_extregs_config)
};
}
+/* Exceptions */
+
+u32 xtensa_device::extreg_exccause_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_exccause read\n"); return 0x4; /* m_extreg_exccause;*/ }
+void xtensa_device::extreg_exccause_w(u32 data) { m_extreg_exccause = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_exccause set to %08x\n", data); }
+
+u32 xtensa_device::extreg_epc1_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc1 read\n"); return m_extreg_epc1; }
+void xtensa_device::extreg_epc1_w(u32 data) { m_extreg_epc1 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc1 set to %08x\n", data); }
+u32 xtensa_device::extreg_epc2_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc2 read\n"); return m_extreg_epc2; }
+void xtensa_device::extreg_epc2_w(u32 data) { m_extreg_epc2 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc2 set to %08x\n", data); }
+u32 xtensa_device::extreg_epc3_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc3 read\n"); return m_extreg_epc3; }
+void xtensa_device::extreg_epc3_w(u32 data) { m_extreg_epc3 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc3 set to %08x\n", data); }
+u32 xtensa_device::extreg_epc4_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc4 read\n"); return m_extreg_epc4; }
+void xtensa_device::extreg_epc4_w(u32 data) { m_extreg_epc4 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc4 set to %08x\n", data); }
+u32 xtensa_device::extreg_epc5_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc5 read\n"); return m_extreg_epc5; }
+void xtensa_device::extreg_epc5_w(u32 data) { m_extreg_epc5 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_epc5 set to %08x\n", data); }
+
+u32 xtensa_device::extreg_eps2_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_eps2 read\n"); return m_extreg_eps2; }
+void xtensa_device::extreg_eps2_w(u32 data) { m_extreg_eps2 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_eps2 set to %08x\n", data); }
+u32 xtensa_device::extreg_eps3_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_eps3 read\n"); return m_extreg_eps3; }
+void xtensa_device::extreg_eps3_w(u32 data) { m_extreg_eps3 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_eps3 set to %08x\n", data); }
+u32 xtensa_device::extreg_eps4_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_eps4 read\n"); return m_extreg_eps4; }
+void xtensa_device::extreg_eps4_w(u32 data) { m_extreg_eps4 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_eps4 set to %08x\n", data); }
+u32 xtensa_device::extreg_eps5_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_eps5 read\n"); return m_extreg_eps5; }
+void xtensa_device::extreg_eps5_w(u32 data) { m_extreg_eps5 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_eps5 set to %08x\n", data); }
+
+u32 xtensa_device::extreg_excsave1_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave1 read\n"); return m_extreg_excsave1; }
+void xtensa_device::extreg_excsave1_w(u32 data) { m_extreg_excsave1 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave1 set to %08x\n", data); }
+u32 xtensa_device::extreg_excsave2_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave2 read\n"); return m_extreg_excsave2; }
+void xtensa_device::extreg_excsave2_w(u32 data) { m_extreg_excsave2 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave2 set to %08x\n", data); }
+u32 xtensa_device::extreg_excsave3_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave3 read\n"); return m_extreg_excsave3; }
+void xtensa_device::extreg_excsave3_w(u32 data) { m_extreg_excsave3 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave3 set to %08x\n", data); }
+u32 xtensa_device::extreg_excsave4_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave4 read\n"); return m_extreg_excsave4; }
+void xtensa_device::extreg_excsave4_w(u32 data) { m_extreg_excsave4 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave4 set to %08x\n", data); }
+u32 xtensa_device::extreg_excsave5_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave5 read\n"); return m_extreg_excsave5; }
+void xtensa_device::extreg_excsave5_w(u32 data) { m_extreg_excsave5 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_excsave5 set to %08x\n", data); }
+
+/* Interrupts */
+
+u32 xtensa_device::extreg_intenable_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_intenable read\n"); return m_extreg_intenable; }
+void xtensa_device::extreg_intenable_w(u32 data) { m_extreg_intenable = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_intenable set to %08x\n", data); }
+u32 xtensa_device::extreg_intclr_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_intclr read\n"); return m_extreg_intclr; }
+void xtensa_device::extreg_intclr_w(u32 data) { m_extreg_intclr = data; m_extreg_intset &= ~data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_intclr set to %08x\n", data); }
+u32 xtensa_device::extreg_intset_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_intset read\n"); return m_extreg_intset; }
+void xtensa_device::extreg_intset_w(u32 data) { m_extreg_intset = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_intset set to %08x\n", data); }
+
+/* Window handling */
+
+u32 xtensa_device::extreg_windowbase_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_windowbase read\n"); return m_extreg_windowbase; }
+void xtensa_device::extreg_windowbase_w(u32 data) { m_extreg_windowbase = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_windowbase set to %08x\n", data); switch_windowbase(0); }
+u32 xtensa_device::extreg_windowstart_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_windowstart read\n"); return m_extreg_windowstart; }
+void xtensa_device::extreg_windowstart_w(u32 data) { m_extreg_windowstart = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_windowstart set to %08x\n", data); }
+
+/* General processor state */
+
+u32 xtensa_device::extreg_ps_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_ps read\n"); return m_extreg_ps; }
+void xtensa_device::extreg_ps_w(u32 data) { m_extreg_ps = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_ps set to %08x\n", data); }
+
+/* Loop handling */
+
+u32 xtensa_device::extreg_lbeg_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_lbeg read\n"); return m_extreg_lbeg; }
+void xtensa_device::extreg_lbeg_w(u32 data) { m_extreg_lbeg = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_lbeg set to %08x\n", data); }
+u32 xtensa_device::extreg_lend_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_lend read\n"); return m_extreg_lend; }
+void xtensa_device::extreg_lend_w(u32 data) { m_extreg_lend = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_lend set to %08x\n", data); }
+u32 xtensa_device::extreg_lcount_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_lcount read\n"); return m_extreg_lcount; }
+void xtensa_device::extreg_lcount_w(u32 data) { m_extreg_lcount = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_lcount set to %08x\n", data); }
+
+/* Shifter */
+
+u32 xtensa_device::extreg_sar_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_sar read\n"); return m_extreg_sar; }
+void xtensa_device::extreg_sar_w(u32 data) { m_extreg_sar = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_sar set to %08x\n", data); }
+
+/* Debugging */
+
+u32 xtensa_device::extreg_ibreaka0_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_ibreaka0 read\n"); return m_extreg_ibreaka0; }
+void xtensa_device::extreg_ibreaka0_w(u32 data) { m_extreg_ibreaka0 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_ibreaka0 set to %08x\n", data); }
+u32 xtensa_device::extreg_dbreaka0_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_dbreaka0 read\n"); return m_extreg_dbreaka0; }
+
+void xtensa_device::extreg_dbreaka0_w(u32 data) { m_extreg_dbreaka0 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_dbreaka0 set to %08x\n", data); }
+u32 xtensa_device::extreg_dbreakc0_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_dbreakc0 read\n"); return m_extreg_dbreakc0; }
+void xtensa_device::extreg_dbreakc0_w(u32 data) { m_extreg_dbreakc0 = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_dbreakc0 set to %08x\n", data); }
+
+u32 xtensa_device::extreg_icountlevel_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_icountlevel read\n"); return m_extreg_icountlevel; }
+void xtensa_device::extreg_icountlevel_w(u32 data) { m_extreg_icountlevel = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_icountlevel set to %08x\n", data); }
+
+/* Misc */
+
+u32 xtensa_device::extreg_cacheattr_r() { LOGMASKED(LOG_NAMED_REGS, "m_extreg_cacheattr read\n"); return m_extreg_cacheattr; }
+void xtensa_device::extreg_cacheattr_w(u32 data) { m_extreg_cacheattr = data; LOGMASKED(LOG_NAMED_REGS, "m_extreg_cacheattr set to %08x\n", data); }
+
+/* Timer */
+
+u32 xtensa_device::extreg_ccompare0_r()
+{
+ LOGMASKED(LOG_TIMER_REGS, "m_extreg_ccompare0 read\n");
+ return m_extreg_ccompare0;
+}
+
+void xtensa_device::extreg_ccompare0_w(u32 data)
+{
+ // writing this clears the timer interrupt
+ m_extreg_ccompare0 = data;
+ LOGMASKED(LOG_TIMER_REGS, "m_extreg_ccompare0 set to %08x (clear timer interrupt)\n", data);
+}
+
+u32 xtensa_device::extreg_ccount_r()
+{
+ LOGMASKED(LOG_TIMER_REGS, "m_extreg_ccount read (%08x)\n", m_extreg_ccount);
+ return m_extreg_ccount;
+}
+
+void xtensa_device::extreg_ccount_w(u32 data)
+{
+ m_extreg_ccount = data;
+ LOGMASKED(LOG_TIMER_REGS, "m_extreg_ccount set to %08x\n", data);
+}
+
+
+void xtensa_device::set_irqpri(u8 val)
+{
+ m_extreg_ps |= (val & 0xf);
+}
+
+void xtensa_device::clear_irqpri(u8 val)
+{
+ m_extreg_ps &= ~(val & 0xf);
+}
+
+u8 xtensa_device::get_irqpri()
+{
+ return m_extreg_ps & 0xf;
+}
+
+void xtensa_device::set_callinc(u8 val)
+{
+ m_extreg_ps = (m_extreg_ps & 0xfffcffff) | ((val & 3) << 16);
+}
+
+u8 xtensa_device::get_callinc()
+{
+ return (m_extreg_ps >> 16) & 3;
+}
+
+void xtensa_device::ext_regs(address_map &map)
+{
+ // Loop Option (0-2),
+ map(0x00, 0x00).rw(FUNC(xtensa_device::extreg_lbeg_r), FUNC(xtensa_device::extreg_lbeg_w)); // "lbeg" LOOP BEGIN
+ map(0x01, 0x01).rw(FUNC(xtensa_device::extreg_lend_r), FUNC(xtensa_device::extreg_lend_w)); // "lend" LOOP END
+ map(0x02, 0x02).rw(FUNC(xtensa_device::extreg_lcount_r), FUNC(xtensa_device::extreg_lcount_w)); // "lcount" LOOP COUNT
+
+ // Core Architecture (3)
+ map(0x03, 0x03).rw(FUNC(xtensa_device::extreg_sar_r), FUNC(xtensa_device::extreg_sar_w)); // "sar" Shift Amount
+
+ // Boolean Option (4)
+ //map(0x04, 0x04) // "br",
+
+ // Extended L32R Option (5)
+ //map(0x05, 0x05) // "litbase",
+
+ // Conditional Store Option (12)
+ //map(0x0c, 0x0c) // "scompare1",
+
+ // MAC16 Option (16-17)
+ //map(0x10, 0x10) // "acclo",
+ //map(0x11, 0x11) // "acchi",
+
+ // MAC16 Option (32-35)
+ //map(0x20, 0x20) // "m0",
+ //map(0x21, 0x21) // "m1",
+ //map(0x22, 0x22) // "m2",
+ //map(0x23, 0x23) // "m3",
+
+ // Windowed Register Option (72-73)
+ map(0x48, 0x48).rw(FUNC(xtensa_device::extreg_windowbase_r), FUNC(xtensa_device::extreg_windowbase_w)); // "WindowBase",
+ map(0x49, 0x49).rw(FUNC(xtensa_device::extreg_windowstart_r), FUNC(xtensa_device::extreg_windowstart_w));// "WindowStart",
+
+ // MMU Option (83)
+ //map(0x53, 0x53) // "ptevaddr",
+
+ // Trace Port Option (89)
+ //map(0x59, 0x59) // "mmid",
+
+ // MMU Option (90-92)
+ //map(0x5a, 0x5a) // "rasid",
+ //map(0x5b, 0x5b) // "itlbcfg",
+ //map(0x5c, 0x5c) // "dtlbcfg",
+
+ // Debug Option (96)
+ //map(0x60, 0x60) // "ibreakenable",
+
+ // XEA1 Only (98)
+ map(0x62, 0x62).rw(FUNC(xtensa_device::extreg_cacheattr_r), FUNC(xtensa_device::extreg_cacheattr_w));// "cacheattr"
+
+ // Conditional Store Option (99)
+ //map(0x63, 0x63) // "atomctl",
+
+ // Debug Option (104)
+ //map(0x68, 0x68) // "ddr",
+
+ // Memory ECC/Parity Option (106-111)
+ //map(0x6a, 0x6a) // "mepc",
+ //map(0x6b, 0x6b) // "meps",
+ //map(0x6c, 0x6c) // "mesave",
+ //map(0x6d, 0x6d) // "mesr",
+ //map(0x6e, 0x6e) // "mecr",
+ //map(0x6f, 0x6f) // "mevaddr",
+
+ // Debug Option (128-129)
+ map(0x80, 0x80).rw(FUNC(xtensa_device::extreg_ibreaka0_r), FUNC(xtensa_device::extreg_ibreaka0_w));// "ibreaka0"
+ //map(0x81, 0x81) // "ibreaka1",
+
+ // Debug Option (144-145)
+ map(0x90, 0x90).rw(FUNC(xtensa_device::extreg_dbreaka0_r), FUNC(xtensa_device::extreg_dbreaka0_w));// "dbreaka0"
+ //map(0x91, 0x91) // "dbreaka1",
+
+ // Debug Option (160-161)
+ map(0xa0, 0xa0).rw(FUNC(xtensa_device::extreg_dbreakc0_r), FUNC(xtensa_device::extreg_dbreakc0_w));// "dbreakc0"
+ //map(0xa1, 0xa1) // "dbreakc1",
+
+ // Exception Option (177)
+ map(0xb1, 0xb1).rw(FUNC(xtensa_device::extreg_epc1_r), FUNC(xtensa_device::extreg_epc1_w));// "epc1"
+
+ // High-Priority Interrupt Option (178-183)
+ map(0xb2, 0xb2).rw(FUNC(xtensa_device::extreg_epc2_r), FUNC(xtensa_device::extreg_epc2_w));// "epc2"
+ map(0xb3, 0xb3).rw(FUNC(xtensa_device::extreg_epc3_r), FUNC(xtensa_device::extreg_epc3_w));// "epc3"
+ map(0xb4, 0xb4).rw(FUNC(xtensa_device::extreg_epc4_r), FUNC(xtensa_device::extreg_epc4_w));// "epc4"
+ map(0xb5, 0xb5).rw(FUNC(xtensa_device::extreg_epc5_r), FUNC(xtensa_device::extreg_epc5_w));// "epc5"
+ //map(0xb6, 0xb6) // "epc6",
+ //map(0xb7, 0xb7) // "epc7",
+
+ // Exception Option (192)
+ //map(0xc0, 0xc0) // "depc",
+
+ // High-Priority Interrupt Option (194-199)
+ map(0xc2, 0xc2).rw(FUNC(xtensa_device::extreg_eps2_r), FUNC(xtensa_device::extreg_eps2_w));// "eps2"
+ map(0xc3, 0xc3).rw(FUNC(xtensa_device::extreg_eps3_r), FUNC(xtensa_device::extreg_eps3_w));// "eps3"
+ map(0xc4, 0xc4).rw(FUNC(xtensa_device::extreg_eps4_r), FUNC(xtensa_device::extreg_eps4_w));// "eps4"
+ map(0xc5, 0xc5).rw(FUNC(xtensa_device::extreg_eps5_r), FUNC(xtensa_device::extreg_eps5_w));// "eps5"
+ //map(0xc6, 0xc6) // "eps6",
+ //map(0xc7, 0xc7) // "eps7",
+
+ // Exception Option (209)
+ map(0xd1, 0xd1).rw(FUNC(xtensa_device::extreg_excsave1_r), FUNC(xtensa_device::extreg_excsave1_w));// "excsave1"
+
+ // High-Priority Interrupt Option (210-215)
+ map(0xd2, 0xd2).rw(FUNC(xtensa_device::extreg_excsave2_r), FUNC(xtensa_device::extreg_excsave2_w));// "excsave2"
+ map(0xd3, 0xd3).rw(FUNC(xtensa_device::extreg_excsave3_r), FUNC(xtensa_device::extreg_excsave3_w));// "excsave3"
+ map(0xd4, 0xd4).rw(FUNC(xtensa_device::extreg_excsave4_r), FUNC(xtensa_device::extreg_excsave4_w));// "excsave4"
+ map(0xd5, 0xd5).rw(FUNC(xtensa_device::extreg_excsave5_r), FUNC(xtensa_device::extreg_excsave5_w));// "excsave5"
+ //map(0xd6, 0xd6) // "excsave6",
+ //map(0xd7, 0xd7) // "excsave7",
+
+ // Coprocessor Option (224)
+ //map(0xe0, 0xe0) // "cpenable",
+
+ // Interrupt Option (226-228)
+ map(0xe2, 0xe2).rw(FUNC(xtensa_device::extreg_intset_r), FUNC(xtensa_device::extreg_intset_w)); // "intset"
+ map(0xe3, 0xe3).rw(FUNC(xtensa_device::extreg_intclr_r), FUNC(xtensa_device::extreg_intclr_w)); // "intclr"
+ map(0xe4, 0xe4).rw(FUNC(xtensa_device::extreg_intenable_r), FUNC(xtensa_device::extreg_intenable_w)); // "intenable"
+
+ // various options (230)
+ map(0xe6, 0xe6).rw(FUNC(xtensa_device::extreg_ps_r), FUNC(xtensa_device::extreg_ps_w)); // "ps" PROCESSOR STATE
+
+ // Relocatable Vector Option (231)
+ //map(0xe7, 0xe7) // "vecbase",
+
+ // Exception Option (232)
+ map(0xe8, 0xe8).rw(FUNC(xtensa_device::extreg_exccause_r), FUNC(xtensa_device::extreg_exccause_w)); // "exccause"
+
+ // Debug Option (233)
+ //map(0xe9, 0xe9) // "debugcause",
+
+ // Timer Interrupt Option (234)
+ map(0xea, 0xea).rw(FUNC(xtensa_device::extreg_ccount_r), FUNC(xtensa_device::extreg_ccount_w)); // "ccount"
+
+ // Processor ID Option (235)
+ //map(0xeb, 0xeb) // "prid",
+
+ // Debug Option (236-237)
+ //map(0xec, 0xec) // "icount",
+ map(0xed, 0xed).rw(FUNC(xtensa_device::extreg_icountlevel_r), FUNC(xtensa_device::extreg_icountlevel_w)); // "icountlevel"
+
+ // Exception Option (238)
+ //map(0xee, 0xee) // "excvaddr",
+
+ // Timer Interrupt Option (240-242)
+ map(0xf0, 0xf0).rw(FUNC(xtensa_device::extreg_ccompare0_r), FUNC(xtensa_device::extreg_ccompare0_w)); // "ccompare0"
+ //map(0xf1, 0xf1) // "ccompare1",
+ //map(0xf2, 0xf2) // "ccompare2",
+
+ // Miscellaneous Special Registers Option (244-247)
+ //map(0xf4, 0xf4) // "misc0",
+ //map(0xf5, 0xf5) // "misc1",
+ //map(0xf6, 0xf6) // "misc2",
+ //map(0xf7, 0xf7) // "misc3",
+
+}
+
+
void xtensa_device::device_start()
{
space(AS_PROGRAM).cache(m_cache);
@@ -41,31 +357,1941 @@ void xtensa_device::device_start()
std::fill(std::begin(m_a), std::end(m_a), 0);
+ m_num_physical_regs = 2048; // just set this higher than it should be for now, until we emulate window exceptions (marimba startup check suggests 32, with it wrapping around when exceptions are disabled)
+ m_a_real.resize(m_num_physical_regs);
+
set_icountptr(m_icount);
state_add(XTENSA_PC, "PC", m_pc);
state_add(STATE_GENPC, "GENPC", m_pc);
state_add(STATE_GENPCBASE, "CURPC", m_pc);
+ state_add(XTENSA_WINDOW, "WinBase", m_extreg_windowbase);
+ state_add(XTENSA_INTENABLE, "IntEnable", m_extreg_intenable);
+ state_add(XTENSA_LOOPBEGIN, "LoopBegin", m_extreg_lbeg);
+ state_add(XTENSA_LOOPEND, "LoopEnd", m_extreg_lend);
+ state_add(XTENSA_LOOPCOUNT, "LoopCount", m_extreg_lcount);
+
for (int i = 0; i < 16; i++)
state_add(XTENSA_A0 + i, string_format("a%d", i).c_str(), m_a[i]);
- save_item(NAME(m_pc));
+ state_add(XTENSA_PC, "PC", m_pc);
+
+ save_item(NAME(m_a_real));
save_item(NAME(m_a));
+ save_item(NAME(m_pc));
+ save_item(NAME(m_icount));
+ save_item(NAME(m_extreg_windowbase));
+ save_item(NAME(m_extreg_windowstart));
+ save_item(NAME(m_extreg_sar));
+ save_item(NAME(m_extreg_lbeg));
+ save_item(NAME(m_extreg_lend));
+ save_item(NAME(m_extreg_lcount));
+ save_item(NAME(m_extreg_ps));
+ save_item(NAME(m_extreg_cacheattr));
+ save_item(NAME(m_extreg_epc1));
+ save_item(NAME(m_extreg_epc2));
+ save_item(NAME(m_extreg_epc3));
+ save_item(NAME(m_extreg_epc4));
+ save_item(NAME(m_extreg_epc5));
+ save_item(NAME(m_extreg_eps2));
+ save_item(NAME(m_extreg_eps3));
+ save_item(NAME(m_extreg_eps4));
+ save_item(NAME(m_extreg_eps5));
+ save_item(NAME(m_extreg_excsave1));
+ save_item(NAME(m_extreg_excsave2));
+ save_item(NAME(m_extreg_excsave3));
+ save_item(NAME(m_extreg_excsave4));
+ save_item(NAME(m_extreg_excsave5));
+ save_item(NAME(m_extreg_ibreaka0));
+ save_item(NAME(m_extreg_dbreaka0));
+ save_item(NAME(m_extreg_dbreakc0));
+ save_item(NAME(m_extreg_icountlevel));
+ save_item(NAME(m_extreg_ccompare0));
+ save_item(NAME(m_extreg_intenable));
+ save_item(NAME(m_extreg_intclr));
+ save_item(NAME(m_extreg_intset));
+ save_item(NAME(m_extreg_ccount));
+ save_item(NAME(m_extreg_exccause));
+ save_item(NAME(m_nextpc));
}
void xtensa_device::device_reset()
{
- // TODO: Reset state
+ m_extreg_windowbase = 0;
+ m_extreg_windowstart = 0;
+ switch_windowbase(0);
+
+ for (int i = 0; i < m_num_physical_regs; i++)
+ m_a_real[i] = 0;
+
+ for (int i = 0; i < 16; i++)
+ m_a[i] = 0;
+
+ m_extreg_sar = 0;
+ m_extreg_lbeg = 0;
+ m_extreg_lend = 0;
+ m_extreg_lcount = 0;
+ m_extreg_ps = 0;
+ m_extreg_cacheattr = 0;
+ m_extreg_epc1 = 0;
+ m_extreg_epc2 = 0;
+ m_extreg_epc3 = 0;
+ m_extreg_epc4 = 0;
+ m_extreg_epc5 = 0;
+ m_extreg_eps2 = 0;
+ m_extreg_eps3 = 0;
+ m_extreg_eps4 = 0;
+ m_extreg_eps5 = 0;
+ m_extreg_excsave1 = 0;
+ m_extreg_excsave2 = 0;
+ m_extreg_excsave3 = 0;
+ m_extreg_excsave4 = 0;
+ m_extreg_excsave5 = 0;
+ m_extreg_ibreaka0 = 0;
+ m_extreg_dbreaka0 = 0;
+ m_extreg_dbreakc0 = 0;
+ m_extreg_icountlevel = 0;
+ m_extreg_ccompare0 = 0;
+ m_extreg_intenable = 0;
+ m_extreg_intclr = 0;
+ m_extreg_intset = 0;
+ m_extreg_ccount = 0;
+ m_extreg_exccause = 0;
+ m_nextpc = 0;
+
+ m_pc = m_startupvector;
+}
+
+void xtensa_device::handle_reserved(u32 inst)
+{
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8s0x%02X ; reserved\n", "db", inst & 0xff);
+ m_nextpc = m_pc + 1;
+}
+
+u32 xtensa_device::get_reg(const u8 reg)
+{
+ return m_a[reg];
+}
+
+void xtensa_device::set_reg(const u8 reg, u32 value)
+{
+ m_a[reg] = value;
+}
+
+void xtensa_device::switch_windowbase(s32 change)
+{
+ for (int i=0;i<16;i++)
+ {
+ s32 realreg = (i + m_extreg_windowbase * 4) & (m_num_physical_regs-1);
+ m_a_real[realreg] = m_a[i];
+ }
+
+ m_extreg_windowbase += change;
+
+ for (int i=0;i<16;i++)
+ {
+ s32 realreg = (i + m_extreg_windowbase * 4) & (m_num_physical_regs-1);
+ m_a[i] = m_a_real[realreg];
+ }
+}
+
+
+u32 xtensa_device::get_mem32(u32 addr)
+{
+ //if (addr & 3)
+ // logerror("get_mem32 unaligned\n");
+
+ return m_space.read_dword(addr & ~3);
+}
+
+void xtensa_device::set_mem32(u32 addr, u32 data)
+{
+ //if (addr & 3)
+ // logerror("set_mem32 unaligned\n");
+
+ m_space.write_dword(addr &~ 3, data);
+}
+
+u8 xtensa_device::get_mem8(u32 addr)
+{
+ return m_space.read_byte(addr);
+}
+
+void xtensa_device::set_mem8(u32 addr, u8 data)
+{
+ m_space.write_byte(addr, data);
+}
+
+u16 xtensa_device::get_mem16(u32 addr)
+{
+ if (addr & 1)
+ logerror("get_mem16 unaligned\n");
+
+ return m_space.read_word(addr & ~1);
+}
+
+void xtensa_device::set_mem16(u32 addr, u16 data)
+{
+ if (addr & 1)
+ logerror("set_mem16 unaligned\n");
+
+ m_space.write_word(addr & ~1, data);
+}
+
+void xtensa_device::handle_retw()
+{
+ // TODO: exceptions etc.
+ u32 addr = get_reg(0);
+ u8 xval = (addr >> 30) & 3;
+ u32 newaddr = (m_pc & 0xc0000000) | (addr & 0x3fffffff);
+ switch_windowbase(-xval);
+ m_nextpc = newaddr;
+}
+bool xtensa_device::handle_bz(u32 inst)
+{
+ const u8 reg = BIT(inst, 8, 4);
+ u32 addr = m_pc + 4 + util::sext(inst >> 12, 12);
+
+ switch (BIT(inst, 6, 2))
+ {
+ case 0b00:// beqz
+ {
+ if (get_reg(reg) == 0)
+ {
+ m_nextpc = addr;
+ return true; // avoid loop check
+ }
+ break;
+ }
+ case 0b01:// bnez
+ {
+ if (get_reg(reg) != 0)
+ {
+ m_nextpc = addr;
+ return true; // avoid loop check
+ }
+ break;
+ }
+ case 0b10:// bltz
+ {
+ if (get_reg(reg) & 0x80000000)
+ {
+ m_nextpc = addr;
+ return true; // avoid loop check
+ }
+ break;
+ }
+ case 0b11:// bgez
+ {
+ if (!(get_reg(reg) & 0x80000000))
+ {
+ m_nextpc = addr;
+ return true; // avoid loop check
+ }
+ break;
+ }
+ break;
+ }
+
+ return false;
+}
+
+void xtensa_device::getop_and_execute()
+{
+ m_nextpc = m_pc + 2;
+ u32 inst = m_cache.read_byte(m_pc);
+ inst |= m_cache.read_byte(m_pc+1)<<8;
+
+ const u8 op0 = BIT(inst, 0, 4);
+ if (op0 < 0b1000)
+ {
+ inst |= u32(m_cache.read_byte(m_pc+2)) << 16;
+ m_nextpc = m_pc + 3;
+ }
+
+ switch (op0)
+ {
+ case 0b0000: // QRST
+ switch (BIT(inst, 16, 4))
+ {
+ case 0b0000: // RST0
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0000: // ST0
+ switch (BIT(inst, 12, 4))
+ {
+ case 0b0000: // SNM0
+ switch (BIT(inst, 4, 4))
+ {
+ case 0b0000: // ILL
+ LOGMASKED(LOG_UNHANDLED_OPS, "ill\n");
+ break;
+
+ case 0b1000: // RET
+ {
+ m_nextpc = get_reg(0);
+ m_pc = m_nextpc; return; // avoid loop check
+ break;
+ }
+
+ case 0b1001: // RETW (with Windowed Register Option)
+ {
+ handle_retw();
+ break;
+ }
+
+
+ case 0b1010: // JX
+ {
+ const u8 reg = BIT(inst, 8, 4);
+ m_nextpc = get_reg(reg);
+ m_pc = m_nextpc; return; // avoid loop check
+ break;
+ }
+
+ case 0b1100: // CALLX0
+ {
+ const u8 reg = BIT(inst, 8, 4);
+ const u32 next = get_reg(reg);
+ set_reg(0, m_nextpc);
+ m_nextpc = next;
+ m_pc = m_nextpc; return; // avoid loop check
+ break;
+ }
+
+ case 0b1101: // CALLX4 (with Windowed Register Option)
+ case 0b1110: // CALLX8 (with Windowed Register Option)
+ case 0b1111: // CALLX12 (with Windowed Register Option)
+ {
+ const u8 reg = BIT(inst, 8, 4);
+ const u8 xval = BIT(inst, 4, 2);
+ set_callinc(xval);
+ const u32 next = get_reg(reg);
+ set_reg(xval*4, (m_nextpc & 0x3fffffff) | (xval << 30));
+ m_nextpc = next;
+ m_pc = m_nextpc; return; // avoid loop check
+ break;
+ }
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0001: // MOVSP (with Windowed Register Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d", "movsp\n", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0010: // SYNC
+ switch (BIT(inst, 4, 8))
+ {
+ case 0b00000000: // ISYNC
+ LOGMASKED(LOG_UNHANDLED_SYNC_OPS, "isync\n");
+ break;
+
+ case 0b00000001: // RSYNC
+ LOGMASKED(LOG_UNHANDLED_SYNC_OPS, "rsync\n");
+ break;
+
+ case 0b00000010: // ESYNC
+ LOGMASKED(LOG_UNHANDLED_SYNC_OPS, "esync\n");
+ break;
+
+ case 0b00000011: // DSYNC
+ LOGMASKED(LOG_UNHANDLED_SYNC_OPS, "dsync\n");
+ break;
+
+ case 0b00001000: // EXCW (with Exception Option)
+ LOGMASKED(LOG_UNHANDLED_SYNC_OPS, "excw\n");
+ break;
+
+ case 0b00001100: // MEMW
+ LOGMASKED(LOG_UNHANDLED_SYNC_OPS, "memw\n");
+ break;
+
+ case 0b00001101: // EXTW (added in RA-2004.1)
+ LOGMASKED(LOG_UNHANDLED_SYNC_OPS, "extw\n");
+ break;
+
+ case 0b00001111: // NOP (added in RA-2004.1; was assembly macro previously)
+ // nothing
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0011: // RFEI
+ switch (BIT(inst, 4, 4))
+ {
+ case 0b0000: // RFET
+ switch (BIT(inst, 8, 4))
+ {
+ case 0b0000: // RFE (with Exception Option)
+ {
+ m_nextpc = m_extreg_epc1;
+ clear_irqpri(2);
+ clear_irqpri(4);
+ break;
+ }
+
+ case 0b0001: // RFUE (with Exception Option; XEA1 only)
+ LOGMASKED(LOG_UNHANDLED_OPS, "rfue\n");
+ break;
+
+ case 0b0010: // RFDE (with Exception Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "rfde\n");
+ break;
+
+ case 0b0100: // RFWO (with Windowed Register option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "rfwo\n");
+ break;
+
+ case 0b0101: // RFWU (with Windowed Register option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "rfwu\n");
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0001: // RFI (with High-Priority Interrupt Option)
+ {
+ u8 level = BIT(inst, 8, 4);
+
+ switch (level)
+ {
+ case 2:
+ m_extreg_ps = m_extreg_eps2;
+ m_nextpc = m_extreg_epc2;
+ break;
+
+ case 3:
+ m_extreg_ps = m_extreg_eps3;
+ m_nextpc = m_extreg_epc3;
+ clear_irqpri(1);
+ break;
+
+ case 4:
+ m_extreg_ps = m_extreg_eps4;
+ m_nextpc = m_extreg_epc4;
+ break;
+
+ case 5:
+ m_extreg_ps = m_extreg_eps5;
+ m_nextpc = m_extreg_epc5;
+ break;
+
+ default:
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8s%d\n", "rfi", level);
+ break;
+ }
+
+ break;
+ }
+
+ case 0b0010: // RFME (with Memory ECC/Parity Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "rfme\n");
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0100: // BREAK (with Debug Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8s%d, %d\n", "break", BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b0101: // SYSCALL (with Exception Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "syscall\n");
+ break;
+
+ case 0b0110: // RSIL (with Interrupt Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, %d\n", "rsil", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0111: // WAITI (with Interrupt Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8s%d\n", "waiti", BIT(inst, 8, 4));
+ break;
+
+ case 0b1000: // ANY4 (with Boolean Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sb%d, b%d\n", "any4", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b1001: // ALL4 (with Boolean Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sb%d, b%d\n", "all4", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b1010: // ANY8 (with Boolean Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sb%d, b%d\n", "any8", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b1011: // ALL8 (with Boolean Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sb%d, b%d\n", "all8", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0001: // AND
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ set_reg(dstreg, get_reg(reg_s) & get_reg(reg_t));
+ break;
+ }
+ case 0b0010: // OR / MOV
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ set_reg(dstreg, get_reg(reg_s) | get_reg(reg_t));
+ }
+ break;
+
+ case 0b0011: // XOR
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ set_reg(dstreg, get_reg(reg_s) ^ get_reg(reg_t));
+ break;
+ }
+
+ case 0b0100: // ST1
+ switch (BIT(inst, 12, 4))
+ {
+ case 0b0000: // SSR - Set Shift Amount for Right Shift
+ {
+ const u8 srcreg = BIT(inst, 8, 4);
+ m_extreg_sar = get_reg(srcreg) & 0x1f;
+ break;
+ }
+ case 0b0001: // SSL - Set Shift Amount for Left Shift
+ {
+ const u8 srcreg = BIT(inst, 8, 4);
+ m_extreg_sar = 32 - (get_reg(srcreg) & 0x1f);
+ break;
+ }
+ case 0b0010: // SSA8L - Set Shift Amount for LE Byte Shift
+ {
+ const u8 srcreg = BIT(inst, 8, 4);
+ m_extreg_sar = (get_reg(srcreg) & 0x3)<<3;
+ break;
+ }
+
+ case 0b0011: // SSA8B - Set Shift Amount for BE Byte Shift
+ {
+ const u8 srcreg = BIT(inst, 8, 4);
+ m_extreg_sar = 32 - ((get_reg(srcreg) & 0x3)<<3);
+ break;
+ }
+
+ case 0b0100: // SSAI
+ {
+ const u8 imm = BIT(inst, 8, 4) + (inst & 0x000010);
+ m_extreg_sar = imm;
+ break;
+ }
+
+ case 0b0110: // RER - Read External Register
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", m_helper.s_st1_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0111: // WER - Write External Register
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", m_helper.s_st1_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b1110: // NSA (with Miscellaneous Operations Option) - Normalization Shift Amount
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", m_helper.s_st1_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b1111: // NSAU (with Miscellaneous Operations Option) - Normalization Shift Amount Unsigned
+ {
+ const u8 dstreg = BIT(inst, 4, 4);
+ const u8 srcreg = BIT(inst, 8, 4);
+ u32 result;
+ const u32 srcval = get_reg(srcreg);
+
+ if (srcval == 0)
+ {
+ result = 32;
+ }
+ else
+ {
+ result = count_leading_zeros_32(srcval);
+ }
+ set_reg(dstreg, result);
+ break;
+ }
+
+ case 0b1000: // ROTW (with Windowed Register Option)
+ {
+ const s8 imm = util::sext(inst >> 4, 4);
+ switch_windowbase(imm);
+ break;
+ }
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0101: // TLB (with Region Translation Option or MMU Option)
+ switch (BIT(inst, 12, 4))
+ {
+ case 0b0011: case 0b0101: case 0b0110: case 0b0111: // RITLB0, PITLB, WITLB, RITLB1
+ case 0b1011: case 0b1101: case 0b1110: case 0b1111: // RDTLB0, PDTLB, WDTLB, RDTLB1
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", m_helper.s_tlb_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0100: case 0b1100: // IITLB, IDTLB
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d\n", m_helper.s_tlb_ops[BIT(inst, 12, 4)], BIT(inst, 8, 4));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0110: // RT0
+ switch (BIT(inst, 8, 4))
+ {
+ case 0b0000: // NEG
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 4, 4);
+ const u32 src = get_reg(srcreg);
+ u32 result;
+ result = (src ^ 0xffffffff) + 1;
+ set_reg(dstreg, result);
+ break;
+ }
+
+ case 0b0001: // ABS
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 4, 4);
+ const u32 src = get_reg(srcreg);
+ u32 result;
+ if (src & 0x80000000)
+ result = 0x80000000 - (src & 0x7fffffff);
+ else
+ result = src;
+ set_reg(dstreg, result);
+ break;
+ }
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b1000:// ADD
+ case 0b1001:// ADDX2
+ case 0b1010:// ADDX4
+ case 0b1011:// ADDX8
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ const u8 shift = BIT(inst, 20, 2);
+ set_reg(dstreg, (get_reg(reg_s)<<shift)+get_reg(reg_t));
+ break;
+ }
+
+ case 0b1100: // SUB
+ case 0b1101: // SUBX2
+ case 0b1110: // SUBX4
+ case 0b1111: // SUBX8
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ const u8 shift = BIT(inst, 20, 2);
+ set_reg(dstreg, (get_reg(reg_s)<<shift)-get_reg(reg_t));
+ break;
+ }
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0001: // RST1
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0000: case 0b0001: // SLLI (shift count is 1..31) - Shift Left Logical Immediate
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 8, 4);
+ const u16 shift = 32 - (BIT(inst, 4, 4) + (BIT(inst, 20) ? 16 : 0));
+ if (shift == 32)
+ {
+ // undefined behavior
+ }
+ else
+ {
+ set_reg(dstreg, get_reg(srcreg) << shift);
+ }
+ break;
+ }
+
+ case 0b0010: // SRAI (shift count is 0..31) - Shift Right Arithmetic Immediate
+ case 0b0011:
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 4, 4);
+ const u8 amount = BIT(inst, 8, 4) + (BIT(inst, 20) ? 16 : 0);
+ const u32 source = get_reg(srcreg);
+ u32 result = source >> amount;
+ if (source & 0x80000000)
+ result |= 0xffffffff << (31 - (amount & 0x1f));
+
+ set_reg(dstreg, result);
+ break;
+ }
+
+ case 0b0100: // SRLI (shift count is 0..15) - Shift Right Logical Immediate
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 4, 4);
+ const u8 amount = BIT(inst, 8, 4);
+ set_reg(dstreg, get_reg(srcreg) >> amount);
+ break;
+ }
+
+ case 0b0110: // XSR (added in T1040)
+ {
+ const u8 spcreg = BIT(inst, 8, 8);
+ const u8 reg = BIT(inst, 4, 4);
+ const u32 spcregval = space(AS_EXTREGS).read_dword(spcreg);
+ const u32 regval = get_reg(reg);
+ space(AS_EXTREGS).write_dword(spcreg, regval);
+ set_reg(reg, spcregval);
+ break;
+ }
+ case 0b0111: // ACCER (added in RC-2009.0)
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0000: // RER
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", "rer", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b1000: // WER
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", "wer", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b1000: // SRC - Shift Right Combined
+ {
+ const u8 reg_r = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ const u64 fullvalue = get_reg(reg_s) | (((u64)get_reg(reg_t))<<32);
+ const u32 result = fullvalue >> (m_extreg_sar & 0x1f);
+ set_reg(reg_r, result);
+
+ break;
+ }
+
+ case 0b1001: // SRL
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 4, 4);
+ set_reg(dstreg, get_reg(srcreg) >> m_extreg_sar);
+ break;
+ }
+ case 0b1010: // SLL - Shift Left Logical
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 8, 4);
+ // we also do the "32 -" part in SSL, which sets m_extreg_sar. is this correct?
+ set_reg(dstreg, get_reg(srcreg) << (32 - m_extreg_sar));
+ break;
+ }
+
+ case 0b1011: // SRA
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 4, 4);
+ const u32 source = get_reg(srcreg);
+ u32 result = source >> m_extreg_sar;
+ if (source & 0x80000000)
+ result |= 0xffffffff << (31 - (m_extreg_sar & 0x1f));
+ set_reg(dstreg,result);
+ break;
+ }
+
+ case 0b1100: // MUL16U (with 16-bit Integer Multiply Option)
+ {
+ const u8 reg_r = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ set_reg(reg_r, (get_reg(reg_s)&0xffff) * (get_reg(reg_t)&0xffff));
+ break;
+ }
+
+ case 0b1101: // MUL16S (with 16-bit Integer Multiply Option)
+ {
+ const u8 reg_r = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ set_reg(reg_r, s16((get_reg(reg_s)&0xffff)) * s16((get_reg(reg_t)&0xffff)));
+ break;
+ }
+
+ case 0b1111: // IMP (Implementation-Specific)
+ switch (BIT(inst, 12, 4))
+ {
+ case 0b0000: // LICT (with Instruction Cache Test Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", "lict", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0001: // SICT (with Instruction Cache Test Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", "sict", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0010: // LICW (with Instruction Cache Test Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", "licw", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0011: // SICW (with Instruction Cache Test Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", "sicw", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b1000: // LDCT (with Data Cache Test Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", "ldct", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b1001: // SDCT (with Data Cache Test Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d\n", "sdct", BIT(inst, 4, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b1110: // RFDX (with On-Chip Debug)
+ switch (BIT(inst, 4, 4))
+ {
+ case 0b0000: // RFDO
+ LOGMASKED(LOG_UNHANDLED_OPS, "rfdo\n");
+ break;
+
+ case 0b0001: // RFDD
+ LOGMASKED(LOG_UNHANDLED_OPS, "rfdd\n");
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0010: // RST2
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0000: case 0b0001: case 0b0010: case 0b0011: case 0b0100: // ANDB, ANDBC, ORB, ORBC, XORB (with Boolean Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sb%d, b%d, b%d\n", m_helper.s_rst2_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b1000: case 0b1010: case 0b1011: // MULL, MULUH, MULSH (with 32-bit Integer Multiply Option)
+ case 0b1100: case 0b1101: case 0b1110: case 0b1111: // QUOU, QUOS, REMU, REMS (with 32-bit Integer Divide Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, a%d\n", m_helper.s_rst2_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0011: // RST3
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0000:// RSR
+ {
+ const u8 spcreg = BIT(inst, 8, 8);
+ const u8 reg = BIT(inst, 4, 4);
+ LOGMASKED(LOG_EXTREG_OPS, "%s.%-3d a%d\n", "rsr", m_helper.special_reg(spcreg, BIT(inst, 20)), reg);
+ set_reg(reg, space(AS_EXTREGS).read_dword(spcreg));
+ break;
+ }
+
+ case 0b0001:// WSR
+ {
+ const u8 spcreg = BIT(inst, 8, 8);
+ const u8 reg = BIT(inst, 4, 4);
+ LOGMASKED(LOG_EXTREG_OPS, "%s.%-3d a%d\n", "wsr", m_helper.special_reg(spcreg, BIT(inst, 20)), reg);
+ space(AS_EXTREGS).write_dword(spcreg, get_reg(reg));
+ break;
+ }
+
+ case 0b0010: // SEXT (with Miscellaneous Operations Option)
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 8, 4);
+ const u8 bit = BIT(inst, 4, 4) + 7;
+ set_reg(dstreg, util::sext(get_reg(srcreg), bit+1));
+ break;
+ }
+
+ case 0b0011: // CLAMPS (with Miscellaneous Operations Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, %d\n", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4) + 7);
+ break;
+
+ case 0b0100: // MIN (with Miscellaneous Operations Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, a%d\n", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b0101: // MAX (with Miscellaneous Operations Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, a%d\n", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b0110: // MINU (with Miscellaneous Operations Option) - Minimum Value Unsigned
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+
+ if (get_reg(reg_s) < get_reg(reg_t))
+ set_reg(dstreg, get_reg(reg_s));
+ else
+ set_reg(dstreg, get_reg(reg_t));
+
+ break;
+ }
+
+ case 0b0111: // MAXU (with Miscellaneous Operations Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, a%d\n", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b1000: // MOVEQZ
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ if (get_reg(reg_t) == 0)
+ {
+ set_reg(dstreg, get_reg(reg_s));
+ }
+ break;
+ }
+ case 0b1001: // MOVNEZ
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ if (get_reg(reg_t) != 0)
+ {
+ set_reg(dstreg, get_reg(reg_s));
+ }
+ break;
+ }
+
+ case 0b1010: // MOVLTZ
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ if ((get_reg(reg_t) & 0x80000000))
+ {
+ set_reg(dstreg, get_reg(reg_s));
+ }
+ break;
+ }
+
+ case 0b1011: // MOVGEZ
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ if (!(get_reg(reg_t) & 0x80000000))
+ {
+ set_reg(dstreg, get_reg(reg_s));
+ }
+ break;
+ }
+
+ case 0b1100: case 0b1101: // MOVF, MOVT (with Boolean Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, b%d\n", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b1110: case 0b1111: // RUR, WUR (TODO: TIE user_register names)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%s.u%-2d a%d\n", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 4, 8), BIT(inst, 12, 4));
+ break;
+ }
+ break;
+
+ case 0b0100: case 0b0101: // EXTUI
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 4, 4);
+ const u8 shift = BIT(inst, 8, 4) + (BIT(inst, 16) ? 16 : 0);
+ const u8 numbits = BIT(inst, 20, 4) + 1;
+ set_reg(dstreg, (get_reg(srcreg) >> shift) & ((1 << numbits)-1));
+ break;
+ }
+
+ case 0b0110: case 0b0111: // CUST0, CUST1
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8s0x%02X ; cust%d?\n", "db", inst & 0xff, BIT(inst, 16));
+ m_nextpc = m_pc + 1;
+ break;
+
+ case 0b1000: // LSCX (with Floating-Point Coprocessor Option)
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0000: // LSX
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, a%d, a%d\n", "lsx", BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b0001: // LSXU
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, a%d, a%d\n", "lsxu", BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b0100: // SSX
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, a%d, a%d\n", "ssx", BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b0101: // SSXU
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, a%d, a%d\n", "ssxu", BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b1001: // LSC4 (with Windowed Register Option)
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0000: // L32E
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, %s\n", "l32e", BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm(int(BIT(inst, 12, 4)) * 4 - 64));
+ break;
+
+ case 0b0100: // S32E
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, %s\n", "s32e", BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm(int(BIT(inst, 12, 4)) * 4 - 64));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b1010: // FP0 (with Floating-Point Coprocessor Option)
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0000: case 0b0001: case 0b0010: case 0b0100: case 0b0101: // ADD.S, SUB.S, MUL.S, MADD.S, MSUB.S
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, f%d, f%d\n", m_helper.s_fp0_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b1000: case 0b1001: case 0b1010: case 0b1011: case 0b1110: // ROUND.S, TRUNC.S, FLOOR.S, CEIL.S, UTRUNC.S
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-7s a%d, f%d, %d\n", m_helper.s_fp0_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b1100: case 0b1101: // FLOAT.S, UFLOAT.S
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-7s f%d, a%d, %d\n", m_helper.s_fp0_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b1111: // FP1OP
+ switch (BIT(inst, 4, 4))
+ {
+ case 0b0000: // MOV.S
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, f%d\n", "mov.s", BIT(inst, 12, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0001: // ABS.S
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, f%d\n", "abs.s", BIT(inst, 12, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0100: // RFR
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, f%d\n", "rfr", BIT(inst, 12, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0101: // WFR
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, a%d\n", "wfr", BIT(inst, 12, 4), BIT(inst, 8, 4));
+ break;
+
+ case 0b0110: // NEG.S
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, f%d\n", "neg.s", BIT(inst, 12, 4), BIT(inst, 8, 4));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b1011: // FP1 (with Floating-Point Option)
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0001: case 0b0010: case 0b0011: case 0b0100: case 0b0101: case 0b0110: case 0b0111: // UN.S, OEQ.S, UEQ.S, OLT.S, ULT.S, OLE.S, ULE.S
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sb%d, f%d, f%d\n", m_helper.s_fp1_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b1000: case 0b1001: case 0b1010: case 0b1011: // MOVEQZ.S, MOVNEZ.S, MOVLTZ.S, MOVGEZ.S
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, f%d, a%d\n", m_helper.s_fp1_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b1100: case 0b1101: // MOVF.S, MOVT.S
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, f%d, b%d\n", m_helper.s_fp1_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0001: // L32R (virtual address is always aligned)
+ {
+ const u8 reg = BIT(inst, 4, 4);
+ const u32 addr = (m_pc + 3 - 0x40000 + (inst >> 8) * 4) & 0xfffffffc;
+ set_reg(reg, get_mem32(addr));
+ break;
+ }
+
+ case 0b0010: // LSAI
+ switch (BIT(inst, 12, 4))
+ {
+ case 0b0000: // L8UI
+ {
+ const u8 dstreg = BIT(inst, 4, 4);
+ const u8 basereg = BIT(inst, 8, 4);
+ const u32 imm = (inst >> 16);
+ set_reg(dstreg, get_mem8(get_reg(basereg) + imm));
+ break;
+ }
+
+ case 0b0100: // S8I
+ {
+ const u8 reg = BIT(inst, 4, 4);
+ const u8 basereg = BIT(inst, 8, 4);
+ const u8 offset = inst >> 16;
+ const u32 addr = get_reg(basereg) + offset;
+ set_mem8(addr, get_reg(reg)&0xff);
+ break;
+ }
+
+ case 0b0001: // L16UI
+ {
+ const u8 dstreg = BIT(inst, 4, 4);
+ const u8 basereg = BIT(inst, 8, 4);
+ const u32 imm = (inst >> 16) * 2;
+ set_reg(dstreg, get_mem16(get_reg(basereg) + imm));
+ break;
+ }
+
+ case 0b0101: // S16I
+ {
+ const u8 reg = BIT(inst, 4, 4);
+ const u8 basereg = BIT(inst, 8, 4);
+ const u16 offset = (inst >> 16) * 2;
+ const u32 addr = get_reg(basereg) + offset;
+ set_mem16(addr, get_reg(reg)&0xffff);
+ break;
+ }
+
+ case 0b1001: // L16SI
+ {
+ const u8 dstreg = BIT(inst, 4, 4);
+ const u8 basereg = BIT(inst, 8, 4);
+ const u32 imm = (inst >> 16) * 2;
+ u32 value = get_mem16(get_reg(basereg) + imm);
+ if (value & 0x00008000)
+ value |= 0xffff0000;
+ set_reg(dstreg, value);
+ break;
+ }
+
+ case 0b0010: // L32I
+ {
+ const u8 dstreg = BIT(inst, 4, 4);
+ const u8 basereg = BIT(inst, 8, 4);
+ const u32 imm = (inst >> 16) * 4;
+ set_reg(dstreg, get_mem32(get_reg(basereg) + imm));
+ break;
+ }
+
+ case 0b0110: // S32I
+ {
+ const u8 srcreg = BIT(inst, 4, 4);
+ const u8 basereg = BIT(inst, 8, 4);
+ const u32 imm = (inst >> 16) * 4;
+ set_mem32(get_reg(basereg) + imm, get_reg(srcreg));
+ break;
+ }
+
+ case 0b1011: // L32AI (with Multiprocessor Synchronization Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, %s\n", m_helper.s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm((inst >> 16) * 4));
+ break;
+
+ case 0b1111: // S32RI (with Multiprocessor Synchronization Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, %s\n", m_helper.s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm((inst >> 16) * 4));
+ break;
+
+ case 0b1110: // S32C1I (with Conditional Store Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, %s\n", m_helper.s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm((inst >> 16) * 4));
+ break;
+
+ case 0b0111: // CACHE
+ switch (BIT(inst, 4, 4))
+ {
+ case 0b0000: case 0b0001: case 0b0010: case 0b0011: // DPFR, DPFW, DPFRO, DPFWO (with Data Cache Option)
+ case 0b0100: case 0b0101: case 0b0110: case 0b0111: // DHWB, DHWBI, DHI, DII (with Data Cache Option)
+ case 0b1100: case 0b1110: case 0b1111: // IPF, IHI, III (with Instruction Cache Option)
+ LOGMASKED(LOG_UNHANDLED_CACHE_OPS, "%-8sa%d, %s\n", m_helper.s_cache_ops[BIT(inst, 4, 4)], BIT(inst, 8, 4), m_helper.format_imm((inst >> 16) * 4));
+ break;
+
+ case 0b1000: // DCE (with Data Cache Option)
+ switch (BIT(inst, 16, 4))
+ {
+ case 0b0000: // DPFL (with Data Cache Index Lock Option)
+ LOGMASKED(LOG_UNHANDLED_CACHE_OPS, "%-8sa%d, %s\n", "dpfl", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
+ break;
+
+ case 0b0010: // DHU (with Data Cache Index Lock Option)
+ LOGMASKED(LOG_UNHANDLED_CACHE_OPS, "%-8sa%d, %s\n", "dhu", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
+ break;
+
+ case 0b0011: // DIU (with Data Cache Index Lock Option)
+ LOGMASKED(LOG_UNHANDLED_CACHE_OPS, "%-8sa%d, %s\n", "diu", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
+ break;
+
+ case 0b0100: // DIWB (added in T1050)
+ LOGMASKED(LOG_UNHANDLED_CACHE_OPS, "%-8sa%d, %s\n", "diwb", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
+ break;
+
+ case 0b0101: // DIWBI (added in T1050)
+ LOGMASKED(LOG_UNHANDLED_CACHE_OPS, "%-8sa%d, %s\n", "diwbi", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
+ break;
+ }
+ break;
+
+ case 0b1101: // ICE (with Instruction Cache Index Lock Option)
+ switch (BIT(inst, 16, 4))
+ {
+ case 0b0000: // IPFL
+ LOGMASKED(LOG_UNHANDLED_CACHE_OPS, "%-8sa%d, %s\n", "ipfl", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
+ break;
+
+ case 0b0010: // IHU
+ LOGMASKED(LOG_UNHANDLED_CACHE_OPS, "%-8sa%d, %s\n", "ihu", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
+ break;
+
+ case 0b0011: // IIU
+ LOGMASKED(LOG_UNHANDLED_CACHE_OPS, "%-8sa%d, %s\n", "iiu", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b1010: // MOVI
+ {
+ const u8 dstreg = BIT(inst, 4, 4);
+ const s32 imm = util::sext((inst & 0x000f00) + (inst >> 16), 12);
+ set_reg(dstreg, imm);
+ break;
+ }
+
+ case 0b1100: // ADDI
+ {
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ const s32 imm = s8(u8(inst >> 16));
+ set_reg(reg_t, get_reg(reg_s)+imm);
+ break;
+ }
+
+ case 0b1101: // ADDMI
+ {
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ const s32 imm = s8(u8(inst >> 16)) * 256;
+ set_reg(reg_t, get_reg(reg_s)+imm);
+ break;
+ }
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0011: // LSCI (with Floating-Point Coprocessor Option)
+ if (BIT(inst, 12, 2) == 0)
+ {
+ // LSI, SSI, LSIU, SSIU
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sf%d, a%d, %s\n", m_helper.s_lsci_ops[BIT(inst, 14, 2)], BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm(BIT(inst, 16, 8) * 4));
+ break;
+ }
+ else
+ {
+ handle_reserved(inst);
+ break;
+ }
+
+ case 0b0100: // MAC16 (with MAC16 Option)
+ switch (BIT(inst, 20, 4))
+ {
+ case 0b0000: case 0b0001: // MACID, MACCD
+ if (BIT(inst, 18, 2) == 0b10)
+ {
+ LOGMASKED(LOG_UNHANDLED_OPS, "%s.dd.%s.%s m%d, a%d, m%d, m%d\n", m_helper.s_mac16_ops[BIT(inst, 18, 2)],
+ m_helper.s_mac16_half[BIT(inst, 16, 2)],
+ BIT(inst, 20) ? "lddec" : "ldinc",
+ BIT(inst, 12, 2), BIT(inst, 8, 4),
+ BIT(inst, 14), BIT(inst, 6) + 2);
+ }
+ else
+ {
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0100: case 0b0101: // MACIA, MACCA
+ if (BIT(inst, 18, 2) == 0b10)
+ {
+ LOGMASKED(LOG_UNHANDLED_OPS, "%s.da.%s.%s m%d, a%d, m%d, a%d\n", m_helper.s_mac16_ops[BIT(inst, 18, 2)],
+ m_helper.s_mac16_half[BIT(inst, 16, 2)],
+ BIT(inst, 20) ? "lddec" : "ldinc",
+ BIT(inst, 12, 2), BIT(inst, 8, 4),
+ BIT(inst, 14), BIT(inst, 4, 4));
+ }
+ else
+ {
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0010: // MACDD
+ if (BIT(inst, 18, 2) != 0b00)
+ {
+ LOGMASKED(LOG_UNHANDLED_OPS, "%s.dd.%s m%d, m%d\n", m_helper.s_mac16_ops[BIT(inst, 18, 2)], m_helper.s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 14), BIT(inst, 6) + 2);
+ }
+ else
+ {
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0011: // MACAD
+ if (BIT(inst, 18, 2) != 0b00)
+ {
+ LOGMASKED(LOG_UNHANDLED_OPS, "%s.ad.%s a%d, m%d\n", m_helper.s_mac16_ops[BIT(inst, 18, 2)], m_helper.s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 8, 4), BIT(inst, 6) + 2);
+ }
+ else
+ {
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0110: // MACDA
+ if (BIT(inst, 18, 2) != 0b00)
+ {
+ LOGMASKED(LOG_UNHANDLED_OPS, "%s.da.%s m%d, a%d\n", m_helper.s_mac16_ops[BIT(inst, 18, 2)], m_helper.s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 14), BIT(inst, 4, 4));
+ }
+ else
+ {
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0111: // MACAA
+ LOGMASKED(LOG_UNHANDLED_OPS, "%s.aa.%s a%d, a%d\n", m_helper.s_mac16_ops[BIT(inst, 18, 2)], m_helper.s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 8, 4), BIT(inst, 4, 4));
+ break;
+
+ case 0b1000: case 0b1001: // MACI, MACC
+ switch (BIT(inst, 16, 4))
+ {
+ case 0b0000: // LDINC, LDDEC
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sm%d, a%d\n", BIT(inst, 20) ? "lddec" : "ldinc", BIT(inst, 12, 2), BIT(inst, 8, 4));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b0101: // CALLN (target address is always aligned)
+ switch (BIT(inst, 4, 2))
+ {
+ case 0b00: // CALL0
+ {
+ const u32 addr = (m_pc & 0xfffffffc) + 4 + util::sext(inst >> 6, 18) * 4;
+ const u32 next = addr;
+ set_reg(0, m_nextpc);
+ m_nextpc = next;
+ m_pc = m_nextpc; return; // avoid loop check
+ break;
+ }
+
+ case 0b01: // CALL4 (with Windowed Register Option)
+ case 0b10: // CALL8 (with Windowed Register Option)
+ case 0b11: // CALL12 (with Windowed Register Option)
+ {
+ const u32 addr = (m_pc & 0xfffffffc) + 4 + util::sext(inst >> 6, 18) * 4;
+ const u8 xval = BIT(inst, 4, 2);
+ set_callinc(xval);
+ const u32 next = addr;
+ set_reg(xval*4, (m_nextpc & 0x3fffffff) | (xval << 30));
+ m_nextpc = next;
+ m_pc = m_nextpc; return; // avoid loop check
+ break;
+ }
+ }
+ break;
+
+ case 0b0110: // SI
+ switch (BIT(inst, 4, 2))
+ {
+ case 0b00: // J
+ {
+ const u32 newpc = m_pc + 4 + util::sext(inst >> 6, 18);
+ m_nextpc = newpc;
+ m_pc = m_nextpc; return; // avoid loop check
+ break;
+ }
+
+ case 0b01: // BZ
+ {
+ if (handle_bz(inst))
+ {
+ m_pc = m_nextpc;
+ return;
+ }
+
+ break;
+ }
+
+ case 0b10: // BI0
+ {
+ const u8 reg = BIT(inst, 8, 4);
+ const u32 imm = m_helper.s_b4const[BIT(inst, 12, 4)];
+ const u32 addr = m_pc + 4 + s8(u8(inst >> 16));
+ const u8 optype = BIT(inst, 6, 2);
+ switch (optype)
+ {
+ case 0b00: // beqi
+ {
+ if (imm == get_reg(reg))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ }
+ case 0b01: // bnei
+ {
+ if (imm != get_reg(reg))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ }
+ case 0b10: // blti
+ if ((s32)get_reg(reg) < (s32)imm)
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ case 0b11: // bgei
+ if ((s32)get_reg(reg) >= (s32)imm)
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ }
+ break;
+ }
+
+ case 0b11: // BI1
+ switch (BIT(inst, 6, 2))
+ {
+ case 0b00: // ENTRY
+ {
+ // TODO window exception checking etc.
+ const u8 reg = BIT(inst, 8, 4);
+ const u32 stacksize = (inst >> 12) << 3;
+ u32 stack = get_reg(reg);
+ switch_windowbase(get_callinc());
+ stack -= stacksize;
+ set_reg(reg, stack);
+ break;
+ }
+
+ case 0b01: // B1
+ switch (BIT(inst, 12, 4))
+ {
+ case 0b0000: case 0b0001: // BF, BT (with Boolean Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sb%d, 0x%08X\n", BIT(inst, 12) ? "bt" : "bf", BIT(inst, 8, 4), m_pc + 4 + s8(u8(inst >> 16)));
+ break;
+
+ case 0b1000: // LOOP (with Loop Option)
+ {
+ const u8 reg = BIT(inst, 8, 4);
+ const u32 addr = m_pc + 4 + s8(u8(inst >> 16));
+ m_extreg_lcount = get_reg(reg)-1;
+ m_extreg_lbeg = m_nextpc;
+ m_extreg_lend = addr;
+ break;
+ }
+
+ case 0b1001: // LOOPNEZ (with Loop Option)
+ {
+ const u8 reg = BIT(inst, 8, 4);
+ const u32 addr = m_pc + 4 + s8(u8(inst >> 16));
+ m_extreg_lcount = get_reg(reg)-1;
+ m_extreg_lbeg = m_nextpc;
+ m_extreg_lend = addr;
+ if (!get_reg(reg))
+ {
+ m_nextpc = m_extreg_lend;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ }
+
+ case 0b1010: // LOOPGTZ (with Loop Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, 0x%08X\n", "loopgtz", BIT(inst, 8, 4), m_pc + 4 + s8(u8(inst >> 16)));
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ case 0b10: // BLTUI - Branch if Less Than Unsigned Immediate
+ {
+ const u8 reg = BIT(inst, 8, 4);
+ const u32 imm = m_helper.s_b4constu[BIT(inst, 12, 4)];
+ const u32 addr = m_pc + 4 + s8(u8(inst >> 16));
+ if (get_reg(reg) < imm)
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ }
+
+ case 0b11: // BGEUI - Branch if Greater Than or Eq Unsigned Immediate
+ {
+ const u8 reg = BIT(inst, 8, 4);
+ const u32 imm = m_helper.s_b4constu[BIT(inst, 12, 4)];
+ const u32 addr = m_pc + 4 + s8(u8(inst >> 16));
+ if (get_reg(reg) >= imm)
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ }
+ }
+ break;
+ }
+ break;
+
+ case 0b0111: // B
+ if (BIT(inst, 13, 2) == 0b11)
+ {
+ // BBCI, BBSI
+ const u8 reg = BIT(inst, 8, 4);
+ const u8 imm = BIT(inst, 4, 4) + (BIT(inst, 12) ? 16 : 0);
+ const u32 addr = m_pc + 4 + s8(u8(inst >> 16));
+ if (BIT(inst, 15)) // BBSI
+ {
+ if ((BIT(get_reg(reg), imm)))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ }
+ else // BBCI
+ {
+ if (!(BIT(get_reg(reg), imm)))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ }
+ break;
+ }
+ else
+ {
+ // BNONE, BEQ, BLT, BLTU, BALL, BBC, BBCI, BANY, BNE, BGE, BGEU, BNALL, BBS
+ const u8 as = BIT(inst, 8, 4);
+ const u8 at = BIT(inst, 4, 4);
+ const u32 addr = m_pc + 4 + s8(u8(inst >> 16));
+
+ switch (BIT(inst, 12, 4))
+ {
+ case 0b0000:// bnone
+ if (!(get_reg(as) & get_reg(at)))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ case 0b0001:// beq
+ if ((get_reg(as) == get_reg(at)))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ case 0b0010:// blt
+ if ((s32)get_reg(as) < (s32)get_reg(at))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ case 0b0011:// bltu
+ if (get_reg(as) < get_reg(at))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ case 0b0100:// ball
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, 0x%08X\n", "ball", as, at, addr);
+ break;
+ case 0b0101:// bbc
+ if (!(BIT(get_reg(as), get_reg(at)&0x1f)))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+
+ break;
+ //case 0b0110:// bbci
+ // LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, 0x%08X\n", "bbci", as, at, addr);
+ // break;
+ //case 0b0111:// bbci
+ // LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, 0x%08X\n", "bbci", as, at, addr);
+ // break;
+ case 0b1000:// bany
+ if (get_reg(as) & get_reg(at))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ case 0b1001:// bne
+ if ((get_reg(as) != get_reg(at)))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ case 0b1010:// bge
+ if ((s32)get_reg(as) >= (s32)get_reg(at))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ case 0b1011:// bgeu
+ if (get_reg(as) >= get_reg(at))
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ case 0b1100:// bnall
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, 0x%08X\n", "bnall", as, at, addr);
+ break;
+ case 0b1101:// bbs
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, 0x%08X\n", "bbs", as, at, addr);
+ break;
+ //case 0b1110:// bbsi
+ // LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, 0x%08X\n", "bbsi", as, at, addr);
+ // break;
+ //case 0b1111:// bbsih
+ // LOGMASKED(LOG_UNHANDLED_OPS, "%-8sa%d, a%d, 0x%08X\n", "bbsih", as, at, addr);
+ // break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 0b1000: // L32I.N (with Code Density Option)
+ {
+ const u8 dstreg = BIT(inst, 4, 4);
+ const u8 basereg = BIT(inst, 8, 4);
+ const u32 imm = BIT(inst, 12, 4) * 4;
+ set_reg(dstreg, get_mem32(get_reg(basereg) + imm));
+ break;
+ }
+
+ case 0b1001: // S32I.N (with Code Density Option)
+ {
+ const u8 srcreg = BIT(inst, 4, 4);
+ const u8 basereg = BIT(inst, 8, 4);
+ const u32 imm = BIT(inst, 12, 4) * 4;
+ set_mem32(get_reg(basereg) + imm, get_reg(srcreg));
+ break;
+ }
+
+ case 0b1010: // ADD.N (with Code Density Option)
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 reg_s = BIT(inst, 8, 4);
+ const u8 reg_t = BIT(inst, 4, 4);
+ set_reg(dstreg, get_reg(reg_s)+get_reg(reg_t));
+ break;
+ }
+
+ case 0b1011: // ADDI.N (with Code Density Option)
+ {
+ const u8 dstreg = BIT(inst, 12, 4);
+ const u8 srcreg = BIT(inst, 8, 4);
+ const s32 imm = BIT(inst, 4, 4) == 0 ? -1 : int(BIT(inst, 4, 4));
+ set_reg(dstreg, get_reg(srcreg)+imm);
+ break;
+ }
+
+ case 0b1100: // ST2 (with Code Density Option)
+ if (!BIT(inst, 7))
+ {
+ // 7-bit immediate field uses asymmetric sign extension (range is -32..95)
+ const u8 dstreg = BIT(inst, 8, 4);
+ const s32 imm = int((inst & 0x0070) + BIT(inst, 12, 4) - (BIT(inst, 5, 2) == 0b11 ? 128 : 0));
+ set_reg(dstreg,imm);
+ break;
+ }
+ else
+ {
+ if (BIT(inst, 6))
+ {
+ // 6-bit immediate field is zero-extended (these forms can branch forward only)
+ const u8 reg = BIT(inst, 8, 4);
+ const u32 addr = m_pc + 4 + (inst & 0x0030) + BIT(inst, 12, 4);
+ if (get_reg(reg) != 0)
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ }
+ else
+ {
+ // 6-bit immediate field is zero-extended (these forms can branch forward only)
+ const u8 reg = BIT(inst, 8, 4);
+ const u32 addr = m_pc + 4 + (inst & 0x0030) + BIT(inst, 12, 4);
+ if (get_reg(reg) == 0)
+ {
+ m_nextpc = addr;
+ m_pc = m_nextpc; return; // avoid loop check
+ }
+ break;
+ }
+ break;
+ }
+
+ case 0b1101: // ST3 (with Code Density Option)
+ switch (BIT(inst, 12, 4))
+ {
+ case 0b0000: // MOV.N
+ {
+ const u8 dstreg = BIT(inst, 4, 4);
+ const u8 srcreg = BIT(inst, 8, 4);
+ set_reg(dstreg, get_reg(srcreg));
+ break;
+ }
+
+ case 0b1111: // S3
+ switch (BIT(inst, 4, 4))
+ {
+ case 0b0000: // RET.N
+ {
+ m_nextpc = get_reg(0);
+ m_pc = m_nextpc; return; // avoid loop check
+ break;
+ }
+
+ case 0b0001: // RETW.N (with Windowed Register Option)
+ {
+ handle_retw();
+ break;
+ }
+
+ case 0b0010: // BREAK.N (with Debug Option)
+ LOGMASKED(LOG_UNHANDLED_OPS, "%-8s%d\n", "break.n", BIT(inst, 8, 4));
+ break;
+
+ case 0b0011: // NOP.N
+ // nothing
+ break;
+
+ case 0b0110: // ILL.N
+ LOGMASKED(LOG_UNHANDLED_OPS, "ill.n\n");
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+ break;
+
+ default:
+ handle_reserved(inst);
+ break;
+ }
+
+ // NOTE, if a branch or jump got us here the loop check isn't done!
+ // handle zero overhead loops
+ if (m_nextpc == m_extreg_lend)
+ {
+ m_extreg_lcount--;
+
+ if (m_extreg_lcount != 0xffffffff)
+ {
+ m_nextpc = m_extreg_lbeg;
+ }
+ }
+
+ m_pc = m_nextpc;
+}
+
+void xtensa_device::check_interrupts()
+{
+ // TODO: this is not accurate(!)
+
+ if ((m_extreg_intenable & 0x10) && (m_extreg_intset & 0x10) && (get_irqpri() < 1))
+ {
+ m_extreg_eps3 = m_extreg_ps;
+ m_extreg_epc3 = m_nextpc;
+ m_pc = m_irq_vectors[4];
+ set_irqpri(1);
+ }
+ else if ((m_extreg_intenable & 0x02) && (m_extreg_intset & 0x02) && (get_irqpri() < 2))
+ {
+ m_extreg_epc1 = m_nextpc;
+ m_pc = m_irq_vectors[1];
+ set_irqpri(2);
+ }
+ else if ((m_extreg_intenable & 0x04) && (m_extreg_intset & 0x04) && (get_irqpri() < 3))
+ {
+ m_extreg_epc1 = m_nextpc;
+ m_pc = m_irq_vectors[1];
+ set_irqpri(4);
+ }
}
+
void xtensa_device::execute_run()
{
- debugger_instruction_hook(m_pc);
+ while (m_icount > 0)
+ {
+ check_interrupts();
+
+ debugger_instruction_hook(m_pc);
+
+ m_extreg_ccount++;
- m_icount = 0;
+ getop_and_execute();
+ m_icount--;
+ }
}
void xtensa_device::execute_set_input(int inputnum, int state)
{
- // TODO
+ if (inputnum == 0x10)
+ {
+ if (state == ASSERT_LINE)
+ m_extreg_intset |= 0x10;
+ else
+ m_extreg_intset &= ~0x10;
+ }
+
+ if (inputnum == 0x2)
+ {
+ if (state == ASSERT_LINE)
+ m_extreg_intset |= 0x02;
+ else
+ m_extreg_intset &= ~0x02;
+ }
+
+ if (inputnum == 0x4)
+ {
+ if (state == ASSERT_LINE)
+ m_extreg_intset |= 0x04;
+ else
+ m_extreg_intset &= ~0x04;
+ }
}
diff --git a/src/devices/cpu/xtensa/xtensa.h b/src/devices/cpu/xtensa/xtensa.h
index 1c288a36aa7..cd5903bfcdb 100644
--- a/src/devices/cpu/xtensa/xtensa.h
+++ b/src/devices/cpu/xtensa/xtensa.h
@@ -1,11 +1,12 @@
// license:BSD-3-Clause
-// copyright-holders:AJR
+// copyright-holders:AJR, David Haywood
#ifndef MAME_CPU_XTENSA_XTENSA_H
#define MAME_CPU_XTENSA_XTENSA_H
#pragma once
+#include "xtensa_helper.h"
class xtensa_device : public cpu_device
{
@@ -13,13 +14,32 @@ public:
xtensa_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
enum {
+ AS_EXTREGS = AS_OPCODES + 1,
+ };
+
+ enum {
XTENSA_PC,
+ XTENSA_WINDOW,
+ XTENSA_INTENABLE,
+ XTENSA_LOOPBEGIN,
+ XTENSA_LOOPEND,
+ XTENSA_LOOPCOUNT,
XTENSA_A0, XTENSA_A1, XTENSA_A2, XTENSA_A3,
XTENSA_A4, XTENSA_A5, XTENSA_A6, XTENSA_A7,
XTENSA_A8, XTENSA_A9, XTENSA_A10, XTENSA_A11,
- XTENSA_A12, XTENSA_A13, XTENSA_A14, XTENSA_A15
+ XTENSA_A12, XTENSA_A13, XTENSA_A14, XTENSA_A15,
};
+ void set_irq_vector(int bit, u32 vector)
+ {
+ m_irq_vectors[bit] = vector;
+ }
+
+ void set_startupvector(u32 vector)
+ {
+ m_startupvector = vector;
+ }
+
protected:
// device-level overrides
virtual void device_start() override;
@@ -38,13 +58,154 @@ protected:
private:
// address space
address_space_config m_space_config;
+ address_space_config m_extregs_config;
+
memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache m_cache;
memory_access<32, 2, 0, ENDIANNESS_LITTLE>::specific m_space;
+ u32 extreg_windowbase_r();
+ void extreg_windowbase_w(u32 data);
+ u32 extreg_windowstart_r();
+ void extreg_windowstart_w(u32 data);
+ u32 extreg_lbeg_r();
+ void extreg_lbeg_w(u32 data);
+ u32 extreg_lend_r();
+ void extreg_lend_w(u32 data);
+ u32 extreg_lcount_r();
+ void extreg_lcount_w(u32 data);
+ u32 extreg_ps_r();
+ void extreg_ps_w(u32 data);
+ u32 extreg_cacheattr_r();
+ void extreg_cacheattr_w(u32 data);
+ u32 extreg_epc1_r();
+ void extreg_epc1_w(u32 data);
+ u32 extreg_epc2_r();
+ void extreg_epc2_w(u32 data);
+ u32 extreg_epc3_r();
+ void extreg_epc3_w(u32 data);
+ u32 extreg_epc4_r();
+ void extreg_epc4_w(u32 data);
+ u32 extreg_epc5_r();
+ void extreg_epc5_w(u32 data);
+ u32 extreg_eps2_r();
+ void extreg_eps2_w(u32 data);
+ u32 extreg_eps3_r();
+ void extreg_eps3_w(u32 data);
+ u32 extreg_eps4_r();
+ void extreg_eps4_w(u32 data);
+ u32 extreg_eps5_r();
+ void extreg_eps5_w(u32 data);
+ u32 extreg_excsave1_r();
+ void extreg_excsave1_w(u32 data);
+ u32 extreg_excsave2_r();
+ void extreg_excsave2_w(u32 data);
+ u32 extreg_excsave3_r();
+ void extreg_excsave3_w(u32 data);
+ u32 extreg_excsave4_r();
+ void extreg_excsave4_w(u32 data);
+ u32 extreg_excsave5_r();
+ void extreg_excsave5_w(u32 data);
+ u32 extreg_ibreaka0_r();
+ void extreg_ibreaka0_w(u32 data);
+ u32 extreg_dbreaka0_r();
+ void extreg_dbreaka0_w(u32 data);
+ u32 extreg_dbreakc0_r();
+ void extreg_dbreakc0_w(u32 data);
+ u32 extreg_icountlevel_r();
+ void extreg_icountlevel_w(u32 data);
+ u32 extreg_ccompare0_r();
+ void extreg_ccompare0_w(u32 data);
+ u32 extreg_intenable_r();
+ void extreg_intenable_w(u32 data);
+ u32 extreg_intclr_r();
+ void extreg_intclr_w(u32 data);
+ u32 extreg_intset_r();
+ void extreg_intset_w(u32 data);
+ u32 extreg_ccount_r();
+ void extreg_ccount_w(u32 data);
+ u32 extreg_exccause_r();
+ void extreg_exccause_w(u32 data);
+ u32 extreg_sar_r();
+ void extreg_sar_w(u32 data);
+
+ void set_irqpri(u8 val);
+ u8 get_irqpri();
+ void clear_irqpri(u8 val);
+
+
+ void set_callinc(u8 val);
+ u8 get_callinc();
+
+ void ext_regs(address_map &map);
+
+ bool handle_bz(u32 inst);
+ void handle_retw();
+ void check_interrupts();
+ void getop_and_execute();
+
+ inline u32 get_reg(u8 reg);
+ inline void set_reg(u8 reg, u32 value);
+
+ inline u32 get_mem32(u32 addr);
+ inline void set_mem32(u32 addr, u32 data);
+
+ inline u8 get_mem8(u32 addr);
+ inline void set_mem8(u32 addr, u8 data);
+
+ inline u16 get_mem16(u32 addr);
+ inline void set_mem16(u32 addr, u16 data);
+
+ void handle_reserved(u32 inst);
+
+ void switch_windowbase(s32 change);
+
// internal state
+ std::vector<u32> m_a_real; // actually 32 or 64 physical registers with Windowed extension
u32 m_a[16];
u32 m_pc;
s32 m_icount;
+
+ u32 m_extreg_windowbase;
+ u32 m_extreg_windowstart;
+ u32 m_extreg_sar;
+ u32 m_extreg_lbeg;
+ u32 m_extreg_lend;
+ u32 m_extreg_lcount;
+ u32 m_extreg_ps;
+ u32 m_extreg_cacheattr;
+ u32 m_extreg_epc1;
+ u32 m_extreg_epc2;
+ u32 m_extreg_epc3;
+ u32 m_extreg_epc4;
+ u32 m_extreg_epc5;
+ u32 m_extreg_eps2;
+ u32 m_extreg_eps3;
+ u32 m_extreg_eps4;
+ u32 m_extreg_eps5;
+ u32 m_extreg_excsave1;
+ u32 m_extreg_excsave2;
+ u32 m_extreg_excsave3;
+ u32 m_extreg_excsave4;
+ u32 m_extreg_excsave5;
+ u32 m_extreg_ibreaka0;
+ u32 m_extreg_dbreaka0;
+ u32 m_extreg_dbreakc0;
+ u32 m_extreg_icountlevel;
+ u32 m_extreg_ccompare0;
+ u32 m_extreg_intenable;
+ u32 m_extreg_intclr;
+ u32 m_extreg_intset;
+ u32 m_extreg_ccount;
+ u32 m_extreg_exccause;
+ u32 m_nextpc;
+
+ // config
+ u32 m_num_physical_regs;
+
+ u32 m_irq_vectors[32];
+ u32 m_startupvector;
+
+ xtensa_helper m_helper;
};
DECLARE_DEVICE_TYPE(XTENSA, xtensa_device)
diff --git a/src/devices/cpu/xtensa/xtensa_helper.cpp b/src/devices/cpu/xtensa/xtensa_helper.cpp
new file mode 100644
index 00000000000..a49ef5511a1
--- /dev/null
+++ b/src/devices/cpu/xtensa/xtensa_helper.cpp
@@ -0,0 +1,230 @@
+
+
+#include "emu.h"
+#include "xtensa_helper.h"
+
+const char *const xtensa_helper::special_regs[256] =
+{
+ "lbeg", "lend", "lcount", // Loop Option (0-2)
+ "sar", // Core Architecture (3)
+ "br", // Boolean Option (4)
+ "litbase", // Extended L32R Option (5)
+ "", "", "", "", "", "",
+ "scompare1", // Conditional Store Option (12)
+ "", "", "",
+ "acclo", "acchi", // MAC16 Option (16-17)
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+ "m0", "m1", "m2", "m3", // MAC16 Option (32-35)
+ "", "", "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "WindowBase", "WindowStart", // Windowed Register Option (72-73)
+ "", "", "", "", "", "", "", "", "",
+ "ptevaddr", // MMU Option (83)
+ "", "", "", "", "",
+ "mmid", // Trace Port Option (89)
+ "rasid", "itlbcfg", "dtlbcfg", // MMU Option (90-92)
+ "", "", "",
+ "ibreakenable", // Debug Option (96)
+ "",
+ "cacheattr", // XEA1 Only (98)
+ "atomctl", // Conditional Store Option (99)
+ "", "", "", "",
+ "ddr", // Debug Option (104)
+ "",
+ "mepc", "meps", "mesave", "mesr", "mecr", "mevaddr", // Memory ECC/Parity Option (106-111)
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+ "ibreaka0", "ibreaka1", // Debug Option (128-129)
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+ "dbreaka0", "dbreaka1", // Debug Option (144-145)
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+ "dbreakc0", "dbreakc1", // Debug Option (160-161)
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+ "epc1", // Exception Option (177)
+ "epc2", "epc3", "epc4", "epc5", "epc6", "epc7", // High-Priority Interrupt Option (178-183)
+ "", "", "", "", "", "", "", "",
+ "depc", // Exception Option (192)
+ "",
+ "eps2", "eps3", "eps4", "eps5", "eps6", "eps7", // High-Priority Interrupt Option (194-199)
+ "", "", "", "", "", "", "", "", "",
+ "excsave1", // Exception Option (209)
+ "excsave2", "excsave3", "excsave4", "excsave5", "excsave6", "excsave7", // High-Priority Interrupt Option (210-215)
+ "", "", "", "", "", "", "", "",
+ "cpenable", // Coprocessor Option (224)
+ "",
+ "intset", "intclr", "intenable", // Interrupt Option (226-228)
+ "",
+ "ps", // various options (230)
+ "vecbase", // Relocatable Vector Option (231)
+ "exccause", // Exception Option (232)
+ "debugcause", // Debug Option (233)
+ "ccount", // Timer Interrupt Option (234)
+ "prid", // Processor ID Option (235)
+ "icount", "icountlevel", // Debug Option (236-237)
+ "excvaddr", // Exception Option (238)
+ "",
+ "ccompare0", "ccompare1", "ccompare2", // Timer Interrupt Option (240-242)
+ "",
+ "misc0", "misc1", "misc2", "misc3", // Miscellaneous Special Registers Option (244-247)
+ "", "", "", "", "", "", "", ""
+};
+
+const char *const xtensa_helper::s_st1_ops[16] =
+{
+ "ssr", "ssl",
+ "ssa8l", "ssa8b",
+ "ssai", "",
+ "rer", "wer",
+ "rotw", "",
+ "", "",
+ "", "",
+ "nsa", "nsau"
+};
+
+const char *const xtensa_helper::s_tlb_ops[16] =
+{
+ "", "", "", "ritlb0",
+ "iitlb", "pitlb", "witlb", "ritlb1",
+ "", "", "", "rdtlb0",
+ "idtlb", "pdtlb", "wdtlb", "rdtlb1"
+};
+
+const char *const xtensa_helper::s_rst2_ops[16] =
+{
+ "andb", "andbc", "orb", "orbc", "xorb", "", "", "",
+ "mull", "", "muluh", "mulsh",
+ "quou", "quos", "remu", "rems"
+};
+
+const char *const xtensa_helper::s_rst3_ops[16] =
+{
+ "rsr", "wsr",
+ "sext", "clamps",
+ "min", "max",
+ "minu", "maxu",
+ "moveqz", "movnez",
+ "movltz", "movgez",
+ "movf", "movt",
+ "rur", "wur"
+};
+
+const char *const xtensa_helper::s_fp0_ops[16] =
+{
+ "add.s", "sub.s", "mul.s", "",
+ "madd.s", "msub.s", "", "",
+ "round.s", "trunc.s", "floor.s", "ceil.s",
+ "float.s", "ufloat.s", "utrunc.s", ""
+};
+
+const char *const xtensa_helper::s_fp1_ops[16] =
+{
+ "", "un.s",
+ "oeq.s", "ueq.s",
+ "olt.s", "ult.s",
+ "ole.s", "ule.s",
+ "moveqz.s", "movltz.s",
+ "movltz.s", "movgez.s",
+ "movf.s", "movt.s",
+ "", ""
+};
+
+const char *const xtensa_helper::s_lsai_ops[16] =
+{
+ "l8ui", "l16ui", "l32i", "",
+ "s8i", "s16i", "s32i", "",
+ "", "l16si", "movi", "l32ai",
+ "addi", "addmi", "s32c1i", "s32ri"
+};
+
+const char *const xtensa_helper::s_cache_ops[16] =
+{
+ "dpfr", "dpfw",
+ "dpfro", "dpfwo",
+ "dhwb", "dhwbi",
+ "dhi", "dii",
+ "", "",
+ "", "",
+ "ipf", "",
+ "ihi", "iii"
+};
+
+const char *const xtensa_helper::s_lsci_ops[4] =
+{
+ "lsi", "ssi", "lsiu", "ssiu"
+};
+
+const char *const xtensa_helper::s_mac16_ops[4] =
+{
+ "umul", "mul", "mula", "muls"
+};
+
+const char *const xtensa_helper::s_mac16_half[4] =
+{
+ "ll", "hl", "lh", "hh"
+};
+
+const char *const xtensa_helper::s_bz_ops[4] =
+{
+ "beqz", "bnez", "bltz", "bgez"
+};
+
+const char *const xtensa_helper::s_bi0_ops[4] =
+{
+ "beqi", "bnei", "blti", "bgei"
+};
+
+const int32_t xtensa_helper::s_b4const[16] =
+{
+ -1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+};
+
+const uint32_t xtensa_helper::s_b4constu[16] =
+{
+ 32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+};
+
+const char *const xtensa_helper::s_b_ops[16] =
+{
+ "bnone", "beq", "blt", "bltu", "ball", "bbc", "bbci", "bbci",
+ "bany", "bne", "bge", "bgeu", "bnall", "bbs", "bbsi", "bbsih"
+};
+
+std::string xtensa_helper::format_imm(uint32_t imm)
+{
+ if (s32(imm) < 0)
+ {
+ if (s32(imm < -9))
+ {
+ return util::string_format("-0x%X", -imm);
+ }
+ else
+ {
+ return util::string_format("-%X", -imm);
+ }
+ }
+ else
+ {
+ if (imm > 9)
+ {
+ return util::string_format("0x%X", imm);
+ }
+ else
+ {
+ return util::string_format("%X", imm);
+ }
+ }
+}
+
+
+std::string xtensa_helper::special_reg(uint8_t n, bool wsr)
+{
+ if (n == 226 && !wsr)
+ return "interrupt";
+
+ const char *s = xtensa_helper::special_regs[n];
+ if (s[0] == '\0')
+ return util::string_format("s%u", n);
+ else
+ return s;
+}
+
diff --git a/src/devices/cpu/xtensa/xtensa_helper.h b/src/devices/cpu/xtensa/xtensa_helper.h
new file mode 100644
index 00000000000..14d32eafaca
--- /dev/null
+++ b/src/devices/cpu/xtensa/xtensa_helper.h
@@ -0,0 +1,33 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+
+#ifndef MAME_CPU_XTENSA_XTENSA_HELPER_H
+#define MAME_CPU_XTENSA_XTENSA_HELPER_H
+
+#pragma once
+
+class xtensa_helper
+{
+public:
+ static const char *const special_regs[256];
+ static const char *const s_st1_ops[16];
+ static const char *const s_tlb_ops[16];
+ static const char *const s_rst2_ops[16];
+ static const char *const s_rst3_ops[16];
+ static const char *const s_fp0_ops[16];
+ static const char *const s_fp1_ops[16];
+ static const char *const s_lsai_ops[16];
+ static const char *const s_cache_ops[16];
+ static const char *const s_lsci_ops[4];
+ static const char *const s_mac16_ops[4];
+ static const char *const s_mac16_half[4];
+ static const char *const s_bz_ops[4];
+ static const char *const s_bi0_ops[4];
+ static const int32_t s_b4const[16];
+ static const uint32_t s_b4constu[16];
+ static const char *const s_b_ops[16];
+ std::string format_imm(uint32_t imm);
+ std::string special_reg(uint8_t n, bool wsr);
+};
+
+#endif
diff --git a/src/devices/cpu/xtensa/xtensad.cpp b/src/devices/cpu/xtensa/xtensad.cpp
index 50cf6da2e4f..c42219d0428 100644
--- a/src/devices/cpu/xtensa/xtensad.cpp
+++ b/src/devices/cpu/xtensa/xtensad.cpp
@@ -18,6 +18,7 @@
#include "emu.h"
#include "xtensad.h"
+#include "xtensa_helper.h"
xtensa_disassembler::xtensa_disassembler()
: util::disasm_interface()
@@ -29,220 +30,6 @@ u32 xtensa_disassembler::opcode_alignment() const
return 1;
}
-namespace {
-
-static const char *const s_special_regs[256] =
-{
- "lbeg", "lend", "lcount", // Loop Option (0-2)
- "sar", // Core Architecture (3)
- "br", // Boolean Option (4)
- "litbase", // Extended L32R Option (5)
- "", "", "", "", "", "",
- "scompare1", // Conditional Store Option (12)
- "", "", "",
- "acclo", "acchi", // MAC16 Option (16-17)
- "", "", "", "", "", "", "", "", "", "", "", "", "", "",
- "m0", "m1", "m2", "m3", // MAC16 Option (32-35)
- "", "", "", "", "", "", "", "", "", "", "", "",
- "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
- "", "", "", "", "", "", "", "",
- "WindowBase", "WindowStart", // Windowed Register Option (72-73)
- "", "", "", "", "", "", "", "", "",
- "ptevaddr", // MMU Option (83)
- "", "", "", "", "",
- "mmid", // Trace Port Option (89)
- "rasid", "itlbcfg", "dtlbcfg", // MMU Option (90-92)
- "", "", "",
- "ibreakenable", // Debug Option (96)
- "",
- "cacheattr", // XEA1 Only (98)
- "atomctl", // Conditional Store Option (99)
- "", "", "", "",
- "ddr", // Debug Option (104)
- "",
- "mepc", "meps", "mesave", "mesr", "mecr", "mevaddr", // Memory ECC/Parity Option (106-111)
- "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
- "ibreaka0", "ibreaka1", // Debug Option (128-129)
- "", "", "", "", "", "", "", "", "", "", "", "", "", "",
- "dbreaka0", "dbreaka1", // Debug Option (144-145)
- "", "", "", "", "", "", "", "", "", "", "", "", "", "",
- "dbreakc0", "dbreakc1", // Debug Option (160-161)
- "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
- "epc1", // Exception Option (177)
- "epc2", "epc3", "epc4", "epc5", "epc6", "epc7", // High-Priority Interrupt Option (178-183)
- "", "", "", "", "", "", "", "",
- "depc", // Exception Option (192)
- "",
- "eps2", "eps3", "eps4", "eps5", "eps6", "eps7", // High-Priority Interrupt Option (194-199)
- "", "", "", "", "", "", "", "", "",
- "excsave1", // Exception Option (209)
- "excsave2", "excsave3", "excsave4", "excsave5", "excsave6", "excsave7", // High-Priority Interrupt Option (210-215)
- "", "", "", "", "", "", "", "",
- "cpenable", // Coprocessor Option (224)
- "",
- "intset", "intclr", "intenable", // Interrupt Option (226-228)
- "",
- "ps", // various options (230)
- "vecbase", // Relocatable Vector Option (231)
- "exccause", // Exception Option (232)
- "debugcause", // Debug Option (233)
- "ccount", // Timer Interrupt Option (234)
- "prid", // Processor ID Option (235)
- "icount", "icountlevel", // Debug Option (236-237)
- "excvaddr", // Exception Option (238)
- "",
- "ccompare0", "ccompare1", "ccompare2", // Timer Interrupt Option (240-242)
- "",
- "misc0", "misc1", "misc2", "misc3", // Miscellaneous Special Registers Option (244-247)
- "", "", "", "", "", "", "", ""
-};
-
-static const char *const s_st1_ops[16] =
-{
- "ssr", "ssl",
- "ssa8l", "ssa8b",
- "ssai", "",
- "rer", "wer",
- "rotw", "",
- "", "",
- "", "",
- "nsa", "nsau"
-};
-
-static const char *const s_tlb_ops[16] =
-{
- "", "", "", "ritlb0",
- "iitlb", "pitlb", "witlb", "ritlb1",
- "", "", "", "rdtlb0",
- "idtlb", "pdtlb", "wdtlb", "rdtlb1"
-};
-
-static const char *const s_rst2_ops[16] =
-{
- "andb", "andbc", "orb", "orbc", "xorb", "", "", "",
- "mull", "", "muluh", "mulsh",
- "quou", "quos", "remu", "rems"
-};
-
-static const char *const s_rst3_ops[16] =
-{
- "rsr", "wsr",
- "sext", "clamps",
- "min", "max",
- "minu", "maxu",
- "moveqz", "movnez",
- "movltz", "movgez",
- "movf", "movt",
- "rur", "wur"
-};
-
-static const char *const s_fp0_ops[16] =
-{
- "add.s", "sub.s", "mul.s", "",
- "madd.s", "msub.s", "", "",
- "round.s", "trunc.s", "floor.s", "ceil.s",
- "float.s", "ufloat.s", "utrunc.s", ""
-};
-
-static const char *const s_fp1_ops[16] =
-{
- "", "un.s",
- "oeq.s", "ueq.s",
- "olt.s", "ult.s",
- "ole.s", "ule.s",
- "moveqz.s", "movltz.s",
- "movltz.s", "movgez.s",
- "movf.s", "movt.s",
- "", ""
-};
-
-static const char *const s_lsai_ops[16] =
-{
- "l8ui", "l16ui", "l32i", "",
- "s8i", "s16i", "s32i", "",
- "", "l16si", "movi", "l32ai",
- "addi", "addmi", "s32c1i", "s32ri"
-};
-
-static const char *const s_cache_ops[16] =
-{
- "dpfr", "dpfw",
- "dpfro", "dpfwo",
- "dhwb", "dhwbi",
- "dhi", "dii",
- "", "",
- "", "",
- "ipf", "",
- "ihi", "iii"
-};
-
-static const char *const s_lsci_ops[4] =
-{
- "lsi", "ssi", "lsiu", "ssiu"
-};
-
-static const char *const s_mac16_ops[4] =
-{
- "umul", "mul", "mula", "muls"
-};
-
-static const char *const s_mac16_half[4] =
-{
- "ll", "hl", "lh", "hh"
-};
-
-static const char *const s_bz_ops[4] =
-{
- "beqz", "bnez", "bltz", "bgez"
-};
-
-static const char *const s_bi0_ops[4] =
-{
- "beqi", "bnei", "blti", "bgei"
-};
-
-static const s32 s_b4const[16] =
-{
- -1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
-};
-
-static const u32 s_b4constu[16] =
-{
- 32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
-};
-
-static const char *const s_b_ops[16] =
-{
- "bnone", "beq", "blt", "bltu", "ball", "bbc", "bbci", "bbci",
- "bany", "bne", "bge", "bgeu", "bnall", "bbs", "bbsi", "bbsih"
-};
-
-} // anonymous namespace
-
-void xtensa_disassembler::format_imm(std::ostream &stream, u32 imm)
-{
- if (s32(imm) < 0)
- {
- stream << '-';
- imm = -imm;
- }
- if (imm > 9)
- stream << "0x";
- util::stream_format(stream, "%X", imm);
-}
-
-std::string xtensa_disassembler::special_reg(u8 n, bool wsr)
-{
- if (n == 226 && !wsr)
- return "interrupt";
-
- const char *s = s_special_regs[n];
- if (s[0] == '\0')
- return util::string_format("s%u", n);
- else
- return s;
-}
-
offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const xtensa_disassembler::data_buffer &opcodes, const xtensa_disassembler::data_buffer &params)
{
u32 inst = opcodes.r16(pc);
@@ -439,7 +226,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
switch (BIT(inst, 12, 4))
{
case 0b0000: case 0b0001: case 0b0010: case 0b0011: // SSR, SSL, SSA8L, SSA8B
- util::stream_format(stream, "%-8sa%d", s_st1_ops[BIT(inst, 12, 4)], BIT(inst, 8, 4));
+ util::stream_format(stream, "%-8sa%d", m_helper.s_st1_ops[BIT(inst, 12, 4)], BIT(inst, 8, 4));
break;
case 0b0100: // SSAI
@@ -448,7 +235,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
case 0b0110: case 0b0111: // RER, WER
case 0b1110: case 0b1111: // NSA, NSAU (with Miscellaneous Operations Option)
- util::stream_format(stream, "%-8sa%d, a%d", s_st1_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
+ util::stream_format(stream, "%-8sa%d, a%d", m_helper.s_st1_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
break;
case 0b1000: // ROTW (with Windowed Register Option)
@@ -466,11 +253,11 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
{
case 0b0011: case 0b0101: case 0b0110: case 0b0111: // RITLB0, PITLB, WITLB, RITLB1
case 0b1011: case 0b1101: case 0b1110: case 0b1111: // RDTLB0, PDTLB, WDTLB, RDTLB1
- util::stream_format(stream, "%-8sa%d, a%d", s_tlb_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
+ util::stream_format(stream, "%-8sa%d, a%d", m_helper.s_tlb_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
break;
case 0b0100: case 0b1100: // IITLB, IDTLB
- util::stream_format(stream, "%-8sa%d", s_tlb_ops[BIT(inst, 12, 4)], BIT(inst, 8, 4));
+ util::stream_format(stream, "%-8sa%d", m_helper.s_tlb_ops[BIT(inst, 12, 4)], BIT(inst, 8, 4));
break;
default:
@@ -514,8 +301,8 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
case 0b0001: // RST1
switch (BIT(inst, 20, 4))
{
- case 0b0000: case 0b0001: // SLLI (shift count is 0..31)
- util::stream_format(stream, "%-8sa%d, a%d, %d", "slli", BIT(inst, 12, 4), BIT(inst, 4, 4), BIT(inst, 8, 4) + (BIT(inst, 20) ? 16 : 0));
+ case 0b0000: case 0b0001: // SLLI (shift count is 1..31)
+ util::stream_format(stream, "%-8sa%d, a%d, %d", "slli", BIT(inst, 12, 4), BIT(inst, 8, 4), 32 - (BIT(inst, 4, 4) + (BIT(inst, 20) ? 16 : 0)));
break;
case 0b0010: case 0b0011: // SRAI (shift count is 0..31)
@@ -527,7 +314,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
break;
case 0b0110: // XSR (added in T1040)
- util::stream_format(stream, "xsr.%-3s a%d", special_reg(BIT(inst, 8, 8), true), BIT(inst, 4, 4));
+ util::stream_format(stream, "xsr.%-3s a%d", m_helper.special_reg(BIT(inst, 8, 8), true), BIT(inst, 4, 4));
break;
case 0b0111: // ACCER (added in RC-2009.0)
@@ -631,12 +418,12 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
switch (BIT(inst, 20, 4))
{
case 0b0000: case 0b0001: case 0b0010: case 0b0011: case 0b0100: // ANDB, ANDBC, ORB, ORBC, XORB (with Boolean Option)
- util::stream_format(stream, "%-8sb%d, b%d, b%d", s_rst2_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-8sb%d, b%d, b%d", m_helper.s_rst2_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
case 0b1000: case 0b1010: case 0b1011: // MULL, MULUH, MULSH (with 32-bit Integer Multiply Option)
case 0b1100: case 0b1101: case 0b1110: case 0b1111: // QUOU, QUOS, REMU, REMS (with 32-bit Integer Divide Option)
- util::stream_format(stream, "%-8sa%d, a%d, a%d", s_rst2_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-8sa%d, a%d, a%d", m_helper.s_rst2_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
default:
@@ -649,24 +436,24 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
switch (BIT(inst, 20, 4))
{
case 0b0000: case 0b0001: // RSR, WSR
- util::stream_format(stream, "%s.%-3d a%d", s_rst3_ops[BIT(inst, 20, 4)], special_reg(BIT(inst, 8, 8), BIT(inst, 20)), BIT(inst, 4, 4));
+ util::stream_format(stream, "%s.%-3d a%d", m_helper.s_rst3_ops[BIT(inst, 20, 4)], m_helper.special_reg(BIT(inst, 8, 8), BIT(inst, 20)), BIT(inst, 4, 4));
break;
case 0b0010: case 0b0011: // SEXT, CLAMPS (with Miscellaneous Operations Option)
- util::stream_format(stream, "%-8sa%d, a%d, %d", s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4) + 7);
+ util::stream_format(stream, "%-8sa%d, a%d, %d", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4) + 7);
break;
case 0b0100: case 0b0101: case 0b0110: case 0b0111: // MIN, MAX, MINU, MAXU (with Miscellaneous Operations Option)
case 0b1000: case 0b1001: case 0b1010: case 0b1011: // MOVEQZ, MOVNEZ, MOVLTZ, MOVGEZ
- util::stream_format(stream, "%-8sa%d, a%d, a%d", s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-8sa%d, a%d, a%d", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
case 0b1100: case 0b1101: // MOVF, MOVT (with Boolean Option)
- util::stream_format(stream, "%-8sa%d, a%d, b%d", s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-8sa%d, a%d, b%d", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
case 0b1110: case 0b1111: // RUR, WUR (TODO: TIE user_register names)
- util::stream_format(stream, "%s.u%-2d a%d", s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 4, 8), BIT(inst, 12, 4));
+ util::stream_format(stream, "%s.u%-2d a%d", m_helper.s_rst3_ops[BIT(inst, 20, 4)], BIT(inst, 4, 8), BIT(inst, 12, 4));
break;
}
break;
@@ -708,13 +495,11 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
switch (BIT(inst, 20, 4))
{
case 0b0000: // L32E
- util::stream_format(stream, "%-8sa%d, a%d, ", "l32e", BIT(inst, 4, 4), BIT(inst, 8, 4));
- format_imm(stream, int(BIT(inst, 12, 4)) * 4 - 64);
+ util::stream_format(stream, "%-8sa%d, a%d, %s", "l32e", BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm(int(BIT(inst, 12, 4)) * 4 - 64));
break;
case 0b0100: // S32E
- util::stream_format(stream, "%-8sa%d, a%d, ", "s32e", BIT(inst, 4, 4), BIT(inst, 8, 4));
- format_imm(stream, int(BIT(inst, 12, 4)) * 4 - 64);
+ util::stream_format(stream, "%-8sa%d, a%d, %s", "s32e", BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm(int(BIT(inst, 12, 4)) * 4 - 64));
break;
default:
@@ -727,15 +512,15 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
switch (BIT(inst, 20, 4))
{
case 0b0000: case 0b0001: case 0b0010: case 0b0100: case 0b0101: // ADD.S, SUB.S, MUL.S, MADD.S, MSUB.S
- util::stream_format(stream, "%-8sf%d, f%d, f%d", s_fp0_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-8sf%d, f%d, f%d", m_helper.s_fp0_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
case 0b1000: case 0b1001: case 0b1010: case 0b1011: case 0b1110: // ROUND.S, TRUNC.S, FLOOR.S, CEIL.S, UTRUNC.S
- util::stream_format(stream, "%-7s a%d, f%d, %d", s_fp0_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-7s a%d, f%d, %d", m_helper.s_fp0_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
case 0b1100: case 0b1101: // FLOAT.S, UFLOAT.S
- util::stream_format(stream, "%-7s f%d, a%d, %d", s_fp0_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-7s f%d, a%d, %d", m_helper.s_fp0_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
case 0b1111: // FP1OP
@@ -777,15 +562,15 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
switch (BIT(inst, 20, 4))
{
case 0b0001: case 0b0010: case 0b0011: case 0b0100: case 0b0101: case 0b0110: case 0b0111: // UN.S, OEQ.S, UEQ.S, OLT.S, ULT.S, OLE.S, ULE.S
- util::stream_format(stream, "%-8sb%d, f%d, f%d", s_fp1_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-8sb%d, f%d, f%d", m_helper.s_fp1_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
case 0b1000: case 0b1001: case 0b1010: case 0b1011: // MOVEQZ.S, MOVNEZ.S, MOVLTZ.S, MOVGEZ.S
- util::stream_format(stream, "%-8sf%d, f%d, a%d", s_fp1_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-8sf%d, f%d, a%d", m_helper.s_fp1_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
case 0b1100: case 0b1101: // MOVF.S, MOVT.S
- util::stream_format(stream, "%-8sf%d, f%d, b%d", s_fp1_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%-8sf%d, f%d, b%d", m_helper.s_fp1_ops[BIT(inst, 20, 4)], BIT(inst, 12, 4), BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
default:
@@ -808,20 +593,17 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
switch (BIT(inst, 12, 4))
{
case 0b0000: case 0b0100: // L8UI, S8I
- util::stream_format(stream, "%-8sa%d, a%d, ", s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
- format_imm(stream, inst >> 16);
+ util::stream_format(stream, "%-8sa%d, a%d, %s", m_helper.s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm(inst >> 16));
break;
case 0b0001: case 0b0101: case 0b1001: // L16UI, S16I, L16SI
- util::stream_format(stream, "%-8sa%d, a%d, ", s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
- format_imm(stream, (inst >> 16) * 2);
+ util::stream_format(stream, "%-8sa%d, a%d, %s", m_helper.s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm((inst >> 16) * 2));
break;
case 0b0010: case 0b0110: // L32I, S32I
case 0b1011: case 0b1111: // L32AI, S32RI (with Multiprocessor Synchronization Option)
case 0b1110: // S32C1I (with Conditional Store Option)
- util::stream_format(stream, "%-8sa%d, a%d, ", s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4));
- format_imm(stream, (inst >> 16) * 4);
+ util::stream_format(stream, "%-8sa%d, a%d, %s", m_helper.s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm((inst >> 16) * 4));
break;
case 0b0111: // CACHE
@@ -830,36 +612,30 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
case 0b0000: case 0b0001: case 0b0010: case 0b0011: // DPFR, DPFW, DPFRO, DPFWO (with Data Cache Option)
case 0b0100: case 0b0101: case 0b0110: case 0b0111: // DHWB, DHWBI, DHI, DII (with Data Cache Option)
case 0b1100: case 0b1110: case 0b1111: // IPF, IHI, III (with Instruction Cache Option)
- util::stream_format(stream, "%-8sa%d, ", s_cache_ops[BIT(inst, 4, 4)], BIT(inst, 8, 4));
- format_imm(stream, (inst >> 16) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", m_helper.s_cache_ops[BIT(inst, 4, 4)], BIT(inst, 8, 4), m_helper.format_imm((inst >> 16) * 4));
break;
case 0b1000: // DCE (with Data Cache Option)
switch (BIT(inst, 16, 4))
{
case 0b0000: // DPFL (with Data Cache Index Lock Option)
- util::stream_format(stream, "%-8sa%d, ", "dpfl", BIT(inst, 8, 4));
- format_imm(stream, (inst >> 20) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", "dpfl", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
break;
case 0b0010: // DHU (with Data Cache Index Lock Option)
- util::stream_format(stream, "%-8sa%d, ", "dhu", BIT(inst, 8, 4));
- format_imm(stream, (inst >> 20) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", "dhu", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
break;
case 0b0011: // DIU (with Data Cache Index Lock Option)
- util::stream_format(stream, "%-8sa%d, ", "diu", BIT(inst, 8, 4));
- format_imm(stream, (inst >> 20) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", "diu", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
break;
case 0b0100: // DIWB (added in T1050)
- util::stream_format(stream, "%-8sa%d, ", "diwb", BIT(inst, 8, 4));
- format_imm(stream, (inst >> 20) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", "diwb", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
break;
case 0b0101: // DIWBI (added in T1050)
- util::stream_format(stream, "%-8sa%d, ", "diwbi", BIT(inst, 8, 4));
- format_imm(stream, (inst >> 20) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", "diwbi", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
break;
}
break;
@@ -868,18 +644,15 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
switch (BIT(inst, 16, 4))
{
case 0b0000: // IPFL
- util::stream_format(stream, "%-8sa%d, ", "ipfl", BIT(inst, 8, 4));
- format_imm(stream, (inst >> 20) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", "ipfl", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
break;
case 0b0010: // IHU
- util::stream_format(stream, "%-8sa%d, ", "ihu", BIT(inst, 8, 4));
- format_imm(stream, (inst >> 20) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", "ihu", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
break;
case 0b0011: // IIU
- util::stream_format(stream, "%-8sa%d, ", "iiu", BIT(inst, 8, 4));
- format_imm(stream, (inst >> 20) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", "iiu", BIT(inst, 8, 4), m_helper.format_imm((inst >> 20) * 4));
break;
default:
@@ -895,13 +668,11 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
break;
case 0b1010: // MOVI
- util::stream_format(stream, "%-8sa%d, ", "movi", BIT(inst, 4, 4));
- format_imm(stream, util::sext((inst & 0x000f00) + (inst >> 16), 12));
+ util::stream_format(stream, "%-8sa%d, %s", "movi", BIT(inst, 4, 4), m_helper.format_imm(util::sext((inst & 0x000f00) + (inst >> 16), 12)));
break;
case 0b1100: case 0b1101: // ADDI, ADDMI
- util::stream_format(stream, "%-8sa%d, a%d, ", s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 8, 4), BIT(inst, 4, 4));
- format_imm(stream, s8(u8(inst >> 16)) * (BIT(inst, 12) ? 256 : 1));
+ util::stream_format(stream, "%-8sa%d, a%d, %s", m_helper.s_lsai_ops[BIT(inst, 12, 4)], BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm(s8(u8(inst >> 16)) * (BIT(inst, 12) ? 256 : 1)));
break;
default:
@@ -914,8 +685,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
if (BIT(inst, 12, 2) == 0)
{
// LSI, SSI, LSIU, SSIU
- util::stream_format(stream, "%-8sf%d, a%d, ", s_lsci_ops[BIT(inst, 14, 2)], BIT(inst, 4, 4), BIT(inst, 8, 4));
- format_imm(stream, BIT(inst, 16, 8) * 4);
+ util::stream_format(stream, "%-8sf%d, a%d, %s", m_helper.s_lsci_ops[BIT(inst, 14, 2)], BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm(BIT(inst, 16, 8) * 4));
return 3 | SUPPORTED;
}
else
@@ -929,8 +699,8 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
{
case 0b0000: case 0b0001: // MACID, MACCD
if (BIT(inst, 18, 2) == 0b10)
- util::stream_format(stream, "%s.dd.%s.%s m%d, a%d, m%d, m%d", s_mac16_ops[BIT(inst, 18, 2)],
- s_mac16_half[BIT(inst, 16, 2)],
+ util::stream_format(stream, "%s.dd.%s.%s m%d, a%d, m%d, m%d", m_helper.s_mac16_ops[BIT(inst, 18, 2)],
+ m_helper.s_mac16_half[BIT(inst, 16, 2)],
BIT(inst, 20) ? "lddec" : "ldinc",
BIT(inst, 12, 2), BIT(inst, 8, 4),
BIT(inst, 14), BIT(inst, 6) + 2);
@@ -943,8 +713,8 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
case 0b0100: case 0b0101: // MACIA, MACCA
if (BIT(inst, 18, 2) == 0b10)
- util::stream_format(stream, "%s.da.%s.%s m%d, a%d, m%d, a%d", s_mac16_ops[BIT(inst, 18, 2)],
- s_mac16_half[BIT(inst, 16, 2)],
+ util::stream_format(stream, "%s.da.%s.%s m%d, a%d, m%d, a%d", m_helper.s_mac16_ops[BIT(inst, 18, 2)],
+ m_helper.s_mac16_half[BIT(inst, 16, 2)],
BIT(inst, 20) ? "lddec" : "ldinc",
BIT(inst, 12, 2), BIT(inst, 8, 4),
BIT(inst, 14), BIT(inst, 4, 4));
@@ -957,7 +727,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
case 0b0010: // MACDD
if (BIT(inst, 18, 2) != 0b00)
- util::stream_format(stream, "%s.dd.%s m%d, m%d", s_mac16_ops[BIT(inst, 18, 2)], s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 14), BIT(inst, 6) + 2);
+ util::stream_format(stream, "%s.dd.%s m%d, m%d", m_helper.s_mac16_ops[BIT(inst, 18, 2)], m_helper.s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 14), BIT(inst, 6) + 2);
else
{
util::stream_format(stream, "%-8s0x%02X ; reserved", "db", inst & 0xff);
@@ -967,7 +737,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
case 0b0011: // MACAD
if (BIT(inst, 18, 2) != 0b00)
- util::stream_format(stream, "%s.ad.%s a%d, m%d", s_mac16_ops[BIT(inst, 18, 2)], s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 8, 4), BIT(inst, 6) + 2);
+ util::stream_format(stream, "%s.ad.%s a%d, m%d", m_helper.s_mac16_ops[BIT(inst, 18, 2)], m_helper.s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 8, 4), BIT(inst, 6) + 2);
else
{
util::stream_format(stream, "%-8s0x%02X ; reserved", "db", inst & 0xff);
@@ -977,7 +747,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
case 0b0110: // MACDA
if (BIT(inst, 18, 2) != 0b00)
- util::stream_format(stream, "%s.da.%s m%d, a%d", s_mac16_ops[BIT(inst, 18, 2)], s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 14), BIT(inst, 4, 4));
+ util::stream_format(stream, "%s.da.%s m%d, a%d", m_helper.s_mac16_ops[BIT(inst, 18, 2)], m_helper.s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 14), BIT(inst, 4, 4));
else
{
util::stream_format(stream, "%-8s0x%02X ; reserved", "db", inst & 0xff);
@@ -986,7 +756,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
break;
case 0b0111: // MACAA
- util::stream_format(stream, "%s.aa.%s a%d, a%d", s_mac16_ops[BIT(inst, 18, 2)], s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 8, 4), BIT(inst, 4, 4));
+ util::stream_format(stream, "%s.aa.%s a%d, a%d", m_helper.s_mac16_ops[BIT(inst, 18, 2)], m_helper.s_mac16_half[BIT(inst, 16, 2)], BIT(inst, 8, 4), BIT(inst, 4, 4));
break;
case 0b1000: case 0b1001: // MACI, MACC
@@ -1026,21 +796,18 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
break;
case 0b01: // BZ
- util::stream_format(stream, "%-8sa%d, 0x%08X", s_bz_ops[BIT(inst, 6, 2)], BIT(inst, 8, 4), pc + 4 + util::sext(inst >> 12, 12));
+ util::stream_format(stream, "%-8sa%d, 0x%08X", m_helper.s_bz_ops[BIT(inst, 6, 2)], BIT(inst, 8, 4), pc + 4 + util::sext(inst >> 12, 12));
return 3 | STEP_COND | SUPPORTED;
case 0b10: // BI0
- util::stream_format(stream, "%-8sa%d, ", s_bi0_ops[BIT(inst, 6, 2)], BIT(inst, 8, 4));
- format_imm(stream, s_b4const[BIT(inst, 12, 4)]);
- util::stream_format(stream, ", 0x%08X", pc + 4 + s8(u8(inst >> 16)));
+ util::stream_format(stream, "%-8sa%d, %s, 0x%08X", m_helper.s_bi0_ops[BIT(inst, 6, 2)], BIT(inst, 8, 4), m_helper.format_imm(m_helper.s_b4const[BIT(inst, 12, 4)]), pc + 4 + s8(u8(inst >> 16)));
return 3 | STEP_COND | SUPPORTED;
case 0b11: // BI1
switch (BIT(inst, 6, 2))
{
case 0b00: // ENTRY
- util::stream_format(stream, "%-8sa%d, ", "entry", BIT(inst, 8, 4));
- format_imm(stream, (inst >> 12) * 4);
+ util::stream_format(stream, "%-8sa%d, %s", "entry", BIT(inst, 8, 4), m_helper.format_imm((inst >> 12) * 4));
break;
case 0b01: // B1
@@ -1069,9 +836,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
break;
case 0b10: case 0b11: // BLTUI, BGEUI
- util::stream_format(stream, "%-8sa%d, ", BIT(inst, 6) ? "bgeui" : "bltui", BIT(inst, 8, 4));
- format_imm(stream, s_b4constu[BIT(inst, 4, 4)]);
- util::stream_format(stream, ", 0x%08X", pc + 4 + s8(u8(inst >> 16)));
+ util::stream_format(stream, "%-8sa%d, %s, 0x%08X", BIT(inst, 6) ? "bgeui" : "bltui", BIT(inst, 8, 4), m_helper.format_imm(m_helper.s_b4constu[BIT(inst, 12, 4)]), pc + 4 + s8(u8(inst >> 16)));
return 3 | STEP_COND | SUPPORTED;
}
break;
@@ -1079,21 +844,20 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
return 3 | SUPPORTED;
case 0b0111: // B
- if (BIT(inst, 9, 2) == 0b11)
+ if (BIT(inst, 13, 2) == 0b11)
{
// BBCI, BBSI
- util::stream_format(stream, "%-8sa%d, %d, 0x%08X", BIT(inst, 11) ? "bbsi" : "bbci", BIT(inst, 8, 4), BIT(inst, 4, 4) + (BIT(inst, 12) ? 4 : 0), pc + 4 + s8(u8(inst >> 16)));
+ util::stream_format(stream, "%-8sa%d, %d, 0x%08X", BIT(inst, 15) ? "bbsi" : "bbci", BIT(inst, 8, 4), BIT(inst, 4, 4) + (BIT(inst, 12) ? 16 : 0), pc + 4 + s8(u8(inst >> 16)));
}
else
{
// BNONE, BEQ, BLT, BLTU, BALL, BBC, BBCI, BANY, BNE, BGE, BGEU, BNALL, BBS
- util::stream_format(stream, "%-8sa%d, a%d, 0x%08X", s_b_ops[BIT(inst, 12, 4)], BIT(inst, 8, 4), BIT(inst, 4, 4), pc + 4 + s8(u8(inst >> 16)));
+ util::stream_format(stream, "%-8sa%d, a%d, 0x%08X", m_helper.s_b_ops[BIT(inst, 12, 4)], BIT(inst, 8, 4), BIT(inst, 4, 4), pc + 4 + s8(u8(inst >> 16)));
}
return 3 | STEP_COND | SUPPORTED;
case 0b1000: case 0b1001: // L32I.N (with Code Density Option)
- util::stream_format(stream, "%-8sa%d, a%d, ", BIT(inst, 0) ? "s32i.n" : "l32i.n", BIT(inst, 4, 4), BIT(inst, 8, 4));
- format_imm(stream, BIT(inst, 12, 4) * 4);
+ util::stream_format(stream, "%-8sa%d, a%d, %s", BIT(inst, 0) ? "s32i.n" : "l32i.n", BIT(inst, 4, 4), BIT(inst, 8, 4), m_helper.format_imm(BIT(inst, 12, 4) * 4));
return 2 | SUPPORTED;
case 0b1010: // ADD.N (with Code Density Option)
@@ -1108,8 +872,7 @@ offs_t xtensa_disassembler::disassemble(std::ostream &stream, offs_t pc, const x
if (!BIT(inst, 7))
{
// 7-bit immediate field uses asymmetric sign extension (range is -32..95)
- util::stream_format(stream, "%-8sa%d, ", "movi.n", BIT(inst, 8, 4));
- format_imm(stream, int((inst & 0x0070) + BIT(inst, 12, 4) - (BIT(inst, 5, 2) == 0b11 ? 128 : 0)));
+ util::stream_format(stream, "%-8sa%d, %s", "movi.n", BIT(inst, 8, 4), m_helper.format_imm(int((inst & 0x0070) + BIT(inst, 12, 4) - (BIT(inst, 5, 2) == 0b11 ? 128 : 0))));
return 2 | SUPPORTED;
}
else
diff --git a/src/devices/cpu/xtensa/xtensad.h b/src/devices/cpu/xtensa/xtensad.h
index 2ad919c6e92..e2551208e97 100644
--- a/src/devices/cpu/xtensa/xtensad.h
+++ b/src/devices/cpu/xtensa/xtensad.h
@@ -6,6 +6,8 @@
#pragma once
+#include "xtensa_helper.h"
+
class xtensa_disassembler : public util::disasm_interface
{
public:
@@ -18,10 +20,7 @@ protected:
virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
private:
- // formatting helpers
- static void format_imm(std::ostream &stream, u32 imm);
-
- static std::string special_reg(u8 n, bool wsr);
+ xtensa_helper m_helper;
};
#endif // MAME_CPU_XTENSA_XTENSAD_H
diff --git a/src/mame/skeleton/hudson_poems.cpp b/src/mame/skeleton/hudson_poems.cpp
index c5990858267..68d46624917 100644
--- a/src/mame/skeleton/hudson_poems.cpp
+++ b/src/mame/skeleton/hudson_poems.cpp
@@ -23,15 +23,27 @@
2005/11/17 絶体絶命でんぢゃらすじーさん パーティーじゃっ!全員集合!! (Mini-Game Collection)
2005/11/24 ぐ〜チョコランタン スプーだいすき!プレイマット (Kid's Floor Mat)
+ -------------
+
+ Marimba Tengoku has a secret test menu, see notes near input port definition.
+ The ROM check code for that menu is at 0x661010 in ROM and does a full 32-bit word sum
+ of the ROM, comparing it against the value stored in the last 4 bytes (it passes)
+
*/
#include "emu.h"
#include "cpu/xtensa/xtensa.h"
+#include "machine/timer.h"
+#include "emupal.h"
#include "screen.h"
#include "speaker.h"
+#define LOG_SPRITEBASE (1U << 1)
+
+#define VERBOSE (0)
+#include "logmacro.h"
namespace {
@@ -40,65 +52,665 @@ class hudson_poems_state : public driver_device
public:
hudson_poems_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
- m_maincpu(*this, "maincpu")
+ m_maincpu(*this, "maincpu"),
+ m_palette(*this, "palette"),
+ m_screen(*this, "screen"),
+ m_gfxdecode(*this, "gfxdecode"),
+ m_mainram(*this, "mainram"),
+ m_palram(*this, "palram")
{ }
void hudson_poems(machine_config &config);
+ void init_marimba();
+
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
private:
- uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+ u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ void draw_tile(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 tile, int xx, int yy, int gfxbase, int extrapal);
+ void draw_tile8(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 tile, int xx, int yy, int gfxbase, int extrapal);
+ void draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+ void draw_tilemap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int which, int priority);
+
+ u32 poems_random_r();
+ void unk_trigger_w(offs_t offset, u32 data, u32 mem_mask);
+
+ TIMER_DEVICE_CALLBACK_MEMBER(screen_scanline);
+
+ template<int Which> void tilemap_map(address_map &map, u32 base);
void mem_map(address_map &map);
- required_device<cpu_device> m_maincpu;
+ u32 poems_8020010_r();
+ u32 poems_count_r();
+ u32 poems_unk_r();
+ u32 poems_8000038_r(offs_t offset, u32 mem_mask);
+ u32 poems_8000200_r(offs_t offset, u32 mem_mask);
+ u32 unk_aa04_r(offs_t offset, u32 mem_mask);
+ void unk_aa00_w(offs_t offset, u32 data, u32 mem_mask);
+
+ void fade_w(offs_t offset, u32 data, u32 mem_mask);
+ void unktable_w(offs_t offset, u32 data, u32 mem_mask);
+ void unktable_reset_w(offs_t offset, u32 data, u32 mem_mask);
+ void set_palette_val(int entry);
+ void palette_w(offs_t offset, u32 data, u32 mem_mask);
+ void mainram_w(offs_t offset, u32 data, u32 mem_mask);
+
+ void spritegfx_base_w(offs_t offset, u32 data, u32 mem_mask);
+ void spritelist_base_w(offs_t offset, u32 data, u32 mem_mask);
+
+ template<int Layer> void tilemap_base_w(offs_t offset, u32 data, u32 mem_mask);
+ template<int Layer> void tilemap_unk_w(offs_t offset, u32 data, u32 mem_mask);
+ template<int Layer> void tilemap_cfg_w(offs_t offset, u32 data, u32 mem_mask);
+ template<int Layer> void tilemap_scr_w(offs_t offset, u32 data, u32 mem_mask);
+ template<int Layer> void tilemap_high_w(offs_t offset, u32 data, u32 mem_mask);
+
+ template<int Layer> u32 tilemap_base_r(offs_t offset, u32 mem_mask);
+ template<int Layer> u32 tilemap_high_r(offs_t offset, u32 mem_mask);
+ template<int Layer> u32 tilemap_unk_r(offs_t offset, u32 mem_mask);
+ template<int Layer> u32 tilemap_cfg_r(offs_t offset, u32 mem_mask);
+ template<int Layer> u32 tilemap_scr_r(offs_t offset, u32 mem_mask);
+
+ u16 m_unktable[256];
+ u16 m_unktableoffset;
+
+ u32 m_spritegfxbase[4];
+ u32 m_spritelistbase;
+ u32 m_tilemapbase[4];
+ u32 m_tilemapunk[4];
+ u32 m_tilemapcfg[4];
+ u32 m_tilemapscr[4];
+ u32 m_tilemaphigh[4];
+
+ s32 m_hackcounter;
+
+ required_device<xtensa_device> m_maincpu;
+ required_device<palette_device> m_palette;
+ required_device<screen_device> m_screen;
+ required_device<gfxdecode_device> m_gfxdecode;
+ required_shared_ptr<u32> m_mainram;
+ required_shared_ptr<u32> m_palram;
};
void hudson_poems_state::machine_start()
{
+ save_item(NAME(m_unktable));
+ save_item(NAME(m_unktableoffset));
+
+ save_item(NAME(m_spritegfxbase));
+ save_item(NAME(m_spritelistbase));
+
+ save_item(NAME(m_tilemapbase));
+ save_item(NAME(m_tilemapunk));
+ save_item(NAME(m_tilemapcfg));
+ save_item(NAME(m_tilemapscr));
+ save_item(NAME(m_tilemaphigh));
+
+ save_item(NAME(m_hackcounter));
}
+
+
void hudson_poems_state::machine_reset()
{
- m_maincpu->set_pc(0x20010058);
+ m_unktableoffset = 0;
+ m_hackcounter = 0;
+
+ for (int i = 0; i < 4; i++)
+ {
+ m_spritegfxbase[i] = m_tilemapbase[i] = m_tilemaphigh[i] = m_tilemapunk[i] = m_tilemapcfg[i] = m_tilemapscr[i] = 0;
+ }
}
+/*
+You can unlock the test menu on boot by inputing a 3 step sequence while the Konami logo is being shown:
+Step 1 checks if you input white or yellow 2 times
+Step 2 checks if you input red or blue 2 times
+Step 3 checks if you input white or green 3 times
+
+These are not grouped inputs, so for step 1 you must input white x2 or yellow x2 instead of white x1 and yellow x1 for it to count.
+
+*/
+
static INPUT_PORTS_START( hudson_poems )
+ PORT_START( "IN1" )
+ PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("White")
+ PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("Yellow (Select Up)")
+ PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("Red (Ok)")
+ PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("Blue (Select Down)")
+ PORT_BIT( 0x00000200, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("Green")
INPUT_PORTS_END
+void hudson_poems_state::draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ int spritebase = (m_spritelistbase & 0x0003ffff) / 4;
+ gfx_element *gfx = m_gfxdecode->gfx(2);
+
+ for (int i = 0; i < 64; i++)
+ {
+ const u16 spriteword0 = m_mainram[(spritebase + i * 2) + 0] & 0xffff;
+ const u16 spriteword1 = m_mainram[(spritebase + i * 2) + 0] >> 16;
+ const u16 spriteword2 = m_mainram[(spritebase + i * 2) + 1] & 0xffff;
+ const u16 spriteword3 = m_mainram[(spritebase + i * 2) + 1] >> 16;
+
+ const int x = (spriteword3 & 0x03ff);
+ const int y = (spriteword2 & 0x03ff);
+ int tilenum = spriteword1 & 0x03ff;
+ const int pal = (spriteword2 & 0x7c00)>>10;
+
+ // is it selecting from multiple tile pages (which can have different bases?) (probably from a register somewhere)
+ const int tilebase = (m_spritegfxbase[(spriteword0 & 0x0300)>>8] & 0x0003ffff) / 32; // m_spritegfxbase contains a full memory address pointer to RAM
+
+ tilenum += tilebase;
+
+ /* based on code analysis of function at 006707A4
+ word0 ( 0abb bbBB ---- -dFf ) OR ( 1abb bbcc dddd dddd ) a = ? b = alpha blend? (toggles between all bits on and off for battery logo) BB = sprite base F = flipX f = flipY
+ word1 ( wwhh ---t tttt tttt ) - other bits are used, but pulled from ram? t = tile number? ww = width hh = height
+ word2 ( 0Ppp ppyy yyyy yyyy ) P = palette bank p = palette y = ypos
+ word3 ( aabb bbxx xxxx xxxx ) x = xpos
+ */
+
+ const int alpha = (spriteword0 & 0x3c00)>>10;
+ const int flipx = spriteword0 & 2;
+ const int flipy = spriteword0 & 1;
+ int height = (spriteword1 & 0x3000)>>12;
+ height = 1 << height;
+ int width = (spriteword1 & 0xc000)>>14;
+ width = 1 << width;
+
+ if (alpha == 0x00)
+ continue;
+
+
+ if (spriteword0 & 0x8000)
+ {
+ // unsure for now
+ }
+ else
+ {
+ const int basetilenum = tilenum;
+ for (int xx = 0; xx < width; xx++)
+ {
+ int xpos, ypos;
+
+ if (!flipx)
+ xpos = x + xx * 8;
+ else
+ xpos = x + (((width-1) * 8) - xx * 8);
+
+ for (int yy = 0; yy < height; yy++)
+ {
+ if (!flipy)
+ ypos = y + yy * 8;
+ else
+ ypos = y + (((height-1) * 8) - yy * 8);
+
+ if (alpha == 0xf)
+ gfx->transpen(bitmap, cliprect, basetilenum + xx + (yy * 0x20), pal, flipx, flipy, xpos, ypos, 0);
+ else
+ gfx->alpha(bitmap, cliprect, basetilenum + xx + (yy * 0x20), pal, flipx, flipy, xpos, ypos, 0, 0xff-(alpha<<4));
+
+ }
+ }
+ }
+ }
+
+ /*
+ popmessage("%08x %08x\n%08x %08x\n%08x %08x\n%08x %08x\n", m_mainram[spritebase + 0], m_mainram[spritebase + 1],
+ m_mainram[spritebase + 2], m_mainram[spritebase + 3],
+ m_mainram[spritebase + 4], m_mainram[spritebase + 5],
+ m_mainram[spritebase + 6], m_mainram[spritebase + 7]);
+ */
+}
-uint32_t hudson_poems_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+void hudson_poems_state::draw_tilemap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int which, int priority)
{
+ int width, base, bpp, gfxbase, extrapal;
+
+ // guess, could be more/less bits, or somewhere else entirely, works for the 2 scenes that need it
+ const int thispriority = (m_tilemapcfg[which] & 0x01f00000) >> 20;
+
+ if (thispriority != priority)
+ return;
+
+ // seems to get set for disabled layers
+ if (m_tilemapcfg[which] & 0x02000000)
+ return;
+
+ extrapal = 0;
+
+ if (m_tilemapunk[which] == 2)
+ width = 512;
+ else
+ width = 256;
+
+ if (m_tilemapcfg[which] & 0x20000000)
+ bpp = 8;
+ else
+ bpp = 4;
+
+ if (m_tilemapcfg[which] & 0x00080000)
+ extrapal = 1;
+ else
+ extrapal = 0;
+
+ // contains a full 32-bit address
+ base = (m_tilemapbase[which] & 0x0003ffff) / 4;
+
+ // contains a full 32-bit address. for this to work in the test mode the interrupts must be disabled as soon as test mode is entered, otherwise the pointer
+ // gets overwritten with an incorrect one. Test mode does not require interrupts to function, although the bit we use to disable them is likely incorrect.
+ // this does NOT really seem to be tied to tilemap number, probably from a config reg
+ // this reg?
+ const int whichbase = (m_tilemapcfg[which] & 0x00000060) >> 5;
+ gfxbase = (m_spritegfxbase[whichbase] & 0x0003ffff);
+
+ int yscroll = (m_tilemapscr[which] >> 16) & 0x7ff;
+ if (yscroll & 0x400)
+ yscroll -= 0x800;
+
+ int xscroll = (m_tilemapscr[which] >> 0) & 0x7ff;
+ if (xscroll & 0x400)
+ xscroll -= 0x800;
+
+ const int tilemap_drawheight = ((m_tilemaphigh[which] >> 16) & 0xff);
+ int tilemap_drawwidth = ((m_tilemaphigh[which] >> 0) & 0x1ff);
+
+ // clamp to size of tilemap (test mode has 256 wide tilemap in RAM, but sets full 320 width?)
+ if (tilemap_drawwidth > width)
+ tilemap_drawwidth = width;
+
+ // note m_tilemaphigh seems to be in pixels, we currently treat it as tiles
+ // these could actually be 'end pos' regs, with unknown start regs currently always set to 0
+
+ for (int y = 0; y < tilemap_drawheight / 8; y++)
+ {
+ const int ypos = (y * 8 + yscroll) & 0x1ff;
+
+ for (int x = 0; x < tilemap_drawwidth / 8 / 2; x++)
+ {
+ u32 tiles = m_mainram[base + (y * width / 8 / 2) + x];
+ const int xpos = (x * 16 + xscroll) & 0x1ff;
+
+ if (bpp == 4)
+ {
+ draw_tile(screen, bitmap, cliprect, (tiles & 0xffff), xpos, ypos, gfxbase, extrapal);
+ draw_tile(screen, bitmap, cliprect, ((tiles >> 16) & 0xffff), xpos + 8, ypos, gfxbase, extrapal);
+ }
+ else if (bpp == 8)
+ {
+ draw_tile8(screen, bitmap, cliprect, (tiles & 0xffff), xpos, ypos, gfxbase, extrapal);
+ draw_tile8(screen, bitmap, cliprect, ((tiles >> 16) & 0xffff), xpos + 8, ypos, gfxbase, extrapal);
+ }
+ }
+ }
+}
+
+
+
+void hudson_poems_state::spritegfx_base_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_spritegfxbase[offset]);
+ LOGMASKED(LOG_SPRITEBASE, "%s: spritegfx_base_w %d %08x\n", machine().describe_context(), offset, data);
+}
+
+void hudson_poems_state::spritelist_base_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_spritelistbase);
+}
+
+template<int Layer> void hudson_poems_state::tilemap_base_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_tilemapbase[Layer]); }
+template<int Layer> void hudson_poems_state::tilemap_cfg_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_tilemapcfg[Layer]); }
+template<int Layer> void hudson_poems_state::tilemap_unk_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_tilemapunk[Layer]); }
+template<int Layer> void hudson_poems_state::tilemap_high_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_tilemaphigh[Layer]); }
+template<int Layer> void hudson_poems_state::tilemap_scr_w(offs_t offset, u32 data, u32 mem_mask) { COMBINE_DATA(&m_tilemapscr[Layer]); }
+
+template<int Layer> u32 hudson_poems_state::tilemap_base_r(offs_t offset, u32 mem_mask) { return m_tilemapbase[Layer]; }
+template<int Layer> u32 hudson_poems_state::tilemap_high_r(offs_t offset, u32 mem_mask) { return m_tilemaphigh[Layer]; }
+template<int Layer> u32 hudson_poems_state::tilemap_unk_r(offs_t offset, u32 mem_mask) { return m_tilemapunk[Layer]; }
+template<int Layer> u32 hudson_poems_state::tilemap_cfg_r(offs_t offset, u32 mem_mask) { return m_tilemapcfg[Layer]; }
+template<int Layer> u32 hudson_poems_state::tilemap_scr_r(offs_t offset, u32 mem_mask) { return m_tilemapscr[Layer]; }
+
+
+void hudson_poems_state::draw_tile(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 tile, int xx, int yy, int gfxbase, int extrapal)
+{
+ gfx_element *gfx = m_gfxdecode->gfx(2);
+ const int flipx = tile & 0x0800;
+ const int flipy = tile & 0x0400;
+ int pal = (tile & 0xf000)>>12;
+ pal += extrapal * 0x10;
+ tile &= 0x3ff;
+ tile += gfxbase / 32;
+ gfx->transpen(bitmap,cliprect,tile,pal,flipx,flipy,xx,yy, 0);
+}
+
+void hudson_poems_state::draw_tile8(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 tile, int xx, int yy, int gfxbase, int extrapal)
+{
+ gfx_element *gfx = m_gfxdecode->gfx(3);
+ const int flipx = tile & 0x0800;
+ const int flipy = tile & 0x0400;
+ int pal = 0;//(tile & 0xf000)>>8;
+ pal += extrapal;
+ tile &= 0x3ff;
+ tile += gfxbase / 64;
+ gfx->transpen(bitmap,cliprect,tile,pal,flipx,flipy,xx,yy, 0);
+}
+
+u32 hudson_poems_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(0, cliprect);
+
+ for (int pri = 0x1f; pri >= 0; pri--)
+ {
+ draw_tilemap(screen, bitmap, cliprect, 0, pri);
+ draw_tilemap(screen, bitmap, cliprect, 1, pri); // title screen background
+ draw_tilemap(screen, bitmap, cliprect, 2, pri); // seems to be status bar in the game demo, but suggests that tilegfx base isn't tied to tilmap number
+ draw_tilemap(screen, bitmap, cliprect, 3, pri); // background for the character in game demo etc.
+ }
+
+ draw_sprites(screen, bitmap, cliprect);
+
return 0;
}
+u32 hudson_poems_state::poems_unk_r()
+{
+ return 0x00000000;
+}
+
+u32 hudson_poems_state::poems_random_r()
+{
+ return machine().rand();
+}
+
+
+u32 hudson_poems_state::poems_count_r()
+{
+ return ((m_hackcounter++) & 0x3) ? 0xffffffff : 0;
+}
+
+u32 hudson_poems_state::poems_8020010_r()
+{
+ return 0x4;
+}
+
+u32 hudson_poems_state::unk_aa04_r(offs_t offset, u32 mem_mask)
+{
+ return ((m_hackcounter++) & 0x3) ? 0xffffffff : 0;
+}
+
+void hudson_poems_state::unk_aa00_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ logerror("%s: unk_aa00_w %08x %08x\n", machine().describe_context(), data, mem_mask);
+}
+
+u32 hudson_poems_state::poems_8000038_r(offs_t offset, u32 mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ if (m_maincpu->pc() != 0x2c000b5a)
+ logerror("%s: poems_8000038_r %08x\n", machine().describe_context(), mem_mask);
+
+ if (m_mainram[0x1baf8/4] == 0x00000000)
+ return 0xffffffff;
+ else
+ return 0x00000000;
+}
+
+u32 hudson_poems_state::poems_8000200_r(offs_t offset, u32 mem_mask)
+{
+ if (!machine().side_effects_disabled())
+ logerror("%s: poems_8000200_r %08x\n", machine().describe_context(), mem_mask);
+
+ // in some places it loops on bit 0 being clear, in other places it seems to simply be used like an ack
+ return 0x00000001;
+}
+
+void hudson_poems_state::set_palette_val(int entry)
+{
+ const u16 datax = m_palram[entry];
+ const int b = ((datax) & 0x001f) >> 0;
+ const int g = ((datax) & 0x03e0) >> 5;
+ const int r = ((datax) & 0x7c00) >> 10;
+ m_palette->set_pen_color(entry, pal5bit(r), pal5bit(g), pal5bit(b));
+}
+
+void hudson_poems_state::palette_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_palram[offset]);
+ set_palette_val(offset);
+}
+
+void hudson_poems_state::fade_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ logerror("%s: fade_w %08x %08x\n", machine().describe_context(), data, mem_mask);
+
+ u8 val = 0x1f - ((data >> 16) & 0x1f);
+
+ const double intensity = (double)(val & 0x1f) / (double)0x1f;
+ for (int i = 0; i < 0x200; i++)
+ m_palette->set_pen_contrast(i, intensity);
+
+}
+
+void hudson_poems_state::unktable_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ if (mem_mask & 0x0000ffff)
+ {
+ if (m_unktableoffset < 256)
+ {
+ m_unktable[m_unktableoffset] = data & 0x0000ffff;
+ set_palette_val(m_unktableoffset);
+ m_unktableoffset++;
+ }
+ }
+
+ if (mem_mask & 0xffff0000)
+ {
+ if (m_unktableoffset < 256)
+ {
+ m_unktable[m_unktableoffset] = (data & 0xffff0000)>>16;
+ set_palette_val(m_unktableoffset);
+ m_unktableoffset++;
+ }
+ }
+}
+
+void hudson_poems_state::unktable_reset_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ m_unktableoffset = 0;
+}
+
+void hudson_poems_state::unk_trigger_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ logerror("%s: unk_trigger_w %08x %08x\n", machine().describe_context(), data, mem_mask);
+ m_maincpu->set_input_line(0x4, ASSERT_LINE);
+}
+
+
+void hudson_poems_state::mainram_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_mainram[offset]);
+
+ m_gfxdecode->gfx(2)->mark_dirty(offset / 8);
+ m_gfxdecode->gfx(3)->mark_dirty(offset / 16);
+}
+
+template<int Which>
+void hudson_poems_state::tilemap_map(address_map &map, u32 base)
+{
+ map(base+0x00, base+0x03).rw(FUNC(hudson_poems_state::tilemap_cfg_r<Which>), FUNC(hudson_poems_state::tilemap_cfg_w<Which>));
+ map(base+0x04, base+0x07).rw(FUNC(hudson_poems_state::tilemap_base_r<Which>), FUNC(hudson_poems_state::tilemap_base_w<Which>));
+ map(base+0x08, base+0x0b).rw(FUNC(hudson_poems_state::tilemap_unk_r<Which>), FUNC(hudson_poems_state::tilemap_unk_w<Which>)); // usually 1 or 2 (tilemap width in ram?)
+ map(base+0x0c, base+0x0f).ram(); // usually 0 or 1
+ map(base+0x10, base+0x13).ram(); // not used?
+ map(base+0x14, base+0x17).ram(); // not used?
+ map(base+0x18, base+0x1b).rw(FUNC(hudson_poems_state::tilemap_high_r<Which>), FUNC(hudson_poems_state::tilemap_high_w<Which>)); // top word is display height, bottom word seems to be display width
+ map(base+0x1c, base+0x1f).rw(FUNC(hudson_poems_state::tilemap_scr_r<Which>), FUNC(hudson_poems_state::tilemap_scr_w<Which>)); // top word is y scroll, bottom word is x scroll
+ map(base+0x20, base+0x23).ram(); // used, always 00001000 (maybe zoom?)
+ map(base+0x24, base+0x27).ram(); // not used?
+ map(base+0x28, base+0x2b).ram(); // not used?
+ map(base+0x2c, base+0x2f).ram(); // used, always 00001000 (maybe zoom?)
+ map(base+0x30, base+0x33).ram(); // not used?
+ map(base+0x34, base+0x37).ram(); // not used?
+ map(base+0x38, base+0x3b).ram(); // not used?
+ map(base+0x3c, base+0x3f).ram(); // not used?
+}
+
void hudson_poems_state::mem_map(address_map &map)
{
- map(0x20000000, 0x207fffff).rom().region("maincpu", 0);
- map(0x2c000000, 0x2c7fffff).ram();
+ map(0x00000000, 0x007fffff).mirror(0x20000000).rom().region("maincpu", 0);
+
+ /////////////////// unknown
+ map(0x04000040, 0x04000043).r(FUNC(hudson_poems_state::poems_random_r)).nopw();
+ map(0x04000140, 0x04000143).r(FUNC(hudson_poems_state::poems_random_r)).nopw();
+ map(0x04000240, 0x04000243).r(FUNC(hudson_poems_state::poems_random_r)).nopw();
+ map(0x04000340, 0x04000343).r(FUNC(hudson_poems_state::poems_random_r)).nopw();
+
+ //map(0x04000324, 0x04000327).nopw(); // uploads a table here from ROM after uploading fixed values from ROM to some other addresses
+ map(0x0400033c, 0x0400033f).w(FUNC(hudson_poems_state::unk_trigger_w)); // maybe DMA?
+ map(0x04001000, 0x04001003).r(FUNC(hudson_poems_state::poems_random_r)).nopw();
+
+
+ map(0x0400100c, 0x0400100f).nopr(); // read in various places at end of calls, every frame, but result seems to go unused?
+ map(0x04002040, 0x04002043).portr("IN1");
+
+ /////////////////// palette / regs?
+
+ map(0x08000038, 0x0800003b).r(FUNC(hudson_poems_state::poems_8000038_r));
+ //map(0x0800003c, 0x0800003f).nopw(); // used close to the fade write code, writes FFFFFFFF
+
+ //map(0x08000048, 0x0800004b).nopw(); // ^^
+ //map(0x0800004c, 0x0800004f).nopw(); // ^^
+ //map(0x08000050, 0x08000053).nopw(); // ^^ 16-bit write, sometimes writes 00000101 & 0000FFFF
+ //map(0x08000054, 0x08000057).nopw(); // ^^ writes 15555555 while fading
+ map(0x0800005c, 0x0800005f).w(FUNC(hudson_poems_state::fade_w));
+
+ // are these runtime registers, or DMA sources?
+ map(0x08000070, 0x0800007f).w(FUNC(hudson_poems_state::spritegfx_base_w)); // ^^ sometimes writes 2C009C00 (one of the tile data bases)
+
+ // registers 0x080 - 0x0bf are tilemap 0
+ tilemap_map<0>(map, 0x08000080);
+ // registers 0x0c0 - 0x0ff are tilemap 1
+ tilemap_map<1>(map, 0x080000c0);
+ // registers 0x100 - 0x13f are tilemap 2
+ tilemap_map<2>(map, 0x08000100);
+ // registers 0x140 - 0x17f are tilemap 3
+ tilemap_map<3>(map, 0x08000140);
+
+ // registers at 0x180 are sprites
+
+ //map(0x08000180, 0x08000183).nopw(); // gets set to 0000007F on startup (list length?)
+ map(0x08000184, 0x08000187).w(FUNC(hudson_poems_state::spritelist_base_w)); // gets set to 2C009400 on startup
+
+ map(0x08000800, 0x08000fff).ram().w(FUNC(hudson_poems_state::palette_w)).share("palram");
+
+ /////////////////// sound regs??
+
+ map(0x08008000, 0x08008003).nopw();
+
+ map(0x08008200, 0x08008203).r(FUNC(hudson_poems_state::poems_8000200_r));
+ map(0x08008204, 0x08008207).nopr().nopw(); // read only seems to be used to ack after write, value doesn't matter, similar code to 200 above
+
+ map(0x08008400, 0x08008403).nopw();
+
+ map(0x08008a00, 0x08008a7f).ram(); // filled with 32 copies of '0x0001'
+ map(0x08008c00, 0x08008c7f).ram(); // filled with 32 copies of '0x0003'
+ map(0x08009000, 0x080093ff).ram(); // filled with 32 copies of '0x0200, 0x0004, 0x0000, 0x0100, 0x0c02, 0x0000, 0x0000, 0x0000'
+ map(0x08009400, 0x080097ff).ram(); // filled with 32 copies of '0x0000, 0x3fff, 0x0000, 0x0000, 0x3fff, 0x0000, 0x0000, 0x0000'
+ map(0x08009800, 0x08009bff).ram(); // filled with 32 copies of '0x0080, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000'
+
+ map(0x0800a000, 0x0800a003).nopw();
+ map(0x0800a004, 0x0800a007).nopw();
+
+ map(0x0800aa00, 0x0800aa03).w(FUNC(hudson_poems_state::unk_aa00_w)); // writes 2c020000, which is the top of RAM? (or middle?)
+ map(0x0800aa04, 0x0800aa07).r(FUNC(hudson_poems_state::unk_aa04_r));
+
+ map(0x0800b000, 0x0800b003).w(FUNC(hudson_poems_state::unktable_w)); // writes a table of increasing 16-bit values here
+ map(0x0800b004, 0x0800b007).w(FUNC(hudson_poems_state::unktable_reset_w));
+
+ map(0x0800c040, 0x0800c05f).ram();
+
+ ///////////////////
+
+ map(0x08020000, 0x08020003).nopr().nopw();
+ map(0x08020004, 0x08020007).nopr().nopw();
+ map(0x08020008, 0x0802000b).nopr();
+ map(0x08020010, 0x08020013).r(FUNC(hudson_poems_state::poems_8020010_r));
+ map(0x08020014, 0x08020017).nopw(); // writes 0x10
+ map(0x08020018, 0x0802001b).r(FUNC(hudson_poems_state::poems_unk_r)).nopw(); // writes 0x10
+ map(0x08020020, 0x08020023).r(FUNC(hudson_poems_state::poems_count_r));
+
+ ///////////////////
+
+ map(0x2c000000, 0x2c03ffff).ram().w(FUNC(hudson_poems_state::mainram_w)).share("mainram");
+}
+
+static GFXDECODE_START( gfx_poems )
+ GFXDECODE_ENTRY( "maincpu", 0, gfx_8x8x4_packed_lsb, 0, 16 )
+ GFXDECODE_ENTRY( "maincpu", 0, gfx_8x8x8_raw, 0, 1 )
+
+ GFXDECODE_RAM( "mainram", 0, gfx_8x8x4_packed_lsb, 0, 32 )
+ GFXDECODE_RAM( "mainram", 0, gfx_8x8x8_raw, 0, 2 )
+GFXDECODE_END
+
+TIMER_DEVICE_CALLBACK_MEMBER(hudson_poems_state::screen_scanline)
+{
+ const int scanline = param;
+
+ if (scanline == 100)
+ {
+ if (m_tilemapunk[0] != 1) // wrong, this is probably just tilemap size, with 1 being 256 and 2 being 512, but prevents unwanted IRQs in Test Mode
+ m_maincpu->set_input_line(0x10, ASSERT_LINE);
+ }
+
+ if (scanline == 150)
+ {
+ m_maincpu->set_input_line(0x04, CLEAR_LINE);
+ }
}
void hudson_poems_state::hudson_poems(machine_config &config)
{
- // 27Mhz XTAL
-
- // Xtensa based CPU?
+ // 27Mhz XTAL, Xtensa based CPU
XTENSA(config, m_maincpu, 27_MHz_XTAL);
m_maincpu->set_addrmap(AS_PROGRAM, &hudson_poems_state::mem_map);
+ // the vectors can be configured when the CPU is manufactured, so treat as config options
+ m_maincpu->set_startupvector(0x00000040);
+ m_maincpu->set_irq_vector(4, 0x2c0001b4); // 0x10
+ m_maincpu->set_irq_vector(1, 0x2c000194); // 0x02
+ m_maincpu->set_irq_vector(2, 0x2c000194); // 0x04
+ // 0x2c0001b4 these are also valid vectors
+ // 0x2c0001c4
+ // 0x2c0001d4
+ // 0x2c000000 is a register window exception (4)
+ // 0x2c000040 is a register window exception (4)
+ // 0x2c000080 is a register window exception (8)
+ // 0x2c0000c0 is a register window exception (8)
+ // 0x2c000100 is a register window exception (12)
+ // 0x2c000140 is a register window exception (12)
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
- screen.set_size(320, 240); // resolution not confirmed
+ screen.set_size(320, 240);
screen.set_visarea(0, 320-1, 0, 240-1);
screen.set_screen_update(FUNC(hudson_poems_state::screen_update));
+ TIMER(config, "scantimer").configure_scanline(FUNC(hudson_poems_state::screen_scanline), "screen", 0, 1);
+
+ GFXDECODE(config, m_gfxdecode, "palette", gfx_poems);
+ PALETTE(config, m_palette).set_format(palette_device::xBGR_555, 0x200);
+
SPEAKER(config, "speaker").front_center();
}
+void hudson_poems_state::init_marimba()
+{
+}
+
ROM_START( marimba )
ROM_REGION( 0x800000, "maincpu", 0 )
ROM_LOAD( "marimbatengoku.u2", 0x000000, 0x800000, CRC(b2ac0c5b) SHA1(48f3cdf399b032d86234125eeac3fb1cdc73538a) ) // glob with TSOP pads
@@ -110,4 +722,4 @@ ROM_END
} // anonymous namespace
-CONS( 2005, marimba, 0, 0, hudson_poems, hudson_poems, hudson_poems_state, empty_init, "Konami", "Marimba Tengoku (Japan)", MACHINE_IS_SKELETON )
+CONS( 2005, marimba, 0, 0, hudson_poems, hudson_poems, hudson_poems_state, init_marimba, "Konami", "Marimba Tengoku (Japan)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NO_SOUND )