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