12 int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, audioclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq, scale, paused;
19 message(char *fmt, ...)
25 vsnprint(buf, sizeof buf, fmt, va);
26 string(screen, Pt(10, 10), display->black, ZP, display->defaultfont, buf);
41 extern int battery, ramen;
43 fd = open(file, OREAD);
49 if(len == 0 || len > 16*1048576)
50 sysfatal("are you sure this is a ROM?");
53 sysfatal("malloc: %r");
55 if(readn(fd, cart, len) < len)
60 for(i = 0x134; i <= 0x14C; i++)
63 sysfatal("checksum mismatch: %.2x != %.2x", ck, cart[0x14D]);
64 memcpy(mem, cart, 32768);
65 memset(title, 0, sizeof(title));
66 memcpy(title, cart+0x134, 16);
86 case 0x0F: case 0x10: case 0x13:
93 case 0x19: case 0x1A: case 0x1C: case 0x1D:
97 sysfatal("%s: unknown cartridge type %.2x", file, cart[0x147]);
101 case 0: case 1: case 2:
102 case 3: case 4: case 5:
104 rombanks = 2 << (uint)cart[0x148];
116 sysfatal("header field 0x148 (%.2x) invalid", cart[0x148]);
132 sysfatal("header field 0x149 (%.2x) invalid", cart[0x149]);
135 ram = mallocz(rambanks * 8192, 1);
137 sysfatal("malloc: %r");
139 if(len < rombanks * 0x4000)
140 sysfatal("cartridge image is too small, %.4x < %.4x", (int)len, rombanks * 0x4000);
141 initdraw(nil, nil, title);
142 originwindow(screen, Pt(0, 0), screen->r.min);
143 p = divpt(addpt(screen->r.min, screen->r.max), 2);
144 picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
145 bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
146 tmp = allocimage(display, Rect(0, 0, scale * 160, scale * 144), XRGB32, 0, 0);
147 draw(screen, screen->r, bg, nil, ZP);
150 strncpy(buf, file, sizeof buf - 4);
151 s = buf + strlen(buf) - 3;
152 if(s < buf || strcmp(s, ".gb") != 0)
155 savefd = create(buf, ORDWR|OEXCL, 0666);
157 savefd = open(buf, ORDWR);
161 readn(savefd, ram, rambanks * 8192);
173 fd = open("/dev/kbd", OREAD);
175 sysfatal("open: %r");
177 if(read(fd, buf, 256) <= 0)
178 sysfatal("read /dev/kbd: %r");
180 if(utfrune(buf, Kdel))
182 if(utfrune(buf, KF|5))
184 if(utfrune(buf, KF|6))
187 if(buf[0] != 'k' && buf[0] != 'K')
192 s += chartorune(&r, s);
233 threadmain(int argc, char** argv)
249 sysfatal("unknown flag -%c", ARGC());
252 sysfatal("argument missing");
262 mc = initmouse(nil, screen);
264 sysfatal("init mouse: %r");
265 proccreate(keyproc, nil, 8192);
268 savestate("gb.save");
272 loadstate("gb.save");
293 if(audioclock >= CPUFREQ / SAMPLE){
295 audioclock -= CPUFREQ / SAMPLE;
297 if(timer && timerclock >= timerfreq){
300 mem[TIMA] = mem[TMA];
308 draw(screen, screen->r, bg, nil, ZP);
318 extern uchar pic[160*144*4*3*3];
324 while(nbrecv(mc->c, &m) > 0)
326 if(nbrecvul(mc->resizec) > 0){
327 if(getwindow(display, Refnone) < 0)
328 sysfatal("resize failed: %r");
329 p = divpt(addpt(screen->r.min, screen->r.max), 2);
330 picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
331 if(bg->chan != screen->chan){
333 bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
335 draw(screen, screen->r, bg, nil, ZP);
337 if(screen->chan != tmp->chan){
338 loadimage(tmp, tmp->r, pic, 160*144*4*scale*scale);
339 draw(screen, picr, tmp, nil, ZP);
341 loadimage(screen, picr, pic, 160*144*4*scale*scale);
342 flushimage(display, 1);
343 memset(pic, sizeof pic, 0);
347 diff = BILLION/60 - (new - old);