summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/m88000/m88000.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/m88000/m88000.cpp')
-rw-r--r--src/devices/cpu/m88000/m88000.cpp1474
1 files changed, 1448 insertions, 26 deletions
diff --git a/src/devices/cpu/m88000/m88000.cpp b/src/devices/cpu/m88000/m88000.cpp
index 7498d02591d..67a511a48a1 100644
--- a/src/devices/cpu/m88000/m88000.cpp
+++ b/src/devices/cpu/m88000/m88000.cpp
@@ -1,17 +1,129 @@
// license:BSD-3-Clause
-// copyright-holders:AJR
-/***************************************************************************
+// copyright-holders:Patrick Mackinlay
- Motorola M88000 RISC microprocessors
-
- Currently this device is just a stub with no actual execution core.
-
-***************************************************************************/
+/*
+ * Motorola M88000 Family of RISC microprocessors.
+ *
+ * TODO:
+ * - cache/mmu interface
+ * - misaligned access exceptions
+ * - floating point exceptions
+ * - user/supervisor space
+ * - xip/fip/nip exception flag
+ * - pipeline and cycles counts
+ * - mc88110
+ * - little-endian mode
+ */
#include "emu.h"
+#include "debugger.h"
#include "m88000.h"
#include "m88000d.h"
+#define LOG_GENERAL (1U << 0)
+#define LOG_EXCEPTION (1U << 1)
+
+//#define VERBOSE (LOG_GENERAL|LOG_EXCEPTION)
+
+#include "logmacro.h"
+
+enum exception_number : unsigned
+{
+ E_RESET = 0, // reset exception
+ E_INTERRUPT = 1, // interrupt exception
+ E_INSTRUCTION = 2, // instruction access exception
+ E_DATA = 3, // data access exception
+ E_MISALIGNED = 4, // misaligned access exception
+ E_UNIMPLEMENTED = 5, // unimplemented opcode exception
+ E_PRIVILEGE = 6, // privilege violation exception
+ E_BOUNDS = 7, // bounds check violation exception
+ E_INT_DIVIDE = 8, // illegal integer divide exception
+ E_INT_OVERFLOW = 9, // integer overflow exception
+ E_ERROR = 10, // error exception
+
+ E_SFU1_P = 114, // sfu 1 precise - floating-point precise exception
+ E_SFU1_I = 115, // sfu 1 imprecise - floating-point imprecise exception
+ E_SFU2_P = 116, // sfu 2 precise exception
+ E_SFU3_P = 118, // sfu 3 precise exception
+ E_SFU4_P = 120, // sfu 4 precise exception
+ E_SFU5_P = 122, // sfu 5 precise exception
+ E_SFU6_P = 124, // sfu 6 precise exception
+ E_SFU7_P = 126, // sfu 7 precise exception
+};
+
+enum cr_number : unsigned
+{
+ PID = 0, // processor identification
+ PSR = 1, // processor status
+ EPSR = 2, // exception-time processor status
+ SSBR = 3, // shadow scoreboard
+ SXIP = 4, // shadow execute instruction pointer
+ SNIP = 5, // shadow next instruction pointer
+ SFIP = 6, // shadow fetch instruction pointer
+ VBR = 7, // vector base
+ DMT0 = 8, // data memory transaction 0
+ DMD0 = 9, // data memory data 0
+ DMA0 = 10, // data memory address 0
+ DMT1 = 11, // data memory transaction 1
+ DMD1 = 12, // data memory data 1
+ DMA1 = 13, // data memory address 1
+ DMT2 = 14, // data memory transaction 2
+ DMD2 = 15, // data memory data 2
+ DMA2 = 16, // data memory address 2
+ SR0 = 17, // supervisor storage 0
+ SR1 = 18, // supervisor storage 1
+ SR2 = 19, // supervisor storage 2
+ SR3 = 20, // supervisor storage 3
+};
+
+enum fcr_number : unsigned
+{
+ FPECR = 0, // floating-point exception cause
+ FPHS1 = 1, // floating-point source 1 operand high
+ FPLS1 = 2, // floating-point source 1 operand low
+ FPHS2 = 3, // floating-point source 2 operand high
+ FPLS2 = 4, // floating-point source 2 operand low
+ FPPT = 5, // floating-point precise operation type
+ FPRH = 6, // floating-point result high
+ FPRL = 7, // floating-point result low
+ FPIT = 8, // floating-point imprecise operation type
+ FPSR = 62, // floating-point user status
+ FPCR = 63, // floating-point user control
+};
+
+enum ip_mask : u32
+{
+ IP_A = 0xffff'fffc, // address
+ IP_V = 0x0000'0002, // valid
+ IP_E = 0x0000'0001, // exception
+};
+
+enum psr_mask : u32
+{
+ PSR_SFRZ = 0x0000'0001, // shadow freeze
+ PSR_IND = 0x0000'0002, // interrupt disable
+ PSR_MXM = 0x0000'0004, // misaligned access enable
+ PSR_SFD1 = 0x0000'0008, // sfu1 disable
+ PSR_SFD = 0x0000'03f0, // sfu2-7 disable
+ PSR_C = 0x1000'0000, // carry
+ PSR_SER = 0x2000'0000, // serial mode
+ PSR_BO = 0x4000'0000, // byte ordering (1=little-endian)
+ PSR_MODE = 0x8000'0000, // supervisor/user mode (1=supervisor)
+};
+
+enum cr_mask : u32
+{
+ PSR_MASK = 0xf000'000f,
+ VBR_MASK = 0xffff'f000,
+};
+
+enum fcr_mask : u32
+{
+ FPECR_MASK = 0x0000'00ff,
+ FPSR_MASK = 0x0000'001f,
+ FPCR_MASK = 0x0000'c01f,
+};
+
// device type definitions
DEFINE_DEVICE_TYPE(MC88100, mc88100_device, "mc88100", "Motorola MC88100")
@@ -19,12 +131,18 @@ mc88100_device::mc88100_device(const machine_config &mconfig, const char *tag, d
: cpu_device(mconfig, MC88100, tag, owner, clock)
, m_code_config("code", ENDIANNESS_BIG, 32, 32, 0)
, m_data_config("data", ENDIANNESS_BIG, 32, 32, 0)
- , m_pc(0)
- , m_r{0}
- , m_cr{0}
+ , m_xip(0)
+ , m_nip(0)
+ , m_fip(0)
+ , m_r{ 0 }
+ , m_cr{ 0 }
+ , m_fcr{ 0 }
+ , m_int_state(false)
, m_icount(0)
{
- m_cr[0] = 0x00000001;
+ m_cr[PID] = 0x00000001;
+
+ softfloat_roundingMode = softfloat_round_near_even;
}
std::unique_ptr<util::disasm_interface> mc88100_device::create_disassembler()
@@ -34,7 +152,6 @@ std::unique_ptr<util::disasm_interface> mc88100_device::create_disassembler()
device_memory_interface::space_config_vector mc88100_device::memory_space_config() const
{
- // MC88100 has physically separate code and data buses
return space_config_vector {
std::make_pair(AS_PROGRAM, &m_code_config),
std::make_pair(AS_DATA, &m_data_config)
@@ -44,35 +161,1340 @@ device_memory_interface::space_config_vector mc88100_device::memory_space_config
void mc88100_device::device_start()
{
space(AS_PROGRAM).cache(m_inst_cache);
- space(AS_DATA).specific(m_data_space);
+
+ if (has_configured_map(AS_DATA))
+ space(AS_DATA).specific(m_data_space);
+ else
+ space(AS_PROGRAM).specific(m_data_space);
set_icountptr(m_icount);
- state_add(M88000_PC, "PC", m_pc);
- state_add(STATE_GENPC, "GENPC", m_pc).noshow();
- state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow();
- state_add(STATE_GENFLAGS, "CURFLAGS", m_cr[1]).mask(0xf00003ff).noshow();
+ state_add(STATE_GENPC, "GENPC", m_xip).mask(IP_A).noshow();
+ state_add(STATE_GENPCBASE, "CURPC", m_xip).mask(IP_A).noshow();
+
+ state_add(32, "XIP", m_xip).mask(IP_A).readonly();
+ state_add(33, "NIP", m_nip).mask(IP_A).readonly();
+ state_add(34, "FIP", m_fip,
+ [this](u32 data)
+ {
+ m_xip = 0;
+ m_nip = 0;
+ m_fip = (data & IP_A) | IP_V;
+ }).mask(IP_A);
+ state_add(35, "SB", m_sb);
+
+ state_add(36 + PSR, "PSR", m_cr[PSR]).mask(PSR_MASK);
+ state_add(36 + VBR, "VBR", m_cr[VBR]).mask(VBR_MASK);
+ state_add(36 + SR0, "sr0", m_cr[SR0]);
+ state_add(36 + SR1, "sr1", m_cr[SR1]);
+ state_add(36 + SR2, "sr2", m_cr[SR2]);
+ state_add(36 + SR3, "sr3", m_cr[SR3]);
+
for (int i = 1; i < 32; i++)
- state_add(M88000_R1 + i - 1, string_format("r%d", i).c_str(), m_r[i]);
- state_add(M88000_PSR, "PSR", m_cr[1]).mask(0xf00003ff);
- state_add(M88000_VBR, "VBR", m_cr[7]).mask(0xfffff000);
+ state_add(i, string_format("r%d", i).c_str(), m_r[i]);
+
+ save_item(NAME(m_xip));
+ save_item(NAME(m_nip));
+ save_item(NAME(m_fip));
+ save_item(NAME(m_sb));
+
+ save_item(NAME(m_r));
+ save_item(NAME(m_cr));
+ save_item(NAME(m_fcr));
+
+ save_item(NAME(m_int_state));
}
void mc88100_device::device_reset()
{
- m_pc = 0;
- m_cr[1] = 0x800003fb;
- m_cr[7] = 0;
+ m_cr[PSR] = PSR_MODE | PSR_SFD | PSR_SFD1 | PSR_IND | PSR_SFRZ;
+ m_cr[EPSR] = PSR_SFD;
+ m_cr[VBR] = 0;
+
+ m_xip = 0;
+ m_nip = 0;
+ m_fip = IP_V;
}
void mc88100_device::execute_run()
{
- debugger_instruction_hook(m_pc);
+ while (m_icount > 0)
+ {
+ // update shadow registers
+ if (!(m_cr[PSR] & PSR_SFRZ))
+ {
+ m_cr[SXIP] = m_xip;
+ m_cr[SNIP] = m_nip;
+ m_cr[SFIP] = m_fip;
+ }
+
+ // interrupt check
+ if (m_int_state && !(m_cr[PSR] & PSR_IND))
+ {
+ exception(E_INTERRUPT);
+
+ // notify debugger
+ if (machine().debug_flags & DEBUG_FLAG_ENABLED)
+ debug()->interrupt_hook(INPUT_LINE_IRQ0);
+ }
+
+ if (m_xip & IP_V)
+ {
+ debugger_instruction_hook(m_xip & IP_A);
- m_icount = 0;
+ execute(m_xop);
+ }
+
+ // fetch
+ if (m_fip & IP_V)
+ m_fop = m_inst_cache.read_dword(m_fip & IP_A);
+
+ // next becomes execute
+ m_xop = m_nop;
+ m_xip = m_nip;
+
+ // fetch becomes next
+ m_nop = m_fop;
+ m_nip = m_fip;
+
+ // increment fetch
+ m_fip += 4;
+
+ m_icount--;
+ }
+}
+
+// decoding macros
+#define D BIT(inst, 21, 5)
+#define D0 (((inst >> 21) + 0) & 31)
+#define D1 (((inst >> 21) + 1) & 31)
+
+#define S1 BIT(inst, 16, 5)
+#define S1H (((inst >> 16) + 0) & 31)
+#define S1L (((inst >> 16) + 1) & 31)
+
+#define S2 BIT(inst, 0, 5)
+#define S2H ((inst + 0) & 31)
+#define S2L ((inst + 1) & 31)
+
+#define IMM16 BIT(inst, 0, 16)
+#define VEC9 BIT(inst, 0, 9)
+#define CR BIT(inst, 5, 6)
+
+void mc88100_device::execute(u32 const inst)
+{
+ switch (BIT(inst, 26, 6))
+ {
+ // load/store/exchange immediate
+ case 0x00: // xmem.bu: exchange register with memory unsigned byte
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_byte(m_r[S1] + IMM16);
+ m_data_space.write_byte(m_r[S1] + IMM16, u8(data));
+ }
+ break;
+ case 0x01: // xmem: exchange register with memory word
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_dword(m_r[S1] + IMM16);
+ m_data_space.write_dword(m_r[S1] + IMM16, data);
+ }
+ break;
+ case 0x02: // ld.hu: load half word unsigned
+ m_r[D] = m_data_space.read_word(m_r[S1] + IMM16);
+ break;
+ case 0x03: // ld.bu: load byte unsigned
+ m_r[D] = m_data_space.read_byte(m_r[S1] + IMM16);
+ break;
+ case 0x04: // ld.d: load double word
+ m_r[D0] = m_data_space.read_dword(m_r[S1] + IMM16 + 0);
+ m_r[D1] = m_data_space.read_dword(m_r[S1] + IMM16 + 4);
+ break;
+ case 0x05: // ld: load word
+ m_r[D] = m_data_space.read_dword(m_r[S1] + IMM16);
+ break;
+ case 0x06: // ld.h: load half word
+ m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + IMM16)));
+ break;
+ case 0x07: // ld.b: load byte
+ m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + IMM16)));
+ break;
+ case 0x08: // st.d: store double word (unscaled)
+ m_data_space.write_dword(m_r[S1] + IMM16 + 0, m_r[D0]);
+ m_data_space.write_dword(m_r[S1] + IMM16 + 4, m_r[D1]);
+ break;
+ case 0x09: // st: store word (unscaled)
+ m_data_space.write_dword(m_r[S1] + IMM16, m_r[D]);
+ break;
+ case 0x0a: // st.h: store half word (unscaled)
+ m_data_space.write_word(m_r[S1] + IMM16, u16(m_r[D]));
+ break;
+ case 0x0b: // st.b: store byte (unscaled)
+ m_data_space.write_byte(m_r[S1] + IMM16, u8(m_r[D]));
+ break;
+ case 0x0c: // lda.d: load address double word (unscaled)
+ case 0x0d: // lda: load address word (unscaled)
+ case 0x0e: // lda.h: load address half word (unscaled)
+ case 0x0f: // lda.b: load address byte (unscaled)
+ m_r[D] = m_r[S1] + IMM16;
+ break;
+
+ // logical immediate
+ case 0x10: // and: logical and (immediate)
+ m_r[D] = m_r[S1] & (0xffff0000U | IMM16);
+ break;
+ case 0x11: // and.u: logical and upper (immediate)
+ m_r[D] = m_r[S1] & ((u32(IMM16) << 16) | 0x0000ffffU);
+ break;
+ case 0x12: // mask: logical mask (immediate)
+ m_r[D] = m_r[S1] & IMM16;
+ break;
+ case 0x13: // mask.u: logical mask upper (immediate)
+ m_r[D] = m_r[S1] & (u32(IMM16) << 16);
+ break;
+ case 0x14: // xor: logical exclusive or (immediate)
+ m_r[D] = m_r[S1] ^ IMM16;
+ break;
+ case 0x15: // xor.u: logical exclusive or upper (immediate)
+ m_r[D] = m_r[S1] ^ (u32(IMM16) << 16);
+ break;
+ case 0x16: // or: logical or (immediate)
+ m_r[D] = m_r[S1] | IMM16;
+ break;
+ case 0x17: // or.u: logical or upper (immediate)
+ m_r[D] = m_r[S1] | (u32(IMM16) << 16);
+ break;
+
+ // integer arithmetic
+ case 0x18: // addu: unsigned integer add (immediate)
+ m_r[D] = m_r[S1] + IMM16;
+ break;
+ case 0x19: // subu: unsigned integer subtract (immediate)
+ m_r[D] = m_r[S1] + ~IMM16 + 1;
+ break;
+ case 0x1a: // divu: unsigned integer divide (immediate)
+ if (!(m_cr[PSR] & PSR_SFD1))
+ {
+ if (IMM16)
+ m_r[D] = s32(m_r[S1]) / s32(IMM16);
+ else
+ exception(E_INT_DIVIDE);
+ }
+ else
+ exception(E_SFU1_P);
+ break;
+ case 0x1b: // mul: integer multiply (immediate)
+ if (!(m_cr[PSR] & PSR_SFD1))
+ m_r[D] = m_r[S1] * IMM16;
+ else
+ exception(E_SFU1_P);
+ break;
+ case 0x1c: // add: integer add (immediate)
+ m_r[D] = m_r[S1] + IMM16;
+ break;
+ case 0x1d: // sub: integer subtract (immediate)
+ m_r[D] = m_r[S1] + ~IMM16 + 1;
+ break;
+ case 0x1e: // div: signed integer divide (immediate)
+ if (!(m_cr[PSR] & PSR_SFD1))
+ {
+ if (IMM16 && !BIT(m_r[S1], 31))
+ m_r[D] = s32(m_r[S1]) / s32(IMM16);
+ else
+ exception(E_INT_DIVIDE);
+ }
+ else
+ exception(E_SFU1_P);
+ break;
+ case 0x1f: // cmp: integer compare (immediate)
+ m_r[D] = cmp(m_r[S1], IMM16);
+ break;
+
+ // control registers
+ case 0x20:
+ switch (BIT(inst, 11, 5))
+ {
+ case 0x08: // ldcr: load from control register (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = m_cr[CR];
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x09: // fldcr: load from floating-point control register
+ if ((m_cr[PSR] & PSR_MODE) || (CR >= FPSR))
+ m_r[D] = m_fcr[CR];
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x10: // stcr: store to control register (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ set_cr(CR, m_r[S1]);
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x11: // fstcr: store to floating-point control register
+ if ((m_cr[PSR] & PSR_MODE) || (CR >= FPSR))
+ set_fcr(CR, m_r[S1]);
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x18: // xcr: exchange control register (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ u32 const data = m_r[S1];
+
+ m_r[D] = m_cr[CR];
+ set_cr(CR, data);
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x19: // fxcr: exchange floating-point control register
+ if ((m_cr[PSR] & PSR_MODE) || (CR >= FPSR))
+ {
+ u32 const data = m_r[S1];
+
+ m_r[D] = m_fcr[CR];
+ set_fcr(CR, data);
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ default:
+ exception(E_UNIMPLEMENTED);
+ break;
+ }
+ break;
+ case 0x21: // floating-point
+ if (!(m_cr[PSR] & PSR_SFD1) && D)
+ {
+ unsigned const td = BIT(inst, 5, 2);
+
+ float64_t const s1 = BIT(inst, 9, 2) ? float64_t{ (u64(m_r[S1H]) << 32) | m_r[S1L] } : f32_to_f64(float32_t{ m_r[S1] });
+ float64_t const s2 = BIT(inst, 7, 2) ? float64_t{ (u64(m_r[S2H]) << 32) | m_r[S2L] } : f32_to_f64(float32_t{ m_r[S2] });
+
+ switch (BIT(inst, 11, 5))
+ {
+ case 0x00: fset(td, D, f64_mul(s1, s2)); break; // fmul
+ case 0x04: fset(td, D, i32_to_f64(s32(m_r[S2]))); break; // flt
+ case 0x05: fset(td, D, f64_add(s1, s2)); break; // fadd
+ case 0x06: fset(td, D, f64_sub(s1, s2)); break; // fsub
+ case 0x07: m_r[D] = fcmp(s1, s2); break; // fcmp
+ case 0x09: m_r[D] = f64_to_i32(s2, softfloat_roundingMode, true); break; // int
+ case 0x0a: m_r[D] = f64_to_i32(s2, softfloat_round_near_even, true); break; // nint
+ case 0x0b: m_r[D] = f64_to_i32(s2, softfloat_round_minMag, true); break; // trunc
+ case 0x0e: fset(td, D, f64_div(s1, s2)); break; // fdiv
+ }
+ }
+ else
+ exception(E_SFU1_P);
+ break;
+
+ // special-function units 2-7
+ case 0x22: exception(E_SFU2_P); break;
+ case 0x23: exception(E_SFU3_P); break;
+ case 0x24: exception(E_SFU4_P); break;
+ case 0x25: exception(E_SFU5_P); break;
+ case 0x26: exception(E_SFU6_P); break;
+ case 0x27: exception(E_SFU7_P); break;
+
+ case 0x28: case 0x29: case 0x2a: case 0x2b:
+ case 0x2c: case 0x2d: case 0x2e: case 0x2f:
+ exception(E_UNIMPLEMENTED);
+ break;
+ // flow-control
+ case 0x30: // br: unconditional branch
+ m_fip = m_xip + (s32(inst << 6) >> 4);
+ m_nip &= ~IP_V;
+ break;
+ case 0x31: // br.n: unconditional branch (delayed)
+ m_fip = m_xip + (s32(inst << 6) >> 4);
+ break;
+ case 0x32: // bsr: branch to subroutine
+ m_fip = m_xip + (s32(inst << 6) >> 4);
+ m_r[1] = m_nip & IP_A;
+ m_nip &= ~IP_V;
+ break;
+ case 0x33: // bsr.n: branch to subroutine (delayed)
+ m_fip = m_xip + (s32(inst << 6) >> 4);
+ m_r[1] = (m_nip & IP_A) + 4;
+ break;
+ case 0x34: // bb0: branch on bit clear
+ if (!BIT(m_r[S1], D))
+ {
+ m_fip = m_xip + (s32(inst << 16) >> 14);
+ m_nip &= ~IP_V;
+ }
+ break;
+ case 0x35: // bb0.n: branch on bit clear (delayed)
+ if (!BIT(m_r[S1], D))
+ m_fip = m_xip + (s32(inst << 16) >> 14);
+ break;
+ case 0x36: // bb1: branch on bit set
+ if (BIT(m_r[S1], D))
+ {
+ m_fip = m_xip + (s32(inst << 16) >> 14);
+ m_nip &= ~IP_V;
+ }
+ break;
+ case 0x37: // bb1.n: branch on bit set (delayed)
+ if (BIT(m_r[S1], D))
+ m_fip = m_xip + (s32(inst << 16) >> 14);
+ break;
+ case 0x38:
+ case 0x39:
+ exception(E_UNIMPLEMENTED);
+ break;
+ case 0x3a: // bcnd: conditional branch
+ if (condition(D, m_r[S1]))
+ {
+ m_fip = m_xip + (s32(inst << 16) >> 14);
+ m_nip &= ~IP_V;
+ }
+ break;
+ case 0x3b: // bcnd.n: conditional branch (delayed)
+ if (condition(D, m_r[S1]))
+ m_fip = m_xip + (s32(inst << 16) >> 14);
+ break;
+ case 0x3c: // bit field
+ switch (BIT(inst, 10, 6))
+ {
+ case 0x20: // clr: clear bit field (immediate)
+ {
+ unsigned const width = BIT(inst, 5, 5);
+ unsigned const offset = inst & 31;
+
+ m_r[D] = m_r[S1] & ~(make_bitmask<u32>(width ? width : 32) << offset);
+ }
+ break;
+ case 0x22: // set: set bit field (immediate)
+ {
+ unsigned const width = BIT(inst, 5, 5);
+ unsigned const offset = inst & 31;
+
+ m_r[D] = m_r[S1] | (make_bitmask<u32>(width ? width : 32) << offset);
+ }
+ break;
+ case 0x24: // ext: extract signed bit field (immediate)
+ {
+ unsigned const width = BIT(inst, 5, 5);
+ unsigned const offset = inst & 31;
+
+ if (width && (width + offset) < 32)
+ m_r[D] = s32(m_r[S1] << (32 - (width + offset))) >> (32 - width);
+ else
+ m_r[D] = s32(m_r[S1]) >> offset;
+ }
+ break;
+ case 0x26: // extu: extract unsigned bit field (immediate)
+ {
+ unsigned const width = BIT(inst, 5, 5);
+ unsigned const offset = inst & 31;
+
+ if (width)
+ m_r[D] = BIT(m_r[S1], offset, width);
+ else
+ m_r[D] = m_r[S1] >> offset;
+ }
+ break;
+ case 0x28: // mak: make bit field (immediate)
+ {
+ unsigned const width = BIT(inst, 5, 5);
+ unsigned const offset = inst & 31;
+
+ if (width)
+ m_r[D] = (m_r[S1] & make_bitmask<u32>(width)) << offset;
+ else
+ m_r[D] = m_r[S1] << offset;
+ }
+ break;
+ case 0x2a: // rot: rotate (immediate)
+ {
+ unsigned const offset = inst & 31;
+
+ m_r[D] = (m_r[S1] << (32 - offset)) | (m_r[S1] >> offset);
+ }
+ break;
+
+ case 0x34: // tb0: trap on bit clear
+ if ((m_cr[PSR] & PSR_MODE) || (VEC9 > 127))
+ {
+ if (!BIT(m_r[S1], D))
+ exception(VEC9, true);
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x36: // tb1: trap on bit set
+ if ((m_cr[PSR] & PSR_MODE) || (VEC9 > 127))
+ {
+ if (BIT(m_r[S1], D))
+ exception(VEC9, true);
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x3a: // tcnd: conditional trap
+ // TODO: synchronize
+ if ((m_cr[PSR] & PSR_MODE) || (VEC9 > 127))
+ {
+ if (condition(D, m_r[S1]))
+ exception(VEC9, true);
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ default:
+ exception(E_UNIMPLEMENTED);
+ break;
+ }
+ break;
+ case 0x3d: // nonfloating-point
+ switch (BIT(inst, 5, 11))
+ {
+ case 0x000: // xmem.bu: exchange register with memory byte unsigned
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_byte(m_r[S1] + m_r[S2]);
+ m_data_space.write_byte(m_r[S1] + m_r[S2], u8(data));
+ }
+ break;
+ case 0x008: // xmem.bu.usr: exchange register with memory byte unsigned user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_byte(m_r[S1] + m_r[S2]);
+ m_data_space.write_byte(m_r[S1] + m_r[S2], u8(data));
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x020: // xmem: exchange register with memory word
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_dword(m_r[S1] + m_r[S2]);
+ m_data_space.write_dword(m_r[S1] + m_r[S2], u32(data));
+ }
+ break;
+ case 0x028: // xmem.usr: exchange register with memory word user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_dword(m_r[S1] + m_r[S2]);
+ m_data_space.write_dword(m_r[S1] + m_r[S2], u32(data));
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x010: // xmem.bu: exchange register with memory byte unsigned (scaled)
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_byte(m_r[S1] + (m_r[S2] << 0));
+ m_data_space.write_byte(m_r[S1] + (m_r[S2] << 0), u8(data));
+ }
+ break;
+ case 0x018: // xmem.bu.usr: exchange register with memory byte unsigned user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_byte(m_r[S1] + (m_r[S2] << 0));
+ m_data_space.write_byte(m_r[S1] + (m_r[S2] << 0), u8(data));
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x030: // xmem: exchange register with memory word (scaled)
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 2));
+ m_data_space.write_dword(m_r[S1] + (m_r[S2] << 2), u32(data));
+ }
+ break;
+ case 0x038: // xmem.usr: exchange register with memory word user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ u32 const data = m_r[D];
+
+ m_r[D] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 2));
+ m_data_space.write_dword(m_r[S1] + (m_r[S2] << 2), u32(data));
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+
+ // logical register
+ case 0x200: // and: logical and (register)
+ m_r[D] = m_r[S1] & m_r[S2];
+ break;
+ case 0x220: // and.c: logical not-and (register)
+ m_r[D] = m_r[S1] & ~m_r[S2];
+ break;
+ case 0x280: // xor: logical exclusive or (register)
+ m_r[D] = m_r[S1] ^ m_r[S2];
+ break;
+ case 0x2a0: // xor.c: logical not-exclusive or (register)
+ m_r[D] = m_r[S1] ^ ~m_r[S2];
+ break;
+ case 0x2c0: // or: logical or (register)
+ m_r[D] = m_r[S1] | m_r[S2];
+ break;
+ case 0x2e0: // or.c: logical not-or (register)
+ m_r[D] = m_r[S1] | ~m_r[S2];
+ break;
+
+ // integer arithmetic register
+ case 0x300: // addu: unsigned integer add (register)
+ m_r[D] = m_r[S1] + m_r[S2];
+ break;
+ case 0x308: // addu.co: unsigned integer add with carry out (register)
+ {
+ u32 const data = m_r[S1] + m_r[S2];
+
+ // compute carry out
+ if (carry(m_r[S1], m_r[S2], data))
+ m_cr[PSR] |= PSR_C;
+ else
+ m_cr[PSR] &= ~PSR_C;
+
+ m_r[D] = data;
+ }
+ break;
+ case 0x310: // addu.ci: unsigned integer add with carry in (register)
+ m_r[D] = m_r[S1] + m_r[S2] + bool(m_cr[PSR] & PSR_C);
+ break;
+ case 0x318: // addu.cio: unsigned integer add with carry in and out (register)
+ {
+ u32 const data = m_r[S1] + m_r[S2] + bool(m_cr[PSR] & PSR_C);
+
+ // compute carry out
+ if (carry(m_r[S1], m_r[S2], data))
+ m_cr[PSR] |= PSR_C;
+ else
+ m_cr[PSR] &= ~PSR_C;
+
+ m_r[D] = data;
+ }
+ break;
+ case 0x320: // subu: unsigned integer subtract (register)
+ m_r[D] = m_r[S1] + ~m_r[S2] + 1;
+ break;
+ case 0x328: // subu.co: unsigned integer subtract with borrow out (register)
+ {
+ u32 const data = m_r[S1] + ~m_r[S2] + 1;
+
+ // compute borrow out
+ if (carry(m_r[S1], ~m_r[S2], data))
+ m_cr[PSR] |= PSR_C;
+ else
+ m_cr[PSR] &= ~PSR_C;
+
+ m_r[D] = data;
+ }
+ break;
+ case 0x330: // subu.ci: unsigned integer subtract with borrow in (register)
+ m_r[D] = m_r[S1] + ~m_r[S2] + !bool(m_cr[PSR] & PSR_C);
+ break;
+ case 0x338: // subu.cio: unsigned integer subtract with borrow in and out (register)
+ {
+ u32 const data = m_r[S1] + ~m_r[S2] + !bool(m_cr[PSR] & PSR_C);
+
+ // compute borrow out
+ if (carry(m_r[S1], ~m_r[S2], data))
+ m_cr[PSR] |= PSR_C;
+ else
+ m_cr[PSR] &= ~PSR_C;
+
+ m_r[D] = data;
+ }
+ break;
+ case 0x340: // divu: unsigned integer divide (register)
+ if (!(m_cr[PSR] & PSR_SFD1))
+ {
+ if (m_r[S2])
+ m_r[D] = s32(m_r[S1]) / s32(m_r[S2]);
+ else
+ exception(E_INT_DIVIDE);
+ }
+ else
+ exception(E_SFU1_P);
+ break;
+ case 0x360: // mul: integer multiply (register)
+ if (!(m_cr[PSR] & PSR_SFD1))
+ m_r[D] = m_r[S1] * m_r[S2];
+ else
+ exception(E_SFU1_P);
+ break;
+ case 0x380: // add: integer add (register)
+ {
+ u32 const data = m_r[S1] + m_r[S2];
+
+ if (!overflow(m_r[S1], m_r[S2], data))
+ m_r[D] = data;
+ else
+ exception(E_INT_OVERFLOW);
+ }
+ break;
+ case 0x388: // add.co: integer add with carry out (register)
+ {
+ u32 const data = m_r[S1] + m_r[S2];
+
+ if (!overflow(m_r[S1], m_r[S2], data))
+ {
+ // compute carry out
+ if (carry(m_r[S1], m_r[S2], data))
+ m_cr[PSR] |= PSR_C;
+ else
+ m_cr[PSR] &= ~PSR_C;
+
+ m_r[D] = data;
+ }
+ else
+ exception(E_INT_OVERFLOW);
+ }
+ break;
+ case 0x390: // add.ci: integer add with carry in (register)
+ {
+ u32 const data = m_r[S1] + m_r[S2] + bool(m_cr[PSR] & PSR_C);
+
+ if (!overflow(m_r[S1], m_r[S2], data))
+ m_r[D] = data;
+ else
+ exception(E_INT_OVERFLOW);
+ }
+ break;
+ case 0x398: // add.cio: integer add with carry in and out (register)
+ {
+ u32 const data = m_r[S1] + m_r[S2] + bool(m_cr[PSR] & PSR_C);
+
+ if (!overflow(m_r[S1], m_r[S2], data))
+ {
+ // compute carry out
+ if (carry(m_r[S1], m_r[S2], data))
+ m_cr[PSR] |= PSR_C;
+ else
+ m_cr[PSR] &= ~PSR_C;
+
+ m_r[D] = data;
+ }
+ else
+ exception(E_INT_OVERFLOW);
+ }
+ break;
+ case 0x3a0: // sub: integer subtract (register)
+ m_r[D] = m_r[S1] + ~m_r[S2] + 1;
+ break;
+ case 0x3a8: // sub.co: integer subtract with borrow out (register)
+ {
+ u32 const data = m_r[S1] + ~m_r[S2] + 1;
+
+ // compute borrow out
+ if (carry(m_r[S1], ~m_r[S2], data))
+ m_cr[PSR] |= PSR_C;
+ else
+ m_cr[PSR] &= ~PSR_C;
+
+ m_r[D] = data;
+ }
+ break;
+ case 0x3b0: // sub.ci: integer subtract with borrow in (register)
+ m_r[D] = m_r[S1] + ~m_r[S2] + !bool(m_cr[PSR] & PSR_C);
+ break;
+ case 0x3b8: // sub.cio: integer subtract with borrow in and out (register)
+ {
+ u32 const data = m_r[S1] + ~m_r[S2] + !bool(m_cr[PSR] & PSR_C);
+
+ // compute borrow out
+ if (carry(m_r[S1], ~m_r[S2], data))
+ m_cr[PSR] |= PSR_C;
+ else
+ m_cr[PSR] &= ~PSR_C;
+
+ m_r[D] = data;
+ }
+ break;
+ case 0x3c0: // div: signed integer divide (register)
+ if (!(m_cr[PSR] & PSR_SFD1))
+ {
+ if (m_r[S2] && !BIT(m_r[S1], 31) && !BIT(m_r[S2], 31))
+ m_r[D] = s32(m_r[S1]) / s32(m_r[S2]);
+ else
+ exception(E_INT_DIVIDE);
+ }
+ else
+ exception(E_SFU1_P);
+ break;
+ case 0x3e0: // cmp: integer compare (register)
+ m_r[D] = cmp(m_r[S1], m_r[S2]);
+ break;
+
+ // bit field register
+ case 0x400: // clr: clear bit field (register)
+ {
+ unsigned const width = (m_r[S2] >> 5) & 31;
+ unsigned const offset = m_r[S2] & 31;
+
+ m_r[D] = m_r[S1] & ~(make_bitmask<u32>(width ? width : 32) << offset);
+ }
+ break;
+ case 0x440: // set: set bit field (register)
+ {
+ unsigned const width = (m_r[S2] >> 5) & 31;
+ unsigned const offset = m_r[S2] & 31;
+
+ m_r[D] = m_r[S1] | (make_bitmask<u32>(width ? width : 32) << offset);
+ }
+ break;
+ case 0x480: // ext: extract signed bit field (register)
+ {
+ unsigned const width = (m_r[S2] >> 5) & 31;
+ unsigned const offset = m_r[S2] & 31;
+
+ if (width && (width + offset) < 32)
+ m_r[D] = s32(m_r[S1] << (32 - (width + offset))) >> (32 - width);
+ else
+ m_r[D] = s32(m_r[S1]) >> offset;
+ }
+ break;
+ case 0x4c0: // extu: extract unsigned bit field (register)
+ {
+ unsigned const width = (m_r[S2] >> 5) & 31;
+ unsigned const offset = m_r[S2] & 31;
+
+ if (width)
+ m_r[D] = BIT(m_r[S1], offset, width);
+ else
+ m_r[D] = m_r[S1] >> offset;
+ }
+ break;
+ case 0x500: // mak: make bit field (register)
+ {
+ unsigned const width = (m_r[S2] >> 5) & 31;
+ unsigned const offset = m_r[S2] & 31;
+
+ if (width)
+ m_r[D] = (m_r[S1] & make_bitmask<u32>(width)) << offset;
+ else
+ m_r[D] = m_r[S1] << offset;
+ }
+ break;
+ case 0x540: // rot: rotate (register)
+ {
+ unsigned const offset = m_r[S2] & 31;
+
+ m_r[D] = (m_r[S1] << (32 - offset)) | (m_r[S1] >> offset);
+ }
+ break;
+ case 0x740: // ff1: find first bit set
+ {
+ unsigned const count = count_leading_zeros(m_r[S2]);
+
+ m_r[D] = (count == 32) ? count : 31 - count;
+ }
+ break;
+ case 0x760: // ff0: find first bit clear
+ {
+ unsigned const count = count_leading_ones(m_r[S2]);
+
+ m_r[D] = (count == 32) ? count : 31 - count;
+ }
+ break;
+
+ case 0x600: // jmp: unconditional jump
+ m_fip = (m_r[S2] & IP_A) | IP_V;
+ m_nip &= ~IP_V;
+ break;
+ case 0x620: // jmp.n: unconditional jump (delayed)
+ m_fip = (m_r[S2] & IP_A) | IP_V;
+ break;
+ case 0x640: // jsr: unconditional jump to subroutine
+ m_fip = (m_r[S2] & IP_A) | IP_V;
+ m_r[1] = m_nip & IP_A;
+ m_nip &= ~IP_V;
+ break;
+ case 0x660: // jsr.n: unconditional jump to subroutine (delayed)
+ m_fip = (m_r[S2] & IP_A) | IP_V;
+ m_r[1] = (m_nip & IP_A) + 4;
+ break;
+ case 0x7c0: // tbnd: trap on bounds check (register)
+ if (m_r[S1] > m_r[S2])
+ exception(E_BOUNDS, true);
+ break;
+ case 0x7e0: // rte: return from exception (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ m_xip &= ~IP_V;
+
+ m_nip = m_cr[SNIP];
+ m_nop = m_inst_cache.read_dword(m_nip & IP_A);
+
+ m_fip = m_cr[SFIP];
+
+ m_sb = m_cr[SSBR];
+ m_cr[PSR] = m_cr[EPSR];
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+
+ case 0x040: // ld.hu: load half word unsigned
+ m_r[D] = m_data_space.read_word(m_r[S1] + m_r[S2]);
+ break;
+ case 0x048: // ld.hu.usr: load half word unsigned user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = m_data_space.read_word(m_r[S1] + m_r[S2]);
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x060: // ld.b: load byte unsigned
+ m_r[D] = m_data_space.read_byte(m_r[S1] + m_r[S2]);
+ break;
+ case 0x068: // ld.b.usr: load byte unsigned user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = m_data_space.read_byte(m_r[S1] + m_r[S2]);
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x080: // ld.d: load double word
+ m_r[D0] = m_data_space.read_dword(m_r[S1] + m_r[S2] + 0);
+ m_r[D1] = m_data_space.read_dword(m_r[S1] + m_r[S2] + 4);
+ break;
+ case 0x088: // ld.d.usr: load double word user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ m_r[D0] = m_data_space.read_dword(m_r[S1] + m_r[S2] + 0);
+ m_r[D1] = m_data_space.read_dword(m_r[S1] + m_r[S2] + 4);
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x0a0: // ld: load word
+ m_r[D] = m_data_space.read_dword(m_r[S1] + m_r[S2]);
+ break;
+ case 0x0a8: // ld.usr: load word user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = m_data_space.read_dword(m_r[S1] + m_r[S2]);
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x0c0: // ld.h: load half word
+ m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + m_r[S2])));
+ break;
+ case 0x0c8: // ld.h.usr: load half word user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + m_r[S2])));
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x0e0: // ld.b: load byte
+ m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + m_r[S2])));
+ break;
+ case 0x0e8: // ld.b.usr: load byte user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + m_r[S2])));
+ else
+ exception(E_PRIVILEGE);
+ break;
+
+ case 0x050: // ld.hu: load half word unsigned (scaled)
+ m_r[D] = m_data_space.read_word(m_r[S1] + (m_r[S2] << 1));
+ break;
+ case 0x058: // ld.hu.usr: load half word unsigned user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = m_data_space.read_word(m_r[S1] + (m_r[S2] << 1));
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x070: // ld.b: load byte unsigned (scaled)
+ m_r[D] = m_data_space.read_byte(m_r[S1] + (m_r[S2] << 0));
+ break;
+ case 0x078: // ld.b.usr: load byte unsigned user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = m_data_space.read_byte(m_r[S1] + (m_r[S2] << 0));
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x090: // ld.d: load double word (scaled)
+ m_r[D0] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 3) + 0);
+ m_r[D1] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 3) + 4);
+ break;
+ case 0x098: // ld.d.usr: load double word user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ m_r[D0] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 3) + 0);
+ m_r[D1] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 3) + 4);
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x0b0: // ld: load word (scaled)
+ m_r[D] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 2));
+ break;
+ case 0x0b8: // ld.usr: load word user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = m_data_space.read_dword(m_r[S1] + (m_r[S2] << 2));
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x0d0: // ld.h: load half word (scaled)
+ m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + (m_r[S2] << 1))));
+ break;
+ case 0x0d8: // ld.h.usr: load half word user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = s32(s16(m_data_space.read_word(m_r[S1] + (m_r[S2] << 1))));
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x0f0: // ld.b: load byte (scaled)
+ m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + (m_r[S2] << 1))));
+ break;
+ case 0x0f8: // ld.b.usr: load byte user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_r[D] = s32(s8(m_data_space.read_byte(m_r[S1] + (m_r[S2] << 1))));
+ else
+ exception(E_PRIVILEGE);
+ break;
+
+ case 0x100: // st.d: store double word
+ m_data_space.write_dword(m_r[S1] + m_r[S2] + 0, u32(m_r[D0]));
+ m_data_space.write_dword(m_r[S1] + m_r[S2] + 4, u32(m_r[D1]));
+ break;
+ case 0x108: // st.d.usr: store double word user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ m_data_space.write_dword(m_r[S1] + m_r[S2] + 0, u32(m_r[D0]));
+ m_data_space.write_dword(m_r[S1] + m_r[S2] + 4, u32(m_r[D1]));
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x120: // st: store word
+ m_data_space.write_dword(m_r[S1] + m_r[S2], u32(m_r[D]));
+ break;
+ case 0x128: // st.usr: store word user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_data_space.write_dword(m_r[S1] + m_r[S2], u32(m_r[D]));
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x140: // st.h: store half word
+ m_data_space.write_word(m_r[S1] + m_r[S2], u16(m_r[D]));
+ break;
+ case 0x148: // st.h.usr: store half word user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_data_space.write_word(m_r[S1] + m_r[S2], u16(m_r[D]));
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x160: // st.b: store byte
+ m_data_space.write_byte(m_r[S1] + m_r[S2], u8(m_r[D]));
+ break;
+ case 0x168: // st.b.usr: store byte user (privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_data_space.write_byte(m_r[S1] + m_r[S2], u8(m_r[D]));
+ else
+ exception(E_PRIVILEGE);
+ break;
+
+ case 0x110: // st.d: store double word (scaled)
+ m_data_space.write_dword(m_r[S1] + (m_r[S2] << 3) + 0, u32(m_r[D0]));
+ m_data_space.write_dword(m_r[S1] + (m_r[S2] << 3) + 4, u32(m_r[D1]));
+ break;
+ case 0x118: // st.d.usr: store double word user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ {
+ m_data_space.write_dword(m_r[S1] + (m_r[S2] << 3) + 0, u32(m_r[D0]));
+ m_data_space.write_dword(m_r[S1] + (m_r[S2] << 3) + 4, u32(m_r[D1]));
+ }
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x130: // st: store word (scaled)
+ m_data_space.write_dword(m_r[S1] + (m_r[S2] << 2), u32(m_r[D]));
+ break;
+ case 0x138: // st.usr: store word user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_data_space.write_dword(m_r[S1] + (m_r[S2] << 2), u32(m_r[D]));
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x150: // st.h: store half word (scaled)
+ m_data_space.write_word(m_r[S1] + (m_r[S2] << 1), u16(m_r[D]));
+ break;
+ case 0x158: // st.h.usr: store half word user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_data_space.write_word(m_r[S1] + (m_r[S2] << 1), u16(m_r[D]));
+ else
+ exception(E_PRIVILEGE);
+ break;
+ case 0x170: // st.b: store byte (scaled)
+ m_data_space.write_byte(m_r[S1] + (m_r[S2] << 0), u8(m_r[D]));
+ break;
+ case 0x178: // st.b.usr: store byte user (scaled, privileged)
+ if (m_cr[PSR] & PSR_MODE)
+ m_data_space.write_byte(m_r[S1] + (m_r[S2] << 0), u8(m_r[D]));
+ else
+ exception(E_PRIVILEGE);
+ break;
+
+ case 0x180: // lda.d: load address double word
+ case 0x1a0: // lda: load address word
+ case 0x1c0: // lda.h: load address half word
+ case 0x1e0: // lda.b: load address byte
+ m_r[D] = m_r[S1] + m_r[S2];
+ break;
+ case 0x190: // lda.d: load address double word (scaled)
+ m_r[D] = m_r[S1] + (m_r[S2] << 3);
+ break;
+ case 0x1b0: // lda: load address word (scaled)
+ m_r[D] = m_r[S1] + (m_r[S2] << 2);
+ break;
+ case 0x1d0: // lda.h: load address half word (scaled)
+ m_r[D] = m_r[S1] + (m_r[S2] << 1);
+ break;
+ case 0x1f0: // lda.b: load address byte (scaled)
+ m_r[D] = m_r[S1] + (m_r[S2] << 0);
+ break;
+ default:
+ exception(E_UNIMPLEMENTED);
+ break;
+ }
+ break;
+ case 0x3e: // tbnd: trap on bounds check (immediate)
+ if (m_r[S1] > IMM16)
+ exception(E_BOUNDS, true);
+ break;
+ case 0x3f:
+ exception(E_UNIMPLEMENTED);
+ break;
+ }
+
+ m_r[0] = 0;
}
void mc88100_device::execute_set_input(int inputnum, int state)
{
- // TODO
+ if (inputnum == INPUT_LINE_IRQ0)
+ m_int_state = bool(state);
+}
+
+void mc88100_device::set_cr(unsigned const cr, u32 const data)
+{
+ switch (cr)
+ {
+ case PID:
+ case SXIP:
+ // read-only
+ break;
+
+ case PSR:
+ case EPSR:
+ m_cr[cr] = (m_cr[cr] & ~PSR_MASK) | (data & PSR_MASK);
+ break;
+
+ case VBR:
+ m_cr[cr] = data & VBR_MASK;
+ break;
+
+ case SSBR: case SNIP: case SFIP:
+ case DMT0: case DMD0: case DMA0:
+ case DMT1: case DMD1: case DMA1:
+ case DMT2: case DMD2: case DMA2:
+ case SR0: case SR1: case SR2: case SR3:
+ m_cr[cr] = data;
+ break;
+
+ default:
+ // unknown register
+ logerror("set_cr unknown register %d data 0x%08x xip 0x%08x\n", cr, data, m_xip);
+ break;
+ }
+}
+
+void mc88100_device::set_fcr(unsigned const fcr, u32 const data)
+{
+ switch (fcr)
+ {
+ case FPECR:
+ m_fcr[fcr] = data & FPECR_MASK;
+ break;
+
+ case FPHS1: case FPLS1:
+ case FPHS2: case FPLS2:
+ case FPPT:
+ case FPRH: case FPRL:
+ case FPIT:
+ // read-only
+ break;
+
+ case FPSR:
+ m_fcr[fcr] = data & FPSR_MASK;
+ break;
+
+ case FPCR:
+ switch (BIT(data, 14, 2))
+ {
+ case 0: softfloat_roundingMode = softfloat_round_near_even; break;
+ case 1: softfloat_roundingMode = softfloat_round_minMag; break;
+ case 2: softfloat_roundingMode = softfloat_round_min; break;
+ case 3: softfloat_roundingMode = softfloat_round_max; break;
+ }
+
+ m_fcr[fcr] = data & FPCR_MASK;
+ break;
+
+ default:
+ // unknown register
+ logerror("set_fcr unknown register %d data 0x%08x xip 0x%08x\n", fcr, data, m_xip);
+ break;
+ }
+}
+
+void mc88100_device::exception(unsigned vector, bool const trap)
+{
+ LOGMASKED(LOG_EXCEPTION, "exception %u xip 0x%08x\n", vector, m_xip & IP_A);
+
+ if (!(m_cr[PSR] & PSR_SFRZ))
+ m_cr[EPSR] = m_cr[PSR];
+ else if (!trap)
+ vector = E_ERROR;
+
+ m_cr[PSR] |= PSR_MODE | PSR_SFD1 | PSR_IND | PSR_SFRZ;
+ m_sb = 0;
+
+ // invalidate execution and next instruction pointers
+ m_xip &= ~IP_V;
+ m_nip &= ~IP_V;
+
+ // set fetch instruction pointer
+ m_fip = m_cr[VBR] | (vector << 3) | IP_V;
+
+ // notify debugger
+ if ((vector != E_INTERRUPT) && (machine().debug_flags & DEBUG_FLAG_ENABLED))
+ debug()->exception_hook(vector);
+}
+
+bool mc88100_device::condition(unsigned const m5, u32 const src) const
+{
+ bool const sign = BIT(src, 31);
+ bool const zero = !BIT(src, 0, 31);
+
+ return BIT(m5, sign * 2 + zero);
+}
+
+enum cmp_mask : u32
+{
+ CMP_EQ = 0x0000'0004, // equal
+ CMP_NE = 0x0000'0008, // not equal
+ CMP_GT = 0x0000'0010, // signed greater than
+ CMP_LE = 0x0000'0020, // signed less than or equal
+ CMP_LT = 0x0000'0040, // signed less than
+ CMP_GE = 0x0000'0080, // signed greater than or equal
+ CMP_HI = 0x0000'0100, // unsigned greater than
+ CMP_LS = 0x0000'0200, // unsigned less than or equal
+ CMP_LO = 0x0000'0400, // unsigned less than
+ CMP_HS = 0x0000'0800, // unsigned greater than or equal
+};
+
+u32 mc88100_device::cmp(u32 const src1, u32 const src2) const
+{
+ u32 result = (CMP_HS | CMP_LS | CMP_GE | CMP_LE | CMP_EQ);
+
+ if (src1 != src2)
+ {
+ result = CMP_NE;
+
+ if (src1 > src2)
+ result |= (CMP_HS | CMP_HI);
+ else
+ result |= (CMP_LO | CMP_LS);
+
+ if (s32(src1) > s32(src2))
+ result |= (CMP_GE | CMP_GT);
+ else
+ result |= (CMP_LT | CMP_LE);
+ }
+
+ return result;
+}
+
+bool mc88100_device::carry(u32 const src1, u32 const src2, u32 const dest) const
+{
+ return ((BIT(src2, 31) && BIT(src1, 31)) || (!BIT(dest, 31) && (BIT(src2, 31) || BIT(src1, 31))));
+}
+
+bool mc88100_device::overflow(u32 const src1, u32 const src2, u32 const dest) const
+{
+ return (BIT(src2, 31) == BIT(src1, 31)) && (BIT(dest, 31) != BIT(src2, 31));
+}
+
+enum fcmp_mask : u32
+{
+ FCMP_NC = 0x0000'0001, // not comparable
+ FCMP_CP = 0x0000'0002, // comparable
+ FCMP_EQ = 0x0000'0004, // equal
+ FCMP_NE = 0x0000'0008, // not equal
+ FCMP_GT = 0x0000'0010, // signed greater than
+ FCMP_LE = 0x0000'0020, // signed less than or equal
+ FCMP_LT = 0x0000'0040, // signed less than
+ FCMP_GE = 0x0000'0080, // signed greater than or equal
+ FCMP_OU = 0x0000'0100, // out of range
+ FCMP_IB = 0x0000'0200, // in range or on boundary
+ FCMP_IN = 0x0000'0400, // in range
+ FCMP_OB = 0x0000'0800, // out of range or on boundary
+};
+
+u32 mc88100_device::fcmp(float64_t const src1, float64_t const src2)
+{
+ u32 result = FCMP_GE | FCMP_LE | FCMP_EQ | FCMP_CP;
+
+ // TODO: reserved operands exception
+
+ if (!f64_eq(src1, src2))
+ {
+ result = FCMP_NE | FCMP_CP;
+
+ if (f64_lt(src1, src2))
+ result |= (FCMP_LT | FCMP_LE);
+ else
+ result |= (FCMP_GE | FCMP_GT);
+ }
+
+ if (!BIT(src2.v, 63) && (result & FCMP_CP))
+ {
+ if (src1.v && (result & FCMP_NE))
+ {
+ if (BIT(src1.v, 63) || (result & FCMP_GT))
+ result |= FCMP_OU | FCMP_OB;
+ else if (!BIT(src1.v, 63) && (result & FCMP_LT))
+ result |= FCMP_IN | FCMP_IB;
+ }
+ else
+ result |= FCMP_OB | FCMP_IB;
+ }
+
+ return result;
+}
+
+void mc88100_device::fset(unsigned const td, unsigned const d, float64_t const data)
+{
+ switch (td)
+ {
+ case 0:
+ m_r[d] = f64_to_f32(data).v;
+ break;
+
+ case 1:
+ m_r[(d + 0) & 31] = u32(data.v >> 32);
+ m_r[(d + 1) & 31] = u32(data.v >> 0);
+ break;
+ }
}