]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/gb/cpu.c
demote libemu to common code
[plan9front.git] / sys / src / games / gb / cpu.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "../eui.h"
5 #include "dat.h"
6 #include "fns.h"
7
8 u8int r[8], ime;
9 u16int pc, curpc, sp;
10 int halt, trace;
11
12 enum {
13         FLAGC = 0x10,
14         FLAGH = 0x20,
15         FLAGN = 0x40,
16         FLAGZ = 0x80
17 };
18 enum { rB, rC, rD, rE, rH, rL, rHL, rA, rF = rHL };
19 #define BC() (r[rB] << 8 | r[rC])
20 #define DE() (r[rD] << 8 | r[rE])
21 #define HL() (r[rH] << 8 | r[rL])
22
23 Var cpuvars[] = { ARR(r), VAR(ime), VAR(pc), VAR(curpc), VAR(sp), VAR(halt), {nil, 0, 0} };
24
25 static u8int
26 fetch8(void)
27 {
28         return memread(pc++);
29 }
30
31 static u16int
32 fetch16(void)
33 {
34         u16int u;
35         
36         u = memread(pc++);
37         return u | memread(pc++) << 8;
38 }
39
40 static void
41 push8(u8int u)
42 {
43         memwrite(--sp, u);
44 }
45
46 static void
47 push16(u16int u)
48 {
49         memwrite(--sp, u >> 8);
50         memwrite(--sp, u);
51 }
52
53 static u8int
54 pop8(void)
55 {
56         return memread(sp++);
57 }
58
59 static u16int
60 pop16(void)
61 {
62         u16int v;
63         
64         v = memread(sp++);
65         return v | memread(sp++) << 8;
66 }
67
68 static u16int
69 read16(u16int n)
70 {
71         return memread(n) | memread(n+1) << 8;
72 }
73
74 static void
75 write16(u16int n, u16int v)
76 {
77         memwrite(n++, v);
78         memwrite(n, v >> 8);
79 }
80
81 static int
82 move(u8int dst, u8int src)
83 {
84         if(dst == rHL){
85                 if(src == rHL){
86                         halt = 1;
87                         return 4;
88                 }
89                 memwrite(HL(), r[src]);
90                 return 8;
91         }
92         if(src == rHL){
93                 r[dst] = memread(HL());
94                 return 8;
95         }
96         r[dst] = r[src];
97         return 4;
98 }
99
100 static int
101 alu(u8int op, u8int n)
102 {
103         u8int v4;
104         u8int u;
105         u16int v;
106         int t;
107
108         switch(n){
109         case 8: u = fetch8(); t = 8; break;
110         case rHL:
111                 u = memread(HL());
112                 t = 8;
113                 break;
114         default:
115                 u = r[n];
116                 t = 4;
117         }
118         v4 = 0;
119         switch(op){
120         default:
121                 v4 = (r[rA] & 0x0f) + (u & 0x0f);
122                 v = r[rA] + u;
123                 break;
124         case 1:
125                 v4 = (r[rA] & 0x0f) + (u & 0x0f) + (r[rF] >> 4 & 1);
126                 v = r[rA] + u + (r[rF] >> 4 & 1);
127                 break;
128         case 2:
129         case 7:
130                 v4 = (r[rA] & 0x0f) + (~u & 0x0f) + 1;
131                 v = r[rA] + (u ^ 0xff) + 1;
132                 break;
133         case 3:
134                 v4 = (r[rA] & 0x0f) + (~u & 0x0f) + (~r[rF] >> 4 & 1);
135                 v = r[rA] + (u ^ 0xff) + (~r[rF] >> 4 & 1);
136                 break;
137         case 4: v = r[rA] & u; break;
138         case 5: v = r[rA] ^ u; break;
139         case 6: v = r[rA] | u; break;
140         }
141         r[rF] = 0;
142         if((u8int)v == 0)
143                 r[rF] |= FLAGZ;
144         if(op < 2){
145                 if((v & 0x100) != 0)
146                         r[rF] |= FLAGC;
147                 if((v4 & 0x10) != 0)
148                         r[rF] |= FLAGH;
149         }else if(op < 4 || op == 7){
150                 r[rF] |= FLAGN;
151                 if((v & 0x100) == 0)
152                         r[rF] |= FLAGC;
153                 if((v4 & 0x10) == 0)
154                         r[rF] |= FLAGH;
155         }else
156                 if(op == 4)
157                         r[rF] |= FLAGH;
158         if(op != 7)
159                 r[rA] = v;
160         return t;
161 }
162
163 static int
164 branch(int cc, int t)
165 {
166         u16int v;
167         
168         v = (s8int)fetch8();
169         if(!cc)
170                 return t + 8;
171         pc += v;
172         return t + 12;
173 }
174
175 static u8int
176 inc(u8int v)
177 {
178         r[rF] &= FLAGC;
179         ++v;
180         if(v == 0)
181                 r[rF] |= FLAGZ;
182         if((v & 0xf) == 0)
183                 r[rF] |= FLAGH;
184         return v;
185 }
186
187 static u8int
188 dec(u8int v)
189 {
190         --v;
191         r[rF] = r[rF] & FLAGC | FLAGN;
192         if(v == 0)
193                 r[rF] |= FLAGZ;
194         if((v & 0xf) == 0xf)
195                 r[rF] |= FLAGH;
196         return v;
197 }
198
199 static int
200 addhl(u16int u)
201 {
202         u32int v;
203         
204         r[rF] &= ~(FLAGN|FLAGC|FLAGH);
205         v = HL() + u;
206         if((v & 0x10000) != 0)
207                 r[rF] |= FLAGC;
208         if((HL() & 0xfff) + (u & 0xfff) >= 0x1000)
209                 r[rF] |= FLAGH;
210         r[rL] = v;
211         r[rH] = v >> 8;
212         return 8;
213 }
214
215 static void
216 adchl(u16int u)
217 {
218         u32int v, v4;
219         
220         v = HL() + u + (r[rF] & FLAGC);
221         v4 = (HL() & 0xfff) + (u & 0xfff) + (r[rF] & FLAGC);
222         r[rF] = 0;
223         if((v & 0x10000) != 0)
224                 r[rF] |= FLAGC;
225         if((v4 & 0x1000) != 0)
226                 r[rF] |= FLAGH;
227         if((u16int)v == 0)
228                 r[rF] |= FLAGZ;
229         r[rL] = v;
230         r[rH] = v >> 8;
231 }
232
233 static void
234 sbchl(u16int u)
235 {
236         u32int v, v4;
237         
238         v = HL() + (u16int)~u + (~r[rF] & FLAGC);
239         v4 = (HL() & 0xfff) + (~u & 0xfff) + (~r[rF] & FLAGC);
240         r[rF] = FLAGN;
241         if((v & 0x10000) == 0)
242                 r[rF] |= FLAGC;
243         if((v4 & 0x1000) == 0)
244                 r[rF] |= FLAGH;
245         if((u16int)v == 0)
246                 r[rF] |= FLAGZ;
247         r[rL] = v;
248         r[rH] = v >> 8;
249 }
250
251 static int
252 jump(int cc)
253 {
254         u16int v;
255         
256         v = fetch16();
257         if(!cc)
258                 return 12;
259         pc = v;
260         return 16;
261 }
262
263 static int
264 call(u16int a, int cc)
265 {
266         if(!cc)
267                 return 12;
268         push16(pc);
269         pc = a;
270         return cc < 0 ? 16 : 24;
271 }
272
273 static int
274 bits(void)
275 {
276         u8int op, v, n, m, c;
277         u16int a;
278         int t;
279         
280         op = fetch8();
281         n = op & 7;
282         m = op >> 3 & 7;
283         a = HL();
284         if(n == 6){
285                 v = memread(a);
286                 t = 16;
287         }else{
288                 v = r[n];
289                 t = 8;
290         }
291         switch(op >> 6){
292         case 0:
293                 c = r[rF] >> 4 & 1;
294                 switch(m){
295                 default: r[rF] = v >> 3 & 0x10; v = v << 1 | v >> 7; break;
296                 case 1:  r[rF] = v << 4 & 0x10; v = v >> 1 | v << 7; break;
297                 case 2:  r[rF] = v >> 3 & 0x10; v = v << 1 | c; break;
298                 case 3:  r[rF] = v << 4 & 0x10; v = v >> 1 | c << 7; break;
299                 case 4:  r[rF] = v >> 3 & 0x10; v = v << 1; break;
300                 case 5:  r[rF] = v << 4 & 0x10; v = v & 0x80 | v >> 1; break;
301                 case 6:  r[rF] = 0; v = v << 4 | v >> 4; break;
302                 case 7:  r[rF] = v << 4 & 0x10; v >>= 1; break;
303                 }
304                 if(v == 0)
305                         r[rF] |= FLAGZ;
306                 break;
307         case 1:
308                 r[rF] = r[rF] & ~(FLAGN|FLAGZ) | FLAGH;
309                 if((v & 1<<m) == 0)
310                         r[rF] |= FLAGZ;
311                 if(n == 6)
312                         t = 12;
313                 return t;
314         case 2:
315                 v &= ~(1<<m);
316                 break;
317         case 3:
318                 v |= (1<<m);
319         }
320         if(n == 6)
321                 memwrite(a, v);
322         else
323                 r[n] = v;
324         return t;
325 }
326
327 void
328 reset(void)
329 {
330         r[rA] = 0x01;
331         r[rF] = 0xb0;
332         r[rC] = 0x13;
333         r[rE] = 0xd8;
334         r[rL] = 0x4d;
335         r[rH] = 0x01;
336         if((mode & COL) == COL)
337                 r[rA] = 0x11;
338         sp = 0xfffe;
339         pc = 0x100;
340 }
341
342 int
343 step(void)
344 {
345         u8int op, v4;
346         u16int v, w;
347         s8int s;
348
349         if(halt)
350                 if((reg[IF] & reg[IE]) != 0)
351                         halt = 0;
352                 else
353                         return 4;
354         if((reg[IF] & reg[IE]) != 0 && ime != 0){
355                 push16(pc);
356                 ime = 0;
357                 v4 = reg[IF] & reg[IE];
358                 v4 &= -v4;
359                 reg[IF] &= ~v4;
360                 for(pc = 0x40; v4 != 1; pc += 8)
361                         v4 >>= 1;
362                 return 12;
363         }
364         curpc = pc;
365         op = fetch8();
366         if(trace)
367                 print("%.4x %.2x AF %.2x%.2x BC %.2x%.2x DE %.2x%.2x HL %.2x%.2x SP %.4x\n", curpc, op, r[rA], r[rF], r[rB], r[rC], r[rD], r[rE], r[rH], r[rL], sp);
368         switch(op >> 6){
369         case 1: return move(op >> 3 & 7, op & 7);
370         case 2: return alu(op >> 3 & 7, op & 7);
371         }
372         switch(op){
373         case 0x00: return 4;
374         case 0x10:
375                 if((mode & CGB) != 0 && (reg[KEY1] & 1) != 0){
376                         reg[DIV] += divclock - clock >> 7 - ((mode & TURBO) != 0);
377                         divclock = clock;
378                         mode ^= TURBO;
379                         timertac(reg[TAC], 1);
380                         reg[KEY1] ^= 0x81;
381                         return 4;
382                 }
383                 print("STOP ignored (pc=%.4ux)\n", curpc);
384                 return 4;
385         case 0x20: return branch((r[rF] & FLAGZ) == 0, 0);
386         case 0x30: return branch((r[rF] & FLAGC) == 0, 0);
387         case 0x01: r[rC] = fetch8(); r[rB] = fetch8(); return 12;
388         case 0x11: r[rE] = fetch8(); r[rD] = fetch8(); return 12;
389         case 0x21: r[rL] = fetch8(); r[rH] = fetch8(); return 12;
390         case 0x31: sp = fetch16(); return 12;
391         case 0x02: memwrite(BC(), r[rA]); return 8;
392         case 0x12: memwrite(DE(), r[rA]); return 8;
393         case 0x22: memwrite(HL(), r[rA]); if(++r[rL] == 0) r[rH]++; return 8;
394         case 0x32: memwrite(HL(), r[rA]); if(r[rL]-- == 0) r[rH]--; return 8;
395         case 0x03: if(++r[rC] == 0) r[rB]++; return 8;
396         case 0x13: if(++r[rE] == 0) r[rD]++; return 8;
397         case 0x23: if(++r[rL] == 0) r[rH]++; return 8;
398         case 0x33: sp++; return 8;
399         case 0x04: inc(r[rB]++); return 4;
400         case 0x14: inc(r[rD]++); return 4;
401         case 0x24: inc(r[rH]++); return 4;
402         case 0x34: memwrite(HL(), inc(memread(HL()))); return 12;
403         case 0x05: dec(r[rB]--); return 4;
404         case 0x15: dec(r[rD]--); return 4;
405         case 0x25: dec(r[rH]--); return 4;
406         case 0x35: memwrite(HL(), dec(memread(HL()))); return 12;
407         case 0x06: r[rB] = fetch8(); return 8;
408         case 0x16: r[rD] = fetch8(); return 8;
409         case 0x26: r[rH] = fetch8(); return 8;
410         case 0x36: memwrite(HL(), fetch8()); return 12;
411         case 0x07:
412                 r[rF] = r[rA] >> 3 & 0x10;
413                 r[rA] = r[rA] << 1 | r[rA] >> 7;
414                 return 4;
415         case 0x17:
416                 v = r[rF] >> 4 & 1;
417                 r[rF] = r[rA] >> 3 & 0x10;
418                 r[rA] = r[rA] << 1 | v; 
419                 return 4;
420         case 0x27:
421                 if(r[rA] > 0x99 && (r[rF] & FLAGN) == 0 || (r[rF] & FLAGC) != 0){
422                         r[rF] |= FLAGC;
423                         v = 0x60;
424                 }else{
425                         r[rF] &= ~FLAGC;
426                         v = 0;
427                 }
428                 if((r[rA] & 0xf) > 9 && (r[rF] & FLAGN) == 0 || (r[rF] & FLAGH) != 0)
429                         v |= 6;
430                 if((r[rF] & FLAGN) != 0)
431                         r[rA] -= v;
432                 else
433                         r[rA] += v;
434                 r[rF] &= ~(FLAGZ|FLAGH);
435                 if(r[rA] == 0)
436                         r[rF] |= FLAGZ;
437                 return 4;
438         case 0x37: r[rF] = r[rF] & ~(FLAGN | FLAGH) | FLAGC; return 4;
439         case 0x08: write16(fetch16(), sp); return 20;
440         case 0x18: return branch(1, 0);
441         case 0x28: return branch((r[rF] & FLAGZ) != 0, 0);
442         case 0x38: return branch((r[rF] & FLAGC) != 0, 0);
443         case 0x09: return addhl(BC());
444         case 0x19: return addhl(DE());
445         case 0x29: return addhl(HL());
446         case 0x39: return addhl(sp);
447         case 0x0a: r[rA] = memread(BC()); return 8;
448         case 0x1a: r[rA] = memread(DE()); return 8;
449         case 0x2a: r[rA] = memread(HL()); if(++r[rL] == 0) r[rH]++; return 8;
450         case 0x3a: r[rA] = memread(HL()); if(r[rL]-- == 0) r[rH]--; return 8;
451         case 0x0b: if(r[rC]-- == 0) r[rB]--; return 8;
452         case 0x1b: if(r[rE]-- == 0) r[rD]--; return 8;
453         case 0x2b: if(r[rL]-- == 0) r[rH]--; return 8;
454         case 0x3b: sp--; return 8;
455         case 0x0c: inc(r[rC]++); return 4;
456         case 0x1c: inc(r[rE]++); return 4;
457         case 0x2c: inc(r[rL]++); return 4;
458         case 0x3c: inc(r[rA]++); return 4;
459         case 0x0d: dec(r[rC]--); return 4;
460         case 0x1d: dec(r[rE]--); return 4;
461         case 0x2d: dec(r[rL]--); return 4;
462         case 0x3d: dec(r[rA]--); return 4;
463         case 0x0e: r[rC] = fetch8(); return 8;
464         case 0x1e: r[rE] = fetch8(); return 8;
465         case 0x2e: r[rL] = fetch8(); return 8;
466         case 0x3e: r[rA] = fetch8(); return 8;
467         case 0x0f:
468                 r[rF] = r[rA] << 4 & 0x10;
469                 r[rA] = r[rA] >> 1 | r[rA] << 7;
470                 return 4;
471         case 0x1f:
472                 v = r[rF] << 3 & 0x80;
473                 r[rF] = r[rA] << 4 & 0x10;
474                 r[rA] = r[rA] >> 1 | v;
475                 return 4;
476         case 0x2f:
477                 r[rF] |= FLAGN|FLAGH;
478                 r[rA] ^= 0xff;
479                 return 4;
480         case 0x3f:
481                 r[rF] = r[rF] & ~(FLAGN|FLAGH) ^ FLAGC;
482                 return 4;
483         case 0xc0: if((r[rF] & FLAGZ) == 0) {pc = pop16(); return 20;} return 8;
484         case 0xd0: if((r[rF] & FLAGC) == 0) {pc = pop16(); return 20;} return 8;
485         case 0xe0: memwrite(0xff00 | fetch8(), r[rA]); return 12;
486         case 0xf0: r[rA] = memread(0xff00 | fetch8()); return 12;
487         case 0xc1: r[rC] = pop8(); r[rB] = pop8(); return 12;
488         case 0xd1: r[rE] = pop8(); r[rD] = pop8(); return 12;
489         case 0xe1: r[rL] = pop8(); r[rH] = pop8(); return 12;
490         case 0xf1: r[rF] = pop8() & 0xf0; r[rA] = pop8(); return 12;
491         case 0xc2: return jump((r[rF] & FLAGZ) == 0);
492         case 0xd2: return jump((r[rF] & FLAGC) == 0);
493         case 0xe2: memwrite(0xff00 | r[rC], r[rA]); return 8;
494         case 0xf2: r[rA] = memread(0xff00 | r[rC]); return 8;
495         case 0xc3: return jump(1);
496         case 0xf3: ime = 0; return 4;
497         case 0xc4: return call(fetch16(), (r[rF] & FLAGZ) == 0);
498         case 0xd4: return call(fetch16(), (r[rF] & FLAGC) == 0);
499         case 0xc5: push8(r[rB]); push8(r[rC]); return 16;
500         case 0xd5: push8(r[rD]); push8(r[rE]); return 16;
501         case 0xe5: push8(r[rH]); push8(r[rL]); return 16;
502         case 0xf5: push8(r[rA]); push8(r[rF]); return 16;
503         case 0xc6: return alu(0, 8);
504         case 0xd6: return alu(2, 8);
505         case 0xe6: return alu(4, 8);
506         case 0xf6: return alu(6, 8);
507         case 0xc7: return call(0x00, -1);
508         case 0xd7: return call(0x10, -1);
509         case 0xe7: return call(0x20, -1);
510         case 0xf7: return call(0x30, -1);
511         case 0xc8: if((r[rF] & FLAGZ) != 0) {pc = pop16(); return 20;} return 8;
512         case 0xd8: if((r[rF] & FLAGC) != 0) {pc = pop16(); return 20;} return 8;
513         case 0xe8: case 0xf8:
514                 s = fetch8();
515                 v = sp + s;
516                 v4 = (sp & 0xf) + (s & 0xf);
517                 w = (sp & 0xff) + (s & 0xff);
518                 r[rF] = 0;
519                 if(v4 >= 0x10)
520                         r[rF] |= FLAGH;
521                 if(w >= 0x100)
522                         r[rF] |= FLAGC; 
523                 if(op == 0xe8){
524                         sp = v;
525                         return 16;
526                 }else{
527                         r[rL] = v;
528                         r[rH] = v >> 8;
529                         return 12;
530                 }
531         case 0xc9: pc = pop16(); return 16;
532         case 0xd9: pc = pop16(); ime = 1; return 16;
533         case 0xe9: pc = HL(); return 4;
534         case 0xf9: sp = HL(); return 8;
535         case 0xca: return jump((r[rF] & FLAGZ) != 0);
536         case 0xda: return jump((r[rF] & FLAGC) != 0);
537         case 0xea: memwrite(fetch16(), r[rA]); return 16;
538         case 0xfa: r[rA] = memread(fetch16()); return 16;
539         case 0xcb: return bits();
540         case 0xfb: ime = 1; return 4;
541         case 0xcc: return call(fetch16(), (r[rF] & FLAGZ) != 0);
542         case 0xdc: return call(fetch16(), (r[rF] & FLAGC) != 0);
543         case 0xcd: return call(fetch16(), 1);
544         case 0xce: return alu(1, 8);
545         case 0xde: return alu(3, 8);
546         case 0xee: return alu(5, 8);
547         case 0xfe: return alu(7, 8);
548         case 0xcf: return call(0x08, -1);
549         case 0xdf: return call(0x18, -1);
550         case 0xef: return call(0x28, -1);
551         case 0xff: return call(0x38, -1);
552         }
553         sysfatal("undefined opcode %#.2x at pc=%#.4x", op, curpc);
554         return 0;
555 }