unidasm: Add Interdata Series 16 disassembler

This commit is contained in:
AJR 2023-03-11 09:19:24 -05:00
parent fa4ea8e951
commit 6543248641
4 changed files with 465 additions and 0 deletions

View File

@ -3778,3 +3778,13 @@ if opt_tool(CPUS, "NOVA") then
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/nova/novadasm.cpp")
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/nova/novadasm.h")
end
--------------------------------------------------
-- Interdata Series 16, disassembler only
--@src/devices/cpu/interdata16/interdata16.h,CPUS["INTERDATA16"] = true
--------------------------------------------------
if opt_tool(CPUS, "INTERDATA16") then
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/interdata16/dasm16.cpp")
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/interdata16/dasm16.h")
end

View File

@ -0,0 +1,428 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/***************************************************************************
Interdata/Perkin-Elmer Series 16 disassembler
The instrution set supported here is that of the Model 8/16E Processor,
which is backward-compatible with practically all of its predecessors.
Only SETM(R) and the double-precision floating point instructions were
relatively late additions to the 16-bit architecture; most others were
supported as least as far back as the Model 5 (1970), though
multiply/divide and floating point support were optional on a few
subsequent models. Interdata's first-generation Models 3 & 4 lacked
short-form instructions and list processing, which likely made these
processors incompatible with most later software.
Not supported here are the unique instruction set of the low-end
Model 1, the unusual extended instructions provided on some Model 4 and
Model 50 configurations, or the only partially compatible instruction
set and extended addressing modes of Interdata's 32-bit series.
***************************************************************************/
#include "emu.h"
#include "dasm16.h"
interdata16_disassembler::interdata16_disassembler()
: util::disasm_interface()
{
}
u32 interdata16_disassembler::opcode_alignment() const
{
return 2;
}
namespace {
static constexpr offs_t STEP_COND = interdata16_disassembler::STEP_COND;
static constexpr offs_t STEP_OVER = interdata16_disassembler::STEP_OVER;
static constexpr offs_t STEP_OUT = interdata16_disassembler::STEP_OUT;
using namespace std::literals;
static const std::pair<std::string_view, offs_t> s_inst_table[0x100] =
{
// 00-0F
{ {}, 0 },
{ "BALR"sv, STEP_OVER },
{ "BTCR"sv, STEP_COND },
{ "BFCR"sv, STEP_COND },
{ "NHR"sv, 0 },
{ "CLHR"sv, 0 },
{ "OHR"sv, 0 },
{ "XHR"sv, 0 },
{ "LHR"sv, 0 },
{ "CHR"sv, 0 },
{ "AHR"sv, 0 },
{ "SHR"sv, 0 },
{ "MHR"sv, 0 },
{ "DHR"sv, 0 },
{ "ACHR"sv, 0 },
{ "SCHR"sv, 0 },
// 10-1F
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ "SETMR"sv, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
// 20-2F
{ "BTBS"sv, STEP_COND },
{ "BTFS"sv, STEP_COND },
{ "BFBS"sv, STEP_COND },
{ "BFFS"sv, STEP_COND },
{ "LIS"sv, 0 },
{ "LCS"sv, 0 },
{ "AIS"sv, 0 },
{ "SIS"sv, 0 },
{ "LER"sv, 0 },
{ "CER"sv, 0 },
{ "AER"sv, 0 },
{ "SER"sv, 0 },
{ "MER"sv, 0 },
{ "DER"sv, 0 },
{ "FXR"sv, 0 },
{ "FLR"sv, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ "LPSR"sv, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ "LDR"sv, 0 },
{ "CDR"sv, 0 },
{ "ADR"sv, 0 },
{ "SDR"sv, 0 },
{ "MDR"sv, 0 },
{ "DDR"sv, 0 },
{ "FXDR"sv, 0 },
{ "FLDR"sv, 0 },
// 40-4F
{ "STH"sv, 0 },
{ "BAL"sv, STEP_OVER },
{ "BTC"sv, STEP_COND },
{ "BFC"sv, STEP_COND },
{ "NH"sv, 0 },
{ "CLH"sv, 0 },
{ "OH"sv, 0 },
{ "XH"sv, 0 },
{ "LH"sv, 0 },
{ "CH"sv, 0 },
{ "AH"sv, 0 },
{ "SH"sv, 0 },
{ "MH"sv, 0 },
{ "DH"sv, 0 },
{ "ACH"sv, 0 },
{ "SCH"sv, 0 },
// 50-5F
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ "SETM"sv, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
// 60-6F
{ "STE"sv, 0 },
{ "AHM"sv, 0 },
{ {}, 0 },
{ {}, 0 },
{ "ATL"sv, 0 },
{ "ABL"sv, 0 },
{ "RTL"sv, 0 },
{ "RBL"sv, 0 },
{ "LE"sv, 0 },
{ "CE"sv, 0 },
{ "AE"sv, 0 },
{ "SE"sv, 0 },
{ "ME"sv, 0 },
{ "DE"sv, 0 },
{ {}, 0 },
{ {}, 0 },
// 70-7F
{ "STD"sv, 0 },
{ "STME"sv, 0 },
{ "LME", 0 },
{ "LPS", 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ "LD"sv, 0 },
{ "CD"sv, 0 },
{ "AD"sv, 0 },
{ "SD"sv, 0 },
{ "MD"sv, 0 },
{ "DD"sv, 0 },
{ {}, 0 },
{ {}, 0 },
// 80-8F
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
// 90-9F
{ "SRLS"sv, 0 },
{ "SLLS"sv, 0 },
{ "STBR"sv, 0 },
{ "LBR"sv, 0 },
{ "EXBR"sv, 0 },
{ "EPSR"sv, 0 },
{ "WBR"sv, 0 },
{ "RBR"sv, 0 },
{ "WHR"sv, 0 },
{ "RHR"sv, 0 },
{ "WDR"sv, 0 },
{ "RDR"sv, 0 },
{ "MHUR"sv, 0 },
{ "SSR"sv, 0 },
{ "OCR"sv, 0 },
{ "AIR"sv, 0 },
// A0-AF
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
// B0-BF
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
// C0-CF
{ "BXH"sv, 0 },
{ "BXLE"sv, 0 },
{ "LPSW"sv, STEP_OUT },
{ "THI"sv, 0 },
{ "NHI"sv, 0 },
{ "CLHI"sv, 0 },
{ "OHI"sv, 0 },
{ "XHI"sv, 0 },
{ "LHI"sv, 0 },
{ "CHI"sv, 0 },
{ "AHI"sv, 0 },
{ "SHI"sv, 0 },
{ "SRHL"sv, 0 },
{ "SLHL"sv, 0 },
{ "SRHA"sv, 0 },
{ "SLHA"sv, 0 },
// D0-DF
{ "STM"sv, 0 },
{ "LM"sv, 0 },
{ "STB"sv, 0 },
{ "LB"sv, 0 },
{ "CLB"sv, 0 },
{ "AL"sv, 0 },
{ "WB"sv, 0 },
{ "RB"sv, 0 },
{ "WH"sv, 0 },
{ "RH"sv, 0 },
{ "WD"sv, 0 },
{ "RD"sv, 0 },
{ "MHU"sv, 0 },
{ "SS"sv, 0 },
{ "OC"sv, 0 },
{ "AI"sv, 0 },
// E0-EF
{ {}, 0 },
{ "SVC"sv, STEP_OVER },
{ "SINT"sv, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ "RRL"sv, 0 },
{ "RLL"sv, 0 },
{ "SRL"sv, 0 },
{ "SLL"sv, 0 },
{ "SRA"sv, 0 },
{ "SLA"sv, 0 },
// F0-FF
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 },
{ {}, 0 }
};
static const std::string_view s_b_mnemonics[32] =
{
"NOP"sv, "BM"sv, "BP"sv, "BNZ"sv, "BO"sv, {}, {}, {}, "BC"sv, {}, {}, {}, {}, {}, {}, {},
"B"sv, "BNM"sv, "BNP"sv, "BZ"sv, "BNO"sv, {}, {}, {}, "BNC"sv, {}, {}, {}, {}, {}, {}, {}
};
} // anonymous namespace
void interdata16_disassembler::format_s16(std::ostream &stream, s16 halfword)
{
if (halfword < 0)
{
stream << '-';
halfword = -halfword;
}
if (u16(halfword) <= 9)
util::stream_format(stream, "%d", halfword);
else
util::stream_format(stream, "X'%X'", u16(halfword));
}
offs_t interdata16_disassembler::disassemble(std::ostream &stream, offs_t pc, const interdata16_disassembler::data_buffer &opcodes, const interdata16_disassembler::data_buffer &params)
{
const u16 i = opcodes.r16(pc);
auto const inst = s_inst_table[BIT(i, 8, 8)];
offs_t flags = inst.second;
if (inst.first.empty())
{
// Illegal opcodes
util::stream_format(stream, "%-6sX'%04X'", "DC", i);
return 2 | SUPPORTED;
}
else if ((i & 0xfc00) == 0x2000)
{
// Short conditional branches
const std::string_view bm = s_b_mnemonics[(i & 0x0200) >> 5 | (i & 0x00f0) >> 4];
if (!bm.empty())
util::stream_format(stream, "%-6sX'%04X'", util::string_format("%sS", bm), (BIT(i, 8) ? pc + BIT(i, 0, 4) * 2 : pc - BIT(i, 0, 4) * 2) & 0xffff);
else
util::stream_format(stream, "%-6s%d,%d", inst.first, BIT(i, 4, 4), BIT(i, 0, 4));
if (BIT(i, 4, 4) == 0)
flags = 0;
return 2 | flags | SUPPORTED;
}
else
{
if ((i & 0xbe00) == 0x0200)
{
// Conditional branches
const std::string_view bm = s_b_mnemonics[BIT(i, 4, 5)];
if (!bm.empty())
{
if (BIT(i, 14))
util::stream_format(stream, "%-6s", bm);
else
util::stream_format(stream, "%-6s", util::string_format("%sR", bm));
if (BIT(i, 4, 4) == 0)
flags = 0;
}
else
util::stream_format(stream, "%-6s%d,", inst.first, BIT(i, 4, 4));
}
else if ((i & 0xbf00) == 0x3300 || (i & 0xdf00) == 0xc200 || (i & 0xff00) == 0xd500) // LPS(R), LPSW, SINT, AL
util::stream_format(stream, "%-6s", inst.first, BIT(i, 4, 4));
else if ((i & 0xff00) == 0xe100) // SVC
util::stream_format(stream, "%-6s%d,", inst.first, BIT(i, 4, 4));
else
util::stream_format(stream, "%-6sR%d,", inst.first, BIT(i, 4, 4));
if (BIT(i, 14))
{
// RX or RI
if (BIT(i, 0, 4) != 0)
{
format_s16(stream, opcodes.r16(pc + 2));
util::stream_format(stream, "(R%d)", BIT(i, 0, 4));
}
else if ((i >= 0xc900 && i < 0xd000) || i >= 0xea00)
format_s16(stream, opcodes.r16(pc + 2));
else
util::stream_format(stream, "X'%04X'", opcodes.r16(pc + 2));
return 4 | flags | SUPPORTED;
}
else
{
// RR or SF
if ((i & 0xf800) == 0x2000 || (i & 0xfe00) == 0x9000)
util::stream_format(stream, "%d", BIT(i, 0, 4));
else
util::stream_format(stream, "R%d", BIT(i, 0, 4));
return 2 | flags | SUPPORTED;
}
}
}

