]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/gb/cpu.c
games/nes: cleanup and resize handling
[plan9front.git] / sys / src / games / gb / cpu.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <draw.h>
5 #include "dat.h"
6 #include "fns.h"
7
8 #define lohi(L, H) (((u16int)L) | (((u16int)H) << 8))
9
10 u8int R[8], Fl;
11 u16int pc, sp, curpc;
12 int halt, IME;
13
14 static void
15 invalid(void)
16 {
17         sysfatal("invalid instruction %.2x (pc = %.4x)", memread(curpc), curpc);
18 }
19
20 static u8int
21 fetch8(void)
22 {
23         return memread(pc++);
24 }
25
26 static u16int
27 fetch16(void)
28 {
29         u16int r;
30         
31         r = lohi(memread(pc), memread(pc+1));
32         pc += 2;
33         return r;
34 }
35
36 static void
37 push8(u8int n)
38 {
39         memwrite(--sp, n);
40 }
41
42 static void
43 push16(u16int n)
44 {
45         memwrite(--sp, n >> 8);
46         memwrite(--sp, n);
47 }
48
49 static u8int
50 pop8(void)
51 {
52         return memread(sp++);
53 }
54
55 static u16int
56 pop16(void)
57 {
58         u8int a, b;
59         
60         b = pop8();
61         a = pop8();
62         return lohi(b, a);
63 }
64
65 static int
66 ld01(u8int op)
67 {
68         u8int val, a, b;
69         int time;
70         
71         a = (op & 0x38) >> 3;
72         b = op & 7;
73         time = 4;
74         if(a == rHL && b == rHL){
75                 halt = 1;
76                 return 4;
77         }
78         if(b == rHL){
79                 val = memread(lohi(R[rL], R[rH]));
80                 time = 8;
81         }else{
82                 val = R[b];
83         }
84         if(a == rHL){
85                 memwrite(lohi(R[rL], R[rH]), val);
86                 time = 8;
87         }else{
88                 R[a] = val;
89         }
90         return time;
91 }
92
93 static int
94 ldi(u8int op)
95 {
96         u8int val, a;
97         
98         val = fetch8();
99         a = (op & 0x38) >> 3;
100         if(a == rHL){
101                 memwrite(lohi(R[rL], R[rH]), val);
102                 return 12;
103         }else{
104                 R[a] = val;
105                 return 8;
106         }
107 }
108
109 static int
110 ld16(u8int op)
111 {
112         u16int val;
113         u8int a;
114         
115         val = fetch16();
116         a = (op & 0x30) >> 4;
117         switch(a){
118         case 0:
119                 R[rB] = val >> 8;
120                 R[rC] = val;
121                 break;
122         case 1:
123                 R[rD] = val >> 8;
124                 R[rE] = val;
125                 break;
126         case 2:
127                 R[rH] = val >> 8;
128                 R[rL] = val;
129                 break;
130         case 3:
131                 sp = val;
132                 break;
133         }
134         return 12;
135 }
136
137 static int
138 add16(u8int op)
139 {
140         u16int val1, val2;
141         u8int a;
142         u32int val32;
143         
144         a = (op & 0x30) >> 4;
145         switch(a){
146         case 0:
147                 val1 = lohi(R[rC], R[rB]);
148                 break;
149         case 1:
150                 val1 = lohi(R[rE], R[rD]);
151                 break;
152         case 2:
153                 val1 = lohi(R[rL], R[rH]);
154                 break;
155         default:
156                 val1 = sp;
157         }
158         Fl &= FLAGZ;
159         val2 = lohi(R[rL], R[rH]);
160         val32 = (u32int)(val1) + (u32int)(val2);
161         if(val32 > 0xFFFF)
162                 Fl |= FLAGC;
163         if(((val1&0xFFF)+(val2&0xFFF)) > 0xFFF)
164                 Fl |= FLAGH;
165         R[rL] = val32;
166         R[rH] = val32 >> 8;
167         return 8;
168 }
169
170 static int
171 ldin(u8int op)
172 {
173         u16int addr;
174
175         switch(op >> 4){
176         case 0:
177                 addr = lohi(R[rC], R[rB]);
178                 break;
179         case 1:
180                 addr = lohi(R[rE], R[rD]);
181                 break;
182         default:
183                 addr = lohi(R[rL], R[rH]);
184         }
185         if(op & 8){
186                 R[rA] = memread(addr);
187         }else{
188                 memwrite(addr, R[rA]);
189         }
190         if((op >> 4) > 1){
191                 if(op & 16)
192                         addr--;
193                 else
194                         addr++;
195                 R[rL] = addr;
196                 R[rH] = addr >> 8;
197         }
198         return 8;
199 }
200
201 static int
202 inc16(u8int op)
203 {
204         u16int val;
205         u8int a;
206         
207         a = (op & 0x38) >> 3;
208         switch(a >> 1){
209         case 0:
210                 val = lohi(R[rC], R[rB]);
211                 break;
212         case 1:
213                 val = lohi(R[rE], R[rD]);
214                 break;
215         case 2:
216                 val = lohi(R[rL], R[rH]);
217                 break;
218         default:
219                 val = sp;
220         }
221         if(a & 1)
222                 val--;
223         else
224                 val++;
225         switch(a >> 1){
226         case 0:
227                 R[rB] = val >> 8;
228                 R[rC] = val;
229                 break;
230         case 1:
231                 R[rD] = val >> 8;
232                 R[rE] = val;
233                 break;
234         case 2:
235                 R[rH] = val >> 8;
236                 R[rL] = val;
237                 break;
238         default:
239                 sp = val;
240         }
241         return 8;
242 }
243
244 static int
245 inc8(u8int op)
246 {
247         u8int val, a;
248         int time;
249         
250         a = (op & 0x38) >> 3;
251         if(a == rHL){
252                 val = memread(lohi(R[rL], R[rH]));
253                 time = 12;
254         }else{
255                 val = R[a];
256                 time = 4;
257         }
258         if(a == rHL){
259                 memwrite(lohi(R[rL], R[rH]), val+1);
260         }else{
261                 R[a] = val + 1;
262         }
263         Fl &= FLAGC;
264         if(val == 0xFF)
265                 Fl |= FLAGZ;
266         if((val & 0xF) == 0xF)
267                 Fl |= FLAGH;
268         return time;
269 }
270
271 static int
272 dec8(u8int op)
273 {
274         u8int val, a;
275         int time;
276         
277         a = (op & 0x38) >> 3;
278         if(a == rHL){
279                 val = memread(lohi(R[rL], R[rH]));
280                 time = 12;
281         }else{
282                 val = R[a];
283                 time = 4;
284         }
285         if(a == rHL){
286                 memwrite(lohi(R[rL], R[rH]), val - 1);
287         }else{
288                 R[a] = val - 1;
289         }
290         Fl = (Fl & FLAGC) | FLAGN;
291         if(val == 1)
292                 Fl |= FLAGZ;
293         if((val & 0xF) == 0)
294                 Fl |= FLAGH;
295         return time;
296 }
297
298 static int
299 alu(u8int op)
300 {
301         u8int val4, val8, a, b;
302         short val16;
303         int time;
304         
305         a = op & 7;
306         b = (op & 0x38) >> 3;
307         if((op >> 6) == 3){
308                 val8 = fetch8();
309                 time = 8;
310         }else if(a == rHL){
311                 val8 = memread(lohi(R[rL], R[rH]));
312                 time = 8;
313         }else{
314                 val8 = R[a];
315                 time = 4;
316         }
317         switch(b){
318         case 0:
319         case 1:
320                 val16 = (ushort)(R[rA]) + (ushort)(val8);
321                 val4 = (R[rA] & 0xF) + (val8 & 0xF);
322                 if(b == 1 && (Fl & FLAGC)){
323                         val16++;
324                         val4++;
325                 }
326                 Fl = 0;
327                 val8 = val16;
328                 if(val16 >= 0x100)
329                         Fl |= FLAGC;
330                 if(val4 >= 0x10)
331                         Fl |= FLAGH;
332                 break;
333         case 2:
334         case 3:
335         case 7:
336                 val16 = (ushort)R[rA];
337                 val16 -= (ushort)val8;
338                 val4 = val8 & 0xF;
339                 if(b == 3 && (Fl & FLAGC)){
340                         val16--;
341                         val4++;
342                 }
343                 val8 = val16;
344                 Fl = FLAGN;
345                 if(val16 < 0)
346                         Fl |= FLAGC;
347                 if(val4 > (R[rA] & 0xF))
348                         Fl |= FLAGH;
349                 break;
350         case 4:
351                 val8 &= R[rA];
352                 Fl = FLAGH;
353                 break;
354         case 5:
355                 val8 ^= R[rA];
356                 Fl = 0;
357                 break;
358         default:
359                 Fl = 0;
360                 val8 |= R[rA];
361         }
362         if(val8 == 0)
363                 Fl |= FLAGZ;
364         if(b != 7)
365                 R[rA] = val8;
366         return time;
367 }
368
369 static int
370 jr(u8int op)
371 {
372         u8int a;
373         u16int addr;
374         short step;
375         
376         a = (op & 0x38) >> 3;
377         switch(a){
378         case 0:
379                 return 4;
380         case 1:
381                 addr = fetch16();
382                 memwrite(addr, sp);
383                 memwrite(addr + 1, sp >> 8);
384                 return 8;
385         }
386         step = (short)(schar)fetch8();
387         switch(a){
388         case 2:
389                 return 4;
390         case 4:
391                 if(Fl & FLAGZ)
392                         return 8;
393                 break;
394         case 5:
395                 if((Fl & FLAGZ) == 0)
396                         return 8;
397                 break;
398         case 6:
399                 if(Fl & FLAGC)
400                         return 8;
401                 break;
402         case 7:
403                 if((Fl & FLAGC) == 0)
404                         return 8;
405         }
406         pc += step;
407         return 8;
408 }
409
410 static int
411 jp(u8int op)
412 {
413         u16int addr;
414         
415         addr = fetch16();
416         if(op != 0xC3){
417                 switch((op & 0x38) >> 3){
418                 case 0:
419                         if(Fl & FLAGZ)
420                                 return 12;
421                         break;
422                 case 1:
423                         if((Fl & FLAGZ) == 0)
424                                 return 12;
425                         break;
426                 case 2:
427                         if(Fl & FLAGC)
428                                 return 12;
429                         break;
430                 case 3:
431                         if((Fl & FLAGC) == 0)
432                                 return 12;
433                         break;
434                 }
435         }
436         pc = addr;
437         return 12;
438 }
439
440 static int
441 call(u8int op)
442 {
443         u16int addr;
444         
445         addr = fetch16();
446         if(op != 0xCD){
447                 switch((op & 0x38) >> 3){
448                 case 0:
449                         if(Fl & FLAGZ)
450                                 return 12;
451                         break;
452                 case 1:
453                         if((Fl & FLAGZ) == 0)
454                                 return 12;
455                         break;
456                 case 2:
457                         if(Fl & FLAGC)
458                                 return 12;
459                         break;
460                 case 3:
461                         if((Fl & FLAGC) == 0)
462                                 return 12;
463                         break;
464                 }
465         }
466         push16(pc);
467         pc = addr;
468         return 12;
469 }
470
471 static int
472 rst(u8int op)
473 {
474         u16int addr;
475
476         addr = op & 0x38;
477         push16(pc);
478         pc = addr;
479         return 32;
480 }
481
482 static int
483 ret(u8int op)
484 {
485         if(op != 0xC9 && op!= 0xD9){
486                 switch((op & 0x38) >> 3){
487                 case 0:
488                         if(Fl & FLAGZ)
489                                 return 8;
490                         break;
491                 case 1:
492                         if((Fl & FLAGZ) == 0)
493                                 return 8;
494                         break;
495                 case 2:
496                         if(Fl & FLAGC)
497                                 return 8;
498                         break;
499                 case 3:
500                         if((Fl & FLAGC) == 0)
501                                 return 8;
502                         break;
503                 }
504         }
505         pc = pop16();
506         if(op == 0xD9)
507                 IME = 1;
508         return 8;
509 }
510
511 static int
512 push(u8int op)
513 {
514         u8int a;
515
516         a = (op & 0x38) >> 4;
517         switch(a){
518         case 0:
519                 push8(R[rB]);
520                 push8(R[rC]);
521                 break;
522         case 1:
523                 push8(R[rD]);
524                 push8(R[rE]);
525                 break;
526         case 2:
527                 push8(R[rH]);
528                 push8(R[rL]);
529                 break;
530         default:
531                 push8(R[rA]);
532                 push8(Fl);
533                 break;
534         }
535         return 16;
536 }
537
538 static int
539 pop(u8int op)
540 {
541         u8int a;
542         
543         a = (op & 0x38) >> 4;
544         switch(a){
545         case 0:
546                 R[rC] = pop8();
547                 R[rB] = pop8();
548                 break;
549         case 1:
550                 R[rE] = pop8();
551                 R[rD] = pop8();
552                 break;
553         case 2:
554                 R[rL] = pop8();
555                 R[rH] = pop8();
556                 break;
557         default:
558                 Fl = pop8() & 0xF0;
559                 R[rA] = pop8();
560         }
561         return 12;
562 }
563
564 static int
565 shift(u8int op, int cb)
566 {
567         u16int val;
568         u8int a, b;
569         int time;
570         
571         a = (op & 0x38) >> 3;
572         b = op & 7;
573         if(b == rHL){
574                 val = memread(lohi(R[rL], R[rH]));
575                 time = 16;
576         }else{
577                 val = R[b];
578                 time = 8;
579         }
580         switch(a){
581         case 0:
582                 Fl = 0;
583                 if(val & 0x80)
584                         Fl = FLAGC;
585                 val = (val << 1) | (val >> 7);
586                 break;
587         case 1:
588                 Fl = 0;
589                 if(val & 1)
590                         Fl = FLAGC;
591                 val = (val >> 1) | (val << 7);
592                 break;
593         case 2:
594                 val <<= 1;
595                 if(Fl & FLAGC)
596                         val |= 1;
597                 Fl = 0;
598                 if(val & 0x100)
599                         Fl = FLAGC;
600                 break;
601         case 3:
602                 if(Fl & FLAGC)
603                         val |= 0x100;
604                 Fl = 0;
605                 if(val & 1)
606                         Fl = FLAGC;
607                 val >>= 1;
608                 break;
609         case 4:
610                 Fl = 0;
611                 if(val & 0x80)
612                         Fl = FLAGC;
613                 val <<= 1;
614                 break;
615         case 5:
616                 Fl = 0;
617                 if(val & 1)
618                         Fl = FLAGC;
619                 val = (val >> 1) | (val & 0x80);
620                 break;
621         case 6:
622                 val = (val << 4) | (val >> 4);
623                 Fl = 0;
624                 break;
625         default:
626                 Fl = 0;
627                 if(val & 1)
628                         Fl = FLAGC;
629                 val >>= 1;
630         }
631         if((val & 0xFF) == 0)
632                 Fl |= FLAGZ;
633         if(b == rHL)
634                 memwrite(lohi(R[rL], R[rH]), val);
635         else
636                 R[b] = val;
637         if(!cb)
638                 Fl &= FLAGC;
639         return time;
640 }
641
642 static int
643 bit(u8int op)
644 {
645         u8int val, a, b;
646         int time;
647         
648         a = (op & 0x38) >> 3;
649         b = op & 7;
650         if(b == rHL){
651                 val = memread(lohi(R[rL], R[rH])),
652                 time = 16;
653         }else{
654                 val = R[b];
655                 time = 8;
656         }
657         Fl = (Fl & FLAGC) | FLAGH;
658         if((val & (1<<a)) == 0)
659                 Fl |= FLAGZ;
660         return time;
661 }
662
663 static int
664 setres(u8int op)
665 {
666         u8int val, a, b;
667         int time;
668         
669         a = (op & 0x38) >> 3;
670         b = op & 7;
671         if(b == rHL){
672                 val = memread(lohi(R[rL], R[rH]));
673                 time = 16;
674         }else{
675                 val = R[b];
676                 time = 8;
677         }
678         if(op & 0x40)
679                 val |= (1 << a);
680         else
681                 val &= ~(1 << a);
682         if(b == rHL)
683                 memwrite(lohi(R[rL], R[rH]), val);
684         else
685                 R[b] = val;
686         return time;
687 }
688
689 static int
690 cb(void)
691 {
692         u8int op;
693         
694         op = fetch8();
695         if((op & 0xC0) == 0)
696                 return shift(op, 1);
697         if((op & 0xC0) == 0x40)
698                 return bit(op);
699         return setres(op);
700 }
701
702 void
703 interrupt(u8int t)
704 {
705         mem[IF] |= (1 << t);
706 }
707
708 int
709 step(void)
710 {
711         u8int op;
712         ushort val;
713         extern u8int daa[];
714         int val32, i;
715
716         if(halt){
717                 if(mem[IF] & mem[IE])
718                         halt = 0;
719                 else
720                         return 4;
721         }
722         if(IME && (mem[IF] & mem[IE]))
723                 for(i = 0; i < 5; i++)
724                         if(mem[IF] & mem[IE] & (1<<i)){
725                                 mem[IF] &= ~(1<<i);
726                                 push16(pc);
727                                 IME = 0;
728                                 halt = 0;
729                                 pc = 0x40 + 8 * i;
730                                 break;
731                         }
732         curpc = pc;
733         op = fetch8();
734         if(0){
735                 print("%.4x A %.2x B %.2x C %.2x D %.2x E %.2x HL %.2x%.2x SP %.4x F %.2x ", curpc, R[rA], R[rB], R[rC], R[rD], R[rE], R[rH], R[rL], sp, Fl);
736                 disasm(curpc);
737         }
738         if((op & 0xC7) == 0x00)
739                 return jr(op);
740         if((op & 0xCF) == 0x01)
741                 return ld16(op);
742         if((op & 0xCF) == 0x09)
743                 return add16(op);
744         if((op & 0xC7) == 0x02)
745                 return ldin(op);
746         if((op & 0xC7) == 0x03)
747                 return inc16(op);
748         if((op & 0xC7) == 0x04)
749                 return inc8(op);
750         if((op & 0xC7) == 0x05)
751                 return dec8(op);
752         if((op & 0xC7) == 0x06)
753                 return ldi(op);
754         if((op & 0xE7) == 0x07)
755                 return shift(op, 0);
756         if((op & 0xC0) == 0x40)
757                 return ld01(op);
758         if((op & 0xC0) == 0x80 || (op & 0xC7) == 0xC6)
759                 return alu(op);
760         if((op & 0xE7) == 0xC0 || op == 0xC9 || op == 0xD9)
761                 return ret(op);
762         if((op & 0xCF) == 0xC1)
763                 return pop(op);
764         if((op & 0xE7) == 0xC2 || op == 0xC3)
765                 return jp(op);
766         if((op & 0xE7) == 0xC4 || op == 0xCD)
767                 return call(op);
768         if((op & 0xCF) == 0xC5)
769                 return push(op);
770         if((op & 0xC7) == 0xC7)
771                 return rst(op);
772         switch(op){
773         case 0x27:
774                 i = (((int)R[rA]) + (((int)Fl) * 16)) * 2;
775                 R[rA] = daa[i];
776                 Fl = daa[i+1];
777                 return 4;
778         case 0x2F:
779                 R[rA] = ~R[rA];
780                 Fl |= FLAGN | FLAGH;
781                 return 4;
782         case 0x37:
783                 Fl = (Fl & FLAGZ) | FLAGC;
784                 return 4;
785         case 0x3F:
786                 Fl &= FLAGZ | FLAGC;
787                 Fl ^= FLAGC;
788                 return 4;
789         case 0xE0:
790                 memwrite(lohi(fetch8(), 0xFF), R[rA]);
791                 return 8;
792         case 0xE2:
793                 memwrite(lohi(R[rC], 0xFF), R[rA]);
794                 return 8;
795         case 0xE8:
796                 val = (short)(schar)fetch8();
797                 val32 = (uint)sp + (uint)val;
798                 Fl = 0;
799                 if(((sp & 0xFF) + (val & 0xFF)) > 0xFF)
800                         Fl |= FLAGC;
801                 if(((sp & 0xF) + (val & 0xF)) > 0xF)
802                         Fl |= FLAGH;
803                 sp = val32;
804                 return 16;
805         case 0xE9:
806                 pc = lohi(R[rL], R[rH]);
807                 return 4;
808         case 0xEA:
809                 memwrite(fetch16(), R[rA]);
810                 return 16;
811         case 0xF0:
812                 R[rA] = memread(lohi(fetch8(), 0xFF));
813                 return 12;
814         case 0xFA:
815                 R[rA] = memread(fetch16());
816                 return 16;
817         case 0xF2:
818                 R[rA] = memread(lohi(R[rC], 0xFF));
819                 return 8;
820         case 0xCB:
821                 return cb();
822         case 0xF3:
823                 IME= 0;
824                 return 4;
825         case 0xF8:
826                 val = (short)(schar)fetch8();
827                 val32 = (uint)sp + (uint)val;
828                 Fl = 0;
829                 if(((sp & 0xFF) + (val & 0xFF)) > 0xFF)
830                         Fl |= FLAGC;
831                 if(((sp & 0xF) + (val & 0xF)) > 0xF)
832                         Fl |= FLAGH;
833                 R[rL] = val32;
834                 R[rH] = val32 >> 8;
835                 return 12;
836         case 0xF9:
837                 sp = lohi(R[rL], R[rH]);
838                 return 8;
839         case 0xFB:
840                 IME = 1;
841                 return 4;
842         default:
843                 invalid();
844         }
845         return 0;
846 }