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…
Add table
Add a link
Reference in a new issue