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 &params)
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