1
2 /*
3
4 z80.c
5
6 This file emulates the Z80 Gameboy (COLOR) CPU.
7 It also contains a part of the debugger.
8
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include <string.h>
15
16 #include "globals.h"
17 #include "z80.h"
18 #include "gameboy.h"
19 #include "sgb.h"
20
21 #include "sys.h"
22 #include "debug.h"
23
24 TYPE_Z80_REG Z80_REG;
25
26 int Z80_HALTED,DBLSPEED;
27 int Z80_IE;
28 ulong Z80_CPUCLKS;
29 uchar Z80_TICKS,DUMMY_F;
30 unsigned int skipover;
31 int breakpoint,lastbreakpoint;
32 int db_trace;
33
34
35 /* Table of clock-ticks for an opcode */
36 /* (taken from original Z80) */
37
38 unsigned char Z80_CLKS[2][256]=
39 {{
40 4,12, 8, 8, 4, 4, 8, 8, 20, 8, 8, 8, 4, 4, 8, 8,
41 4,12, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 4, 4, 8, 8,
42 8,12, 8, 8, 4, 4, 8, 4, 8, 8, 8, 8, 4, 4, 8, 4,
43 8,12, 8, 8,12,12,12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
44 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
45 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
46 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
47 8, 8, 8, 8, 8, 8, 4, 8, 4, 4, 4, 4, 4, 4, 8, 4,
48 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
49 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
50 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
51 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
52 8,12,12,12,12,16, 8,16, 8, 4,12, 0,12,12, 8,16,
53 8,12,12, 0,12,16, 8,16, 8,16,12, 0,12, 0, 8,16,
54 12,12, 8, 0, 0,16, 8,16, 16, 4,16, 0, 0, 0, 8,16,
55 12,12, 8, 4, 0,16, 8,16, 12, 8,16, 4, 0, 0, 8,16 },
56 {
57 2, 6, 4, 4, 2, 2, 4, 4, 10, 4, 4, 4, 2, 2, 4, 4,
58 2, 6, 4, 4, 2, 2, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4,
59 4, 6, 4, 4, 2, 2, 4, 2, 4, 4, 4, 4, 2, 2, 4, 2,
60 4, 6, 4, 4, 6, 6, 6, 2, 4, 4, 4, 4, 2, 2, 4, 2,
61 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
62 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
63 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
64 4, 4, 4, 4, 4, 4, 2, 4, 2, 2, 2, 2, 2, 2, 4, 2,
65 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
66 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
67 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
68 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
69 4, 6, 6, 6, 6, 8, 4, 8, 4, 2, 6, 0, 6, 6, 4, 8,
70 4, 6, 6, 0, 6, 8, 4, 8, 4, 8, 6, 0, 6, 0, 4, 8,
71 6, 6, 4, 0, 0, 8, 4, 8, 8, 2, 8, 0, 0, 0, 4, 8,
72 6, 6, 4, 2, 0, 8, 4, 8, 6, 4, 8, 2, 0, 0, 4, 8
73 }};
74 int Z80CLKS_JR[2]={4,2};
75 int Z80CLKS_RET[2]={12,6};
76 int Z80CLKS_JP[2]={4,2};
77 int Z80CLKS_CALL[2]={12,6};
78 int Z80CLKS_PREFIXCB[2]={8,4};
79 int Z80CLKS_PREFIXCBINDHL[2]={8,4};
80 int Z80CLKS_RST[2]={16,8};
81
82
83 /* (OLD table from vgb)*/
84 /*
85 uchar Z80_CLKS[2][0x100]=
86 {{
87 4,12, 8, 8, 4, 4, 8, 4,20, 8, 8, 8, 4, 4, 8, 4,
88 4,12, 8, 8, 4, 4, 8, 4, 8, 8, 8, 8, 4, 4, 8, 4,
89 8,12, 8, 8, 4, 4, 8, 4, 8, 8, 8, 8, 4, 4, 8, 4,
90 8,12, 8, 8,12,12,12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
91 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
92 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
93 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
94 8, 8, 8, 8, 8, 8, 4, 8, 4, 4, 4, 4, 4, 4, 8, 4,
95 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
96 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
97 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
98 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
99 8, 8,12,12,12,16, 8,32, 8, 8,12, 0,12,12, 8,32,
100 8, 8,12, 0,12,16, 8,32, 8, 8,12, 0,12, 0, 8,32,
101 12, 8, 8, 0, 0,16, 8,32,16, 4,16, 0, 0, 0, 8,32,
102 12, 8, 8, 4, 0,16, 8,32,12, 8,16, 4, 0, 0, 8,32 },{
103 2, 6, 4, 4, 2, 2, 4, 2,10, 4, 4, 4, 2, 2, 4, 2,
104 2, 6, 4, 4, 2, 2, 4, 2, 4, 4, 4, 4, 2, 2, 4, 2,
105 4, 6, 4, 4, 2, 2, 4, 2, 4, 4, 4, 4, 2, 2, 4, 2,
106 4, 6, 4, 4, 6, 6, 6, 2, 4, 4, 4, 4, 2, 2, 4, 2,
107 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
108 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
109 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
110 4, 4, 4, 4, 4, 4, 2, 4, 2, 2, 2, 2, 2, 2, 4, 2,
111 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
112 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
113 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
114 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
115 4, 4, 6, 6, 6, 8, 4,16, 4, 4, 6, 0, 6, 6, 4,16,
116 4, 4, 6, 0, 6, 8, 4,16, 4, 4, 6, 0, 6, 0, 4,16,
117 6, 4, 4, 0, 0, 8, 4,16, 4, 2, 8, 0, 0, 0, 4,16,
118 6, 4, 4, 2, 0, 8, 4,16, 6, 4, 8, 2, 0, 0, 4,16 }
119 };
120 int Z80CLKS_JR[2]={4,2};
121 int Z80CLKS_JP[2]={4,2};
122 int Z80CLKS_CALL[2]={8,4};
123 int Z80CLKS_RET[2]={8,4};
124 int Z80CLKS_PREFIXCB[2]={8,4};
125 int Z80CLKS_PREFIXCBINDHL[2]={8,4};
126 */
127
128 char errorstr[100];
129
130 #undef Z80OPC_GAMEBOYC_SKIP /* Full INCLUDE */
131 #include "z80opc.h"
132
ExecOpcode(void)133 int ExecOpcode(void)
134 {
135 uint LASTPC;
136 uchar Opcode;
137
138 LASTPC=Z80_REG.W.PC;
139 Opcode=GetByteAt(LASTPC);
140 Z80_REG.W.PC++;
141 Z80_TICKS=0;
142
143 switch (Opcode)
144 {
145 case 0x00:break; /* NOP */
146 case 0x01: /* LD BC,NN */
147 Z80_REG.W.BC=GetWordAt(Z80_REG.W.PC);Z80_REG.W.PC+=2;
148 break;
149 case 0x02: /* LD (BC),A */
150 SetByteAt(Z80_REG.W.BC,Z80_REG.B.A);
151 break;
152 case 0x03:Z80_REG.W.BC++;break; /* INC BC */
153 case 0x04:M_INCB(Z80_REG.B.B);break; /* INC B */
154 case 0x05:M_DECB(Z80_REG.B.B);break; /* DEC B */
155 case 0x06: /* LD B,N */
156 Z80_REG.B.B=GetByteAt(Z80_REG.W.PC++);break;
157 case 0x07:M_RLCA;break; /* RLCA */
158 case 0x08: /* LD (NN),SP */
159 SetWordAt(GetWordAt(Z80_REG.W.PC),Z80_REG.W.SP);
160 Z80_REG.W.PC+=2;break;
161 case 0x09:M_ADDHL(Z80_REG.W.BC);break; /* ADD HL,BC */
162 case 0x0A: /* LD A,(BC) */
163 Z80_REG.B.A=GetByteAt(Z80_REG.W.BC);break;
164 case 0x0B:Z80_REG.W.BC--;break; /* DEC BC */
165 case 0x0C:M_INCB(Z80_REG.B.C);break; /* INC C */
166 case 0x0D:M_DECB(Z80_REG.B.C);break; /* DEC C */
167 case 0x0E:
168 Z80_REG.B.C=GetByteAt(Z80_REG.W.PC++);break; /* LD C,N */
169 case 0x0F:M_RRCA;break; /* RRCA */
170 case 0x10: /* STOP */
171 switch (KEY1&0x81) {
172 case 0x01:
173 KEY1=0x80;
174 DBLSPEED=1;
175 break;
176 case 0x81:
177 KEY1=0x00;
178 DBLSPEED=0;
179 break;
180 default:
181 Z80_IE=Z80_HALTED=1;
182 break;
183 }
184 break;
185 case 0x11: /* LD DE,NN */
186 Z80_REG.W.DE=GetWordAt(Z80_REG.W.PC);
187 Z80_REG.W.PC+=2;
188 if (Z80_REG.W.DE==0x1B58) {
189 if ((GetWordAt(Z80_REG.W.PC)+GetByteAt(Z80_REG.W.PC+2))==0) {
190 Z80_REG.W.DE=0x0001;
191 }
192 }
193 break;
194 case 0x12: /* LD (DE),A */
195 SetByteAt(Z80_REG.W.DE,Z80_REG.B.A);
196 break;
197 case 0x13:Z80_REG.W.DE++;break; /* INC DE */
198 case 0x14:M_INCB(Z80_REG.B.D);break; /* INC D */
199 case 0x15:M_DECB(Z80_REG.B.D);break; /* DEC D */
200 case 0x16: /* LD D,N */
201 Z80_REG.B.D=GetByteAt(Z80_REG.W.PC++);break;
202 case 0x17:M_RLA;break; /* RLA */
203 case 0x18:M_JR;break; /* JR N */
204 case 0x19:M_ADDHL(Z80_REG.W.DE);break; /* ADD HL,DE */
205 case 0x1A: /* LD A,(DE) */
206 Z80_REG.B.A=GetByteAt(Z80_REG.W.DE);break;
207 case 0x1B:Z80_REG.W.DE--;break; /* DEC DE */
208 case 0x1C:M_INCB(Z80_REG.B.E);break; /* INC E */
209 case 0x1D:M_DECB(Z80_REG.B.E);break; /* DEC E */
210 case 0x1E:
211 Z80_REG.B.E=GetByteAt(Z80_REG.W.PC++);break; /* LD E,N */
212 case 0x1F:M_RRA;break; /* RRA */
213 case 0x20: /* JR NZ,N */
214 if ((Z80_REG.B.F & FLAG_Z)==0) M_JR
215 else Z80_REG.W.PC++;
216 break;
217 case 0x21: /* LD HL,NN */
218 Z80_REG.W.HL=GetWordAt(Z80_REG.W.PC);Z80_REG.W.PC+=2;
219 break;
220 case 0x22: /* LDI (HL),A */
221 SetByteAt(Z80_REG.W.HL++,Z80_REG.B.A);
222 break;
223 case 0x23:Z80_REG.W.HL++;break; /* INC HL */
224 case 0x24:M_INCB(Z80_REG.B.H);break; /* INC H */
225 case 0x25:M_DECB(Z80_REG.B.H);break; /* DEC H */
226 case 0x26: /* LD H,N */
227 Z80_REG.B.H=GetByteAt(Z80_REG.W.PC++);break;
228 case 0x27:M_DAA;break; /* DAA */
229 case 0x28: /* JR Z,N */
230 if ((Z80_REG.B.F & FLAG_Z)!=0) M_JR
231 else Z80_REG.W.PC++;
232 break;
233 case 0x29:M_ADDHL(Z80_REG.W.HL);break; /* ADD HL,HL */
234 case 0x2A:Z80_REG.B.A=GetByteAt(Z80_REG.W.HL++);break; /* LDI A,(HL) */
235 case 0x2B:Z80_REG.W.HL--;break; /* DEC HL */
236 case 0x2C:M_INCB(Z80_REG.B.L);break; /* INC L */
237 case 0x2D:M_DECB(Z80_REG.B.L);break; /* DEC L */
238 case 0x2E:
239 Z80_REG.B.L=GetByteAt(Z80_REG.W.PC++);break; /* LD L,N */
240 case 0x2F: /* CPL */
241 Z80_REG.B.A^=0xFF;
242 Z80_REG.B.F=(Z80_REG.B.F & (FLAG_Z | FLAG_C))
243 |FLAG_N|FLAG_H;
244 break;
245 case 0x30: /* JR NC,N */
246 if ((Z80_REG.B.F & FLAG_C)==0) M_JR
247 else Z80_REG.W.PC++;
248 break;
249 case 0x31: /* LD SP,NN */
250 Z80_REG.W.SP=GetWordAt(Z80_REG.W.PC);Z80_REG.W.PC+=2;
251 break;
252 case 0x32: /* LDD (HL),A */
253 SetByteAt(Z80_REG.W.HL--,Z80_REG.B.A);
254 break;
255 case 0x33:Z80_REG.W.SP++;break; /* INC SP */
256 case 0x34: /* INC (HL) */
257 DUMMY_F=GetByteAt(Z80_REG.W.HL);
258 M_INCB(DUMMY_F);
259 SetByteAt(Z80_REG.W.HL,DUMMY_F);
260 break;
261 case 0x35: /* DEC (HL) */
262 DUMMY_F=GetByteAt(Z80_REG.W.HL);
263 M_DECB(DUMMY_F);
264 SetByteAt(Z80_REG.W.HL,DUMMY_F);
265 break;
266 case 0x36: /* LD (HL),N */
267 SetByteAt(Z80_REG.W.HL,GetByteAt(Z80_REG.W.PC++));break;
268 case 0x37: /* SCF */
269 Z80_REG.B.F=(Z80_REG.B.F & FLAG_Z) | FLAG_C;break;
270 case 0x38: /* JR C,N */
271 if ((Z80_REG.B.F & FLAG_C)!=0) M_JR
272 else Z80_REG.W.PC++;
273 break;
274 case 0x39:M_ADDHL(Z80_REG.W.SP);break; /* ADD HL,SP */
275 case 0x3A:Z80_REG.B.A=GetByteAt(Z80_REG.W.HL--);break; /* LDD A,(HL) */
276 case 0x3B:Z80_REG.W.SP--;break; /* DEC SP */
277 case 0x3C:M_INCB(Z80_REG.B.A);break; /* INC A */
278 case 0x3D:M_DECB(Z80_REG.B.A);break; /* DEC A */
279 case 0x3E:
280 Z80_REG.B.A=GetByteAt(Z80_REG.W.PC++);break; /* LD A,N */
281 case 0x3F: /* CCF */
282 Z80_REG.B.F=(Z80_REG.B.F ^ FLAG_C) & (FLAG_C | FLAG_Z);
283 break;
284 case 0x40:Z80_REG.B.B=Z80_REG.B.B;break; /* LD B,B */
285 case 0x41:Z80_REG.B.B=Z80_REG.B.C;break; /* LD B,C */
286 case 0x42:Z80_REG.B.B=Z80_REG.B.D;break; /* LD B,D */
287 case 0x43:Z80_REG.B.B=Z80_REG.B.E;break; /* LD B,E */
288 case 0x44:Z80_REG.B.B=Z80_REG.B.H;break; /* LD B,H */
289 case 0x45:Z80_REG.B.B=Z80_REG.B.L;break; /* LD B,L */
290 case 0x46:Z80_REG.B.B=GetByteAt(Z80_REG.W.HL);break; /* LD B,(HL) */
291 case 0x47:Z80_REG.B.B=Z80_REG.B.A;break; /* LD B,A */
292 case 0x48:Z80_REG.B.C=Z80_REG.B.B;break; /* LD C,B */
293 case 0x49:Z80_REG.B.C=Z80_REG.B.C;break; /* LD C,C */
294 case 0x4A:Z80_REG.B.C=Z80_REG.B.D;break; /* LD C,D */
295 case 0x4B:Z80_REG.B.C=Z80_REG.B.E;break; /* LD C,E */
296 case 0x4C:Z80_REG.B.C=Z80_REG.B.H;break; /* LD C,H */
297 case 0x4D:Z80_REG.B.C=Z80_REG.B.L;break; /* LD C,L */
298 case 0x4E:Z80_REG.B.C=GetByteAt(Z80_REG.W.HL);break; /* LD C,(HL) */
299 case 0x4F:Z80_REG.B.C=Z80_REG.B.A;break; /* LD C,A */
300 case 0x50:Z80_REG.B.D=Z80_REG.B.B;break; /* LD D,B */
301 case 0x51:Z80_REG.B.D=Z80_REG.B.C;break; /* LD D,C */
302 case 0x52:Z80_REG.B.D=Z80_REG.B.D;break; /* LD D,D */
303 case 0x53:Z80_REG.B.D=Z80_REG.B.E;break; /* LD D,E */
304 case 0x54:Z80_REG.B.D=Z80_REG.B.H;break; /* LD D,H */
305 case 0x55:Z80_REG.B.D=Z80_REG.B.L;break; /* LD D,L */
306 case 0x56:Z80_REG.B.D=GetByteAt(Z80_REG.W.HL);break; /* LD D,(HL) */
307 case 0x57:Z80_REG.B.D=Z80_REG.B.A;break; /* LD D,A */
308 case 0x58:Z80_REG.B.E=Z80_REG.B.B;break; /* LD E,B */
309 case 0x59:Z80_REG.B.E=Z80_REG.B.C;break; /* LD E,C */
310 case 0x5A:Z80_REG.B.E=Z80_REG.B.D;break; /* LD E,D */
311 case 0x5B:Z80_REG.B.E=Z80_REG.B.E;break; /* LD E,E */
312 case 0x5C:Z80_REG.B.E=Z80_REG.B.H;break; /* LD E,H */
313 case 0x5D:Z80_REG.B.E=Z80_REG.B.L;break; /* LD E,L */
314 case 0x5E:Z80_REG.B.E=GetByteAt(Z80_REG.W.HL);break; /* LD E,(HL) */
315 case 0x5F:Z80_REG.B.E=Z80_REG.B.A;break; /* LD E,A */
316 case 0x60:Z80_REG.B.H=Z80_REG.B.B;break; /* LD H,B */
317 case 0x61:Z80_REG.B.H=Z80_REG.B.C;break; /* LD H,C */
318 case 0x62:Z80_REG.B.H=Z80_REG.B.D;break; /* LD H,D */
319 case 0x63:Z80_REG.B.H=Z80_REG.B.E;break; /* LD H,E */
320 case 0x64:Z80_REG.B.H=Z80_REG.B.H;break; /* LD H,H */
321 case 0x65:Z80_REG.B.H=Z80_REG.B.L;break; /* LD H,L */
322 case 0x66:Z80_REG.B.H=GetByteAt(Z80_REG.W.HL);break; /* LD H,(HL) */
323 case 0x67:Z80_REG.B.H=Z80_REG.B.A;break; /* LD H,A */
324 case 0x68:Z80_REG.B.L=Z80_REG.B.B;break; /* LD L,B */
325 case 0x69:Z80_REG.B.L=Z80_REG.B.C;break; /* LD L,C */
326 case 0x6A:Z80_REG.B.L=Z80_REG.B.D;break; /* LD L,D */
327 case 0x6B:Z80_REG.B.L=Z80_REG.B.E;break; /* LD L,E */
328 case 0x6C:Z80_REG.B.L=Z80_REG.B.H;break; /* LD L,H */
329 case 0x6D:Z80_REG.B.L=Z80_REG.B.L;break; /* LD L,L */
330 case 0x6E:Z80_REG.B.L=GetByteAt(Z80_REG.W.HL);break; /* LD L,(HL) */
331 case 0x6F:Z80_REG.B.L=Z80_REG.B.A;break; /* LD L,A */
332 case 0x70:SetByteAt(Z80_REG.W.HL,Z80_REG.B.B);break; /* LD (HL),B */
333 case 0x71:SetByteAt(Z80_REG.W.HL,Z80_REG.B.C);break; /* LD (HL),C */
334 case 0x72:SetByteAt(Z80_REG.W.HL,Z80_REG.B.D);break; /* LD (HL),D */
335 case 0x73:SetByteAt(Z80_REG.W.HL,Z80_REG.B.E);break; /* LD (HL),E */
336 case 0x74:SetByteAt(Z80_REG.W.HL,Z80_REG.B.H);break; /* LD (HL),H */
337 case 0x75:SetByteAt(Z80_REG.W.HL,Z80_REG.B.L);break; /* LD (HL),L */
338 case 0x76:Z80_IE=Z80_HALTED=1;break; /* HALT */
339 case 0x77:SetByteAt(Z80_REG.W.HL,Z80_REG.B.A);break; /* LD (HL),A */
340 case 0x78:Z80_REG.B.A=Z80_REG.B.B;break; /* LD A,B */
341 case 0x79:Z80_REG.B.A=Z80_REG.B.C;break; /* LD A,C */
342 case 0x7A:Z80_REG.B.A=Z80_REG.B.D;break; /* LD A,D */
343 case 0x7B:Z80_REG.B.A=Z80_REG.B.E;break; /* LD A,E */
344 case 0x7C:Z80_REG.B.A=Z80_REG.B.H;break; /* LD A,H */
345 case 0x7D:Z80_REG.B.A=Z80_REG.B.L;break; /* LD A,L */
346 case 0x7E:Z80_REG.B.A=GetByteAt(Z80_REG.W.HL);break; /* LD A,(HL) */
347 case 0x7F:Z80_REG.B.A=Z80_REG.B.A;break; /* LD A,A */
348 case 0x80:M_ADD(Z80_REG.B.B);break; /* ADD A,B */
349 case 0x81:M_ADD(Z80_REG.B.C);break; /* ADD A,C */
350 case 0x82:M_ADD(Z80_REG.B.D);break; /* ADD A,D */
351 case 0x83:M_ADD(Z80_REG.B.E);break; /* ADD A,E */
352 case 0x84:M_ADD(Z80_REG.B.H);break; /* ADD A,H */
353 case 0x85:M_ADD(Z80_REG.B.L);break; /* ADD A,L */
354 case 0x86:M_ADD(GetByteAt(Z80_REG.W.HL));break; /* ADD A,(HL) */
355 case 0x87:M_ADD(Z80_REG.B.A);break; /* ADD A,A */
356 case 0x88:M_ADC(Z80_REG.B.B);break; /* ADC A,B */
357 case 0x89:M_ADC(Z80_REG.B.C);break; /* ADC A,C */
358 case 0x8A:M_ADC(Z80_REG.B.D);break; /* ADC A,D */
359 case 0x8B:M_ADC(Z80_REG.B.E);break; /* ADC A,E */
360 case 0x8C:M_ADC(Z80_REG.B.H);break; /* ADC A,H */
361 case 0x8D:M_ADC(Z80_REG.B.L);break; /* ADC A,L */
362 case 0x8E:M_ADC(GetByteAt(Z80_REG.W.HL));break; /* ADC A,(HL) */
363 case 0x8F:M_ADC(Z80_REG.B.A);break; /* ADC A,A */
364 case 0x90:M_SUB(Z80_REG.B.B);break; /* SUB A,B */
365 case 0x91:M_SUB(Z80_REG.B.C);break; /* SUB A,C */
366 case 0x92:M_SUB(Z80_REG.B.D);break; /* SUB A,D */
367 case 0x93:M_SUB(Z80_REG.B.E);break; /* SUB A,E */
368 case 0x94:M_SUB(Z80_REG.B.H);break; /* SUB A,H */
369 case 0x95:M_SUB(Z80_REG.B.L);break; /* SUB A,L */
370 case 0x96:M_SUB(GetByteAt(Z80_REG.W.HL));break; /* SUB A,(HL) */
371 case 0x97:M_SUB(Z80_REG.B.A);break; /* SUB A,A */
372 case 0x98:M_SBC(Z80_REG.B.B);break; /* SBC A,B */
373 case 0x99:M_SBC(Z80_REG.B.C);break; /* SBC A,C */
374 case 0x9A:M_SBC(Z80_REG.B.D);break; /* SBC A,D */
375 case 0x9B:M_SBC(Z80_REG.B.E);break; /* SBC A,E */
376 case 0x9C:M_SBC(Z80_REG.B.H);break; /* SBC A,H */
377 case 0x9D:M_SBC(Z80_REG.B.L);break; /* SBC A,L */
378 case 0x9E:M_SBC(GetByteAt(Z80_REG.W.HL));break; /* SBC A,(HL) */
379 case 0x9F:M_SBC(Z80_REG.B.A);break; /* SBC A,A */
380 case 0xA0:M_AND(Z80_REG.B.B);break; /* AND A,B */
381 case 0xA1:M_AND(Z80_REG.B.C);break; /* AND A,C */
382 case 0xA2:M_AND(Z80_REG.B.D);break; /* AND A,D */
383 case 0xA3:M_AND(Z80_REG.B.E);break; /* AND A,E */
384 case 0xA4:M_AND(Z80_REG.B.H);break; /* AND A,H */
385 case 0xA5:M_AND(Z80_REG.B.L);break; /* AND A,L */
386 case 0xA6:M_AND(GetByteAt(Z80_REG.W.HL));break; /* AND A,(HL) */
387 case 0xA7:M_AND(Z80_REG.B.A);break; /* AND A,A */
388 case 0xA8:M_XOR(Z80_REG.B.B);break; /* XOR A,B */
389 case 0xA9:M_XOR(Z80_REG.B.C);break; /* XOR A,C */
390 case 0xAA:M_XOR(Z80_REG.B.D);break; /* XOR A,D */
391 case 0xAB:M_XOR(Z80_REG.B.E);break; /* XOR A,E */
392 case 0xAC:M_XOR(Z80_REG.B.H);break; /* XOR A,H */
393 case 0xAD:M_XOR(Z80_REG.B.L);break; /* XOR A,L */
394 case 0xAE:M_XOR(GetByteAt(Z80_REG.W.HL));break; /* XOR A,(HL) */
395 case 0xAF:M_XOR(Z80_REG.B.A);break; /* XOR A,A */
396 case 0xB0:M_OR(Z80_REG.B.B);break; /* OR A,B */
397 case 0xB1:M_OR(Z80_REG.B.C);break; /* OR A,C */
398 case 0xB2:M_OR(Z80_REG.B.D);break; /* OR A,D */
399 case 0xB3:M_OR(Z80_REG.B.E);break; /* OR A,E */
400 case 0xB4:M_OR(Z80_REG.B.H);break; /* OR A,H */
401 case 0xB5:M_OR(Z80_REG.B.L);break; /* OR A,L */
402 case 0xB6:M_OR(GetByteAt(Z80_REG.W.HL));break; /* OR A,(HL) */
403 case 0xB7:M_OR(Z80_REG.B.A);break; /* OR A,A */
404 case 0xB8:M_CP(Z80_REG.B.B);break; /* CP A,B */
405 case 0xB9:M_CP(Z80_REG.B.C);break; /* CP A,C */
406 case 0xBA:M_CP(Z80_REG.B.D);break; /* CP A,D */
407 case 0xBB:M_CP(Z80_REG.B.E);break; /* CP A,E */
408 case 0xBC:M_CP(Z80_REG.B.H);break; /* CP A,H */
409 case 0xBD:M_CP(Z80_REG.B.L);break; /* CP A,L */
410 case 0xBE:M_CP(GetByteAt(Z80_REG.W.HL));break; /* CP A,(HL) */
411 case 0xBF:M_CP(Z80_REG.B.A);break; /* CP A,A */
412 case 0xC0:if ((Z80_REG.B.F & FLAG_Z)==0) M_RET;break; /* RET NZ */
413 case 0xC1:M_POPW(Z80_REG.W.BC);break; /* POP BC */
414 case 0xC2: /* JP NZ,NN */
415 if ((Z80_REG.B.F & FLAG_Z)==0) M_JP
416 else Z80_REG.W.PC+=2;
417 break;
418 case 0xC3:M_JP;break; /* JP NN */
419 case 0xC4: /* CALL NZ,NN */
420 if ((Z80_REG.B.F & FLAG_Z)==0) M_CALL
421 else Z80_REG.W.PC+=2;
422 break;
423 case 0xC5:M_PUSHW(Z80_REG.W.BC);break; /* PUSH BC */
424 case 0xC6: /* ADD A,N */
425 M_ADD(GetByteAt(Z80_REG.W.PC));
426 Z80_REG.W.PC++;
427 break;
428 case 0xC7:M_RST(0x00);break; /* RST 00 */
429 case 0xC8:if ((Z80_REG.B.F & FLAG_Z)!=0) M_RET;break; /* RET Z */
430 case 0xC9:M_RET;break; /* RET */
431 case 0xCA: /* JP Z,NN */
432 if ((Z80_REG.B.F & FLAG_Z)!=0) M_JP
433 else Z80_REG.W.PC+=2;
434 break;
435 case 0xCB: /* CB-PREFIX */
436 M_PREFIXCB(GetByteAt(Z80_REG.W.PC));
437 Z80_REG.W.PC++;
438 break;
439 case 0xCC: /* CALL Z,NN */
440 if ((Z80_REG.B.F & FLAG_Z)!=0) M_CALL
441 else Z80_REG.W.PC+=2;
442 break;
443 case 0xCD:M_CALL;break; /* CALL NN */
444 case 0xCE: /* ADC A,N */
445 M_ADC(GetByteAt(Z80_REG.W.PC));
446 Z80_REG.W.PC++;
447 break;
448 case 0xCF:M_RST(0x08);break; /* RST 08 */
449 case 0xD0:if ((Z80_REG.B.F & FLAG_C)==0) M_RET;break; /* RET NC */
450 case 0xD1:M_POPW(Z80_REG.W.DE);break; /* POP DE */
451 case 0xD2: /* JP NC,NN */
452 if ((Z80_REG.B.F & FLAG_C)==0) M_JP
453 else Z80_REG.W.PC+=2;
454 break;
455 /* case 0xD3: illegal opcode */
456 case 0xD4: /* CALL NC,NN */
457 if ((Z80_REG.B.F & FLAG_C)==0) M_CALL
458 else Z80_REG.W.PC+=2;
459 break;
460 case 0xD5:M_PUSHW(Z80_REG.W.DE);break; /* PUSH DE */
461 case 0xD6: /* SUB A,N */
462 M_SUB(GetByteAt(Z80_REG.W.PC));
463 Z80_REG.W.PC++;
464 break;
465 case 0xD7:M_RST(0x10);break; /* RST 10 */
466 case 0xD8:if ((Z80_REG.B.F & FLAG_C)!=0) M_RET;break; /* RET C */
467 case 0xD9:M_RET;Z80_IE=1;break; /* RETI */
468 case 0xDA: /* JP C,NN */
469 if ((Z80_REG.B.F & FLAG_C)!=0) M_JP
470 else Z80_REG.W.PC+=2;
471 break;
472 /* case 0xDB: illegal opcode */
473 case 0xDC: /* CALL C,NN */
474 if ((Z80_REG.B.F & FLAG_C)!=0) M_CALL
475 else Z80_REG.W.PC+=2;
476 break;
477 /* case 0xDD: illegal opcode */
478 case 0xDE: /* SUB A,N */
479 M_SBC(GetByteAt(Z80_REG.W.PC));
480 Z80_REG.W.PC++;
481 break;
482 case 0xDF:M_RST(0x18);break; /* RST 18 */
483 case 0xE0: /* LD (FF00+N),A */
484 SetByteAt(0xFF00+GetByteAt(Z80_REG.W.PC++),
485 Z80_REG.B.A);break;
486 case 0xE1:M_POPW(Z80_REG.W.HL);break; /* POP HL */
487 case 0xE2: /* LD (FF00+C),A */
488 SetByteAt(0xFF00+Z80_REG.B.C,Z80_REG.B.A);break;
489 /* case 0xE3: illegal opcode */
490 /* case 0xE4: illegal opcode */
491 case 0xE5:M_PUSHW(Z80_REG.W.HL);break; /* PUSH HL */
492 case 0xE6: /* ADC A,N */
493 M_AND(GetByteAt(Z80_REG.W.PC));
494 Z80_REG.W.PC++;
495 break;
496 case 0xE7:M_RST(0x20);break; /* RST 20 */
497 case 0xE8:M_ADDSPN;break; /* ADD SP,N */
498 case 0xE9:Z80_REG.W.PC=Z80_REG.W.HL;break; /* JP (HL) */
499 case 0xEA: /* LD (NN),A */
500 SetByteAt(GetWordAt(Z80_REG.W.PC),Z80_REG.B.A);
501 Z80_REG.W.PC+=2;break;
502 /* case 0xEB: illegal opcode */
503 /* case 0xEC: illegal opcode */
504 /* case 0xED: illegal opcode */
505 case 0xEE: /* XOR A,N */
506 M_XOR(GetByteAt(Z80_REG.W.PC));
507 Z80_REG.W.PC++;
508 break;
509 case 0xEF:M_RST(0x28);break; /* RST 28 */
510 case 0xF0: /* LD A,(FF00+N) */
511 Z80_REG.B.A=GetByteAt(0xFF00+
512 GetByteAt(Z80_REG.W.PC++));
513 break;
514 case 0xF1: /* POP AF */
515 M_POPW(Z80_REG.W.AF);
516 Z80_REG.B.F&=0xF0; /* filter */
517 break;
518 case 0xF2: /* LD A,(FF00+C) */
519 Z80_REG.B.A=GetByteAt(0xFF00+Z80_REG.B.C);
520 break;
521 case 0xF3:Z80_IE=0;break; /* DI */
522 /* case 0xF4: illegal opcode */
523 case 0xF5: /* PUSH AF */
524 Z80_REG.B.F&=0xF0;
525 M_PUSHW(Z80_REG.W.AF);
526 break;
527 case 0xF6: /* OR A,N */
528 M_OR(GetByteAt(Z80_REG.W.PC));
529 Z80_REG.W.PC++;
530 break;
531 case 0xF7:M_RST(0x30);break; /* RST 30 */
532 case 0xF8:M_LDHLSPN;break; /* LD HL,SP+N */
533 case 0xF9:Z80_REG.W.SP=Z80_REG.W.HL;break; /* LD SP,HL */
534 case 0xFA: /* LD A,(NN) */
535 Z80_REG.B.A=GetByteAt(GetWordAt(Z80_REG.W.PC));
536 Z80_REG.W.PC+=2;break;
537 case 0xFB:Z80_IE=1;break; /* EI */
538 /* case 0xFC: illegal opcode */
539 /* case 0xFD: illegal opcode */
540 case 0xFE: /* CP A,N */
541 M_CP(GetByteAt(Z80_REG.W.PC));
542 Z80_REG.W.PC++;
543 break;
544 case 0xFF:M_RST(0x38);break; /* RST 38 */
545
546 default:
547 snprintf(errorstr, sizeof(errorstr),"Illegal opcode (%02X) at %X:%X\n",
548 Opcode, rombanknr,LASTPC);
549 fputs(errorstr,stderr);
550 return 1;
551 }
552 Z80_TICKS+=Z80_CLKS[DBLSPEED][Opcode];
553
554 return 0;
555 }
556
557 static char *HEX="0123456789ABCDEF";
558
getHEX(char * str)559 int getHEX(char *str) {
560 int ret;
561 unsigned int i,j;
562
563 /* fprintf(stderr,"analysing '%s'\n",str);*/
564
565 if (str==NULL || strlen(str)>4 || strlen(str)<1) return -1;
566
567 ret=0;
568 for (i=0;i<strlen(str);i++) {
569 ret<<=4;str[i]=toupper(str[i]);
570 for (j=0;j<16;j++) if (str[i]==HEX[j]) break;
571 if (j<16) ret+=j; else return -1;
572 }
573
574 return ret;
575 }
576
StartCPU()577 void StartCPU()
578 {
579 int err;
580
581 #ifdef DEBUG
582 int addr,val;
583 char cstr[70];
584 char cmd;
585 char param[70];
586 int i;
587 int cmdloop;
588 #endif
589
590 Z80_HALTED=0;
591 breakpoint=-1;
592 lastbreakpoint=-1;skipover=0;db_trace=0;
593 err=0;
594
595 while (!err) {
596 #ifdef DEBUG
597 if ((breakpoint==Z80_REG.W.PC)||(skipover==0)) {
598 if (breakpoint==Z80_REG.W.PC)
599 fprintf(OUTSTREAM,"*Breakpoint reached at 0x%04X\n",breakpoint);
600 breakpoint=-1;skipover=0;
601 DebugState();fprintf(OUTSTREAM,"\n");
602
603 cmdloop=1;
604 while (cmdloop) {
605 fprintf(OUTSTREAM,":");
606 fgets(cstr,sizeof(cstr),stdin);
607 if (strlen(cstr)>64) {
608 fprintf(OUTSTREAM,"Command too long.\n");
609 while (getc(stdin)!=10);
610 continue;
611 }
612
613 cmd=cstr[0];
614
615 i=1;
616 while (cstr[i]==' ') i++;
617
618 if (cstr[i]) strncpy(param,&cstr[i],strlen(&cstr[i])-1);
619 param[strlen(&cstr[i])-1]=0;
620
621 switch (toupper(cmd)) {
622 case 'V':
623 if ((addr=getHEX(param))<0) {
624 fprintf(OUTSTREAM,"invalid address\n");
625 break;
626 }
627 fprintf(OUTSTREAM,"%04X=%02X\n",addr,GetByteAt(addr));
628 break;
629 case 'G':
630 if ((addr=getHEX(param))<0) {
631 breakpoint=lastbreakpoint;
632 cmdloop=0;
633 skipover=-1;
634 break;
635 }
636 Z80_REG.W.PC=addr;
637 Z80_HALTED=0;
638 cmdloop=0;
639 skipover=-1;
640 break;
641 case 'B':
642 if ((breakpoint=getHEX(param))<0) {
643 fprintf(OUTSTREAM,"Breakpoint is set at: %04X\n",breakpoint);
644 break;
645 }
646 fprintf(OUTSTREAM,"Breakpoint set at: %04X\n",breakpoint);
647 lastbreakpoint=breakpoint;
648 break;
649 case 'C':
650 breakpoint=lastbreakpoint=-1;
651 fprintf(OUTSTREAM,"Breakpoint cleared.\n");
652 break;
653 case 'D':
654 if ((addr=getHEX(param))<0) {
655 fprintf(OUTSTREAM,"invalid address\n");
656 break;
657 }
658 i=16*16+addr;
659 for (;addr<i;addr+=16) {
660 fprintf(OUTSTREAM,"%04X: %02X %02X %02X %02X %02X %02X %02X %02X \
661 %02X %02X %02X %02X %02X %02X %02X %02X\n",
662 addr,
663 GetByteAt(addr),GetByteAt(addr+1),
664 GetByteAt(addr+2),GetByteAt(addr+3),
665 GetByteAt(addr+4),GetByteAt(addr+5),
666 GetByteAt(addr+6),GetByteAt(addr+7),
667 GetByteAt(addr+8),GetByteAt(addr+9),
668 GetByteAt(addr+10),GetByteAt(addr+11),
669 GetByteAt(addr+12),GetByteAt(addr+13),
670 GetByteAt(addr+14),GetByteAt(addr+15));
671 }
672 break;
673 case 'E':
674 if ((addr=getHEX(param))<0) {
675 fprintf(OUTSTREAM,"invalid address\n");
676 break;
677 }
678 fprintf(OUTSTREAM,"Value (00-FF): ");
679 scanf("%02X",&val);fgetc(stdin);
680 SetByteAt(addr,val);
681 fprintf(OUTSTREAM,"Written 0x%02X => 0x%04X.\n",val,addr);
682 break;
683 case 'H':
684 fprintf(OUTSTREAM,"%s%s\n", debugger_help1, debugger_help2);
685 break;
686 case 'O':
687 skipover=atoi(param);
688 fprintf(OUTSTREAM,"Skip over commands numer set to: %d.\n",skipover);
689 break;
690 case '#':
691 fprintf(OUTSTREAM,"Which screen (0=0x9800,1=9C00) ? ");
692 scanf("%d",&addr);
693 fprintf(OUTSTREAM,"Which tile data (0=0x9000,1=0x8000) ? ");
694 scanf("%d",&i);fgetc(stdin);
695 if (addr!=1) addr=0;
696 if (i!=1) i=0;
697 #ifdef UNIX
698 vramdump(addr,i);
699 #endif
700 break;
701 case 'Q':
702 return;
703 default:
704 if (!db_trace) {
705 DebugState();fprintf(OUTSTREAM,"\n");
706 }
707 cmdloop=0;
708 skipover=0;
709 }
710 }
711 } else skipover=skipover ? skipover-1 : 0;
712 #endif
713 if (!Z80_HALTED) {
714 #ifdef DEBUG
715 if (db_trace) {DebugState();fprintf(OUTSTREAM,"\n");}
716 #endif
717 err=ExecOpcode();
718 }
719
720 /* update registers & interrupt processing */
721 gameboyspecifics();
722 }
723 savestate();
724 }
725
726
727