diff options
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 |
commit | 95e7e1272ad690c6a866669457418f31a4b2c62f (patch) | |
tree | 33623c766fc728657c094071fbda502a12f399c0 | |
parent | 8c70c1418b958265edbcea3c1c5796d0552d62ea (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.cpp | 119 | ||||
-rw-r--r-- | src/devices/cpu/dsp16/dsp16.h | 10 | ||||
-rw-r--r-- | src/devices/cpu/dsp16/dsp16dis.cpp | 887 | ||||
-rw-r--r-- | src/devices/cpu/dsp16/dsp16dis.h | 63 |
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 ¶ms) { - 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 ¶ms) override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const ¶ms) 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 |