From 41a333e7919ad8f16508bdaf4f9a2192a3c06589 Mon Sep 17 00:00:00 2001 From: AJR Date: Thu, 5 Sep 2019 14:46:00 -0400 Subject: [PATCH] Add Fujitsu FR disassembler and skeleton CPU device --- scripts/src/cpu.lua | 17 + scripts/target/mame/arcade.lua | 1 + scripts/target/mame/mess.lua | 1 + src/devices/cpu/fr/fr.cpp | 137 +++++ src/devices/cpu/fr/fr.h | 69 +++ src/devices/cpu/fr/frdasm.cpp | 977 +++++++++++++++++++++++++++++++++ src/devices/cpu/fr/frdasm.h | 49 ++ src/tools/unidasm.cpp | 2 + 8 files changed, 1253 insertions(+) create mode 100644 src/devices/cpu/fr/fr.cpp create mode 100644 src/devices/cpu/fr/fr.h create mode 100644 src/devices/cpu/fr/frdasm.cpp create mode 100644 src/devices/cpu/fr/frdasm.h diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index 018e8c7ab0f..ceb6fb6f27f 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -567,6 +567,23 @@ if (CPUS["F8"]~=null or _OPTIONS["with-tools"]) then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/f8/f8dasm.h") end +-------------------------------------------------- +-- Fujitsu FR +--@src/devices/cpu/fr/fr.h,CPUS["FR"] = true +-------------------------------------------------- + +if (CPUS["FR"]~=null) then + files { + MAME_DIR .. "src/devices/cpu/fr/fr.cpp", + MAME_DIR .. "src/devices/cpu/fr/fr.h", + } +end + +if (CPUS["FR"]~=null or _OPTIONS["with-tools"]) then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/fr/frdasm.cpp") + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/fr/frdasm.h") +end + -------------------------------------------------- -- G65816 --@src/devices/cpu/g65816/g65816.h,CPUS["G65816"] = true diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index a00aaeb668c..80f1245f5bb 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -137,6 +137,7 @@ CPUS["HPC"] = true --CPUS["RII"] = true --CPUS["BCP"] = true --CPUS["CR16B"] = true +CPUS["FR"] = true -------------------------------------------------- -- specify available sound cores diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 8ce66040e49..599ee17c63b 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -146,6 +146,7 @@ CPUS["RII"] = true CPUS["BCP"] = true CPUS["F2MC16"] = true CPUS["CR16B"] = true +CPUS["FR"] = true -------------------------------------------------- -- specify available sound cores; some of these are diff --git a/src/devices/cpu/fr/fr.cpp b/src/devices/cpu/fr/fr.cpp new file mode 100644 index 00000000000..07ecaad136f --- /dev/null +++ b/src/devices/cpu/fr/fr.cpp @@ -0,0 +1,137 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Fujitsu FR series + + Currently this device is just a stub with no actual execution core. + +***************************************************************************/ + +#include "emu.h" +#include "fr.h" +#include "frdasm.h" + +// device type definitions +DEFINE_DEVICE_TYPE(MB91101A, mb91101a_device, "mb91101a", "Fujitsu MB91101A") + +fr_cpu_device::fr_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int addrbits, address_map_constructor map) + : cpu_device(mconfig, type, tag, owner, clock) + , m_space_config("program", ENDIANNESS_BIG, 32, addrbits, 0, map) + , m_space(nullptr) + , m_cache(nullptr) + , m_regs{0} + , m_pc(0) + , m_ps(0) + , m_tbr(0) + , m_rp(0) + , m_md(0) + , m_icount(0) +{ +} + +mb91101a_device::mb91101a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : fr_cpu_device(mconfig, MB91101A, tag, owner, clock, 32, address_map_constructor()) +{ +} + +std::unique_ptr fr_cpu_device::create_disassembler() +{ + return std::make_unique(); +} + +device_memory_interface::space_config_vector fr_cpu_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_space_config), + }; +} + +void fr_cpu_device::device_start() +{ + m_space = &space(AS_PROGRAM); + m_cache = m_space->cache<2, 0, ENDIANNESS_BIG>(); + + set_icountptr(m_icount); + + state_add(FR_PC, "PC", m_pc).mask(0xfffffffe); + state_add(STATE_GENPC, "GENPC", m_pc).mask(0xfffffffe).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_pc).mask(0xfffffffe).noshow(); + state_add(FR_PS, "PS", m_ps).mask(0x001f073f).formatstr("%08X"); + state_add(STATE_GENFLAGS, "CURFLAGS", m_ps).mask(0x001f073f).noshow().formatstr("%19s"); + state_add(FR_CCR, "CCR", + [this]() { return u8(m_ps & 0x0000003f); }, + [this](u8 value) { m_ps = (m_ps & 0x001f0700) | value; }).mask(0x3f).noshow(); + state_add(FR_ILM, "ILM", + [this]() { return u8((m_ps & 0x001f0000) >> 16); }, + [this](u8 value) { m_ps = (m_ps & 0x0000073f) | u32(value) << 16; }).mask(0x1f).noshow(); + state_add(FR_TBR, "TBR", m_tbr); + state_add(FR_RP, "RP", m_rp); + state_add(FR_SSP, "SSP", m_regs[15]); + state_add(FR_USP, "USP", m_regs[16]); + state_add(FR_MD, "MD", m_md); + state_add(FR_MDH, "MDH", + [this]() { return u32(m_md >> 32); }, + [this](u32 value) { m_md = (m_md & 0x00000000ffffffffULL) | u64(value) << 32; }).noshow(); + state_add(FR_MDL, "MDL", + [this]() { return u32(m_md & 0x00000000ffffffffULL); }, + [this](u32 value) { m_md = (m_md & 0xffffffff00000000ULL) | value; }).noshow(); + for (int i = 0; i < 15; i++) + state_add(FR_R0 + i, string_format("R%d", i).c_str(), m_regs[i]); + state_add(FR_R15, "R15", + [this]() { return m_regs[BIT(m_ps, 5) ? 16 : 15]; }, + [this](u32 value) { m_regs[BIT(m_ps, 5) ? 16 : 15] = value; }); + + save_item(NAME(m_regs)); + save_item(NAME(m_pc)); + save_item(NAME(m_ps)); + save_item(NAME(m_tbr)); + save_item(NAME(m_rp)); + save_item(NAME(m_md)); +} + +void fr_cpu_device::device_reset() +{ + // Only TBR, SSP, ILM and certain CCR and SCR bits are reset here; PC will be reloaded subsequently + m_ps = (m_ps & 0x0000060f) | 0x000f0000; + m_tbr = 0x000ffc00; + m_regs[15] = 0x00000000; +} + +void fr_cpu_device::execute_run() +{ + m_pc = m_space->read_dword(m_tbr + 0x3fc); + + debugger_instruction_hook(m_pc); + + m_icount = 0; +} + +void fr_cpu_device::execute_set_input(int inputnum, int state) +{ + // TODO +} + +void fr_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + str = string_format("<%d%d%d%d%d> %c%c%c--%c%c%c%c%c%c", + BIT(m_ps, 20), + BIT(m_ps, 19), + BIT(m_ps, 18), + BIT(m_ps, 17), + BIT(m_ps, 16), + BIT(m_ps, 10) ? 'D' : '.', + BIT(m_ps, 9) ? 'd' : '.', + BIT(m_ps, 8) ? 'T' : '.', + BIT(m_ps, 5) ? 'S' : '.', + BIT(m_ps, 4) ? 'I' : '.', + BIT(m_ps, 3) ? 'N' : '.', + BIT(m_ps, 2) ? 'Z' : '.', + BIT(m_ps, 1) ? 'V' : '.', + BIT(m_ps, 0) ? 'C' : '.'); + break; + } +} diff --git a/src/devices/cpu/fr/fr.h b/src/devices/cpu/fr/fr.h new file mode 100644 index 00000000000..c5b4899cace --- /dev/null +++ b/src/devices/cpu/fr/fr.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_FR_FR_H +#define MAME_CPU_FR_FR_H 1 + +#pragma once + + +class fr_cpu_device : public cpu_device +{ +public: + enum { + FR_PC, FR_PS, FR_CCR, FR_ILM, + FR_TBR, FR_RP, FR_SSP, FR_USP, + FR_MD, FR_MDH, FR_MDL, + FR_R0, FR_R1, FR_R2, FR_R3, + FR_R4, FR_R5, FR_R6, FR_R7, + FR_R8, FR_R9, FR_R10, FR_R11, + FR_R12, FR_R13, FR_R14, FR_R15 + }; + +protected: + // construction/destruction + fr_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int addrbits, address_map_constructor map); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_execute_interface overrides + virtual void execute_run() override; + virtual void execute_set_input(int inputnum, int state) override; + + // device_disasm_interface overrides + virtual std::unique_ptr create_disassembler() override; + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str) const override; + +private: + // address space + address_space_config m_space_config; + address_space *m_space; + memory_access_cache<2, 0, ENDIANNESS_BIG> *m_cache; + + // internal state + u32 m_regs[17]; // includes both SSP and USP + u32 m_pc; + u32 m_ps; + u32 m_tbr; + u32 m_rp; + u64 m_md; + s32 m_icount; +}; + +class mb91101a_device : public fr_cpu_device +{ +public: + // device type constructor + mb91101a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +DECLARE_DEVICE_TYPE(MB91101A, mb91101a_device) + +#endif // MAME_CPU_FR_FR_H diff --git a/src/devices/cpu/fr/frdasm.cpp b/src/devices/cpu/fr/frdasm.cpp new file mode 100644 index 00000000000..4a6998e0240 --- /dev/null +++ b/src/devices/cpu/fr/frdasm.cpp @@ -0,0 +1,977 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Fujitsu FR family disassembler + + While Fujitsu's manuals also refer to R13, R14 and R15 by function as + AC (accumulator), FP (frame pointer) and SP (stack pointer), these + aliases do not appear to be commonly used. All indexed addressing modes + are based on one of these three registers. + + The PS (program status) register can only be manipulated with special + instructions, some of which affect only the sections known as CCR + (condition code register) and ILM (interrupt level mask). + + TODO: The FR81 family has extra opcodes (primarily floating-point + instructions) which are not included here. + +***************************************************************************/ + +#include "emu.h" +#include "frdasm.h" + +fr_disassembler::fr_disassembler() + : util::disasm_interface() +{ +} + +u32 fr_disassembler::opcode_alignment() const +{ + return 2; +} + +void fr_disassembler::format_u8(std::ostream &stream, u8 value) +{ + util::stream_format(stream, "#0x%02X", value); +} + +void fr_disassembler::format_i8(std::ostream &stream, u8 value) +{ + if (value >= 0x0a) + util::stream_format(stream, "#0x%X", value); + else + util::stream_format(stream, "#%d", value); +} + +void fr_disassembler::format_disp(std::ostream &stream, u8 offs, unsigned shift) +{ + // 10-bit (word), 9-bit (half-word) or 8-bit (byte) signed displacement + u16 disp; + if (BIT(offs, 7)) + { + disp = u16(0x100 - offs) << shift; + stream << "-"; + } + else + disp = u16(offs) << shift; + + if (disp >= 0x0a) + util::stream_format(stream, "0x%X", disp); + else + util::stream_format(stream, "%d", disp); +} + +void fr_disassembler::format_u10(std::ostream &stream, u16 value) +{ + if (value >= 0x0a) + util::stream_format(stream, "#0x%X", value); + else + util::stream_format(stream, "#%d", value); +} + +void fr_disassembler::format_i20(std::ostream &stream, u32 value) +{ + util::stream_format(stream, "#0x%05X", value); +} + +void fr_disassembler::format_i32(std::ostream &stream, u32 value) +{ + util::stream_format(stream, "#0x%08X", value); +} + +void fr_disassembler::format_label(std::ostream &stream, offs_t addr) +{ + util::stream_format(stream, "0x%X", u32(addr)); +} + +void fr_disassembler::format_dir(std::ostream &stream, u16 addr) +{ + if (addr >= 0x100) + util::stream_format(stream, "@0x%03X", addr); + else + util::stream_format(stream, "@0x%02X", addr); +} + +void fr_disassembler::format_ac_rdisp(std::ostream &stream, u8 rj) +{ + util::stream_format(stream, "@(R13, R%d)", rj); +} + +void fr_disassembler::format_sp_udisp(std::ostream &stream, u8 disp) +{ + // unsigned displacement + util::stream_format(stream, "@(R15, %d)", disp); +} + +void fr_disassembler::format_rs(std::ostream &stream, u8 reg) +{ + switch (reg) + { + case 0: // Table Base Register + stream << "TBR"; + break; + + case 1: // Return Pointer + stream << "RP"; + break; + + case 2: // System Stack Pointer (R15 when S = 0) + stream << "SSP"; + break; + + case 3: // User Stack Pointer (R15 when S = 1) + stream << "USP"; + break; + + case 4: // Multiply/Divide Register (high 32 bits) + stream << "MDH"; + break; + + case 5: // Multiply/Divide Register (low 32 bits) + stream << "MDL"; + break; + + default: + stream << "reserved"; + break; + } +} + +offs_t fr_disassembler::dasm_invalid(std::ostream &stream, u16 opcode) +{ + util::stream_format(stream, "%-8s0x%04X", ".DATA.H", opcode); + return 2 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_i4op(std::ostream &stream, u16 opcode, const char *inst) +{ + // Arithmetic instructions with 4-bit (effectively 5-bit) positive or negative immediate offset + util::stream_format(stream, "%-8s#", inst); + u8 value = (opcode & 0x00f0) >> 4; + if (BIT(opcode, 9)) + { + stream << "-"; + value = 0x10 - value; + } + if (value >= 0x0a) + util::stream_format(stream, "0x%X", value); + else + util::stream_format(stream, "%d", value); + + util::stream_format(stream, ", R%d", opcode & 0x000f); + return 2 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_shift(std::ostream &stream, u16 opcode, const char *inst) +{ + // Register shifts with 4-bit (effectively 5-bit) immediate offset + util::stream_format(stream, "%-8s#%d, R%d", inst, (opcode & 0x01f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_rrop(std::ostream &stream, u16 opcode, const char *inst) +{ + // Simple register-to-register operations (and multiplication) + util::stream_format(stream, "%-8sR%d, R%d", inst, (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_ld_fp_disp(std::ostream &stream, u16 opcode, const char *inst, unsigned shift) +{ + // Load (zero extended) from memory at frame pointer ± 10-bit/9-bit/8-bit displacement + util::stream_format(stream, "%-8s@(R14, ", inst); + format_disp(stream, (opcode & 0x0ff0) >> 4, shift); + util::stream_format(stream, "), R%d", opcode & 0x000f); + return 2 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_st_fp_disp(std::ostream &stream, u16 opcode, const char *inst, unsigned shift) +{ + // Store to memory at frame pointer ± 10-bit/9-bit/8-bit displacement + util::stream_format(stream, "%-8sR%d, @(R14, ", inst, opcode & 0x000f); + format_disp(stream, (opcode & 0x0ff0) >> 4, shift); + stream << ")"; + return 2 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_ldstm(std::ostream &stream, u16 opcode, const char *inst) +{ + // Load/store register list in (R0-R7) or (R8-R15) + util::stream_format(stream, "%-8s(", inst); + int base = BIT(opcode, 8) ? 8 : 0; + for (int i = 0; i < 8; i++) + { + if (BIT(opcode, i)) + { + util::stream_format(stream, "R%d", BIT(opcode, 9) ? base + 7 - i : base + i); + opcode &= ~(1 << i); + if ((opcode & 0x00ff) != 0) + stream << ", "; + else + break; + } + } + stream << ")"; + return 2 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_bop(std::ostream &stream, u16 opcode, const char *inst) +{ + // Operands are 4-bit immediate mask and upper or lower nibble of memory + util::stream_format(stream, "%-8s#0x%X, @R%d", inst, (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_cop(std::ostream &stream, u16 op1, u16 op2, const char *inst, bool crj, bool cri) +{ + // Coprocessor instructions + util::stream_format(stream, "%-8s#%d, ", inst, op1 & 0x000f); + format_u8(stream, (op2 & 0xff00) >> 8); + util::stream_format(stream, ", %sR%d, %sR%d", crj ? "C" : "", (op2 & 0x00f0) >> 4, cri ? "C" : "", op2 & 0x000f); + return 4 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_call(std::ostream &stream, offs_t pc, const char *inst, u16 disp) +{ + // 12-bit relative calls, with or without delay slot + util::stream_format(stream, "%-8s", inst); + if (disp >= 0x800) + format_label(stream, pc + 2 - 0x1000 + disp); + else + format_label(stream, pc + 2 + disp); + return 2 | SUPPORTED | STEP_OVER; +} + +offs_t fr_disassembler::dasm_branch(std::ostream &stream, offs_t pc, const char *inst, u16 disp) +{ + // Conditional/unconditional 9-bit relative branches, with or without delay slot + util::stream_format(stream, "%-8s", inst); + if (disp >= 0x100) + format_label(stream, pc + 2 - 0x200 + disp); + else + format_label(stream, pc + 2 + disp); + return 2 | SUPPORTED; +} + +offs_t fr_disassembler::dasm_07(std::ostream &stream, offs_t pc, const fr_disassembler::data_buffer &opcodes, u16 opcode) +{ + switch (opcode & 0x00f0) + { + case 0x00: + util::stream_format(stream, "%-8s@R15+, R%d", "LD", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x10: + util::stream_format(stream, "%-8sR%d, PS", "MOV", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x80: + util::stream_format(stream, "%-8s@R15+, ", "LD"); + format_rs(stream, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x90: + util::stream_format(stream, "%-8s@R15+, PS", "MOV"); + return 2 | SUPPORTED; + + default: + return dasm_invalid(stream, opcode); + } +} + +offs_t fr_disassembler::dasm_17(std::ostream &stream, offs_t pc, const fr_disassembler::data_buffer &opcodes, u16 opcode) +{ + switch (opcode & 0x00f0) + { + case 0x00: + util::stream_format(stream, "%-8sR%d, @-R15", "ST", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x10: + util::stream_format(stream, "%-8sPS, R%d", "MOV", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x80: + util::stream_format(stream, "%-8s", "ST"); + format_rs(stream, opcode & 0x000f); + stream << ", @-R15"; + return 2 | SUPPORTED; + + case 0x90: + util::stream_format(stream, "%-8sPS, @-R15", "ST"); + return 2 | SUPPORTED; + + default: + return dasm_invalid(stream, opcode); + } +} + +offs_t fr_disassembler::dasm_97(std::ostream &stream, offs_t pc, const fr_disassembler::data_buffer &opcodes, u16 opcode) +{ + switch (opcode & 0x00f0) + { + case 0x00: + util::stream_format(stream, "%-8s@R%d", "JMP", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x10: + util::stream_format(stream, "%-8s@R%d", "CALL", opcode & 0x000f); + return 2 | SUPPORTED | STEP_OVER; + + case 0x20: + if ((opcode & 0x000f) == 0) + { + stream << "RET"; + return 2 | SUPPORTED | STEP_OUT; + } + else + return dasm_invalid(stream, opcode); + + case 0x30: + if ((opcode & 0x000f) == 0) + { + stream << "RETI"; + return 2 | SUPPORTED | STEP_OUT; + } + else + return dasm_invalid(stream, opcode); + + case 0x40: + util::stream_format(stream, "%-8sR%d", "DIV0S", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x50: + util::stream_format(stream, "%-8sR%d", "DIV0U", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x60: + util::stream_format(stream, "%-8sR%d", "DIV1", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x70: + util::stream_format(stream, "%-8sR%d", "DIV2", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x80: + util::stream_format(stream, "%-8sR%d", "EXTSB", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x90: + util::stream_format(stream, "%-8sR%d", "EXTUB", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0xa0: + util::stream_format(stream, "%-8sR%d", "EXTSH", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0xb0: + util::stream_format(stream, "%-8sR%d", "EXTUH", opcode & 0x000f); + return 2 | SUPPORTED; + + default: + return dasm_invalid(stream, opcode); + } +} + +offs_t fr_disassembler::dasm_9f(std::ostream &stream, offs_t pc, const fr_disassembler::data_buffer &opcodes, u16 opcode) +{ + switch (opcode & 0x00f0) + { + case 0x00: + util::stream_format(stream, "%-8s@R%d", "JMP:D", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x10: + util::stream_format(stream, "%-8s@R%d", "CALL:D", opcode & 0x000f); + return 2 | SUPPORTED | STEP_OVER | step_over_extra(1); + + case 0x20: + if ((opcode & 0x000f) == 0) + { + stream << "RET:D"; + return 2 | SUPPORTED | STEP_OUT | step_over_extra(1); + } + else + return dasm_invalid(stream, opcode); + + + case 0x30: + if ((opcode & 0x000f) == 0) + { + // Emulator software interrupt (#0x09) + stream << "INTE"; + return 2 | SUPPORTED | STEP_OVER; + } + else + return dasm_invalid(stream, opcode); + + case 0x60: + if ((opcode & 0x000f) == 0) + { + stream << "DIV3"; + return 2 | SUPPORTED; + } + else + return dasm_invalid(stream, opcode); + + case 0x70: + if ((opcode & 0x000f) == 0) + { + stream << "DIV4S"; + return 2 | SUPPORTED; + } + else + return dasm_invalid(stream, opcode); + + + case 0x80: // LDI:32 + util::stream_format(stream, "%-8s", "LDI"); + format_i32(stream, opcodes.r32(pc + 2)); + util::stream_format(stream, ", R%d", opcode & 0x000f); + return 6 | SUPPORTED; + + case 0x90: + if ((opcode & 0x000f) == 0) + { + stream << "LEAVE"; + return 2 | SUPPORTED; + } + else + return dasm_invalid(stream, opcode); + + case 0xa0: + if ((opcode & 0x000f) == 0) + { + stream << "NOP"; + return 2 | SUPPORTED; + } + else + return dasm_invalid(stream, opcode); + + case 0xc0: + return dasm_cop(stream, opcode, opcodes.r16(pc + 2), "COPOP", true, true); + + case 0xd0: + return dasm_cop(stream, opcode, opcodes.r16(pc + 2), "COPLD", false, true); + + case 0xe0: + return dasm_cop(stream, opcode, opcodes.r16(pc + 2), "COPST", true, false); + + case 0xf0: + return dasm_cop(stream, opcode, opcodes.r16(pc + 2), "COPSV", true, false); + + default: + return dasm_invalid(stream, opcode); + } +} + +offs_t fr_disassembler::disassemble(std::ostream &stream, offs_t pc, const fr_disassembler::data_buffer &opcodes, const fr_disassembler::data_buffer ¶ms) +{ + u16 opcode = opcodes.r16(pc); + + switch (opcode >> 8) + { + case 0x00: + util::stream_format(stream, "%-8s", "LD"); + format_ac_rdisp(stream, (opcode & 0x00f0) >> 4); + util::stream_format(stream, ", R%d", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x01: + util::stream_format(stream, "%-8s", "LDUH"); + format_ac_rdisp(stream, (opcode & 0x00f0) >> 4); + util::stream_format(stream, ", R%d", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x02: + util::stream_format(stream, "%-8s", "LDUB"); + format_ac_rdisp(stream, (opcode & 0x00f0) >> 4); + util::stream_format(stream, ", R%d", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x03: + util::stream_format(stream, "%-8s", "LD"); + format_sp_udisp(stream, (opcode & 0x00f0) >> 2); + util::stream_format(stream, ", R%d", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x04: + util::stream_format(stream, "%-8s@R%d, R%d", "LD", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x05: + util::stream_format(stream, "%-8s@R%d, R%d", "LDUH", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x06: + util::stream_format(stream, "%-8s@R%d, R%d", "LDUB", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x07: + return dasm_07(stream, pc, opcodes, opcode); + + case 0x08: + util::stream_format(stream, "%-8s", "DMOV"); + format_dir(stream, (opcode & 0x00ff) << 2); + stream << ", R13"; + return 2 | SUPPORTED; + + case 0x09: + util::stream_format(stream, "%-8s", "DMOVH"); + format_dir(stream, (opcode & 0x00ff) << 1); + stream << ", R13"; + return 2 | SUPPORTED; + + case 0x0a: + util::stream_format(stream, "%-8s", "DMOVB"); + format_dir(stream, opcode & 0x00ff); + stream << ", R13"; + return 2 | SUPPORTED; + + case 0x0b: + util::stream_format(stream, "%-8s", "DMOV"); + format_dir(stream, (opcode & 0x00ff) << 2); + stream << ", @-R15"; + return 2 | SUPPORTED; + + case 0x0c: + util::stream_format(stream, "%-8s", "DMOV"); + format_dir(stream, (opcode & 0x00ff) << 2); + stream << ", @R13+"; + return 2 | SUPPORTED; + + case 0x0d: + util::stream_format(stream, "%-8s", "DMOVH"); + format_dir(stream, (opcode & 0x00ff) << 1); + stream << ", @R13+"; + return 2 | SUPPORTED; + + case 0x0e: + util::stream_format(stream, "%-8s", "DMOVB"); + format_dir(stream, opcode & 0x00ff); + stream << ", @R13+"; + return 2 | SUPPORTED; + + case 0x0f: + util::stream_format(stream, "%-8s", "ENTER"); + format_u10(stream, (opcode & 0x00ff) << 2); + return 2 | SUPPORTED; + + case 0x10: + util::stream_format(stream, "%-8sR%d, ", "ST", opcode & 0x000f); + format_ac_rdisp(stream, (opcode & 0x00f0) >> 4); + return 2 | SUPPORTED; + + case 0x11: + util::stream_format(stream, "%-8sR%d, ", "STH", opcode & 0x000f); + format_ac_rdisp(stream, (opcode & 0x00f0) >> 4); + return 2 | SUPPORTED; + + case 0x12: + util::stream_format(stream, "%-8sR%d, ", "STB", opcode & 0x000f); + format_ac_rdisp(stream, (opcode & 0x00f0) >> 4); + return 2 | SUPPORTED; + + case 0x13: + util::stream_format(stream, "%-8sR%d, ", "ST", opcode & 0x000f); + format_sp_udisp(stream, (opcode & 0x00f0) >> 2); + return 2 | SUPPORTED; + + case 0x14: + util::stream_format(stream, "%-8sR%d, @R%d", "ST", opcode & 0x000f, (opcode & 0x00f0) >> 4); + return 2 | SUPPORTED; + + case 0x15: + util::stream_format(stream, "%-8sR%d, @R%d", "STH", opcode & 0x000f, (opcode & 0x00f0) >> 4); + return 2 | SUPPORTED; + + case 0x16: + util::stream_format(stream, "%-8sR%d, @R%d", "STB", opcode & 0x000f, (opcode & 0x00f0) >> 4); + return 2 | SUPPORTED; + + case 0x17: + return dasm_17(stream, pc, opcodes, opcode); + + case 0x18: + util::stream_format(stream, "%-8sR13, ", "DMOV"); + format_dir(stream, (opcode & 0x00ff) << 2); + return 2 | SUPPORTED; + + case 0x19: + util::stream_format(stream, "%-8sR13, ", "DMOVH"); + format_dir(stream, (opcode & 0x00ff) << 1); + return 2 | SUPPORTED; + + case 0x1a: + util::stream_format(stream, "%-8sR13, ", "DMOVB"); + format_dir(stream, opcode & 0x00ff); + return 2 | SUPPORTED; + + case 0x1b: + util::stream_format(stream, "%-8s@R15+, ", "DMOV"); + format_dir(stream, (opcode & 0x00ff) << 2); + return 2 | SUPPORTED; + + case 0x1c: + util::stream_format(stream, "%-8s@R13+, ", "DMOV"); + format_dir(stream, (opcode & 0x00ff) << 2); + return 2 | SUPPORTED; + + case 0x1d: + util::stream_format(stream, "%-8s@R13+, ", "DMOVH"); + format_dir(stream, (opcode & 0x00ff) << 1); + return 2 | SUPPORTED; + + case 0x1e: + util::stream_format(stream, "%-8s@R13+, ", "DMOVB"); + format_dir(stream, opcode & 0x00ff); + return 2 | SUPPORTED; + + case 0x1f: + util::stream_format(stream, "%-8s", "INT"); + format_u8(stream, opcode & 0x00ff); + return 2 | SUPPORTED | STEP_OVER; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + return dasm_ld_fp_disp(stream, opcode, "LD", 2); + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + return dasm_st_fp_disp(stream, opcode, "ST", 2); + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + return dasm_ld_fp_disp(stream, opcode, "LDUH", 1); + + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + return dasm_st_fp_disp(stream, opcode, "STH", 1); + + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + return dasm_ld_fp_disp(stream, opcode, "LDUB", 0); + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + return dasm_st_fp_disp(stream, opcode, "STB", 0); + + case 0x80: + return dasm_bop(stream, opcode, "BANDL"); + + case 0x81: + return dasm_bop(stream, opcode, "BANDH"); + + case 0x82: + return dasm_rrop(stream, opcode, "AND"); + + case 0x83: + util::stream_format(stream, "%-8s", "ANDCCR"); + format_u8(stream, opcode & 0x00ff); + return 2 | SUPPORTED; + + case 0x84: + util::stream_format(stream, "%-8sR%d, @R%d", "AND", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x85: + util::stream_format(stream, "%-8sR%d, @R%d", "ANDH", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x86: + util::stream_format(stream, "%-8sR%d, @R%d", "ANDB", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x87: + util::stream_format(stream, "%-8s", "STILM"); + format_u8(stream, opcode & 0x00ff); + return 2 | SUPPORTED; + + case 0x88: + return dasm_bop(stream, opcode, "BTSTL"); + + case 0x89: + return dasm_bop(stream, opcode, "BTSTH"); + + case 0x8a: + util::stream_format(stream, "%-8s@R%d, R%d", "XCHB", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x8b: + return dasm_rrop(stream, opcode, "MOV"); + + case 0x8c: + return dasm_ldstm(stream, opcode, "LDM0"); + + case 0x8d: + return dasm_ldstm(stream, opcode, "LDM1"); + + case 0x8e: + return dasm_ldstm(stream, opcode, "STM0"); + + case 0x8f: + return dasm_ldstm(stream, opcode, "STM1"); + + case 0x90: + return dasm_bop(stream, opcode, "BORL"); + + case 0x91: + return dasm_bop(stream, opcode, "BORH"); + + case 0x92: + return dasm_rrop(stream, opcode, "OR"); + + case 0x93: + util::stream_format(stream, "%-8s", "ORCCR"); + format_u8(stream, opcode & 0x00ff); + return 2 | SUPPORTED; + + case 0x94: + util::stream_format(stream, "%-8sR%d, @R%d", "OR", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x95: + util::stream_format(stream, "%-8sR%d, @R%d", "ORH", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x96: + util::stream_format(stream, "%-8sR%d, @R%d", "ORB", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x97: + return dasm_97(stream, pc, opcodes, opcode); + + case 0x98: + return dasm_bop(stream, opcode, "BEORL"); + + case 0x99: + return dasm_bop(stream, opcode, "BEORH"); + + case 0x9a: + return dasm_rrop(stream, opcode, "EOR"); + + case 0x9b: // LDI:20 + util::stream_format(stream, "%-8s", "LDI"); + format_i20(stream, u32(opcode & 0x00f0) << 12 | opcodes.r16(pc + 2)); + util::stream_format(stream, ", R%d", opcode & 0x000f); + return 4 | SUPPORTED; + + case 0x9c: + util::stream_format(stream, "%-8sR%d, @R%d", "EOR", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x9d: + util::stream_format(stream, "%-8sR%d, @R%d", "EORH", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x9e: + util::stream_format(stream, "%-8sR%d, @R%d", "EORB", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0x9f: + return dasm_9f(stream, pc, opcodes, opcode); + + case 0xa0: + case 0xa1: // ADDN2 + return dasm_i4op(stream, opcode, "ADDN"); + + case 0xa2: + return dasm_rrop(stream, opcode, "ADDN"); + + case 0xa3: + util::stream_format(stream, "%-8s#", "ADDSP"); + format_disp(stream, opcode & 0x00ff, 2); + return 2 | SUPPORTED; + + case 0xa4: + case 0xa5: // ADD2 + return dasm_i4op(stream, opcode, "ADD"); + + case 0xa6: + return dasm_rrop(stream, opcode, "ADD"); + + case 0xa7: + return dasm_rrop(stream, opcode, "ADDC"); + + case 0xa8: + case 0xa9: // CMP2 + return dasm_i4op(stream, opcode, "CMP"); + + case 0xaa: + return dasm_rrop(stream, opcode, "CMP"); + + case 0xab: + return dasm_rrop(stream, opcode, "MULH"); + + case 0xac: + return dasm_rrop(stream, opcode, "SUB"); + + case 0xad: + return dasm_rrop(stream, opcode, "SUBC"); + + case 0xae: + return dasm_rrop(stream, opcode, "SUBN"); + + case 0xaf: + return dasm_rrop(stream, opcode, "MUL"); + + case 0xb0: + case 0xb1: // LSR2 + return dasm_shift(stream, opcode, "LSR"); + + case 0xb2: + return dasm_rrop(stream, opcode, "LSR"); + + case 0xb3: + util::stream_format(stream, "%-8sR%d, ", "MOV", opcode & 0x000f); + format_rs(stream, (opcode & 0x00f0) >> 4); + return 2 | SUPPORTED; + + case 0xb4: + case 0xb5: // LSL2 + return dasm_shift(stream, opcode, "LSL"); + + case 0xb6: + return dasm_rrop(stream, opcode, "LSL"); + + case 0xb7: + util::stream_format(stream, "%-8s", "MOV"); + format_rs(stream, (opcode & 0x00f0) >> 4); + util::stream_format(stream, ", R%d", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0xb8: + case 0xb9: // ASR2 + return dasm_shift(stream, opcode, "ASR"); + + case 0xba: + return dasm_rrop(stream, opcode, "ASR"); + + case 0xbb: + return dasm_rrop(stream, opcode, "MULUH"); + + case 0xbc: + util::stream_format(stream, "%-8s@R%d+, #%d", "LDRES", opcode & 0x000f, (opcode & 0x00f0) >> 4); + return 2 | SUPPORTED; + + case 0xbd: + util::stream_format(stream, "%-8s#%d, @R%d+", "STRES", (opcode & 0x00f0) >> 4, opcode & 0x000f); + return 2 | SUPPORTED; + + case 0xbf: + return dasm_rrop(stream, opcode, "MULU"); + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: // LDI:8 + util::stream_format(stream, "%-8s", "LDI"); + format_i8(stream, (opcode & 0x0ff0) >> 4); + util::stream_format(stream, ", R%d", opcode & 0x000f); + return 2 | SUPPORTED; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + return dasm_call(stream, pc, "CALL", (opcode & 0x07ff) << 1); + + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + return dasm_call(stream, pc, "CALL:D", (opcode & 0x07ff) << 1) | step_over_extra(1); + + case 0xe0: + return dasm_branch(stream, pc, "BRA", (opcode & 0x00ff) << 1); + + case 0xe1: + return dasm_branch(stream, pc, "BNO", (opcode & 0x00ff) << 1); + + case 0xe2: + return dasm_branch(stream, pc, "BEQ", (opcode & 0x00ff) << 1); + + case 0xe3: + return dasm_branch(stream, pc, "BNE", (opcode & 0x00ff) << 1); + + case 0xe4: + return dasm_branch(stream, pc, "BC", (opcode & 0x00ff) << 1); + + case 0xe5: + return dasm_branch(stream, pc, "BNC", (opcode & 0x00ff) << 1); + + case 0xe6: + return dasm_branch(stream, pc, "BN", (opcode & 0x00ff) << 1); + + case 0xe7: + return dasm_branch(stream, pc, "BP", (opcode & 0x00ff) << 1); + + case 0xe8: + return dasm_branch(stream, pc, "BV", (opcode & 0x00ff) << 1); + + case 0xe9: + return dasm_branch(stream, pc, "BNV", (opcode & 0x00ff) << 1); + + case 0xea: + return dasm_branch(stream, pc, "BLT", (opcode & 0x00ff) << 1); + + case 0xeb: + return dasm_branch(stream, pc, "BGE", (opcode & 0x00ff) << 1); + + case 0xec: + return dasm_branch(stream, pc, "BLE", (opcode & 0x00ff) << 1); + + case 0xed: + return dasm_branch(stream, pc, "BGT", (opcode & 0x00ff) << 1); + + case 0xee: + return dasm_branch(stream, pc, "BLS", (opcode & 0x00ff) << 1); + + case 0xef: + return dasm_branch(stream, pc, "BHI", (opcode & 0x00ff) << 1); + + case 0xf0: + return dasm_branch(stream, pc, "BRA:D", (opcode & 0x00ff) << 1); + + case 0xf1: + return dasm_branch(stream, pc, "BNO:D", (opcode & 0x00ff) << 1); + + case 0xf2: + return dasm_branch(stream, pc, "BEQ:D", (opcode & 0x00ff) << 1); + + case 0xf3: + return dasm_branch(stream, pc, "BNE:D", (opcode & 0x00ff) << 1); + + case 0xf4: + return dasm_branch(stream, pc, "BC:D", (opcode & 0x00ff) << 1); + + case 0xf5: + return dasm_branch(stream, pc, "BNC:D", (opcode & 0x00ff) << 1); + + case 0xf6: + return dasm_branch(stream, pc, "BN:D", (opcode & 0x00ff) << 1); + + case 0xf7: + return dasm_branch(stream, pc, "BP:D", (opcode & 0x00ff) << 1); + + case 0xf8: + return dasm_branch(stream, pc, "BV:D", (opcode & 0x00ff) << 1); + + case 0xf9: + return dasm_branch(stream, pc, "BNV:D", (opcode & 0x00ff) << 1); + + case 0xfa: + return dasm_branch(stream, pc, "BLT:D", (opcode & 0x00ff) << 1); + + case 0xfb: + return dasm_branch(stream, pc, "BGE:D", (opcode & 0x00ff) << 1); + + case 0xfc: + return dasm_branch(stream, pc, "BLE:D", (opcode & 0x00ff) << 1); + + case 0xfd: + return dasm_branch(stream, pc, "BGT:D", (opcode & 0x00ff) << 1); + + case 0xfe: + return dasm_branch(stream, pc, "BLS:D", (opcode & 0x00ff) << 1); + + case 0xff: + return dasm_branch(stream, pc, "BHI:D", (opcode & 0x00ff) << 1); + + default: + return dasm_invalid(stream, opcode); + } +} diff --git a/src/devices/cpu/fr/frdasm.h b/src/devices/cpu/fr/frdasm.h new file mode 100644 index 00000000000..c02dfbb1b22 --- /dev/null +++ b/src/devices/cpu/fr/frdasm.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_FR_FRDASM_H +#define MAME_CPU_FR_FRDASM_H 1 + +#pragma once + +class fr_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + fr_disassembler(); + + // disassembler overrides + 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; + +protected: + // internal helpers + void format_u8(std::ostream &stream, u8 value); + void format_i8(std::ostream &stream, u8 value); + void format_disp(std::ostream &stream, u8 offs, unsigned shift); + void format_u10(std::ostream &stream, u16 value); + void format_i20(std::ostream &stream, u32 value); + void format_i32(std::ostream &stream, u32 value); + void format_label(std::ostream &stream, offs_t addr); + void format_dir(std::ostream &stream, u16 addr); + void format_ac_rdisp(std::ostream &stream, u8 rj); + void format_sp_udisp(std::ostream &stream, u8 disp); + void format_rs(std::ostream &stream, u8 reg); + offs_t dasm_invalid(std::ostream &stream, u16 opcode); + offs_t dasm_i4op(std::ostream &stream, u16 opcode, const char *inst); + offs_t dasm_shift(std::ostream &stream, u16 opcode, const char *inst); + offs_t dasm_rrop(std::ostream &stream, u16 opcode, const char *inst); + offs_t dasm_ld_fp_disp(std::ostream &stream, u16 opcode, const char *inst, unsigned shift); + offs_t dasm_st_fp_disp(std::ostream &stream, u16 opcode, const char *inst, unsigned shift); + offs_t dasm_ldstm(std::ostream &stream, u16 opcode, const char *inst); + offs_t dasm_bop(std::ostream &stream, u16 opcode, const char *inst); + offs_t dasm_cop(std::ostream &stream, u16 op1, u16 op2, const char *inst, bool crj, bool cri); + offs_t dasm_call(std::ostream &stream, offs_t pc, const char *inst, u16 disp); + offs_t dasm_branch(std::ostream &stream, offs_t pc, const char *inst, u16 disp); + offs_t dasm_07(std::ostream &stream, offs_t pc, const data_buffer &opcodes, u16 opcode); + offs_t dasm_17(std::ostream &stream, offs_t pc, const data_buffer &opcodes, u16 opcode); + offs_t dasm_97(std::ostream &stream, offs_t pc, const data_buffer &opcodes, u16 opcode); + offs_t dasm_9f(std::ostream &stream, offs_t pc, const data_buffer &opcodes, u16 opcode); +}; + +#endif // MAME_CPU_FR_FRDASM_H diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index 677b3a65edb..3e776f586c0 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -49,6 +49,7 @@ using util::BIT; #include "cpu/esrip/esripdsm.h" #include "cpu/f2mc16/f2mc16dasm.h" #include "cpu/f8/f8dasm.h" +#include "cpu/fr/frdasm.h" #include "cpu/g65816/g65816ds.h" #include "cpu/h6280/6280dasm.h" #include "cpu/h8/h8d.h" @@ -359,6 +360,7 @@ static const dasm_table_entry dasm_table[] = { "esrip", be, 0, []() -> util::disasm_interface * { return new esrip_disassembler; } }, { "f2mc16", le, 0, []() -> util::disasm_interface * { return new f2mc16_disassembler; } }, { "f8", be, 0, []() -> util::disasm_interface * { return new f8_disassembler; } }, + { "fr", be, 0, []() -> util::disasm_interface * { return new fr_disassembler; } }, { "g65816", le, 0, []() -> util::disasm_interface * { return new g65816_disassembler(&g65816_unidasm); } }, { "h6280", le, 0, []() -> util::disasm_interface * { return new h6280_disassembler; } }, { "h8", be, 0, []() -> util::disasm_interface * { return new h8_disassembler; } },