various games/gb improvements

This commit is contained in:
aiju 2012-04-06 23:29:37 +02:00
parent e9854eb12b
commit 4950b5468b
9 changed files with 337 additions and 41 deletions

View file

@ -9,7 +9,7 @@
u8int R[8], Fl;
u16int pc, sp, curpc;
int halt, IME, nobios;
int halt, IME;
static void
invalid(void)

View file

@ -462,4 +462,4 @@ u8int daa[] = {
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
};
};

View file

@ -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;

View file

@ -4,3 +4,7 @@ int step(void);
void ppustep(void);
void disasm(u16int);
void interrupt(u8int);
void message(char *, ...);
void flushram(void);
void savestate(char *);
void loadstate(char *);

View file

@ -1,15 +1,31 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <keyboard.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <cursor.h>
#include <keyboard.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)
@ -17,8 +33,11 @@ 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 @@ loadrom(char *file)
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 @@ loadrom(char *file)
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 @@ keyproc(void *)
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 @@ keyproc(void *)
while(*s != 0){
s += chartorune(&r, s);
switch(r){
case 'q':
case Kesc:
threadexitsall(nil);
case Kdown:
keys |= 1<<3;
@ -141,8 +220,10 @@ keyproc(void *)
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 @@ threadmain(int argc, char** argv)
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 @@ threadmain(int argc, char** argv)
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]++;
@ -197,5 +295,12 @@ threadmain(int argc, char** argv)
old = new;
syncclock = 0;
}
if(msgclock > 0){
msgclock -= t;
if(msgclock <= 0){
draw(screen, screen->r, bg, nil, ZP);
msgclock = 0;
}
}
}
}

View file

@ -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,9 +23,47 @@ memread(u16int p)
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)
{
@ -33,25 +72,48 @@ memwrite(u16int p, u8int v)
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;

View file

@ -9,6 +9,7 @@ OFILES=\
disasm.$O\
ppu.$O\
daa.$O\
state.$O\
HFILES=dat.h fns.h

View file

@ -46,15 +46,6 @@ pixelbelow(int x, int y, int val)
pixel(x, y, val, 0);
}
static void
zeropic(void)
{
int i;
for(i = 0; i < sizeof pic; i++)
pic[i] = ((i & 3) == 3) ? 0 : 0xFF;
}
static void
drawbg(void)
{
@ -163,6 +154,7 @@ void
ppustep(void)
{
extern Rectangle picr;
extern Image *tmp;
if(mem[LY] == 144){
mem[STAT] &= ~3;
@ -188,9 +180,13 @@ ppustep(void)
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);
}
}
}

126
sys/src/games/gb/state.c Normal file
View file

@ -0,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);
}