games/gba: new faster ppu code, audio support
This commit is contained in:
parent
02ea56dbda
commit
5de71b116a
8 changed files with 1235 additions and 513 deletions
370
sys/src/games/gba/apu.c
Normal file
370
sys/src/games/gba/apu.c
Normal file
|
@ -0,0 +1,370 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
Event evsamp;
|
||||
int srate, sratediv;
|
||||
s16int sbuf[2*4000], *sbufp, bias;
|
||||
enum {
|
||||
Freq = 44100,
|
||||
};
|
||||
static int stime;
|
||||
s8int snddma[2];
|
||||
static int fd;
|
||||
|
||||
u16int envctr, envrel, envmod;
|
||||
u8int sweepen, sweepctr;
|
||||
u16int sweepfreq;
|
||||
typedef struct chan chan;
|
||||
struct chan {
|
||||
u8int n, ectr;
|
||||
u16int len;
|
||||
u16int *env, *freq;
|
||||
u16int fctr, fthr;
|
||||
u32int finc;
|
||||
u8int vol;
|
||||
};
|
||||
u8int wave[64], wpos, wbank;
|
||||
u16int lfsr;
|
||||
|
||||
chan sndch[4] = {
|
||||
{
|
||||
.n = 0,
|
||||
.env = reg + 0x62/2,
|
||||
.freq = reg + 0x64/2,
|
||||
},
|
||||
{
|
||||
.n = 1,
|
||||
.env = reg + 0x68/2,
|
||||
.freq = reg + 0x6c/2,
|
||||
},
|
||||
{
|
||||
.n = 2,
|
||||
},
|
||||
{
|
||||
.n = 3,
|
||||
.env = reg + 0x78/2,
|
||||
.freq = reg + 0x7c/2,
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
rate(int i, u16int v)
|
||||
{
|
||||
switch(i){
|
||||
case 0: case 1:
|
||||
sndch[i].finc = 131072ULL * 65536 / (srate * (2048 - (v & 0x7ff)));
|
||||
break;
|
||||
case 2:
|
||||
sndch[2].finc = 2097152ULL * 65536 / (srate * (2048 - (v & 0x7ff)));
|
||||
break;
|
||||
case 3:
|
||||
sndch[3].finc = 524288ULL * 65536 / srate;
|
||||
if((v & 7) != 0)
|
||||
sndch[3].finc /= v & 7;
|
||||
else
|
||||
sndch[3].finc <<= 1;
|
||||
sndch[3].finc >>= (v >> 4 & 15) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
env(chan *c)
|
||||
{
|
||||
if((envmod & 1) == 0 && c->len > 0 && (*c->freq & 1<<14) != 0)
|
||||
--c->len;
|
||||
if(c->len == 0){
|
||||
c->vol = 0;
|
||||
return;
|
||||
}
|
||||
if((envmod & 7) != 7 || c->ectr == 0 || --c->ectr != 0)
|
||||
return;
|
||||
c->ectr = *c->env >> 8 & 7;
|
||||
if((*c->env & 1<<11) != 0){
|
||||
if(c->vol < 15)
|
||||
c->vol++;
|
||||
}else
|
||||
if(c->vol > 0)
|
||||
c->vol--;
|
||||
}
|
||||
|
||||
s8int
|
||||
wavesamp(void)
|
||||
{
|
||||
s8int x;
|
||||
u16int vol, cnt;
|
||||
int v;
|
||||
|
||||
sndch[2].fctr = v = sndch[2].fctr + sndch[2].finc;
|
||||
if(sndch[2].len == 0 || (reg[0x70/2] & 1<<7) == 0)
|
||||
return 0;
|
||||
vol = reg[0x72/2];
|
||||
cnt = reg[0x70/2];
|
||||
for(;;){
|
||||
x = wave[wbank ^ wpos];
|
||||
v -= 0x10000;
|
||||
if(v < 0)
|
||||
break;
|
||||
wpos++;
|
||||
if((cnt & 1<<5) != 0)
|
||||
wpos &= 63;
|
||||
else
|
||||
wpos &= 31;
|
||||
}
|
||||
if((vol & 1<<15) != 0)
|
||||
x = (x >> 2) + (x >> 3);
|
||||
else if((vol & 3<<14) == 0)
|
||||
x = 0;
|
||||
else
|
||||
x = x >> (vol >> 14 & 3);
|
||||
return x;
|
||||
}
|
||||
|
||||
s8int
|
||||
lfsrsamp(void)
|
||||
{
|
||||
int v;
|
||||
u16int l;
|
||||
|
||||
sndch[3].fctr = v = sndch[3].fctr + sndch[3].finc;
|
||||
for(;;){
|
||||
l = lfsr;
|
||||
v -= 0x10000;
|
||||
if(v < 0)
|
||||
break;
|
||||
lfsr >>= 1;
|
||||
if(((l ^ lfsr) & 1) != 0)
|
||||
if((reg[0x7c/2] & 1<<3) != 0)
|
||||
lfsr |= 0x40;
|
||||
else
|
||||
lfsr |= 0x4000;
|
||||
}
|
||||
if((l & 1) != 0)
|
||||
return -sndch[3].vol;
|
||||
else
|
||||
return sndch[3].vol;
|
||||
}
|
||||
|
||||
void
|
||||
sweep(int wb)
|
||||
{
|
||||
u16int fr;
|
||||
int d;
|
||||
u16int cnt;
|
||||
|
||||
cnt = reg[0x60/2];
|
||||
d = sweepfreq >> (cnt & 7);
|
||||
if((cnt & 1<<3) != 0)
|
||||
d = -d;
|
||||
fr = sweepfreq + d;
|
||||
print("%d %d %d\n", d, sweepfreq, fr);
|
||||
if(fr > 2047){
|
||||
sndch[0].len = 0;
|
||||
sndch[0].vol = 0;
|
||||
sweepen = 0;
|
||||
}else if(wb){
|
||||
sweepfreq = fr;
|
||||
reg[0x64/2] = reg[0x64/2] & 0xfc00 | fr;
|
||||
rate(0, fr);
|
||||
sweep(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sndstart(chan *c, u16int v)
|
||||
{
|
||||
u16int cnt;
|
||||
|
||||
c->vol = *c->env >> 12;
|
||||
c->ectr = *c->env >> 8 & 7;
|
||||
if(c->len == 0)
|
||||
c->len = 64;
|
||||
if(c == sndch){
|
||||
cnt = reg[0x60/2];
|
||||
sweepen = (cnt & 0x07) != 0 && (cnt & 0x70) != 0;
|
||||
sweepctr = cnt >> 4 & 7;
|
||||
sweepfreq = v & 0x7ff;
|
||||
if((cnt & 0x07) != 0)
|
||||
sweep(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sampletick(void *)
|
||||
{
|
||||
u16int cntl, cnth;
|
||||
s16int ch[6];
|
||||
s16int s[2];
|
||||
int i;
|
||||
|
||||
addevent(&evsamp, sratediv + evsamp.time);
|
||||
|
||||
if(--envctr == 0){
|
||||
envctr = envrel;
|
||||
env(&sndch[0]);
|
||||
env(&sndch[1]);
|
||||
if((envmod & 1) == 0 && sndch[2].len > 0 && (reg[0x74/2] & 1<<14) != 0)
|
||||
sndch[2].len--;
|
||||
env(&sndch[3]);
|
||||
if((envmod & 3) == 2 && sweepen && --sweepctr == 0){
|
||||
sweepctr = reg[0x60/2] >> 4 & 7;
|
||||
sweep(1);
|
||||
}
|
||||
envmod++;
|
||||
}
|
||||
|
||||
sndch[0].fctr += sndch[0].finc;
|
||||
if(sndch[0].fctr >= sndch[0].fthr)
|
||||
ch[0] = sndch[0].vol;
|
||||
else
|
||||
ch[0] = -sndch[0].vol;
|
||||
sndch[1].fctr += sndch[1].finc;
|
||||
if(sndch[1].fctr >= sndch[1].fthr)
|
||||
ch[1] = sndch[1].vol;
|
||||
else
|
||||
ch[1] = -sndch[1].vol;
|
||||
ch[2] = wavesamp();
|
||||
ch[3] = lfsrsamp();
|
||||
|
||||
cntl = reg[SOUNDCNTL];
|
||||
cnth = reg[SOUNDCNTH];
|
||||
for(i = 0; i < 4; i++)
|
||||
ch[i] = ch[i] >> (cnth & 3);
|
||||
ch[5] = snddma[0] << 1 + (cnth >> 2 & 1);
|
||||
ch[6] = snddma[1] << 1 + (cnth >> 3 & 1);
|
||||
|
||||
s[0] = 0;
|
||||
s[1] = 0;
|
||||
for(i = 0; i < 4; i++){
|
||||
if((cntl & 1<<8<<i) != 0)
|
||||
s[1] += ch[i] * (1 + (cntl & 7));
|
||||
if((cntl & 1<<12<<i) != 0)
|
||||
s[0] += ch[i] * (1 + (cntl >> 4 & 7));
|
||||
}
|
||||
for(i = 5; i < 6; i++){
|
||||
if((cnth & 1<<3<<i) != 0)
|
||||
s[1] += ch[i];
|
||||
if((cnth & 1<<4<<i) != 0)
|
||||
s[0] += ch[i];
|
||||
}
|
||||
s[0] += bias;
|
||||
s[1] += bias;
|
||||
if(s[0] < -0x200) s[0] = -0x200;
|
||||
else if(s[0] > 0x1ff) s[0] = 0x1ff;
|
||||
if(s[1] < -0x200) s[1] = -0x200;
|
||||
else if(s[1] > 0x1ff) s[1] = 0x1ff;
|
||||
|
||||
stime -= Freq;
|
||||
while(stime < 0){
|
||||
if(sbufp < sbuf + nelem(sbuf)){
|
||||
sbufp[0] = s[0] << 6;
|
||||
sbufp[1] = s[1] << 6;
|
||||
sbufp += 2;
|
||||
}
|
||||
stime += srate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sndwrite(u16int a, u16int v)
|
||||
{
|
||||
int sh, p, i;
|
||||
static u16int thr[4] = {0x2000, 0x4000, 0x8000, 0xC000};
|
||||
|
||||
switch(a){
|
||||
case 0x62:
|
||||
sndch[0].fthr = thr[v >> 6 & 3];
|
||||
sndch[0].len = 64 - (v & 63);
|
||||
break;
|
||||
case 0x64:
|
||||
rate(0, v);
|
||||
if((v & 1<<15) != 0)
|
||||
sndstart(&sndch[0], v);
|
||||
break;
|
||||
case 0x68:
|
||||
sndch[1].fthr = thr[v >> 6 & 3];
|
||||
break;
|
||||
case 0x6c:
|
||||
rate(1, v);
|
||||
if((v & 1<<15) != 0)
|
||||
sndstart(&sndch[1], v);
|
||||
break;
|
||||
case 0x70:
|
||||
wbank = v >> 1 & 32;
|
||||
break;
|
||||
case 0x72:
|
||||
sndch[2].len = 256 - (v & 0xff);
|
||||
break;
|
||||
case 0x74:
|
||||
rate(2, v);
|
||||
if((v & 1<<15) != 0 && sndch[2].len == 0)
|
||||
sndch[2].len = 256;
|
||||
break;
|
||||
case 0x7c:
|
||||
rate(3, v);
|
||||
if((v & 1<<15) != 0){
|
||||
if((v & 1<<3) != 0)
|
||||
lfsr = 0x7f;
|
||||
else
|
||||
lfsr = 0x7fff;
|
||||
sndstart(&sndch[3], v);
|
||||
}
|
||||
break;
|
||||
case SOUNDBIAS*2:
|
||||
sh = 9 - (v >> 14 & 3);
|
||||
if(sratediv != 1<<sh){
|
||||
srate = 1 << 24 - sh;
|
||||
sratediv = 1 << sh;
|
||||
envrel = srate / 512;
|
||||
rate(0, reg[0x64/2]);
|
||||
rate(1, reg[0x6c/2]);
|
||||
rate(2, reg[0x74/2]);
|
||||
rate(3, reg[0x7c/2]);
|
||||
}
|
||||
bias = (v & 0x3ff) - 0x200;
|
||||
break;
|
||||
case 0x90: case 0x92: case 0x94: case 0x96:
|
||||
case 0x98: case 0x9a: case 0x9c: case 0x9e:
|
||||
p = ~reg[0x70/2] >> 1 & 32;
|
||||
for(i = a - 0x90; i < a - 0x90 + 2; i++){
|
||||
wave[(wpos + 2 * i) & 31 + p] = v >> 4 & 0xf;
|
||||
wave[(wpos + 2 * i + 1) & 31 + p] = v & 0xf;
|
||||
v >>= 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
audioinit(void)
|
||||
{
|
||||
fd = open("/dev/audio", OWRITE);
|
||||
if(fd < 0)
|
||||
sysfatal("open: %r");
|
||||
sbufp = sbuf;
|
||||
sndwrite(SOUNDBIAS*2, 0x200);
|
||||
evsamp.f = sampletick;
|
||||
addevent(&evsamp, sratediv);
|
||||
}
|
||||
|
||||
int
|
||||
audioout(void)
|
||||
{
|
||||
int rc;
|
||||
static int cl;
|
||||
|
||||
if(sbufp == nil)
|
||||
return -1;
|
||||
if(sbufp == sbuf)
|
||||
return 0;
|
||||
cl = clock;
|
||||
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
|
||||
if(rc > 0)
|
||||
sbufp -= (rc+1)/2;
|
||||
if(sbufp < sbuf)
|
||||
sbufp = sbuf;
|
||||
return 0;
|
||||
}
|
|
@ -15,11 +15,20 @@ extern u16int reg[];
|
|||
extern uchar *rom, *back;
|
||||
extern int nrom, nback, backup;
|
||||
|
||||
extern int ppux, ppuy;
|
||||
extern u8int bldy, blda, bldb;
|
||||
extern int hblank, ppuy;
|
||||
|
||||
extern int clock;
|
||||
extern int scale;
|
||||
|
||||
typedef struct Event Event;
|
||||
struct Event {
|
||||
int time;
|
||||
void (*f)(void *);
|
||||
Event *next;
|
||||
void *aux;
|
||||
};
|
||||
extern Event *elist;
|
||||
|
||||
enum {
|
||||
DISPCNT = 0x0/2,
|
||||
DISPSTAT = 0x4/2,
|
||||
|
@ -35,6 +44,10 @@ enum {
|
|||
BG2XH = 0x2a/2,
|
||||
BG2YL = 0x2c/2,
|
||||
BG2YH = 0x2e/2,
|
||||
BG3XL = 0x38/2,
|
||||
BG3XH = 0x3a/2,
|
||||
BG3YL = 0x3c/2,
|
||||
BG3YH = 0x3e/2,
|
||||
|
||||
WIN0H = 0x40/2,
|
||||
WIN1H = 0x42/2,
|
||||
|
@ -42,15 +55,24 @@ enum {
|
|||
WIN1V = 0x46/2,
|
||||
WININ = 0x48/2,
|
||||
WINOUT = 0x4a/2,
|
||||
MOSAIC = 0x4c/2,
|
||||
BLDCNT = 0x50/2,
|
||||
BLDALPHA = 0x52/2,
|
||||
BLDY = 0x54/2,
|
||||
|
||||
SOUNDCNTL = 0x80/2,
|
||||
SOUNDCNTH = 0x82/2,
|
||||
SOUNDBIAS = 0x88/2,
|
||||
|
||||
FIFOAH = 0xa2/2,
|
||||
FIFOBH = 0xa6/2,
|
||||
|
||||
DMA0CNTH = 0xba/2,
|
||||
DMA1CNTH = 0xc6/2,
|
||||
DMA2CNTH = 0xd2/2,
|
||||
DMA3CNTH = 0xde/2,
|
||||
|
||||
TM0CNTH = 0x102/2,
|
||||
KEYCNT = 0x132/2,
|
||||
|
||||
IE = 0x200/2,
|
||||
|
@ -73,9 +95,16 @@ enum {
|
|||
IRQVCTREN = 1<<5,
|
||||
|
||||
/* BGnCNT */
|
||||
BGMOSAIC = 1<<6,
|
||||
BG8 = 1<<7,
|
||||
DISPWRAP = 1<<13,
|
||||
|
||||
/* TIMERnCNTH */
|
||||
PRESC = 3,
|
||||
COUNTUP = 1<<2,
|
||||
TIMERIRQ = 1<<6,
|
||||
TIMERON = 1<<7,
|
||||
|
||||
/* DMAnCNTH */
|
||||
DMADCNT = 5,
|
||||
DMASCNT = 7,
|
||||
|
@ -111,4 +140,5 @@ enum {
|
|||
|
||||
KB = 1024,
|
||||
BACKTYPELEN = 64,
|
||||
HZ = 16777216,
|
||||
};
|
||||
|
|
211
sys/src/games/gba/ev.c
Normal file
211
sys/src/games/gba/ev.c
Normal file
|
@ -0,0 +1,211 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
typedef struct {
|
||||
u16int *cnt;
|
||||
Event;
|
||||
u16int val;
|
||||
int clock;
|
||||
u8int i, sh, snd;
|
||||
} Timer;
|
||||
|
||||
typedef struct fifo fifo;
|
||||
struct fifo {
|
||||
u32int d[8];
|
||||
u8int head, level, headpos;
|
||||
};
|
||||
fifo sndfifo[2];
|
||||
|
||||
Event *elist;
|
||||
Timer timers[4];
|
||||
Event evhblank;
|
||||
|
||||
void
|
||||
addevent(Event *ev, int time)
|
||||
{
|
||||
Event **p, *e;
|
||||
int t;
|
||||
|
||||
t = time;
|
||||
for(p = &elist; (e = *p) != nil; p = &e->next){
|
||||
if(t < e->time){
|
||||
e->time -= t;
|
||||
break;
|
||||
}
|
||||
t -= e->time;
|
||||
}
|
||||
ev->next = e;
|
||||
ev->time = t;
|
||||
*p = ev;
|
||||
}
|
||||
|
||||
void
|
||||
delevent(Event *ev)
|
||||
{
|
||||
Event **p, *e;
|
||||
|
||||
for(p = &elist; (e = *p) != nil; p = &e->next)
|
||||
if(e == ev){
|
||||
*p = e->next;
|
||||
if(e->next != nil)
|
||||
e->next->time += e->time;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
popevent(void)
|
||||
{
|
||||
Event *e;
|
||||
int t;
|
||||
|
||||
do{
|
||||
e = elist;
|
||||
t = e->time;
|
||||
elist = e->next;
|
||||
e->f(e->aux);
|
||||
}while((elist->time += t) <= 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fifoput(int i, u32int s)
|
||||
{
|
||||
fifo *f;
|
||||
|
||||
f = sndfifo + i;
|
||||
if(f->level < 8)
|
||||
f->d[(f->head + f->level++) & 7] = s;
|
||||
}
|
||||
|
||||
void
|
||||
fifotimer(int b, int n)
|
||||
{
|
||||
fifo *f;
|
||||
int i, j;
|
||||
extern s8int snddma[2];
|
||||
|
||||
for(i = 0; i < 2; i++){
|
||||
if((b & 1<<i) == 0)
|
||||
continue;
|
||||
f = &sndfifo[i];
|
||||
for(j = 0; j < n && f->level > 0; j++){
|
||||
snddma[i] = f->d[f->head] & 0xff;
|
||||
f->d[f->head] >>= 8;
|
||||
if(++f->headpos == 4){
|
||||
f->head = (f->head + 1) & 7;
|
||||
f->level--;
|
||||
f->headpos = 0;
|
||||
}
|
||||
}
|
||||
if(f->level <= 4)
|
||||
dmastart(DMASOUND);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
soundcnth(u16int v)
|
||||
{
|
||||
timers[0].snd = 0;
|
||||
timers[1].snd = 0;
|
||||
if((v & 3<<8) != 0)
|
||||
timers[(v >> 10) & 1].snd |= 1;
|
||||
if((v & 3<<12) != 0)
|
||||
timers[(v >> 14) & 1].snd |= 2;
|
||||
if((v & 1<<11) != 0){
|
||||
sndfifo[0].level = 0;
|
||||
sndfifo[0].head = 0;
|
||||
sndfifo[0].headpos = 0;
|
||||
}
|
||||
if((v & 1<<15) != 0){
|
||||
sndfifo[1].level = 0;
|
||||
sndfifo[1].head = 0;
|
||||
sndfifo[1].headpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
u16int
|
||||
timerget(int i)
|
||||
{
|
||||
Timer *t;
|
||||
|
||||
t = &timers[i];
|
||||
if((*t->cnt & (COUNTUP|TIMERON)) != TIMERON)
|
||||
return t->val;
|
||||
return t->val + (clock - t->clock >> t->sh);
|
||||
}
|
||||
|
||||
void
|
||||
timerset(int i, u16int nc)
|
||||
{
|
||||
u32int v;
|
||||
u16int oc;
|
||||
Timer *t;
|
||||
|
||||
t = &timers[i];
|
||||
oc = *t->cnt;
|
||||
if((oc & (PRESC|COUNTUP|TIMERON)) == (nc & (PRESC|COUNTUP|TIMERON)))
|
||||
return;
|
||||
if((oc & (COUNTUP|TIMERON)) == TIMERON){
|
||||
v = t->val + (clock - t->clock >> t->sh);
|
||||
delevent(t);
|
||||
}else
|
||||
v = t->val;
|
||||
if((oc & TIMERON) == 0 && (nc & TIMERON) != 0)
|
||||
v = t->cnt[-1];
|
||||
if((nc & 3) != 0)
|
||||
t->sh = 4 + (nc & 3) * 2;
|
||||
else
|
||||
t->sh = 0;
|
||||
t->val = v;
|
||||
t->clock = clock & -(1 << t->sh);
|
||||
if((nc & (COUNTUP|TIMERON)) == TIMERON)
|
||||
addevent(t, (0x10000 - t->val << t->sh) + (-clock & (1 << t->sh) - 1));
|
||||
}
|
||||
|
||||
void
|
||||
timertick(void *aux)
|
||||
{
|
||||
Timer *t;
|
||||
u32int v;
|
||||
int to;
|
||||
|
||||
t = aux;
|
||||
t->clock = clock + t->time & -(1 << t->sh);
|
||||
t->val = -t->time >> t->sh;
|
||||
do{
|
||||
to = 0;
|
||||
do{
|
||||
t->val = v = t->val + t->cnt[-1];
|
||||
to++;
|
||||
}while(v >= 0x10000);
|
||||
if(t == aux)
|
||||
addevent(t, (0x10000 - t->val << t->sh) + (-clock & (1 << t->sh) - 1));
|
||||
if((*t->cnt & TIMERIRQ) != 0)
|
||||
setif(IRQTIM0 << t->i);
|
||||
if(t->snd)
|
||||
fifotimer(t->snd, to);
|
||||
if(++t >= timers + 4 || (*t->cnt & (COUNTUP | TIMERON)) != (COUNTUP|TIMERON))
|
||||
break;
|
||||
t->val = v = t->val + to;
|
||||
}while(v >= 0x10000);
|
||||
}
|
||||
|
||||
void
|
||||
eventinit(void)
|
||||
{
|
||||
int i;
|
||||
extern void hblanktick(void *);
|
||||
|
||||
for(i = 0; i < 4; i++){
|
||||
timers[i].f = timertick;
|
||||
timers[i].aux = &timers[i];
|
||||
timers[i].i = i;
|
||||
timers[i].cnt = ®[TM0CNTH + i * 2];
|
||||
}
|
||||
evhblank.f = hblanktick;
|
||||
addevent(&evhblank, 240*4);
|
||||
}
|
|
@ -11,3 +11,15 @@ int dmastep(void);
|
|||
void dmastart(int);
|
||||
void flushback(void);
|
||||
void writeback(void);
|
||||
void eventinit(void);
|
||||
void popevent(void);
|
||||
u16int timerget(int);
|
||||
void timerset(int, u16int);
|
||||
void addevent(Event *, int);
|
||||
void ppuwrite(u16int, u16int);
|
||||
void fifoput(int, u32int);
|
||||
void soundcnth(u16int);
|
||||
void soundbias(u16int);
|
||||
void audioinit(void);
|
||||
int audioout(void);
|
||||
void sndwrite(u16int, u16int);
|
||||
|
|
|
@ -15,11 +15,10 @@ Mousectl *mc;
|
|||
int keys, paused, framestep, backup;
|
||||
QLock pauselock;
|
||||
int savefd, saveframes;
|
||||
int clock;
|
||||
|
||||
char *biosfile = "/sys/games/lib/gbabios.bin";
|
||||
|
||||
int ppuclock;
|
||||
|
||||
void *
|
||||
emalloc(ulong sz)
|
||||
{
|
||||
|
@ -347,6 +346,7 @@ flush(void)
|
|||
flushimage(display, 1);
|
||||
if(profile)
|
||||
timing();
|
||||
audioout();
|
||||
if(framestep){
|
||||
paused = 1;
|
||||
qlock(&pauselock);
|
||||
|
@ -370,7 +370,7 @@ flush(void)
|
|||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [-23T] [-s savetype] [-b biosfile] rom\n", argv0);
|
||||
fprint(2, "usage: %s [-23aT] [-s savetype] [-b biosfile] rom\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
|
@ -388,6 +388,9 @@ threadmain(int argc, char **argv)
|
|||
case '3':
|
||||
scale = 3;
|
||||
break;
|
||||
case 'a':
|
||||
audioinit();
|
||||
break;
|
||||
case 's':
|
||||
s = EARGF(usage());
|
||||
backup = parsetype(s, &nback);
|
||||
|
@ -416,7 +419,8 @@ threadmain(int argc, char **argv)
|
|||
sysfatal("initmouse: %r");
|
||||
proccreate(keyproc, nil, mainstacksize);
|
||||
screeninit();
|
||||
|
||||
|
||||
eventinit();
|
||||
memreset();
|
||||
reset();
|
||||
for(;;){
|
||||
|
@ -430,11 +434,8 @@ threadmain(int argc, char **argv)
|
|||
t = 8;
|
||||
else
|
||||
t = step();
|
||||
ppuclock += t;
|
||||
while(ppuclock >= 4){
|
||||
ppustep();
|
||||
ppuclock -= 4;
|
||||
}
|
||||
timerstep(t);
|
||||
clock += t;
|
||||
if((elist->time -= t) <= 0)
|
||||
popevent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,6 @@ u16int pram[512], oam[512];
|
|||
uchar *rom, *back;
|
||||
int nrom, nback;
|
||||
u16int reg[512];
|
||||
u16int tim[4];
|
||||
int timerclock;
|
||||
int dmaact;
|
||||
enum {
|
||||
DMASRC,
|
||||
|
@ -100,7 +98,7 @@ regread(u32int a)
|
|||
|
||||
if(ppuy >= 160 && ppuy != 227)
|
||||
v |= 1;
|
||||
if(ppux >= 240)
|
||||
if(hblank)
|
||||
v |= 2;
|
||||
if(ppuy == v >> 8)
|
||||
v |= 4;
|
||||
|
@ -108,7 +106,7 @@ regread(u32int a)
|
|||
case 0x006:
|
||||
return ppuy;
|
||||
case 0x100: case 0x104: case 0x108: case 0x10c:
|
||||
return tim[(a - 0x100) / 4];
|
||||
return timerget((a - 0x100) / 4);
|
||||
case 0x130:
|
||||
return keys ^ 0x3ff;
|
||||
default:
|
||||
|
@ -122,7 +120,11 @@ regwrite16(u32int a, u16int v)
|
|||
u16int *p;
|
||||
int i;
|
||||
static u8int ws0[4] = {5,4,3,9};
|
||||
|
||||
|
||||
if(a < 0x56)
|
||||
ppuwrite(a, v);
|
||||
else if(a < 0xa0)
|
||||
sndwrite(a, v);
|
||||
p = ®[a/2];
|
||||
switch(a){
|
||||
case IF*2:
|
||||
|
@ -133,19 +135,6 @@ regwrite16(u32int a, u16int v)
|
|||
*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:
|
||||
i = (a - DMA0CNTH*2) / 12;
|
||||
if((v & DMAEN) != 0){
|
||||
|
@ -159,9 +148,14 @@ regwrite16(u32int a, u16int v)
|
|||
}else
|
||||
dmaact &= ~1<<i;
|
||||
break;
|
||||
case SOUNDCNTH*2:
|
||||
soundcnth(v);
|
||||
break;
|
||||
case FIFOAH*2: case FIFOBH*2:
|
||||
fifoput(a >> 2 & 1, p[-1] | v << 16);
|
||||
break;
|
||||
case 0x102: case 0x106: case 0x10a: case 0x10e:
|
||||
if((*p & 1<<7) == 0 && (v & 1<<7) != 0)
|
||||
tim[(a-0x102)/4] = p[-1];
|
||||
timerset((a - 0x102) / 4, v);
|
||||
break;
|
||||
case WAITCNT*2:
|
||||
waitst[3] = waitst[7] = ws0[v & 3];
|
||||
|
@ -196,7 +190,7 @@ regwrite(u32int a, u32int v, int n)
|
|||
w = w & 0xff00 | (u8int)v;
|
||||
else
|
||||
w = w & 0xff | v << 8;
|
||||
regwrite16(a, w);
|
||||
regwrite16(a & ~1, w);
|
||||
break;
|
||||
default:
|
||||
regwrite16(a, v);
|
||||
|
@ -242,6 +236,11 @@ memread(u32int a, int n, int seq)
|
|||
cyc++;
|
||||
if(n == 4)
|
||||
return regread(b) | regread(b+2) << 16;
|
||||
else if(n == 1)
|
||||
if((b & 1) != 0)
|
||||
return regread(b) >> 8;
|
||||
else
|
||||
return regread(b) & 0xff;
|
||||
return regread(b);
|
||||
case 5:
|
||||
b = a & sizeof(pram) - 1;
|
||||
|
@ -353,6 +352,7 @@ void
|
|||
memreset(void)
|
||||
{
|
||||
reg[0x88/2] = 0x200;
|
||||
reg[BG2PA] = reg[BG2PD] = 0x100;
|
||||
if(backup == EEPROM)
|
||||
if(nrom <= 16*KB*KB)
|
||||
eepstart = 0x1000000;
|
||||
|
@ -362,50 +362,6 @@ memreset(void)
|
|||
eepstart = -1;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -413,7 +369,7 @@ dmastep(void)
|
|||
u16int *cntp, cnt;
|
||||
u32int *dr;
|
||||
u32int v;
|
||||
int sz;
|
||||
int sz, snd;
|
||||
|
||||
cyc = 0;
|
||||
for(i = 0; i < 4; i++)
|
||||
|
@ -425,6 +381,9 @@ dmastep(void)
|
|||
cntp = reg + DMA0CNTH + i * 6;
|
||||
cnt = *cntp;
|
||||
dr = dmar + 4 * i;
|
||||
snd = (cnt >> DMAWHEN & 3) == 3 && (i == 1 || i == 2);
|
||||
if(snd)
|
||||
cnt = cnt & ~(3 << DMADCNT) | DMAFIX << DMADCNT | DMAWIDE;
|
||||
|
||||
sz = (cnt & DMAWIDE) != 0 ? 4 : 2;
|
||||
if(i == 0)
|
||||
|
@ -468,15 +427,18 @@ dmastart(int cond)
|
|||
u16int *cntp, cnt, c;
|
||||
|
||||
cntp = reg + DMA0CNTH;
|
||||
for(i = 0; i < 3; i++, cntp += 6){
|
||||
for(i = 0; i < 4; i++, cntp += 6){
|
||||
cnt = *cntp;
|
||||
if((cnt & DMAEN) == 0)
|
||||
continue;
|
||||
c = cnt >> DMAWHEN & 3;
|
||||
if(c == 3)
|
||||
c += (i + 1) / 2;
|
||||
if(c == cond)
|
||||
if(c == cond){
|
||||
dmaact |= 1<<i;
|
||||
if(c == DMASOUND)
|
||||
dmar[i * 4 + DMACNT] = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ OFILES=\
|
|||
mem.$O\
|
||||
gba.$O\
|
||||
ppu.$O\
|
||||
ev.$O\
|
||||
apu.$O\
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue