1 |
/* |
2 |
* mon_8080.cpp - 8080 disassembler |
3 |
* |
4 |
* mon (C) 1997-2000 Christian Bauer, Marc Hellwig |
5 |
* |
6 |
* This program is free software; you can redistribute it and/or modify |
7 |
* it under the terms of the GNU General Public License as published by |
8 |
* the Free Software Foundation; either version 2 of the License, or |
9 |
* (at your option) any later version. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
*/ |
20 |
|
21 |
#include "sysdeps.h" |
22 |
|
23 |
#include "mon.h" |
24 |
#include "mon_disass.h" |
25 |
|
26 |
|
27 |
// Addressing modes |
28 |
enum { |
29 |
A_IMPL, |
30 |
A_BC, // bc |
31 |
A_DE, // de |
32 |
A_HL, // hl |
33 |
A_SP, // sp |
34 |
A_PSW, // psw |
35 |
A_REG1, // register (bits 0..2 of opcode) |
36 |
A_REG2, // register (bits 3..5 of opcode) |
37 |
A_2REG, // register (bits 3..5 of opcode),register (bits 0..2 of opcode) |
38 |
A_RST, // restart |
39 |
A_BYTE, // xx |
40 |
A_R2_B, // register (bits 3..5 of opcode),xx |
41 |
A_WORD, // xxxx |
42 |
A_BC_W, // bc,xxxx |
43 |
A_DE_W, // de,xxxx |
44 |
A_HL_W, // hl,xxxx |
45 |
A_SP_W // sp,xxxx |
46 |
}; |
47 |
|
48 |
// Mnemonics |
49 |
enum { |
50 |
M_ACI, M_ADC, M_ADD, M_ADI, M_ANA, M_ANI, M_CALL, M_CC, M_CM, M_CMA, M_CMC, |
51 |
M_CMP, M_CNC, M_CNZ, M_CP, M_CPE, M_CPI, M_CPO, M_CZ, M_DAA, M_DAD, M_DCR, |
52 |
M_DCX, M_DI, M_EI, M_HLT, M_IN, M_INR, M_INX, M_JMP, M_JC, M_JM, M_JNC, M_JNZ, |
53 |
M_JP, M_JPE, M_JPO, M_JZ, M_LDA, M_LDAX, M_LHLD, M_LXI, M_MOV, M_MVI, M_NOP, |
54 |
M_ORA, M_ORI, M_OUT, M_PCHL, M_POP, M_PUSH, M_RAL, M_RAR, M_RET, M_RC, M_RM, |
55 |
M_RNC, M_RNZ, M_RP, M_RPE, M_RPO, M_RZ, M_RLC, M_RRC, M_RST, M_SBB, M_SBI, |
56 |
M_SHLD, M_SPHL, M_STA, M_STAX, M_STC, M_SUB, M_SUI, M_XCHG, M_XRA, M_XRI, M_XTHL, |
57 |
M_ILLEGAL, |
58 |
|
59 |
M_MAXIMUM // Highest element |
60 |
}; |
61 |
|
62 |
// Mnemonic for each opcode |
63 |
static const char mnemonic[256] = { |
64 |
M_NOP , M_LXI , M_STAX, M_INX , M_INR, M_DCR , M_MVI, M_RLC, // 00 |
65 |
M_ILLEGAL, M_DAD , M_LDAX, M_DCX , M_INR, M_DCR , M_MVI, M_RRC, |
66 |
M_ILLEGAL, M_LXI , M_STAX, M_INX , M_INR, M_DCR , M_MVI, M_RAL, // 10 |
67 |
M_ILLEGAL, M_DAD , M_LDAX, M_DCX , M_INR, M_DCR , M_MVI, M_RAR, |
68 |
M_ILLEGAL, M_LXI , M_SHLD, M_INX , M_INR, M_DCR , M_MVI, M_DAA, // 20 |
69 |
M_ILLEGAL, M_DAD , M_LHLD, M_DCX , M_INR, M_DCR , M_MVI, M_CMA, |
70 |
M_ILLEGAL, M_LXI , M_STA , M_INX , M_INR, M_DCR , M_MVI, M_STC, // 30 |
71 |
M_ILLEGAL, M_DAD , M_LDA , M_DCX , M_INR, M_DCR , M_MVI, M_CMC, |
72 |
M_MOV , M_MOV , M_MOV , M_MOV , M_MOV, M_MOV , M_MOV, M_MOV, // 40 |
73 |
M_MOV , M_MOV , M_MOV , M_MOV , M_MOV, M_MOV , M_MOV, M_MOV, |
74 |
M_MOV , M_MOV , M_MOV , M_MOV , M_MOV, M_MOV , M_MOV, M_MOV, // 50 |
75 |
M_MOV , M_MOV , M_MOV , M_MOV , M_MOV, M_MOV , M_MOV, M_MOV, |
76 |
M_MOV , M_MOV , M_MOV , M_MOV , M_MOV, M_MOV , M_MOV, M_MOV, // 60 |
77 |
M_MOV , M_MOV , M_MOV , M_MOV , M_MOV, M_MOV , M_MOV, M_MOV, |
78 |
M_MOV , M_MOV , M_MOV , M_MOV , M_MOV, M_MOV , M_HLT, M_MOV, // 70 |
79 |
M_MOV , M_MOV , M_MOV , M_MOV , M_MOV, M_MOV , M_MOV, M_MOV, |
80 |
M_ADD , M_ADD , M_ADD , M_ADD , M_ADD, M_ADD , M_ADD, M_ADD, // 80 |
81 |
M_ADC , M_ADC , M_ADC , M_ADC , M_ADC, M_ADC , M_ADC, M_ADC, |
82 |
M_SUB , M_SUB , M_SUB , M_SUB , M_SUB, M_SUB , M_SUB, M_SUB, // 90 |
83 |
M_SBB , M_SBB , M_SBB , M_SBB , M_SBB, M_SBB , M_SBB, M_SBB, |
84 |
M_ANA , M_ANA , M_ANA , M_ANA , M_ANA, M_ANA , M_ANA, M_ANA, // a0 |
85 |
M_XRA , M_XRA , M_XRA , M_XRA , M_XRA, M_XRA , M_XRA, M_XRA, |
86 |
M_ORA , M_ORA , M_ORA , M_ORA , M_ORA, M_ORA , M_ORA, M_ORA, // b0 |
87 |
M_CMP , M_CMP , M_CMP , M_CMP , M_CMP, M_CMP , M_CMP, M_CMP, |
88 |
M_RNZ , M_POP , M_JNZ , M_JMP , M_CNZ, M_PUSH , M_ADI, M_RST, // c0 |
89 |
M_RZ , M_RET , M_JZ , M_ILLEGAL, M_CZ , M_CALL , M_ACI, M_RST, |
90 |
M_RNC , M_POP , M_JNC , M_OUT , M_CNC, M_PUSH , M_SUI, M_RST, // d0 |
91 |
M_RC , M_ILLEGAL, M_JC , M_IN , M_CC , M_ILLEGAL, M_SBI, M_RST, |
92 |
M_RPO , M_POP , M_JPO , M_XTHL , M_CPO, M_PUSH , M_ANI, M_RST, // e0 |
93 |
M_RPE , M_PCHL , M_JPE , M_XCHG , M_CPE, M_ILLEGAL, M_XRI, M_RST, |
94 |
M_RP , M_POP , M_JP , M_DI , M_CP , M_PUSH , M_ORI, M_RST, // f0 |
95 |
M_RM , M_SPHL , M_JM , M_EI , M_CM , M_ILLEGAL, M_CPI, M_RST |
96 |
}; |
97 |
|
98 |
// Addressing mode for each opcode |
99 |
static const char adr_mode[256] = { |
100 |
A_IMPL, A_BC_W, A_BC , A_BC , A_REG2, A_REG2, A_R2_B, A_IMPL, // 00 |
101 |
A_IMPL, A_BC , A_BC , A_BC , A_REG2, A_REG2, A_R2_B, A_IMPL, |
102 |
A_IMPL, A_DE_W, A_DE , A_DE , A_REG2, A_REG2, A_R2_B, A_IMPL, // 10 |
103 |
A_IMPL, A_DE , A_DE , A_DE , A_REG2, A_REG2, A_R2_B, A_IMPL, |
104 |
A_IMPL, A_HL_W, A_WORD, A_HL , A_REG2, A_REG2, A_R2_B, A_IMPL, // 20 |
105 |
A_IMPL, A_HL , A_WORD, A_HL , A_REG2, A_REG2, A_R2_B, A_IMPL, |
106 |
A_IMPL, A_SP_W, A_WORD, A_SP , A_REG2, A_REG2, A_R2_B, A_IMPL, // 30 |
107 |
A_IMPL, A_SP , A_WORD, A_SP , A_REG2, A_REG2, A_R2_B, A_IMPL, |
108 |
A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, // 40 |
109 |
A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, |
110 |
A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, // 50 |
111 |
A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, |
112 |
A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, // 60 |
113 |
A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, |
114 |
A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_IMPL, A_2REG, // 70 |
115 |
A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, A_2REG, |
116 |
A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, // 80 |
117 |
A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, |
118 |
A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, // 90 |
119 |
A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, |
120 |
A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, // a0 |
121 |
A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, |
122 |
A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, // b0 |
123 |
A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, A_REG1, |
124 |
A_IMPL, A_BC , A_WORD, A_WORD, A_WORD, A_BC , A_BYTE, A_RST , // c0 |
125 |
A_IMPL, A_IMPL, A_WORD, A_IMPL, A_WORD, A_WORD, A_BYTE, A_RST , |
126 |
A_IMPL, A_DE , A_WORD, A_BYTE, A_WORD, A_DE , A_BYTE, A_RST , // d0 |
127 |
A_IMPL, A_IMPL, A_WORD, A_BYTE, A_WORD, A_IMPL, A_BYTE, A_RST , |
128 |
A_IMPL, A_HL , A_WORD, A_IMPL, A_WORD, A_HL , A_BYTE, A_RST , // e0 |
129 |
A_IMPL, A_IMPL, A_WORD, A_IMPL, A_WORD, A_IMPL, A_BYTE, A_RST , |
130 |
A_IMPL, A_PSW , A_WORD, A_IMPL, A_WORD, A_PSW , A_BYTE, A_RST , // f0 |
131 |
A_IMPL, A_IMPL, A_WORD, A_IMPL, A_WORD, A_IMPL, A_BYTE, A_RST |
132 |
}; |
133 |
|
134 |
// Chars for each mnemonic |
135 |
static const char mnem_1[] = "aaaaaacccccccccccccdddddehiiijjjjjjjjjllllmmnoooppprrrrrrrrrrrrrrsssssssssxxxx?"; |
136 |
static const char mnem_2[] = "cdddnnacmmmmnnppppzaacciilnnnmcmnnpppzddhxovorrucouaaecmnnpppzlrsbbhptttuucrrt "; |
137 |
static const char mnem_3[] = "icdiail acpcz eio adrx t rxp cz eo aalivipaithpslrt cz eo cctbilhaacbihaih "; |
138 |
static const char mnem_4[] = " l xd l h dl x g l "; |
139 |
|
140 |
// Register names |
141 |
static const char reg_name[] = {"bcdehlma"}; |
142 |
|
143 |
// Instruction length for each addressing mode |
144 |
static const char adr_length[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3}; |
145 |
|
146 |
|
147 |
/* |
148 |
* Disassemble one instruction, return number of bytes |
149 |
*/ |
150 |
|
151 |
int disass_8080(FILE *f, uint32 adr, uint8 op, uint8 lo, uint8 hi) |
152 |
{ |
153 |
char mode = adr_mode[op], mnem = mnemonic[op]; |
154 |
|
155 |
// Display instruction bytes in hex |
156 |
switch (adr_length[mode]) { |
157 |
case 1: |
158 |
fprintf(f, "%02x\t\t", op); |
159 |
break; |
160 |
|
161 |
case 2: |
162 |
fprintf(f, "%02x %02x\t\t", op, lo); |
163 |
break; |
164 |
|
165 |
case 3: |
166 |
fprintf(f, "%02x %02x %02x\t", op, lo, hi); |
167 |
break; |
168 |
} |
169 |
|
170 |
// Print mnemonic |
171 |
fprintf(f, "%c%c%c%c ", mnem_1[mnem], mnem_2[mnem], mnem_3[mnem], mnem_4[mnem]); |
172 |
|
173 |
// Print argument |
174 |
switch (mode) { |
175 |
case A_IMPL: |
176 |
break; |
177 |
|
178 |
case A_BC: |
179 |
fprintf(f, "bc"); |
180 |
break; |
181 |
|
182 |
case A_DE: |
183 |
fprintf(f, "de"); |
184 |
break; |
185 |
|
186 |
case A_HL: |
187 |
fprintf(f, "hl"); |
188 |
break; |
189 |
|
190 |
case A_SP: |
191 |
fprintf(f, "sp"); |
192 |
break; |
193 |
|
194 |
case A_PSW: |
195 |
fprintf(f, "psw"); |
196 |
break; |
197 |
|
198 |
case A_REG1: |
199 |
fprintf(f, "%c", reg_name[op & 7]); |
200 |
break; |
201 |
|
202 |
case A_REG2: |
203 |
fprintf(f, "%c", reg_name[(op >> 3) & 7]); |
204 |
break; |
205 |
|
206 |
case A_2REG: |
207 |
fprintf(f, "%c,%c", reg_name[(op >> 3) & 7], reg_name[op & 7]); |
208 |
break; |
209 |
|
210 |
case A_RST: |
211 |
fprintf(f, "$%02x", op & 0x38); |
212 |
break; |
213 |
|
214 |
case A_BYTE: |
215 |
fprintf(f, "$%02x", lo); |
216 |
break; |
217 |
|
218 |
case A_R2_B: |
219 |
fprintf(f, "%c,$%02x", reg_name[(op >> 3) & 7], lo); |
220 |
break; |
221 |
|
222 |
case A_WORD: |
223 |
fprintf(f, "$%04x", (hi << 8) | lo); |
224 |
break; |
225 |
|
226 |
case A_BC_W: |
227 |
fprintf(f, "bc,$%04x", (hi << 8) | lo); |
228 |
break; |
229 |
|
230 |
case A_DE_W: |
231 |
fprintf(f, "de,$%04x", (hi << 8) | lo); |
232 |
break; |
233 |
|
234 |
case A_HL_W: |
235 |
fprintf(f, "hl,$%04x", (hi << 8) | lo); |
236 |
break; |
237 |
|
238 |
case A_SP_W: |
239 |
fprintf(f, "sp,$%04x", (hi << 8) | lo); |
240 |
break; |
241 |
} |
242 |
|
243 |
fputc('\n', f); |
244 |
return adr_length[mode]; |
245 |
} |