games/gba: slowly working (no pun intended)
This commit is contained in:
parent
709e78b9f9
commit
77f3fa19de
8 changed files with 3181 additions and 0 deletions
1269
sys/src/games/gba/cpu.c
Normal file
1269
sys/src/games/gba/cpu.c
Normal file
File diff suppressed because it is too large
Load diff
114
sys/src/games/gba/dat.h
Normal file
114
sys/src/games/gba/dat.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
typedef char s8int;
|
||||
typedef short s16int;
|
||||
typedef long s32int;
|
||||
typedef vlong s64int;
|
||||
|
||||
extern int cpuhalt, trace, keys;
|
||||
|
||||
extern u32int curpc;
|
||||
extern int irq;
|
||||
|
||||
extern int dmaact;
|
||||
extern uchar vram[];
|
||||
extern u16int pram[], oam[];
|
||||
extern u16int reg[];
|
||||
extern uchar *rom, *back;
|
||||
extern int nrom, nback, backup;
|
||||
|
||||
extern int ppux, ppuy;
|
||||
extern u8int bldy, blda, bldb;
|
||||
|
||||
extern int scale;
|
||||
|
||||
enum {
|
||||
DISPCNT = 0x0/2,
|
||||
DISPSTAT = 0x4/2,
|
||||
BG0CNT = 0x8/2,
|
||||
BG0HOFS = 0x10/2,
|
||||
BG0VOFS = 0x12/2,
|
||||
|
||||
BG2PA = 0x20/2,
|
||||
BG2PB = 0x22/2,
|
||||
BG2PC = 0x24/2,
|
||||
BG2PD = 0x26/2,
|
||||
BG2XL = 0x28/2,
|
||||
BG2XH = 0x2a/2,
|
||||
BG2YL = 0x2c/2,
|
||||
BG2YH = 0x2e/2,
|
||||
|
||||
WIN0H = 0x40/2,
|
||||
WIN1H = 0x42/2,
|
||||
WIN0V = 0x44/2,
|
||||
WIN1V = 0x46/2,
|
||||
WININ = 0x48/2,
|
||||
WINOUT = 0x4a/2,
|
||||
BLDCNT = 0x50/2,
|
||||
BLDALPHA = 0x52/2,
|
||||
BLDY = 0x54/2,
|
||||
|
||||
DMA0CNTH = 0xba/2,
|
||||
DMA1CNTH = 0xc6/2,
|
||||
DMA2CNTH = 0xd2/2,
|
||||
DMA3CNTH = 0xde/2,
|
||||
|
||||
KEYCNT = 0x132/2,
|
||||
|
||||
IE = 0x200/2,
|
||||
IF = 0x202/2,
|
||||
WAITCNT = 0x204/2,
|
||||
IME = 0x208/2,
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
/* DISPCNT */
|
||||
FRAME = 1<<4,
|
||||
HBLFREE = 1<<5,
|
||||
OBJNOMAT = 1<<6,
|
||||
FBLANK = 1<<7,
|
||||
|
||||
/* DISPSTAT */
|
||||
IRQVBLEN = 1<<3,
|
||||
IRQHBLEN = 1<<4,
|
||||
IRQVCTREN = 1<<5,
|
||||
|
||||
/* BGnCNT */
|
||||
BG8 = 1<<7,
|
||||
DISPWRAP = 1<<13,
|
||||
|
||||
/* DMAnCNTH */
|
||||
DMADCNT = 5,
|
||||
DMASCNT = 7,
|
||||
DMAREP = 1<<9,
|
||||
DMAWIDE = 1<<10,
|
||||
DMAWHEN = 12,
|
||||
DMAIRQ = 1<<14,
|
||||
DMAEN = 1<<15,
|
||||
|
||||
DMAINC = 0,
|
||||
DMADEC = 1,
|
||||
DMAFIX = 2,
|
||||
DMAINCREL = 3,
|
||||
|
||||
DMANOW = 0,
|
||||
DMAVBL = 1,
|
||||
DMAHBL = 2,
|
||||
DMASPEC = 3,
|
||||
DMASOUND = 4,
|
||||
DMAVIDEO = 5,
|
||||
|
||||
IRQVBL = 1<<0,
|
||||
IRQHBL = 1<<1,
|
||||
IRQVCTR = 1<<2,
|
||||
IRQTIM0 = 1<<3,
|
||||
IRQDMA0 = 1<<8,
|
||||
IRQKEY = 1<<12,
|
||||
|
||||
NOBACK = 0,
|
||||
SRAM = 1,
|
||||
EEPROM = 2,
|
||||
FLASH = 3,
|
||||
|
||||
KB = 1024,
|
||||
BACKTYPELEN = 64,
|
||||
};
|
13
sys/src/games/gba/fns.h
Normal file
13
sys/src/games/gba/fns.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
u32int memread(u32int, int, int);
|
||||
void memwrite(u32int, u32int, int);
|
||||
extern int (*step)(void);
|
||||
void reset(void);
|
||||
void memreset(void);
|
||||
void setif(u16int);
|
||||
void ppustep(void);
|
||||
void timerstep(int t);
|
||||
void flush(void);
|
||||
int dmastep(void);
|
||||
void dmastart(int);
|
||||
void flushback(void);
|
||||
void writeback(void);
|
439
sys/src/games/gba/gba.c
Normal file
439
sys/src/games/gba/gba.c
Normal file
|
@ -0,0 +1,439 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <mouse.h>
|
||||
#include <keyboard.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
int cpuhalt;
|
||||
int scale, profile;
|
||||
Rectangle picr;
|
||||
Image *bg, *tmp;
|
||||
Mousectl *mc;
|
||||
int keys, paused, framestep, backup;
|
||||
QLock pauselock;
|
||||
int savefd, saveframes;
|
||||
|
||||
char *biosfile = "/sys/games/lib/gbabios.bin";
|
||||
|
||||
int ppuclock;
|
||||
|
||||
void *
|
||||
emalloc(ulong sz)
|
||||
{
|
||||
void *v;
|
||||
|
||||
v = malloc(sz);
|
||||
if(v == nil)
|
||||
sysfatal("malloc: %r");
|
||||
setmalloctag(v, getcallerpc(&sz));
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
writeback(void)
|
||||
{
|
||||
if(saveframes == 0)
|
||||
saveframes = 15;
|
||||
}
|
||||
|
||||
void
|
||||
flushback(void)
|
||||
{
|
||||
if(savefd >= 0)
|
||||
pwrite(savefd, back, nback, BACKTYPELEN);
|
||||
saveframes = 0;
|
||||
}
|
||||
|
||||
void
|
||||
loadbios(void)
|
||||
{
|
||||
extern uchar bios[16384];
|
||||
|
||||
int fd;
|
||||
|
||||
fd = open(biosfile, OREAD);
|
||||
if(fd < 0)
|
||||
sysfatal("open: %r");
|
||||
readn(fd, bios, 16384);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
romtype(int *size)
|
||||
{
|
||||
u32int *p, n, v;
|
||||
union {char a[4]; u32int u;} s1 = {"EEPR"}, s2 = {"SRAM"}, s3 = {"FLAS"};
|
||||
|
||||
p = (u32int *) rom;
|
||||
n = nrom / 4;
|
||||
do{
|
||||
v = *p++;
|
||||
if(v == s1.u && memcmp(p - 1, "EEPROM_V", 8) == 0){
|
||||
print("backup type is either eeprom4 or eeprom64 -- can't detect which one\n");
|
||||
return NOBACK;
|
||||
}
|
||||
if(v == s2.u && memcmp(p - 1, "SRAM_V", 6) == 0){
|
||||
*size = 32*KB;
|
||||
return SRAM;
|
||||
}
|
||||
if(v == s3.u){
|
||||
if(memcmp(p - 1, "FLASH_V", 7) == 0 || memcmp(p - 1, "FLASH512_V", 10) == 0){
|
||||
*size = 64*KB;
|
||||
return FLASH;
|
||||
}
|
||||
if(memcmp(p - 1, "FLASH1M_V", 9) == 0){
|
||||
*size = 128*KB;
|
||||
return FLASH;
|
||||
}
|
||||
}
|
||||
}while(--n);
|
||||
return NOBACK;
|
||||
}
|
||||
|
||||
int
|
||||
parsetype(char *s, int *size)
|
||||
{
|
||||
if(strcmp(s, "eeprom4") == 0){
|
||||
*size = 512;
|
||||
return EEPROM;
|
||||
}else if(strcmp(s, "eeprom64") == 0){
|
||||
*size = 8*KB;
|
||||
return EEPROM;
|
||||
}else if(strcmp(s, "sram256") == 0){
|
||||
*size = 32*KB;
|
||||
return SRAM;
|
||||
}else if(strcmp(s, "flash512") == 0){
|
||||
*size = 64*KB;
|
||||
return FLASH;
|
||||
}else if(strcmp(s, "flash1024") == 0){
|
||||
*size = 128*KB;
|
||||
return FLASH;
|
||||
}else
|
||||
return NOBACK;
|
||||
}
|
||||
|
||||
void
|
||||
typename(char *s, int type, int size)
|
||||
{
|
||||
char *st;
|
||||
switch(type){
|
||||
case EEPROM:
|
||||
st = "eeprom";
|
||||
break;
|
||||
case FLASH:
|
||||
st = "flash";
|
||||
break;
|
||||
case SRAM:
|
||||
st = "sram";
|
||||
break;
|
||||
default:
|
||||
sysfatal("typestr: unknown type %d -- shouldn't happen", type);
|
||||
return;
|
||||
}
|
||||
snprint(s, BACKTYPELEN, "%s%d", st, size/128);
|
||||
}
|
||||
|
||||
void
|
||||
loadsave(char *file)
|
||||
{
|
||||
char *buf, *p;
|
||||
char tstr[BACKTYPELEN];
|
||||
int type, size;
|
||||
|
||||
buf = emalloc(strlen(file) + 4);
|
||||
strcpy(buf, file);
|
||||
p = strchr(buf, '.');
|
||||
if(p == nil)
|
||||
p = buf + strlen(buf);
|
||||
strcpy(p, ".sav");
|
||||
savefd = open(buf, ORDWR);
|
||||
if(savefd < 0){
|
||||
if(backup == NOBACK){
|
||||
backup = romtype(&nback);
|
||||
if(backup == NOBACK){
|
||||
fprint(2, "failed to autodetect save format\n");
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
savefd = create(buf, OWRITE, 0664);
|
||||
if(savefd < 0){
|
||||
fprint(2, "create: %r");
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
memset(tstr, 0, sizeof(tstr));
|
||||
typename(tstr, backup, nback);
|
||||
write(savefd, tstr, sizeof(tstr));
|
||||
back = emalloc(nback);
|
||||
memset(back, 0, nback);
|
||||
write(savefd, back, nback);
|
||||
free(buf);
|
||||
atexit(flushback);
|
||||
return;
|
||||
}
|
||||
readn(savefd, tstr, sizeof(tstr));
|
||||
tstr[31] = 0;
|
||||
type = parsetype(tstr, &size);
|
||||
if(type == NOBACK || backup != NOBACK && (type != backup || nback != size))
|
||||
sysfatal("%s: invalid format", buf);
|
||||
backup = type;
|
||||
nback = size;
|
||||
back = emalloc(nback);
|
||||
readn(savefd, back, nback);
|
||||
atexit(flushback);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void
|
||||
loadrom(char *file)
|
||||
{
|
||||
int fd;
|
||||
vlong sz;
|
||||
|
||||
fd = open(file, OREAD);
|
||||
if(fd < 0)
|
||||
sysfatal("open: %r");
|
||||
sz = seek(fd, 0, 2);
|
||||
if(sz <= 0 || sz >= 32*1024*1024)
|
||||
sysfatal("nope.jpg");
|
||||
seek(fd, 0, 0);
|
||||
nrom = sz;
|
||||
rom = emalloc(nrom);
|
||||
if(readn(fd, rom, sz) < sz)
|
||||
sysfatal("read: %r");
|
||||
close(fd);
|
||||
loadsave(file);
|
||||
if(nrom == 32*KB*KB && backup == EEPROM)
|
||||
nrom -= 256;
|
||||
}
|
||||
|
||||
void
|
||||
screeninit(void)
|
||||
{
|
||||
Point p;
|
||||
|
||||
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
||||
picr = (Rectangle){subpt(p, Pt(scale * 120, scale * 80)), addpt(p, Pt(scale * 120, scale * 80))};
|
||||
tmp = allocimage(display, Rect(0, 0, scale * 240, scale > 1 ? 1 : scale * 160), CHAN4(CIgnore, 1, CBlue, 5, CGreen, 5, CRed, 5), scale > 1, 0);
|
||||
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
||||
draw(screen, screen->r, bg, nil, ZP);
|
||||
}
|
||||
|
||||
void
|
||||
keyproc(void *)
|
||||
{
|
||||
int fd, k;
|
||||
static char buf[256];
|
||||
char *s;
|
||||
Rune r;
|
||||
|
||||
fd = open("/dev/kbd", OREAD);
|
||||
if(fd < 0)
|
||||
sysfatal("open: %r");
|
||||
for(;;){
|
||||
if(read(fd, buf, sizeof(buf) - 1) <= 0)
|
||||
sysfatal("read /dev/kbd: %r");
|
||||
if(buf[0] == 'c'){
|
||||
/*if(utfrune(buf, KF|5))
|
||||
savereq = 1;
|
||||
if(utfrune(buf, KF|6))
|
||||
loadreq = 1;*/
|
||||
if(utfrune(buf, Kdel)){
|
||||
close(fd);
|
||||
threadexitsall(nil);
|
||||
}
|
||||
if(utfrune(buf, 't'))
|
||||
trace = !trace;
|
||||
}
|
||||
if(buf[0] != 'k' && buf[0] != 'K')
|
||||
continue;
|
||||
s = buf + 1;
|
||||
k = 0;
|
||||
while(*s != 0){
|
||||
s += chartorune(&r, s);
|
||||
switch(r){
|
||||
case Kdel: close(fd); threadexitsall(nil);
|
||||
case 'z': k |= 1<<1; break;
|
||||
case 'x': k |= 1<<0; break;
|
||||
case 'a': k |= 1<<9; break;
|
||||
case 's': k |= 1<<8; break;
|
||||
case Kshift: k |= 1<<2; break;
|
||||
case 10: k |= 1<<3; break;
|
||||
case Kup: k |= 1<<6; break;
|
||||
case Kdown: k |= 1<<7; break;
|
||||
case Kleft: k |= 1<<5; break;
|
||||
case Kright: k |= 1<<4; break;
|
||||
case Kesc:
|
||||
if(paused)
|
||||
qunlock(&pauselock);
|
||||
else
|
||||
qlock(&pauselock);
|
||||
paused = !paused;
|
||||
break;
|
||||
case KF|1:
|
||||
if(paused){
|
||||
qunlock(&pauselock);
|
||||
paused=0;
|
||||
}
|
||||
framestep = !framestep;
|
||||
break;
|
||||
}
|
||||
}
|
||||
keys = k;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
timing(void)
|
||||
{
|
||||
static int fcount;
|
||||
static vlong old;
|
||||
static char buf[32];
|
||||
vlong new;
|
||||
|
||||
if(++fcount == 60)
|
||||
fcount = 0;
|
||||
else
|
||||
return;
|
||||
new = nsec();
|
||||
if(new != old)
|
||||
sprint(buf, "%6.2f%%", 1e11 / (new - old));
|
||||
else
|
||||
buf[0] = 0;
|
||||
draw(screen, rectaddpt(Rect(10, 10, 200, 30), screen->r.min), bg, nil, ZP);
|
||||
string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf);
|
||||
old = nsec();
|
||||
}
|
||||
|
||||
void
|
||||
flush(void)
|
||||
{
|
||||
extern uchar pic[];
|
||||
Mouse m;
|
||||
int x;
|
||||
|
||||
if(nbrecvul(mc->resizec) > 0){
|
||||
if(getwindow(display, Refnone) < 0)
|
||||
sysfatal("resize failed: %r");
|
||||
screeninit();
|
||||
}
|
||||
while(nbrecv(mc->c, &m) > 0)
|
||||
;
|
||||
if(scale == 1){
|
||||
loadimage(tmp, tmp->r, pic, 240*160*2);
|
||||
draw(screen, picr, tmp, nil, ZP);
|
||||
} else {
|
||||
Rectangle r;
|
||||
uchar *s;
|
||||
int w;
|
||||
|
||||
s = pic;
|
||||
r = picr;
|
||||
w = 240*2*scale;
|
||||
while(r.min.y < picr.max.y){
|
||||
loadimage(tmp, tmp->r, s, w);
|
||||
s += w;
|
||||
r.max.y = r.min.y+scale;
|
||||
draw(screen, r, tmp, nil, ZP);
|
||||
r.min.y = r.max.y;
|
||||
}
|
||||
}
|
||||
flushimage(display, 1);
|
||||
if(profile)
|
||||
timing();
|
||||
if(framestep){
|
||||
paused = 1;
|
||||
qlock(&pauselock);
|
||||
framestep = 0;
|
||||
}
|
||||
|
||||
if(saveframes > 0 && --saveframes == 0)
|
||||
flushback();
|
||||
|
||||
if((reg[KEYCNT] & 1<<14) != 0){
|
||||
x = reg[KEYCNT] & keys;
|
||||
if((reg[KEYCNT] & 1<<15) != 0){
|
||||
if(x == (reg[KEYCNT] & 0x3ff))
|
||||
setif(IRQKEY);
|
||||
}else
|
||||
if(x != 0)
|
||||
setif(IRQKEY);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [-23T] [-s savetype] [-b biosfile] rom\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
threadmain(int argc, char **argv)
|
||||
{
|
||||
char *s;
|
||||
int t;
|
||||
|
||||
scale = 1;
|
||||
ARGBEGIN {
|
||||
case '2':
|
||||
scale = 2;
|
||||
break;
|
||||
case '3':
|
||||
scale = 3;
|
||||
break;
|
||||
case 's':
|
||||
s = EARGF(usage());
|
||||
backup = parsetype(s, &nback);
|
||||
if(backup == NOBACK)
|
||||
sysfatal("unknown save type '%s'", s);
|
||||
break;
|
||||
case 'b':
|
||||
biosfile = strdup(EARGF(usage()));
|
||||
break;
|
||||
case 'T':
|
||||
profile++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
} ARGEND;
|
||||
if(argc < 1)
|
||||
usage();
|
||||
|
||||
loadbios();
|
||||
loadrom(argv[0]);
|
||||
|
||||
if(initdraw(nil, nil, nil) < 0)
|
||||
sysfatal("initdraw: %r");
|
||||
mc = initmouse(nil, screen);
|
||||
if(mc == nil)
|
||||
sysfatal("initmouse: %r");
|
||||
proccreate(keyproc, nil, mainstacksize);
|
||||
screeninit();
|
||||
|
||||
memreset();
|
||||
reset();
|
||||
for(;;){
|
||||
if(paused){
|
||||
qlock(&pauselock);
|
||||
qunlock(&pauselock);
|
||||
}
|
||||
if(dmaact)
|
||||
t = dmastep();
|
||||
else if(cpuhalt)
|
||||
t = 8;
|
||||
else
|
||||
t = step();
|
||||
ppuclock += t;
|
||||
while(ppuclock >= 4){
|
||||
ppustep();
|
||||
ppuclock -= 4;
|
||||
}
|
||||
timerstep(t);
|
||||
}
|
||||
}
|
665
sys/src/games/gba/mem.c
Normal file
665
sys/src/games/gba/mem.c
Normal file
|
@ -0,0 +1,665 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
uchar bios[16*KB], wram0[32*KB], wram1[256*KB];
|
||||
uchar vram[96*KB];
|
||||
u16int pram[512], oam[512];
|
||||
uchar *rom, *back;
|
||||
int nrom, nback;
|
||||
u16int reg[512];
|
||||
u16int tim[4];
|
||||
int timerclock;
|
||||
int dmaact;
|
||||
enum {
|
||||
DMASRC,
|
||||
DMADST,
|
||||
DMACNT
|
||||
};
|
||||
u32int dmar[16];
|
||||
u8int waitst[16] = {5, 5, 5, 5, 3, 5, 5, 9, 8, 10, 10, 14};
|
||||
|
||||
extern int cyc;
|
||||
|
||||
static int eepromread(void);
|
||||
static void eepromwrite(int);
|
||||
static u8int flashread(u16int);
|
||||
static void flashwrite(u16int, u8int);
|
||||
|
||||
static u32int
|
||||
arread(uchar *c, int n)
|
||||
{
|
||||
switch(n){
|
||||
default:
|
||||
return c[0];
|
||||
case 2:
|
||||
return c[0] | c[1] << 8;
|
||||
case 4:
|
||||
return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
arwrite(uchar *c, u32int v, int n)
|
||||
{
|
||||
switch(n){
|
||||
case 4:
|
||||
c[3] = v >> 24;
|
||||
c[2] = v >> 16;
|
||||
case 2:
|
||||
c[1] = v >> 8;
|
||||
default:
|
||||
c[0] = v;
|
||||
}
|
||||
}
|
||||
|
||||
static u32int
|
||||
ar16read(u16int *c, int h, int n)
|
||||
{
|
||||
switch(n){
|
||||
case 1:
|
||||
return c[0] >> (h << 3);
|
||||
default:
|
||||
return c[0];
|
||||
case 4:
|
||||
return c[0] | c[1] << 16;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ar16write(u16int *c, int h, u32int v, int n)
|
||||
{
|
||||
switch(n){
|
||||
case 1:
|
||||
if(h)
|
||||
c[0] = c[0] & 0xff | ((u8int)v) << 8;
|
||||
else
|
||||
c[0] = c[0] & 0xff00 | (u8int)v;
|
||||
break;
|
||||
case 2:
|
||||
c[0] = v;
|
||||
break;
|
||||
case 4:
|
||||
c[0] = v;
|
||||
c[1] = v >> 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u32int
|
||||
regread(u32int a)
|
||||
{
|
||||
u32int v;
|
||||
|
||||
switch(a){
|
||||
case DISPSTAT*2:
|
||||
v = reg[a/2] & ~7;
|
||||
|
||||
if(ppuy >= 160 && ppuy != 227)
|
||||
v |= 1;
|
||||
if(ppux >= 240)
|
||||
v |= 2;
|
||||
if(ppuy == v >> 8)
|
||||
v |= 4;
|
||||
return v;
|
||||
case 0x006:
|
||||
return ppuy;
|
||||
case 0x100: case 0x104: case 0x108: case 0x10c:
|
||||
return tim[(a - 0x100) / 4];
|
||||
case 0x130:
|
||||
return keys ^ 0x3ff;
|
||||
default:
|
||||
return reg[a/2];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
regwrite16(u32int a, u16int v)
|
||||
{
|
||||
u16int *p;
|
||||
int i;
|
||||
static u8int ws0[4] = {5,4,3,9};
|
||||
|
||||
p = ®[a/2];
|
||||
switch(a){
|
||||
case IF*2:
|
||||
*p &= ~v;
|
||||
setif(0);
|
||||
return;
|
||||
case BLDALPHA*2:
|
||||
blda = v & 0x1f;
|
||||
if(blda > 16)
|
||||
blda = 16;
|
||||
bldb = v >> 8 & 0x1f;
|
||||
if(bldb > 16)
|
||||
bldb = 16;
|
||||
break;
|
||||
case BLDY*2:
|
||||
bldy = v & 0x1f;
|
||||
if(bldy > 16)
|
||||
bldy = 16;
|
||||
break;
|
||||
case DMA0CNTH*2: case DMA1CNTH*2: case DMA2CNTH*2: case DMA3CNTH*2:
|
||||
if((*p & DMAEN) == 0 && (v & DMAEN) != 0){
|
||||
i = (a - DMA0CNTH*2) / 12;
|
||||
if((v >> DMAWHEN & 3) == 0)
|
||||
dmaact |= 1<<i;
|
||||
if(i == 3 && (v >> DMAWHEN & 3) == 3)
|
||||
print("DMA video capture mode\n");
|
||||
dmar[4*i + DMASRC] = p[-5] | p[-4] << 16;
|
||||
dmar[4*i + DMADST] = p[-3] | p[-2] << 16;
|
||||
dmar[4*i + DMACNT] = p[-1];
|
||||
}
|
||||
break;
|
||||
case 0x102: case 0x106: case 0x10a: case 0x10e:
|
||||
if((*p & 1<<7) == 0 && (v & 1<<7) != 0)
|
||||
tim[(a-0x102)/4] = p[-1];
|
||||
break;
|
||||
case IME*2: case IE*2:
|
||||
setif(0);
|
||||
break;
|
||||
case WAITCNT*2:
|
||||
waitst[3] = waitst[7] = ws0[v & 3];
|
||||
waitst[0] = ws0[v >> 2 & 3];
|
||||
waitst[4] = ((v & 1<<4) == 0) + 2;
|
||||
waitst[1] = ws0[v >> 5 & 3];
|
||||
waitst[5] = (v & 1<<7) == 0 ? 5 : 2;
|
||||
waitst[2] = ws0[v >> 8 & 3];
|
||||
waitst[6] = (v & 1<<10) == 0 ? 9 : 2;
|
||||
for(i = 0; i < 8; i++)
|
||||
waitst[8 + i] = waitst[i] + waitst[i | 4];
|
||||
break;
|
||||
case 0x301:
|
||||
cpuhalt = 1;
|
||||
break;
|
||||
}
|
||||
*p = v;
|
||||
}
|
||||
|
||||
static void
|
||||
regwrite(u32int a, u32int v, int n)
|
||||
{
|
||||
u16int w;
|
||||
|
||||
switch(n){
|
||||
case 1:
|
||||
if((a & ~1) == IF)
|
||||
w = 0;
|
||||
else
|
||||
w = regread(a);
|
||||
if((a & 1) == 0)
|
||||
w = w & 0xff00 | (u8int)v;
|
||||
else
|
||||
w = w & 0xff | v << 8;
|
||||
regwrite16(a, w);
|
||||
break;
|
||||
default:
|
||||
if((a & 1) != 0)
|
||||
sysfatal("unaligned register access");
|
||||
regwrite16(a, v);
|
||||
break;
|
||||
case 4:
|
||||
if((a & 1) != 0)
|
||||
sysfatal("unaligned register access");
|
||||
regwrite16(a, v);
|
||||
regwrite16(a + 2, v >> 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
setif(u16int v)
|
||||
{
|
||||
reg[IF] |= v;
|
||||
irq = (reg[IME] & 1) != 0 && (reg[IF] & reg[IE]) != 0;
|
||||
if(irq)
|
||||
cpuhalt = 0;
|
||||
}
|
||||
|
||||
u32int
|
||||
memread(u32int a, int n, int seq)
|
||||
{
|
||||
u32int b;
|
||||
assert((a & n-1) == 0);
|
||||
|
||||
switch(a >> 24){
|
||||
case 0:
|
||||
b = a & sizeof(bios) - 1;
|
||||
cyc++;
|
||||
return arread(bios + b, n);
|
||||
case 2:
|
||||
b = a & sizeof(wram1) - 1;
|
||||
cyc += n > 2 ? 6 : 3;
|
||||
return arread(wram1 + b, n);
|
||||
case 3:
|
||||
b = a & sizeof(wram0) - 1;
|
||||
cyc++;
|
||||
return arread(wram0 + b, n);
|
||||
case 4:
|
||||
b = a & 0xffffff;
|
||||
if(b >= sizeof(reg)) goto fault;
|
||||
cyc++;
|
||||
if(n == 4)
|
||||
return regread(b) | regread(b+2) << 16;
|
||||
return regread(b);
|
||||
case 5:
|
||||
b = a & sizeof(pram) - 1;
|
||||
cyc += (n+1) >> 1;
|
||||
return ar16read(pram + b/2, b & 1, n);
|
||||
case 6:
|
||||
b = a & 128*KB - 1;
|
||||
if(b >= 64*KB)
|
||||
b &= ~(32*KB);
|
||||
cyc += (n+1) >> 1;
|
||||
return arread(vram + b, n);
|
||||
case 7:
|
||||
b = a & sizeof(oam) - 1;
|
||||
cyc++;
|
||||
return ar16read(oam + b/2, b & 1, n);
|
||||
case 8: case 9: case 10: case 11: case 12: case 13:
|
||||
b = a & 0x1ffffff;
|
||||
cyc += waitst[(a >> 25) - 4 | seq << 2 | (n > 2) << 3];
|
||||
if(b >= nrom){
|
||||
if(backup == EEPROM && b >= 0x1000000 && (nrom < 16*KB*KB || b >= 0x1ffff00))
|
||||
return eepromread();
|
||||
return 0;
|
||||
}
|
||||
return arread(rom + b, n);
|
||||
case 14:
|
||||
if(backup == SRAM){
|
||||
b = a & nback - 1;
|
||||
return arread(back + b, n);
|
||||
}
|
||||
if(backup == FLASH)
|
||||
return flashread(a);
|
||||
return 0;
|
||||
default:
|
||||
fault:
|
||||
sysfatal("read from %#.8ux (pc=%#.8ux)", a, curpc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
memwrite(u32int a, u32int v, int n)
|
||||
{
|
||||
u32int b;
|
||||
assert((a & n-1) == 0);
|
||||
|
||||
switch(a >> 24){
|
||||
case 0:
|
||||
return;
|
||||
case 2:
|
||||
b = a & sizeof(wram1) - 1;
|
||||
cyc += n > 2 ? 6 : 3;
|
||||
arwrite(wram1 + b, v, n);
|
||||
return;
|
||||
case 3:
|
||||
b = a & sizeof(wram0) - 1;
|
||||
cyc++;
|
||||
arwrite(wram0 + b, v, n);
|
||||
return;
|
||||
case 4:
|
||||
cyc++;
|
||||
b = a & 0xffffff;
|
||||
if(b == 0x410) return;
|
||||
if(b >= sizeof(reg)) goto fault;
|
||||
regwrite(b, v, n);
|
||||
return;
|
||||
case 5:
|
||||
b = a & sizeof(pram) - 1;
|
||||
cyc += (n+1) >> 1;
|
||||
ar16write(pram + b/2, b & 1, v, n);
|
||||
return;
|
||||
case 6:
|
||||
b = a & 128*KB - 1;
|
||||
if(b >= 64*KB)
|
||||
b &= ~(32*KB);
|
||||
cyc += (n+1) >> 1;
|
||||
arwrite(vram + b, v, n);
|
||||
return;
|
||||
case 7:
|
||||
b = a & sizeof(oam) - 1;
|
||||
cyc++;
|
||||
ar16write(oam + b/2, b & 1, v, n);
|
||||
return;
|
||||
case 8: case 9: case 10: case 11: case 12: case 13:
|
||||
if(backup == EEPROM){
|
||||
b = a & 0x01ffffff;
|
||||
if(b >= 0x1000000 && (nrom < 16*KB*KB || b >= 0x1ffff00))
|
||||
eepromwrite(v & 1);
|
||||
}
|
||||
return;
|
||||
case 14:
|
||||
if(backup == SRAM){
|
||||
b = a & nback - 1;
|
||||
arwrite(back + b, v, n);
|
||||
writeback();
|
||||
return;
|
||||
}
|
||||
if(backup == FLASH){
|
||||
flashwrite(a, v);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
default:
|
||||
fault:
|
||||
sysfatal("write to %#.8ux, value %#.8ux (pc=%#.8ux)", a, v, curpc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
memreset(void)
|
||||
{
|
||||
reg[0x88/2] = 0x200;
|
||||
}
|
||||
|
||||
void
|
||||
timerstep(int t)
|
||||
{
|
||||
int i, carry;
|
||||
u16int c;
|
||||
u16int nt;
|
||||
|
||||
nt = -t;
|
||||
carry = 0;
|
||||
timerclock += t;
|
||||
for(i = 0; i < 4; i++){
|
||||
c = reg[0x102/2 + i*2];
|
||||
if((c & 1<<7) == 0)
|
||||
goto next;
|
||||
if((c & 1<<2) == 0)
|
||||
switch(c & 3){
|
||||
case 1:
|
||||
if((timerclock & 63) != 0)
|
||||
goto next;
|
||||
break;
|
||||
case 2:
|
||||
if((timerclock & 255) != 0)
|
||||
goto next;
|
||||
break;
|
||||
case 3:
|
||||
if((timerclock & 1023) != 0)
|
||||
goto next;
|
||||
break;
|
||||
}
|
||||
else
|
||||
if(!carry)
|
||||
goto next;
|
||||
if(carry = tim[i] >= nt){
|
||||
tim[i] += reg[0x100/2 + i*2];
|
||||
if((c & 1<<6) != 0)
|
||||
setif(IRQTIM0 << i);
|
||||
}
|
||||
tim[i] += t;
|
||||
continue;
|
||||
next:
|
||||
carry = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dmastep(void)
|
||||
{
|
||||
int i;
|
||||
u16int *cntp, cnt;
|
||||
u32int *dr;
|
||||
u32int v;
|
||||
int sz;
|
||||
|
||||
cyc = 0;
|
||||
for(i = 0; i < 4; i++)
|
||||
if((dmaact & 1<<i) != 0)
|
||||
break;
|
||||
if(i == 4)
|
||||
return cyc;
|
||||
curpc = -1;
|
||||
cntp = reg + DMA0CNTH + i * 6;
|
||||
cnt = *cntp;
|
||||
dr = dmar + 4 * i;
|
||||
|
||||
sz = (cnt & DMAWIDE) != 0 ? 4 : 2;
|
||||
if(i == 0)
|
||||
dr[DMASRC] &= 0x07FFFFFF;
|
||||
else
|
||||
dr[DMASRC] &= 0x0FFFFFFF;
|
||||
if(i != 3)
|
||||
dr[DMADST] &= 0x7FFFFFFF;
|
||||
else
|
||||
dr[DMADST] &= 0x0FFFFFFF;
|
||||
v = memread(dr[DMASRC] & -sz, sz, 1);
|
||||
memwrite(dr[DMADST] & -sz, v, sz);
|
||||
switch(cnt >> DMADCNT & 3){
|
||||
case DMAINC: case DMAINCREL: dr[DMADST] += sz; break;
|
||||
case DMADEC: dr[DMADST] -= sz; break;
|
||||
}
|
||||
switch(cnt >> DMASCNT & 3){
|
||||
case DMAINC: dr[DMASRC] += sz; break;
|
||||
case DMADEC: dr[DMASRC] -= sz; break;
|
||||
}
|
||||
if(dr[DMACNT] == 0)
|
||||
dr[DMACNT] = i != 3 ? 0x4000 : 0x10000;
|
||||
if(--dr[DMACNT] == 0){
|
||||
dmaact &= ~(1<<i);
|
||||
if((cnt & DMAREP) != 0){
|
||||
dmar[DMACNT] = cntp[-1];
|
||||
if((cnt >> DMADCNT & 3) == DMAINCREL)
|
||||
dmar[DMADST] = cntp[-3] | cntp[-2] << 16;
|
||||
}else
|
||||
*cntp &= ~DMAEN;
|
||||
if((cnt & DMAIRQ) != 0)
|
||||
setif(IRQDMA0 << i);
|
||||
}
|
||||
return cyc;
|
||||
}
|
||||
|
||||
void
|
||||
dmastart(int cond)
|
||||
{
|
||||
int i;
|
||||
u16int *cntp, cnt, c;
|
||||
|
||||
cntp = reg + DMA0CNTH;
|
||||
for(i = 0; i < 3; i++, cntp += 6){
|
||||
cnt = *cntp;
|
||||
if((cnt & DMAEN) == 0)
|
||||
continue;
|
||||
c = cnt >> DMAWHEN & 3;
|
||||
if(c == 3)
|
||||
c += (i + 1) / 2;
|
||||
if(c == cond)
|
||||
dmaact |= 1<<i;
|
||||
}
|
||||
}
|
||||
|
||||
int eepromstate, eeprompos, eepromaddr;
|
||||
u64int eepromdata;
|
||||
|
||||
enum {
|
||||
EEPROMCMD,
|
||||
EEPROMRDCMD,
|
||||
EEPROMRDRESP,
|
||||
EEPROMWRCMD,
|
||||
EEPROMWRDATA,
|
||||
EEPROMWRRESP,
|
||||
};
|
||||
|
||||
static int
|
||||
eepromread(void)
|
||||
{
|
||||
int v;
|
||||
|
||||
switch(eepromstate){
|
||||
case EEPROMRDRESP:
|
||||
eeprompos++;
|
||||
if(eeprompos <= 4)
|
||||
return 0;
|
||||
if(eeprompos == 68){
|
||||
eepromstate = EEPROMCMD;
|
||||
eeprompos = 0;
|
||||
}
|
||||
v = eepromdata >> 63;
|
||||
eepromdata <<= 1;
|
||||
return v;
|
||||
case EEPROMWRRESP:
|
||||
if(++eeprompos == 1000){
|
||||
eepromstate = EEPROMCMD;
|
||||
eeprompos = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
eepromwrite(int n)
|
||||
{
|
||||
uchar *p;
|
||||
|
||||
switch(eepromstate){
|
||||
case EEPROMCMD:
|
||||
eepromaddr = eepromaddr << 1 | n;
|
||||
if(++eeprompos >= 2){
|
||||
switch(eepromaddr & 3){
|
||||
case 2:
|
||||
eepromstate = EEPROMWRCMD;
|
||||
break;
|
||||
case 3:
|
||||
eepromstate = EEPROMRDCMD;
|
||||
break;
|
||||
}
|
||||
eeprompos = 0;
|
||||
}
|
||||
break;
|
||||
case EEPROMRDCMD:
|
||||
case EEPROMWRCMD:
|
||||
eepromaddr = eepromaddr << 1 | n;
|
||||
eeprompos++;
|
||||
if(nback == 512){
|
||||
if(eeprompos >= 7)
|
||||
eepromaddr = eepromaddr >> 1 & 0x3f;
|
||||
else
|
||||
break;
|
||||
}else{
|
||||
if(eeprompos >= 15)
|
||||
eepromaddr = eepromaddr >> 1 & 0x3fff;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(eepromstate == EEPROMRDCMD){
|
||||
p = back + eepromaddr * 8;
|
||||
eepromdata = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24 | (u64int)p[4] << 32 |
|
||||
(u64int)p[5] << 40 | (u64int)p[6] << 48 | (u64int)p[7] << 56;
|
||||
eeprompos = 0;
|
||||
eepromstate = EEPROMRDRESP;
|
||||
break;
|
||||
}else{
|
||||
eepromdata = n;
|
||||
eeprompos = 1;
|
||||
eepromstate = EEPROMWRDATA;
|
||||
break;
|
||||
}
|
||||
case EEPROMWRDATA:
|
||||
if(eeprompos == 64){
|
||||
p = back + eepromaddr * 8;
|
||||
p[0] = eepromdata;
|
||||
p[1] = eepromdata >> 8;
|
||||
p[2] = eepromdata >> 16;
|
||||
p[3] = eepromdata >> 24;
|
||||
p[4] = eepromdata >> 32;
|
||||
p[5] = eepromdata >> 40;
|
||||
p[6] = eepromdata >> 48;
|
||||
p[7] = eepromdata >> 56;
|
||||
eepromstate = EEPROMWRRESP;
|
||||
eeprompos = 0;
|
||||
writeback();
|
||||
break;
|
||||
}
|
||||
eepromdata = eepromdata << 1 | n;
|
||||
eeprompos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int flashstate, flashmode, flashbank;
|
||||
|
||||
enum {
|
||||
FLASHCMD0,
|
||||
FLASHCMD1,
|
||||
FLASHCMD2,
|
||||
FLASHBANK,
|
||||
FLASHWRITE,
|
||||
|
||||
FLASHID = 1,
|
||||
FLASHERASE = 2,
|
||||
};
|
||||
|
||||
static u8int
|
||||
flashread(u16int a)
|
||||
{
|
||||
if((flashmode & FLASHID) != 0)
|
||||
return (a & 1) != 0 ? 0xd4 : 0xbf;
|
||||
return back[(flashbank << 16) + a];
|
||||
}
|
||||
|
||||
static void
|
||||
flashwrite(u16int a, u8int v)
|
||||
{
|
||||
int erase;
|
||||
|
||||
switch(flashstate){
|
||||
case FLASHCMD0:
|
||||
if(a == 0x5555 && v == 0xaa)
|
||||
flashstate = FLASHCMD1;
|
||||
break;
|
||||
case FLASHCMD1:
|
||||
if(a == 0x2aaa && v == 0x55)
|
||||
flashstate = FLASHCMD2;
|
||||
else
|
||||
flashstate = FLASHCMD0;
|
||||
break;
|
||||
case FLASHCMD2:
|
||||
flashstate = FLASHCMD0;
|
||||
erase = flashmode & FLASHERASE;
|
||||
flashmode &= ~FLASHERASE;
|
||||
switch(v){
|
||||
case 0x90: flashmode |= FLASHID; break;
|
||||
case 0xF0: flashmode &= ~FLASHID; break;
|
||||
case 0x80: flashmode |= FLASHERASE; break;
|
||||
case 0x10:
|
||||
if(erase){
|
||||
memset(back, 0xff, nback);
|
||||
writeback();
|
||||
}
|
||||
break;
|
||||
case 0x30:
|
||||
if(erase){
|
||||
memset(back + (a & 0xf000) + (flashbank << 16), 0xff, 4096);
|
||||
writeback();
|
||||
}
|
||||
break;
|
||||
case 0xA0:
|
||||
writeback();
|
||||
flashstate = FLASHWRITE;
|
||||
break;
|
||||
case 0xB0: flashstate = FLASHBANK; break;
|
||||
default:
|
||||
print("unknown flash cmd %x\n", v);
|
||||
}
|
||||
break;
|
||||
case FLASHBANK:
|
||||
flashbank = v % (nback >> 16);
|
||||
flashstate = FLASHCMD0;
|
||||
break;
|
||||
case FLASHWRITE:
|
||||
back[(flashbank << 16) + a] &= v;
|
||||
writeback();
|
||||
flashstate = FLASHCMD0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
13
sys/src/games/gba/mkfile
Normal file
13
sys/src/games/gba/mkfile
Normal file
|
@ -0,0 +1,13 @@
|
|||
</$objtype/mkfile
|
||||
|
||||
BIN=/$objtype/bin/games
|
||||
TARG=gba
|
||||
OFILES=\
|
||||
cpu.$O\
|
||||
mem.$O\
|
||||
gba.$O\
|
||||
ppu.$O\
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
</sys/src/cmd/mkone
|
653
sys/src/games/gba/ppu.c
Normal file
653
sys/src/games/gba/ppu.c
Normal file
|
@ -0,0 +1,653 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
int ppux, ppuy;
|
||||
uchar pic[240*160*2*3*3];
|
||||
u8int bldy, blda, bldb;
|
||||
|
||||
typedef struct bg bg;
|
||||
struct bg {
|
||||
uchar n;
|
||||
uchar depth;
|
||||
|
||||
s32int rpx0, rpy0, rpx, rpy;
|
||||
s32int sx, sy;
|
||||
|
||||
u16int tx, ty;
|
||||
u8int tnx, tny;
|
||||
u16int t;
|
||||
u8int *chr;
|
||||
u16int *pal;
|
||||
};
|
||||
static u8int mode=-1;
|
||||
static bg bgst[4] = {{.n = 0}, {.n = 1}, {.n = 2}, {.n = 3}};
|
||||
static u32int pixeldat[2], pixelpri[2];
|
||||
static u16int bgmask;
|
||||
static u8int objwin, objtrans;
|
||||
|
||||
typedef struct sprite sprite;
|
||||
struct sprite {
|
||||
uchar w, wb, h;
|
||||
s16int x;
|
||||
uchar ysh;
|
||||
|
||||
uchar *base;
|
||||
u16int *pal;
|
||||
u16int inc;
|
||||
|
||||
u32int t0;
|
||||
u16int t1;
|
||||
uchar depth;
|
||||
|
||||
s32int rx, ry;
|
||||
s16int dx, dy;
|
||||
};
|
||||
static sprite sprt[128], *sp = sprt;
|
||||
enum {
|
||||
SPRROT = 1<<8,
|
||||
SPRDIS = 1<<9,
|
||||
SPRDOUB = 1<<9,
|
||||
SPR8 = 1<<13,
|
||||
SPRWIDE = 1<<14,
|
||||
SPRTALL = 1<<15,
|
||||
SPRHFLIP = 1<<28,
|
||||
SPRVFLIP = 1<<29,
|
||||
SPRSIZE0 = 1<<30,
|
||||
SPRSIZE1 = 1<<31
|
||||
};
|
||||
|
||||
void
|
||||
pixeldraw(int x, int y, u16int v)
|
||||
{
|
||||
uchar *p;
|
||||
u16int *q;
|
||||
union { u16int w; u8int b[2]; } u;
|
||||
|
||||
if(scale == 1){
|
||||
p = pic + (x + y * 240) * 2;
|
||||
p[0] = v;
|
||||
p[1] = v >> 8;
|
||||
return;
|
||||
}
|
||||
u.b[0] = v;
|
||||
u.b[1] = v >> 8;
|
||||
if(scale == 2){
|
||||
q = (u16int*)pic + (x + y * 240) * 2;
|
||||
q[0] = u.w;
|
||||
q[1] = u.w;
|
||||
}else{
|
||||
q = (u16int*)pic + (x + y * 240) * 3;
|
||||
q[0] = u.w;
|
||||
q[1] = u.w;
|
||||
q[2] = u.w;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pixel(u16int c, int n, int p)
|
||||
{
|
||||
if(p < pixelpri[0]){
|
||||
pixeldat[1] = pixeldat[0];
|
||||
pixelpri[1] = pixelpri[0];
|
||||
pixelpri[0] = p;
|
||||
pixeldat[0] = c | n << 16;
|
||||
}else if(p < pixelpri[1]){
|
||||
pixelpri[1] = p;
|
||||
pixeldat[1] = c | n << 16;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tile(bg *b)
|
||||
{
|
||||
u16int bgcnt, ta, tx, ty, y, t;
|
||||
u8int d;
|
||||
u8int *chr;
|
||||
|
||||
bgcnt = reg[BG0CNT + b->n];
|
||||
d = bgcnt >> 7 & 1;
|
||||
tx = b->tx;
|
||||
ty = b->ty;
|
||||
ta = (bgcnt << 3 & 0xf800) + ((tx & 0x1f) << 1) + ((ty & 0x1f) << 6);
|
||||
switch(bgcnt >> 14){
|
||||
case 1: ta += tx << 6 & 0x800; break;
|
||||
case 2: ta += ty << 6 & 0x800; break;
|
||||
case 3: ta += tx << 6 & 0x800 | ty << 7 & 0x1000; break;
|
||||
}
|
||||
t = vram[ta] | vram[ta+1] << 8;
|
||||
b->t = t;
|
||||
chr = vram + (bgcnt << 12 & 0xc000) + ((t & 0x3ff) << 5+d);
|
||||
y = b->tny;
|
||||
if((t & 1<<11) != 0)
|
||||
y ^= 7;
|
||||
chr = chr + (y << 2+d);
|
||||
b->chr = chr;
|
||||
if(d != 0)
|
||||
b->pal = pram;
|
||||
else
|
||||
b->pal = pram + (t >> 8 & 0xf0);
|
||||
}
|
||||
|
||||
void
|
||||
bginit(bg *b, int scal, int bit)
|
||||
{
|
||||
u16int cnt, x, y;
|
||||
u16int *rr;
|
||||
|
||||
cnt = reg[DISPCNT];
|
||||
if(scal){
|
||||
rr = reg + (b->n - 2 << 3);
|
||||
if(ppuy == 0){
|
||||
b->rpx0 = (s32int)(rr[BG2XL] | rr[BG2XH] << 16) << 4 >> 4;
|
||||
b->rpy0 = (s32int)(rr[BG2YL] | rr[BG2YH] << 16) << 4 >> 4;
|
||||
}
|
||||
b->rpx = b->rpx0;
|
||||
b->rpy = b->rpy0;
|
||||
b->rpx0 += (s16int)rr[BG2PB];
|
||||
b->rpy0 += (s16int)rr[BG2PD];
|
||||
switch(cnt & 7){
|
||||
case 3:
|
||||
case 4:
|
||||
b->sx = 240 << 8;
|
||||
b->sy = 160 << 8;
|
||||
b->depth = (cnt & 7) == 3;
|
||||
break;
|
||||
case 5:
|
||||
b->sx = 160 << 8;
|
||||
b->sy = 128 << 8;
|
||||
b->depth = 1;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
rr = reg + (b->n << 1);
|
||||
x = rr[BG0HOFS] & 0x1ff;
|
||||
y = (rr[BG0VOFS] & 0x1ff) + ppuy;
|
||||
b->tx = x >> 3;
|
||||
b->ty = y >> 3;
|
||||
b->tnx = x & 7;
|
||||
b->tny = y & 7;
|
||||
tile(b);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bgsinit(void)
|
||||
{
|
||||
mode = reg[DISPCNT] & 7;
|
||||
switch(mode){
|
||||
case 0:
|
||||
bginit(&bgst[0], 0, 0);
|
||||
bginit(&bgst[1], 0, 0);
|
||||
bginit(&bgst[2], 0, 0);
|
||||
bginit(&bgst[3], 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
bginit(&bgst[0], 0, 0);
|
||||
bginit(&bgst[1], 0, 0);
|
||||
bginit(&bgst[2], 1, 0);
|
||||
break;
|
||||
case 2:
|
||||
bginit(&bgst[2], 1, 0);
|
||||
bginit(&bgst[3], 1, 0);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
bginit(&bgst[2], 1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bitbg(bg *b)
|
||||
{
|
||||
u16int cnt;
|
||||
int v;
|
||||
uchar *p;
|
||||
u16int *rr;
|
||||
uchar *base;
|
||||
|
||||
cnt = reg[DISPCNT];
|
||||
rr = reg - 8 + (b->n << 3);
|
||||
if((bgmask & 1<<b->n) == 0)
|
||||
goto next;
|
||||
if(b->rpx >= 0 && b->rpy >= 0 && b->rpx <= b->sx && b->rpy <= b->sy){
|
||||
base = vram;
|
||||
if((cnt & FRAME) != 0 && (cnt & 7) != 3)
|
||||
base += 0xa000;
|
||||
if(b->depth){
|
||||
p = base + 2 * (b->rpx >> 8) + 480 * (b->rpy >> 8);
|
||||
v = p[0] | p[1] << 8;
|
||||
}else{
|
||||
v = base[(b->rpx >> 8) + 240 * (b->rpy >> 8)];
|
||||
if(v != 0)
|
||||
v = pram[v];
|
||||
else
|
||||
v = -1;
|
||||
}
|
||||
}else
|
||||
v = -1;
|
||||
if(v >= 0)
|
||||
pixel(v, b->n, reg[BG0CNT + b->n] & 3);
|
||||
next:
|
||||
b->rpx += (s16int) rr[BG2PA];
|
||||
b->rpy += (s16int) rr[BG2PC];
|
||||
}
|
||||
|
||||
void
|
||||
rotbg(bg *b)
|
||||
{
|
||||
u16int *rr, ta;
|
||||
u16int bgcnt;
|
||||
int row, sz, x, y;
|
||||
uchar *p, v;
|
||||
|
||||
rr = reg - 8 + (b->n << 3);
|
||||
if((bgmask & 1<<b->n) == 0)
|
||||
goto next;
|
||||
bgcnt = reg[BG0CNT + b->n];
|
||||
row = (bgcnt >> 14) + 4;
|
||||
sz = 1 << 3 + row;
|
||||
x = b->rpx >> 8;
|
||||
y = b->rpy >> 8;
|
||||
if((bgcnt & DISPWRAP) != 0){
|
||||
x &= sz - 1;
|
||||
y &= sz - 1;
|
||||
}else if((uint)x >= sz || (uint)y >= sz)
|
||||
goto next;
|
||||
ta = (bgcnt << 3 & 0xf800) + ((y >> 3) << row) + (x >> 3);
|
||||
p = vram + (bgcnt << 12 & 0xc000) + (vram[ta] << 6);
|
||||
p += (x & 7) + ((y & 7) << 3);
|
||||
if((v = *p) != 0)
|
||||
pixel(pram[v], b->n, bgcnt & 3);
|
||||
next:
|
||||
b->rpx += (s16int) rr[BG2PA];
|
||||
b->rpy += (s16int) rr[BG2PC];
|
||||
}
|
||||
|
||||
void
|
||||
txtbg(bg *b)
|
||||
{
|
||||
u16int bgcnt;
|
||||
u8int x, v;
|
||||
|
||||
bgcnt = reg[BG0CNT + b->n];
|
||||
if((bgmask & 1<<b->n) == 0)
|
||||
goto next;
|
||||
x = b->tnx;
|
||||
if((b->t & 1<<10) != 0)
|
||||
x ^= 7;
|
||||
if((bgcnt & BG8) != 0)
|
||||
v = b->chr[x];
|
||||
else{
|
||||
v = b->chr[x>>1];
|
||||
if((x & 1) != 0)
|
||||
v >>= 4;
|
||||
else
|
||||
v &= 0xf;
|
||||
}
|
||||
if(v != 0)
|
||||
pixel(b->pal[v], b->n, bgcnt & 3);
|
||||
next:
|
||||
if(++b->tnx == 8){
|
||||
b->tnx = 0;
|
||||
b->tx++;
|
||||
tile(b);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bgs(void)
|
||||
{
|
||||
switch(mode){
|
||||
case 0:
|
||||
txtbg(&bgst[0]);
|
||||
txtbg(&bgst[1]);
|
||||
txtbg(&bgst[2]);
|
||||
txtbg(&bgst[3]);
|
||||
break;
|
||||
case 1:
|
||||
txtbg(&bgst[0]);
|
||||
txtbg(&bgst[1]);
|
||||
rotbg(&bgst[2]);
|
||||
break;
|
||||
case 2:
|
||||
rotbg(&bgst[2]);
|
||||
rotbg(&bgst[3]);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
bitbg(&bgst[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sprinit(void)
|
||||
{
|
||||
u16int *p, *pp;
|
||||
u16int cnt, t1;
|
||||
u32int t0;
|
||||
int budg;
|
||||
uchar ws, h, hb, d, dy, s;
|
||||
static uchar wss[16] = {3, 4, 5, 6, 4, 5, 5, 6, 3, 3, 4, 5};
|
||||
static uchar hss[16] = {3, 4, 5, 6, 3, 3, 4, 5, 4, 5, 5, 6};
|
||||
|
||||
sp = sprt;
|
||||
cnt = reg[DISPCNT];
|
||||
budg = (cnt & HBLFREE) != 0 ? 954 : 1210;
|
||||
for(p = oam; p < oam + 512; p += 4){
|
||||
t0 = p[0];
|
||||
if((t0 & (SPRROT|SPRDIS)) == SPRDIS)
|
||||
continue;
|
||||
t0 |= p[1] << 16;
|
||||
s = t0 >> 30 & 3 | t0 >> 12 & 12;
|
||||
hb = h = 1 << hss[s];
|
||||
dy = ppuy - (u8int) t0;
|
||||
if((t0 & (SPRROT|SPRDOUB)) == (SPRROT|SPRDOUB))
|
||||
hb <<= 1;
|
||||
if(dy >= hb || (u8int)t0 + hb > 256 && ppuy + 256 - (u8int)t0 >= hb)
|
||||
continue;
|
||||
sp->x = (s32int)(t0 << 7) >> 23;
|
||||
sp->t0 = t0;
|
||||
ws = wss[s];
|
||||
sp->wb = sp->w = 1<<ws;
|
||||
sp->h = h;
|
||||
sp->t1 = t1 = p[2];
|
||||
sp->base = vram + 0x10000 + ((t1 & 0x3ff) << 5);
|
||||
d = (t0 & SPR8) != 0;
|
||||
sp->ysh = (cnt & OBJNOMAT) != 0 ? 2 + d + ws : 10;
|
||||
if((t0 & SPRROT) != 0){
|
||||
if((t0 & SPRDOUB) != 0)
|
||||
sp->wb <<= 1;
|
||||
budg -= 10 + sp->w*2;
|
||||
pp = oam + 3 + (t0 >> 21 & 0x1f0);
|
||||
sp->dx = pp[0];
|
||||
sp->dy = pp[8];
|
||||
sp->rx = (dy - hb/2) * (s16int) pp[4] + (sp->w << 7) - sp->dx * sp->wb/2;
|
||||
sp->ry = (dy - hb/2) * (s16int)pp[12] + (sp->h << 7) - sp->dy * sp->wb/2;
|
||||
if(sp->x < 0){
|
||||
sp->rx -= sp->x * sp->dx;
|
||||
sp->ry -= sp->x * sp->dy;
|
||||
}
|
||||
}else{
|
||||
budg -= sp->w;
|
||||
if((t0 & SPRVFLIP) != 0)
|
||||
dy = h - 1 - dy;
|
||||
sp->base += (dy & 7) << 2 + d;
|
||||
sp->base += dy >> 3 << sp->ysh;
|
||||
if((t0 & SPRHFLIP) != 0)
|
||||
sp->base += sp->w - 7 << 2 + d;
|
||||
sp->inc = (1 << 5 + d) - (1 << 2 + d);
|
||||
if(sp->x < 0)
|
||||
if((t0 & SPRHFLIP) != 0){
|
||||
sp->base -= ((-sp->x & 7) >> 1 - d) + (-sp->x >> 3 << 5 + d);
|
||||
if((t0 & SPR8) == 0 && (sp->x & 1) != 0)
|
||||
sp->base--;
|
||||
}else
|
||||
sp->base += ((-sp->x & 7) >> 1 - d) + (-sp->x >> 3 << 5 + d);
|
||||
}
|
||||
if((t0 & SPR8) != 0)
|
||||
sp->pal = pram + 0x100;
|
||||
else
|
||||
sp->pal = pram + 0x100 + (t1 >> 8 & 0xf0);
|
||||
if(budg < 0)
|
||||
break;
|
||||
sp++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spr(void)
|
||||
{
|
||||
sprite *s;
|
||||
ushort dx;
|
||||
u32int t0;
|
||||
uchar v;
|
||||
ushort x, y;
|
||||
u16int c;
|
||||
int pv, ppri, pri;
|
||||
uchar d;
|
||||
uchar *b;
|
||||
|
||||
pv = -1;
|
||||
ppri = 6;;
|
||||
for(s = sprt; s < sp; s++){
|
||||
dx = ppux - s->x;
|
||||
if(dx >= s->wb)
|
||||
continue;
|
||||
t0 = s->t0;
|
||||
if((t0 & SPRROT) != 0){
|
||||
x = s->rx >> 8;
|
||||
y = s->ry >> 8;
|
||||
if(x < s->w && y < s->h){
|
||||
b = s->base;
|
||||
d = (t0 & SPR8) != 0;
|
||||
b += (y & 7) << 2 + d;
|
||||
b += y >> 3 << s->ysh;
|
||||
b += (x & 7) >> 1 - d;
|
||||
b += x >> 3 << 5 + d;
|
||||
v = *b;
|
||||
if(!d)
|
||||
if((x & 1) != 0)
|
||||
v >>= 4;
|
||||
else
|
||||
v &= 0xf;
|
||||
}else
|
||||
v = 0;
|
||||
s->rx += s->dx;
|
||||
s->ry += s->dy;
|
||||
}else if((t0 & SPRHFLIP) != 0){
|
||||
if((t0 & SPR8) != 0)
|
||||
v = *--s->base;
|
||||
else if((dx & 1) != 0)
|
||||
v = *s->base & 0x0f;
|
||||
else
|
||||
v = *--s->base >> 4;
|
||||
if((dx & 7) == 7)
|
||||
s->base -= s->inc;
|
||||
}else{
|
||||
v = *s->base;
|
||||
if((t0 & SPR8) != 0)
|
||||
s->base++;
|
||||
else if((dx & 1) != 0){
|
||||
v >>= 4;
|
||||
s->base++;
|
||||
}else
|
||||
v &= 0xf;
|
||||
if((dx & 7) == 7)
|
||||
s->base += s->inc;
|
||||
}
|
||||
if(v != 0){
|
||||
pri = s->t1 >> 10 & 3;
|
||||
c = s->pal[v];
|
||||
switch(s->t0 >> 10 & 3){
|
||||
case 1:
|
||||
c |= 1<<16;
|
||||
case 0:
|
||||
if(ppri > pri){
|
||||
pv = c;
|
||||
ppri = pri;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
objwin = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pv >= 0){
|
||||
pixel(pv, 4, ppri);
|
||||
if(pv >> 16 != 0)
|
||||
objtrans = 1;
|
||||
}
|
||||
}
|
||||
|
||||
u16int
|
||||
mix(u16int c1, u16int c2)
|
||||
{
|
||||
u16int r, g, b, eva, evb;
|
||||
|
||||
eva = blda;
|
||||
evb = bldb;
|
||||
b = ((c1 & 0x7c00) * eva + (c2 & 0x7c00) * evb) >> 4;
|
||||
g = ((c1 & 0x03e0) * eva + (c2 & 0x03e0) * evb) >> 4;
|
||||
r = ((c1 & 0x001f) * eva + (c2 & 0x001f) * evb) >> 4;
|
||||
if(b > 0x7c00) b = 0x7c00;
|
||||
if(g > 0x03e0) g = 0x03e0;
|
||||
if(r > 0x001f) r = 0x001f;
|
||||
return b & 0x7c00 | g & 0x03e0 | r;
|
||||
}
|
||||
|
||||
u16int
|
||||
brighten(u16int c1)
|
||||
{
|
||||
u16int r, g, b, y;
|
||||
|
||||
y = bldy;
|
||||
b = c1 & 0x7c00;
|
||||
b = b + (0x7c00 - b) * y / 16;
|
||||
g = c1 & 0x03e0;
|
||||
g = g + (0x03e0 - g) * y / 16;
|
||||
r = c1 & 0x001f;
|
||||
r = r + (0x001f - r) * y / 16;
|
||||
if(b > 0x7c00) b = 0x7c00;
|
||||
if(g > 0x03e0) g = 0x03e0;
|
||||
if(r > 0x001f) r = 0x001f;
|
||||
return b & 0x7c00 | g & 0x03e0 | r;
|
||||
}
|
||||
|
||||
u16int
|
||||
darken(u16int c1)
|
||||
{
|
||||
u16int r, g, b, y;
|
||||
|
||||
y = 16 - bldy;
|
||||
b = c1 & 0x7c00;
|
||||
b = b * y / 16;
|
||||
g = c1 & 0x03e0;
|
||||
g = g * y / 16;
|
||||
r = c1 & 0x001f;
|
||||
r = r * y / 16;
|
||||
return b & 0x7c00 | g & 0x03e0 | r;
|
||||
}
|
||||
|
||||
void
|
||||
windows(void)
|
||||
{
|
||||
u16int dispcnt;
|
||||
u16int v, h;
|
||||
|
||||
dispcnt = reg[DISPCNT];
|
||||
bgmask = dispcnt >> 8 | 1<<5;
|
||||
if((dispcnt >> 13) != 0){
|
||||
if((dispcnt & 1<<13) != 0){
|
||||
v = reg[WIN0V];
|
||||
h = reg[WIN0H];
|
||||
if(ppuy < (u8int)v && ppuy >= v >> 8 &&
|
||||
ppux < (u8int)h && ppux >= h >> 8){
|
||||
bgmask &= reg[WININ];
|
||||
goto windone;
|
||||
}
|
||||
}
|
||||
if((dispcnt & 1<<14) != 0){
|
||||
v = reg[WIN1V];
|
||||
h = reg[WIN1H];
|
||||
if(ppuy < (u8int)v && ppuy >= v >> 8 &&
|
||||
ppux < (u8int)h && ppux >= h >> 8){
|
||||
bgmask &= reg[WININ] >> 8;
|
||||
goto windone;
|
||||
}
|
||||
}
|
||||
if((dispcnt & 1<<15) != 0 && objwin != 0){
|
||||
bgmask &= reg[WINOUT] >> 8;
|
||||
goto windone;
|
||||
}
|
||||
bgmask &= reg[WINOUT];
|
||||
}
|
||||
windone:
|
||||
if(pixelpri[0] != 8 && (bgmask & 1<<4) == 0){
|
||||
pixelpri[0] = 8;
|
||||
pixeldat[0] = pram[0] | 5 << 16;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
colormath(void)
|
||||
{
|
||||
u8int src0;
|
||||
u16int bldcnt;
|
||||
|
||||
if((bgmask & 1<<5) == 0)
|
||||
return;
|
||||
bldcnt = reg[BLDCNT];
|
||||
src0 = pixeldat[0] >> 16;
|
||||
if(objtrans && src0 == 4)
|
||||
goto alpha;
|
||||
if((bldcnt & 3<<6) == 0 || (bldcnt & 1<<src0) == 0)
|
||||
return;
|
||||
switch(bldcnt >> 6 & 3){
|
||||
case 1:
|
||||
alpha:
|
||||
if((bldcnt & 1<<8+(pixeldat[1]>>16)) == 0)
|
||||
return;
|
||||
pixeldat[0] = mix(pixeldat[0], pixeldat[1]);
|
||||
break;
|
||||
case 2:
|
||||
pixeldat[0] = brighten(pixeldat[0]);
|
||||
break;
|
||||
case 3:
|
||||
pixeldat[0] = darken(pixeldat[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ppustep(void)
|
||||
{
|
||||
u16int stat;
|
||||
u16int cnt;
|
||||
|
||||
stat = reg[DISPSTAT];
|
||||
cnt = reg[DISPCNT];
|
||||
if(ppuy < 160 && ppux < 240)
|
||||
if((cnt & FBLANK) == 0){
|
||||
objwin = 0;
|
||||
objtrans = 0;
|
||||
pixelpri[0] = 8;
|
||||
pixeldat[0] = pram[0] | 5 << 16;
|
||||
if((cnt & 1<<12) != 0)
|
||||
spr();
|
||||
windows();
|
||||
bgs();
|
||||
colormath();
|
||||
pixeldraw(ppux, ppuy, pixeldat[0]);
|
||||
}else
|
||||
pixeldraw(ppux, ppuy, 0xffff);
|
||||
if(ppux == 240 && ppuy < 160){
|
||||
if((stat & IRQHBLEN) != 0)
|
||||
setif(IRQHBL);
|
||||
dmastart(DMAHBL);
|
||||
}
|
||||
if(++ppux >= 308){
|
||||
ppux = 0;
|
||||
if(++ppuy >= 228){
|
||||
ppuy = 0;
|
||||
flush();
|
||||
}
|
||||
if((stat & IRQVCTREN) != 0 && ppuy == stat >> 8)
|
||||
setif(IRQVCTR);
|
||||
if(ppuy < 160){
|
||||
bgsinit();
|
||||
sprinit();
|
||||
}else if(ppuy == 160){
|
||||
if((stat & IRQVBLEN) != 0)
|
||||
setif(IRQVBL);
|
||||
dmastart(DMAVBL);
|
||||
}
|
||||
}
|
||||
}
|
15
sys/src/games/gba/test.c
Normal file
15
sys/src/games/gba/test.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void main()
|
||||
{
|
||||
int fd;
|
||||
Dir *d;
|
||||
int n, i;
|
||||
|
||||
fd = open(".", OREAD);
|
||||
n = dirreadall(fd, &d);
|
||||
for(i = 0; i < n; i++)
|
||||
if(d[i].name[0] == '\xef')
|
||||
remove(d[i].name);
|
||||
}
|
Loading…
Reference in a new issue