summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/ns32000/ns32000.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/ns32000/ns32000.cpp')
-rw-r--r--src/devices/cpu/ns32000/ns32000.cpp5370
1 files changed, 3258 insertions, 2112 deletions
diff --git a/src/devices/cpu/ns32000/ns32000.cpp b/src/devices/cpu/ns32000/ns32000.cpp
index 9c059c3d099..123353299fb 100644
--- a/src/devices/cpu/ns32000/ns32000.cpp
+++ b/src/devices/cpu/ns32000/ns32000.cpp
@@ -4,64 +4,76 @@
#include "emu.h"
#include "ns32000.h"
-#include "ns32000dasm.h"
-#include "debugger.h"
+#include "ns32000d.h"
+#include "debug/debugcpu.h"
+
+#define LOG_TRANSLATE (1U << 1)
+//#define VERBOSE (LOG_TRANSLATE)
+
+#include "logmacro.h"
DEFINE_DEVICE_TYPE(NS32008, ns32008_device, "ns32008", "National Semiconductor NS32008")
DEFINE_DEVICE_TYPE(NS32016, ns32016_device, "ns32016", "National Semiconductor NS32016")
DEFINE_DEVICE_TYPE(NS32032, ns32032_device, "ns32032", "National Semiconductor NS32032")
+DEFINE_DEVICE_TYPE(NS32332, ns32332_device, "ns32332", "National Semiconductor NS32332")
+DEFINE_DEVICE_TYPE(NS32532, ns32532_device, "ns32532", "National Semiconductor NS32532")
/*
* TODO:
- * - prefetch queue
- * - fetch/ea/data/rmw bus cycles
- * - address translation/abort
- * - unimplemented instructions
- * - format 6: subp,addp
- * - format 8: movus/movsu
- * - format 14: rdval,wrval,lmr,smr
- * - cascaded interrupts
- * - opcode/operand/memory clock cycles
- * - 32332, 32532
+ * - instruction timing
+ * - prefetch queue/caches
+ * - overflow exceptions
+ * - debug registers
+ * - translation look-aside buffer
*/
enum psr_mask : u16
{
// accessible in user mode
- PSR_C = 0x0001, // carry/borrow condition
- PSR_T = 0x0002, // trace trap enable
- PSR_L = 0x0004, // less than condition
- // unused
- // unused
- PSR_F = 0x0020, // general condition
- PSR_Z = 0x0040, // zero condition
- PSR_N = 0x0080, // negative condition
+ PSR_C = 0x0001, // carry/borrow condition
+ PSR_T = 0x0002, // trace trap enable
+ PSR_L = 0x0004, // less than condition
+ // unused
+ PSR_V = 0x0010, // (32532 only) enable overflow trap
+ PSR_F = 0x0020, // general condition
+ PSR_Z = 0x0040, // zero condition
+ PSR_N = 0x0080, // negative condition
// accessible in supervisor mode
- PSR_U = 0x0100, // user mode
- PSR_S = 0x0200, // stack pointer select
- PSR_P = 0x0400, // prevent multiple trace trap
- PSR_I = 0x0800, // interrupt enable
- // unused
- // unused
- // unused
- // unused
+ PSR_U = 0x0100, // user mode
+ PSR_S = 0x0200, // stack pointer select
+ PSR_P = 0x0400, // prevent multiple trace trap
+ PSR_I = 0x0800, // interrupt enable
+ // unused
+ // unused
+ // unused
+ // unused
};
enum cfg_mask : u32
{
- CFG_I = 0x01, // vectored interrupts
- CFG_F = 0x02, // fpu present
- CFG_M = 0x04, // mmu present
- CFG_C = 0x08, // custom coprocessor present
+ CFG_I = 0x0001, // vectored interrupts
+ CFG_F = 0x0002, // fpu present
+ CFG_M = 0x0004, // mmu present
+ CFG_C = 0x0008, // custom coprocessor present
+ CFG_FF = 0x0010, // (32332 only) fast fpu protocol
+ CFG_FM = 0x0020, // (32332 only) fast mmu protocol
+ CFG_FC = 0x0040, // (32332 only) fast custom coprocessor protocol
+ CFG_P = 0x0080, // (32332 only) page size >= 4kb
+ CFG_DE = 0x0100, // (32532 only) direct exception mode enable
+ CFG_DC = 0x0200, // (32532 only) data cache enable
+ CFG_LDC = 0x0400, // (32532 only) lock data cache
+ CFG_IC = 0x0800, // (32532 only) instruction cache enable
+ CFG_LIC = 0x1000, // (32532 only) lock instruction cache
+ CFG_PF = 0x2000, // (32532 only) pipelined floating-point execution
};
-enum trap_type : unsigned
+enum exception_type : unsigned
{
NVI = 0, // non-vectored interrupt
NMI = 1, // non-maskable interrupt
ABT = 2, // abort
- FPU = 3, // floating point unit
+ SLV = 3, // slave processor
ILL = 4, // illegal operation
SVC = 5, // supervisor call
DVZ = 6, // integer divide by zero
@@ -69,17 +81,33 @@ enum trap_type : unsigned
BPT = 8, // breakpoint instruction
TRC = 9, // instruction trace
UND = 10, // undefined opcode
+ BER = 11, // (32332 only) bus error
+ RBE = 11, // (32532 only) restartable bus error
+ NBE = 12, // (32532 only) non-restartable bus error
+ OVF = 13, // (32532 only) integer overflow trap
+ DBG = 14, // (32532 only) debug trap
};
-static const u32 size_mask[] = { 0x000000ffU, 0x0000ffffU, 0x00000000U, 0xffffffffU };
+class ns32000_abort : public std::exception { };
+class ns32000_delay : public std::exception { };
-#define SP ((m_psr & PSR_S) ? m_sp1 : m_sp0)
+static const u32 size_mask[] = { 0x0000'00ffU, 0x0000'ffffU, 0x0000'0000U, 0xffff'ffffU };
-template <int Width>ns32000_device<Width>::ns32000_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int databits, int addrbits)
+template <int HighBits, int Width>ns32000_device<HighBits, Width>::ns32000_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: cpu_device(mconfig, type, tag, owner, clock)
- , m_program_config("program", ENDIANNESS_LITTLE, databits, addrbits, 0)
- , m_interrupt_config("interrupt", ENDIANNESS_LITTLE, databits, addrbits, 0)
+ , m_address_mask(util::make_bitmask<u32>(HighBits))
+ , m_program_config("program", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
+ , m_iam_config("iam", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
+ , m_iac_config("iac", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
+ , m_eim_config("eim", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
+ , m_eic_config("eic", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
+ , m_sif_config("sif", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
+ , m_nif_config("nif", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
+ , m_odt_config("odt", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
+ , m_rmw_config("rmw", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
+ , m_ear_config("ear", ENDIANNESS_LITTLE, 8 << Width, HighBits, 0)
, m_fpu(*this, finder_base::DUMMY_TAG)
+ , m_mmu(*this, finder_base::DUMMY_TAG)
, m_icount(0)
, m_pc(0)
, m_sb(0)
@@ -89,9 +117,7 @@ template <int Width>ns32000_device<Width>::ns32000_device(const machine_config &
, m_intbase(0)
, m_psr(0)
, m_mod(0)
- , m_cfg(0)
- , m_r{0}
- , m_f{0}
+ , m_r{}
, m_nmi_line(false)
, m_int_line(false)
, m_wait(false)
@@ -100,24 +126,40 @@ template <int Width>ns32000_device<Width>::ns32000_device(const machine_config &
}
ns32008_device::ns32008_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : ns32000_device(mconfig, NS32008, tag, owner, clock, 8, 24)
+ : ns32000_device(mconfig, NS32008, tag, owner, clock)
{
}
ns32016_device::ns32016_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : ns32000_device(mconfig, NS32016, tag, owner, clock, 16, 24)
+ : ns32000_device(mconfig, NS32016, tag, owner, clock)
{
}
ns32032_device::ns32032_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : ns32000_device(mconfig, NS32032, tag, owner, clock, 32, 24)
+ : ns32000_device(mconfig, NS32032, tag, owner, clock)
+{
+}
+
+ns32332_device::ns32332_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ns32000_device(mconfig, NS32332, tag, owner, clock)
+{
+}
+
+ns32532_device::ns32532_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : ns32000_device(mconfig, NS32532, tag, owner, clock)
+ , ns32000_mmu_interface(mconfig, *this)
+ , m_pt1_config("pt1", ENDIANNESS_LITTLE, 32, 32, 0)
+ , m_pt2_config("pt2", ENDIANNESS_LITTLE, 32, 32, 0)
{
}
-template <int Width> void ns32000_device<Width>::device_start()
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::device_start()
{
set_icountptr(m_icount);
+ save_item(NAME(m_ssp));
+ save_item(NAME(m_sps));
+
save_item(NAME(m_pc));
save_item(NAME(m_sb));
save_item(NAME(m_fp));
@@ -129,7 +171,6 @@ template <int Width> void ns32000_device<Width>::device_start()
save_item(NAME(m_cfg));
save_item(NAME(m_r));
- save_item(NAME(m_f));
save_item(NAME(m_nmi_line));
save_item(NAME(m_int_line));
@@ -149,7 +190,7 @@ template <int Width> void ns32000_device<Width>::device_start()
state_add(index++, "INTBASE", m_intbase);
state_add(index++, "PSR", m_psr);
state_add(index++, "MOD", m_mod);
- state_add(index++, "CFG", m_cfg);
+ state_add(index++, "CFG", m_cfg).formatstr("%5s");
// general registers
for (unsigned i = 0; i < 8; i++)
@@ -158,12 +199,16 @@ template <int Width> void ns32000_device<Width>::device_start()
// floating point registers
if (m_fpu)
m_fpu->state_add(*this, index);
+
+ // memory management registers
+ if (m_mmu)
+ m_mmu->state_add(*this, index);
}
-template <int Width> void ns32000_device<Width>::device_reset()
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::device_reset()
{
for (std::pair<int, address_space_config const *> s : memory_space_config())
- space(has_configured_map(s.first) ? s.first : 0).cache(m_bus[s.first]);
+ space(has_configured_map(s.first) ? s.first : 0).specific(m_bus[s.first]);
m_pc = 0;
m_psr = 0;
@@ -174,12 +219,12 @@ template <int Width> void ns32000_device<Width>::device_reset()
m_wait = false;
}
-template <int Width> void ns32000_device<Width>::state_string_export(device_state_entry const &entry, std::string &str) const
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::state_string_export(device_state_entry const &entry, std::string &str) const
{
switch (entry.index())
{
case STATE_GENFLAGS:
- str = string_format("%c%c%c%c%c%c%c%c%c%c",
+ str = string_format("%c%c%c%c%c%c%c%c%c%c%c",
(m_psr & PSR_I) ? 'I' : '.',
(m_psr & PSR_P) ? 'P' : '.',
(m_psr & PSR_S) ? 'S' : '.',
@@ -187,42 +232,281 @@ template <int Width> void ns32000_device<Width>::state_string_export(device_stat
(m_psr & PSR_N) ? 'N' : '.',
(m_psr & PSR_Z) ? 'Z' : '.',
(m_psr & PSR_F) ? 'F' : '.',
+ (m_psr & PSR_V) ? 'V' : '.',
(m_psr & PSR_L) ? 'L' : '.',
(m_psr & PSR_T) ? 'T' : '.',
(m_psr & PSR_C) ? 'C' : '.');
break;
+
+ case 8:
+ str = string_format("%c%c%c%c%c",
+ (m_cfg & CFG_P) ? 'P' : '.',
+ (m_cfg & CFG_C) ? ((m_cfg & CFG_FC) ? 'C' : 'c') : '.',
+ (m_cfg & CFG_M) ? ((m_cfg & CFG_FM) ? 'M' : 'm') : '.',
+ (m_cfg & CFG_F) ? ((m_cfg & CFG_FF) ? 'F' : 'f') : '.',
+ (m_cfg & CFG_I) ? 'I' : '.');
+ break;
+ }
+}
+
+/*
+ * The optional MMU and lack of alignment restrictions require memory accessors
+ * to handle several scenarios:
+ *
+ * MMU Aligned Pages Approach
+ * N Y N/A aligned handler
+ * N N N/A unaligned handler
+ * Y Y 1 translate address, aligned handler
+ * Y N 1 translate address, unaligned handler
+ * Y N 2 translate two addresses, use masks/shifts to align
+ * data, aligned handlers
+ *
+ * Underlying handlers further subdivide accesses by device bus width.
+ */
+template <int HighBits, int Width> template<typename T> T ns32000_device<HighBits, Width>::mem_read(unsigned st, u32 address, bool user, bool pfs)
+{
+ u32 physical = address;
+ ns32000_mmu_interface::translate_result tr = m_mmu ?
+ m_mmu->translate(m_bus[st].space(), st, physical, (m_psr & PSR_U) || user, false, pfs) : ns32000_mmu_interface::COMPLETE;
+
+ if (tr == ns32000_mmu_interface::COMPLETE)
+ {
+ u32 const unitmask = sizeof(T) - 1;
+ unsigned const offset = address & unitmask;
+
+ T data = 0;
+ m_ready = true;
+
+ if (offset)
+ {
+ u32 const pagemask = ((m_cfg & CFG_P) ? 0xfffU : 0x1ffU) & ~unitmask;
+
+ if (!m_mmu || (~address & pagemask))
+ {
+ // unaligned access, one page (or no mmu)
+ switch (sizeof(T))
+ {
+ case 1: abort(); // can't happen
+ case 2: data = m_bus[st].read_word_unaligned(physical); break;
+ case 4: data = m_bus[st].read_dword_unaligned(physical); break;
+ case 8: data = m_bus[st].read_qword_unaligned(physical); break;
+ }
+ }
+ else
+ {
+ // unaligned access, two pages
+
+ // first page
+ unsigned const shift = offset * 8;
+ switch (sizeof(T))
+ {
+ case 1: abort(); // can't happen
+ case 2: data |= m_bus[st].read_word(physical & ~unitmask, u16(-1) << shift) >> shift; break;
+ case 4: data |= m_bus[st].read_dword(physical & ~unitmask, u32(-1) << shift) >> shift; break;
+ case 8: data |= m_bus[st].read_qword(physical & ~unitmask, u64(-1) << shift) >> shift; break;
+ }
+
+ // second page
+ physical = (address + sizeof(T)) & ~unitmask;
+ tr = m_mmu->translate(m_bus[st].space(), st, physical, (m_psr & PSR_U) || user, false);
+
+ if (tr == ns32000_mmu_interface::COMPLETE)
+ {
+ unsigned const shift = (sizeof(T) - offset) * 8;
+ switch (sizeof(T))
+ {
+ case 1: abort(); // can't happen
+ case 2: data |= m_bus[st].read_word(physical & ~unitmask, u16(-1) >> shift) << shift; break;
+ case 4: data |= m_bus[st].read_dword(physical & ~unitmask, u32(-1) >> shift) << shift; break;
+ case 8: data |= m_bus[st].read_qword(physical & ~unitmask, u64(-1) >> shift) << shift; break;
+ }
+ }
+ else if (tr == ns32000_mmu_interface::ABORT)
+ throw ns32000_abort();
+ }
+ }
+ else
+ {
+ // aligned access
+ switch (sizeof(T))
+ {
+ case 1: data = m_bus[st].read_byte(physical); break;
+ case 2: data = m_bus[st].read_word(physical); break;
+ case 4: data = m_bus[st].read_dword(physical); break;
+ case 8: data = m_bus[st].read_qword(physical); break;
+ }
+ }
+
+ if (!m_ready)
+ throw ns32000_delay();
+ else
+ return data;
}
+ else if (tr == ns32000_mmu_interface::ABORT)
+ throw ns32000_abort();
+
+ return 0;
}
-template <int Width> s32 ns32000_device<Width>::displacement(unsigned &bytes)
+template <int HighBits, int Width> template<typename T> void ns32000_device<HighBits, Width>::mem_write(unsigned st, u32 address, u64 data, bool user)
{
- s32 disp = space(0).read_byte(m_pc + bytes);
- if (BIT(disp, 7))
+ u32 physical = address;
+ ns32000_mmu_interface::translate_result tr = m_mmu ?
+ m_mmu->translate(m_bus[st].space(), st, physical, (m_psr & PSR_U) || user, true) : ns32000_mmu_interface::COMPLETE;
+
+ if (tr == ns32000_mmu_interface::COMPLETE)
{
- if (BIT(disp, 6))
+ u32 const unitmask = sizeof(T) - 1;
+ unsigned const offset = address & unitmask;
+
+ m_ready = true;
+
+ if (offset)
+ {
+ u32 const pagemask = ((m_cfg & CFG_P) ? 0xfffU : 0x1ffU) & ~unitmask;
+
+ if (!m_mmu || (~address & pagemask))
+ {
+ // unaligned access, one page (or no mmu)
+ switch (sizeof(T))
+ {
+ case 1: abort(); // can't happen
+ case 2: m_bus[st].write_word_unaligned(physical, data); break;
+ case 4: m_bus[st].write_dword_unaligned(physical, data); break;
+ case 8: m_bus[st].write_qword_unaligned(physical, data); break;
+ }
+ }
+ else
+ {
+ // unaligned access, two pages
+
+ // first page
+ unsigned const shift = offset * 8;
+ switch (sizeof(T))
+ {
+ case 1: abort(); // can't happen
+ case 2: m_bus[st].write_word(physical & ~unitmask, data << shift, u16(-1) << shift); break;
+ case 4: m_bus[st].write_dword(physical & ~unitmask, data << shift, u32(-1) << shift); break;
+ case 8: m_bus[st].write_qword(physical & ~unitmask, data << shift, u64(-1) << shift); break;
+ }
+
+ // second page
+ physical = (address + sizeof(T)) & ~unitmask;
+ tr = m_mmu->translate(m_bus[st].space(), st, physical, (m_psr & PSR_U) || user, true);
+
+ if (tr == ns32000_mmu_interface::COMPLETE)
+ {
+ unsigned const shift = (sizeof(T) - offset) * 8;
+ switch (sizeof(T))
+ {
+ case 1: abort(); // can't happen
+ case 2: m_bus[st].write_word(physical & ~unitmask, data >> shift, u16(-1) >> shift); break;
+ case 4: m_bus[st].write_dword(physical & ~unitmask, data >> shift, u32(-1) >> shift); break;
+ case 8: m_bus[st].write_qword(physical & ~unitmask, data >> shift, u64(-1) >> shift); break;
+ }
+ }
+ else if (tr == ns32000_mmu_interface::ABORT)
+ throw ns32000_abort();
+ }
+ }
+ else
+ {
+ // aligned access
+ /*
+ * Tektronix 4132 firmware requires that MOVB rN,<mem> (where mem
+ * is a word-aligned memory address) drives a 16-bit value from the
+ * register onto the data bus (with /HBE deasserted). The effect is
+ * important when the data is being written to a fixed-width 16-bit
+ * register (Am9516 in this case), as the byte enables are ignored
+ * and a 16-bit value is latched. This code assumes the same effect
+ * occurs with word/dword-aligned MOVB/MOVW on the 32032 and 32332.
+ */
+ // TODO: verify how real hardware behaves
+ switch (sizeof(T))
+ {
+ case 1:
+ if (Width == 1)
+ {
+ unsigned const shift = (physical & 1) * 8;
+
+ m_bus[st].write_word(physical, data << shift, 0xffU << shift);
+ }
+ else if (Width == 2)
+ {
+ unsigned const shift = (physical & 3) * 8;
+
+ m_bus[st].write_dword(physical, data << shift, 0xffU << shift);
+ }
+ else
+ m_bus[st].write_byte(physical, data);
+ break;
+ case 2:
+ if (Width == 2)
+ {
+ unsigned const shift = (physical & 2) * 8;
+
+ m_bus[st].write_dword(physical, data << shift, 0xffffU << shift);
+ }
+ else
+ m_bus[st].write_word(physical, data);
+ break;
+ case 4: m_bus[st].write_dword(physical, data); break;
+ case 8: m_bus[st].write_qword(physical, data); break;
+ }
+ }
+
+ if (!m_ready)
+ throw ns32000_delay();
+ }
+ else if (tr == ns32000_mmu_interface::ABORT)
+ throw ns32000_abort();
+}
+
+/*
+ * TODO: this function still doesn't accurately emulate instruction fetch:
+ * - prefetch or opportunistic refill
+ * - buffer re-alignment
+ * - sequential fetch translation optimization
+ * - instruction fetch cycles
+ */
+template <int HighBits, int Width> template<typename T> T ns32000_device<HighBits, Width>::fetch(unsigned &bytes)
+{
+ T const data = mem_read<T>(m_sequential ? ns32000::ST_SIF : ns32000::ST_NIF, m_pc + bytes, false, bytes == 0);
+
+ bytes += sizeof(T);
+ m_sequential = true;
+
+ return data;
+}
+
+template <int HighBits, int Width> s32 ns32000_device<HighBits, Width>::displacement(unsigned &bytes)
+{
+ u32 const byte0 = fetch<u8>(bytes);
+ if (BIT(byte0, 7))
+ {
+ if (BIT(byte0, 6))
{
// double word displacement
- disp = s32(swapendian_int32(space(0).read_dword_unaligned(m_pc + bytes)) << 2) >> 2;
- bytes += 4;
+ u32 const byte1 = fetch<u8>(bytes);
+ u32 const byte2 = fetch<u8>(bytes);
+ u32 const byte3 = fetch<u8>(bytes);
+
+ return util::sext((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3, 30);
}
else
{
// word displacement
- disp = s16(swapendian_int16(space(0).read_word_unaligned(m_pc + bytes)) << 2) >> 2;
- bytes += 2;
+ u8 const byte1 = fetch<u8>(bytes);
+
+ return util::sext((byte0 << 8) | byte1, 14);
}
}
else
- {
// byte displacement
- disp = s8(disp << 1) >> 1;
- bytes += 1;
- }
-
- return disp;
+ return util::sext(byte0, 7);
}
-template <int Width> void ns32000_device<Width>::decode(addr_mode *mode, unsigned &bytes)
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::decode(addr_mode *mode, unsigned &bytes)
{
bool scaled[] = { false, false };
@@ -231,10 +515,13 @@ template <int Width> void ns32000_device<Width>::decode(addr_mode *mode, unsigne
{
if (mode[i].gen > 0x1b)
{
- u8 const index = space(0).read_byte(m_pc + bytes);
- bytes += 1;
+ u8 const index = fetch<u8>(bytes);
mode[i].disp = m_r[index & 7] << (mode[i].gen & 3);
+
+ static const unsigned tea[] = { 5, 7, 8, 10 };
+ mode[i].tea = tea[mode[i].gen & 3];
+
mode[i].gen = index >> 3;
scaled[i] = true;
}
@@ -252,33 +539,41 @@ template <int Width> void ns32000_device<Width>::decode(addr_mode *mode, unsigne
{
mode[i].base = m_r[mode[i].gen];
mode[i].type = MEM;
+ mode[i].tea += 5;
}
else
+ {
mode[i].type = REG;
+ mode[i].tea += 2;
+ }
break;
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
// register relative
mode[i].base = m_r[mode[i].gen & 7] + displacement(bytes);
mode[i].type = MEM;
+ mode[i].tea += 5;
break;
case 0x10:
// frame memory relative disp2(disp1(FP))
mode[i].base = m_fp + displacement(bytes);
mode[i].disp += displacement(bytes);
- mode[i].type = IND;
+ mode[i].type = REL;
+ mode[i].tea += 7 + top(SIZE_D, mode[i].base);
break;
case 0x11:
// stack memory relative disp2(disp1(SP))
- mode[i].base = SP + displacement(bytes);
+ mode[i].base = SP() + displacement(bytes);
mode[i].disp += displacement(bytes);
- mode[i].type = IND;
+ mode[i].type = REL;
+ mode[i].tea += 7 + top(SIZE_D, mode[i].base);
break;
case 0x12:
// static memory relative disp2(disp1(SB))
mode[i].base = m_sb + displacement(bytes);
mode[i].disp += displacement(bytes);
- mode[i].type = IND;
+ mode[i].type = REL;
+ mode[i].tea += 7 + top(SIZE_D, mode[i].base);
break;
case 0x13:
// reserved
@@ -287,55 +582,81 @@ template <int Width> void ns32000_device<Width>::decode(addr_mode *mode, unsigne
// immediate
switch (mode[i].size)
{
- case SIZE_B: mode[i].imm = space(0).read_byte(m_pc + bytes); break;
- case SIZE_W: mode[i].imm = swapendian_int16(space(0).read_word_unaligned(m_pc + bytes)); break;
- case SIZE_D: mode[i].imm = swapendian_int32(space(0).read_dword_unaligned(m_pc + bytes)); break;
- case SIZE_Q: mode[i].imm = swapendian_int64(space(0).read_qword_unaligned(m_pc + bytes)); break;
+ case SIZE_B: mode[i].imm = fetch<u8>(bytes); break;
+ case SIZE_W: mode[i].imm = swapendian_int16(fetch<u16>(bytes)); break;
+ case SIZE_D: mode[i].imm = swapendian_int32(fetch<u32>(bytes)); break;
+ case SIZE_Q: mode[i].imm = swapendian_int64(fetch<u64>(bytes)); break;
}
- bytes += mode[i].size + 1;
mode[i].type = IMM;
+ mode[i].tea += 4;
break;
case 0x15:
// absolute @disp
mode[i].base = displacement(bytes);
mode[i].type = MEM;
+ mode[i].tea += 4;
break;
case 0x16:
// external EXT(disp1) + disp2
mode[i].base = displacement(bytes) * 4;
mode[i].disp += displacement(bytes);
mode[i].type = EXT;
+ mode[i].tea += 11 + top(SIZE_D, m_mod) + top(SIZE_D, mode[i].base);
break;
case 0x17:
// top of stack TOS
- mode[i].base = SP;
+ mode[i].base = SP();
mode[i].type = scaled[i] ? MEM : TOS;
+ if (!scaled[i])
+ {
+ if (mode[i].access == WRITE)
+ mode[i].tea += 4;
+ else if (mode[i].access == READ)
+ mode[i].tea += 2;
+ else
+ mode[i].tea += 3;
+ }
+ else
+ mode[i].tea += 4;
break;
case 0x18:
// frame memory disp(FP)
mode[i].base = m_fp + displacement(bytes);
mode[i].type = MEM;
+ mode[i].tea += 5;
break;
case 0x19:
// stack memory disp(SP)
- mode[i].base = SP + displacement(bytes);
+ mode[i].base = SP() + displacement(bytes);
mode[i].type = MEM;
+ mode[i].tea += 5;
break;
case 0x1a:
// static memory disp(SB)
mode[i].base = m_sb + displacement(bytes);
mode[i].type = MEM;
+ mode[i].tea += 5;
break;
case 0x1b:
// program memory *+disp
mode[i].base = m_pc + displacement(bytes);
mode[i].type = MEM;
+ mode[i].tea += 5;
break;
}
}
}
+template <int HighBits, int Width> u32 &ns32000_device<HighBits, Width>::SP()
+{
+ return SP(m_psr & PSR_S);
+}
+
+template <int HighBits, int Width> u32 &ns32000_device<HighBits, Width>::SP(bool user)
+{
+ return user ? m_sp1 : m_sp0;
+}
-template <int Width> u32 ns32000_device<Width>::ea(addr_mode const mode)
+template <int HighBits, int Width> u32 ns32000_device<HighBits, Width>::ea(addr_mode const mode)
{
u32 base;
@@ -345,13 +666,13 @@ template <int Width> u32 ns32000_device<Width>::ea(addr_mode const mode)
base = m_r[mode.gen];
break;
- case IND:
- base = m_bus[12].read_dword_unaligned(mode.base);
+ case REL:
+ base = mem_read<u32>(ns32000::ST_EAR, mode.base);
break;
case EXT:
- base = m_bus[12].read_dword_unaligned(m_mod + 4);
- base = m_bus[12].read_dword_unaligned(base + mode.base);
+ base = mem_read<u32>(ns32000::ST_EAR, m_mod + 4);
+ base = mem_read<u32>(ns32000::ST_EAR, base + mode.base);
break;
default:
@@ -362,49 +683,36 @@ template <int Width> u32 ns32000_device<Width>::ea(addr_mode const mode)
return base + mode.disp;
}
-template <int Width> u64 ns32000_device<Width>::gen_read(addr_mode mode)
+template <int HighBits, int Width> u64 ns32000_device<HighBits, Width>::gen_read(addr_mode mode)
{
- u64 data = 0;
+ if (mode.type == IMM)
+ return mode.imm;
- switch (mode.type)
- {
- case IMM:
- data = mode.imm;
- break;
+ if (mode.type == REG)
+ return m_r[mode.gen] & size_mask[mode.size];
- case REG:
- data = m_r[mode.gen] & size_mask[mode.size];
- break;
+ unsigned const st = (mode.access == RMW) ? ns32000::ST_RMW : ns32000::ST_ODT;
+ u32 const address = (mode.type == TOS) ? SP() : ea(mode);
+ u64 data = 0;
- case TOS:
- switch (mode.size)
- {
- case SIZE_B: data = space(0).read_byte(SP); break;
- case SIZE_W: data = space(0).read_word_unaligned(SP); break;
- case SIZE_D: data = space(0).read_dword_unaligned(SP); break;
- case SIZE_Q: data = space(0).read_qword_unaligned(SP); break;
- }
+ switch (mode.size)
+ {
+ case SIZE_B: data = mem_read<u8>(st, address); break;
+ case SIZE_W: data = mem_read<u16>(st, address); break;
+ case SIZE_D: data = mem_read<u32>(st, address); break;
+ case SIZE_Q: data = mem_read<u64>(st, address); break;
+ }
- // post-increment stack pointer
- if (mode.access == READ)
- SP += mode.size + 1;
- break;
+ m_icount -= top(mode.size, address);
- default:
- switch (mode.size)
- {
- case SIZE_B: data = space(0).read_byte(ea(mode)); break;
- case SIZE_W: data = space(0).read_word_unaligned(ea(mode)); break;
- case SIZE_D: data = space(0).read_dword_unaligned(ea(mode)); break;
- case SIZE_Q: data = space(0).read_qword_unaligned(ea(mode)); break;
- }
- break;
- }
+ // post-increment stack pointer
+ if (mode.type == TOS && mode.access == READ)
+ SP() += mode.size + 1;
return data;
}
-template <int Width> s64 ns32000_device<Width>::gen_read_sx(addr_mode mode)
+template <int HighBits, int Width> s64 ns32000_device<HighBits, Width>::gen_read_sx(addr_mode mode)
{
u64 data = gen_read(mode);
@@ -419,41 +727,32 @@ template <int Width> s64 ns32000_device<Width>::gen_read_sx(addr_mode mode)
return data;
}
-template <int Width> void ns32000_device<Width>::gen_write(addr_mode mode, u64 data)
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::gen_write(addr_mode mode, u64 data)
{
- switch (mode.type)
+ if (mode.type == REG)
{
- case REG:
m_r[mode.gen] = (m_r[mode.gen] & ~size_mask[mode.size]) | (data & size_mask[mode.size]);
- break;
+ return;
+ }
- case TOS:
- // pre-decrement stack pointer
- if (mode.access == WRITE)
- SP -= mode.size + 1;
+ // pre-decrement stack pointer
+ if (mode.type == TOS && mode.access == WRITE)
+ SP() -= mode.size + 1;
- switch (mode.size)
- {
- case SIZE_B: space(0).write_byte(SP, data); break;
- case SIZE_W: space(0).write_word_unaligned(SP, data); break;
- case SIZE_D: space(0).write_dword_unaligned(SP, data); break;
- case SIZE_Q: space(0).write_qword_unaligned(SP, data); break;
- }
- break;
+ u32 const address = (mode.type == TOS) ? SP() : ea(mode);
- default:
- switch (mode.size)
- {
- case SIZE_B: space(0).write_byte(ea(mode), data); break;
- case SIZE_W: space(0).write_word_unaligned(ea(mode), data); break;
- case SIZE_D: space(0).write_dword_unaligned(ea(mode), data); break;
- case SIZE_Q: space(0).write_qword_unaligned(ea(mode), data); break;
- }
- break;
+ switch (mode.size)
+ {
+ case SIZE_B: mem_write<u8>(ns32000::ST_ODT, address, data); break;
+ case SIZE_W: mem_write<u16>(ns32000::ST_ODT, address, data); break;
+ case SIZE_D: mem_write<u32>(ns32000::ST_ODT, address, data); break;
+ case SIZE_Q: mem_write<u64>(ns32000::ST_ODT, address, data); break;
}
+
+ m_icount -= top(mode.size, address);
}
-template <int Width> bool ns32000_device<Width>::condition(unsigned const cc)
+template <int HighBits, int Width> bool ns32000_device<HighBits, Width>::condition(unsigned const cc)
{
switch (cc & 15)
{
@@ -495,7 +794,7 @@ template <int Width> bool ns32000_device<Width>::condition(unsigned const cc)
return false;
}
-template <int Width> void ns32000_device<Width>::flags(u32 const src1, u32 const src2, u32 const dest, unsigned const size, bool const subtraction)
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::flags(u32 const src1, u32 const src2, u32 const dest, unsigned const size, bool const subtraction)
{
unsigned const sign_bit = (size + 1) * 8 - 1;
@@ -511,1392 +810,1072 @@ template <int Width> void ns32000_device<Width>::flags(u32 const src1, u32 const
m_psr |= PSR_F;
}
-template <int Width> void ns32000_device<Width>::interrupt(unsigned const vector, u32 const return_address, bool const trap)
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::interrupt(unsigned const trap)
{
- // clear trace pending flag
- if (vector == TRC)
- m_psr &= ~PSR_P;
+ if (machine().debug_enabled() && (trap > ABT))
+ debug()->exception_hook(trap);
- // push psr
- m_sp0 -= 2;
- space(0).write_word_unaligned(m_sp0, m_psr);
+ unsigned offset = trap * 4;
- // update psr
- if (trap)
- m_psr &= ~(PSR_P | PSR_S | PSR_U | PSR_T);
- else
- m_psr &= ~(PSR_I | PSR_P | PSR_S | PSR_U | PSR_T);
+ switch (trap)
+ {
+ case NVI:
+ // maskable interrupt
+ m_sps = m_psr;
+ m_psr &= ~(PSR_I | PSR_P | PSR_S | PSR_U | PSR_V | PSR_T);
+
+ if (m_cfg & CFG_I)
+ {
+ // acknowledge interrupt and read vector
+ s8 vector = mem_read<u8>(ns32000::ST_IAM, 0xffff'fe00U & m_address_mask);
+ if (vector < 0 && vector >= -16)
+ {
+ // vectored mode, cascaded
+ u32 const cascade = mem_read<u32>(ns32000::ST_ODT, m_intbase + vector * 4);
+
+ vector = mem_read<u8>(ns32000::ST_IAC, cascade);
+ }
+
+ offset = vector * 4;
+ }
+ else
+ // acknowledge non-vectored interrupt
+ mem_read<u8>(ns32000::ST_IAM, 0xffff'fe00U & m_address_mask);
+ break;
+
+ case NMI:
+ // non-maskable interrupt
+ m_sps = m_psr;
+ m_psr &= ~(PSR_I | PSR_P | PSR_S | PSR_U | PSR_V | PSR_T);
+
+ // acknowledge interrupt and discard vector
+ mem_read<u8>(ns32000::ST_IAM, 0xffff'ff00U & m_address_mask);
+ m_nmi_line = false;
+ break;
+
+ case ABT:
+ case BER:
+ // abort
+ SP() = m_ssp;
+ m_psr &= ~PSR_P;
+ m_sps = m_psr;
+ m_psr &= ~(PSR_I | PSR_S | PSR_U | PSR_V | PSR_T);
+ break;
- // fetch external procedure descriptor
- u32 const descriptor = space(0).read_dword_unaligned(m_intbase + vector * 4);
+ case TRC:
+ // trace trap
+ m_psr &= ~PSR_P;
+ m_sps = m_psr;
+ m_psr &= ~(PSR_S | PSR_U | PSR_V | PSR_T);
+ break;
- // push mod
- m_sp0 -= 2;
- space(0).write_word_unaligned(m_sp0, m_mod);
+ default:
+ // traps other than trace
+ SP() = m_ssp;
+ m_psr = m_sps;
+ if ((type() == NS32332 && trap == ILL) || (type() == NS32532 && (trap == ILL || trap == UND)))
+ m_sps &= ~PSR_P;
+ m_psr &= ~(PSR_P | PSR_S | PSR_U | PSR_V | PSR_T);
+ break;
+ }
+
+ // push saved program status and mod
+ m_sp0 -= 4;
+ mem_write<u32>(ns32000::ST_ODT, m_sp0, u32(m_sps) << 16 | m_mod);
// push return address
m_sp0 -= 4;
- space(0).write_dword_unaligned(m_sp0, return_address);
+ mem_write<u32>(ns32000::ST_ODT, m_sp0, m_pc);
- // update mod, sb, pc
- m_mod = u16(descriptor);
- m_sb = space(0).read_dword_unaligned(m_mod + 0);
- m_pc = space(0).read_dword_unaligned(m_mod + 8) + u16(descriptor >> 16);
+ if (!(m_cfg & CFG_DE))
+ {
+ // fetch external procedure descriptor
+ u32 const desc = mem_read<u32>(ns32000::ST_ODT, m_intbase + offset);
+
+ // update mod, sb, pc
+ m_mod = u16(desc);
+ m_sb = mem_read<u32>(ns32000::ST_ODT, m_mod + 0);
+ m_pc = mem_read<u32>(ns32000::ST_ODT, m_mod + 8) + (desc >> 16);
+ }
+ else
+ m_pc = mem_read<u32>(ns32000::ST_ODT, m_intbase + offset);
// TODO: flush queue
m_sequential = false;
- if (trap && (machine().debug_flags & DEBUG_FLAG_ENABLED))
- debug()->exception_hook(vector);
+ m_icount -= top(SIZE_W, m_sp0) * 2 + top(SIZE_W, m_intbase + offset) + top(SIZE_D, m_sp0) + top(SIZE_D, m_mod);
}
-template <int Width> void ns32000_device<Width>::execute_run()
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::lpr(unsigned reg, addr_mode const mode, bool user, unsigned &tex)
{
- while (m_icount > 0)
+ switch (reg)
{
- if (m_wait)
- {
- m_icount = 0;
- continue;
- }
-
- if (m_nmi_line)
+ case 0x0:
+ m_psr = ((m_psr & 0xff00) | u8(gen_read(mode))) & PSR_MSK();
+ break;
+ case 0x8:
+ m_fp = gen_read(mode);
+ break;
+ case 0x9:
+ SP() = gen_read(mode);
+ break;
+ case 0xa:
+ m_sb = gen_read(mode);
+ break;
+ case 0xd:
+ if (!user)
{
- // acknowledge interrupt and discard vector
- m_bus[4].read_byte(0xffff00);
- m_nmi_line = false;
-
- // service interrupt
- interrupt(NMI, m_pc, false);
+ u32 const src = gen_read(mode);
- // notify the debugger
- if (machine().debug_flags & DEBUG_FLAG_ENABLED)
- debug()->interrupt_hook(INPUT_LINE_NMI);
+ if (mode.size == SIZE_B)
+ m_psr = ((m_psr & 0xff00) | u8(src)) & PSR_MSK();
+ else
+ m_psr = src & PSR_MSK();
}
- else if (m_int_line && (m_psr & PSR_I))
- {
- // acknowledge interrupt and read vector
- s8 vector = m_bus[4].read_byte(0xfffe00);
-
- // check for non-vectored mode
- if (!(m_cfg & CFG_I))
- vector = NVI;
- else if (vector < 0)
- {
- // TODO: cascaded
- }
-
- // service interrupt
- interrupt(vector, m_pc, false);
+ else
+ interrupt(ILL);
+ break;
+ case 0xe:
+ if (!user)
+ m_intbase = gen_read(mode);
+ else
+ interrupt(ILL);
+ break;
+ case 0xf:
+ m_mod = gen_read(mode);
+ break;
+ default:
+ interrupt(UND);
+ break;
+ }
- // notify the debugger
- if (machine().debug_flags & DEBUG_FLAG_ENABLED)
- debug()->interrupt_hook(INPUT_LINE_IRQ0);
- }
+ // TODO: tcy 19-33
+ tex = mode.tea + 19;
+}
- // update trace pending
- if (m_psr & PSR_T)
- m_psr |= PSR_P;
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::spr(unsigned reg, addr_mode const mode, bool user, unsigned &tex)
+{
+ switch (reg)
+ {
+ case 0x0:
+ gen_write(mode, u8(m_psr));
+ break;
+ case 0x8:
+ gen_write(mode, m_fp);
+ break;
+ case 0x9:
+ gen_write(mode, SP());
+ break;
+ case 0xa:
+ gen_write(mode, m_sb);
+ break;
+ case 0xd:
+ if (!user)
+ gen_write(mode, m_psr);
else
- m_psr &= ~PSR_P;
-
- debugger_instruction_hook(m_pc);
+ interrupt(ILL);
+ break;
+ case 0xe:
+ if (!user)
+ gen_write(mode, m_intbase);
+ else
+ interrupt(ILL);
+ break;
+ case 0xf:
+ gen_write(mode, m_mod);
+ break;
+ default:
+ interrupt(UND);
+ break;
+ }
- u8 const opbyte = space(0).read_byte(m_pc);
- unsigned bytes = 1;
- unsigned tcy = 1;
- m_sequential = true;
+ // TODO: tcy 21-27
+ tex = mode.tea + 21;
+}
- if ((opbyte & 15) == 10)
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::execute_run()
+{
+ while (m_icount > 0)
+ {
+ if (m_wait)
{
- // format 0: cccc 1010
- // Bcond dst
- // disp
- s32 const dst = displacement(bytes);
-
- if (condition(opbyte >> 4))
- {
- m_pc += dst;
- m_sequential = false;
- tcy = 6;
- }
- else
- tcy = 7;
+ m_icount = 0;
+ continue;
}
- else if ((opbyte & 15) == 2)
+
+ try
{
- // format 1: oooo 0010
- switch (opbyte >> 4)
+ if (m_nmi_line)
{
- case 0x0:
- // BSR dst
- // disp
- {
- s32 const dst = displacement(bytes);
-
- SP -= 4;
- space(0).write_dword_unaligned(SP, m_pc + bytes);
+ // notify the debugger
+ if (machine().debug_enabled())
+ debug()->interrupt_hook(INPUT_LINE_NMI, m_pc);
- m_pc += dst;
- m_sequential = false;
- tcy = 6;
- }
- break;
- case 0x1:
- // RET constant
- // disp
- {
- s32 const constant = displacement(bytes);
-
- u32 const addr = space(0).read_dword_unaligned(SP);
- SP += 4 + constant;
-
- m_pc = addr;
- m_sequential = false;
- tcy = 2;
- }
- break;
- case 0x2:
- // CXP index
- // disp
- {
- s32 const index = displacement(bytes);
-
- u32 const link_base = space(0).read_dword_unaligned(m_mod + 4);
- u32 const descriptor = space(0).read_dword_unaligned(link_base + index * 4);
+ // service interrupt
+ interrupt(NMI);
+ }
+ else if (m_int_line && (m_psr & PSR_I))
+ {
+ // notify the debugger
+ if (machine().debug_enabled())
+ debug()->interrupt_hook(INPUT_LINE_IRQ0, m_pc);
- SP -= 4;
- space(0).write_dword_unaligned(SP, m_mod);
- SP -= 4;
- space(0).write_dword_unaligned(SP, m_pc + bytes);
+ // service interrupt
+ interrupt(NVI);
+ }
- m_mod = u16(descriptor);
- m_sb = space(0).read_dword_unaligned(m_mod + 0);
- m_pc = space(0).read_dword_unaligned(m_mod + 8) + u16(descriptor >> 16);
- m_sequential = false;
- tcy = 16;
- }
- break;
- case 0x3:
- // RXP constant
- // disp
- {
- s32 const constant = displacement(bytes);
+ // update trace pending
+ if (m_psr & PSR_T)
+ m_psr |= PSR_P;
+ else
+ m_psr &= ~PSR_P;
- m_pc = space(0).read_dword_unaligned(SP);
- SP += 4;
- m_mod = space(0).read_dword_unaligned(SP);
- SP += 4;
+ debugger_instruction_hook(m_pc);
- m_sb = space(0).read_dword_unaligned(m_mod + 0);
- SP += constant;
- m_sequential = false;
- tcy = 2;
- }
- break;
- case 0x4:
- // RETT constant
- // disp
- if (!(m_psr & PSR_U))
- {
- s32 const constant = displacement(bytes);
+ // save state
+ m_ssp = SP();
+ m_sps = m_psr;
- u32 &sp(SP);
- m_pc = space(0).read_dword_unaligned(sp);
- sp += 4;
- m_mod = space(0).read_word_unaligned(sp);
- sp += 2;
- m_psr = space(0).read_word_unaligned(sp);
- sp += 2;
+ unsigned bytes = 0;
+ u8 const opbyte = fetch<u8>(bytes);
+ unsigned tex = 1;
- m_sb = space(0).read_dword_unaligned(m_mod);
+ if ((opbyte & 15) == 10)
+ {
+ // format 0: cccc 1010
+ // Bcond dst
+ // disp
+ s32 const dst = displacement(bytes);
- SP += constant;
- m_sequential = false;
- tcy = 35;
- }
- else
- interrupt(ILL, m_pc);
- break;
- case 0x5:
- // RETI
- if (!(m_psr & PSR_U))
+ if (condition(BIT(opbyte, 4, 4)))
{
- // interrupt return bus cycle
- m_bus[6].read_byte(0xfffe00);
-
- u32 &sp(SP);
- m_pc = space(0).read_dword_unaligned(sp);
- sp += 4;
- m_mod = space(0).read_word_unaligned(sp);
- sp += 2;
- m_psr = space(0).read_word_unaligned(sp);
- sp += 2;
-
- m_sb = space(0).read_dword_unaligned(m_mod);
+ m_pc += dst;
m_sequential = false;
- tcy = 39;
+ tex = 6;
}
else
- interrupt(ILL, m_pc);
- break;
- case 0x6:
- // SAVE reglist
- // imm
+ tex = 7;
+ }
+ else if ((opbyte & 15) == 2)
+ {
+ // format 1: oooo 0010
+ switch (BIT(opbyte, 4, 4))
{
- u8 const reglist = space(0).read_byte(m_pc + bytes++);
-
- tcy = 13;
- for (unsigned i = 0; i < 8; i++)
+ case 0x0:
+ // BSR dst
+ // disp
{
- if (BIT(reglist, i))
- {
- SP -= 4;
- space(0).write_dword_unaligned(SP, m_r[i]);
- tcy += 4;
- }
- }
- }
- break;
- case 0x7:
- // RESTORE reglist
- // imm
- {
- u8 const reglist = space(0).read_byte(m_pc + bytes++);
+ s32 const dst = displacement(bytes);
- tcy = 12;
- for (unsigned i = 0; i < 8; i++)
- {
- if (BIT(reglist, i))
- {
- m_r[7 - i] = space(0).read_dword_unaligned(SP);
- SP += 4;
- tcy += 5;
- }
+ SP() -= 4;
+ mem_write<u32>(ns32000::ST_ODT, SP(), m_pc + bytes);
+
+ m_pc += dst;
+ m_sequential = false;
+ tex = top(SIZE_D, SP()) + 6;
}
- }
- break;
- case 0x8:
- // ENTER reglist,constant
- // imm,disp
- {
- u8 const reglist = space(0).read_byte(m_pc + bytes++);
- s32 const constant = displacement(bytes);
+ break;
+ case 0x1:
+ // RET constant
+ // disp
+ {
+ s32 const constant = displacement(bytes);
- SP -= 4;
- space(0).write_dword_unaligned(SP, m_fp);
- m_fp = SP;
- SP -= constant;
+ u32 const addr = mem_read<u32>(ns32000::ST_ODT, SP());
+ SP() += 4;
- tcy = 18;
- for (unsigned i = 0; i < 8; i++)
- {
- if (BIT(reglist, i))
- {
- SP -= 4;
- space(0).write_dword_unaligned(SP, m_r[i]);
- tcy += 4;
- }
+ m_pc = addr;
+ m_sequential = false;
+ tex = top(SIZE_D, SP()) + 2;
+ SP() += constant;
}
- }
- break;
- case 0x9:
- // EXIT reglist
- // imm
- {
- u8 const reglist = space(0).read_byte(m_pc + bytes++);
-
- tcy = 17;
- for (unsigned i = 0; i < 8; i++)
+ break;
+ case 0x2:
+ // CXP index
+ // disp
{
- if (BIT(reglist, i))
- {
- m_r[7 - i] = space(0).read_dword_unaligned(SP);
- SP += 4;
- tcy += 5;
- }
- }
- SP = m_fp;
- m_fp = space(0).read_dword_unaligned(SP);
- SP += 4;
- }
- break;
- case 0xa:
- // NOP
- tcy = 3;
- break;
- case 0xb:
- // WAIT
- m_wait = true;
- tcy = 6;
- break;
- case 0xc:
- // DIA
- m_wait = true;
- tcy = 3;
- break;
- case 0xd:
- // FLAG
- if (m_psr & PSR_F)
- {
- interrupt(FLG, m_pc);
- tcy = 44;
- }
- else
- tcy = 6;
- break;
- case 0xe:
- // SVC
- interrupt(SVC, m_pc);
- tcy = 40;
- break;
- case 0xf:
- // BPT
- interrupt(BPT, m_pc);
- tcy = 40;
- break;
- }
- }
- else if ((opbyte & 15) == 12 || (opbyte & 15) == 13 || (opbyte & 15) == 15)
- {
- // format 2: gggg gsss sooo 11ii
- u16 const opword = space(0).read_word_unaligned(m_pc);
- bytes = 2;
+ s32 const index = displacement(bytes);
- // HACK: use reserved mode for second unused type
- addr_mode mode[] = { addr_mode((opword >> 11) & 31), addr_mode(0x13) };
+ u32 const link_base = mem_read<u32>(ns32000::ST_ODT, m_mod + 4);
+ u32 const desc = mem_read<u32>(ns32000::ST_ODT, link_base + index * 4);
- unsigned const quick = (opword >> 7) & 15;
- size_code const size = size_code(opbyte & 3);
+ SP() -= 4;
+ mem_write<u16>(ns32000::ST_ODT, SP(), m_mod);
+ SP() -= 4;
+ mem_write<u32>(ns32000::ST_ODT, SP(), m_pc + bytes);
- switch ((opbyte >> 4) & 7)
- {
- case 0:
- // ADDQi src,dst
- // quick,gen
- // rmw.i
- {
- mode[0].rmw_i(size);
- decode(mode, bytes);
+ u16 const mod = u16(desc);
+ u32 const sb = mem_read<u32>(ns32000::ST_ODT, mod + 0);
+ u32 const pc = mem_read<u32>(ns32000::ST_ODT, mod + 8) + (desc >> 16);
- u32 const src1 = s32(quick << 28) >> 28;
- u32 const src2 = gen_read(mode[0]);
+ tex = top(SIZE_D, m_mod + 4) + top(SIZE_W, link_base + index * 4) * 2 + top(SIZE_W, SP()) + top(SIZE_D, SP()) + top(SIZE_D, mod) * 2 + 16;
- u32 const dst = src1 + src2;
- flags(src1, src2, dst, size, false);
+ m_pc = pc;
+ m_mod = mod;
+ m_sb = sb;
+ m_sequential = false;
+ }
+ break;
+ case 0x3:
+ // RXP constant
+ // disp
+ {
+ s32 const constant = displacement(bytes);
- gen_write(mode[0], dst);
+ u32 const pc = mem_read<u32>(ns32000::ST_ODT, SP());
+ SP() += 4;
+ u16 const mod = mem_read<u16>(ns32000::ST_ODT, SP());
+ SP() += 4;
+ u32 const sb = mem_read<u32>(ns32000::ST_ODT, mod);
- tcy = (mode[0].type == REG) ? 4 : 6;
- }
- break;
- case 1:
- // CMPQi src1,src2
- // quick,gen
- // read.i
- {
- mode[0].read_i(size);
- decode(mode, bytes);
+ tex = top(SIZE_D, SP()) + top(SIZE_W, SP()) + top(SIZE_D, mod) + 2;
- u32 const src1 = (s32(quick << 28) >> 28) & size_mask[size];
- u32 const src2 = gen_read(mode[0]);
+ m_pc = pc;
+ m_mod = mod;
+ m_sb = sb;
+ SP() += constant;
+ m_sequential = false;
+ }
+ break;
+ case 0x4:
+ // RETT constant
+ // disp
+ if (!(m_psr & PSR_U))
+ {
+ s32 const constant = displacement(bytes);
- m_psr &= ~(PSR_N | PSR_Z | PSR_L);
+ u32 const pc = mem_read<u32>(ns32000::ST_ODT, SP() + 0);
+ u16 const psr = mem_read<u16>(ns32000::ST_ODT, SP() + 6) & PSR_MSK();
- if ((size == SIZE_D && s32(src1) > s32(src2))
- || ((size == SIZE_W && s16(src1) > s16(src2))
- || ((size == SIZE_B && s8(src1) > s8(src2)))))
- m_psr |= PSR_N;
+ if (!(m_cfg & CFG_DE))
+ {
+ u16 const mod = mem_read<u16>(ns32000::ST_ODT, SP() + 4);
+ u32 const sb = mem_read<u32>(ns32000::ST_ODT, mod);
- if (src1 == src2)
- m_psr |= PSR_Z;
+ m_mod = mod;
+ m_sb = sb;
- if ((size == SIZE_D && u32(src1) > u32(src2))
- || ((size == SIZE_W && u16(src1) > u16(src2))
- || ((size == SIZE_B && u8(src1) > u8(src2)))))
- m_psr |= PSR_L;
+ tex = top(SIZE_D, SP()) + top(SIZE_W, SP()) * 2 + top(SIZE_D, mod) + 35;
+ }
+ else
+ tex = top(SIZE_D, SP()) + top(SIZE_W, SP()) + 35;
- tcy = 3;
- }
- break;
- case 2:
- // SPRi procreg,dst
- // short,gen
- // write.i
- mode[0].write_i(size);
- decode(mode, bytes);
+ SP() += 8;
- switch (quick)
- {
- case 0x0: // US
- // TODO: user stack pointer?
- gen_write(mode[0], m_sp1);
- break;
- case 0x8: // FP
- gen_write(mode[0], m_fp);
- break;
- case 0x9: // SP
- gen_write(mode[0], SP);
- break;
- case 0xa: // SB
- gen_write(mode[0], m_sb);
- break;
- case 0xd: // PSR
- if (!(m_psr & PSR_U))
- gen_write(mode[0], m_psr);
+ m_pc = pc;
+ m_psr = psr;
+ SP() += constant;
+
+ m_sequential = false;
+ }
else
- interrupt(ILL, m_pc);
+ interrupt(ILL);
break;
- case 0xe: // INTBASE
+ case 0x5:
+ // RETI
if (!(m_psr & PSR_U))
- gen_write(mode[0], m_intbase);
- else
- interrupt(ILL, m_pc);
- break;
- case 0xf: // MOD
- gen_write(mode[0], m_mod);
- break;
- }
-
- // TODO: tcy 21-27
- tcy = 21;
- break;
- case 3:
- // Scondi dst
- // gen
- // write.i
- {
- mode[0].write_i(size);
- decode(mode, bytes);
+ {
+ // end of interrupt, master
+ s8 vector = mem_read<u8>(ns32000::ST_EIM, 0xffff'fe00U & m_address_mask);
- bool const dst = condition(quick);
- gen_write(mode[0], dst);
+ // check for vectored mode
+ if (m_cfg & CFG_I)
+ {
+ if (vector < 0 && vector >= -16)
+ {
+ u32 const cascade = mem_read<u32>(ns32000::ST_ODT, m_intbase + vector * 4);
- tcy = dst ? 10 : 9;
- }
- break;
- case 4:
- // ACBi inc,index,dst
- // quick,gen,disp
- // rmw.i
- {
- mode[0].rmw_i(size);
- decode(mode, bytes);
+ // end of interrupt, cascaded
+ vector = mem_read<u8>(ns32000::ST_EIC, cascade);
+ }
+ }
- s32 const inc = s32(quick << 28) >> 28;
- u32 index = gen_read(mode[0]);
- s32 const dst = displacement(bytes);
+ u32 const pc = mem_read<u32>(ns32000::ST_ODT, SP() + 0);
+ u16 const psr = mem_read<u16>(ns32000::ST_ODT, SP() + 6) & PSR_MSK();
- index += inc;
- gen_write(mode[0], index);
+ if (!(m_cfg & CFG_DE))
+ {
+ u16 const mod = mem_read<u16>(ns32000::ST_ODT, SP() + 4);
+ u32 const sb = mem_read<u32>(ns32000::ST_ODT, mod);
- if (index & size_mask[size])
- {
- m_pc += dst;
- m_sequential = false;
+ m_mod = mod;
+ m_sb = sb;
- tcy = (mode[0].type == REG) ? 17 : 15;
- }
- else
- tcy = (mode[0].type == REG) ? 18 : 16;
- }
- break;
- case 5:
- // MOVQi src,dst
- // quick,gen
- // write.i
- mode[0].write_i(size);
- decode(mode, bytes);
+ tex = top(SIZE_B) + top(SIZE_W, SP()) * 3 + top(SIZE_D) * 3 + 39;
+ }
+ else
+ tex = top(SIZE_B) + top(SIZE_W, SP()) * 2 + top(SIZE_D) * 2 + 39;
- gen_write(mode[0], s32(quick << 28) >> 28);
+ SP() += 8;
- tcy = (mode[0].type == REG) ? 3 : 2;
- break;
- case 6:
- // LPRi procreg,src
- // short,gen
- // read.i
- mode[0].read_i(size);
- decode(mode, bytes);
-
- switch (quick)
- {
- case 0x0: // UPSR
- m_psr = (m_psr & 0xff00) | u8(gen_read(mode[0]));
- break;
- case 0x8: // FP
- m_fp = gen_read(mode[0]);
- break;
- case 0x9: // SP
- SP = gen_read(mode[0]);
- break;
- case 0xa: // SB
- m_sb = gen_read(mode[0]);
- break;
- case 0xd: // PSR
- if (!(m_psr & PSR_U))
- {
- u32 const src = gen_read(mode[0]);
+ m_pc = pc;
+ m_psr = psr;
- if (size == SIZE_B)
- m_psr = (m_psr & 0xff00) | u8(src);
- else
- m_psr = src;
+ m_sequential = false;
}
else
- interrupt(ILL, m_pc);
- break;
- case 0xe: // INTBASE
- if (!(m_psr & PSR_U))
- m_intbase = gen_read(mode[0]);
- else
- interrupt(ILL, m_pc);
+ interrupt(ILL);
break;
- case 0xf: // MOD
- m_mod = gen_read(mode[0]);
- break;
- default:
- interrupt(UND, m_pc);
- break;
- }
-
- // TODO: tcy 19-33
- tcy = 19;
- break;
- case 7:
- // format 3: gggg gooo o111 11ii
- switch ((opword >> 7) & 15)
- {
- case 0x0:
- // CXPD desc
- // gen
- // addr
- if (size == SIZE_D)
+ case 0x6:
+ // SAVE reglist
+ // imm
{
- mode[0].addr();
- decode(mode, bytes);
-
- u32 const descriptor = gen_read(mode[0]);
+ u8 const reglist = fetch<u8>(bytes);
- SP -= 4;
- space(0).write_dword_unaligned(SP, m_mod);
- SP -= 4;
- space(0).write_dword_unaligned(SP, m_pc + bytes);
-
- m_mod = u16(descriptor);
- m_sb = space(0).read_dword_unaligned(m_mod + 0);
- m_pc = space(0).read_dword_unaligned(m_mod + 8) + u16(descriptor >> 16);
- m_sequential = false;
-
- tcy = 13;
+ tex = 13;
+ for (unsigned i = 0; i < 8; i++)
+ {
+ if (BIT(reglist, i))
+ {
+ SP() -= 4;
+ mem_write<u32>(ns32000::ST_ODT, SP(), m_r[i]);
+ tex += top(SIZE_D, SP()) + 4;
+ }
+ }
}
- else
- interrupt(UND, m_pc);
break;
- case 0x2:
- // BICPSRi src
- // gen
- // read.[BW]
- if (size == SIZE_B || size == SIZE_W)
+ case 0x7:
+ // RESTORE reglist
+ // imm
{
- mode[0].read_i(size);
- decode(mode, bytes);
+ u8 const reglist = fetch<u8>(bytes);
- if (size == SIZE_B || !(m_psr & PSR_U))
+ tex = 12;
+ for (unsigned i = 0; i < 8; i++)
{
- u16 const src = gen_read(mode[0]);
-
- m_psr &= ~src;
-
- tcy = (size == SIZE_B) ? 18 : 30;
+ if (BIT(reglist, i))
+ {
+ m_r[7 - i] = mem_read<u32>(ns32000::ST_ODT, SP());
+ tex += top(SIZE_D, SP()) + 5;
+ SP() += 4;
+ }
}
- else
- interrupt(ILL, m_pc);
}
- else
- interrupt(UND, m_pc);
break;
- case 0x4:
- // JUMP dst
- // gen
- // addr
- if (size == SIZE_D)
+ case 0x8:
+ // ENTER reglist,constant
+ // imm,disp
{
- mode[0].addr();
- decode(mode, bytes);
+ u8 const reglist = fetch<u8>(bytes);
+ s32 const constant = displacement(bytes);
- m_pc = ea(mode[0]);
- m_sequential = false;
+ SP() -= 4;
+ mem_write<u32>(ns32000::ST_ODT, SP(), m_fp);
+ u32 const fp = SP();
+ tex = top(SIZE_D, SP()) + 18;
+ SP() -= constant;
+
+ for (unsigned i = 0; i < 8; i++)
+ {
+ if (BIT(reglist, i))
+ {
+ SP() -= 4;
+ mem_write<u32>(ns32000::ST_ODT, SP(), m_r[i]);
+ tex += top(SIZE_D, SP()) + 4;
+ }
+ }
- tcy = 2;
+ m_fp = fp;
}
- else
- interrupt(UND, m_pc);
break;
- case 0x6:
- // BISPSRi src
- // gen
- // read.[BW]
- if (size == SIZE_B || size == SIZE_W)
+ case 0x9:
+ // EXIT reglist
+ // imm
{
- mode[0].read_i(size);
- decode(mode, bytes);
+ u8 const reglist = fetch<u8>(bytes);
- if (size == SIZE_B || !(m_psr & PSR_U))
+ tex = 17;
+ for (unsigned i = 0; i < 8; i++)
{
- u16 const src = gen_read(mode[0]);
-
- m_psr |= src;
-
- tcy = (size == SIZE_B) ? 18 : 30;
+ if (BIT(reglist, i))
+ {
+ m_r[7 - i] = mem_read<u32>(ns32000::ST_ODT, SP());
+ tex += top(SIZE_D, SP()) + 5;
+ SP() += 4;
+ }
}
- else
- interrupt(ILL, m_pc);
+ SP() = m_fp;
+ m_fp = mem_read<u32>(ns32000::ST_ODT, SP());
+ tex += top(SIZE_D, SP());
+ SP() += 4;
}
- else
- interrupt(UND, m_pc);
break;
case 0xa:
- // ADJSPi src
- // gen
- // read.i
- {
- mode[0].read_i(size);
- decode(mode, bytes);
-
- s32 const src = gen_read_sx(mode[0]);
-
- SP -= src;
-
- tcy = 6;
- }
+ // NOP
+ tex = 3;
+ break;
+ case 0xb:
+ // WAIT
+ m_wait = true;
+ tex = 6;
break;
case 0xc:
- // JSR dst
- // gen
- // addr
- if (size == SIZE_D)
+ // DIA
+ tex = 3;
+ m_sequential = false;
+ break;
+ case 0xd:
+ // FLAG
+ if (m_psr & PSR_F)
{
- mode[0].addr();
- decode(mode, bytes);
-
- SP -= 4;
- space(0).write_dword_unaligned(SP, m_pc + bytes);
-
- m_pc = ea(mode[0]);
- m_sequential = false;
-
- tcy = 5;
+ interrupt(FLG);
+ tex = 44;
}
else
- interrupt(UND, m_pc);
+ tex = 6;
break;
case 0xe:
- // CASEi src
- // gen
- // read.i
- {
- mode[0].read_i(size);
- decode(mode, bytes);
-
- s32 const src = gen_read_sx(mode[0]);
-
- m_pc += src;
- m_sequential = false;
-
- tcy = 4;
- }
+ // SVC
+ interrupt(SVC);
+ tex = 40;
break;
- default:
- interrupt(UND, m_pc);
+ case 0xf:
+ // BPT
+ interrupt(BPT);
+ tex = 40;
break;
}
- break;
}
- }
- else if ((opbyte & 3) != 2)
- {
- // format 4: xxxx xyyy yyoo ooii
- u16 const opword = space(0).read_word_unaligned(m_pc);
- bytes = 2;
-
- addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
- size_code const size = size_code(opbyte & 3);
-
- switch ((opbyte >> 2) & 15)
+ else if ((opbyte & 15) == 12 || (opbyte & 15) == 13 || (opbyte & 15) == 15)
{
- case 0x0:
- // ADDi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
-
- u32 const src1 = gen_read(mode[0]);
- u32 const src2 = gen_read(mode[1]);
+ // format 2: gggg gsss sooo 11ii
+ u16 const opword = (u16(fetch<u8>(bytes)) << 8) | opbyte;
- u32 const dst = src1 + src2;
- flags(src1, src2, dst, size, false);
+ // HACK: use reserved mode for second unused type
+ addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(0x13) };
- gen_write(mode[1], dst);
+ unsigned const quick = BIT(opword, 7, 4);
+ size_code const size = size_code(opbyte & 3);
- tcy = (mode[1].type == REG) ? 4 : 3;
- }
- break;
- case 0x1:
- // CMPi src1,src2
- // gen,gen
- // read.i,read.i
+ switch (BIT(opbyte, 4, 3))
{
- mode[0].read_i(size);
- mode[1].read_i(size);
- decode(mode, bytes);
-
- u32 const src1 = gen_read(mode[0]);
- u32 const src2 = gen_read(mode[1]);
-
- m_psr &= ~(PSR_N | PSR_Z | PSR_L);
-
- if ((size == SIZE_D && s32(src1) > s32(src2))
- || ((size == SIZE_W && s16(src1) > s16(src2))
- || ((size == SIZE_B && s8(src1) > s8(src2)))))
- m_psr |= PSR_N;
-
- if (src1 == src2)
- m_psr |= PSR_Z;
-
- if ((size == SIZE_D && u32(src1) > u32(src2))
- || ((size == SIZE_W && u16(src1) > u16(src2))
- || ((size == SIZE_B && u8(src1) > u8(src2)))))
- m_psr |= PSR_L;
+ case 0:
+ // ADDQi src,dst
+ // quick,gen
+ // rmw.i
+ {
+ mode[0].rmw_i(size);
+ decode(mode, bytes);
- tcy = 3;
- }
- break;
- case 0x2:
- // BICi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
+ u32 const src1 = util::sext(quick, 4);
+ u32 const src2 = gen_read(mode[0]);
- u32 const src = gen_read(mode[0]);
- u32 const dst = gen_read(mode[1]);
+ u32 const dst = src1 + src2;
+ flags(src1, src2, dst, size, false);
- gen_write(mode[1], dst & ~src);
+ gen_write(mode[0], dst);
- tcy = (mode[1].type == REG) ? 4 : 3;
- }
- break;
- case 0x4:
- // ADDCi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
+ tex = (mode[0].type == REG) ? 4 : mode[0].tea + 6;
+ }
+ break;
+ case 1:
+ // CMPQi src1,src2
+ // quick,gen
+ // read.i
+ {
+ mode[0].read_i(size);
+ decode(mode, bytes);
- u32 const src1 = gen_read(mode[0]);
- u32 const src2 = gen_read(mode[1]);
+ u32 const src1 = util::sext(quick, 4) & size_mask[size];
+ u32 const src2 = gen_read(mode[0]);
- u32 const dst = src1 + src2 + (m_psr & PSR_C);
- flags(src1, src2, dst, size, false);
+ m_psr &= ~(PSR_N | PSR_Z | PSR_L);
- gen_write(mode[1], dst);
+ if ((size == SIZE_D && s32(src1) > s32(src2))
+ || ((size == SIZE_W && s16(src1) > s16(src2))
+ || ((size == SIZE_B && s8(src1) > s8(src2)))))
+ m_psr |= PSR_N;
- tcy = (mode[1].type == REG) ? 4 : 3;
- }
- break;
- case 0x5:
- // MOVi src,dst
- // gen,gen
- // read.i,write.i
- {
- mode[0].read_i(size);
- mode[1].write_i(size);
- decode(mode, bytes);
+ if (src1 == src2)
+ m_psr |= PSR_Z;
- u32 const src = gen_read(mode[0]);
+ if ((size == SIZE_D && u32(src1) > u32(src2))
+ || ((size == SIZE_W && u16(src1) > u16(src2))
+ || ((size == SIZE_B && u8(src1) > u8(src2)))))
+ m_psr |= PSR_L;
- gen_write(mode[1], src);
-
- tcy = (mode[1].type == REG) ? 3 : 1;
- }
- break;
- case 0x6:
- // ORi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
+ tex = (mode[0].type == REG) ? 3 : mode[0].tea + 3;
+ }
+ break;
+ case 2:
+ // SPRi procreg,dst
+ // short,gen
+ // write.i
+ mode[0].write_i(size);
decode(mode, bytes);
- u32 const src = gen_read(mode[0]);
- u32 const dst = gen_read(mode[1]);
+ spr(quick, mode[0], m_psr & PSR_U, tex);
+ break;
+ case 3:
+ // Scondi dst
+ // gen
+ // write.i
+ {
+ mode[0].write_i(size);
+ decode(mode, bytes);
- gen_write(mode[1], src | dst);
+ bool const dst = condition(quick);
+ gen_write(mode[0], dst);
- tcy = (mode[1].type == REG) ? 4 : 3;
- }
- break;
- case 0x8:
- // SUBi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
+ tex = mode[0].tea + (dst ? 10 : 9);
+ }
+ break;
+ case 4:
+ // ACBi inc,index,dst
+ // quick,gen,disp
+ // rmw.i
+ {
+ mode[0].rmw_i(size);
+ decode(mode, bytes);
- u32 const src1 = gen_read(mode[0]);
- u32 const src2 = gen_read(mode[1]);
+ s32 const inc = util::sext(quick, 4);
+ u32 index = gen_read(mode[0]);
+ s32 const dst = displacement(bytes);
- u32 const dst = src2 - src1;
- flags(src1, src2, dst, size, true);
+ index += inc;
+ gen_write(mode[0], index);
- gen_write(mode[1], dst);
+ if (index & size_mask[size])
+ {
+ m_pc += dst;
+ m_sequential = false;
- tcy = (mode[1].type == REG) ? 4 : 3;
- }
- break;
- case 0x9:
- // ADDR src,dst
- // gen,gen
- // addr,write.D
- if (size == SIZE_D)
- {
- mode[0].addr();
- mode[1].write_i(size);
+ tex = (mode[0].type == REG) ? 17 : mode[0].tea + 15;
+ }
+ else
+ tex = (mode[0].type == REG) ? 18 : mode[0].tea + 16;
+ }
+ break;
+ case 5:
+ // MOVQi src,dst
+ // quick,gen
+ // write.i
+ mode[0].write_i(size);
decode(mode, bytes);
- gen_write(mode[1], ea(mode[0]));
+ gen_write(mode[0], util::sext(quick, 4));
- tcy = (mode[1].type == REG) ? 3 : 2;
- }
- else
- interrupt(UND, m_pc);
- break;
- case 0xa:
- // ANDi src,dst
- // gen,gen
- // read.i,rmw.i
- {
+ tex = (mode[0].type == REG) ? 3 : mode[0].tea + 2;
+ break;
+ case 6:
+ // LPRi procreg,src
+ // short,gen
+ // read.i
mode[0].read_i(size);
- mode[1].rmw_i(size);
decode(mode, bytes);
- u32 const src = gen_read(mode[0]);
- u32 const dst = gen_read(mode[1]);
+ lpr(quick, mode[0], m_psr & PSR_U, tex);
+ break;
+ case 7:
+ // format 3: gggg gooo o111 11ii
+ switch (BIT(opword, 7, 4))
+ {
+ case 0x0:
+ // CXPD desc
+ // gen
+ // addr
+ if (size == SIZE_D)
+ {
+ mode[0].addr();
+ decode(mode, bytes);
- gen_write(mode[1], src & dst);
+ u32 const address = ea(mode[0]);
- tcy = (mode[1].type == REG) ? 4 : 3;
- }
- break;
- case 0xc:
- // SUBCi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
+ SP() -= 4;
+ mem_write<u16>(ns32000::ST_ODT, SP(), m_mod);
+ SP() -= 4;
+ mem_write<u32>(ns32000::ST_ODT, SP(), m_pc + bytes);
- u32 const src1 = gen_read(mode[0]);
- u32 const src2 = gen_read(mode[1]);
+ u32 const desc = mem_read<u32>(ns32000::ST_ODT, address);
+ u16 const mod = u16(desc);
+ u32 const sb = mem_read<u32>(ns32000::ST_ODT, mod + 0);
+ u32 const pc = mem_read<u32>(ns32000::ST_ODT, mod + 8) + (desc >> 16);
- u32 const dst = src2 - src1 - (m_psr & PSR_C);
- flags(src1, src2, dst, size, true);
+ tex = mode[0].tea + top(SIZE_W, address) * 3 + top(SIZE_D, mod) * 3 + 13;
- gen_write(mode[1], dst);
+ m_pc = pc;
+ m_mod = mod;
+ m_sb = sb;
+ m_sequential = false;
+ }
+ else
+ interrupt(UND);
+ break;
+ case 0x2:
+ // BICPSRi src
+ // gen
+ // read.[BW]
+ if (size == SIZE_B || size == SIZE_W)
+ {
+ mode[0].read_i(size);
+ decode(mode, bytes);
- tcy = (mode[1].type == REG) ? 4 : 3;
- }
- break;
- case 0xd:
- // TBITi offset,base
- // gen,gen
- // read.i,regaddr
- {
- mode[0].read_i(size);
- mode[1].regaddr();
- decode(mode, bytes);
+ if (size == SIZE_B || !(m_psr & PSR_U))
+ {
+ u16 const src = gen_read(mode[0]);
- s32 const offset = gen_read_sx(mode[0]);
+ m_psr &= ~src;
- if (mode[1].type == REG)
- {
- if (BIT(m_r[mode[1].gen], offset & 31))
- m_psr |= PSR_F;
+ tex = mode[0].tea + ((size == SIZE_B) ? 18 : 30);
+ }
+ else
+ interrupt(ILL);
+ }
else
- m_psr &= ~PSR_F;
+ interrupt(UND);
+ break;
+ case 0x4:
+ // JUMP dst
+ // gen
+ // addr
+ if (size == SIZE_D)
+ {
+ mode[0].addr();
+ decode(mode, bytes);
- tcy = 4;
- }
- else
- {
- u8 const byte = space(0).read_byte(ea(mode[1]) + (offset >> 3));
+ m_pc = ea(mode[0]);
+ m_sequential = false;
- if (BIT(byte, offset & 7))
- m_psr |= PSR_F;
+ tex = mode[0].tea + 2;
+ }
else
- m_psr &= ~PSR_F;
-
- tcy = 14;
- }
- }
- break;
- case 0xe:
- // XORi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
-
- u32 const src = gen_read(mode[0]);
- u32 const dst = gen_read(mode[1]);
-
- gen_write(mode[1], src ^ dst);
-
- tcy = (mode[1].type == REG) ? 4 : 3;
- }
- break;
- }
- }
- else switch (opbyte)
- {
- case 0x0e:
- // format 5: 0000 0sss s0oo ooii 0000 1110
- {
- u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
- bytes += 2;
-
- size_code const size = size_code(opword & 3);
-
- // string instruction options
- bool const translate = BIT(opword, 7);
- bool const backward = BIT(opword, 8);
- unsigned const uw = (opword >> 9) & 3;
-
- switch ((opword >> 2) & 15)
- {
- case 0:
- // MOVSi options
- tcy = (translate || backward || uw) ? 54 : 18;
-
- m_psr &= ~PSR_F;
- while (m_r[0])
- {
- u32 data =
- (size == SIZE_D) ? space(0).read_dword_unaligned(m_r[1]) :
- (size == SIZE_W) ? space(0).read_word_unaligned(m_r[1]) :
- space(0).read_byte(m_r[1]);
-
- if (translate)
- data = space(0).read_byte(m_r[3] + u8(data));
-
- tcy += translate ? 27 : (backward || uw) ? 24 : 13;
-
- bool const match = !((m_r[4] ^ data) & size_mask[size]);
- if ((uw == 1 && !match) || (uw == 3 && match))
+ interrupt(UND);
+ break;
+ case 0x6:
+ // BISPSRi src
+ // gen
+ // read.[BW]
+ if (size == SIZE_B || size == SIZE_W)
{
- m_psr |= PSR_F;
- break;
- }
+ mode[0].read_i(size);
+ decode(mode, bytes);
- if (size == SIZE_D)
- space(0).write_dword_unaligned(m_r[2], data);
- else if (size == SIZE_W)
- space(0).write_word_unaligned(m_r[2], data);
- else
- space(0).write_byte(m_r[2], data);
+ if (size == SIZE_B || !(m_psr & PSR_U))
+ {
+ u16 const src = gen_read(mode[0]);
- if (backward)
- {
- m_r[1] -= size + 1;
- m_r[2] -= size + 1;
+ m_psr |= src & PSR_MSK();
+
+ tex = mode[0].tea + ((size == SIZE_B) ? 18 : 30);
+ }
+ else
+ interrupt(ILL);
}
else
+ interrupt(UND);
+ break;
+ case 0xa:
+ // ADJSPi src
+ // gen
+ // read.i
{
- m_r[1] += size + 1;
- m_r[2] += size + 1;
- }
+ mode[0].read_i(size);
+ decode(mode, bytes);
- m_r[0]--;
- }
- break;
- case 1:
- // CMPSi options
- tcy = 53;
+ s32 const src = gen_read_sx(mode[0]);
- m_psr |= PSR_Z;
- m_psr &= ~(PSR_N | PSR_F | PSR_L);
- while (m_r[0])
- {
- u32 src1 =
- (size == SIZE_D) ? space(0).read_dword_unaligned(m_r[1]) :
- (size == SIZE_W) ? space(0).read_word_unaligned(m_r[1]) :
- space(0).read_byte(m_r[1]);
- u32 src2 =
- (size == SIZE_D) ? space(0).read_dword_unaligned(m_r[2]) :
- (size == SIZE_W) ? space(0).read_word_unaligned(m_r[2]) :
- space(0).read_byte(m_r[2]);
-
- if (translate)
- src1 = space(0).read_byte(m_r[3] + u8(src1));
-
- tcy += translate ? 38 : 35;
-
- bool const match = !((m_r[4] ^ src1) & size_mask[size]);
- if ((uw == 1 && !match) || (uw == 3 && match))
- {
- m_psr |= PSR_F;
- break;
- }
+ SP() -= src;
- if (src1 != src2)
+ tex = mode[0].tea + 6;
+ }
+ break;
+ case 0xc:
+ // JSR dst
+ // gen
+ // addr
+ if (size == SIZE_D)
{
- m_psr &= ~PSR_Z;
+ mode[0].addr();
+ decode(mode, bytes);
- if ((size == SIZE_D && s32(src1) > s32(src2))
- || ((size == SIZE_W && s16(src1) > s16(src2))
- || ((size == SIZE_B && s8(src1) > s8(src2)))))
- m_psr |= PSR_N;
+ SP() -= 4;
+ mem_write<u32>(ns32000::ST_ODT, SP(), m_pc + bytes);
- if ((size == SIZE_D && u32(src1) > u32(src2))
- || ((size == SIZE_W && u16(src1) > u16(src2))
- || ((size == SIZE_B && u8(src1) > u8(src2)))))
- m_psr |= PSR_L;
+ m_pc = ea(mode[0]);
+ m_sequential = false;
- break;
- }
-
- if (backward)
- {
- m_r[1] -= size + 1;
- m_r[2] -= size + 1;
+ // TODO: where does the TOPi come from?
+ tex = mode[0].tea + top(SIZE_D, SP()) + top(size) + 5;
}
else
+ interrupt(UND);
+ break;
+ case 0xe:
+ // CASEi src
+ // gen
+ // read.i
{
- m_r[1] += size + 1;
- m_r[2] += size + 1;
- }
-
- m_r[0]--;
- }
- break;
- case 2:
- // SETCFG cfglist
- // short
- if (!(m_psr & PSR_U))
- {
- m_cfg = (opword >> 7) & 15;
-
- tcy = 15;
- }
- else
- interrupt(ILL, m_pc);
- break;
- case 3:
- // SKPSi options
- tcy = 51;
-
- m_psr &= ~PSR_F;
- while (m_r[0])
- {
- u32 data =
- (size == SIZE_D) ? space(0).read_dword_unaligned(m_r[1]) :
- (size == SIZE_W) ? space(0).read_word_unaligned(m_r[1]) :
- space(0).read_byte(m_r[1]);
+ mode[0].read_i(size);
+ decode(mode, bytes);
- if (translate)
- data = space(0).read_byte(m_r[3] + u8(data));
+ s32 const src = gen_read_sx(mode[0]);
- tcy += translate ? 30 : 27;
+ m_pc += src;
+ m_sequential = false;
- bool const match = !((m_r[4] ^ data) & size_mask[size]);
- if ((uw == 1 && !match) || (uw == 3 && match))
- {
- m_psr |= PSR_F;
- break;
+ tex = mode[0].tea + 4;
}
-
- if (backward)
- m_r[1] -= size + 1;
- else
- m_r[1] += size + 1;
-
- m_r[0]--;
+ break;
+ default:
+ interrupt(UND);
+ break;
}
break;
- default:
- interrupt(UND, m_pc);
- break;
}
}
- break;
- case 0x4e:
- // format 6: xxxx xyyy yyoo ooii 0100 1110
+ else if ((opbyte & 3) != 2)
{
- u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
- bytes += 2;
+ // format 4: xxxx xyyy yyoo ooii
+ u16 const opword = (u16(fetch<u8>(bytes)) << 8) | opbyte;
- addr_mode mode[] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
- size_code const size = size_code(opword & 3);
+ addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(BIT(opword, 6, 5)) };
+ size_code const size = size_code(opbyte & 3);
- switch ((opword >> 2) & 15)
+ switch (BIT(opbyte, 2, 4))
{
case 0x0:
- // ROTi count,dst
+ // ADDi src,dst
// gen,gen
- // read.B,rmw.i
+ // read.i,rmw.i
{
- mode[0].read_i(SIZE_B);
+ mode[0].read_i(size);
mode[1].rmw_i(size);
decode(mode, bytes);
- s32 const count = gen_read_sx(mode[0]);
- u32 const src = gen_read(mode[1]);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- unsigned const limit = (size + 1) * 8 - 1;
- u32 const dst = ((src << (count & limit)) & size_mask[size]) | ((src & size_mask[size]) >> (limit - (count & limit) + 1));
+ u32 const dst = src1 + src2;
+ flags(src1, src2, dst, size, false);
gen_write(mode[1], dst);
- tcy = 14 + (count & limit);
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 3;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 4;
+ else
+ tex = 4;
}
break;
case 0x1:
- // ASHi count,dst
+ // CMPi src1,src2
// gen,gen
- // read.B,rmw.i
+ // read.i,read.i
{
- mode[0].read_i(SIZE_B);
- mode[1].rmw_i(size);
+ mode[0].read_i(size);
+ mode[1].read_i(size);
decode(mode, bytes);
- s32 const count = gen_read_sx(mode[0]);
- s32 const src = gen_read_sx(mode[1]);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- u32 const dst = (count < 0) ? (src >> -count) : (src << count);
+ m_psr &= ~(PSR_N | PSR_Z | PSR_L);
- gen_write(mode[1], dst);
+ if ((size == SIZE_D && s32(src1) > s32(src2))
+ || ((size == SIZE_W && s16(src1) > s16(src2))
+ || ((size == SIZE_B && s8(src1) > s8(src2)))))
+ m_psr |= PSR_N;
+
+ if (src1 == src2)
+ m_psr |= PSR_Z;
+
+ if ((size == SIZE_D && u32(src1) > u32(src2))
+ || ((size == SIZE_W && u16(src1) > u16(src2))
+ || ((size == SIZE_B && u8(src1) > u8(src2)))))
+ m_psr |= PSR_L;
- tcy = 14 + std::abs(count);
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 3;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 3;
+ else
+ tex = 3;
}
break;
case 0x2:
- // CBITi offset,base
- // gen,gen
- // read.i,regaddr
- case 0x3:
- // CBITIi offset,base
- // gen,gen
- // read.i,regaddr
+ // BICi src,dst
+ // gen,gen
+ // read.i,rmw.i
{
mode[0].read_i(size);
- mode[1].regaddr();
+ mode[1].rmw_i(size);
decode(mode, bytes);
- s32 const offset = gen_read_sx(mode[0]);
-
- if (mode[1].type == REG)
- {
- if (BIT(m_r[mode[1].gen], offset & 31))
- m_psr |= PSR_F;
- else
- m_psr &= ~PSR_F;
+ u32 const src = gen_read(mode[0]);
+ u32 const dst = gen_read(mode[1]);
- m_r[mode[1].gen] &= ~(1U << (offset & 31));
+ gen_write(mode[1], dst & ~src);
- tcy = 7;
- }
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 3;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 4;
else
- {
- u32 const byte_ea = ea(mode[1]) + (offset >> 3);
- u8 const byte = space(0).read_byte(byte_ea);
-
- if (BIT(byte, offset & 7))
- m_psr |= PSR_F;
- else
- m_psr &= ~PSR_F;
-
- space(0).write_byte(byte_ea, byte & ~(1U << (offset & 7)));
-
- tcy = 15;
- }
+ tex = 4;
}
break;
case 0x4:
- interrupt(UND, m_pc);
- break;
- case 0x5:
- // LSHi count,dst
+ // ADDCi src,dst
// gen,gen
- // read.B,rmw.i
+ // read.i,rmw.i
{
- mode[0].read_i(SIZE_B);
+ mode[0].read_i(size);
mode[1].rmw_i(size);
decode(mode, bytes);
- s32 const count = gen_read_sx(mode[0]);
- u32 const src = gen_read(mode[1]);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- u32 const dst = (count < 0) ? (src >> -count) : (src << count);
+ u32 const dst = src1 + src2 + (m_psr & PSR_C);
+ flags(src1, src2, dst, size, false);
gen_write(mode[1], dst);
- tcy = 14 + std::abs(count);
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 3;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 4;
+ else
+ tex = 4;
}
break;
- case 0x6:
- // SBITi offset,base
- // gen,gen
- // read.i,regaddr
- case 0x7:
- // SBITI offset,base
- // gen,gen
- // read.i,regaddr
+ case 0x5:
+ // MOVi src,dst
+ // gen,gen
+ // read.i,write.i
{
mode[0].read_i(size);
- mode[1].regaddr();
+ mode[1].write_i(size);
decode(mode, bytes);
- s32 const offset = gen_read_sx(mode[0]);
+ // special-case non-masked source data when moving from
+ // register to memory; see comments in mem_write()
+ u32 const src = (mode[0].type == REG) ? m_r[mode[0].gen] : gen_read(mode[0]);
- if (mode[1].type == REG)
- {
- if (BIT(m_r[mode[1].gen], offset & 31))
- m_psr |= PSR_F;
- else
- m_psr &= ~PSR_F;
-
- m_r[mode[1].gen] |= (1U << (offset & 31));
+ gen_write(mode[1], src);
- tcy = 7;
- }
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 1;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 3;
else
- {
- u32 const byte_ea = ea(mode[1]) + (offset >> 3);
- u8 const byte = space(0).read_byte(byte_ea);
+ tex = 3;
+ }
+ break;
+ case 0x6:
+ // ORi src,dst
+ // gen,gen
+ // read.i,rmw.i
+ {
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- if (BIT(byte, offset & 7))
- m_psr |= PSR_F;
- else
- m_psr &= ~PSR_F;
+ u32 const src = gen_read(mode[0]);
+ u32 const dst = gen_read(mode[1]);
- space(0).write_byte(byte_ea, byte | (1U << (offset & 7)));
+ gen_write(mode[1], src | dst);
- tcy = 15;
- }
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 3;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 4;
+ else
+ tex = 4;
}
break;
case 0x8:
- // NEGi src,dst
+ // SUBi src,dst
// gen,gen
- // read.i,write.i
+ // read.i,rmw.i
{
mode[0].read_i(size);
- mode[1].write_i(size);
+ mode[1].rmw_i(size);
decode(mode, bytes);
- u32 const src = gen_read(mode[0]);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- if (src)
- m_psr |= PSR_C;
- else
- m_psr &= ~PSR_C;
+ u32 const dst = src2 - src1;
+ flags(src1, src2, dst, size, true);
- if ((src ^ ~(size_mask[size] >> 1)) & size_mask[size])
- {
- m_psr &= ~PSR_F;
- gen_write(mode[1], -src);
- }
- else
- {
- m_psr |= PSR_F;
- gen_write(mode[1], src);
- }
+ gen_write(mode[1], dst);
- tcy = 5;
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 3;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 4;
+ else
+ tex = 4;
}
break;
case 0x9:
- // NOTi src,dst
+ // ADDR src,dst
// gen,gen
- // read.i,write.i
+ // addr,write.D
+ if (size == SIZE_D)
{
- mode[0].read_i(size);
+ mode[0].addr();
mode[1].write_i(size);
decode(mode, bytes);
- u32 const src = gen_read(mode[0]);
-
- gen_write(mode[1], src ^ 1U);
+ gen_write(mode[1], ea(mode[0]));
- tcy = 5;
+ tex = (mode[1].type == REG) ? mode[0].tea + 3 : mode[0].tea + mode[1].tea + 2;
}
+ else
+ interrupt(UND);
break;
case 0xa:
- interrupt(UND, m_pc);
- break;
- case 0xb:
- // SUBPi src,dst
+ // ANDi src,dst
// gen,gen
// read.i,rmw.i
- fatalerror("unimplemented: subp (%s)\n", machine().describe_context());
-
- // TODO: tcy 16/18
- break;
- case 0xc:
- // ABSi src,dst
- // gen,gen
- // read.i,write.i
{
mode[0].read_i(size);
- mode[1].write_i(size);
+ mode[1].rmw_i(size);
decode(mode, bytes);
- s32 const src = gen_read_sx(mode[0]);
+ u32 const src = gen_read(mode[0]);
+ u32 const dst = gen_read(mode[1]);
- m_psr &= ~PSR_F;
- if (src == s32(0x80000000) >> (32 - (size + 1) * 8))
- {
- m_psr |= PSR_F;
- gen_write(mode[1], src);
- }
- else
- gen_write(mode[1], std::abs(src));
+ gen_write(mode[1], src & dst);
- tcy = (src < 0) ? 9 : 8;
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 3;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 4;
+ else
+ tex = 4;
}
break;
- case 0xd:
- // COMi src,dst
+ case 0xc:
+ // SUBCi src,dst
// gen,gen
- // read.i,write.i
+ // read.i,rmw.i
{
mode[0].read_i(size);
- mode[1].write_i(size);
+ mode[1].rmw_i(size);
decode(mode, bytes);
- u32 const src = gen_read(mode[0]);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- gen_write(mode[1], ~src);
+ u32 const dst = src2 - src1 - (m_psr & PSR_C);
+ flags(src1, src2, dst, size, true);
+
+ gen_write(mode[1], dst);
- tcy = 7;
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 3;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 4;
+ else
+ tex = 4;
}
break;
- case 0xe:
- // IBITi offset,base
+ case 0xd:
+ // TBITi offset,base
// gen,gen
// read.i,regaddr
{
@@ -1913,1061 +1892,1746 @@ template <int Width> void ns32000_device<Width>::execute_run()
else
m_psr &= ~PSR_F;
- m_r[mode[1].gen] ^= (1U << (offset & 31));
-
- tcy = 9;
+ tex = mode[0].tea + 4;
}
else
{
- u32 const byte_ea = ea(mode[1]) + (offset >> 3);
- u8 const byte = space(0).read_byte(byte_ea);
+ u8 const byte = mem_read<u8>(ns32000::ST_ODT, ea(mode[1]) + (offset >> 3));
if (BIT(byte, offset & 7))
m_psr |= PSR_F;
else
m_psr &= ~PSR_F;
- space(0).write_byte(byte_ea, byte ^ (1U << (offset & 7)));
-
- tcy = 17;
+ tex = mode[0].tea + mode[1].tea + top(SIZE_B) + 14;
}
}
break;
- case 0xf:
- // ADDPi src,dst
- // gen,gen
- // read.i,rmw.i
- fatalerror("unimplemented: addp (%s)\n", machine().describe_context());
+ case 0xe:
+ // XORi src,dst
+ // gen,gen
+ // read.i,rmw.i
+ {
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
+ u32 const dst = gen_read(mode[1]);
+
+ gen_write(mode[1], src ^ dst);
- // TODO: tcy 16/18
+ if (mode[1].type != REG)
+ tex = mode[0].tea + mode[1].tea + 3;
+ else if (mode[0].type != REG)
+ tex = mode[0].tea + 4;
+ else
+ tex = 4;
+ }
break;
}
}
- break;
- case 0xce:
- // format 7: xxxx xyyy yyoo ooii 1100 1110
+ else switch (opbyte)
{
- u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
- bytes += 2;
+ case 0x0e:
+ // format 5: 0000 0sss s0oo ooii 0000 1110
+ {
+ u16 const opword = fetch<u16>(bytes);
- addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
- size_code const size = size_code(opword & 3);
+ size_code const size = size_code(opword & 3);
- switch ((opword >> 2) & 15)
- {
- case 0x0:
- // MOVMi block1,block2,length
- // gen,gen,disp
- // addr,addr
- {
- mode[0].addr();
- mode[1].addr();
- decode(mode, bytes);
+ // string instruction options
+ bool const translate = BIT(opword, 7);
+ bool const backward = BIT(opword, 8);
+ unsigned const uw = BIT(opword, 9, 2);
- u32 block1 = ea(mode[0]);
- u32 block2 = ea(mode[1]);
- unsigned const num = displacement(bytes) / (size + 1) + 1;
+ switch (BIT(opword, 2, 4))
+ {
+ case 0:
+ // MOVSi options
+ tex = (translate || backward || uw) ? 54 : 18;
- // TODO: aligned/unaligned transfers?
- for (unsigned i = 0; i < num; i++)
+ m_psr &= ~PSR_F;
+ while (m_r[0])
{
- switch (size)
+ u32 data =
+ (size == SIZE_D) ? mem_read<u32>(ns32000::ST_ODT, m_r[1]) :
+ (size == SIZE_W) ? mem_read<u16>(ns32000::ST_ODT, m_r[1]) :
+ mem_read<u8>(ns32000::ST_ODT, m_r[1]);
+
+ if (translate)
+ data = mem_read<u8>(ns32000::ST_ODT, m_r[3] + u8(data));
+
+ tex += top(size, m_r[1]) + (translate ? top(SIZE_B) + 27 : (backward || uw) ? 24 : 13);
+
+ bool const match = !((m_r[4] ^ data) & size_mask[size]);
+ if ((uw == 1 && !match) || (uw == 3 && match))
{
- case SIZE_B: space(0).write_byte(block2, space(0).read_byte(block1)); break;
- case SIZE_W: space(0).write_word_unaligned(block2, space(0).read_word_unaligned(block1)); break;
- case SIZE_D: space(0).write_dword_unaligned(block2, space(0).read_dword_unaligned(block1)); break;
- default:
- // can't happen
+ m_psr |= PSR_F;
break;
}
- block1 += (size + 1);
- block2 += (size + 1);
- }
+ if (size == SIZE_D)
+ mem_write<u32>(ns32000::ST_ODT, m_r[2], data);
+ else if (size == SIZE_W)
+ mem_write<u16>(ns32000::ST_ODT, m_r[2], data);
+ else
+ mem_write<u8>(ns32000::ST_ODT, m_r[2], data);
- tcy = 20 + 3 * num;
- }
- break;
- case 0x1:
- // CMPMi block1,block2,length
- // gen,gen,disp
- // addr,addr
- {
- mode[0].addr();
- mode[1].addr();
- decode(mode, bytes);
+ tex += top(size, m_r[2]);
- u32 block1 = ea(mode[0]);
- u32 block2 = ea(mode[1]);
- unsigned const num = displacement(bytes) / (size + 1) + 1;
+ if (backward)
+ {
+ m_r[1] -= size + 1;
+ m_r[2] -= size + 1;
+ }
+ else
+ {
+ m_r[1] += size + 1;
+ m_r[2] += size + 1;
+ }
- tcy = 24;
+ m_r[0]--;
+ }
+ break;
+ case 1:
+ // CMPSi options
+ tex = 53;
m_psr |= PSR_Z;
- m_psr &= ~(PSR_N | PSR_L);
-
- // TODO: aligned/unaligned transfers?
- for (unsigned i = 0; i < num; i++)
+ m_psr &= ~(PSR_N | PSR_F | PSR_L);
+ while (m_r[0])
{
- s32 int1 = 0;
- s32 int2 = 0;
-
- switch (size)
+ u32 src1 =
+ (size == SIZE_D) ? mem_read<u32>(ns32000::ST_ODT, m_r[1]) :
+ (size == SIZE_W) ? mem_read<u16>(ns32000::ST_ODT, m_r[1]) :
+ mem_read<u8>(ns32000::ST_ODT, m_r[1]);
+ u32 src2 =
+ (size == SIZE_D) ? mem_read<u32>(ns32000::ST_ODT, m_r[2]) :
+ (size == SIZE_W) ? mem_read<u16>(ns32000::ST_ODT, m_r[2]) :
+ mem_read<u8>(ns32000::ST_ODT, m_r[2]);
+
+ if (translate)
+ src1 = mem_read<u8>(ns32000::ST_ODT, m_r[3] + u8(src1));
+
+ tex += top(size, m_r[1]) + top(size, m_r[2]) + (translate ? top(SIZE_B) + 38 : 35);
+
+ bool const match = !((m_r[4] ^ src1) & size_mask[size]);
+ if ((uw == 1 && !match) || (uw == 3 && match))
{
- case SIZE_B:
- int1 = s8(space(0).read_byte(block1));
- int2 = s8(space(0).read_byte(block2));
- break;
- case SIZE_W:
- int1 = s16(space(0).read_word_unaligned(block1));
- int2 = s16(space(0).read_word_unaligned(block2));
- break;
- case SIZE_D:
- int1 = s32(space(0).read_dword_unaligned(block1));
- int2 = s32(space(0).read_dword_unaligned(block2));
- break;
- default:
- // can't happen
+ m_psr |= PSR_F;
break;
}
- tcy += 9;
-
- if (int1 != int2)
+ if (src1 != src2)
{
m_psr &= ~PSR_Z;
- if (int1 > int2)
+
+ if ((size == SIZE_D && s32(src1) > s32(src2))
+ || ((size == SIZE_W && s16(src1) > s16(src2))
+ || ((size == SIZE_B && s8(src1) > s8(src2)))))
m_psr |= PSR_N;
- if (u32(int1) > u32(int2))
+
+ if ((size == SIZE_D && u32(src1) > u32(src2))
+ || ((size == SIZE_W && u16(src1) > u16(src2))
+ || ((size == SIZE_B && u8(src1) > u8(src2)))))
m_psr |= PSR_L;
break;
}
- block1 += (size + 1);
- block2 += (size + 1);
+ if (backward)
+ {
+ m_r[1] -= size + 1;
+ m_r[2] -= size + 1;
+ }
+ else
+ {
+ m_r[1] += size + 1;
+ m_r[2] += size + 1;
+ }
+
+ m_r[0]--;
}
- }
- break;
- case 0x2:
- // INSSi src,base,offset,length
- // gen,gen,imm
- // read.i,regaddr
- {
- mode[0].read_i(size);
- mode[1].regaddr();
- decode(mode, bytes);
+ break;
+ case 2:
+ // SETCFG cfglist
+ // short
+ if (!(m_psr & PSR_U))
+ {
+ if (type() == NS32532)
+ m_cfg = BIT(opword, 7, 4) | (CFG_P | CFG_FC | CFG_FM | CFG_FF);
+ else if (type() == NS32332)
+ m_cfg = BIT(opword, 7, 8);
+ else
+ m_cfg = BIT(opword, 7, 4);
+
+ tex = 15;
+ }
+ else
+ interrupt(ILL);
+ break;
+ case 3:
+ // SKPSi options
+ tex = 51;
- u8 const imm = space(0).read_byte(m_pc + bytes++);
- unsigned const offset = imm >> 5;
- u32 const mask = ((2ULL << (imm & 31)) - 1) << offset;
+ m_psr &= ~PSR_F;
+ while (m_r[0])
+ {
+ u32 data =
+ (size == SIZE_D) ? mem_read<u32>(ns32000::ST_ODT, m_r[1]) :
+ (size == SIZE_W) ? mem_read<u16>(ns32000::ST_ODT, m_r[1]) :
+ mem_read<u8>(ns32000::ST_ODT, m_r[1]);
- u32 const src = gen_read(mode[0]);
- u32 const base = gen_read(mode[1]);
+ if (translate)
+ data = mem_read<u8>(ns32000::ST_ODT, m_r[3] + u8(data));
- gen_write(mode[1], (base & ~mask) | ((src << offset) & mask));
+ tex += top(size, m_r[1]) + (translate ? top(SIZE_B) + 30 : 27);
- // TODO: tcy 39-49
- tcy = 39;
+ bool const match = !((m_r[4] ^ data) & size_mask[size]);
+ if ((uw == 1 && !match) || (uw == 3 && match))
+ {
+ m_psr |= PSR_F;
+ break;
+ }
+
+ if (backward)
+ m_r[1] -= size + 1;
+ else
+ m_r[1] += size + 1;
+
+ m_r[0]--;
+ }
+ break;
+ default:
+ interrupt(UND);
+ break;
}
- break;
- case 0x3:
- // EXTSi base,dst,offset,length
- // gen,gen,imm
- // regaddr,write.i
+ }
+ break;
+ case 0x4e:
+ // format 6: xxxx xyyy yyoo ooii 0100 1110
+ {
+ u16 const opword = fetch<u16>(bytes);
+
+ addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(BIT(opword, 6, 5)) };
+ size_code const size = size_code(opword & 3);
+
+ switch (BIT(opword, 2, 4))
{
- mode[0].regaddr();
- mode[1].write_i(size);
- decode(mode, bytes);
+ case 0x0:
+ // ROTi count,dst
+ // gen,gen
+ // read.B,rmw.i
+ {
+ mode[0].read_i(SIZE_B);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- u8 const imm = space(0).read_byte(m_pc + bytes++);
- unsigned const offset = imm >> 5;
- u32 const mask = (2ULL << (imm & 31)) - 1;
+ s32 const count = gen_read_sx(mode[0]);
+ u32 const src = gen_read(mode[1]);
- u32 const base = gen_read(mode[0]);
- u32 const dst = (base >> offset) & mask;
+ unsigned const limit = (size + 1) * 8 - 1;
+ u32 const dst = ((src << (count & limit)) & size_mask[size]) | ((src & size_mask[size]) >> (limit - (count & limit) + 1));
- gen_write(mode[1], dst);
+ gen_write(mode[1], dst);
- // TODO: tcy 26-36
- tcy = 26;
- }
- break;
- case 0x4:
- // MOVXBW src,dst
- // gen,gen
- // read.B,write.W
- if (size == SIZE_B)
- {
- mode[0].read_i(size);
- mode[1].write_i(SIZE_W);
- decode(mode, bytes);
+ tex = mode[0].tea + mode[1].tea + 14 + (count & limit);
+ }
+ break;
+ case 0x1:
+ // ASHi count,dst
+ // gen,gen
+ // read.B,rmw.i
+ {
+ mode[0].read_i(SIZE_B);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- u8 const src = gen_read(mode[0]);
- s16 const dst = s8(src);
+ s32 const count = gen_read_sx(mode[0]);
+ s32 const src = gen_read_sx(mode[1]);
- gen_write(mode[1], dst);
+ u32 const dst = (count < 0) ? (src >> -count) : (src << count);
- tcy = 6;
- }
- else
- interrupt(UND, m_pc);
- break;
- case 0x5:
- // MOVZBW src,dst
- // gen,gen
- // read.B,write.W
- if (size == SIZE_B)
- {
- mode[0].read_i(size);
- mode[1].write_i(SIZE_W);
- decode(mode, bytes);
+ gen_write(mode[1], dst);
- u8 const src = gen_read(mode[0]);
- u16 const dst = src;
+ tex = mode[0].tea + mode[1].tea + 14 + std::abs(count);
+ }
+ break;
+ case 0x2:
+ // CBITi offset,base
+ // gen,gen
+ // read.i,regaddr
+ case 0x3:
+ // CBITIi offset,base
+ // gen,gen
+ // read.i,regaddr
+ {
+ mode[0].read_i(size);
+ mode[1].regaddr();
+ decode(mode, bytes);
- gen_write(mode[1], dst);
+ s32 const offset = gen_read_sx(mode[0]);
- tcy = 5;
- }
- else
- interrupt(UND, m_pc);
- break;
- case 0x6:
- // MOVZiD src,dst
- // gen,gen
- // read.[BW],write.D
- if (size == SIZE_B || size == SIZE_W)
- {
- mode[0].read_i(size);
- mode[1].write_i(SIZE_D);
- decode(mode, bytes);
+ if (mode[1].type == REG)
+ {
+ if (BIT(m_r[mode[1].gen], offset & 31))
+ m_psr |= PSR_F;
+ else
+ m_psr &= ~PSR_F;
- u32 const src = gen_read(mode[0]);
+ m_r[mode[1].gen] &= ~(1U << (offset & 31));
- gen_write(mode[1], src);
+ tex = mode[0].tea + 7;
+ }
+ else
+ {
+ u32 const byte_ea = ea(mode[1]) + (offset >> 3);
+ u8 const byte = mem_read<u8>(ns32000::ST_ODT, byte_ea);
- tcy = 5;
- }
- else
- interrupt(UND, m_pc);
- break;
- case 0x7:
- // MOVXiD src,dst
- // gen,gen
- // read.[BW],write.D
- if (size == SIZE_B || size == SIZE_W)
- {
- mode[0].read_i(size);
- mode[1].write_i(SIZE_D);
- decode(mode, bytes);
+ if (BIT(byte, offset & 7))
+ m_psr |= PSR_F;
+ else
+ m_psr &= ~PSR_F;
- u32 const src = gen_read(mode[0]);
- s32 const dst = (size == SIZE_W) ? s16(src) : s8(src);
+ mem_write<u8>(ns32000::ST_ODT, byte_ea, byte & ~(1U << (offset & 7)));
- gen_write(mode[1], dst);
+ tex = mode[0].tea + mode[1].tea + top(SIZE_B) * 2 + 15;
+ }
+ }
+ break;
+ case 0x4:
+ interrupt(UND);
+ break;
+ case 0x5:
+ // LSHi count,dst
+ // gen,gen
+ // read.B,rmw.i
+ {
+ mode[0].read_i(SIZE_B);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- tcy = 6;
- }
- else
- interrupt(UND, m_pc);
- break;
- case 0x8:
- // MULi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
+ s32 const count = gen_read_sx(mode[0]);
+ u32 const src = gen_read(mode[1]);
- u32 const src1 = gen_read(mode[0]);
- u32 const src2 = gen_read(mode[1]);
+ u32 const dst = (count < 0) ? (src >> -count) : (src << count);
- u32 const dst = src1 * src2;
+ gen_write(mode[1], dst);
- gen_write(mode[1], dst);
+ tex = mode[0].tea + mode[1].tea + 14 + std::abs(count);
+ }
+ break;
+ case 0x6:
+ // SBITi offset,base
+ // gen,gen
+ // read.i,regaddr
+ case 0x7:
+ // SBITIi offset,base
+ // gen,gen
+ // read.i,regaddr
+ {
+ mode[0].read_i(size);
+ mode[1].regaddr();
+ decode(mode, bytes);
- tcy = 15;
- }
- break;
- case 0x9:
- // MEIi src,dst
- // gen,gen
- // read.i,rmw.2i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size_code(size * 2 + 1));
- decode(mode, bytes);
+ s32 const offset = gen_read_sx(mode[0]);
- u32 const src1 = gen_read(mode[0]);
- u32 const src2 = ((mode[1].type == REG)
- ? m_r[mode[1].gen ^ 0]
- : gen_read(mode[1])) & size_mask[size];
+ if (mode[1].type == REG)
+ {
+ if (BIT(m_r[mode[1].gen], offset & 31))
+ m_psr |= PSR_F;
+ else
+ m_psr &= ~PSR_F;
- u64 const dst = mulu_32x32(src1, src2);
+ m_r[mode[1].gen] |= (1U << (offset & 31));
- if (mode[1].type == REG)
+ tex = mode[0].tea + 7;
+ }
+ else
+ {
+ u32 const byte_ea = ea(mode[1]) + (offset >> 3);
+ u8 const byte = mem_read<u8>(ns32000::ST_ODT, byte_ea);
+
+ if (BIT(byte, offset & 7))
+ m_psr |= PSR_F;
+ else
+ m_psr &= ~PSR_F;
+
+ mem_write<u8>(ns32000::ST_ODT, byte_ea, byte | (1U << (offset & 7)));
+
+ tex = mode[0].tea + mode[1].tea + top(SIZE_B) * 2 + 15;
+ }
+ }
+ break;
+ case 0x8:
+ // NEGi src,dst
+ // gen,gen
+ // read.i,write.i
{
- m_r[mode[1].gen ^ 0] = (m_r[mode[1].gen ^ 0] & ~size_mask[size]) | ((dst >> 0) & size_mask[size]);
- m_r[mode[1].gen ^ 1] = (m_r[mode[1].gen ^ 1] & ~size_mask[size]) | ((dst >> ((size + 1) * 8)) & size_mask[size]);
+ mode[0].read_i(size);
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
+
+ if (src)
+ m_psr |= PSR_C;
+ else
+ m_psr &= ~PSR_C;
+
+ if ((src ^ ~(size_mask[size] >> 1)) & size_mask[size])
+ {
+ m_psr &= ~PSR_F;
+ gen_write(mode[1], -src);
+ }
+ else
+ {
+ m_psr |= PSR_F;
+ gen_write(mode[1], src);
+ }
+
+ tex = mode[0].tea + mode[1].tea + 5;
}
- else
+ break;
+ case 0x9:
+ // NOTi src,dst
+ // gen,gen
+ // read.i,write.i
+ {
+ mode[0].read_i(size);
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
+
+ gen_write(mode[1], src ^ 1U);
+
+ tex = mode[0].tea + mode[1].tea + 5;
+ }
+ break;
+ case 0xa:
+ interrupt(UND);
+ break;
+ case 0xb:
+ // SUBPi src,dst
+ // gen,gen
+ // read.i,rmw.i
+ {
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
+
+ // binary coded decimal subtraction with carry
+ // TODO: CHECK
+ u32 dst = 0;
+ bool carry = m_psr & PSR_C;
+ unsigned const tcy = carry ? 18 : 16;
+ for (unsigned digit = 0; digit < (size + 1) * 2; digit++)
+ {
+ signed sum = BIT(src2, digit * 4, 4) - BIT(src1, digit * 4, 4) - carry;
+
+ if (sum < 0)
+ {
+ sum = sum + 10;
+ carry = true;
+ }
+ else
+ carry = false;
+
+ dst |= sum << digit * 4;
+ }
+
+ if (carry)
+ m_psr |= PSR_C;
+ else
+ m_psr &= ~PSR_C;
+
gen_write(mode[1], dst);
- tcy = 23;
- }
- break;
- case 0xa:
- interrupt(UND, m_pc);
- break;
- case 0xb:
- // DEIi src,dst
- // gen,gen
- // read.i,rmw.2i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size_code(size * 2 + 1));
- decode(mode, bytes);
+ tex = mode[0].tea + mode[1].tea + tcy;
+ }
+ break;
+ case 0xc:
+ // ABSi src,dst
+ // gen,gen
+ // read.i,write.i
+ {
+ mode[0].read_i(size);
+ mode[1].write_i(size);
+ decode(mode, bytes);
- u32 const src1 = gen_read(mode[0]);
- if (src1)
+ s32 const src = gen_read_sx(mode[0]);
+
+ m_psr &= ~PSR_F;
+ if (src == s32(0x80000000) >> (32 - (size + 1) * 8))
+ {
+ m_psr |= PSR_F;
+ gen_write(mode[1], src);
+ }
+ else
+ gen_write(mode[1], std::abs(src));
+
+ tex = mode[0].tea + mode[1].tea + ((src < 0) ? 9 : 8);
+ }
+ break;
+ case 0xd:
+ // COMi src,dst
+ // gen,gen
+ // read.i,write.i
+ {
+ mode[0].read_i(size);
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
+
+ gen_write(mode[1], ~src);
+
+ tex = mode[0].tea + mode[1].tea + 7;
+ }
+ break;
+ case 0xe:
+ // IBITi offset,base
+ // gen,gen
+ // read.i,regaddr
{
- u64 const src2 = (mode[1].type == REG)
- ? (u64(m_r[mode[1].gen ^ 1] & size_mask[size]) << ((size + 1) * 8)) | (m_r[mode[1].gen ^ 0] & size_mask[size])
- : gen_read(mode[1]);
+ mode[0].read_i(size);
+ mode[1].regaddr();
+ decode(mode, bytes);
- u32 const quotient = src2 / src1;
- u32 const remainder = src2 % src1;
+ s32 const offset = gen_read_sx(mode[0]);
if (mode[1].type == REG)
{
- m_r[mode[1].gen ^ 0] = (m_r[mode[1].gen ^ 0] & ~size_mask[size]) | (remainder & size_mask[size]);
- m_r[mode[1].gen ^ 1] = (m_r[mode[1].gen ^ 1] & ~size_mask[size]) | (quotient & size_mask[size]);
+ if (BIT(m_r[mode[1].gen], offset & 31))
+ m_psr |= PSR_F;
+ else
+ m_psr &= ~PSR_F;
- tcy = 31;
+ m_r[mode[1].gen] ^= (1U << (offset & 31));
+
+ tex = mode[0].tea + 9;
}
else
{
- gen_write(mode[1], (u64(quotient) << ((size + 1) * 8)) | remainder);
+ u32 const byte_ea = ea(mode[1]) + (offset >> 3);
+ u8 const byte = mem_read<u8>(ns32000::ST_ODT, byte_ea);
+
+ if (BIT(byte, offset & 7))
+ m_psr |= PSR_F;
+ else
+ m_psr &= ~PSR_F;
- tcy = 38;
+ mem_write<u8>(ns32000::ST_ODT, byte_ea, byte ^ (1U << (offset & 7)));
+
+ tex = mode[0].tea + mode[1].tea + top(SIZE_B) * 2 + 17;
}
}
- else
+ break;
+ case 0xf:
+ // ADDPi src,dst
+ // gen,gen
+ // read.i,rmw.i
{
- // restore stack pointer
- if (mode[0].type == TOS)
- SP -= size + 1;
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
+
+ // binary coded decimal addition with carry
+ // TODO: CHECK
+ u32 dst = 0;
+ bool carry = m_psr & PSR_C;
+ unsigned const tcy = carry ? 18 : 16;
+ for (unsigned digit = 0; digit < (size + 1) * 2; digit++)
+ {
+ unsigned sum = BIT(src1, digit * 4, 4) + BIT(src2, digit * 4, 4) + carry;
+
+ if (sum > 9)
+ {
+ sum = sum - 10;
+ carry = true;
+ }
+ else
+ carry = false;
+
+ dst |= sum << digit * 4;
+ }
+
+ if (carry)
+ m_psr |= PSR_C;
+ else
+ m_psr &= ~PSR_C;
+
+ gen_write(mode[1], dst);
- interrupt(DVZ, m_pc);
+ tex = mode[0].tea + mode[1].tea + tcy;
}
+ break;
}
- break;
- case 0xc:
- // QUOi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
+ }
+ break;
+ case 0xce:
+ // format 7: xxxx xyyy yyoo ooii 1100 1110
+ {
+ u16 const opword = fetch<u16>(bytes);
+
+ addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(BIT(opword, 6, 5)) };
+ size_code const size = size_code(opword & 3);
- s32 const src1 = gen_read_sx(mode[0]);
- if (src1)
+ switch (BIT(opword, 2, 4))
+ {
+ case 0x0:
+ // MOVMi block1,block2,length
+ // gen,gen,disp
+ // addr,addr
{
- s32 const src2 = gen_read_sx(mode[1]);
+ mode[0].addr();
+ mode[1].addr();
+ decode(mode, bytes);
- s32 const dst = src2 / src1;
+ u32 block1 = ea(mode[0]);
+ u32 block2 = ea(mode[1]);
+ unsigned const num = displacement(bytes) / (size + 1) + 1;
- gen_write(mode[1], dst);
+ // TODO: aligned/unaligned transfers?
+ for (unsigned i = 0; i < num; i++)
+ {
+ switch (size)
+ {
+ case SIZE_B: mem_write<u8>(ns32000::ST_ODT, block2, mem_read<u8>(ns32000::ST_ODT, block1)); break;
+ case SIZE_W: mem_write<u16>(ns32000::ST_ODT, block2, mem_read<u16>(ns32000::ST_ODT, block1)); break;
+ case SIZE_D: mem_write<u32>(ns32000::ST_ODT, block2, mem_read<u32>(ns32000::ST_ODT, block1)); break;
+ default:
+ // can't happen
+ break;
+ }
+
+ block1 += (size + 1);
+ block2 += (size + 1);
+ }
- // TODO: tcy 49-55
- tcy = 49;
+ tex = mode[0].tea + mode[1].tea + (top(size, block1) + top(size, block2)) * num + 3 * num + 20;
}
- else
+ break;
+ case 0x1:
+ // CMPMi block1,block2,length
+ // gen,gen,disp
+ // addr,addr
{
- // restore stack pointer
- if (mode[0].type == TOS)
- SP -= size + 1;
+ mode[0].addr();
+ mode[1].addr();
+ decode(mode, bytes);
- interrupt(DVZ, m_pc);
- }
- }
- break;
- case 0xd:
- // REMi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
+ u32 block1 = ea(mode[0]);
+ u32 block2 = ea(mode[1]);
+ unsigned const num = displacement(bytes) / (size + 1) + 1;
+
+ tex = mode[0].tea + mode[1].tea + 24;
+
+ m_psr |= PSR_Z;
+ m_psr &= ~(PSR_N | PSR_L);
- s32 const src1 = gen_read_sx(mode[0]);
- if (src1)
+ // TODO: aligned/unaligned transfers?
+ for (unsigned i = 0; i < num; i++)
+ {
+ s32 int1 = 0;
+ s32 int2 = 0;
+
+ switch (size)
+ {
+ case SIZE_B:
+ int1 = s8(mem_read<u8>(ns32000::ST_ODT, block1));
+ int2 = s8(mem_read<u8>(ns32000::ST_ODT, block2));
+ break;
+ case SIZE_W:
+ int1 = s16(mem_read<u16>(ns32000::ST_ODT, block1));
+ int2 = s16(mem_read<u16>(ns32000::ST_ODT, block2));
+ break;
+ case SIZE_D:
+ int1 = s32(mem_read<u32>(ns32000::ST_ODT, block1));
+ int2 = s32(mem_read<u32>(ns32000::ST_ODT, block2));
+ break;
+ default:
+ // can't happen
+ break;
+ }
+
+ tex += top(size, block1) + top(size, block2) + 9;
+
+ if (int1 != int2)
+ {
+ m_psr &= ~PSR_Z;
+ if (int1 > int2)
+ m_psr |= PSR_N;
+ if (u32(int1) > u32(int2))
+ m_psr |= PSR_L;
+
+ break;
+ }
+
+ block1 += (size + 1);
+ block2 += (size + 1);
+ }
+ }
+ break;
+ case 0x2:
+ // INSSi src,base,offset,length
+ // gen,gen,imm
+ // read.i,regaddr
{
- s32 const src2 = gen_read_sx(mode[1]);
+ mode[0].read_i(size);
+ mode[1].regaddr();
+ decode(mode, bytes);
- s32 const dst = src2 % src1;
+ u8 const imm = fetch<u8>(bytes);
+ unsigned const offset = imm >> 5;
+ u32 const mask = ((2ULL << (imm & 31)) - 1) << offset;
- gen_write(mode[1], dst);
+ u32 const src = gen_read(mode[0]);
+ u32 const base = gen_read(mode[1]);
- // TODO: tcy 57-62
- tcy = 57;
+ gen_write(mode[1], (base & ~mask) | ((src << offset) & mask));
+
+ // TODO: tcy 39-49
+ tex = mode[0].tea + mode[1].tea + 39;
}
- else
+ break;
+ case 0x3:
+ // EXTSi base,dst,offset,length
+ // gen,gen,imm
+ // regaddr,write.i
{
- // restore stack pointer
- if (mode[0].type == TOS)
- SP -= size + 1;
+ mode[0].regaddr();
+ mode[1].write_i(size);
+ decode(mode, bytes);
- interrupt(DVZ, m_pc);
- }
- }
- break;
- case 0xe:
- // MODi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
+ u8 const imm = fetch<u8>(bytes);
+ unsigned const offset = imm >> 5;
+ u32 const mask = (2ULL << (imm & 31)) - 1;
- s32 const src1 = gen_read_sx(mode[0]);
- if (src1)
+ u32 const base = gen_read(mode[0]);
+ u32 const dst = (base >> offset) & mask;
+
+ gen_write(mode[1], dst);
+
+ // TODO: tcy 26-36
+ tex = mode[0].tea + mode[1].tea + 26;
+ }
+ break;
+ case 0x4:
+ // MOVXBW src,dst
+ // gen,gen
+ // read.B,write.W
+ if (size == SIZE_B)
{
- s32 const src2 = gen_read_sx(mode[1]);
+ mode[0].read_i(size);
+ mode[1].write_i(SIZE_W);
+ decode(mode, bytes);
- s32 const dst = (src1 + (src2 % src1)) % src1;
+ u8 const src = gen_read(mode[0]);
+ s16 const dst = s8(src);
gen_write(mode[1], dst);
- // TODO: tcy 54-73
- tcy = 54;
+ tex = mode[0].tea + mode[1].tea + 6;
}
else
+ interrupt(UND);
+ break;
+ case 0x5:
+ // MOVZBW src,dst
+ // gen,gen
+ // read.B,write.W
+ if (size == SIZE_B)
{
- // restore stack pointer
- if (mode[0].type == TOS)
- SP -= size + 1;
+ mode[0].read_i(size);
+ mode[1].write_i(SIZE_W);
+ decode(mode, bytes);
- interrupt(DVZ, m_pc);
- }
- }
- break;
- case 0xf:
- // DIVi src,dst
- // gen,gen
- // read.i,rmw.i
- {
- mode[0].read_i(size);
- mode[1].rmw_i(size);
- decode(mode, bytes);
+ u8 const src = gen_read(mode[0]);
+ u16 const dst = src;
- s32 const src1 = gen_read_sx(mode[0]);
- if (src1)
+ gen_write(mode[1], dst);
+
+ tex = mode[0].tea + mode[1].tea + 5;
+ }
+ else
+ interrupt(UND);
+ break;
+ case 0x6:
+ // MOVZiD src,dst
+ // gen,gen
+ // read.[BW],write.D
+ if (size == SIZE_B || size == SIZE_W)
{
- s32 const src2 = gen_read_sx(mode[1]);
+ mode[0].read_i(size);
+ mode[1].write_i(SIZE_D);
+ decode(mode, bytes);
- s32 const quotient = src2 / src1;
- s32 const remainder = src2 % src1;
+ u32 const src = gen_read(mode[0]);
- if ((quotient < 0) && remainder)
- gen_write(mode[1], quotient - 1);
- else
- gen_write(mode[1], quotient);
+ gen_write(mode[1], src);
- // TODO: tcy 58-68
- tcy = 58;
+ tex = mode[0].tea + mode[1].tea + 5;
}
else
+ interrupt(UND);
+ break;
+ case 0x7:
+ // MOVXiD src,dst
+ // gen,gen
+ // read.[BW],write.D
+ if (size == SIZE_B || size == SIZE_W)
{
- // restore stack pointer
- if (mode[0].type == TOS)
- SP -= size + 1;
+ mode[0].read_i(size);
+ mode[1].write_i(SIZE_D);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
+ s32 const dst = (size == SIZE_W) ? s16(src) : s8(src);
+
+ gen_write(mode[1], dst);
- interrupt(DVZ, m_pc);
+ tex = mode[0].tea + mode[1].tea + 6;
}
- }
- break;
- }
- }
- break;
- case 0x2e:
- case 0x6e:
- case 0xae:
- case 0xee:
- // format 8: xxxx xyyy yyrr roii oo10 1110
- {
- u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
- bytes += 2;
+ else
+ interrupt(UND);
+ break;
+ case 0x8:
+ // MULi src,dst
+ // gen,gen
+ // read.i,rmw.i
+ {
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
- unsigned const reg = (opword >> 3) & 7;
- size_code const size = size_code(opword & 3);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- switch ((opword & 4) | (opbyte >> 6))
- {
- case 0:
- // EXTi offset,base,dst,length
- // reg,gen,gen,disp
- // regaddr,write.i
- {
- mode[0].regaddr();
- mode[1].write_i(size);
- decode(mode, bytes);
+ u32 const dst = src1 * src2;
- s32 const offset = m_r[reg];
- s32 const length = displacement(bytes);
- u32 const mask = (1U << length) - 1;
+ gen_write(mode[1], dst);
- u32 dst;
- if (mode[0].type != REG)
+ tex = mode[0].tea + mode[1].tea + 15 + (size + 1) * 16; // 2+2 + 15 + 16 ==
+ }
+ break;
+ case 0x9:
+ // MEIi src,dst
+ // gen,gen
+ // read.i,rmw.2i
{
- u32 const base_ea = ea(mode[0]) + (offset >> 3);
- u32 const base = space(0).read_dword_unaligned(base_ea);
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- dst = (base >> (offset & 7));
+ mode[1].rmw_i(size_code(size * 2 + 1));
+ u64 const dst = mulu_32x32(src1, src2);
- // TODO: tcy 17-51
- tcy = 17;
+ if (mode[1].type == REG)
+ {
+ m_r[mode[1].gen ^ 0] = (m_r[mode[1].gen ^ 0] & ~size_mask[size]) | ((dst >> 0) & size_mask[size]);
+ m_r[mode[1].gen ^ 1] = (m_r[mode[1].gen ^ 1] & ~size_mask[size]) | ((dst >> ((size + 1) * 8)) & size_mask[size]);
+ }
+ else
+ // TODO: write high dword first
+ gen_write(mode[1], dst);
+
+ tex = mode[0].tea + mode[1].tea + 23 + (size + 1) * 16;
}
- else
+ break;
+ case 0xa:
+ interrupt(UND);
+ break;
+ case 0xb:
+ // DEIi src,dst
+ // gen,gen
+ // read.i,rmw.2i
{
- dst = (m_r[mode[0].gen] >> (offset & 31));
+ mode[0].read_i(size);
+ mode[1].rmw_i(size_code(size * 2 + 1));
+ decode(mode, bytes);
- // TODO: tcy 19-29
- tcy = 19;
+ u32 const src1 = gen_read(mode[0]);
+ if (src1)
+ {
+ u64 const src2 = (mode[1].type == REG)
+ ? (u64(m_r[mode[1].gen ^ 1] & size_mask[size]) << ((size + 1) * 8)) | (m_r[mode[1].gen ^ 0] & size_mask[size])
+ : gen_read(mode[1]);
+
+ u32 const quotient = src2 / src1;
+ u32 const remainder = src2 % src1;
+
+ if (mode[1].type == REG)
+ {
+ m_r[mode[1].gen ^ 0] = (m_r[mode[1].gen ^ 0] & ~size_mask[size]) | (remainder & size_mask[size]);
+ m_r[mode[1].gen ^ 1] = (m_r[mode[1].gen ^ 1] & ~size_mask[size]) | (quotient & size_mask[size]);
+
+ tex = mode[0].tea + 31 + (size + 1) * 16;
+ }
+ else
+ {
+ gen_write(mode[1], (u64(quotient) << ((size + 1) * 8)) | remainder);
+
+ tex = mode[0].tea + mode[1].tea + 38 + (size + 1) * 16;
+ }
+ }
+ else
+ interrupt(DVZ);
}
+ break;
+ case 0xc:
+ // QUOi src,dst
+ // gen,gen
+ // read.i,rmw.i
+ {
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- gen_write(mode[1], dst & mask);
- }
- break;
- case 1:
- // CVTP offset,base,dst
- // reg,gen,gen
- // addr,write.D
- if (size == SIZE_D)
- {
- mode[0].addr();
- mode[1].write_i(size);
- decode(mode, bytes);
+ s32 const src1 = gen_read_sx(mode[0]);
+ if (src1)
+ {
+ s32 const src2 = gen_read_sx(mode[1]);
- s32 const offset = s32(m_r[reg]);
- u32 const base = ea(mode[0]);
+ s32 const dst = src2 / src1;
- gen_write(mode[1], base * 8 + offset);
+ gen_write(mode[1], dst);
- tcy = 7;
- }
- else
- interrupt(UND, m_pc);
- break;
- case 2:
- // INSi offset,src,base,length
- // reg,gen,gen,disp
- // read.i,regaddr
- {
- mode[0].read_i(size);
- mode[1].regaddr();
- decode(mode, bytes);
+ // TODO: tcy 49-55
+ tex = mode[0].tea + mode[1].tea + 49 + (size + 1) * 16;
+ }
+ else
+ interrupt(DVZ);
+ }
+ break;
+ case 0xd:
+ // REMi src,dst
+ // gen,gen
+ // read.i,rmw.i
+ {
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- s32 const offset = m_r[reg];
- s32 const length = displacement(bytes);
- u32 const src = gen_read(mode[0]);
+ s32 const src1 = gen_read_sx(mode[0]);
+ if (src1)
+ {
+ s32 const src2 = gen_read_sx(mode[1]);
- u32 dst;
- if (mode[1].type == REG)
- {
- u32 const base = m_r[mode[1].gen];
- u32 const mask = ((1U << length) - 1) << (offset & 31);
+ s32 const dst = src2 % src1;
- dst = (base & ~mask) | ((src << (offset & 31)) & mask);
+ gen_write(mode[1], dst);
- // TODO: tcy 29-39
- tcy = 29;
+ // TODO: tcy 57-62
+ tex = mode[0].tea + mode[1].tea + 57 + (size + 1) * 16;
+ }
+ else
+ interrupt(DVZ);
}
- else
+ break;
+ case 0xe:
+ // MODi src,dst
+ // gen,gen
+ // read.i,rmw.i
{
- u32 const base_ea = ea(mode[1]) + (offset >> 3);
- u32 const base = space(0).read_dword_unaligned(base_ea);
- u32 const mask = ((1U << length) - 1) << (offset & 7);
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ s32 const src1 = gen_read_sx(mode[0]);
+ if (src1)
+ {
+ s32 const src2 = gen_read_sx(mode[1]);
+
+ s32 const dst = (src1 + (src2 % src1)) % src1;
- dst = (base & ~mask) | ((src << (offset & 7)) & mask);
+ gen_write(mode[1], dst);
- // TODO: tcy 28-96
- tcy = 28;
+ // TODO: tcy 54-73
+ tex = mode[0].tea + mode[1].tea + 54 + (size + 1) * 16;
+ }
+ else
+ interrupt(DVZ);
}
+ break;
+ case 0xf:
+ // DIVi src,dst
+ // gen,gen
+ // read.i,rmw.i
+ {
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- gen_write(mode[1], dst);
+ s32 const src1 = gen_read_sx(mode[0]);
+ if (src1)
+ {
+ s32 const src2 = gen_read_sx(mode[1]);
+
+ s32 const quotient = src2 / src1;
+ s32 const remainder = src2 % src1;
+
+ if ((quotient < 0) && remainder)
+ gen_write(mode[1], quotient - 1);
+ else
+ gen_write(mode[1], quotient);
+
+ // TODO: tcy 58-68
+ tex = mode[0].tea + mode[1].tea + 58 + (size + 1) * 16;
+ }
+ else
+ interrupt(DVZ);
+ }
+ break;
}
- break;
- case 3:
- // CHECKi dst,bounds,src
- // reg,gen,gen
- // addr,read.i
- {
- mode[0].addr();
- mode[1].read_i(size);
- decode(mode, bytes);
+ }
+ break;
+ case 0x2e:
+ case 0x6e:
+ case 0xae:
+ case 0xee:
+ // format 8: xxxx xyyy yyrr roii oo10 1110
+ {
+ u16 const opword = fetch<u16>(bytes);
- u32 const bounds = ea(mode[0]);
- s32 const src = gen_read_sx(mode[1]);
+ addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(BIT(opword, 6, 5)) };
+ unsigned const reg = BIT(opword, 3, 3);
+ size_code const size = size_code(opword & 3);
- s32 lower = 0;
- s32 upper = 0;
- switch (size)
+ switch ((opword & 4) | BIT(opbyte, 6, 2))
+ {
+ case 0:
+ // EXTi offset,base,dst,length
+ // reg,gen,gen,disp
+ // regaddr,write.i
{
- case SIZE_B:
- upper = s8(space(0).read_byte(bounds + 0));
- lower = s8(space(0).read_byte(bounds + 1));
- break;
- case SIZE_W:
- upper = s16(space(0).read_word_unaligned(bounds + 0));
- lower = s16(space(0).read_word_unaligned(bounds + 2));
- break;
- case SIZE_D:
- upper = s32(space(0).read_dword_unaligned(bounds + 0));
- lower = s32(space(0).read_dword_unaligned(bounds + 4));
- break;
- default:
- // can't happen
- break;
- }
+ mode[0].regaddr();
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ s32 const offset = m_r[reg];
+ s32 const length = displacement(bytes);
+ u32 const mask = (1U << length) - 1;
+
+ if (mode[0].type == REG)
+ {
+ gen_write(mode[1], (m_r[mode[0].gen] >> (offset & 31)) & mask);
+
+ // TODO: tcy 17-51
+ tex = mode[0].tea + mode[1].tea + 17;
+ }
+ else
+ {
+ u32 const base_ea = ea(mode[0]) + (offset >> 3);
+ u32 const base = mem_read<u32>(ns32000::ST_ODT, base_ea);
- if (src >= lower && src <= upper)
+ gen_write(mode[1], (base >> (offset & 7)) & mask);
+
+ // TODO: tcy 19-29
+ tex = mode[0].tea + mode[1].tea + top(SIZE_D, base_ea) + 19;
+ }
+ }
+ break;
+ case 1:
+ // CVTP offset,base,dst
+ // reg,gen,gen
+ // addr,write.D
+ if (size == SIZE_D)
{
- m_psr &= ~PSR_F;
- m_r[reg] = src - lower;
+ mode[0].addr();
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ s32 const offset = s32(m_r[reg]);
+ u32 const base = ea(mode[0]);
+
+ gen_write(mode[1], base * 8 + offset);
- tcy = 11;
+ tex = mode[0].tea + mode[1].tea + 7;
}
else
+ interrupt(UND);
+ break;
+ case 2:
+ // INSi offset,src,base,length
+ // reg,gen,gen,disp
+ // read.i,regaddr
{
- m_psr |= PSR_F;
+ mode[0].read_i(size);
+ mode[1].regaddr();
+ decode(mode, bytes);
- tcy = (src >= lower) ? 7 : 10;
- }
- }
- break;
- case 4:
- // INDEXi accum,length,index
- // reg,gen,gen
- // read.i,read.i
- {
- mode[0].read_i(size);
- mode[1].read_i(size);
- decode(mode, bytes);
+ s32 const offset = m_r[reg];
+ s32 const length = displacement(bytes);
+ u32 const src = gen_read(mode[0]);
- u32 const length = gen_read(mode[0]);
- u32 const index = gen_read(mode[1]);
+ if (mode[1].type == REG)
+ {
+ u32 const mask = ((1U << length) - 1) << (offset & 31);
- m_r[reg] = m_r[reg] * (length + 1) + index;
+ m_r[mode[1].gen] = (m_r[mode[1].gen] & ~mask) | ((src << (offset & 31)) & mask);
- tcy = 25;
- }
- break;
- case 5:
- // FFSi base,offset
- // gen,gen
- // read.i,rmw.B
- {
- mode[0].read_i(size);
- mode[1].rmw_i(SIZE_B);
- decode(mode, bytes);
+ // TODO: tcy 28-96
+ tex = mode[0].tea + 28;
+ }
+ else
+ {
+ u32 const base_ea = ea(mode[1]) + (offset >> 3);
+ u32 const base = mem_read<u32>(ns32000::ST_ODT, base_ea);
+ u32 const mask = ((1U << length) - 1) << (offset & 7);
+
+ mem_write<u32>(ns32000::ST_ODT, base_ea, (base & ~mask) | ((src << (offset & 7)) & mask));
- u32 const base = gen_read(mode[0]);
- u32 offset = gen_read(mode[1]);
- unsigned const limit = (size + 1) * 8;
+ // TODO: tcy 29-39
+ tex = mode[0].tea + mode[1].tea + top(SIZE_D, base_ea) * 2 + 29;
+ }
+ }
+ break;
+ case 3:
+ // CHECKi dst,bounds,src
+ // reg,gen,gen
+ // addr,read.i
+ {
+ mode[0].addr();
+ mode[1].read_i(size);
+ decode(mode, bytes);
+
+ u32 const bounds = ea(mode[0]);
+ s32 const src = gen_read_sx(mode[1]);
- m_psr |= PSR_F;
- while (offset < limit)
- if (BIT(base, offset))
+ s32 lower = 0;
+ s32 upper = 0;
+ switch (size)
{
- m_psr &= ~PSR_F;
+ case SIZE_B:
+ upper = s8(mem_read<u8>(ns32000::ST_ODT, bounds + 0));
+ lower = s8(mem_read<u8>(ns32000::ST_ODT, bounds + 1));
+ break;
+ case SIZE_W:
+ upper = s16(mem_read<u16>(ns32000::ST_ODT, bounds + 0));
+ lower = s16(mem_read<u16>(ns32000::ST_ODT, bounds + 2));
+ break;
+ case SIZE_D:
+ upper = s32(mem_read<u32>(ns32000::ST_ODT, bounds + 0));
+ lower = s32(mem_read<u32>(ns32000::ST_ODT, bounds + 4));
+ break;
+ default:
+ // can't happen
break;
}
- else
- offset++;
- gen_write(mode[1], offset & (limit - 1));
-
- // TODO: tcy 24-28
- tcy = 24;
- }
- break;
- case 6:
- // MOVSU/MOVUS src,dst
- // gen,gen
- // addr,addr
- {
- mode[0].addr();
- mode[1].addr();
- decode(mode, bytes);
+ if (src >= lower && src <= upper)
+ {
+ m_psr &= ~PSR_F;
- fatalerror("unimplemented: movsu/movus (%s)\n", machine().describe_context());
+ tex = mode[0].tea + mode[1].tea + top(size, bounds) * 2 + 11;
+ }
+ else
+ {
+ m_psr |= PSR_F;
- tcy = 33;
- }
- break;
- }
- }
- break;
- case 0x3e:
- // format 9: xxxx xyyy yyoo ofii 0011 1110
- if (m_cfg & CFG_F)
- {
- if (!m_fpu)
- fatalerror("floating point unit not configured (%s)\n", machine().describe_context());
+ tex = mode[0].tea + mode[1].tea + top(size, bounds) * 2 + ((src >= lower) ? 7 : 10);
+ }
- u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
- bytes += 2;
+ // updating the destination when out of bounds
+ // is undefined, but required by DB32016 firmware
+ m_r[reg] = (src - lower) & size_mask[size];
+ }
+ break;
+ case 4:
+ // INDEXi accum,length,index
+ // reg,gen,gen
+ // read.i,read.i
+ {
+ mode[0].read_i(size);
+ mode[1].read_i(size);
+ decode(mode, bytes);
- addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
- size_code const size_f = BIT(opword, 0) ? SIZE_D : SIZE_Q;
- size_code const size = size_code(opword & 3);
+ u32 const length = gen_read(mode[0]);
+ u32 const index = gen_read(mode[1]);
- m_fpu->write_id(opbyte);
- m_fpu->write_op(swapendian_int16(opword));
+ m_r[reg] = m_r[reg] * (length + 1) + index;
- switch ((opword >> 3) & 7)
- {
- case 0:
- // MOVif src,dst
- // gen,gen
- // read.i,write.f
- mode[0].read_i(size);
- mode[1].write_f(size_f);
- decode(mode, bytes);
+ tex = mode[0].tea + mode[1].tea + 25 + (size + 1) * 16;
+ }
+ break;
+ case 5:
+ // FFSi base,offset
+ // gen,gen
+ // read.i,rmw.B
+ {
+ mode[0].read_i(size);
+ mode[1].rmw_i(SIZE_B);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 1:
- // LFSR src
- // gen
- // read.D
- mode[0].read_i(size);
- decode(mode, bytes);
+ u32 const base = gen_read(mode[0]);
+ u32 offset = gen_read(mode[1]);
+ unsigned const limit = (size + 1) * 8;
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 2:
- // MOVLF src,dst
- // gen,gen
- // read.L,write.F
- mode[0].read_f(SIZE_Q);
- mode[1].write_f(size_f);
- decode(mode, bytes);
+ m_psr |= PSR_F;
+ while (offset < limit)
+ if (BIT(base, offset))
+ {
+ m_psr &= ~PSR_F;
+ break;
+ }
+ else
+ offset++;
+
+ gen_write(mode[1], offset & (limit - 1));
+
+ // TODO: tcy 24-28
+ tex = mode[0].tea + mode[1].tea + 24 + (size + 1) * 24;
+ }
+ break;
+ case 6:
+ // MOVSU/MOVUS src,dst
+ // gen,gen
+ // addr,addr
+ if (!(m_psr & PSR_U))
+ {
+ if (reg == 1 || reg == 3)
+ {
+ mode[0].addr();
+ mode[1].addr();
+ decode(mode, bytes);
+
+ switch (size)
+ {
+ case SIZE_B: mem_write<u8>(ns32000::ST_ODT, ea(mode[1]), mem_read<u8>(ns32000::ST_ODT, ea(mode[0]), reg == 3), reg == 1); break;
+ case SIZE_W: mem_write<u16>(ns32000::ST_ODT, ea(mode[1]), mem_read<u16>(ns32000::ST_ODT, ea(mode[0]), reg == 3), reg == 1); break;
+ case SIZE_D: mem_write<u32>(ns32000::ST_ODT, ea(mode[1]), mem_read<u32>(ns32000::ST_ODT, ea(mode[0]), reg == 3), reg == 1); break;
+ default:
+ // can't happen
+ break;
+ }
+
+ tex = mode[0].tea + mode[1].tea + top(size) * 2 + 33;
+ }
+ else
+ interrupt(UND);
+ }
+ else
+ interrupt(ILL);
+ break;
+ }
+ }
+ break;
+ case ns32000_slave_interface::FORMAT_9:
+ // format 9: xxxx xyyy yyoo ofii 0011 1110
+ if (m_cfg & CFG_F)
+ {
+ u16 const opword = fetch<u16>(bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 3:
- // MOVFL src,dst
- // gen,gen
- // read.F,write.L
- mode[0].read_f(SIZE_D);
- mode[1].write_f(size_f);
- decode(mode, bytes);
+ addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(BIT(opword, 6, 5)) };
+ size_code const size_f = BIT(opword, 2) ? SIZE_D : SIZE_Q;
+ size_code const size = size_code(opword & 3);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 4:
- // ROUNDfi src,dst
- // gen,gen
- // read.f,write.i
- mode[0].read_f(size_f);
- mode[1].write_i(size);
- decode(mode, bytes);
+ switch (BIT(opword, 3, 3))
+ {
+ case 0:
+ // MOVif src,dst
+ // gen,gen
+ // read.i,write.f
+ mode[0].read_i(size);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 5:
- // TRUNCfi src,dst
- // gen,gen
- // read.f,write.i
- mode[0].read_f(size_f);
- mode[1].write_i(size);
- decode(mode, bytes);
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 1:
+ // LFSR src
+ // gen
+ // read.D
+ mode[0].read_i(size);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 6:
- // SFSR dst
- // gen
- // write.D
- mode[0].write_i(size);
- decode(mode, bytes);
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 2:
+ // MOVLF src,dst
+ // gen,gen
+ // read.L,write.F
+ mode[0].read_f(SIZE_Q);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[1], mode[0]))
- interrupt(FPU, m_pc);
- break;
- case 7:
- // FLOORfi src,dst
- // gen,gen
- // read.f,write.i
- mode[0].read_f(size_f);
- mode[1].write_i(size);
- decode(mode, bytes);
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 3:
+ // MOVFL src,dst
+ // gen,gen
+ // read.F,write.L
+ mode[0].read_f(SIZE_D);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- }
- }
- else
- interrupt(UND, m_pc);
- break;
- case 0x7e: // format 10
- interrupt(UND, m_pc);
- break;
- case 0xbe:
- // format 11: xxxx xyyy yyoo oo0f 1011 1110
- if (m_cfg & CFG_F)
- {
- if (!m_fpu)
- fatalerror("floating point unit not configured (%s)\n", machine().describe_context());
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 4:
+ // ROUNDfi src,dst
+ // gen,gen
+ // read.f,write.i
+ mode[0].read_f(size_f);
+ mode[1].write_i(size);
+ decode(mode, bytes);
- u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
- bytes += 2;
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 5:
+ // TRUNCfi src,dst
+ // gen,gen
+ // read.f,write.i
+ mode[0].read_f(size_f);
+ mode[1].write_i(size);
+ decode(mode, bytes);
- addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
- size_code const size_f = BIT(opword, 0) ? SIZE_D : SIZE_Q;
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 6:
+ // SFSR dst
+ // gen
+ // write.D
+ mode[1].write_i(size);
+ decode(mode, bytes);
- m_fpu->write_id(opbyte);
- m_fpu->write_op(swapendian_int16(opword));
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 7:
+ // FLOORfi src,dst
+ // gen,gen
+ // read.f,write.i
+ mode[0].read_f(size_f);
+ mode[1].write_i(size);
+ decode(mode, bytes);
- switch ((opword >> 2) & 15)
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ }
+ }
+ else
+ interrupt(UND);
+ break;
+ case 0x7e: // format 10
+ interrupt(UND);
+ break;
+ case ns32000_slave_interface::FORMAT_11:
+ // format 11: xxxx xyyy yyoo oo0f 1011 1110
+ if (m_cfg & CFG_F)
{
- case 0x0:
- // ADDf src,dst
- // gen,gen
- // read.f,rmw.f
- mode[0].read_f(size_f);
- mode[1].rmw_f(size_f);
- decode(mode, bytes);
+ u16 const opword = fetch<u16>(bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 0x1:
- // MOVf src,dst
- // gen,gen
- // read.f,write.f
- mode[0].read_f(size_f);
- mode[1].write_f(size_f);
- decode(mode, bytes);
+ addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(BIT(opword, 6, 5)) };
+ size_code const size_f = BIT(opword, 0) ? SIZE_D : SIZE_Q;
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 0x2:
- // CMPf src1,src2
- // gen,gen
- // read.f,read.f
+ switch (BIT(opword, 2, 4))
{
+ case 0x0:
+ // ADDf src,dst
+ // gen,gen
+ // read.f,rmw.f
mode[0].read_f(size_f);
- mode[1].read_f(size_f);
+ mode[1].rmw_f(size_f);
decode(mode, bytes);
- u16 const status = slave(mode[0], mode[1]);
- if (!(status & ns32000_slave_interface::SLAVE_Q))
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0x1:
+ // MOVf src,dst
+ // gen,gen
+ // read.f,write.f
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0x2:
+ // CMPf src1,src2
+ // gen,gen
+ // read.f,read.f
{
- m_psr &= ~(PSR_N | PSR_Z | PSR_L);
- m_psr |= status & (ns32000_slave_interface::SLAVE_N | ns32000_slave_interface::SLAVE_Z | ns32000_slave_interface::SLAVE_L);
+ mode[0].read_f(size_f);
+ mode[1].read_f(size_f);
+ decode(mode, bytes);
+
+ u16 const status = slave(opbyte, opword, mode[0], mode[1]);
+ if (!(status & ns32000_slave_interface::SLAVE_Q))
+ {
+ m_psr &= ~(PSR_N | PSR_Z | PSR_L);
+ m_psr |= status & (ns32000_slave_interface::SLAVE_N | ns32000_slave_interface::SLAVE_Z | ns32000_slave_interface::SLAVE_L);
+ }
+ else
+ interrupt(SLV);
}
- else
- interrupt(FPU, m_pc);
- }
- break;
- case 0x3:
- // Trap(SLAVE)
- // operands from ns32532 datasheet
- mode[0].read_f(size_f);
- mode[1].read_f(size_f);
- decode(mode, bytes);
+ break;
+ case 0x3:
+ // Trap(SLAVE)
+ // not defined; treat like CMPf
+ mode[0].read_f(size_f);
+ mode[1].read_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 0x4:
- // SUBf src,dst
- // gen,gen
- // read.f,rmw.f
- mode[0].read_f(size_f);
- mode[1].rmw_f(size_f);
- decode(mode, bytes);
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0x4:
+ // SUBf src,dst
+ // gen,gen
+ // read.f,rmw.f
+ mode[0].read_f(size_f);
+ mode[1].rmw_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 0x5:
- // NEGf src,dst
- // gen,gen
- // read.f,write.f
- mode[0].read_f(size_f);
- mode[1].write_f(size_f);
- decode(mode, bytes);
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0x5:
+ // NEGf src,dst
+ // gen,gen
+ // read.f,write.f
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 0x8:
- // DIVf src,dst
- // gen,gen
- // read.f,rmw.f
- mode[0].read_f(size_f);
- mode[1].rmw_f(size_f);
- decode(mode, bytes);
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0x8:
+ // DIVf src,dst
+ // gen,gen
+ // read.f,rmw.f
+ mode[0].read_f(size_f);
+ mode[1].rmw_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 0x9:
- // Trap(SLAVE)
- // operands from ns32532 datasheet
- mode[0].read_f(size_f);
- mode[1].write_f(size_f);
- decode(mode, bytes);
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0x9:
+ // Trap(SLAVE)
+ // not defined; treat like MOVf
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 0xc:
- // MULf src,dst
- // gen,gen
- // read.f,rmw.f
- mode[0].read_f(size_f);
- mode[1].rmw_f(size_f);
- decode(mode, bytes);
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0xc:
+ // MULf src,dst
+ // gen,gen
+ // read.f,rmw.f
+ mode[0].read_f(size_f);
+ mode[1].rmw_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
- case 0xd:
- // ABSf src,dst
- // gen,gen
- // read.f,write.f
- mode[0].read_f(size_f);
- mode[1].write_f(size_f);
- decode(mode, bytes);
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0xd:
+ // ABSf src,dst
+ // gen,gen
+ // read.f,write.f
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
- if (slave(mode[0], mode[1]))
- interrupt(FPU, m_pc);
- break;
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ }
}
- }
- else
- interrupt(UND, m_pc);
- break;
- case 0xfe: // format 12
- case 0x9e: // format 13
- interrupt(UND, m_pc);
- break;
- case 0x1e:
- // format 14: xxxx xsss s0oo ooii 0001 1110
- if (!(m_psr & PSR_U))
- {
- if (m_cfg & CFG_M)
+ else
+ interrupt(UND);
+ break;
+ case ns32000_slave_interface::FORMAT_12:
+ // format 12: xxxx xyyy yyoo oo0f 1111 1110
+ if ((m_cfg & CFG_F) && type() == NS32332)
{
- u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
- bytes += 2;
+ u16 const opword = fetch<u16>(bytes);
- addr_mode mode[] = { addr_mode((opword >> 11) & 31), addr_mode(0x13) };
-
- //unsigned const quick = (opword >> 7) & 15;
- size_code const size = size_code(opword & 3);
+ addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(BIT(opword, 6, 5)) };
+ size_code const size_f = BIT(opword, 0) ? SIZE_D : SIZE_Q;
- // TODO: mmu instructions
- switch ((opword >> 2) & 15)
+ switch (BIT(opword, 2, 4))
{
- case 0:
- // RDVAL loc
- // gen
- // addr
- mode[0].addr();
+ case 0x2:
+ // POLYf src,dst
+ // gen,gen
+ // read.f,read.f
+ mode[0].read_f(size_f);
+ mode[1].read_f(size_f);
decode(mode, bytes);
- tcy = 21;
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
break;
- case 1:
- // WRVAL loc
- // gen
- // addr
- mode[0].addr();
+ case 0x3:
+ // DOTf src,dst
+ // gen,gen
+ // read.f,read.f
+ mode[0].read_f(size_f);
+ mode[1].read_f(size_f);
decode(mode, bytes);
- tcy = 21;
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
break;
- case 2:
- // LMR mmureg,src
- // short,gen
- // read.D
- mode[0].read_i(size);
+ case 0x4:
+ // SCALBf src,dst
+ // gen,gen
+ // read.f,rmw.f
+ mode[0].read_f(size_f);
+ mode[1].rmw_f(size_f);
decode(mode, bytes);
- tcy = 30;
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
break;
- case 3:
- // SMR mmureg,dst
- // short,gen
- // write.D
- mode[0].write_i(size);
+ case 0x5:
+ // LOGBf src,dst
+ // gen,gen
+ // read.f,write.f
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
decode(mode, bytes);
- tcy = 25;
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
break;
- default:
- interrupt(UND, m_pc);
+ case 0x0: // REMf
+ case 0x8: // Trap(SLV)
+ case 0xc: // ATAN2f
+ // not defined; treat like ADDf
+ mode[0].read_f(size_f);
+ mode[1].rmw_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0x1: // SQRTf
+ case 0x9: // Trap(SLV)
+ case 0xd: // SICOSf
+ // not defined; treat like MOVf
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+ break;
+ case 0x6: // Trap(UND)
+ case 0x7: // Trap(UND)
+ case 0xa: // Trap(UND)
+ case 0xb: // Trap(UND)
+ case 0xe: // Trap(UND)
+ case 0xf: // Trap(UND)
+ interrupt(UND);
break;
}
}
else
- interrupt(UND, m_pc);
+ interrupt(UND);
+ break;
+ case 0x9e: // format 13
+ interrupt(UND);
+ break;
+ case ns32000_slave_interface::FORMAT_14:
+ // format 14: xxxx xsss s0oo ooii 0001 1110
+ if (!(m_psr & PSR_U))
+ {
+ if (m_cfg & CFG_M)
+ {
+ u16 const opword = fetch<u16>(bytes);
+
+ addr_mode mode[] = { addr_mode(BIT(opword, 11, 5)), addr_mode(0x13) };
+
+ //unsigned const quick = BIT(opword, 7, 4);
+ size_code const size = size_code(opword & 3);
+
+ switch (BIT(opword, 2, 4))
+ {
+ case 0:
+ // RDVAL loc
+ // gen
+ // addr
+ {
+ mode[0].addr();
+ decode(mode, bytes);
+
+ u16 const status = slave(opbyte, opword, mode[0], mode[1]);
+ if (!(status & ns32000_slave_interface::SLAVE_Q))
+ {
+ if (status & ns32000_slave_interface::SLAVE_F)
+ m_psr |= PSR_F;
+ else
+ m_psr &= ~PSR_F;
+ }
+ else
+ interrupt(SLV);
+
+ tex = mode[0].tea + top(SIZE_B) + 21;
+ }
+ break;
+ case 1:
+ // WRVAL loc
+ // gen
+ // addr
+ {
+ mode[0].addr();
+ decode(mode, bytes);
+
+ u16 const status = slave(opbyte, opword, mode[0], mode[1]);
+ if (!(status & ns32000_slave_interface::SLAVE_Q))
+ {
+ if (status & ns32000_slave_interface::SLAVE_F)
+ m_psr |= PSR_F;
+ else
+ m_psr &= ~PSR_F;
+ }
+ else
+ interrupt(SLV);
+
+ tex = mode[0].tea + top(SIZE_B) + 21;
+ }
+ break;
+ case 2:
+ // LMR mmureg,src
+ // short,gen
+ // read.D
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+
+ tex = mode[0].tea + top(size);
+ break;
+ case 3:
+ // SMR mmureg,dst
+ // short,gen
+ // write.D
+ mode[0].write_i(size);
+ decode(mode, bytes);
+
+ if (slave(opbyte, opword, mode[1], mode[0]))
+ interrupt(SLV);
+
+ tex = mode[0].tea + top(size);
+ break;
+ case 9:
+ if (type() == NS32532)
+ {
+ // CINV options,src
+ // short,gen
+ // read.D
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
+ if (slave(opbyte, opword, mode[0], mode[1]))
+ interrupt(SLV);
+
+ // TODO: tex
+ }
+ else
+ interrupt(UND);
+ break;
+ default:
+ interrupt(UND);
+ break;
+ }
+ }
+ else
+ interrupt(UND);
+ }
+ else
+ interrupt(ILL);
+ break;
+ case 0x16: // format 15.0
+ case 0x36: // format 15.1
+ case 0xb6: // format 15.5
+ // TODO: custom coprocessor
+ break;
+ case 0x5e: // format 16
+ case 0xde: // format 17
+ case 0x8e: // format 18
+ case 0x06:
+ case 0x26:
+ case 0x46:
+ case 0x66:
+ case 0x86:
+ case 0xa6:
+ case 0xc6:
+ case 0xe6:
+ // format 19
+ interrupt(UND);
+ break;
}
- else
- interrupt(ILL, m_pc);
- break;
- case 0x16: // format 15.0
- case 0x36: // format 15.1
- case 0xb6: // format 15.5
- // TODO: custom coprocessor
- break;
- case 0x5e: // format 16
- case 0xde: // format 17
- case 0x8e: // format 18
- case 0x06:
- case 0x26:
- case 0x46:
- case 0x66:
- case 0x86:
- case 0xa6:
- case 0xc6:
- case 0xe6:
- // format 19
- interrupt(UND, m_pc);
- break;
- }
- if (m_sequential)
- m_pc += bytes;
+ if (m_sequential)
+ m_pc += bytes;
- // trace trap
- if (m_psr & PSR_P)
- interrupt(TRC, m_pc);
+ // trace trap
+ if (m_psr & PSR_P)
+ interrupt(TRC);
+
+ m_icount -= tex;
+ }
+ catch (ns32000_delay const &)
+ {
+ // HACK: approximate handling /RDY by restarting the instruction;
+ // this approach can easily result in repeated incorrect memory
+ // accesses, but is sufficient to support pc532 SCSI pseudo-DMA.
- m_icount -= tcy;
+ // restore state
+ SP() = m_ssp;
+ m_psr = m_sps;
+
+ // burn a cycle
+ m_icount -= 1;
+ }
+ catch (ns32000_abort const &)
+ {
+ try
+ {
+ interrupt(ABT);
+ }
+ catch (ns32000_abort const &)
+ {
+ // this shouldn't happen; probably indicates supervisor stack overflow (stuck interrupt?)
+ if (machine().debug_enabled())
+ machine().debug_break();
+ else
+ fatalerror("abort during abort entry 0x%08x\n", m_pc);
+ }
+ }
}
}
-template <int Width> void ns32000_device<Width>::execute_set_input(int inputnum, int state)
+template <int HighBits, int Width> void ns32000_device<HighBits, Width>::execute_set_input(int inputnum, int state)
{
if (state)
m_wait = false;
@@ -2986,32 +3650,71 @@ template <int Width> void ns32000_device<Width>::execute_set_input(int inputnum,
}
}
-template <int Width> device_memory_interface::space_config_vector ns32000_device<Width>::memory_space_config() const
+template <int HighBits, int Width> device_memory_interface::space_config_vector ns32000_device<HighBits, Width>::memory_space_config() const
{
return space_config_vector{
std::make_pair(AS_PROGRAM, &m_program_config),
- std::make_pair(4, &m_interrupt_config), // interrupt acknowledge, master
- std::make_pair(5, &m_interrupt_config), // interrupt acknowledge, cascaded
- std::make_pair(6, &m_interrupt_config), // end of interrupt, master
- std::make_pair(7, &m_interrupt_config), // end of interrupt, cascaded
- std::make_pair(10, &m_program_config), // data transfer
- std::make_pair(11, &m_program_config), // read read-modify-write operand
- std::make_pair(12, &m_program_config), // read for effective address
+
+ std::make_pair(ns32000::ST_IAM, &m_iam_config),
+ std::make_pair(ns32000::ST_IAC, &m_iac_config),
+ std::make_pair(ns32000::ST_EIM, &m_eim_config),
+ std::make_pair(ns32000::ST_EIC, &m_eic_config),
+ std::make_pair(ns32000::ST_SIF, &m_sif_config),
+ std::make_pair(ns32000::ST_NIF, &m_nif_config),
+ std::make_pair(ns32000::ST_ODT, &m_odt_config),
+ std::make_pair(ns32000::ST_RMW, &m_rmw_config),
+ std::make_pair(ns32000::ST_EAR, &m_ear_config),
};
}
-template <int Width> bool ns32000_device<Width>::memory_translate(int spacenum, int intention, offs_t &address)
+template <int HighBits, int Width> bool ns32000_device<HighBits, Width>::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space)
{
- return true;
+ target_space = &space(spacenum);
+ return !m_mmu || m_mmu->translate(space(spacenum), spacenum, address, m_psr & PSR_U, intention == TR_WRITE, false, true) == ns32000_mmu_interface::COMPLETE;
}
-template <int Width> std::unique_ptr<util::disasm_interface> ns32000_device<Width>::create_disassembler()
+template <int HighBits, int Width> std::unique_ptr<util::disasm_interface> ns32000_device<HighBits, Width>::create_disassembler()
{
return std::make_unique<ns32000_disassembler>();
}
-template <int Width> u16 ns32000_device<Width>::slave(addr_mode op1, addr_mode op2)
+template <int HighBits, int Width> u16 ns32000_device<HighBits, Width>::slave(u8 opbyte, u16 opword, addr_mode op1, addr_mode op2)
{
+ switch (opbyte)
+ {
+ case ns32000_slave_interface::FORMAT_14:
+ if (!m_mmu)
+ fatalerror("slave mmu coprocessor not configured (%s)\n", machine().describe_context());
+
+ if (m_cfg & CFG_FM)
+ return slave_fast(dynamic_cast<ns32000_fast_slave_interface &>(*m_mmu), opbyte, opword, op1, op2);
+ else
+ return slave_slow(dynamic_cast<ns32000_slow_slave_interface &>(*m_mmu), opbyte, opword, op1, op2);
+ break;
+
+ case ns32000_slave_interface::FORMAT_9:
+ case ns32000_slave_interface::FORMAT_11:
+ case ns32000_slave_interface::FORMAT_12:
+ if (!m_fpu)
+ fatalerror("slave fpu coprocessor not configured (%s)\n", machine().describe_context());
+
+ if (m_cfg & CFG_FF)
+ return slave_fast(dynamic_cast<ns32000_fast_slave_interface &>(*m_fpu), opbyte, opword, op1, op2);
+ else
+ return slave_slow(dynamic_cast<ns32000_slow_slave_interface &>(*m_fpu), opbyte, opword, op1, op2);
+ break;
+
+ default:
+ fatalerror("slave coprocessor not supported (%s)\n", machine().describe_context());
+ return ns32000_slave_interface::SLAVE_Q;
+ }
+}
+
+template <int HighBits, int Width> u16 ns32000_device<HighBits, Width>::slave_slow(ns32000_slow_slave_interface &slave, u8 opbyte, u16 opword, addr_mode op1, addr_mode op2)
+{
+ slave.slow_write(opbyte);
+ slave.slow_write(swapendian_int16(opword));
+
if ((op1.access == READ || op1.access == RMW) && !(op1.type == REG && op1.slave))
{
u64 const data = gen_read(op1);
@@ -3019,23 +3722,33 @@ template <int Width> u16 ns32000_device<Width>::slave(addr_mode op1, addr_mode o
switch (op1.size)
{
case SIZE_B:
- m_fpu->write_op(u8(data));
+ slave.slow_write(u8(data));
break;
case SIZE_W:
- m_fpu->write_op(u16(data));
+ slave.slow_write(u16(data));
break;
case SIZE_D:
- m_fpu->write_op(u16(data >> 0));
- m_fpu->write_op(u16(data >> 16));
+ slave.slow_write(u16(data >> 0));
+ slave.slow_write(u16(data >> 16));
break;
case SIZE_Q:
- m_fpu->write_op(u16(data >> 0));
- m_fpu->write_op(u16(data >> 16));
- m_fpu->write_op(u16(data >> 32));
- m_fpu->write_op(u16(data >> 48));
+ slave.slow_write(u16(data >> 0));
+ slave.slow_write(u16(data >> 16));
+ slave.slow_write(u16(data >> 32));
+ slave.slow_write(u16(data >> 48));
break;
}
}
+ else if (op1.access == ADDR)
+ {
+ u32 const data = ea(op1);
+
+ slave.slow_write(u16(data >> 0));
+ slave.slow_write(u16(data >> 16));
+
+ // single-byte memory read cycle
+ mem_read<u8>(ns32000::ST_ODT, data, true);
+ }
if ((op2.access == READ || op2.access == RMW) && !(op2.type == REG && op2.slave))
{
@@ -3044,41 +3757,41 @@ template <int Width> u16 ns32000_device<Width>::slave(addr_mode op1, addr_mode o
switch (op2.size)
{
case SIZE_B:
- m_fpu->write_op(u8(data));
+ slave.slow_write(u8(data));
break;
case SIZE_W:
- m_fpu->write_op(u16(data));
+ slave.slow_write(u16(data));
break;
case SIZE_D:
- m_fpu->write_op(u16(data >> 0));
- m_fpu->write_op(u16(data >> 16));
+ slave.slow_write(u16(data >> 0));
+ slave.slow_write(u16(data >> 16));
break;
case SIZE_Q:
- m_fpu->write_op(u16(data >> 0));
- m_fpu->write_op(u16(data >> 16));
- m_fpu->write_op(u16(data >> 32));
- m_fpu->write_op(u16(data >> 48));
+ slave.slow_write(u16(data >> 0));
+ slave.slow_write(u16(data >> 16));
+ slave.slow_write(u16(data >> 32));
+ slave.slow_write(u16(data >> 48));
break;
}
}
- u16 const status = m_fpu->read_st(&m_icount);
+ u16 const status = slave.slow_status(&m_icount);
if (!(status & ns32000_slave_interface::SLAVE_Q))
{
if ((op2.access == WRITE || op2.access == RMW) && !(op2.type == REG && op2.slave))
{
- u64 data = m_fpu->read_op();
+ u64 data = slave.slow_read();
switch (op2.size)
{
case SIZE_D:
- data |= u64(m_fpu->read_op()) << 16;
+ data |= u64(slave.slow_read()) << 16;
break;
case SIZE_Q:
- data |= u64(m_fpu->read_op()) << 16;
- data |= u64(m_fpu->read_op()) << 32;
- data |= u64(m_fpu->read_op()) << 48;
+ data |= u64(slave.slow_read()) << 16;
+ data |= u64(slave.slow_read()) << 32;
+ data |= u64(slave.slow_read()) << 48;
break;
default:
break;
@@ -3087,15 +3800,448 @@ template <int Width> u16 ns32000_device<Width>::slave(addr_mode op1, addr_mode o
gen_write(op2, data);
}
}
- else
+
+ return status;
+}
+
+template <int HighBits, int Width> u16 ns32000_device<HighBits, Width>::slave_fast(ns32000_fast_slave_interface &slave, u8 opbyte, u16 opword, addr_mode op1, addr_mode op2)
+{
+ slave.fast_write(u32(opbyte) << 24 | u32(swapendian_int16(opword)) << 8);
+
+ if ((op1.access == READ || op1.access == RMW) && !(op1.type == REG && op1.slave))
{
- // restore stack pointer
- if (op1.type == TOS && op1.access == READ)
- SP -= op1.size + 1;
+ u64 const data = gen_read(op1);
- if (op2.type == TOS && op2.access == READ)
- SP -= op2.size + 1;
+ switch (op1.size)
+ {
+ case SIZE_B:
+ slave.fast_write(u8(data));
+ break;
+ case SIZE_W:
+ slave.fast_write(u16(data));
+ break;
+ case SIZE_D:
+ slave.fast_write(u32(data));
+ break;
+ case SIZE_Q:
+ slave.fast_write(u32(data >> 0));
+ slave.fast_write(u32(data >> 32));
+ break;
+ }
+ }
+ else if (op1.access == ADDR)
+ {
+ u32 const data = ea(op1);
+
+ slave.fast_write(u32(data));
+
+ // single-byte memory read cycle
+ mem_read<u8>(ns32000::ST_ODT, data, true);
+ }
+
+ if ((op2.access == READ || op2.access == RMW) && !(op2.type == REG && op2.slave))
+ {
+ u64 const data = gen_read(op2);
+
+ switch (op2.size)
+ {
+ case SIZE_B:
+ slave.fast_write(u8(data));
+ break;
+ case SIZE_W:
+ slave.fast_write(u16(data));
+ break;
+ case SIZE_D:
+ slave.fast_write(u32(data));
+ break;
+ case SIZE_Q:
+ slave.fast_write(u32(data >> 0));
+ slave.fast_write(u32(data >> 32));
+ break;
+ }
+ }
+
+ // TODO: status is optional in fast protocol
+ u32 const status = slave.fast_status(&m_icount);
+
+ if (!(status & ns32000_slave_interface::SLAVE_Q))
+ {
+ if ((op2.access == WRITE || op2.access == RMW) && !(op2.type == REG && op2.slave))
+ {
+ u64 data = slave.fast_read();
+
+ if (op2.size == SIZE_Q)
+ data |= u64(slave.fast_read()) << 32;
+
+ gen_write(op2, data);
+ }
}
return status;
}
+
+void ns32532_device::device_add_mconfig(machine_config &config)
+{
+ set_mmu(*this);
+}
+
+void ns32532_device::device_reset()
+{
+ ns32000_device<32, 2>::device_reset();
+
+ m_cfg = CFG_P | CFG_FC | CFG_FM | CFG_FF;
+}
+
+device_memory_interface::space_config_vector ns32532_device::memory_space_config() const
+{
+ auto vector = ns32000_device<32, 2>::memory_space_config();
+
+ vector.push_back(std::make_pair(ns32000::ST_PT1, &m_pt1_config));
+ vector.push_back(std::make_pair(ns32000::ST_PT2, &m_pt2_config));
+
+ return vector;
+}
+
+void ns32532_device::state_add(device_state_interface &parent, int &index)
+{
+ save_item(NAME(m_ptb));
+ save_item(NAME(m_tear));
+ save_item(NAME(m_mcr));
+ save_item(NAME(m_msr));
+
+ save_item(NAME(m_dcr));
+ save_item(NAME(m_dsr));
+ save_item(NAME(m_car));
+ save_item(NAME(m_bpc));
+
+ parent.state_add(index++, "PTB0", m_ptb[0]);
+ parent.state_add(index++, "PTB1", m_ptb[1]);
+ parent.state_add(index++, "TEAR", m_tear);
+ parent.state_add(index++, "MCR", m_mcr);
+ parent.state_add(index++, "MSR", m_msr);
+
+ parent.state_add(index++, "DCR", m_dcr);
+ parent.state_add(index++, "DSR", m_dsr);
+ parent.state_add(index++, "CAR", m_car);
+ parent.state_add(index++, "BPC", m_bpc);
+}
+
+static constexpr u32 MSR(unsigned st, bool user, bool write, unsigned tex)
+{
+ enum msr_mask : u32
+ {
+ MSR_TEX = 0x0003, // translation exception
+ MSR_DDT = 0x0004, // data direction (1=write)
+ MSR_UST = 0x0008, // user/supervisor (1=user)
+ MSR_STT = 0x00f0, // cpu status
+ };
+
+ return u32(((st << 4) & MSR_STT) | (user ? MSR_UST : 0) | (write ? MSR_DDT : 0) | (tex & MSR_TEX));
+}
+
+ns32000_mmu_interface::translate_result ns32532_device::translate(address_space &space, unsigned st, u32 &address, bool user, bool write, bool rdwrval, bool suppress)
+{
+ enum mcr_mask : u32
+ {
+ MCR_TU = 0x0001, // translate user-mode addresses
+ MCR_TS = 0x0002, // translate supervisor-mode addresses
+ MCR_DS = 0x0004, // dual-space translation
+ MCR_AO = 0x0008, // access level override
+ };
+
+ enum msr_tex_mask : u32
+ {
+ TEX_PTE1 = 0x1,
+ TEX_PTE2 = 0x2,
+ TEX_PROT = 0x3,
+ };
+
+ enum pte_mask : u32
+ {
+ PTE_V = 0x0000'0001, // valid
+ PTE_PL = 0x0000'0006, // protection level
+ PTE_CI = 0x0000'0020, // cache inhibit
+ PTE_R = 0x0000'0040, // referenced
+ PTE_M = 0x0000'0080, // modified
+ PTE_PFN = 0xffff'f000, // page frame number
+ };
+
+ enum pte_pl_mask : u32
+ {
+ PL_SRO = 0x00000000, // supervisor read only
+ PL_SRW = 0x00000002, // supervisor read write
+ PL_URO = 0x00000004, // user read only
+ PL_URW = 0x00000006, // user read write
+ };
+
+ // check translation required
+ if ((!user && !(m_mcr & MCR_TS)) || (user && !(m_mcr & MCR_TU)))
+ return COMPLETE;
+
+ // TODO: translation look-aside buffer
+
+ bool const address_space = (m_mcr & MCR_DS) && user;
+ unsigned const access_level = (user && !(m_mcr & MCR_AO))
+ ? ((write || st == ns32000::ST_RMW) ? PL_URW : PL_URO)
+ : ((write || st == ns32000::ST_RMW) ? PL_SRW : PL_SRO);
+
+ LOGMASKED(LOG_TRANSLATE, "translate address_space %d access_level %d page table 0x%08x address 0x%08x\n",
+ address_space, access_level, m_ptb[address_space], address);
+
+ // read level 1 page table entry
+ u32 const pte1_address = m_ptb[address_space] | (BIT(address, 22, 10) * 4);
+ u32 const pte1 = m_bus[ns32000::ST_PT1].read_dword(pte1_address);
+ LOGMASKED(LOG_TRANSLATE, "translate level 1 page table address 0x%08x entry 0x%08x\n", pte1_address, pte1);
+
+ // access check
+ if ((pte1 & PTE_PL) < access_level)
+ {
+ if (!suppress)
+ {
+ m_msr = MSR(st, user, write, TEX_PROT);
+ m_tear = address;
+
+ LOGMASKED(LOG_TRANSLATE, "translate level 1 protection exception\n");
+
+ return ABORT;
+ }
+ else
+ return CANCEL;
+ }
+ if (!(pte1 & PTE_V))
+ {
+ if (!suppress)
+ {
+ m_msr = MSR(st, user, write, TEX_PTE1);
+ m_tear = address;
+
+ LOGMASKED(LOG_TRANSLATE, "translate level 1 invalid\n");
+ }
+
+ return ABORT;
+ }
+
+ // set referenced
+ if (!(pte1 & PTE_R) && !suppress)
+ m_bus[ns32000::ST_PT1].write_byte(pte1_address, pte1 | PTE_R);
+
+ // read level 2 page table entry
+ u32 const pte2_address = (pte1 & PTE_PFN) | (BIT(address, 12, 10) * 4);
+ u32 const pte2 = m_bus[ns32000::ST_PT2].read_dword(pte2_address);
+ LOGMASKED(LOG_TRANSLATE, "translate level 2 page table address 0x%08x entry 0x%08x\n", pte2_address, pte2);
+
+ // access check
+ if ((pte2 & PTE_PL) < access_level)
+ {
+ if (!suppress)
+ {
+ m_msr = MSR(st, user, write, TEX_PROT);
+ m_tear = address;
+
+ LOGMASKED(LOG_TRANSLATE, "translate level 2 protection exception\n");
+
+ return ABORT;
+ }
+ else
+ return CANCEL;
+ }
+ if (!(pte2 & PTE_V))
+ {
+ if (!suppress)
+ {
+ m_msr = MSR(st, user, write, TEX_PTE2);
+ m_tear = address;
+
+ LOGMASKED(LOG_TRANSLATE, "translate level 2 invalid\n");
+
+ return ABORT;
+ }
+ else
+ return rdwrval ? COMPLETE : CANCEL;
+ }
+
+ // set modified and referenced
+ if ((!(pte2 & PTE_R) || ((write || st == ns32000::ST_RMW) && !(pte2 & PTE_M))) && !suppress)
+ m_bus[ns32000::ST_PT2].write_dword(pte2_address, pte2 | ((write || st == ns32000::ST_RMW) ? PTE_M : 0) | PTE_R);
+
+ address = (pte2 & PTE_PFN) | BIT(address, 0, 12);
+ LOGMASKED(LOG_TRANSLATE, "translate complete 0x%08x\n", address);
+
+ return COMPLETE;
+}
+
+void ns32532_device::lpr(unsigned reg, addr_mode const mode, bool user, unsigned &tex)
+{
+ switch (reg)
+ {
+ case 0x1:
+ if (!user)
+ m_dcr = gen_read(mode);
+ else
+ interrupt(ILL);
+ break;
+ case 0x2:
+ if (!user)
+ m_bpc = gen_read(mode);
+ else
+ interrupt(ILL);
+ break;
+ case 0x3:
+ if (!user)
+ m_dsr = gen_read(mode);
+ else
+ interrupt(ILL);
+ break;
+ case 0x4:
+ if (!user)
+ m_car = gen_read(mode);
+ else
+ interrupt(ILL);
+ break;
+ case 0xb:
+ if (!user)
+ SP(true) = gen_read(mode);
+ else
+ interrupt(ILL);
+ break;
+ case 0xc:
+ if (!user)
+ m_cfg = gen_read(mode) | (CFG_P | CFG_FC | CFG_FM | CFG_FF);
+ else
+ interrupt(ILL);
+ break;
+
+ default:
+ ns32000_device<32, 2>::lpr(reg, mode, user, tex);
+ return;
+ }
+
+ // TODO: tcy 19-33
+ tex = mode.tea + 19;
+}
+
+void ns32532_device::spr(unsigned reg, addr_mode const mode, bool user, unsigned &tex)
+{
+ switch (reg)
+ {
+ case 0x1:
+ if (!user)
+ gen_write(mode, m_dcr);
+ else
+ interrupt(ILL);
+ break;
+ case 0x2:
+ if (!user)
+ gen_write(mode, m_bpc);
+ else
+ interrupt(ILL);
+ break;
+ case 0x3:
+ if (!user)
+ gen_write(mode, m_dsr);
+ else
+ interrupt(ILL);
+ break;
+ case 0x4:
+ if (!user)
+ gen_write(mode, m_car);
+ else
+ interrupt(ILL);
+ break;
+ case 0xb:
+ if (!user)
+ gen_write(mode, SP(true));
+ else
+ interrupt(ILL);
+ break;
+ case 0xc:
+ if (!user)
+ gen_write(mode, m_cfg);
+ else
+ interrupt(ILL);
+ break;
+
+ default:
+ ns32000_device<32, 2>::spr(reg, mode, user, tex);
+ return;
+ }
+
+ // TODO: tcy 21-27
+ tex = mode.tea + 21;
+}
+
+
+u16 ns32532_device::slave(u8 opbyte, u16 opword, addr_mode op1, addr_mode op2)
+{
+ if (opbyte == FORMAT_14)
+ {
+ switch (BIT(opword, 2, 4))
+ {
+ case 0: // rdval
+ case 1: // wrval
+ {
+ u32 address = ea(op1);
+
+ switch (translate(space(AS_PROGRAM), ns32000::ST_ODT, address, true, BIT(opword, 2), true, true))
+ {
+ case CANCEL:
+ return ns32000_slave_interface::SLAVE_F;
+
+ case ABORT:
+ interrupt(ABT);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 2: // lmr
+ switch (BIT(opword, 7, 4))
+ {
+ case 0x8: break;
+ case 0x9: m_mcr = gen_read(op1); break;
+ case 0xa: m_msr = gen_read(op1); break;
+ case 0xb: m_tear = gen_read(op1); break;
+ case 0xc: m_ptb[0] = gen_read(op1) & ~0xfffU; break; // TODO: invalidate TLB
+ case 0xd: m_ptb[1] = gen_read(op1) & ~0xfffU; break; // TODO: invalidate TLB
+ case 0xe: gen_read(op1); break; // ivar0
+ case 0xf: gen_read(op1); break; // ivar1
+ default:
+ interrupt(UND);
+ break;
+ }
+ break;
+
+ case 3: // smr
+ switch (BIT(opword, 7, 4))
+ {
+ case 0x8: break;
+ case 0x9: gen_write(op2, m_mcr); break;
+ case 0xa: gen_write(op2, m_msr); break;
+ case 0xb: gen_write(op2, m_tear); break;
+ case 0xc: gen_write(op2, m_ptb[0]); break;
+ case 0xd: gen_write(op2, m_ptb[1]); break;
+ case 0xe: break;
+ case 0xf: break;
+ default:
+ interrupt(UND);
+ break;
+ }
+ break;
+
+ case 9: // cinv
+ // TODO: invalidate cache
+ break;
+
+ default:
+ interrupt(UND);
+ break;
+ }
+ }
+ else
+ return ns32000_device<32, 2>::slave(opbyte, opword, op1, op2);
+
+ return ns32000_slave_interface::SLAVE_OK;
+}