ref: e7ae491b6fcc823ed415090f660086bee7dec659
parent: ee75c96a3cb4322ce5e6ce3414b18faaf287b3f7
author: aiju <aiju@phicode.de>
date: Fri Apr 6 19:29:37 EDT 2012
various games/gb improvements
--- a/sys/src/games/gb/cpu.c
+++ b/sys/src/games/gb/cpu.c
@@ -9,7 +9,7 @@
u8int R[8], Fl;
u16int pc, sp, curpc;
-int halt, IME, nobios;
+int halt, IME;
static void
invalid(void)
--- a/sys/src/games/gb/daa.c
+++ b/sys/src/games/gb/daa.c
@@ -462,4 +462,4 @@
0x87, 0x50, 0x88, 0x50, 0x89, 0x50, 0x8A, 0x50, 0x8B, 0x50, 0x8C, 0x50, 0x8D, 0x50, 0x8E, 0x50, 0x8F, 0x50,
0x90, 0x50, 0x91, 0x50, 0x92, 0x50, 0x93, 0x50, 0x94, 0x50, 0x95, 0x50, 0x96, 0x50, 0x97, 0x50, 0x98, 0x50,
0x99, 0x50
-};
\ No newline at end of file
+};
--- a/sys/src/games/gb/dat.h
+++ b/sys/src/games/gb/dat.h
@@ -1,8 +1,10 @@
extern u16int pc, curpc, sp;
extern u8int R[8], Fl;
-extern int halt, IME, bank, keys;
+extern int halt, IME, keys;
extern int clock, ppuclock, divclock, timerclock, syncclock, timerfreq, timer;
-extern uchar mem[];
+extern int rombank, rambank, ramen, battery, ramrom;
+
+extern uchar mem[], *ram;
extern uchar *cart;
extern int mbc, rombanks, rambanks;
--- a/sys/src/games/gb/fns.h
+++ b/sys/src/games/gb/fns.h
@@ -4,3 +4,7 @@
void ppustep(void);
void disasm(u16int);
void interrupt(u8int);
+void message(char *, ...);
+void flushram(void);
+void savestate(char *);
+void loadstate(char *);
--- a/sys/src/games/gb/gb.c
+++ b/sys/src/games/gb/gb.c
@@ -1,24 +1,43 @@
#include <u.h>
#include <libc.h>
+#include <draw.h>
#include <thread.h>
+#include <mouse.h>
+#include <cursor.h>
#include <keyboard.h>
-#include <draw.h>
#include "dat.h"
#include "fns.h"
-uchar *cart;
-int mbc, rombanks, clock, ppuclock, divclock, timerclock, syncclock, timerfreq, timer, keys;
+uchar *cart, *ram;
+int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, syncclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq;
Rectangle picr;
-Image *bg;
+Image *bg, *tmp;
+Mousectl *mc;
void
+message(char *fmt, ...)
+{+ va_list va;
+ char buf[512];
+
+ va_start(va, fmt);
+ vsnprint(buf, sizeof buf, fmt, va);
+ string(screen, Pt(10, 10), display->black, ZP, display->defaultfont, buf);
+ msgclock = CPUFREQ;
+ va_end(va);
+}
+
+void
loadrom(char *file)
{int fd, i;
vlong len;
u8int ck;
+ char buf[512];
char title[17];
Point p;
+ char *s;
+ extern int battery, ramen;
fd = open(file, OREAD);
if(fd < 0)
@@ -44,19 +63,34 @@
memcpy(mem, cart, 32768);
memset(title, 0, sizeof(title));
memcpy(title, cart+0x134, 16);
+ battery = 0;
switch(cart[0x147]){+ case 0x09:
+ battery = 1;
+ case 0x08:
+ ramen = 1;
case 0x00:
mbc = 0;
break;
- case 0x01:
+ case 0x03:
+ battery = 1;
+ case 0x01: case 0x02:
mbc = 1;
break;
- case 0x13:
+ case 0x06:
+ battery = 1;
+ case 0x05:
+ mbc = 2;
+ break;
+ case 0x0F: case 0x10: case 0x13:
+ battery = 1;
+ case 0x11: case 0x12:
mbc = 3;
break;
default:
sysfatal("%s: unknown cartridge type %.2x", file, cart[0x147]);}
+
switch(cart[0x148]){case 0: case 1: case 2:
case 3: case 4: case 5:
@@ -72,17 +106,56 @@
case 54:
rombanks = 96;
break;
+ default:
+ sysfatal("header field 0x148 (%.2x) invalid", cart[0x148]);}
+ switch(cart[0x149]){+ case 0:
+ if(mbc != 2){+ rambanks = 0;
+ break;
+ }
+ /*fallthrough*/
+ case 1: case 2:
+ rambanks = 1;
+ break;
+ case 3:
+ rambanks = 4;
+ break;
+ default:
+ sysfatal("header field 0x149 (%.2x) invalid", cart[0x149]);+ }
+ if(rambanks > 0){+ ram = mallocz(rambanks * 8192, 1);
+ if(ram == nil)
+ sysfatal("malloc: %r");+ }
if(len < rombanks * 0x4000)
sysfatal("cartridge image is too small, %.4x < %.4x", (int)len, rombanks * 0x4000);-
initdraw(nil, nil, title);
- open("/dev/mouse", OREAD);originwindow(screen, Pt(0, 0), screen->r.min);
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(80, 72)), addpt(p, Pt(80, 72))};bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
+ if(screen->chan != XRGB32 || screen->chan != XBGR32)
+ tmp = allocimage(display, Rect(0, 0, 160, 144), XRGB32, 0, 0);
draw(screen, screen->r, bg, nil, ZP);
+
+ if(ram && battery){+ strncpy(buf, file, sizeof buf - 4);
+ s = buf + strlen(buf) - 3;
+ if(s < buf || strcmp(s, ".gb") != 0)
+ s += 3;
+ strcpy(s, ".gbs");
+ savefd = create(buf, ORDWR|OEXCL, 0666);
+ if(savefd < 0)
+ savefd = open(buf, ORDWR);
+ if(savefd < 0)
+ message("open: %r");+ else
+ readn(savefd, ram, rambanks * 8192);
+ atexit(flushram);
+ }
}
void
@@ -98,8 +171,14 @@
for(;;){if(read(fd, buf, 256) <= 0)
sysfatal("read /dev/kbd: %r");- if(buf[0] == 'c' && strchr(buf, 'q'))
- threadexitsall(nil);
+ if(buf[0] == 'c'){+ if(strchr(buf, Kesc))
+ threadexitsall(nil);
+ if(utfrune(buf, KF|5))
+ savereq = 1;
+ if(utfrune(buf, KF|6))
+ loadreq = 1;
+ }
if(buf[0] != 'k' && buf[0] != 'K')
continue;
s = buf + 1;
@@ -107,7 +186,7 @@
while(*s != 0){s += chartorune(&r, s);
switch(r){- case 'q':
+ case Kesc:
threadexitsall(nil);
case Kdown:
keys |= 1<<3;
@@ -141,8 +220,10 @@
void
threadmain(int argc, char** argv)
{- int t, count;
+ int t;
vlong old, new, diff;
+ Mouse m;
+ Point p;
ARGBEGIN{default:
@@ -159,12 +240,20 @@
R[rH] = 0x01;
Fl = 0xB0;
loadrom(argv[0]);
+ mc = initmouse(nil, screen);
+ if(mc == nil)
+ sysfatal("init mouse: %r");proccreate(keyproc, nil, 8192);
- count = 0;
old = nsec();
for(;;){- if(pc == 0x231 && count++)
- break;
+ if(savereq){+ savestate("gb.save");+ savereq = 0;
+ }
+ if(loadreq){+ loadstate("gb.save");+ loadreq = 0;
+ }
t = step();
clock += t;
ppuclock += t;
@@ -174,6 +263,15 @@
if(ppuclock >= 456){ppustep();
ppuclock -= 456;
+ while(nbrecv(mc->c, &m) > 0)
+ ;
+ if(nbrecvul(mc->resizec) > 0){+ if(getwindow(display, Refnone) < 0)
+ sysfatal("resize failed: %r");+ p = divpt(addpt(screen->r.min, screen->r.max), 2);
+ picr = (Rectangle){subpt(p, Pt(80, 72)), addpt(p, Pt(80, 72))};+ bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
+ }
}
if(divclock >= 256){mem[DIV]++;
@@ -196,6 +294,13 @@
sleep(diff);
old = new;
syncclock = 0;
+ }
+ if(msgclock > 0){+ msgclock -= t;
+ if(msgclock <= 0){+ draw(screen, screen->r, bg, nil, ZP);
+ msgclock = 0;
+ }
}
}
}
--- a/sys/src/games/gb/mem.c
+++ b/sys/src/games/gb/mem.c
@@ -6,7 +6,8 @@
#include "fns.h"
uchar mem[65536];
-int bank;
+int rombank, rambank, ramen, battery, ramrom;
+extern int savefd;
u8int
memread(u16int p)
@@ -22,10 +23,48 @@
return (mem[0xFF00] & 0xF0) | ~(keys & 0x0F);
return (mem[0xFF00] & 0xF0) | 0x0F;
}
+ if(!ramen && ((p & 0xE000) == 0xA000))
+ return 0xFF;
return mem[p];
}
+static void
+ramswitch(int state, int bank)
+{+ if(ramen){+ memcpy(ram + 8192 * rambank, mem + 0xA000, 8192);
+ if(battery && savefd > 0){+ seek(savefd, rambank * 8192, 0);
+ write(savefd, ram + 8192 * rambank, 8192);
+ }
+ ramen = 0;
+ }
+ rambank = bank;
+ if(state){+ if(bank >= rambanks)
+ sysfatal("invalid RAM bank %d selected (pc = %.4x)", bank, curpc);+ memcpy(mem + 0xA000, ram + 8192 * rambank, 8192);
+ ramen = 1;
+ }
+}
+
void
+flushram(void)
+{+ if(ramen)
+ ramswitch(ramen, rambank);
+}
+
+static void
+romswitch(int bank)
+{+ if(bank >= rombanks)
+ sysfatal("invalid ROM bank %d selected (pc = %.4x)", bank, curpc);+ rombank = bank;
+ memcpy(mem + 0x4000, cart + 0x4000 * bank, 0x4000);
+}
+
+void
memwrite(u16int p, u8int v)
{ if(p < 0x8000){@@ -33,25 +72,48 @@
case 0:
return;
case 1:
+ case 2:
switch(p >> 13){+ case 0:
+ if((v & 0x0F) == 0x0A)
+ ramswitch(1, rambank);
+ else
+ ramswitch(0, rambank);
+ return;
case 1:
+ v &= 0x1F;
if(v == 0)
v++;
- bank = v;
- if(bank >= rombanks)
- sysfatal("invalid ROM bank %d selected (pc = %.4x)", bank, curpc);- memcpy(mem + 0x4000, cart + 0x4000 * bank, 0x4000);
+ romswitch((rombank & 0xE0) | v);
return;
-
+ case 2:
+ if(ramrom)
+ ramswitch(ramen, v & 3);
+ else
+ romswitch(((v & 3) << 5) | (rombank & 0x1F));
+ return;
+ case 3:
+ ramrom = v;
+ return;
}
return;
case 3:
switch(p >> 13){+ case 0:
+ if((v & 0x0F) == 0x0A)
+ ramswitch(1, rambank);
+ else
+ ramswitch(0, rambank);
+ return;
case 1:
- bank = v;
- if(bank >= rombanks)
- sysfatal("invalid ROM bank %d selected (pc = %.4x)", bank, curpc);- memcpy(mem + 0x4000, cart + 0x4000 * bank, 0x4000);
+ v &= 0x7F;
+ if(v == 0)
+ v++;
+ romswitch(v);
+ return;
+ case 2:
+ if(v < 4)
+ ramswitch(ramen, v);
return;
}
return;
--- a/sys/src/games/gb/mkfile
+++ b/sys/src/games/gb/mkfile
@@ -9,6 +9,7 @@
disasm.$O\
ppu.$O\
daa.$O\
+ state.$O\
HFILES=dat.h fns.h
--- a/sys/src/games/gb/ppu.c
+++ b/sys/src/games/gb/ppu.c
@@ -47,15 +47,6 @@
}
static void
-zeropic(void)
-{- int i;
-
- for(i = 0; i < sizeof pic; i++)
- pic[i] = ((i & 3) == 3) ? 0 : 0xFF;
-}
-
-static void
drawbg(void)
{u8int Y, x, y, ty, toy, tx, tox, tnl1, tnl2, pal, val,h;
@@ -163,6 +154,7 @@
ppustep(void)
{extern Rectangle picr;
+ extern Image *tmp;
if(mem[LY] == 144){mem[STAT] &= ~3;
@@ -188,9 +180,13 @@
if(mem[LY] > 160){mem[LY] = 0;
if(mem[LCDC] & LCDOP){- loadimage(screen, picr, pic, sizeof(pic));
+ if(tmp){+ loadimage(tmp, tmp->r, pic, sizeof(pic));
+ draw(screen, picr, tmp, nil, ZP);
+ }else
+ loadimage(screen, picr, pic, sizeof(pic));
flushimage(display, 1);
- zeropic();
+ memset(pic, sizeof pic, 0);
}
}
}
--- /dev/null
+++ b/sys/src/games/gb/state.c
@@ -1,0 +1,126 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include "dat.h"
+#include "fns.h"
+
+static int fd;
+
+static void
+put8(u8int i)
+{+ write(fd, &i, 1);
+}
+
+static void
+put16(u16int i)
+{+ put8(i);
+ put8(i >> 8);
+}
+
+static void
+put32(u32int i)
+{+ put8(i);
+ put8(i >> 8);
+ put8(i >> 16);
+ put8(i >> 24);
+}
+
+static int
+get8(void)
+{+ u8int c;
+
+ read(fd, &c, 1);
+ return c;
+}
+
+static int
+get16(void)
+{+ int i;
+
+ i = get8();
+ i |= get8() << 8;
+ return i;
+}
+
+static int
+get32(void)
+{+ int i;
+
+ i = get8();
+ i |= get8() << 8;
+ i |= get8() << 16;
+ i |= get8() << 24;
+ return i;
+}
+
+void
+loadstate(char *file)
+{+ flushram();
+ fd = open(file, OREAD);
+ if(fd < 0){+ message("open: %r");+ return;
+ }
+ read(fd, mem, 65536);
+ if(ram != nil)
+ read(fd, ram, rambanks * 8192);
+ read(fd, R, sizeof R);
+ sp = get16();
+ pc = get16();
+ Fl = get8();
+ halt = get32();
+ IME = get32();
+ clock = get32();
+ ppuclock = get32();
+ divclock = get32();
+ syncclock = get32();
+ timerfreq = get32();
+ timer = get32();
+ rombank = get32();
+ rambank = get32();
+ ramen = get32();
+ battery = get32();
+ ramrom = get32();
+ close(fd);
+}
+
+void
+savestate(char *file)
+{+ flushram();
+ fd = create(file, ORDWR, 0666);
+ if(fd < 0){+ message("create: %r");+ return;
+ }
+ write(fd, mem, 65536);
+ if(ram != nil)
+ write(fd, ram, rambanks * 8192);
+ write(fd, R, sizeof R);
+ put16(sp);
+ put16(pc);
+ put8(Fl);
+ put32(halt);
+ put32(IME);
+ put32(clock);
+ put32(ppuclock);
+ put32(divclock);
+ put32(timerclock);
+ put32(syncclock);
+ put32(timerfreq);
+ put32(timer);
+ put32(rombank);
+ put32(rambank);
+ put32(ramen);
+ put32(battery);
+ put32(ramrom);
+ close(fd);
+}
--
⑨