summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2018-03-18 23:47:04 +1100
committer Vas Crabb <vas@vastheman.com>2018-03-18 23:47:04 +1100
commit95e7e1272ad690c6a866669457418f31a4b2c62f (patch)
tree33623c766fc728657c094071fbda502a12f399c0
parent8c70c1418b958265edbcea3c1c5796d0552d62ea (diff)
dsp16: rewrite disassembler - less cluttered output, better handling of ambiguous operations, look-ahead for predicated jumps, live will/won't comments on conditional instructions
-rw-r--r--src/devices/cpu/dsp16/dsp16.cpp119
-rw-r--r--src/devices/cpu/dsp16/dsp16.h10
-rw-r--r--src/devices/cpu/dsp16/dsp16dis.cpp887
-rw-r--r--src/devices/cpu/dsp16/dsp16dis.h63
4 files changed, 636 insertions, 443 deletions
diff --git a/src/devices/cpu/dsp16/dsp16.cpp b/src/devices/cpu/dsp16/dsp16.cpp
index 36f1a2d5085..ada5e000cdc 100644
--- a/src/devices/cpu/dsp16/dsp16.cpp
+++ b/src/devices/cpu/dsp16/dsp16.cpp
@@ -64,9 +64,9 @@
the current value in the input register and initiates a read.
TODO:
- * PSW overflow bits
+ * PSW overflow bits - are they sticky, how are they reset?
* Clarify rounding behaviour (F2 1011)
- * Random condition
+ * Random condition (CON 01000/01001)
* Clarify serial behaviour
* Serial input
* More serial I/O signals
@@ -196,7 +196,7 @@ dsp16_device_base::dsp16_device_base(
, m_sio_sioc(0U), m_sio_obuf(0U), m_sio_osr(0U), m_sio_ofsr(0U)
, m_sio_clk(1U), m_sio_clk_div(0U), m_sio_ld(1U), m_sio_ld_div(0U), m_sio_flags(SIO_FLAGS_NONE)
, m_pio_pioc(0U), m_pio_pdx_in(0U), m_pio_pdx_out(0U), m_pio_pids_cnt(0U), m_pio_pods_cnt(0U)
- , m_cache_pcbase(0U), m_st_pcbase(0U), m_st_yh(0), m_st_ah{ 0, 0 }, m_st_yl(0U), m_st_al{ 0U, 0U }
+ , m_cache_pcbase(0U), m_st_pcbase(0U), m_st_genflags(0U), m_st_yh(0), m_st_ah{ 0, 0 }, m_st_yl(0U), m_st_al{ 0U, 0U }
{
}
@@ -234,6 +234,7 @@ void dsp16_device_base::device_start()
state_add(STATE_GENPC, "PC", m_xaau_pc);
state_add(STATE_GENPCBASE, "CURPC", m_st_pcbase).noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_st_genflags).mask(0x0fU).noshow().callexport().formatstr("%16s");
state_add(DSP16_PT, "PT", m_xaau_pt);
state_add(DSP16_PR, "PR", m_xaau_pr);
state_add(DSP16_PI, "PI", m_xaau_pi);
@@ -616,13 +617,88 @@ void dsp16_device_base::state_export(device_state_entry const &entry)
}
}
+void dsp16_device_base::state_string_export(device_state_entry const &entry, std::string &str) const
+{
+ switch (entry.index())
+ {
+ // show DAU flags
+ case STATE_GENFLAGS:
+ str = util::string_format(
+ "%s%s%s%s",
+ dau_psw_lmi() ? "LMI " : "",
+ dau_psw_leq() ? "LEQ " : "",
+ dau_psw_llv() ? "LLV " : "",
+ dau_psw_lmv() ? "LMV " : "");
+ break;
+ }
+}
+
/***********************************************************************
device_disasm_interface implementation
***********************************************************************/
util::disasm_interface *dsp16_device_base::create_disassembler()
{
- return new dsp16_disassembler;
+ return new dsp16_disassembler(*this);
+}
+
+/***********************************************************************
+ dsp16_disassembler::cpu implementation
+***********************************************************************/
+
+dsp16_disassembler::cpu::predicate dsp16_device_base::check_con(offs_t pc, u16 op) const
+{
+ if (pc != m_st_pcbase)
+ {
+ return predicate::INDETERMINATE;
+ }
+ else
+ {
+ bool result;
+ u16 const con(op_con(op));
+ switch (con >> 1)
+ {
+ case 0x0: // mi/pl
+ result = dau_psw_lmi();
+ break;
+ case 0x1: // eq/ne
+ result = dau_psw_leq();
+ break;
+ case 0x2: // lvs/lvc
+ result = dau_psw_llv();
+ break;
+ case 0x3: // mvs/mvc
+ result = dau_psw_lmv();
+ break;
+ case 0x4: // heads/tails
+ return predicate::INDETERMINATE; // FIXME: implement PRNG
+ case 0x5: // c0ge/c0lt
+ case 0x6: // c1ge/c1lt
+ result = 0 <= m_dau_c[(con >> 1) - 0x05];
+ break;
+ case 0x7: // true/false
+ result = true;
+ break;
+ case 0x8: // gt/le
+ result = !dau_psw_lmi() && !dau_psw_leq();
+ break;
+ default: // Reserved
+ return predicate::INDETERMINATE;
+ }
+ return (bool(BIT(con, 0)) == result) ? predicate::SKIPPED : predicate::TAKEN;
+ }
+}
+
+dsp16_disassembler::cpu::predicate dsp16_device_base::check_branch(offs_t pc) const
+{
+ if (pc != m_st_pcbase)
+ return predicate::INDETERMINATE;
+ else if (FLAGS_PRED_TRUE == (m_flags & FLAGS_PRED_MASK))
+ return predicate::TAKEN;
+ else if (FLAGS_PRED_FALSE == (m_flags & FLAGS_PRED_MASK))
+ return predicate::SKIPPED;
+ else
+ return predicate::INDETERMINATE;
}
template <offs_t Base> READ16_MEMBER(dsp16_device_base::external_memory_r)
@@ -663,7 +739,36 @@ inline void dsp16_device_base::execute_one_rom()
case phase::OP1:
if (machine().debug_flags & DEBUG_FLAG_ENABLED)
- debugger_instruction_hook(this, m_st_pcbase);
+ {
+ if (FLAGS_PRED_NONE == (m_flags && FLAGS_PRED_MASK))
+ {
+ debugger_instruction_hook(this, m_st_pcbase);
+ }
+ else
+ {
+ switch (op >> 11)
+ {
+ case 0x00: // goto JA
+ case 0x01:
+ case 0x10: // call JA
+ case 0x11:
+ break;
+ case 0x18: // goto B
+ switch (op_b(op))
+ {
+ case 0x0: // return
+ case 0x2: // goto pt
+ case 0x3: // call pt
+ break;
+ default:
+ debugger_instruction_hook(this, m_st_pcbase);
+ }
+ break;
+ default:
+ debugger_instruction_hook(this, m_st_pcbase);
+ }
+ }
+ }
// IACK is updated for the next instruction
switch (m_flags & FLAGS_IACK_MASK)
@@ -1878,7 +1983,7 @@ inline bool dsp16_device_base::op_dau_con(u16 op, bool inc)
case 0x6: // c1ge/c1lt
{
s8 &c(m_dau_c[(con >> 1) - 0x05]);
- result = c >= 0;
+ result = 0 <= c;
if (inc)
++c;
}
@@ -1889,7 +1994,7 @@ inline bool dsp16_device_base::op_dau_con(u16 op, bool inc)
case 0x8: // gt/le
result = !dau_psw_lmi() && !dau_psw_leq();
break;
- default:
+ default: // Reserved
throw emu_fatalerror("DSP16: reserved CON value %02X (PC = %04X)\n", con, m_st_pcbase);
}
return BIT(con, 0) ? !result : result;
diff --git a/src/devices/cpu/dsp16/dsp16.h b/src/devices/cpu/dsp16/dsp16.h
index ac58b0ef0e4..599db7e6bd5 100644
--- a/src/devices/cpu/dsp16/dsp16.h
+++ b/src/devices/cpu/dsp16/dsp16.h
@@ -10,6 +10,8 @@
#pragma once
+#include "dsp16dis.h"
+
#include <utility>
@@ -62,7 +64,7 @@
downcast<dsp16_device_base &>(*device).set_pods_cb(DEVCB_##obj);
-class dsp16_device_base : public cpu_device
+class dsp16_device_base : public cpu_device, protected dsp16_disassembler::cpu
{
public:
DECLARE_WRITE_LINE_MEMBER(exm_w);
@@ -137,10 +139,15 @@ protected:
// device_state_interface implementation
virtual void state_import(device_state_entry const &entry) override;
virtual void state_export(device_state_entry const &entry) override;
+ virtual void state_string_export(device_state_entry const &entry, std::string &str) const override;
// device_disasm_interface implementation
virtual util::disasm_interface *create_disassembler() override;
+ // dsp16_disassembler::cpu implementation
+ virtual predicate check_con(offs_t pc, u16 op) const override;
+ virtual predicate check_branch(offs_t pc) const override;
+
// for specialisations to override
virtual void external_memory_enable(address_space &space, bool enable) = 0;
@@ -396,6 +403,7 @@ private:
// fake registers for the debugger
u16 m_cache_pcbase;
u16 m_st_pcbase;
+ u16 m_st_genflags;
s16 m_st_yh, m_st_ah[2];
u16 m_st_yl, m_st_al[2];
};
diff --git a/src/devices/cpu/dsp16/dsp16dis.cpp b/src/devices/cpu/dsp16/dsp16dis.cpp
index 683fe488d1a..7574c1c868c 100644
--- a/src/devices/cpu/dsp16/dsp16dis.cpp
+++ b/src/devices/cpu/dsp16/dsp16dis.cpp
@@ -1,198 +1,28 @@
// license:BSD-3-Clause
-// copyright-holders:Andrew Gardner, Vas Crabb
+// copyright-holders:Vas Crabb
#include "emu.h"
#include "dsp16dis.h"
+/***************************************************************************
-std::string dsp16_disassembler::disasmF1Field(u8 F1, u8 D, u8 S)
-{
- switch (F1)
- {
- case 0x00: return util::string_format("a%u = p, p = x*y", D);
- case 0x01: return util::string_format("a%u = a%u + p, p = x*y", D, S);
- case 0x02: return util::string_format("p = x*y");
- case 0x03: return util::string_format("a%u = a%u - p, p = x*y", D, S);
- case 0x04: return util::string_format("a%u = p", D);
- case 0x05: return util::string_format("a%u = a%u + p", D, S);
- case 0x06: return util::string_format("nop");
- case 0x07: return util::string_format("a%u = a%u - p", D, S);
- case 0x08: return util::string_format("a%u = a%u | y", D, S);
- case 0x09: return util::string_format("a%u = a%u ^ y", D, S);
- case 0x0a: return util::string_format("a%u & y", S);
- case 0x0b: return util::string_format("a%u - y", S);
- case 0x0c: return util::string_format("a%u = y", D);
- case 0x0d: return util::string_format("a%u = a%u + y", D, S);
- case 0x0e: return util::string_format("a%u = a%u & y", D, S);
- case 0x0f: return util::string_format("a%u = a%u - y", D, S);
- }
- return "UNKNOWN";
-}
+ WE|AT&T DSP16 series disassembler
-std::string dsp16_disassembler::disasmYField(u8 Y)
-{
- switch (Y & 0x03U)
- {
- case 0x00: return util::string_format("*r%u", Y >> 2);
- case 0x01: return util::string_format("*r%u++", Y >> 2);
- case 0x02: return util::string_format("*r%u--", Y >> 2);
- case 0x03: return util::string_format("*r%u++j", Y >> 2);
- }
- return "UNKNOWN";
-}
+***************************************************************************/
-std::string dsp16_disassembler::disasmZField(u8 Z)
-{
- switch (Z & 0x03U)
- {
- case 0x00: return util::string_format("*r%uzp", Z >> 2);
- case 0x01: return util::string_format("*r%upz", Z >> 2);
- case 0x02: return util::string_format("*r%um2", Z >> 2);
- case 0x03: return util::string_format("*r%ujk", Z >> 2);
- }
- return "UNKNOWN";
-}
-
-std::string dsp16_disassembler::disasmF2Field(u8 F2, u8 D, u8 S)
-{
- switch (F2)
- {
- case 0x00: return util::string_format("a%u = a%u >> 1", D, S);
- case 0x01: return util::string_format("a%u = a%u << 1", D, S);
- case 0x02: return util::string_format("a%u = a%u >> 4", D, S);
- case 0x03: return util::string_format("a%u = a%u << 4", D, S);
- case 0x04: return util::string_format("a%u = a%u >> 8", D, S);
- case 0x05: return util::string_format("a%u = a%u << 8", D, S);
- case 0x06: return util::string_format("a%u = a%u >> 16", D, S);
- case 0x07: return util::string_format("a%u = a%u << 16", D, S);
- case 0x08: return util::string_format("a%u = p", D);
- case 0x09: return util::string_format("a%uh = a%uh + 1", D, S);
- case 0x0a: return util::string_format("RESERVED");
- case 0x0b: return util::string_format("a%u = rnd(a%u)", D, S);
- case 0x0c: return util::string_format("a%u = y", D);
- case 0x0d: return util::string_format("a%u = a%u + 1", D, S);
- case 0x0e: return util::string_format("a%u = a%u", D, S);
- case 0x0f: return util::string_format("a%u = -a%u", D, S);
- }
- return "UNKNOWN";
-}
+/***********************************************************************
+ construction/destruction
+***********************************************************************/
-std::string dsp16_disassembler::disasmCONField(u8 CON)
+dsp16_disassembler::dsp16_disassembler() : m_host(nullptr)
{
- switch (CON)
- {
- case 0x00: return "mi";
- case 0x01: return "pl";
- case 0x02: return "eq";
- case 0x03: return "ne";
- case 0x04: return "lvs";
- case 0x05: return "lvc";
- case 0x06: return "mvs";
- case 0x07: return "mvc";
- case 0x08: return "heads";
- case 0x09: return "tails";
- case 0x0a: return "c0ge";
- case 0x0b: return "c0lt";
- case 0x0c: return "c1ge";
- case 0x0d: return "c1lt";
- case 0x0e: return "true";
- case 0x0f: return "false";
- case 0x10: return "gt";
- case 0x11: return "le";
-
- default: return "RESERVED";
- }
}
-std::string dsp16_disassembler::disasmBField(u8 B, u32 &dasmflags)
+dsp16_disassembler::dsp16_disassembler(cpu const &host) : m_host(&host)
{
- switch (B)
- {
- case 0x00: dasmflags |= STEP_OUT; return "return"; // TODO: can be predicated
- case 0x01: dasmflags |= STEP_OUT; return "ireturn";
- case 0x02: return "goto pt";
- case 0x03: dasmflags |= STEP_OVER; return "call pt";
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07: return "RESERVED";
- }
- return "UNKNOWN";
-}
-
-std::string dsp16_disassembler::disasmRImmediateField(u8 R)
-{
- switch (R)
- {
- case 0x00: return "j";
- case 0x01: return "k";
- case 0x02: return "rb";
- case 0x03: return "re";
- case 0x04: return "r0";
- case 0x05: return "r1";
- case 0x06: return "r2";
- case 0x07: return "r3";
- }
- return "UNKNOWN";
-}
-
-std::string dsp16_disassembler::disasmRField(u8 R)
-{
- switch (R)
- {
- case 0x00: return "r0";
- case 0x01: return "r1";
- case 0x02: return "r2";
- case 0x03: return "r3";
- case 0x04: return "j";
- case 0x05: return "k";
- case 0x06: return "rb";
- case 0x07: return "re";
- case 0x08: return "pt";
- case 0x09: return "pr";
- case 0x0a: return "pi";
- case 0x0b: return "i";
- case 0x10: return "x";
- case 0x11: return "y";
- case 0x12: return "yl";
- case 0x13: return "auc";
- case 0x14: return "psw";
- case 0x15: return "c0";
- case 0x16: return "c1";
- case 0x17: return "c2";
- case 0x18: return "sioc";
- case 0x19: return "srta";
- case 0x1a: return "sdx";
- case 0x1b: return "tdms";
- case 0x1c: return "pioc";
- case 0x1d: return "pdx0";
- case 0x1e: return "pdx1";
-
- default: return "RESERVED";
- }
-}
-
-std::string dsp16_disassembler::disasmIField(u8 I)
-{
- switch (I)
- {
- case 0x00: return "r0/j";
- case 0x01: return "r1/k";
- case 0x02: return "r2/rb";
- case 0x03: return "r3/re";
-
- default: return "UNKNOWN";
- }
-}
-
-bool dsp16_disassembler::disasmSIField(u8 SI)
-{
- switch (SI)
- {
- case 0x00: return false; // Not a software interrupt
- case 0x01: return true; // Software Interrupt
- }
- return false;
}
+/***********************************************************************
+ util::disasm_interface implementation
+***********************************************************************/
u32 dsp16_disassembler::interface_flags() const
{
@@ -211,320 +41,533 @@ u32 dsp16_disassembler::opcode_alignment() const
offs_t dsp16_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
{
- u8 opSize = 1;
- u32 dasmflags = 0;
- u16 op = opcodes.r16(pc);
- u16 op2 = opcodes.r16(pc+1);
-
- // TODO: Test for previous "if CON" instruction and tab the next instruction in?
-
- const u8 opcode = (op >> 11) & 0x1f;
- switch(opcode)
+ u8 length(1U);
+ u32 flags(0U);
+ u16 const op(opcodes.r16(pc));
+ switch (op >> 11)
{
- // Format 1: Multiply/ALU Read/Write Group
- case 0x06: // F1, Y
+ // control group (p3-14)
+ case 0x00: case 0x01: // goto JA (p3-20)
+ case 0x10: case 0x11: // call JA (p3-23)
+ stream << dasm_ja(op, pc, flags).text << check_branch_predicate(pc);
+ break;
+ case 0x18: // goto B (p3-21)
+ stream << ((op & 0x00ffU) ? dasm_int(op) : dasm_b(op, flags)).text;
+ break;
+ case 0x1a: // if CON goto/call/return # icall (p3-22 # p3-24)
+ if (0xd40e == op)
{
- const u8 Y = (op & 0x000f);
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string yString = disasmYField(Y);
- std::string fString = disasmF1Field(F1, D, S);
- util::stream_format(stream, "%s, %s", fString, yString);
+ util::stream_format(stream, "icall");
+ flags |= STEP_OVER;
}
- break;
- case 0x04: // F1, Y=a1[l]
- case 0x1c: // F1, Y=a0[l]
+ else if ((op >> 5) & 0x003fU)
{
- const u8 Y = (op & 0x000f);
- const u8 X = (op & 0x0010) >> 4;
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string yString = disasmYField(Y);
- std::string fString = disasmF1Field(F1, D, S);
- std::string aString = (opcode == 0x1c) ? "a0" : "a1";
- std::string xString = X ? "" : "l";
- util::stream_format(stream, "%s, %s = %s%s", fString, yString, aString, xString);
+ stream << dasm_int(op).text;
}
- break;
- case 0x16: // F1, x = Y
+ else
{
- const u8 Y = (op & 0x000f);
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string yString = disasmYField(Y);
- std::string fString = disasmF1Field(F1, D, S);
- util::stream_format(stream, "%s, x = %s", fString, yString);
+ result const con(dasm_con(op));
+ u16 const op2(opcodes.r16(inc_pc(pc, 1)));
+ result controlled{ true, false, { } };
+ switch (op2 >> 11)
+ {
+ case 0x00: case 0x01: // goto JA (p3-20)
+ case 0x10: case 0x11: // call JA (p3-23)
+ controlled = dasm_ja(op2, pc, flags);
+ length = 2U;
+ break;
+ case 0x18: // goto B (p3-21)
+ switch ((op >> 8) & 0x0007U)
+ {
+ case 0x0: // return
+ case 0x2: // goto pt
+ case 0x3: // call pt
+ controlled = dasm_b(op2, flags);
+ length = 2U;
+ break;
+ }
+ break;
+ }
+ char const *const comment(controlled.nop ? "" : check_branch_con(pc, op));
+ util::stream_format(
+ stream, "if %1$s%2$s%3$s%4$s",
+ con.text, controlled.nop ? "" : " ", controlled.text, comment);
}
break;
- case 0x17: // F1, y[l] = Y
+
+ // cache instructions (p3-18)
+ case 0x0e: // do K { instr1...instrNI } # redo K (p3-25
{
- const u8 Y = (op & 0x000f);
- const u8 X = (op & 0x0010) >> 4;
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string yString = disasmYField(Y);
- std::string fString = disasmF1Field(F1, D, S);
- std::string xString = X ? "y" : "yl";
- util::stream_format(stream, "%s, %s = %s", fString, xString, yString);
+ u16 const ni((op & 0x0780U) >> 7);
+ u16 const k(op & 0x007fU);
+ if (2U > k)
+ {
+ stream << dasm_int(op).text;
+ }
+ else if (ni)
+ {
+ offs_t const instr1(inc_pc(pc, 1));
+ offs_t const instrni(inc_pc(pc, ni));
+ util::stream_format(
+ stream, (1U < ni) ? "do %1$u { 0x%2$04x...0x%3$04x }" : "do %1$u { 0x%2$04x }",
+ k, instr1, instrni);
+ // TODO: increase skip field size for step over to support this instruction
+ }
+ else
+ {
+ util::stream_format(stream, "redo %1$u", k);
+ flags |= STEP_OVER;
+ }
}
break;
- case 0x1f: // F1, y = Y, x = *pt++[i]
+
+ // data move instructions (p3-16)
+ case 0x02: case 0x03: // R = M (p3-27)
{
- const u8 Y = (op & 0x000f);
- const u8 X = (op & 0x0010) >> 4;
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string yString = disasmYField(Y);
- std::string fString = disasmF1Field(F1, D, S);
- std::string xString = X ? "*pt++i" : "*pt++";
- util::stream_format(stream, "%s, y = %s, x = %s", fString, yString, xString);
+ u16 const m(op & 0x01ffU);
+ switch ((op >> 9) & 0x0007U)
+ {
+ case 0x0: util::stream_format(stream, "set j = 0x%03x", m); break;
+ case 0x1: util::stream_format(stream, "set k = 0x%03x", m); break;
+ case 0x2: util::stream_format(stream, "set rb = 0x%03x", m); break;
+ case 0x3: util::stream_format(stream, "set re = 0x%03x", m); break;
+ default: util::stream_format(stream, "set r%u = 0x%03x", (op >> 9) & 0x0003U, m); break;
+ }
}
break;
- case 0x19: // F1, y = a0, x = *pt++[i]
- case 0x1b: // F1, y = a0, x = *pt++[i]
+ case 0x0a: // R = N (p3-28)
+ if (op & 0x000fU)
{
- const u8 Y = (op & 0x000f);
- const u8 X = (op & 0x0010) >> 4;
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string fString = disasmF1Field(F1, D, S);
- std::string xString = X ? "*pt++i" : "*pt++";
- std::string aString = (opcode == 0x19) ? "a0" : "a1";
-
- if (Y != 0x00)
- util::stream_format(stream, "UNKNOWN");
- else
- util::stream_format(stream, "%s, y = %s, x = %s", fString, aString, xString);
+ stream << dasm_int(op).text;
+ }
+ else
+ {
+ length = 2U;
+ bool const low(!((op >> 8) & 0x0003U));
+ result const r(dasm_r(op));
+ u16 const n(opcodes.r16(inc_pc(pc, 1)));
+ util::stream_format(
+ stream, (low && r.ambiguous) ? "move %1$s = 0x%2$04x" : "%1$s = 0x%2$04x",
+ r.text, n);
}
break;
- case 0x14: // F1, Y = y[l]
+ case 0x09: case 0x0b: // R = aS (p3-29)
{
- const u8 Y = (op & 0x000f);
- const u8 X = (op & 0x0010) >> 4;
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string yString = disasmYField(Y);
- std::string xString = X ? "y" : "yl";
- std::string fString = disasmF1Field(F1, D, S);
- util::stream_format(stream, "%s, %s = %s", fString, yString, xString);
+ bool const high((op >> 8) & 0x0003U);
+ result const r(dasm_r(op));
+ util::stream_format(
+ stream, (high && r.ambiguous) ? "move %1$s = a%2$u" : "%1$s = a%2$u",
+ r.text, (op >> 12) & 0x0001U);
}
break;
-
- // Format 1a: Multiply/ALU Read/Write Group (major typo in docs on p3-51)
- case 0x07: // F1, aT[l] = Y
+ case 0x08: // aT = R (p3-30)
{
- const u8 Y = (op & 0x000f);
- const u8 S = (op & 0x0200) >> 9;
- const u8 aT = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string yString = disasmYField(Y);
- std::string atString = aT ? "a0" : "a1";
- std::string fString = disasmF1Field(F1, aT, S);
- util::stream_format(stream, "%s, %s = %s", fString, atString, yString);
+ bool const high((op >> 8) & 0x0003U);
+ result const r(dasm_r(op));
+ util::stream_format(
+ stream, (high && r.ambiguous) ? "move a%1$u = %2$s" : "a%1$u = %2$s",
+ (~op >> 10) & 0x0001U, r.text);
}
break;
-
- // Format 2: Multiply/ALU Read/Write Group
- case 0x15: // F1, Z : y[l]
+ case 0x0f: // R = Y (p3-32)
+ if ((op >> 10) & 0x0001U)
{
- const u8 Z = (op & 0x000f);
- const u8 X = (op & 0x0010) >> 4;
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string zString = disasmZField(Z);
- std::string xString = X ? "y" : "yl";
- std::string fString = disasmF1Field(F1, D, S);
- util::stream_format(stream, "%s, %s : %s", fString, zString, xString);
- break;
+ stream << dasm_int(op).text;
}
- case 0x1d: // F1, Z : y, x=*pt++[i]
+ else
{
- const u8 Z = (op & 0x000f);
- const u8 X = (op & 0x0010) >> 4;
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string zString = disasmZField(Z);
- std::string xString = X ? "*pt++i" : "*pt++";
- std::string fString = disasmF1Field(F1, D, S);
- util::stream_format(stream, "%s, %s : y, x = %s", fString, zString, xString);
+ bool const high((op >> 8) & 0x0003U);
+ result const r(dasm_r(op)), y(dasm_y(op));
+ util::stream_format(
+ stream, (high && r.ambiguous) ? "move %1$u = %2$s" : "%1$u = %2$s",
+ r.text, y.text);
}
break;
-
- // Format 2a: Multiply/ALU Read/Write Group
- case 0x05: // F1, Z : aT[l]
+ case 0x0c: // Y = R (p3-33)
{
- const u8 Z = (op & 0x000f);
- const u8 X = (op & 0x0010) >> 4;
- const u8 S = (op & 0x0200) >> 9;
- const u8 aT = (op & 0x0400) >> 10;
- const u8 F1 = (op & 0x01e0) >> 5;
- std::string zString = disasmZField(Z);
- std::string atString = (aT ? "a0" : "a1");
- atString += X ? "" : "l";
- std::string fString = disasmF1Field(F1, aT, S);
- util::stream_format(stream, "%s, %s : %s", fString, zString, atString);
- break;
+ bool const high((op >> 8) & 0x0003U);
+ result const r(dasm_r(op)), y(dasm_y(op));
+ util::stream_format(
+ stream, (high && r.ambiguous) ? "move %1$u = %2$s" : "%1$u = %2$s",
+ y.text, r.text);
}
-
- // Format 3: Special Functions
- case 0x12: // if CON F2
- case 0x13: // ifc CON F2
+ break;
+ case 0x0d: // Z : R (p3-34)
{
- // if|ifc CON F2
- const u8 CON = (op & 0x001f);
- const u8 S = (op & 0x0200) >> 9;
- const u8 D = (op & 0x0400) >> 10;
- const u8 F2 = (op & 0x01e0) >> 5;
- std::string fString = disasmF2Field(F2, D, S);
- std::string conString = disasmCONField(CON);
- if (op & 0x0800) util::stream_format(stream, "if %s %s", conString, fString);
- else util::stream_format(stream, "ifc %s %s", conString, fString);
+ bool const high((op >> 8) & 0x0003U);
+ result const r(dasm_r(op)), z(dasm_z(op));
+ util::stream_format(
+ stream, (high && r.ambiguous) ? "move %1$u : %2$s" : "%1$u : %2$s",
+ z.text, r.text);
}
break;
- // Format 4: Branch Direct Group
- case 0x00: case 0x01: // goto JA
+ // special function group (p3-12)
+ case 0x13: // if CON F2 (p3-36)
+ case 0x12: // ifc CON F2 (p3-37)
{
- const u16 JA = (op & 0x0fff) | (pc & 0xf000);
- util::stream_format(stream, "goto 0x%04x", JA);
+ result const f2(dasm_f2(op)), con(dasm_con(op));
+ bool const conditional((op & 0x0001U) || f2.ambiguous || !con.nop);
+ char const *const comment(conditional ? check_special_con(pc, op) : "");
+ util::stream_format(
+ stream, conditional ? "if%1$s %2$s %3$s%4$s" : "%3$s%4$s",
+ (op & 0x0800U) ? "" : "c", con.text, f2.text, comment);
}
break;
- case 0x10: case 0x11: // call JA
+
+ // multiply/ALU group (p3-6)
+ case 0x06: // F1 ; Y (p3-38)
{
- const u16 JA = (op & 0x0fff) | (pc & 0xf000);
- util::stream_format(stream, "call 0x%04x", JA);
- dasmflags |= STEP_OVER;
+ result const f1(dasm_f1(op)), y(dasm_y(op));
+ util::stream_format(
+ stream, "%1$s ; %2$s",
+ f1.text, y.text);
}
break;
-
- // Format 5: Branch Indirect Group
- case 0x18: // goto B
+ case 0x1c: // F1 ; Y=a0[l] (p3-40)
+ case 0x04: // F1 ; Y=a1[l] (p3-40)
{
- const u8 B = (op & 0x0700) >> 8;
- std::string bString = disasmBField(B, dasmflags);
- util::stream_format(stream, "%s", bString);
+ result const f1(dasm_f1(op)), y(dasm_y(op));
+ util::stream_format(
+ stream, f1.nop ? "%2$s = a%3$u%4$s" : "%1$s ; %2$s = a%3$u%4$s",
+ f1.text, y.text, (~op >> 14) & 0x0001U, ((op >> 4) & 0x0001U) ? "" : "l");
}
break;
-
- // Format 6: Contitional Branch Qualifier/Software Interrupt (icall)
- case 0x1a: // if CON [goto/call/return]
+ case 0x16: // F1 ; x = Y (p3-42)
{
- const u8 CON = (op & 0x001f);
- std::string conString = disasmCONField(CON);
- // TODO: Test for invalid ops
- if (op == 0xd40e)
- {
- util::stream_format(stream, "icall");
- dasmflags |= STEP_OVER;
- }
- else
- {
- util::stream_format(stream, "if %s", conString);
- }
+ result const f1(dasm_f1(op)), y(dasm_y(op));
+ util::stream_format(
+ stream, f1.nop ? "au x = %2$s" : "%1$s ; x = %2$s",
+ f1.text, y.text);
}
break;
-
- // Format 7: Data Move Group
- case 0x09: case 0x0b: // R = aS
+ case 0x17: // F1 ; y[l] = Y (p3-44)
{
- const u8 R = (op & 0x03f0) >> 4;
- const u8 S = (op & 0x1000) >> 12;
- std::string rString = disasmRField(R);
- util::stream_format(stream, "move %s = %s", rString, S ? "a1" : "a0");
+ result const f1(dasm_f1(op)), y(dasm_y(op));
+ util::stream_format(
+ stream, f1.nop ? "au y%2$s = %3$s" : "%1$s ; y%2$s = %3$s",
+ f1.text, ((op >> 4) & 0x0001U) ? "" : "l", y.text);
}
break;
- case 0x08: // aT = R
+ case 0x1f: // F1 ; y = Y ; x = *pt++[i] (p3-46)
{
- const u8 R = (op & 0x03f0) >> 4;
- const u8 aT = (op & 0x0400) >> 10;
- std::string rString = disasmRField(R);
- util::stream_format(stream, "move %s = %s", aT ? "a0" : "a1", rString);
+ result const f1(dasm_f1(op)), x(dasm_x(op)), y(dasm_y(op));
+ util::stream_format(
+ stream, f1.nop ? "y = %2$s ; %3$s" : "%1$s ; y = %2$s ; %3$s",
+ f1.text, y.text, x.text);
}
break;
- case 0x0f: // R = Y
+ case 0x19: // F1 ; y = a0 ; x = *pt++[i] (p3-48)
+ case 0x1b: // F1 ; y = a1 ; x = *pt++[i] (p3-48)
+ if (op & 0x000fU)
+ {
+ stream << dasm_int(op).text;
+ }
+ else
{
- const u8 Y = (op & 0x000f);
- const u8 R = (op & 0x03f0) >> 4;
- std::string yString = disasmYField(Y);
- std::string rString = disasmRField(R);
- util::stream_format(stream, "move %s = %s", rString, yString);
- // TODO: Special case the R == [y, yl, or x] case
+ result const f1(dasm_f1(op)), x(dasm_x(op));
+ util::stream_format(
+ stream, f1.nop ? "y = a%2$u ; %3$s" : "%1$s ; y = a%2$u ; %3$s",
+ f1.text, (op >> 12) & 0x0001U, x.text);
}
break;
- case 0x0c: // Y = R
+ case 0x07: // F1 ; aT[l] = Y (p3-50)
{
- const u8 Y = (op & 0x000f);
- const u8 R = (op & 0x03f0) >> 4;
- std::string yString = disasmYField(Y);
- std::string rString = disasmRField(R);
- util::stream_format(stream, "move %s = %s", yString, rString);
+ result const f1(dasm_f1(op)), y(dasm_y(op));
+ util::stream_format(
+ stream, f1.nop ? "a%2$u%3$s = %4$s" : "%1$s ; a%2$u%3$s = %4$s",
+ f1.text, (~op >> 10) & 0x0001U, ((op >> 4) & 0x0001U) ? "" : "l", y.text);
}
break;
- case 0x0d: // Z : R
+ case 0x14: // F1 ; Y = y[l] (p3-52)
{
- const u8 Z = (op & 0x000f);
- const u8 R = (op & 0x03f0) >> 4;
- std::string zString = disasmZField(Z);
- std::string rString = disasmRField(R);
- util::stream_format(stream, "move %s : %s", zString, rString);
+ result const f1(dasm_f1(op)), y(dasm_y(op));
+ util::stream_format(
+ stream, f1.nop ? "au %2$s = y%3$s" : "%1$s ; %2$s = y%3$s",
+ f1.text, y.text, ((op >> 4) & 0x0001U) ? "" : "l");
}
break;
-
- // Format 8: Data Move (immediate operand - 2 words)
- case 0x0a: // R = N
+ case 0x15: // F1 ; Z : y[l] (p3-54)
{
- const u8 R = (op & 0x03f0) >> 4;
- std::string rString = disasmRField(R);
- util::stream_format(stream, "%s = 0x%04x", rString, op2);
- opSize = 2;
+ result const f1(dasm_f1(op)), z(dasm_z(op));
+ util::stream_format(
+ stream, f1.nop ? "au %2$s : y%3$s" : "%1$s ; %2$s : y%3$s",
+ f1.text, z.text, ((op >> 4) & 0x0001U) ? "" : "l");
}
break;
-
- // Format 9: Short Immediate Group
- case 0x02: case 0x03: // R = M
+ case 0x05: // F1 ; Z : aT[l] (p3-56)
{
- const u16 M = (op & 0x01ff);
- const u8 R = (op & 0x0e00) >> 9;
- std::string rString = disasmRImmediateField(R);
- util::stream_format(stream, "set %s = 0x%04x", rString, M);
+ result const f1(dasm_f1(op)), z(dasm_z(op));
+ util::stream_format(
+ stream, f1.nop ? "%2$s : a%3$u4$s" : "%1$s ; %2$s : a%3$u4$s",
+ f1.text, z.text, (~op >> 10) & 0x0001U, ((op >> 4) & 0x0001U) ? "" : "l");
}
break;
-
- // Format 10: do - redo
- case 0x0e: // do|redo K
+ case 0x1d: // F1 ; Z : y ; x=*pt++[i] (p3-58)
{
- const u8 K = (op & 0x007f);
- const u8 NI = (op & 0x0780) >> 7;
-
- // TODO: Limits on K & NI
- if (NI == 0x00)
- {
- util::stream_format(stream, "redo %u", K);
- dasmflags |= STEP_OVER;
- }
- else
- util::stream_format(stream, "do %u { %u instructions }", K, NI);
+ result const f1(dasm_f1(op)), x(dasm_x(op)), z(dasm_z(op));
+ util::stream_format(
+ stream, f1.nop ? "%2$s : y ; %3$s" : "%1$s ; %2$s : y ; %3$s",
+ f1.text, z.text, x.text);
}
break;
- // RESERVED
- case 0x1e:
- util::stream_format(stream, "RESERVED");
+ case 0x1e: // Reserved
+ stream << dasm_int(op).text;
break;
- // UNKNOWN
default:
- util::stream_format(stream, "UNKNOWN");
+ throw false;
}
+ return length | flags | SUPPORTED;
+}
+
+/***********************************************************************
+ sub-instruction helpers
+***********************************************************************/
+
+dsp16_disassembler::result dsp16_disassembler::dasm_int(u16 op)
+{
+ return result{ false, false, util::string_format("int 0x%04x", op) };
+}
+
+dsp16_disassembler::result dsp16_disassembler::dasm_con(u16 op)
+{
+ u16 const con(op & 0x000fU);
+ switch (con)
+ {
+ case 0x00: return result{ false, false, "mi" };
+ case 0x01: return result{ false, false, "pl" };
+ case 0x02: return result{ false, false, "eq" };
+ case 0x03: return result{ false, false, "ne" };
+ case 0x04: return result{ false, false, "lvs" };
+ case 0x05: return result{ false, false, "lvc" };
+ case 0x06: return result{ false, false, "mvs" };
+ case 0x07: return result{ false, false, "mvc" };
+ case 0x08: return result{ false, false, "heads" };
+ case 0x09: return result{ false, false, "tails" };
+ case 0x0a: return result{ false, false, "c0ge" };
+ case 0x0b: return result{ false, false, "c0lt" };
+ case 0x0c: return result{ false, false, "c1ge" };
+ case 0x0d: return result{ false, false, "c1lt" };
+ case 0x0e: return result{ true, false, "true" };
+ case 0x0f: return result{ false, false, "false" };
+ case 0x10: return result{ false, false, "gt" };
+ case 0x11: return result{ false, false, "le" };
+ }
+ return result{ false, false, "if Reserved(0x%01x)" };
+}
+
+dsp16_disassembler::result dsp16_disassembler::dasm_b(u16 op, u32 &flags)
+{
+ u16 const b((op >> 8) & 0x0007U);
+ switch (b)
+ {
+ case 0x0: flags |= STEP_OUT; return result{ false, false, "return" };
+ case 0x1: flags |= STEP_OUT; return result{ false, false, "ireturn" };
+ case 0x2: return result{ false, false, "goto pt" };
+ case 0x3: flags |= STEP_OVER; return result{ false, false, "call pt" };
+ }
+ return result{ false, false, util::string_format("goto Reserved(0x%01x)", b) };
+}
+
+dsp16_disassembler::result dsp16_disassembler::dasm_ja(u16 op, offs_t pc, u32 &flags)
+{
+ if ((op >> 15) & 0x0001U)
+ flags |= STEP_OVER;
+ u16 const ja(op & 0x0fffU);
+ return result{
+ false,
+ false,
+ util::string_format(
+ (op >> 15) & 0x0001U ? "call 0x%1$04x" : "goto 0x%1$04x",
+ (pc & ~((offs_t(1) << 12) - 1)) | ja) };
+}
+
+dsp16_disassembler::result dsp16_disassembler::dasm_f1(u16 op)
+{
+ u16 const d((op >> 10) & 0x0001U);
+ u16 const s((op >> 9) & 0x0001U);
+ switch ((op >> 5) & 0x000fU)
+ {
+ case 0x00: return result{ false, false, util::string_format("a%u = p ; p = x*y", d) };
+ case 0x01: return result{ false, false, util::string_format("a%u = a%u + p, p = x*y", d, s) };
+ case 0x02: return result{ false, false, util::string_format("p = x*y") };
+ case 0x03: return result{ false, false, util::string_format("a%u = a%u-p, p = x*y", d, s) };
+ case 0x04: return result{ false, true, util::string_format("a%u = p", d) };
+ case 0x05: return result{ false, false, util::string_format("a%u = a%u+p", d, d) };
+ case 0x06: return result{ true, false, util::string_format("nop") };
+ case 0x07: return result{ false, false, util::string_format("a%u = a%u-p", d, s) };
+ case 0x08: return result{ false, false, util::string_format("a%u = a%u|y", d, s) };
+ case 0x09: return result{ false, false, util::string_format("a%u = a%u^y", d, s) };
+ case 0x0a: return result{ false, false, util::string_format("a%u&y", s) };
+ case 0x0b: return result{ false, false, util::string_format("a%u-y", s) };
+ case 0x0c: return result{ false, true, util::string_format("a%u = y", d) };
+ case 0x0d: return result{ false, false, util::string_format("a%u = a%u+y", d, s) };
+ case 0x0e: return result{ false, false, util::string_format("a%u = a%u&y", s, s) };
+ case 0x0f: return result{ false, false, util::string_format("a%u = a%u-y", s, s) };
+ }
+ throw false;
+}
+
+dsp16_disassembler::result dsp16_disassembler::dasm_f2(u16 op)
+{
+ u16 const d((op >> 10) & 0x0001U);
+ u16 const s((op >> 9) & 0x0001U);
+ u16 const f2((op >> 5) & 0x000fU);
+ switch (f2)
+ {
+ case 0x00: return result{ false, false, util::string_format("a%u = a%u>>1", d, s) };
+ case 0x01: return result{ false, false, util::string_format("a%u = a%u<<1", d, s) };
+ case 0x02: return result{ false, false, util::string_format("a%u = a%u>>4", d, s) };
+ case 0x03: return result{ false, false, util::string_format("a%u = a%u<<4", d, s) };
+ case 0x04: return result{ false, false, util::string_format("a%u = a%u>>8", d, s) };
+ case 0x05: return result{ false, false, util::string_format("a%u = a%u<<8", d, s) };
+ case 0x06: return result{ false, false, util::string_format("a%u = a%u>>16", d, s) };
+ case 0x07: return result{ false, false, util::string_format("a%u = a%u<<16", d, s) };
+ case 0x08: return result{ false, true, util::string_format("a%u = p", d) };
+ case 0x09: return result{ false, false, util::string_format("a%uh = a%uh+1", d, s) };
+ case 0x0a: return result{ false, false, util::string_format("Reserved(0x%01x)", f2) };
+ case 0x0b: return result{ false, false, util::string_format("a%u = rnd(a%u)", d, s) };
+ case 0x0c: return result{ false, true, util::string_format("a%u = y", d) };
+ case 0x0d: return result{ false, false, util::string_format("a%u = a%u+1", d, s) };
+ case 0x0e: return result{ false, false, util::string_format("a%u = a%u", d, s) };
+ case 0x0f: return result{ false, false, util::string_format("a%u = -a%u", d, s) };
+ }
+ throw false;
+}
+
+dsp16_disassembler::result dsp16_disassembler::dasm_r(u16 op)
+{
+ u16 const r((op >> 4) & 0x001fU);
+ switch (r)
+ {
+ case 0x00: return result{ false, true, "r0" };
+ case 0x01: return result{ false, true, "r1" };
+ case 0x02: return result{ false, true, "r2" };
+ case 0x03: return result{ false, true, "r3" };
+ case 0x04: return result{ false, true, "j" };
+ case 0x05: return result{ false, true, "k" };
+ case 0x06: return result{ false, true, "rb" };
+ case 0x07: return result{ false, true, "re" };
+ case 0x08: return result{ false, false, "pt" };
+ case 0x09: return result{ false, false, "pr" };
+ case 0x0a: return result{ false, false, "pi" };
+ case 0x0b: return result{ false, false, "i" };
+ case 0x10: return result{ false, true, "x" };
+ case 0x11: return result{ false, true, "y" };
+ case 0x12: return result{ false, true, "yl" };
+ case 0x13: return result{ false, false, "auc" };
+ case 0x14: return result{ false, false, "psw" };
+ case 0x15: return result{ false, false, "c0" };
+ case 0x16: return result{ false, false, "c1" };
+ case 0x17: return result{ false, false, "c2" };
+ case 0x18: return result{ false, false, "sioc" };
+ case 0x19: return result{ false, false, "srta" };
+ case 0x1a: return result{ false, false, "sdx" };
+ case 0x1b: return result{ false, false, "tdms" };
+ case 0x1c: return result{ false, false, "pioc" };
+ case 0x1d: return result{ false, false, "pdx0" };
+ case 0x1e: return result{ false, false, "pdx1" };
+ }
+ return result{ false, false, util::string_format("Reserved(0x%02x)", r) };
+}
+
+dsp16_disassembler::result dsp16_disassembler::dasm_x(u16 op)
+{
+ u16 const x((op >> 4) & 0x0001U);
+ return result{ false, false, x ? "x = *pt++i" : "x = *pt++" };
+}
- return opSize | dasmflags | SUPPORTED;
+dsp16_disassembler::result dsp16_disassembler::dasm_y(u16 op)
+{
+ u16 const r((op >> 2) & 0x0003U);
+ switch (op & 0x0003U)
+ {
+ case 0x00: return result{ false, false, util::string_format("*r%u", r) };
+ case 0x01: return result{ false, false, util::string_format("*r%u++", r) };
+ case 0x02: return result{ false, false, util::string_format("*r%u--", r) };
+ case 0x03: return result{ false, false, util::string_format("*r%u++j", r) };
+ }
+ throw false;
+}
+
+dsp16_disassembler::result dsp16_disassembler::dasm_z(u16 op)
+{
+ u16 const r((op >> 2) & 0x0003U);
+ switch (op & 0x0003U)
+ {
+ case 0x00: return result{ false, false, util::string_format("*r%uzp", r) };
+ case 0x01: return result{ false, false, util::string_format("*r%upz", r) };
+ case 0x02: return result{ false, false, util::string_format("*r%um2", r) };
+ case 0x03: return result{ false, false, util::string_format("*r%ujk", r) };
+ }
+ throw false;
+}
+
+/***********************************************************************
+ common maths
+***********************************************************************/
+
+constexpr offs_t dsp16_disassembler::inc_pc(offs_t pc, offs_t inc)
+{
+ return (pc & ~((offs_t(1) << 12) - 1)) | ((pc + inc) & ((offs_t(1) << 12) - 1));
+}
+
+/***********************************************************************
+ live state checks
+***********************************************************************/
+
+char const *dsp16_disassembler::check_branch_predicate(offs_t pc) const
+{
+ if (m_host)
+ {
+ switch (m_host->check_branch(pc))
+ {
+ case cpu::predicate::INDETERMINATE: return "";
+ case cpu::predicate::TAKEN: return " // will branch";
+ case cpu::predicate::SKIPPED: return " // will fall through";
+ }
+ throw false;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+char const *dsp16_disassembler::check_branch_con(offs_t pc, u16 op) const
+{
+ if (m_host)
+ {
+ switch (m_host->check_con(pc, op))
+ {
+ case cpu::predicate::INDETERMINATE: return "";
+ case cpu::predicate::TAKEN: return " // will branch";
+ case cpu::predicate::SKIPPED: return " // will fall through";
+ }
+ throw false;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+char const *dsp16_disassembler::check_special_con(offs_t pc, u16 op) const
+{
+ if (m_host)
+ {
+ switch (m_host->check_con(pc, op))
+ {
+ case cpu::predicate::INDETERMINATE: return "";
+ case cpu::predicate::TAKEN: return " // will execute";
+ case cpu::predicate::SKIPPED: return " // will skip";
+ }
+ throw false;
+ }
+ else
+ {
+ return "";
+ }
}
diff --git a/src/devices/cpu/dsp16/dsp16dis.h b/src/devices/cpu/dsp16/dsp16dis.h
index 09b480733a9..34f31812ba8 100644
--- a/src/devices/cpu/dsp16/dsp16dis.h
+++ b/src/devices/cpu/dsp16/dsp16dis.h
@@ -1,32 +1,69 @@
// license:BSD-3-Clause
-// copyright-holders:Andrew Gardner, Vas Crabb
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ WE|AT&T DSP16 series disassembler
+
+***************************************************************************/
#ifndef MAME_CPU_DSP16_DSP16DIS_H
#define MAME_CPU_DSP16_DSP16DIS_H
#pragma once
+#include <iosfwd>
+#include <string>
+
+
class dsp16_disassembler : public util::disasm_interface
{
public:
- dsp16_disassembler() = default;
+ // interface to live CPU
+ class cpu
+ {
+ public:
+ enum class predicate : u8 { INDETERMINATE, TAKEN, SKIPPED };
+ virtual predicate check_con(offs_t pc, u16 op) const = 0;
+ virtual predicate check_branch(offs_t pc) const = 0;
+ protected:
+ virtual ~cpu() = default;
+ };
+
+ // construction/destruction
+ dsp16_disassembler();
+ dsp16_disassembler(cpu const &host);
virtual ~dsp16_disassembler() = default;
+ // util::disasm_interface implementation
virtual u32 interface_flags() const override;
virtual u32 page_address_bits() const override;
virtual u32 opcode_alignment() const override;
- virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const &params) override;
private:
- std::string disasmF1Field(u8 F1, u8 D, u8 S);
- std::string disasmYField(u8 Y);
- std::string disasmZField(u8 Z);
- std::string disasmF2Field(u8 F2, u8 D, u8 S);
- std::string disasmCONField(u8 CON);
- std::string disasmBField(u8 B, u32 &dasmflags);
- std::string disasmRImmediateField(u8 R);
- std::string disasmRField(u8 R);
- std::string disasmIField(u8 I);
- bool disasmSIField(u8 SI);
+ struct result { bool nop; bool ambiguous; std::string text; };
+
+ // sub-instruction helpers
+ static result dasm_int(u16 op);
+ static result dasm_con(u16 op);
+ static result dasm_b(u16 op, u32 &flags);
+ static result dasm_ja(u16 op, offs_t pc, u32 &flags);
+ static result dasm_f1(u16 op);
+ static result dasm_f2(u16 op);
+ static result dasm_r(u16 op);
+ static result dasm_x(u16 op);
+ static result dasm_y(u16 op);
+ static result dasm_z(u16 op);
+
+ // common maths
+ static constexpr offs_t inc_pc(offs_t pc, offs_t inc);
+
+ // live state checks
+ char const *check_branch_predicate(offs_t pc) const;
+ char const *check_branch_con(offs_t pc, u16 op) const;
+ char const *check_special_con(offs_t pc, u16 op) const;
+
+ // access to live CPU
+ cpu const *const m_host;
};
#endif // MAME_CPU_DSP16_DSP16DIS_H