]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/nes/cpu.c
games/doom: fix idclev cheat in doom2 and final doom (thanks qu7uux)
[plan9front.git] / sys / src / games / nes / cpu.c
1 #include <u.h>
2 #include <libc.h>
3 #include "dat.h"
4 #include "fns.h"
5
6 u16int pc, curpc;
7 u8int rA, rX, rY, rS, rP;
8 u8int irq, nmi;
9
10 static u8int
11 fetch8(void)
12 {
13         return memread(pc++);
14 }
15
16 static u16int
17 fetch16(void)
18 {
19         u16int r;
20         
21         r = memread(pc++);
22         r |= memread(pc++) << 8;
23         return r;
24 }
25
26 static void
27 push8(u8int v)
28 {
29         memwrite(0x100 | rS--, v);
30 }
31
32 static void
33 push16(u16int v)
34 {
35         memwrite(0x100 | rS--, v >> 8);
36         memwrite(0x100 | rS--, v);
37 }
38
39 static u8int
40 pop8(void)
41 {
42         return memread(0x100 | ++rS);
43 }
44
45 static u16int
46 pop16(void)
47 {
48         u16int v;
49         
50         v = memread(0x100 | ++rS);
51         v |= memread(0x100 | ++rS) << 8;
52         return v;
53 }
54
55 #define imm() fetch8()
56 #define zp() memread(fetch8())
57 #define zpX() memread((u8int)(fetch8()+rX))
58 #define zpY() memread((u8int)(fetch8()+rY))
59 #define abso() memread(fetch16())
60 #define absX() memread(a=fetch16()+rX)
61 #define absY() memread(a=fetch16()+rY)
62 #define indX() memread(aindX())
63 #define indY(c) memread(aindY(c))
64
65 static u16int
66 aindX(void)
67 {
68         u8int r;
69         u16int a;
70         
71         r = fetch8() + rX;
72         a = memread(r++);
73         a |= memread(r) << 8;
74         return a;
75 }
76
77 static u16int
78 aindY(int *c)
79 {
80         u8int r;
81         u16int a;
82         
83         r = fetch8();
84         a = memread(r++) + rY;
85         *c = a > 0xFF;
86         a += memread(r) << 8;
87         return a;
88 }
89
90 static void
91 adc(u8int d)
92 {
93         int r;
94         
95         r = rA + d + (rP & FLAGC);
96         rP &= ~(FLAGN | FLAGZ | FLAGV | FLAGC);
97         if(r > 0xFF) rP |= FLAGC;
98         if(r & 0x80) rP |= FLAGN;
99         if((~(rA ^ d) & (rA ^ r)) & 0x80) rP |= FLAGV;
100         rA = r;
101         if(rA == 0) rP |= FLAGZ;
102 }
103
104 static u8int
105 nz(u8int d)
106 {
107         rP &= ~(FLAGN | FLAGZ);
108         if(d & 0x80) rP |= FLAGN;
109         if(d == 0) rP |= FLAGZ;
110         return d;
111 }
112
113 static void
114 asl(u16int a)
115 {
116         u8int v;
117
118         rP &= ~(FLAGN | FLAGZ | FLAGC);
119         v = memread(a);
120         if(v & 0x80) rP |= FLAGC;
121         v <<= 1;
122         if(v == 0) rP |= FLAGZ;
123         if(v & 0x80) rP |= FLAGN;
124         memwrite(a, v);
125 }
126
127 static void
128 lsr(u16int a)
129 {
130         u8int v;
131
132         rP &= ~(FLAGN | FLAGZ | FLAGC);
133         v = memread(a);
134         rP |= v & 1;
135         v >>= 1;
136         if(v == 0) rP |= FLAGZ;
137         if(v & 0x80) rP |= FLAGN;
138         memwrite(a, v);
139 }
140
141 static int
142 branch(void)
143 {
144         signed char t;
145         u16int npc;
146         
147         t = fetch8();
148         npc = pc + t;
149         if((npc ^ pc) >> 8){
150                 pc = npc;
151                 return 4;
152         }
153         pc = npc;
154         return 3;
155 }
156
157 static void
158 cmp(u8int a, u8int d)
159 {
160         rP &= ~(FLAGN | FLAGZ | FLAGC);
161         if(a == d) rP |= FLAGZ;
162         if(a >= d) rP |= FLAGC;
163         if((a - d) & 0x80) rP |= FLAGN;
164 }
165
166 static void
167 dec(u16int a)
168 {
169         memwrite(a, nz(memread(a) - 1));
170 }
171
172 static void
173 inc(u16int a)
174 {
175         u8int v;
176
177         v = memread(a);
178         memwrite(a, v);
179         v = nz(v + 1);
180         if(!(map == 1 && a >= 0x8000))
181                 memwrite(a, v);
182 }
183
184 static void
185 rol(u16int a)
186 {
187         u8int v, b;
188         
189         v = memread(a);
190         b = rP & FLAGC;
191         rP &= ~(FLAGC | FLAGN | FLAGZ);
192         if(v & 0x80) rP |= FLAGC;
193         v = (v << 1) | b;
194         if(v & 0x80) rP |= FLAGN;
195         if(v == 0) rP |= FLAGZ;
196         memwrite(a, v);
197 }
198
199 static void
200 ror(u16int a)
201 {
202         u8int v, b;
203         
204         v = memread(a);
205         b = rP & FLAGC;
206         rP &= ~(FLAGC | FLAGN | FLAGZ);
207         rP |= v & 1;
208         v = (v >> 1) | (b << 7);
209         if(v & 0x80) rP |= FLAGN;
210         if(v == 0) rP |= FLAGZ;
211         memwrite(a, v);
212 }
213
214 static void
215 sbc(u8int d)
216 {
217         int r;
218         
219         r = rA + (u8int)~d + (rP & FLAGC);
220         rP &= ~(FLAGZ | FLAGV | FLAGC | FLAGN);
221         if(r > 0xFF) rP |= FLAGC;
222         if(((rA ^ d) & (rA ^ r)) & 0x80) rP |= FLAGV;
223         rA = r;
224         if(rA == 0) rP |= FLAGZ;
225         if(rA & 0x80) rP |= FLAGN;
226 }
227
228 static void
229 interrupt(int nmi, int brk)
230 {
231         push16(pc);
232         push8(rP | 0x20 | (brk << 4));
233         pc = memread(0xFFFA | (!nmi << 2));
234         pc |= memread(0xFFFB | (!nmi << 2)) << 8;
235         rP |= FLAGI;
236 }
237
238 int trace;
239
240 int
241 step(void)
242 {
243         u8int op;
244         u16int a, v;
245         int c;
246         
247         if(nmi)
248                 if(--nmi == 0){
249                         interrupt(1, 0);
250                         nmi = 0;
251                         return 7;
252                 }
253         if(irq && (rP & 4) == 0){
254                 interrupt(0, 0);
255                 return 7;
256         }
257         curpc = pc;
258         op = fetch8();
259         if(trace)
260                 print("%x %x %x %x %x %x %x\n", curpc, op, rA, rX, rY, rS, rP);
261         switch(op){
262         case 0x00: pc++; interrupt(0, 1); return 7;
263         case 0x01: nz(rA |= indX()); return 6;
264         case 0x05: nz(rA |= zp()); return 3;
265         case 0x06: asl(fetch8()); return 5;
266         case 0x08: push8(rP | 0x30); return 3;
267         case 0x09: nz(rA |= imm()); return 2;
268         case 0x0A:
269                 rP &= ~(FLAGN | FLAGZ | FLAGC);
270                 if(rA & 0x80) rP |= FLAGC;
271                 rA <<= 1;
272                 if(rA == 0) rP |= FLAGZ;
273                 if(rA & 0x80) rP |= FLAGN;
274                 return 2;
275         case 0x0D: nz(rA |= abso()); return 4;
276         case 0x0E: asl(fetch16()); return 6;
277         case 0x10: if((rP & FLAGN) == 0) return branch(); pc++; return 2;
278         case 0x11: nz(rA |= indY(&c)); return 5+c;
279         case 0x15: nz(rA |= zpX()); return 4;
280         case 0x16: asl((u8int)(fetch8() + rX)); return 6;
281         case 0x18: rP &= ~FLAGC; return 2;
282         case 0x19: nz(rA |= absY()); return 4 + ((u8int)a < rY);
283         case 0x1D: nz(rA |= absX()); return 4 + ((u8int)a < rX);
284         case 0x1E: asl(fetch16() + rX); return 7;
285         case 0x20: push16(pc+1); pc = fetch16(); return 6;
286         case 0x21: nz(rA &= indX()); return 6;
287         case 0x24:
288                 a = memread(fetch8());
289                 rP &= ~(FLAGN | FLAGZ | FLAGV);
290                 rP |= a & 0xC0;
291                 if((a & rA) == 0) rP |= FLAGZ;
292                 return 3;
293         case 0x25: nz(rA &= zp()); return 3;
294         case 0x26: rol(fetch8()); return 5;
295         case 0x28: rP = pop8() & 0xcf; return 4;
296         case 0x29: nz(rA &= imm()); return 2;
297         case 0x2A:
298                 a = rP & FLAGC;
299                 rP &= ~(FLAGC | FLAGZ | FLAGN);
300                 if(rA & 0x80) rP |= FLAGC;
301                 rA = (rA << 1) | a;
302                 if(rA & 0x80) rP |= FLAGN;
303                 if(rA == 0) rP |= FLAGZ;
304                 return 2;
305         case 0x2C:
306                 a = memread(fetch16());
307                 rP &= ~(FLAGN | FLAGZ | FLAGV);
308                 rP |= a & 0xC0;
309                 if((a & rA) == 0) rP |= FLAGZ;
310                 return 4;
311         case 0x2D: nz(rA &= abso()); return 4;
312         case 0x2E: rol(fetch16()); return 6;
313         case 0x30: if((rP & FLAGN) != 0) return branch(); pc++; return 3;
314         case 0x31: nz(rA &= indY(&c)); return 5+c;
315         case 0x35: nz(rA &= zpX()); return 4;
316         case 0x36: rol((u8int)(fetch8() + rX)); return 6;
317         case 0x38: rP |= FLAGC; return 2;
318         case 0x39: nz(rA &= absY()); return 4 + ((u8int)a < rY);
319         case 0x3E: rol(fetch16() + rX); return 7;
320         case 0x3D: nz(rA &= absX()); return 4 + ((u8int)a < rX);
321         case 0x40: rP = pop8() & 0xcf; pc = pop16(); return 6;
322         case 0x41: nz(rA ^= indX()); return 6;
323         case 0x45: nz(rA ^= zp()); return 3;
324         case 0x46: lsr(fetch8()); return 5;
325         case 0x48: push8(rA); return 3;
326         case 0x49: nz(rA ^= imm()); return 2;
327         case 0x4A:
328                 rP &= ~(FLAGN | FLAGZ | FLAGC);
329                 rP |= rA & 1;
330                 rA >>= 1;
331                 if(rA == 0) rP |= FLAGZ;
332                 if(rA & 0x80) rP |= FLAGN;
333                 return 2;
334         case 0x4C: pc = fetch16(); return 3;
335         case 0x4D: nz(rA ^= abso()); return 4;
336         case 0x4E: lsr(fetch16()); return 6;
337         case 0x51: nz(rA ^= indY(&c)); return 5+c;
338         case 0x56: lsr((u8int)(fetch8() + rX)); return 6;
339         case 0x58: rP &= ~FLAGI; return 2;
340         case 0x50: if((rP & FLAGV) == 0) return branch(); pc++; return 3;
341         case 0x55: nz(rA ^= zpX()); return 4;
342         case 0x59: nz(rA ^= absY()); return 4 + ((u8int)a < rX);
343         case 0x5D: nz(rA ^= absX()); return 4 + ((u8int)a < rX);
344         case 0x5E: lsr(fetch16() + rX); return 7;
345         case 0x60: pc = pop16() + 1; return 6;
346         case 0x61: adc(indX()); return 6;
347         case 0x65: adc(zp()); return 3;
348         case 0x66: ror(fetch8()); return 5;
349         case 0x68: nz(rA = pop8()); return 4;
350         case 0x69: adc(imm()); return 2;
351         case 0x6A:
352                 a = rP & FLAGC;
353                 rP &= ~(FLAGC | FLAGN | FLAGZ);
354                 rP |= rA & 1;
355                 rA = (rA >> 1) | (a << 7);
356                 if(rA & 0x80) rP |= FLAGN;
357                 if(rA == 0) rP |= FLAGZ;
358                 return 2;
359         case 0x6C: v = fetch16(); pc = memread(v) | (memread((v & 0xFF00) | (u8int)(v+1)) << 8); return 5;
360         case 0x6D: adc(abso()); return 4;
361         case 0x6E: ror(fetch16()); return 6;
362         case 0x70: if((rP & FLAGV) != 0) return branch(); pc++; return 3;
363         case 0x71: adc(indY(&c)); return 5+c;
364         case 0x75: adc(zpX()); return 4;
365         case 0x76: ror((u8int)(fetch8() + rX)); return 6;
366         case 0x78: rP |= FLAGI; return 2;
367         case 0x79: adc(absY()); return 4 + ((u8int)a < rY);
368         case 0x7D: adc(absX()); return 4 + ((u8int)a < rX);
369         case 0x7E: ror(fetch16() + rX); return 7;
370         case 0x81: memwrite(aindX(), rA); return 6;
371         case 0x84: memwrite(fetch8(), rY); return 3;
372         case 0x85: memwrite(fetch8(), rA); return 3;
373         case 0x86: memwrite(fetch8(), rX); return 3;
374         case 0x88: nz(--rY); return 2;
375         case 0x8A: nz(rA = rX); return 2;
376         case 0x8C: memwrite(fetch16(), rY); return 4;
377         case 0x8D: memwrite(fetch16(), rA); return 4;
378         case 0x8E: memwrite(fetch16(), rX); return 4;
379         case 0x90: if((rP & FLAGC) == 0) return branch(); pc++; return 3;
380         case 0x91: memwrite(aindY(&c), rA); return 6;
381         case 0x94: memwrite((u8int)(fetch8() + rX), rY); return 4;
382         case 0x95: memwrite((u8int)(fetch8() + rX), rA); return 4;
383         case 0x96: memwrite((u8int)(fetch8() + rY), rX); return 4;
384         case 0x98: nz(rA = rY); return 2;
385         case 0x99: memwrite(fetch16() + rY, rA); return 5;
386         case 0x9A: rS = rX; return 2;
387         case 0x9D: memwrite(fetch16() + rX, rA); return 5;
388         case 0xA0: nz(rY = imm()); return 2;
389         case 0xA1: nz(rA = indX()); return 6;
390         case 0xA2: nz(rX = imm()); return 2;
391         case 0xA4: nz(rY = zp()); return 3;
392         case 0xA5: nz(rA = zp()); return 3;
393         case 0xA6: nz(rX = zp()); return 3;
394         case 0xA8: nz(rY = rA); return 2;
395         case 0xA9: nz(rA = imm()); return 2;
396         case 0xAA: nz(rX = rA); return 2;
397         case 0xAC: nz(rY = abso()); return 4;
398         case 0xAE: nz(rX = abso()); return 4;
399         case 0xAD: nz(rA = abso()); return 4;
400         case 0xB0: if((rP & FLAGC) != 0) return branch(); pc++; return 3;
401         case 0xB1: nz(rA = indY(&c)); return 5+c;
402         case 0xB4: nz(rY = zpX()); return 4;
403         case 0xB5: nz(rA = zpX()); return 4;
404         case 0xB6: nz(rX = zpY()); return 4;
405         case 0xB8: rP &= ~FLAGV; return 2;
406         case 0xB9: nz(rA = absY()); return 4 + ((u8int)a < rY);
407         case 0xBA: nz(rX = rS); return 2;
408         case 0xBC: nz(rY = absX()); return 4 + ((u8int)a < rX);
409         case 0xBD: nz(rA = absX()); return 4 + ((u8int)a < rX);
410         case 0xBE: nz(rX = absY()); return 4 + ((u8int)a < rY);
411         case 0xC1: cmp(rA, indX()); return 6;
412         case 0xC5: cmp(rA, zp()); return 3;
413         case 0xC9: cmp(rA, imm()); return 2;
414         case 0xCD: cmp(rA, abso()); return 4;
415         case 0xD0: if((rP & FLAGZ) == 0) return branch(); pc++; return 3;
416         case 0xD1: cmp(rA, indY(&c)); return 5 + c;
417         case 0xD5: cmp(rA, zpX()); return 4;
418         case 0xD8: rP &= ~FLAGD; return 2;
419         case 0xD9: cmp(rA, absY()); return 4 + ((u8int)a < rY);
420         case 0xDD: cmp(rA, absX()); return 4 + ((u8int)a < rX);
421         case 0xC0: cmp(rY, imm()); return 2;
422         case 0xC4: cmp(rY, zp()); return 3;
423         case 0xC6: dec(fetch8()); return 5;
424         case 0xC8: nz(++rY); return 2;
425         case 0xCA: nz(--rX); return 2;
426         case 0xCC: cmp(rY, abso()); return 4;
427         case 0xCE: dec(fetch16()); return 6;
428         case 0xD6: dec((u8int)(fetch8() + rX)); return 6;
429         case 0xDE: dec(fetch16() + rX); return 7;
430         case 0xE0: cmp(rX, imm()); return 2;
431         case 0xE1: sbc(indX()); return 6;
432         case 0xE4: cmp(rX, zp()); return 3;
433         case 0xE5: sbc(zp()); return 3;
434         case 0xE6: inc(fetch8()); return 5;
435         case 0xE8: nz(++rX); return 2;
436         case 0xE9: sbc(imm()); return 2;
437         case 0xEA: return 2;
438         case 0xEC: cmp(rX, abso()); return 4;
439         case 0xED: sbc(abso()); return 4;
440         case 0xEE: inc(fetch16()); return 6;
441         case 0xF0: if((rP & FLAGZ) != 0) return branch(); pc++; return 3;
442         case 0xF1: sbc(indY(&c)); return 5+c;
443         case 0xF5: sbc(zpX()); return 4;
444         case 0xF6: inc((u8int)(fetch8() + rX)); return 6;
445         case 0xF8: rP |= FLAGD; return 2;
446         case 0xF9: sbc(absY()); return 4 + ((u8int)a < rY);
447         case 0xFD: sbc(absX()); return 4 + ((u8int)a < rX);
448         case 0xFE: inc(fetch16() + rX); return 7;
449         default:
450                 print("undefined %#x (pc %#x)\n", op, curpc);
451                 return 2;
452         }
453 }