ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/mon/src/mon_z80.cpp
Revision: 1.7
Committed: 2007-01-14T14:01:09Z (17 years, 10 months ago) by cebix
Branch: MAIN
Changes since 1.6: +40 -23 lines
Log Message:
fixed Z80 disassembler bugs

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * mon_z80.cpp - Z80 disassembler
3     *
4 cebix 1.7 * cxmon (C) 1997-2007 Christian Bauer, Marc Hellwig
5 cebix 1.1 *
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 {
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 cebix 1.4 A_BIT_REG1, // bit number (bits 3..5 of opcode) followed by 8-bit register (bits 0..2 of opcode)
50 cebix 1.1 A_RST, // restart
51     A_BC_IND, // (bc)
52     A_DE_IND, // (de)
53     A_HL_IND, // (hl) or (ix) or (iy)
54 cebix 1.4 A_XY_IND, // (ix+d) or (iy+d)
55 cebix 1.1 A_SP_IND, // (sp)
56     A_DE_HL, // de,hl
57     A_AF_AF, // af,af'
58     };
59    
60     // Mnemonics
61     enum {
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 char 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 short 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    
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    
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 cebix 1.7 mon_sprintf(f, "$%04x", (adr + 1 + (int8)mon_read_byte(adr)) & 0xffff); adr++;
212 cebix 1.1 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 cebix 1.7 } else {
233 cebix 1.1 mon_sprintf(f, "(hl)");
234 cebix 1.7 }
235     } else if (mode == A_REG1) {
236 cebix 1.1 mon_sprintf(f, "%s", ix ? reg_name_ix[reg] : (iy ? reg_name_iy[reg] : reg_name[reg]));
237 cebix 1.7 } else {
238 cebix 1.1 mon_sprintf(f, "%s", reg_name[reg]);
239 cebix 1.7 }
240 cebix 1.1 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 cebix 1.7 } else {
250 cebix 1.1 mon_sprintf(f, "(hl)");
251 cebix 1.7 }
252     } else if (mode == A_REG2) {
253 cebix 1.1 mon_sprintf(f, "%s", ix ? reg_name_ix[reg] : (iy ? reg_name_iy[reg] : reg_name[reg]));
254 cebix 1.7 } else {
255 cebix 1.1 mon_sprintf(f, "%s", reg_name[reg]);
256 cebix 1.7 }
257 cebix 1.1 break;
258     }
259    
260 cebix 1.7 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 cebix 1.1 break;
268 cebix 1.7 }
269 cebix 1.1
270 cebix 1.7 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 cebix 1.1 break;
278 cebix 1.7 }
279 cebix 1.1
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 cebix 1.4 case A_BIT_REG1: { // undoc
293     int reg = op & 7;
294 cebix 1.7 if (reg == 6) {
295 cebix 1.4 mon_sprintf(f, "%d", (op >> 3) & 7);
296 cebix 1.7 } else {
297 cebix 1.4 mon_sprintf(f, "%d,%s", (op >> 3) & 7, reg_name[reg]);
298 cebix 1.7 }
299 cebix 1.4 break;
300     }
301    
302 cebix 1.1 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 cebix 1.4 case A_XY_IND: // undoc
319     mon_sprintf(f, "(%s+$%02x)", ix ? "ix" : "iy", mon_read_byte(adr)); adr++;
320     break;
321    
322 cebix 1.1 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    
336     static int print_instr(SFILE *f, char mnem, char dst_mode, char 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    
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 cebix 1.2 char mnem = M_ILLEGAL, dst_mode = A_IMPL, src_mode = A_IMPL;
370 cebix 1.1 switch (op & 0xc0) {
371     case 0x00:
372 cebix 1.4 dst_mode = A_REG1X;
373     if ((ix || iy) && ((op & 7) != 6))
374     src_mode = A_XY_IND;
375 cebix 1.1 switch ((op >> 3) & 7) {
376     case 0: mnem = M_RLC; break;
377     case 1: mnem = M_RRC; break;
378     case 2: mnem = M_RL; break;
379     case 3: mnem = M_RR; break;
380     case 4: mnem = M_SLA; break;
381     case 5: mnem = M_SRA; break;
382 cebix 1.7 case 6: mnem = M_SL1; break; // undoc
383 cebix 1.1 case 7: mnem = M_SRL; break;
384     }
385     break;
386     case 0x40:
387 cebix 1.4 mnem = M_BIT; dst_mode = A_BIT;
388     if (ix || iy)
389     src_mode = A_XY_IND;
390     else
391     src_mode = A_REG1;
392 cebix 1.1 break;
393     case 0x80:
394 cebix 1.4 mnem = M_RES;
395     if (ix || iy) {
396     dst_mode = A_BIT_REG1;
397     src_mode = A_XY_IND;
398     } else {
399     dst_mode = A_BIT;
400     src_mode = A_REG1;
401     }
402 cebix 1.1 break;
403     case 0xc0:
404 cebix 1.4 mnem = M_SET;
405     if (ix || iy) {
406     dst_mode = A_BIT_REG1;
407     src_mode = A_XY_IND;
408     } else {
409     dst_mode = A_BIT;
410     src_mode = A_REG1;
411     }
412 cebix 1.1 break;
413     }
414    
415     // Print instruction
416     print_instr(f, mnem, dst_mode, src_mode, adr, op, ix, iy);
417     return num;
418     }
419    
420     static int disass_ed(SFILE *f, uint32 adr)
421     {
422     // Fetch opcode
423     uint8 op = mon_read_byte(adr);
424    
425     // Decode mnemonic and addressing modes
426     char mnem, dst_mode = A_IMPL, src_mode = A_IMPL;
427     switch (op) {
428     case 0x40:
429     case 0x48:
430     case 0x50:
431     case 0x58:
432     case 0x60:
433     case 0x68:
434     case 0x78:
435 cebix 1.7 mon_sprintf(f, "in %s,(c)", reg_name[(op >> 3) & 7]);
436 cebix 1.1 return 1;
437     case 0x70:
438 cebix 1.7 mon_sprintf(f, "in (c)");
439 cebix 1.1 return 1;
440    
441     case 0x41:
442     case 0x49:
443     case 0x51:
444     case 0x59:
445     case 0x61:
446     case 0x69:
447     case 0x79:
448 cebix 1.7 mon_sprintf(f, "out (c),%s", reg_name[(op >> 3) & 7]);
449 cebix 1.1 return 1;
450     case 0x71: // undoc
451 cebix 1.7 mon_sprintf(f, "out (c),0");
452 cebix 1.1 return 1;
453    
454     case 0x42:
455     case 0x52:
456     case 0x62:
457     case 0x72:
458     mnem = M_SBC; dst_mode = A_HL; src_mode = A_REG3;
459     break;
460    
461     case 0x43:
462     case 0x53:
463     case 0x63:
464     case 0x73:
465     mnem = M_LD; dst_mode = A_ABS16; src_mode = A_REG3;
466     break;
467    
468     case 0x4a:
469     case 0x5a:
470     case 0x6a:
471     case 0x7a:
472     mnem = M_ADC; dst_mode = A_HL; src_mode = A_REG3;
473     break;
474    
475     case 0x4b:
476     case 0x5b:
477     case 0x6b:
478     case 0x7b:
479     mnem = M_LD; dst_mode = A_REG3; src_mode = A_ABS16;
480     break;
481    
482     case 0x44:
483     case 0x4c: // undoc
484     case 0x54: // undoc
485     case 0x5c: // undoc
486     case 0x64: // undoc
487     case 0x6c: // undoc
488     case 0x74: // undoc
489     case 0x7c: // undoc
490     mnem = M_NEG;
491     break;
492    
493     case 0x45:
494     case 0x55: // undoc
495     case 0x5d: // undoc
496     case 0x65: // undoc
497     case 0x6d: // undoc
498     case 0x75: // undoc
499     case 0x7d: // undoc
500     mnem = M_RETN;
501     break;
502     case 0x4d: mnem = M_RETI; break;
503    
504     case 0x46:
505     case 0x4e: // undoc
506     case 0x66: // undoc
507     case 0x6e: // undoc
508     mnem = M_IM0;
509     break;
510     case 0x56:
511     case 0x76: // undoc
512     mnem = M_IM1;
513     break;
514     case 0x5e:
515     case 0x7e: // undoc
516     mnem = M_IM2;
517     break;
518    
519     case 0x47:
520 cebix 1.7 mon_sprintf(f, "ld i,a");
521 cebix 1.1 return 1;
522     case 0x4f:
523 cebix 1.7 mon_sprintf(f, "ld r,a");
524 cebix 1.1 return 1;
525     case 0x57:
526 cebix 1.7 mon_sprintf(f, "ld a,i");
527 cebix 1.1 return 1;
528     case 0x5f:
529 cebix 1.7 mon_sprintf(f, "ld a,r");
530 cebix 1.1 return 1;
531    
532     case 0x67: mnem = M_RRD; break;
533     case 0x6f: mnem = M_RLD; break;
534    
535     case 0xa0: mnem = M_LDI; break;
536     case 0xa1: mnem = M_CPI; break;
537     case 0xa2: mnem = M_INI; break;
538     case 0xa3: mnem = M_OUTI; break;
539     case 0xa8: mnem = M_LDD; break;
540     case 0xa9: mnem = M_CPD; break;
541     case 0xaa: mnem = M_IND; break;
542     case 0xab: mnem = M_OUTD; break;
543     case 0xb0: mnem = M_LDIR; break;
544     case 0xb1: mnem = M_CPIR; break;
545     case 0xb2: mnem = M_INIR; break;
546     case 0xb3: mnem = M_OTIR; break;
547     case 0xb8: mnem = M_LDDR; break;
548     case 0xb9: mnem = M_CPDR; break;
549     case 0xba: mnem = M_INDR; break;
550     case 0xbb: mnem = M_OTDR; break;
551    
552     default:
553 cebix 1.4 mnem = M_NOP;
554 cebix 1.1 break;
555     }
556    
557     // Print instruction
558     return print_instr(f, mnem, dst_mode, src_mode, adr + 1, op, false, false) + 1;
559     }
560    
561     static int disass(SFILE *f, uint32 adr, bool ix, bool iy)
562     {
563     uint8 op = mon_read_byte(adr);
564     if (op == 0xcb)
565     return disass_cb(f, adr + 1, ix, iy) + 1;
566     else
567     return print_instr(f, mnemonic[op], adr_mode[op] >> 8, adr_mode[op] & 0xff, adr + 1, op, ix, iy) + 1;
568     }
569    
570     int disass_z80(FILE *f, uint32 adr)
571     {
572     int num;
573     char buf[64];
574     SFILE sfile = {buf, buf};
575    
576     switch (mon_read_byte(adr)) {
577     case 0xdd: // ix prefix
578     num = disass(&sfile, adr + 1, true, false) + 1;
579     break;
580     case 0xed:
581     num = disass_ed(&sfile, adr + 1) + 1;
582     break;
583     case 0xfd: // iy prefix
584     num = disass(&sfile, adr + 1, false, true) + 1;
585     break;
586     default:
587     num = disass(&sfile, adr, false, false);
588     break;
589     }
590    
591     for (int i=0; i<4; i++) {
592     if (num > i)
593     fprintf(f, "%02x ", mon_read_byte(adr + i));
594     else
595     fprintf(f, " ");
596     }
597    
598     fprintf(f, "\t%s\n", buf);
599     return num;
600     }