View File

@ -0,0 +1,25 @@
// license:BSD-3-Clause
// copyright-holders:AJR
#ifndef MAME_CPU_INTERDATA16_DASM16_H
#define MAME_CPU_INTERDATA16_DASM16_H
#pragma once
class interdata16_disassembler : public util::disasm_interface
{
public:
// construction/destruction
interdata16_disassembler();
protected:
// util::disasm_interface overrides
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;
private:
// formatting helpers
static void format_s16(std::ostream &stream, s16 halfword);
};
#endif // MAME_CPU_INTERDATA16_DASM16_H

View File

@ -76,6 +76,7 @@ using util::BIT;
#include "cpu/i960/i960dis.h"
#include "cpu/ibm1800/ibm1800d.h"
#include "cpu/ie15/ie15dasm.h"
#include "cpu/interdata16/dasm16.h"
#include "cpu/jaguar/jagdasm.h"
#include "cpu/ks0164/ks0164d.h"
#include "cpu/lc57/lc57d.h"
@ -484,6 +485,7 @@ static const dasm_table_entry dasm_table[] =
{ "ibm1130", be, -1, []() -> util::disasm_interface * { return new ibm1130_disassembler; } },
{ "ibm1800", be, -1, []() -> util::disasm_interface * { return new ibm1800_disassembler; } },
{ "ie15", le, 0, []() -> util::disasm_interface * { return new ie15_disassembler; } },
{ "interdata16", be, 0, []() -> util::disasm_interface * { return new interdata16_disassembler; } },
{ "jaguardsp", be, 0, []() -> util::disasm_interface * { return new jaguar_disassembler(jaguar_disassembler::variant::DSP); } },
{ "jaguargpu", be, 0, []() -> util::disasm_interface * { return new jaguar_disassembler(jaguar_disassembler::variant::GPU); } },
{ "konami", be, 0, []() -> util::disasm_interface * { return new konami_disassembler; } },