10 extern uchar ppuram[16384];
11 int nprg, nchr, map, chrram;
16 int clock, ppuclock, apuclock, dmcclock, dmcfreq, sampclock, msgclock, saveclock;
18 int keys, keys2, paused, savereq, loadreq, oflag, savefd = -1;
23 message(char *fmt, ...)
29 vsnprint(buf, sizeof buf, fmt, va);
30 string(screen, Pt(10, 10), display->black, ZP, display->defaultfont, buf);
39 pwrite(savefd, mem + 0x6000, 0x2000, 0);
44 loadrom(char *file, int sflag)
49 static uchar header[16];
53 fd = open(file, OREAD);
56 if(readn(fd, header, sizeof(header)) < sizeof(header))
58 if(memcmp(header, "NES\x1a", 4) != 0)
59 sysfatal("not a ROM");
61 memset(header + 7, 0, 9);
62 flags = header[6] | header[7] << 8;
63 nes20 = (flags & FLNES20M) == FLNES20V;
64 if(flags & (FLVS | FLPC10))
65 sysfatal("ROM not supported");
68 nprg |= (header[HROMH] & 0xf) << 8;
70 sysfatal("invalid ROM");
73 nchr |= (header[HROMH] & 0xf0) << 4;
74 map = (flags >> FLMAPPERL) & 0x0f | (((flags >> FLMAPPERH) & 0x0f) << 4);
76 map |= (header[8] & 0x0f) << 8;
77 if(map >= 256 || mapper[map] == nil)
78 sysfatal("unimplemented mapper %d", map);
80 memset(mem, 0, sizeof(mem));
81 if((flags & FLTRAINER) != 0 && readn(fd, mem + 0x7000, 512) < 512)
83 prg = malloc(nprg * PRGSZ);
85 sysfatal("malloc: %r");
86 if(readn(fd, prg, nprg * PRGSZ) < nprg * PRGSZ)
90 chr = malloc(nchr * CHRSZ);
92 sysfatal("malloc: %r");
93 if(readn(fd, chr, nchr * CHRSZ) < nchr * CHRSZ)
97 chr = malloc(nchr * CHRSZ);
99 sysfatal("malloc: %r");
101 if((flags & FLFOUR) != 0)
103 else if((flags & FLMIRROR) != 0)
108 strncpy(buf, file, sizeof buf - 5);
109 s = buf + strlen(buf) - 4;
110 if(s < buf || strcmp(s, ".nes") != 0)
113 savefd = create(buf, ORDWR | OEXCL, 0666);
115 savefd = open(buf, ORDWR);
119 readn(savefd, mem + 0x6000, 0x2000);
122 mapper[map](INIT, 0);
136 n = read(0, buf, sizeof(buf) - 1);
138 sysfatal("read: %r");
140 n = getfields(buf, down, nelem(down), 1, " ");
142 for(n--; n >= 0; n--){
144 if(strcmp(s, "joy1") == 0)
146 else if(strcmp(s, "joy2") == 0)
148 else if(strcmp(s, "a") == 0)
150 else if(strcmp(s, "b") == 0)
152 else if(strcmp(s, "control") == 0)
154 else if(strcmp(s, "start") == 0)
156 else if(strcmp(s, "up") == 0)
158 else if(strcmp(s, "down") == 0)
160 else if(strcmp(s, "left") == 0)
162 else if(strcmp(s, "right") == 0)
176 static char buf[256];
180 fd = open("/dev/kbd", OREAD);
182 sysfatal("open: %r");
186 memmove(buf, buf+n, sizeof(buf)-n);
189 n = read(fd, buf, sizeof(buf)-1);
191 sysfatal("read /dev/kbd: %r");
196 if(utfrune(buf, Kdel)){
200 if(utfrune(buf, KF|5))
202 if(utfrune(buf, KF|6))
204 if(utfrune(buf, 't'))
207 if(buf[0] != 'k' && buf[0] != 'K')
212 s += chartorune(&r, s);
214 case Kdel: close(fd); threadexitsall(nil);
215 case 'x': k |= 1<<0; break;
216 case 'z': k |= 1<<1; break;
217 case Kshift: k |= 1<<2; break;
218 case 10: k |= 1<<3; break;
219 case Kup: k |= 1<<4; break;
220 case Kdown: k |= 1<<5; break;
221 case Kleft: k |= 1<<6; break;
222 case Kright: k |= 1<<7; break;
237 threadmain(int argc, char **argv)
268 fprint(2, "usage: %s [-23aos] rom\n", argv0);
269 threadexitsall("usage");
271 loadrom(argv[0], sflag);
272 if(initdraw(nil, nil, nil) < 0)
273 sysfatal("initdraw: %r");
274 mc = initmouse(nil, screen);
276 sysfatal("initmouse: %r");
277 proccreate(joyproc, nil, 8192);
278 proccreate(keyproc, nil, 8192);
279 originwindow(screen, Pt(0, 0), screen->r.min);
280 p = divpt(addpt(screen->r.min, screen->r.max), 2);
281 picr = (Rectangle){subpt(p, Pt(scale * 128, scale * h/2)), addpt(p, Pt(scale * 128, scale * h/2))};
282 tmp = allocimage(display, Rect(0, 0, scale * 256, scale * h), XRGB32, 0, 0);
283 bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
284 draw(screen, screen->r, bg, nil, ZP);
286 pc = memread(0xFFFC) | memread(0xFFFD) << 8;
291 savestate("nes.save");
295 loadstate("nes.save");
308 while(ppuclock >= 4){
312 if(apuclock >= APUDIV){
316 if(sampclock >= SAMPDIV){
318 sampclock -= SAMPDIV;
320 if(dmcclock >= dmcfreq){
327 draw(screen, screen->r, bg, nil, ZP);