rlm@1
|
1 #include <cstdio>
|
rlm@1
|
2 #include <cstring>
|
rlm@1
|
3
|
rlm@1
|
4 #include "gbGlobals.h"
|
rlm@1
|
5
|
rlm@1
|
6 typedef struct
|
rlm@1
|
7 {
|
rlm@1
|
8 u8 mask;
|
rlm@1
|
9 u8 value;
|
rlm@1
|
10 char *mnen;
|
rlm@1
|
11 } GBOPCODE;
|
rlm@1
|
12
|
rlm@1
|
13 static char *registers[] =
|
rlm@1
|
14 { "B", "C", "D", "E", "H", "L", "(HL)", "A" };
|
rlm@1
|
15
|
rlm@1
|
16 static char *registers16[] =
|
rlm@1
|
17 { "BC", "DE", "HL", "SP", // for some operations
|
rlm@1
|
18 "BC", "DE", "HL", "AF" }; // for push/pop
|
rlm@1
|
19
|
rlm@1
|
20 static char *cond[] =
|
rlm@1
|
21 { "NZ", "Z", "NC", "C" };
|
rlm@1
|
22
|
rlm@1
|
23 static char hexDigits[16] = {
|
rlm@1
|
24 '0', '1', '2', '3', '4', '5', '6', '7',
|
rlm@1
|
25 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
rlm@1
|
26 };
|
rlm@1
|
27
|
rlm@1
|
28 static GBOPCODE opcodes[] = {
|
rlm@1
|
29 { 0xff, 0x00, "NOP" },
|
rlm@1
|
30 { 0xcf, 0x01, "LD %R4,%W" },
|
rlm@1
|
31 { 0xff, 0x02, "LD (BC),A" },
|
rlm@1
|
32 { 0xcf, 0x03, "INC %R4" },
|
rlm@1
|
33 { 0xc7, 0x04, "INC %r3" },
|
rlm@1
|
34 { 0xc7, 0x05, "DEC %r3" },
|
rlm@1
|
35 { 0xc7, 0x06, "LD %r3,%B" },
|
rlm@1
|
36 { 0xff, 0x07, "RLCA" },
|
rlm@1
|
37 { 0xff, 0x08, "LD (%W),SP" },
|
rlm@1
|
38 { 0xcf, 0x09, "ADD HL,%R4" },
|
rlm@1
|
39 { 0xff, 0x0a, "LD A,(BC)" },
|
rlm@1
|
40 { 0xcf, 0x0b, "DEC %R4" },
|
rlm@1
|
41 { 0xff, 0x0f, "RRCA" },
|
rlm@1
|
42 { 0xff, 0x10, "STOP" },
|
rlm@1
|
43 { 0xff, 0x12, "LD (DE),A" },
|
rlm@1
|
44 { 0xff, 0x17, "RLA" },
|
rlm@1
|
45 { 0xff, 0x18, "JR %d" },
|
rlm@1
|
46 { 0xff, 0x1a, "LD A,(DE)" },
|
rlm@1
|
47 { 0xff, 0x1f, "RRA" },
|
rlm@1
|
48 { 0xe7, 0x20, "JR %c3,%d" },
|
rlm@1
|
49 { 0xff, 0x22, "LDI (HL),A" },
|
rlm@1
|
50 { 0xff, 0x27, "DAA" },
|
rlm@1
|
51 { 0xff, 0x2a, "LDI A,(HL)" },
|
rlm@1
|
52 { 0xff, 0x2f, "CPL" },
|
rlm@1
|
53 { 0xff, 0x32, "LDD (HL),A" },
|
rlm@1
|
54 { 0xff, 0x37, "SCF" },
|
rlm@1
|
55 { 0xff, 0x3a, "LDD A,(HL)" },
|
rlm@1
|
56 { 0xff, 0x3f, "CCF" },
|
rlm@1
|
57 { 0xff, 0x76, "HALT" },
|
rlm@1
|
58 { 0xc0, 0x40, "LD %r3,%r0" },
|
rlm@1
|
59 { 0xf8, 0x80, "ADD A,%r0" },
|
rlm@1
|
60 { 0xf8, 0x88, "ADC A,%r0" },
|
rlm@1
|
61 { 0xf8, 0x90, "SUB %r0" },
|
rlm@1
|
62 { 0xf8, 0x98, "SBC A,%r0" },
|
rlm@1
|
63 { 0xf8, 0xa0, "AND %r0" },
|
rlm@1
|
64 { 0xf8, 0xa8, "XOR %r0" },
|
rlm@1
|
65 { 0xf8, 0xb0, "OR %r0" },
|
rlm@1
|
66 { 0xf8, 0xb8, "CP %r0" },
|
rlm@1
|
67 { 0xe7, 0xc0, "RET %c3" },
|
rlm@1
|
68 { 0xcf, 0xc1, "POP %t4" },
|
rlm@1
|
69 { 0xe7, 0xc2, "JP %c3,%W" },
|
rlm@1
|
70 { 0xff, 0xc3, "JP %W" },
|
rlm@1
|
71 { 0xe7, 0xc4, "CALL %c3,%W" },
|
rlm@1
|
72 { 0xcf, 0xc5, "PUSH %t4" },
|
rlm@1
|
73 { 0xff, 0xc6, "ADD A,%B" },
|
rlm@1
|
74 { 0xc7, 0xc7, "RST %P" },
|
rlm@1
|
75 { 0xff, 0xc9, "RET" },
|
rlm@1
|
76 { 0xff, 0xcd, "CALL %W" },
|
rlm@1
|
77 { 0xff, 0xce, "ADC %B" },
|
rlm@1
|
78 { 0xff, 0xd6, "SUB %B" },
|
rlm@1
|
79 { 0xff, 0xd9, "RETI" },
|
rlm@1
|
80 { 0xff, 0xde, "SBC %B" },
|
rlm@1
|
81 { 0xff, 0xe0, "LD (FF%B),A" },
|
rlm@1
|
82 { 0xff, 0xe2, "LD (FF00h+C),A" },
|
rlm@1
|
83 { 0xff, 0xe6, "AND %B" },
|
rlm@1
|
84 { 0xff, 0xe8, "ADD SP,%D" },
|
rlm@1
|
85 { 0xff, 0xe9, "LD PC,HL" },
|
rlm@1
|
86 { 0xff, 0xea, "LD (%W),A" },
|
rlm@1
|
87 { 0xff, 0xee, "XOR %B" },
|
rlm@1
|
88 { 0xff, 0xf0, "LD A,(FF%B)" },
|
rlm@1
|
89 { 0xff, 0xf2, "LD A,(FF00h+C)" },
|
rlm@1
|
90 { 0xff, 0xf3, "DI" },
|
rlm@1
|
91 { 0xff, 0xf6, "OR %B" },
|
rlm@1
|
92 { 0xff, 0xf8, "LD HL,SP%D" },
|
rlm@1
|
93 { 0xff, 0xf9, "LD SP,HL" },
|
rlm@1
|
94 { 0xff, 0xfa, "LD A,(%W)" },
|
rlm@1
|
95 { 0xff, 0xfb, "EI" },
|
rlm@1
|
96 { 0xff, 0xfe, "CP %B" },
|
rlm@1
|
97 { 0x00, 0x00, "DB %B" }
|
rlm@1
|
98 };
|
rlm@1
|
99
|
rlm@1
|
100 static GBOPCODE cbOpcodes[] = {
|
rlm@1
|
101 { 0xf8, 0x00, "RLC %r0" },
|
rlm@1
|
102 { 0xf8, 0x08, "RRC %r0" },
|
rlm@1
|
103 { 0xf8, 0x10, "RL %r0" },
|
rlm@1
|
104 { 0xf8, 0x18, "RR %r0" },
|
rlm@1
|
105 { 0xf8, 0x20, "SLA %r0" },
|
rlm@1
|
106 { 0xf8, 0x28, "SRA %r0" },
|
rlm@1
|
107 { 0xf8, 0x30, "SWAP %r0" },
|
rlm@1
|
108 { 0xf8, 0x38, "SRL %r0" },
|
rlm@1
|
109 { 0xc0, 0x40, "BIT %b,%r0" },
|
rlm@1
|
110 { 0xc0, 0x80, "RES %b,%r0" },
|
rlm@1
|
111 { 0xc0, 0xc0, "SET %b,%r0" },
|
rlm@1
|
112 { 0x00, 0x00, "DB CBh,%B" }
|
rlm@1
|
113 };
|
rlm@1
|
114
|
rlm@1
|
115 static char *addHex(char *p, u8 value)
|
rlm@1
|
116 {
|
rlm@1
|
117 *p++ = hexDigits[value >> 4];
|
rlm@1
|
118 *p++ = hexDigits[value & 15];
|
rlm@1
|
119 return p;
|
rlm@1
|
120 }
|
rlm@1
|
121
|
rlm@1
|
122 static char *addHex16(char *p, u16 value)
|
rlm@1
|
123 {
|
rlm@1
|
124 p = addHex(p, value>>8);
|
rlm@1
|
125 return addHex(p, value & 255);
|
rlm@1
|
126 }
|
rlm@1
|
127
|
rlm@1
|
128 static char *addStr(char *p, char *s)
|
rlm@1
|
129 {
|
rlm@1
|
130 while (*s)
|
rlm@1
|
131 {
|
rlm@1
|
132 *p++ = *s++;
|
rlm@1
|
133 }
|
rlm@1
|
134 return p;
|
rlm@1
|
135 }
|
rlm@1
|
136
|
rlm@1
|
137 int gbDis(char *buffer, u16 address)
|
rlm@1
|
138 {
|
rlm@1
|
139 char *p = buffer;
|
rlm@1
|
140 int instr = 1;
|
rlm@1
|
141 u16 addr = address;
|
rlm@1
|
142 sprintf(p, "%04x ", address);
|
rlm@1
|
143 p += 12;
|
rlm@1
|
144
|
rlm@1
|
145 u8 opcode = gbReadMemoryQuick(address);
|
rlm@1
|
146 address++;
|
rlm@1
|
147 char * mnen;
|
rlm@1
|
148 GBOPCODE *op;
|
rlm@1
|
149 if (opcode == 0xcb)
|
rlm@1
|
150 {
|
rlm@1
|
151 opcode = gbReadMemoryQuick(address);
|
rlm@1
|
152 address++;
|
rlm@1
|
153 instr++;
|
rlm@1
|
154 op = cbOpcodes;
|
rlm@1
|
155 }
|
rlm@1
|
156 else
|
rlm@1
|
157 {
|
rlm@1
|
158 op = opcodes;
|
rlm@1
|
159 }
|
rlm@1
|
160 while (op->value != (opcode & op->mask))
|
rlm@1
|
161 op++;
|
rlm@1
|
162 mnen = op->mnen;
|
rlm@1
|
163
|
rlm@1
|
164 u8 b0, b1;
|
rlm@1
|
165 s8 disp;
|
rlm@1
|
166 int shift;
|
rlm@1
|
167
|
rlm@1
|
168 while (*mnen)
|
rlm@1
|
169 {
|
rlm@1
|
170 if (*mnen == '%')
|
rlm@1
|
171 {
|
rlm@1
|
172 mnen++;
|
rlm@1
|
173 switch (*mnen++)
|
rlm@1
|
174 {
|
rlm@1
|
175 case 'W':
|
rlm@1
|
176 b0 = gbReadMemoryQuick(address);
|
rlm@1
|
177 address++;
|
rlm@1
|
178 b1 = gbReadMemoryQuick(address);
|
rlm@1
|
179 address++;
|
rlm@1
|
180 p = addHex16(p, b0|b1<<8);
|
rlm@1
|
181 instr += 2;
|
rlm@1
|
182 *p++ = 'h';
|
rlm@1
|
183 break;
|
rlm@1
|
184 case 'B':
|
rlm@1
|
185 p = addHex(p, gbReadMemoryQuick(address));
|
rlm@1
|
186 *p++ = 'h';
|
rlm@1
|
187 address++;
|
rlm@1
|
188 instr++;
|
rlm@1
|
189 break;
|
rlm@1
|
190 case 'D':
|
rlm@1
|
191 disp = gbReadMemoryQuick(address);
|
rlm@1
|
192 if (disp >= 0)
|
rlm@1
|
193 *p++ = '+';
|
rlm@1
|
194 p += sprintf(p, "%d", disp);
|
rlm@1
|
195 instr++;
|
rlm@1
|
196 break;
|
rlm@1
|
197 case 'd':
|
rlm@1
|
198 disp = gbReadMemoryQuick(address);
|
rlm@1
|
199 address++;
|
rlm@1
|
200 p = addHex16(p, address+disp);
|
rlm@1
|
201 *p++ = 'h';
|
rlm@1
|
202 instr++;
|
rlm@1
|
203 break;
|
rlm@1
|
204 case 'b':
|
rlm@1
|
205 // kind of a hack, but it works :-)
|
rlm@1
|
206 *p++ = hexDigits[(opcode >> 3) & 7];
|
rlm@1
|
207 break;
|
rlm@1
|
208 case 'r':
|
rlm@1
|
209 shift = *mnen++ - '0';
|
rlm@1
|
210 p = addStr(p, registers[(opcode >> shift) & 7]);
|
rlm@1
|
211 break;
|
rlm@1
|
212 case 'R':
|
rlm@1
|
213 shift = *mnen++ - '0';
|
rlm@1
|
214 p = addStr(p, registers16[(opcode >> shift) & 3]);
|
rlm@1
|
215 break;
|
rlm@1
|
216 case 't':
|
rlm@1
|
217 shift = *mnen++ - '0';
|
rlm@1
|
218 p = addStr(p, registers16[4+((opcode >> shift) & 3)]);
|
rlm@1
|
219 break;
|
rlm@1
|
220 case 'P':
|
rlm@1
|
221 p = addHex(p, ((opcode >> 3) & 7) * 8);
|
rlm@1
|
222 break;
|
rlm@1
|
223 case 'c':
|
rlm@1
|
224 shift = *mnen++ - '0';
|
rlm@1
|
225 p = addStr(p, cond[(opcode >> shift) & 3]);
|
rlm@1
|
226 break;
|
rlm@1
|
227 }
|
rlm@1
|
228 }
|
rlm@1
|
229 else
|
rlm@1
|
230 *p++ = *mnen++;
|
rlm@1
|
231 }
|
rlm@1
|
232 for (int i = 0; i < instr; i++)
|
rlm@1
|
233 {
|
rlm@1
|
234 u16 a = addr + i;
|
rlm@1
|
235 addHex(buffer+5+i*2, gbReadMemoryQuick(a));
|
rlm@1
|
236 }
|
rlm@1
|
237 *p = 0;
|
rlm@1
|
238 return instr;
|
rlm@1
|
239 }
|