1 /*
2  *  mon_z80.cpp - Z80 disassembler
3  *
4  *  cxmon (C) 1997-2007 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 <stdarg.h>
24 
25 #include "mon.h"
26 #include "mon_disass.h"
27 
28 
29 // Addressing modes
30 enum AddrMode {
31 	A_IMPL,
32 	A_IMM8,		// xx
33 	A_IMM16,	// xxxx
34 	A_ABS8,		// (xx)
35 	A_ABS16,	// (xxxx)
36 	A_REL,		// relative
37 	A_A,		// a
38 	A_HL,		// hl or ix or iy
39 	A_SP,		// sp
40 	A_REG1,		// 8-bit register (bits 0..2 of opcode) or (hl)/(ix+d)/(iy+d)
41 	A_REG1X,	// 8-bit register (bits 0..2 of opcode) or (hl)/(ix+d)/(iy+d), don't substitute h or l on prefixes
42 	A_REG2,		// 8-bit register (bits 3..5 of opcode) or (hl)/(ix+d)/(iy+d)
43 	A_REG2X,	// 8-bit register (bits 3..5 of opcode) or (hl)/(ix+d)/(iy+d), don't substitute h or l on prefixes
44 	A_REG3,		// 16-bit register (bits 4..5 of opcode) bc/de/hl/sp
45 	A_REG4,		// 16-bit register (bits 4..5 of opcode) bc/de/hl/af
46 	A_COND,		// condition code (bits 3..5 of opcode)
47 	A_COND2,	// condition code (bits 3..4 of opcode)
48 	A_BIT,		// bit number (bits 3..5 of opcode)
49 	A_BIT_REG1,	// bit number (bits 3..5 of opcode) followed by 8-bit register (bits 0..2 of opcode)
50 	A_RST,		// restart
51 	A_BC_IND,	// (bc)
52 	A_DE_IND,	// (de)
53 	A_HL_IND,	// (hl) or (ix) or (iy)
54 	A_XY_IND,	// (ix+d) or (iy+d)
55 	A_SP_IND,	// (sp)
56 	A_DE_HL,	// de,hl
57 	A_AF_AF,	// af,af'
58 };
59 
60 // Mnemonics
61 enum Mnemonic {
62 	M_ADC, M_ADD, M_AND, M_BIT, M_CALL, M_CCF, M_CP, M_CPD, M_CPDR, M_CPI,
63 	M_CPIR, M_CPL, M_DAA, M_DEC, M_DI, M_DJNZ, M_EI, M_EX, M_EXX, M_HALT,
64 	M_IM0, M_IM1, M_IM2, M_IN, M_INC, M_IND, M_INDR, M_INI, M_INIR, M_JP,
65 	M_JR, M_LD, M_LDD, M_LDDR, M_LDI, M_LDIR, M_NEG, M_NOP, M_OR, M_OTDR,
66 	M_OTIR, M_OUT, M_OUTD, M_OUTI, M_POP, M_PUSH, M_RES, M_RET, M_RETI,
67 	M_RETN, M_RL, M_RLA, M_RLC, M_RLCA, M_RLD, M_RR, M_RRA, M_RRC, M_RRCA,
68 	M_RRD, M_RST, M_SBC, M_SCF, M_SET, M_SL1, M_SLA, M_SRA, M_SRL, M_SUB,
69 	M_XOR,
70 	M_ILLEGAL,
71 
72 	M_MAXIMUM
73 };
74 
75 // Chars for each mnemonic
76 static const char mnem_1[] = "aaabccccccccddddeeehiiiiiiiiijjlllllnnoooooopprrrrrrrrrrrrrrrssssssssx?";
77 static const char mnem_2[] = "ddniacppppppaeijixxammmnnnnnnprdddddeorttuuuoueeeelllllrrrrrsbcellrruo ";
78 static const char mnem_3[] = "cddtlf ddiilac n  xl    cddii   ddiigp ditttpssttt accd accdtcft1aalbr ";
79 static const char mnem_4[] = "    l   r r    z   t012   r r    r r   rr di h  in   a    a            ";
80 
81 // Mnemonic for each opcode
82 static const Mnemonic mnemonic[256] = {
83 	M_NOP , M_LD , M_LD , M_INC    , M_INC , M_DEC    , M_LD  , M_RLCA,	// 00
84 	M_EX  , M_ADD, M_LD , M_DEC    , M_INC , M_DEC    , M_LD  , M_RRCA,
85 	M_DJNZ, M_LD , M_LD , M_INC    , M_INC , M_DEC    , M_LD  , M_RLA ,	// 10
86 	M_JR  , M_ADD, M_LD , M_DEC    , M_INC , M_DEC    , M_LD  , M_RRA ,
87 	M_JR  , M_LD , M_LD , M_INC    , M_INC , M_DEC    , M_LD  , M_DAA ,	// 20
88 	M_JR  , M_ADD, M_LD , M_DEC    , M_INC , M_DEC    , M_LD  , M_CPL ,
89 	M_JR  , M_LD , M_LD , M_INC    , M_INC , M_DEC    , M_LD  , M_SCF ,	// 30
90 	M_JR  , M_ADD, M_LD , M_DEC    , M_INC , M_DEC    , M_LD  , M_CCF ,
91 	M_LD  , M_LD , M_LD , M_LD     , M_LD  , M_LD     , M_LD  , M_LD  ,	// 40
92 	M_LD  , M_LD , M_LD , M_LD     , M_LD  , M_LD     , M_LD  , M_LD  ,
93 	M_LD  , M_LD , M_LD , M_LD     , M_LD  , M_LD     , M_LD  , M_LD  ,	// 50
94 	M_LD  , M_LD , M_LD , M_LD     , M_LD  , M_LD     , M_LD  , M_LD  ,
95 	M_LD  , M_LD , M_LD , M_LD     , M_LD  , M_LD     , M_LD  , M_LD  ,	// 60
96 	M_LD  , M_LD , M_LD , M_LD     , M_LD  , M_LD     , M_LD  , M_LD  ,
97 	M_LD  , M_LD , M_LD , M_LD     , M_LD  , M_LD     , M_HALT, M_LD  ,	// 70
98 	M_LD  , M_LD , M_LD , M_LD     , M_LD  , M_LD     , M_LD  , M_LD  ,
99 	M_ADD , M_ADD, M_ADD, M_ADD    , M_ADD , M_ADD    , M_ADD , M_ADD ,	// 80
100 	M_ADC , M_ADC, M_ADC, M_ADC    , M_ADC , M_ADC    , M_ADC , M_ADC ,
101 	M_SUB , M_SUB, M_SUB, M_SUB    , M_SUB , M_SUB    , M_SUB , M_SUB ,	// 90
102 	M_SBC , M_SBC, M_SBC, M_SBC    , M_SBC , M_SBC    , M_SBC , M_SBC ,
103 	M_AND , M_AND, M_AND, M_AND    , M_AND , M_AND    , M_AND , M_AND ,	// a0
104 	M_XOR , M_XOR, M_XOR, M_XOR    , M_XOR , M_XOR    , M_XOR , M_XOR ,
105 	M_OR  , M_OR , M_OR , M_OR     , M_OR  , M_OR     , M_OR  , M_OR  ,	// b0
106 	M_CP  , M_CP , M_CP , M_CP     , M_CP  , M_CP     , M_CP  , M_CP  ,
107 	M_RET , M_POP, M_JP , M_JP     , M_CALL, M_PUSH   , M_ADD , M_RST ,	// c0
108 	M_RET , M_RET, M_JP , M_ILLEGAL, M_CALL, M_CALL   , M_ADC , M_RST ,
109 	M_RET , M_POP, M_JP , M_OUT    , M_CALL, M_PUSH   , M_SUB , M_RST ,	// d0
110 	M_RET , M_EXX, M_JP , M_IN     , M_CALL, M_ILLEGAL, M_SBC , M_RST ,
111 	M_RET , M_POP, M_JP , M_EX     , M_CALL, M_PUSH   , M_AND , M_RST ,	// e0
112 	M_RET , M_JP , M_JP , M_EX     , M_CALL, M_ILLEGAL, M_XOR , M_RST ,
113 	M_RET , M_POP, M_JP , M_DI     , M_CALL, M_PUSH   , M_OR  , M_RST ,	// f0
114 	M_RET , M_LD , M_JP , M_EI     , M_CALL, M_ILLEGAL, M_CP  , M_RST
115 };
116 
117 // Source/destination addressing modes for each opcode
118 #define A(d,s) (((A_ ## d) << 8) | (A_ ## s))
119 
120 static const int adr_mode[256] = {
121 	A(IMPL,IMPL)  , A(REG3,IMM16) , A(BC_IND,A)  , A(REG3,IMPL) , A(REG2,IMPL) , A(REG2,IMPL) , A(REG2,IMM8) , A(IMPL,IMPL) ,	// 00
122 	A(AF_AF,IMPL) , A(HL,REG3)    , A(A,BC_IND)  , A(REG3,IMPL) , A(REG2,IMPL) , A(REG2,IMPL) , A(REG2,IMM8) , A(IMPL,IMPL) ,
123 	A(REL,IMPL)   , A(REG3,IMM16) , A(DE_IND,A)  , A(REG3,IMPL) , A(REG2,IMPL) , A(REG2,IMPL) , A(REG2,IMM8) , A(IMPL,IMPL) ,	// 10
124 	A(REL,IMPL)   , A(HL,REG3)    , A(A,DE_IND)  , A(REG3,IMPL) , A(REG2,IMPL) , A(REG2,IMPL) , A(REG2,IMM8) , A(IMPL,IMPL) ,
125 	A(COND2,REL)  , A(REG3,IMM16) , A(ABS16,HL)  , A(REG3,IMPL) , A(REG2,IMPL) , A(REG2,IMPL) , A(REG2,IMM8) , A(IMPL,IMPL) ,	// 20
126 	A(COND2,REL)  , A(HL,REG3)    , A(HL,ABS16)  , A(REG3,IMPL) , A(REG2,IMPL) , A(REG2,IMPL) , A(REG2,IMM8) , A(IMPL,IMPL) ,
127 	A(COND2,REL)  , A(REG3,IMM16) , A(ABS16,A)   , A(REG3,IMPL) , A(REG2,IMPL) , A(REG2,IMPL) , A(REG2,IMM8) , A(IMPL,IMPL) ,	// 30
128 	A(COND2,REL)  , A(HL,REG3)    , A(A,ABS16)   , A(REG3,IMPL) , A(REG2,IMPL) , A(REG2,IMPL) , A(REG2,IMM8) , A(IMPL,IMPL) ,
129 	A(REG2,REG1)  , A(REG2,REG1)  , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2X,REG1), A(REG2,REG1) ,	// 40
130 	A(REG2,REG1)  , A(REG2,REG1)  , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2X,REG1), A(REG2,REG1) ,
131 	A(REG2,REG1)  , A(REG2,REG1)  , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2X,REG1), A(REG2,REG1) ,	// 50
132 	A(REG2,REG1)  , A(REG2,REG1)  , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2X,REG1), A(REG2,REG1) ,
133 	A(REG2,REG1)  , A(REG2,REG1)  , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2X,REG1), A(REG2,REG1) ,	// 60
134 	A(REG2,REG1)  , A(REG2,REG1)  , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2X,REG1), A(REG2,REG1) ,
135 	A(REG2,REG1X) , A(REG2,REG1X) , A(REG2,REG1X), A(REG2,REG1X), A(REG2,REG1X), A(REG2,REG1X), A(IMPL,IMPL) , A(REG2,REG1X),	// 70
136 	A(REG2,REG1)  , A(REG2,REG1)  , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2,REG1) , A(REG2X,REG1), A(REG2,REG1) ,
137 	A(A,REG1)     , A(A,REG1)     , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    ,	// 80
138 	A(A,REG1)     , A(A,REG1)     , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    ,
139 	A(REG1,IMPL)  , A(REG1,IMPL)  , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) ,	// 90
140 	A(A,REG1)     , A(A,REG1)     , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    , A(A,REG1)    ,
141 	A(REG1,IMPL)  , A(REG1,IMPL)  , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) ,	// a0
142 	A(REG1,IMPL)  , A(REG1,IMPL)  , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) ,
143 	A(REG1,IMPL)  , A(REG1,IMPL)  , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) ,	// b0
144 	A(REG1,IMPL)  , A(REG1,IMPL)  , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) , A(REG1,IMPL) ,
145 	A(COND,IMPL)  , A(REG4,IMPL)  , A(COND,IMM16), A(IMM16,IMPL), A(COND,IMM16), A(REG4,IMPL) , A(A,IMM8)    , A(RST,IMPL)  ,	// c0
146 	A(COND,IMPL)  , A(IMPL,IMPL)  , A(COND,IMM16), A(IMPL,IMPL) , A(COND,IMM16), A(IMM16,IMPL), A(A,IMM8)    , A(RST,IMPL)  ,
147 	A(COND,IMPL)  , A(REG4,IMPL)  , A(COND,IMM16), A(ABS8,A)    , A(COND,IMM16), A(REG4,IMPL) , A(IMM8,IMPL) , A(RST,IMPL)  ,	// d0
148 	A(COND,IMPL)  , A(IMPL,IMPL)  , A(COND,IMM16), A(A,ABS8)    , A(COND,IMM16), A(IMPL,IMPL) , A(A,IMM8)    , A(RST,IMPL)  ,
149 	A(COND,IMPL)  , A(REG4,IMPL)  , A(COND,IMM16), A(SP_IND,HL) , A(COND,IMM16), A(REG4,IMPL) , A(IMM8,IMPL) , A(RST,IMPL)  ,	// e0
150 	A(COND,IMPL)  , A(HL_IND,IMPL), A(COND,IMM16), A(DE_HL,IMPL), A(COND,IMM16), A(IMPL,IMPL) , A(IMM8,IMPL) , A(RST,IMPL)  ,
151 	A(COND,IMPL)  , A(REG4,IMPL)  , A(COND,IMM16), A(IMPL,IMPL) , A(COND,IMM16), A(REG4,IMPL) , A(IMM8,IMPL) , A(RST,IMPL)  ,	// f0
152 	A(COND,IMPL)  , A(SP,HL)      , A(COND,IMM16), A(IMPL,IMPL) , A(COND,IMM16), A(IMPL,IMPL) , A(IMM8,IMPL) , A(RST,IMPL)
153 };
154 
155 
156 /*
157  *  sprintf into a "stream"
158  */
159 
160 struct SFILE {
161 	char *buffer;
162 	char *current;
163 };
164 
mon_sprintf(SFILE * f,const char * format,...)165 static int mon_sprintf(SFILE *f, const char *format, ...)
166 {
167 	int n;
168 	va_list args;
169 	va_start(args, format);
170 	vsprintf(f->current, format, args);
171 	f->current += n = strlen(f->current);
172 	va_end(args);
173 	return n;
174 }
175 
176 
177 /*
178  *  Disassemble one instruction, return number of bytes
179  */
180 
181 static const char *reg_name[] = {"b", "c", "d", "e", "h", "l", "*", "a"};
182 static const char *reg_name_ix[] = {"b", "c", "d", "e", "hx", "lx", "*", "a"};	// undoc
183 static const char *reg_name_iy[] = {"b", "c", "d", "e", "hy", "ly", "*", "a"};	// undoc
184 static const char *reg_name_16[] = {"bc", "de", "hl", "sp"};
185 static const char *reg_name_16_2[] = {"bc", "de", "hl", "af"};
186 static const char *cond_name[] = {"nz", "z", "nc", "c", "po", "pe", "p", "m"};
187 
operand(SFILE * f,char mode,uint32 & adr,uint8 op,bool ix,bool iy)188 static void operand(SFILE *f, char mode, uint32 &adr, uint8 op, bool ix, bool iy)
189 {
190 	switch (mode) {
191 		case A_IMPL:
192 			break;
193 
194 		case A_IMM8:
195 			mon_sprintf(f, "$%02x", mon_read_byte(adr)); adr++;
196 			break;
197 
198 		case A_IMM16:
199 			mon_sprintf(f, "$%04x", (mon_read_byte(adr + 1) << 8) | mon_read_byte(adr)); adr += 2;
200 			break;
201 
202 		case A_ABS8:
203 			mon_sprintf(f, "($%02x)", mon_read_byte(adr)); adr++;
204 			break;
205 
206 		case A_ABS16:
207 			mon_sprintf(f, "($%04x)", (mon_read_byte(adr + 1) << 8) | mon_read_byte(adr)); adr += 2;
208 			break;
209 
210 		case A_REL:
211 			mon_sprintf(f, "$%04x", (adr + 1 + (int8)mon_read_byte(adr)) & 0xffff); adr++;
212 			break;
213 
214 		case A_A:
215 			mon_sprintf(f, "a");
216 			break;
217 
218 		case A_HL:
219 			mon_sprintf(f, ix ? "ix" : (iy ? "iy" : "hl"));
220 			break;
221 
222 		case A_SP:
223 			mon_sprintf(f, "sp");
224 			break;
225 
226 		case A_REG1:
227 		case A_REG1X: {
228 			int reg = op & 7;
229 			if (reg == 6) {
230 				if (ix || iy) {
231 					mon_sprintf(f, "(%s+$%02x)", ix ? "ix" : "iy", mon_read_byte(adr)); adr++;
232 				} else {
233 					mon_sprintf(f, "(hl)");
234 				}
235 			} else if (mode == A_REG1) {
236 				mon_sprintf(f, "%s", ix ? reg_name_ix[reg] : (iy ? reg_name_iy[reg] : reg_name[reg]));
237 			} else {
238 				mon_sprintf(f, "%s", reg_name[reg]);
239 			}
240 			break;
241 		}
242 
243 		case A_REG2:
244 		case A_REG2X: {
245 			int reg = (op >> 3) & 7;
246 			if (reg == 6) {
247 				if (ix || iy) {
248 					mon_sprintf(f, "(%s+$%02x)", ix ? "ix" : "iy", mon_read_byte(adr)); adr++;
249 				} else {
250 					mon_sprintf(f, "(hl)");
251 				}
252 			} else if (mode == A_REG2) {
253 				mon_sprintf(f, "%s", ix ? reg_name_ix[reg] : (iy ? reg_name_iy[reg] : reg_name[reg]));
254 			} else {
255 				mon_sprintf(f, "%s", reg_name[reg]);
256 			}
257 			break;
258 		}
259 
260 		case A_REG3: {
261 			int reg = (op >> 4) & 3;
262 			if (reg == 2 && (ix || iy)) {
263 				mon_sprintf(f, ix ? "ix" : "iy");
264 			} else {
265 				mon_sprintf(f, reg_name_16[reg]);
266 			}
267 			break;
268 		}
269 
270 		case A_REG4: {
271 			int reg = (op >> 4) & 3;
272 			if (reg == 2 && (ix || iy)) {
273 				mon_sprintf(f, ix ? "ix" : "iy");
274 			} else {
275 				mon_sprintf(f, reg_name_16_2[reg]);
276 			}
277 			break;
278 		}
279 
280 		case A_COND:
281 			mon_sprintf(f, cond_name[(op >> 3) & 7]);
282 			break;
283 
284 		case A_COND2:
285 			mon_sprintf(f, cond_name[(op >> 3) & 3]);
286 			break;
287 
288 		case A_BIT:
289 			mon_sprintf(f, "%d", (op >> 3) & 7);
290 			break;
291 
292 		case A_BIT_REG1: { // undoc
293 			int reg = op & 7;
294 			if (reg == 6) {
295 				mon_sprintf(f, "%d", (op >> 3) & 7);
296 			} else {
297 				mon_sprintf(f, "%d,%s", (op >> 3) & 7, reg_name[reg]);
298 			}
299 			break;
300 		}
301 
302 		case A_RST:
303 			mon_sprintf(f, "$%02x", op & 0x38);
304 			break;
305 
306 		case A_BC_IND:
307 			mon_sprintf(f, "(bc)");
308 			break;
309 
310 		case A_DE_IND:
311 			mon_sprintf(f, "(de)");
312 			break;
313 
314 		case A_HL_IND:
315 			mon_sprintf(f, ix ? "(ix)" : (iy ? "(iy)" : "(hl)"));
316 			break;
317 
318 		case A_XY_IND: // undoc
319 			mon_sprintf(f, "(%s+$%02x)", ix ? "ix" : "iy", mon_read_byte(adr)); adr++;
320 			break;
321 
322 		case A_SP_IND:
323 			mon_sprintf(f, "(sp)");
324 			break;
325 
326 		case A_DE_HL:
327 			mon_sprintf(f, "de,hl");
328 			break;
329 
330 		case A_AF_AF:
331 			mon_sprintf(f, "af,af'");
332 			break;
333 	}
334 }
335 
print_instr(SFILE * f,Mnemonic mnem,AddrMode dst_mode,AddrMode src_mode,uint32 adr,uint8 op,bool ix,bool iy)336 static int print_instr(SFILE *f, Mnemonic mnem, AddrMode dst_mode, AddrMode src_mode, uint32 adr, uint8 op, bool ix, bool iy)
337 {
338 	uint32 orig_adr = adr;
339 
340 	// Print mnemonic
341 	mon_sprintf(f, "%c%c%c%c ", mnem_1[mnem], mnem_2[mnem], mnem_3[mnem], mnem_4[mnem]);
342 
343 	// Print destination operand
344 	operand(f, dst_mode, adr, op, ix, iy);
345 
346 	// Print source operand
347 	if (src_mode != A_IMPL)
348 		mon_sprintf(f, ",");
349 	operand(f, src_mode, adr, op, ix, iy);
350 
351 	return adr - orig_adr;
352 }
353 
disass_cb(SFILE * f,uint32 adr,bool ix,bool iy)354 static int disass_cb(SFILE *f, uint32 adr, bool ix, bool iy)
355 {
356 	int num;
357 
358 	// Fetch opcode
359 	uint8 op;
360 	if (ix || iy) {
361 		op = mon_read_byte(adr + 1);
362 		num = 2;
363 	} else {
364 		op = mon_read_byte(adr);
365 		num = 1;
366 	}
367 
368 	// Decode mnemonic and addressing modes
369 	Mnemonic mnem = M_ILLEGAL;
370 	AddrMode dst_mode = A_IMPL, src_mode = A_IMPL;
371 
372 	switch (op & 0xc0) {
373 		case 0x00:
374 			dst_mode = A_REG1X;
375 			if ((ix || iy) && ((op & 7) != 6))
376 				src_mode = A_XY_IND;
377 			switch ((op >> 3) & 7) {
378 				case 0: mnem = M_RLC; break;
379 				case 1: mnem = M_RRC; break;
380 				case 2: mnem = M_RL; break;
381 				case 3: mnem = M_RR; break;
382 				case 4: mnem = M_SLA; break;
383 				case 5: mnem = M_SRA; break;
384 				case 6: mnem = M_SL1; break; // undoc
385 				case 7: mnem = M_SRL; break;
386 			}
387 			break;
388 		case 0x40:
389 			mnem = M_BIT; dst_mode = A_BIT;
390 			if (ix || iy)
391 				src_mode = A_XY_IND;
392 			else
393 				src_mode = A_REG1;
394 			break;
395 		case 0x80:
396 			mnem = M_RES;
397 			if (ix || iy) {
398 				dst_mode = A_BIT_REG1;
399 				src_mode = A_XY_IND;
400 			} else {
401 				dst_mode = A_BIT;
402 				src_mode = A_REG1;
403 			}
404 			break;
405 		case 0xc0:
406 			mnem = M_SET;
407 			if (ix || iy) {
408 				dst_mode = A_BIT_REG1;
409 				src_mode = A_XY_IND;
410 			} else {
411 				dst_mode = A_BIT;
412 				src_mode = A_REG1;
413 			}
414 			break;
415 	}
416 
417 	// Print instruction
418 	print_instr(f, mnem, dst_mode, src_mode, adr, op, ix, iy);
419 	return num;
420 }
421 
disass_ed(SFILE * f,uint32 adr)422 static int disass_ed(SFILE *f, uint32 adr)
423 {
424 	// Fetch opcode
425 	uint8 op = mon_read_byte(adr);
426 
427 	// Decode mnemonic and addressing modes
428 	Mnemonic mnem;
429 	AddrMode dst_mode = A_IMPL, src_mode = A_IMPL;
430 
431 	switch (op) {
432 		case 0x40:
433 		case 0x48:
434 		case 0x50:
435 		case 0x58:
436 		case 0x60:
437 		case 0x68:
438 		case 0x78:
439 			mon_sprintf(f, "in   %s,(c)", reg_name[(op >> 3) & 7]);
440 			return 1;
441 		case 0x70:
442 			mon_sprintf(f, "in   (c)");
443 			return 1;
444 
445 		case 0x41:
446 		case 0x49:
447 		case 0x51:
448 		case 0x59:
449 		case 0x61:
450 		case 0x69:
451 		case 0x79:
452 			mon_sprintf(f, "out  (c),%s", reg_name[(op >> 3) & 7]);
453 			return 1;
454 		case 0x71:	// undoc
455 			mon_sprintf(f, "out  (c),0");
456 			return 1;
457 
458 		case 0x42:
459 		case 0x52:
460 		case 0x62:
461 		case 0x72:
462 			mnem = M_SBC; dst_mode = A_HL; src_mode = A_REG3;
463 			break;
464 
465 		case 0x43:
466 		case 0x53:
467 		case 0x63:
468 		case 0x73:
469 			mnem = M_LD; dst_mode = A_ABS16; src_mode = A_REG3;
470 			break;
471 
472 		case 0x4a:
473 		case 0x5a:
474 		case 0x6a:
475 		case 0x7a:
476 			mnem = M_ADC; dst_mode = A_HL; src_mode = A_REG3;
477 			break;
478 
479 		case 0x4b:
480 		case 0x5b:
481 		case 0x6b:
482 		case 0x7b:
483 			mnem = M_LD; dst_mode = A_REG3; src_mode = A_ABS16;
484 			break;
485 
486 		case 0x44:
487 		case 0x4c:	// undoc
488 		case 0x54:	// undoc
489 		case 0x5c:	// undoc
490 		case 0x64:	// undoc
491 		case 0x6c:	// undoc
492 		case 0x74:	// undoc
493 		case 0x7c:	// undoc
494 			mnem = M_NEG;
495 			break;
496 
497 		case 0x45:
498 		case 0x55:	// undoc
499 		case 0x5d:	// undoc
500 		case 0x65:	// undoc
501 		case 0x6d:	// undoc
502 		case 0x75:	// undoc
503 		case 0x7d:	// undoc
504 			mnem = M_RETN;
505 			break;
506 		case 0x4d: mnem = M_RETI; break;
507 
508 		case 0x46:
509 		case 0x4e:	// undoc
510 		case 0x66:	// undoc
511 		case 0x6e:	// undoc
512 			mnem = M_IM0;
513 			break;
514 		case 0x56:
515 		case 0x76:	// undoc
516 			mnem = M_IM1;
517 			break;
518 		case 0x5e:
519 		case 0x7e:	// undoc
520 			mnem = M_IM2;
521 			break;
522 
523 		case 0x47:
524 			mon_sprintf(f, "ld   i,a");
525 			return 1;
526 		case 0x4f:
527 			mon_sprintf(f, "ld   r,a");
528 			return 1;
529 		case 0x57:
530 			mon_sprintf(f, "ld   a,i");
531 			return 1;
532 		case 0x5f:
533 			mon_sprintf(f, "ld   a,r");
534 			return 1;
535 
536 		case 0x67: mnem = M_RRD; break;
537 		case 0x6f: mnem = M_RLD; break;
538 
539 		case 0xa0: mnem = M_LDI; break;
540 		case 0xa1: mnem = M_CPI; break;
541 		case 0xa2: mnem = M_INI; break;
542 		case 0xa3: mnem = M_OUTI; break;
543 		case 0xa8: mnem = M_LDD; break;
544 		case 0xa9: mnem = M_CPD; break;
545 		case 0xaa: mnem = M_IND; break;
546 		case 0xab: mnem = M_OUTD; break;
547 		case 0xb0: mnem = M_LDIR; break;
548 		case 0xb1: mnem = M_CPIR; break;
549 		case 0xb2: mnem = M_INIR; break;
550 		case 0xb3: mnem = M_OTIR; break;
551 		case 0xb8: mnem = M_LDDR; break;
552 		case 0xb9: mnem = M_CPDR; break;
553 		case 0xba: mnem = M_INDR; break;
554 		case 0xbb: mnem = M_OTDR; break;
555 
556 		default:
557 			mnem = M_NOP;
558 			break;
559 	}
560 
561 	// Print instruction
562 	return print_instr(f, mnem, dst_mode, src_mode, adr + 1, op, false, false) + 1;
563 }
564 
disass(SFILE * f,uint32 adr,bool ix,bool iy)565 static int disass(SFILE *f, uint32 adr, bool ix, bool iy)
566 {
567 	uint8 op = mon_read_byte(adr);
568 	if (op == 0xcb)
569 		return disass_cb(f, adr + 1, ix, iy) + 1;
570 	else
571 		return print_instr(f, mnemonic[op], AddrMode(adr_mode[op] >> 8), AddrMode(adr_mode[op] & 0xff), adr + 1, op, ix, iy) + 1;
572 }
573 
disass_z80(FILE * f,uint32 adr)574 int disass_z80(FILE *f, uint32 adr)
575 {
576 	int num;
577 	char buf[64];
578 	SFILE sfile = {buf, buf};
579 
580 	switch (mon_read_byte(adr)) {
581 		case 0xdd:	// ix prefix
582 			num = disass(&sfile, adr + 1, true, false) + 1;
583 			break;
584 		case 0xed:
585 			num = disass_ed(&sfile, adr + 1) + 1;
586 			break;
587 		case 0xfd:	// iy prefix
588 			num = disass(&sfile, adr + 1, false, true) + 1;
589 			break;
590 		default:
591 			num = disass(&sfile, adr, false, false);
592 			break;
593 	}
594 
595 	for (int i=0; i<4; i++) {
596 		if (num > i)
597 			fprintf(f, "%02x ", mon_read_byte(adr + i));
598 		else
599 			fprintf(f, "   ");
600 	}
601 
602 	fprintf(f, "\t%s\n", buf);
603 	return num;
604 }
605