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