various games/gb improvements
This commit is contained in:
parent
e9854eb12b
commit
4950b5468b
9 changed files with 337 additions and 41 deletions
|
@ -9,7 +9,7 @@
|
|||
|
||||
u8int R[8], Fl;
|
||||
u16int pc, sp, curpc;
|
||||
int halt, IME, nobios;
|
||||
int halt, IME;
|
||||
|
||||
static void
|
||||
invalid(void)
|
||||
|
|
|
@ -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
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -9,6 +9,7 @@ OFILES=\
|
|||
disasm.$O\
|
||||
ppu.$O\
|
||||
daa.$O\
|
||||
state.$O\
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
|
|
|
@ -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
126
sys/src/games/gb/state.c
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue