12 int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, syncclock, syncfreq, sleeps, checkclock, 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 if(screen->chan != XRGB32 || screen->chan != XBGR32)
147 tmp = allocimage(display, Rect(0, 0, scale * 160, scale * 144), XRGB32, 0, 0);
148 draw(screen, screen->r, bg, nil, ZP);
151 strncpy(buf, file, sizeof buf - 4);
152 s = buf + strlen(buf) - 3;
153 if(s < buf || strcmp(s, ".gb") != 0)
156 savefd = create(buf, ORDWR|OEXCL, 0666);
158 savefd = open(buf, ORDWR);
162 readn(savefd, ram, rambanks * 8192);
174 fd = open("/dev/kbd", OREAD);
176 sysfatal("open: %r");
178 if(read(fd, buf, 256) <= 0)
179 sysfatal("read /dev/kbd: %r");
181 if(utfrune(buf, Kdel))
183 if(utfrune(buf, KF|5))
185 if(utfrune(buf, KF|6))
188 if(buf[0] != 'k' && buf[0] != 'K')
193 s += chartorune(&r, s);
234 threadmain(int argc, char** argv)
237 vlong old, new, diff;
253 sysfatal("unknown flag -%c", ARGC());
256 sysfatal("argument missing");
266 mc = initmouse(nil, screen);
268 sysfatal("init mouse: %r");
269 proccreate(keyproc, nil, 8192);
270 syncfreq = CPUFREQ / 50;
274 savestate("gb.save");
278 loadstate("gb.save");
295 while(nbrecv(mc->c, &m) > 0)
297 if(nbrecvul(mc->resizec) > 0){
298 if(getwindow(display, Refnone) < 0)
299 sysfatal("resize failed: %r");
300 p = divpt(addpt(screen->r.min, screen->r.max), 2);
301 picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))};
302 bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
309 if(timer && timerclock >= timerfreq){
312 mem[TIMA] = mem[TMA];
317 if(syncclock >= syncfreq){
322 if(checkclock >= CPUFREQ){
324 diff = new - old - sleeps * 10 * MILLION;
325 diff = BILLION - diff;
329 syncfreq = ((vlong)CPUFREQ) * 10 * MILLION / diff;
337 draw(screen, screen->r, bg, nil, ZP);