1 // license:BSD-3-Clause
2 // copyright-holders:Vas Crabb
3 /*****************************************************************************
4 *
5 * 4004dasm.cpp
6 *
7 * Intel MCS-40 CPU Disassembly
8 *
9 *****************************************************************************/
10
11 #include "emu.h"
12 #include "mcs40dasm.h"
13
14
15 #define OP(fmt, lvl, name) { format::fmt, level::lvl, #name, nullptr }
16 #define OPX(tbl) { format::EXT, level::I4004, nullptr, f_opx_##tbl }
17
18 mcs40_disassembler::op const mcs40_disassembler::f_opx_0[16] = {
19 OP(SIMPLE, I4004, nop), OP(SIMPLE, I4040, hlt), OP(SIMPLE, I4040, bbs), OP(SIMPLE, I4040, lcr),
20 OP(SIMPLE, I4040, or4), OP(SIMPLE, I4040, or5), OP(SIMPLE, I4040, an6), OP(SIMPLE, I4040, an7),
21 OP(SIMPLE, I4040, db0), OP(SIMPLE, I4040, db1), OP(SIMPLE, I4040, sb0), OP(SIMPLE, I4040, sb1),
22 OP(SIMPLE, I4040, ein), OP(SIMPLE, I4040, din), OP(SIMPLE, I4040, rpm), OP(ILL, I4004, ill) };
23
24 mcs40_disassembler::op const mcs40_disassembler::f_opx_2[16] = {
25 OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src), OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src),
26 OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src), OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src),
27 OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src), OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src),
28 OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src), OP(PAIRIMM, I4004, fim), OP(PAIR, I4004, src) };
29
30 mcs40_disassembler::op const mcs40_disassembler::f_opx_3[16] = {
31 OP(PAIR, I4004, fin), OP(PAIR, I4004, jin), OP(PAIR, I4004, fin), OP(PAIR, I4004, jin),
32 OP(PAIR, I4004, fin), OP(PAIR, I4004, jin), OP(PAIR, I4004, fin), OP(PAIR, I4004, jin),
33 OP(PAIR, I4004, fin), OP(PAIR, I4004, jin), OP(PAIR, I4004, fin), OP(PAIR, I4004, jin),
34 OP(PAIR, I4004, fin), OP(PAIR, I4004, jin), OP(PAIR, I4004, fin), OP(PAIR, I4004, jin) };
35
36 mcs40_disassembler::op const mcs40_disassembler::f_opx_io[16] = {
37 OP(SIMPLE, I4004, wrm), OP(SIMPLE, I4004, wmp), OP(SIMPLE, I4004, wrr), OP(SIMPLE, I4004, wpm),
38 OP(SIMPLE, I4004, wr0), OP(SIMPLE, I4004, wr1), OP(SIMPLE, I4004, wr2), OP(SIMPLE, I4004, wr3),
39 OP(SIMPLE, I4004, sbm), OP(SIMPLE, I4004, rdm), OP(SIMPLE, I4004, rdr), OP(SIMPLE, I4004, adm),
40 OP(SIMPLE, I4004, rd0), OP(SIMPLE, I4004, rd1), OP(SIMPLE, I4004, rd2), OP(SIMPLE, I4004, rd3) };
41
42 mcs40_disassembler::op const mcs40_disassembler::f_opx_f[16] = {
43 OP(SIMPLE, I4004, clb), OP(SIMPLE, I4004, clc), OP(SIMPLE, I4004, iac), OP(SIMPLE, I4004, cmc),
44 OP(SIMPLE, I4004, cma), OP(SIMPLE, I4004, ral), OP(SIMPLE, I4004, rar), OP(SIMPLE, I4004, tcc),
45 OP(SIMPLE, I4004, dac), OP(SIMPLE, I4004, tcs), OP(SIMPLE, I4004, stc), OP(SIMPLE, I4004, daa),
46 OP(SIMPLE, I4004, kbp), OP(SIMPLE, I4004, dcl), OP(ILL, I4004, ill), OP(ILL, I4004, ill) };
47
48 mcs40_disassembler::op const mcs40_disassembler::f_ops[16] = {
49 OPX(0), OP(COND, I4004, jcn), OPX(2), OPX(3),
50 OP(ABS, I4004, jun), OP(ABS, I4004, jms), OP(REG, I4004, inc), OP(REGPAGE, I4004, isz),
51 OP(REG, I4004, add), OP(REG, I4004, sub), OP(REG, I4004, ld ), OP(REG, I4004, xch),
52 OP(IMM4, I4004, bbl), OP(IMM4, I4004, ldm), OPX(io), OPX(f) };
53
54 char const *const mcs40_disassembler::f_cond[16] = {
55 "$0", "nt", "c", "$3", "z", "$5", "$6", "$7",
56 "$8", "t", "nc", "$b", "nz", "$d", "$e", "$f" };
57
opcode_alignment() const58 u32 mcs40_disassembler::opcode_alignment() const
59 {
60 return 1;
61 }
62
mcs40_disassembler(level lvl,unsigned pcmask)63 mcs40_disassembler::mcs40_disassembler(level lvl, unsigned pcmask) : m_lvl(lvl), m_pcmask(pcmask)
64 {
65 (void)m_pcmask;
66 }
67
disassemble(std::ostream & stream,offs_t pc,const data_buffer & opcodes,const data_buffer & params)68 offs_t mcs40_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms)
69 {
70 offs_t npc(pc + 1);
71 u8 const opcode(opcodes.r8(pc));
72 op const &base_op(f_ops[(opcode >> 4) & 0x0f]);
73 op const &ext_op((base_op.m_format == format::EXT) ? base_op.m_ext[opcode & 0x0f] : base_op);
74 op const desc((ext_op.m_level > m_lvl) ? f_opx_f[0x0f] : ext_op);
75
76 u8 const imm4(opcode & 0x0f);
77 u8 const pair(opcode & 0x0e);
78 switch (desc.m_format)
79 {
80 case format::ILL:
81 util::stream_format(stream, "%-3s $%02x", desc.m_name, opcode);
82 break;
83 case format::SIMPLE:
84 util::stream_format(stream, "%s", desc.m_name);
85 break;
86 case format::IMM4:
87 util::stream_format(stream, "%-3s $%01x", desc.m_name, imm4);
88 break;
89 case format::REG:
90 util::stream_format(stream, "%-3s r%01x", desc.m_name, imm4);
91 break;
92 case format::REGPAGE:
93 npc++;
94 util::stream_format(stream, "%-3s r%01x,$%03x", desc.m_name, imm4, opcodes.r8(pc+1) | (npc & 0x0f00U));
95 break;
96 case format::PAIR:
97 util::stream_format(stream, "%-3s r%01xr%01x", desc.m_name, pair, pair + 1U);
98 break;
99 case format::PAIRIMM:
100 npc++;
101 util::stream_format(stream, "%-3s r%01xr%01x,$%02x", desc.m_name, pair, pair + 1, opcodes.r8(pc+1));
102 break;
103 case format::ABS:
104 npc++;
105 util::stream_format(stream, "%-3s $%03x", desc.m_name, ((u16(opcode) & 0x0fU) << 8) | opcodes.r8(pc+1));
106 break;
107 case format::PAGE:
108 npc++;
109 util::stream_format(stream, "%-3s $%03x", desc.m_name, opcodes.r8(pc+1) | (npc & 0x0f00U));
110 break;
111 case format::COND:
112 npc++;
113 util::stream_format(stream, "%-3s %s,$%03x", desc.m_name, f_cond[imm4], opcodes.r8(pc+1) | (npc & 0x0f00U));
114 break;
115 default:
116 throw false;
117 }
118
119 offs_t flags(0U);
120 if (format::ILL != desc.m_format)
121 {
122 if (0x50U == (opcode & 0xf0U)) // JMS
123 flags = STEP_OVER;
124 else if ((0xc0 == (opcode & 0xf0)) || (0x02 == opcode)) // BBL/BBS
125 flags = STEP_OUT;
126 }
127
128 return (npc - pc) | flags | SUPPORTED;
129 }
130
i4004_disassembler()131 i4004_disassembler::i4004_disassembler() : mcs40_disassembler(level::I4004, 0x0fffU)
132 {
133 }
134
135
i4040_disassembler()136 i4040_disassembler::i4040_disassembler() : mcs40_disassembler(level::I4040, 0x1fffU)
137 {
138 }
139