more games/gb fun

This commit is contained in:
aiju 2012-04-06 20:57:45 +02:00
parent 4950b5468b
commit 8ebb846fb2
9 changed files with 236 additions and 31 deletions

152
sys/src/games/gb/audio.c Normal file
View file

@ -0,0 +1,152 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include "dat.h"
#include "fns.h"
static int fd;
int ch1c, ch2c, ch3c, ch4c, ch4sr = 1;
enum { SAMPLE = 44100 };
static int
thresh(int f, int b)
{
switch(b){
case 0: return f/8;
case 1: return f/4;
case 2: return f/2;
default: return 3*f/4;
}
}
static int
freq(int lower)
{
int f;
f = mem[lower+1] & 7;
f = (f << 8) | mem[lower];
f = muldiv(2048 - f, SAMPLE, 131072);
return f;
}
static void
dosample(short *smp)
{
int ch1s, ch2s, ch3s, ch4s, ch1f, ch2f, ch3f, ch4f, k, r, s;
u8int f;
ch4s = 0;
ch1f = freq(0xFF13);
if(ch1c >= ch1f)
ch1c = 0;
if(ch1c >= thresh(ch1f, mem[0xFF11] >> 6))
ch1s = 1;
else
ch1s = -1;
ch1s *= mem[0xFF12] >> 4;
ch1s *= 10000 / 0xF;
ch1c++;
ch2f = freq(0xFF18);
if(ch2c >= ch2f)
ch2c = 0;
if(ch2c >= thresh(ch1f, mem[0xFF16] >> 6))
ch2s = 1;
else
ch2s = -1;
ch2s *= mem[0xFF17] >> 4;
ch2s *= 10000 / 0xF;
ch2c++;
ch3f = freq(0xFF1D) * 100 / 32;
if(ch3f == 0)
ch3f = 1;
ch3s = 0;
if(mem[0xFF1A] & 0x80){
if(ch3c >= freq(0xFF1D))
ch3c = 0;
k = ch3c * 100 / ch3f;
ch3s = mem[0xFF30 + (k >> 1)];
if(k & 1)
ch3s &= 0xF;
else
ch3s >>= 4;
switch(mem[0xFF1C]){
case 0:
ch3s = 0;
break;
case 2:
ch3s >>= 1;
break;
case 3:
ch3s >>= 2;
break;
}
ch3s *= 10000 / 0xF;
ch3c++;
}
r = mem[0xFF22] & 7;
s = mem[0xFF22] >> 4;
if(r != 0)
ch4f = 524288 / r;
else
ch4f = 524288 * 2;
ch4f >>= s+1;
if(ch4f == 0)
ch4f = 1;
ch4f = SAMPLE / ch4f;
if(ch4c >= ch4f){
ch4sr <<= 1;
if(mem[0xFF22] & 4)
k = ((ch4sr >> 6) ^ (ch4sr >> 7)) & 1;
else
k = ((ch4sr >> 14) ^ (ch4sr >> 15)) & 1;
ch4sr |= k;
ch4c = 0;
}
if(ch4sr & 1)
ch4s = -1;
else
ch4s = 1;
ch4s *= mem[0xFF21] >> 4;
ch4s *= 10000 / 0xF;
smp[0] = 0;
smp[1] = 0;
f = mem[0xFF25];
if(f & 0x01) smp[0] += ch1s;
if(f & 0x02) smp[0] += ch2s;
if(f & 0x04) smp[0] += ch3s;
if(f & 0x08) smp[0] += ch4s;
if(f & 0x10) smp[1] += ch1s;
if(f & 0x20) smp[1] += ch2s;
if(f & 0x40) smp[1] += ch3s;
if(f & 0x80) smp[1] += ch4s;
}
void
audioproc(void *)
{
short samples[10 * 2];
int i;
for(;;){
for(i = 0; i < sizeof samples/4; i++)
dosample(samples + 2 * i);
write(fd, samples, sizeof samples);
}
}
void
initaudio(void)
{
fd = open("/dev/audio", OWRITE);
if(fd < 0)
return;
proccreate(audioproc, nil, 8192);
}

View file

@ -793,14 +793,14 @@ step(void)
memwrite(lohi(R[rC], 0xFF), R[rA]);
return 8;
case 0xE8:
val = (schar)fetch8();
val32 = (int)sp + val;
val = (short)(schar)fetch8();
val32 = (uint)sp + (uint)val;
Fl = 0;
if(val32 > 0xFFFF || val32 < 0)
if(((sp & 0xFF) + (val & 0xFF)) > 0xFF)
Fl |= FLAGC;
if(((sp & 0xFFF) + (val & 0xFFF)) > 0xFFF)
if(((sp & 0xF) + (val & 0xF)) > 0xF)
Fl |= FLAGH;
sp = val;
sp = val32;
return 16;
case 0xE9:
pc = lohi(R[rL], R[rH]);
@ -823,12 +823,15 @@ step(void)
IME= 0;
return 4;
case 0xF8:
val32 = sp + (schar)fetch8();
val = (short)(schar)fetch8();
val32 = (uint)sp + (uint)val;
Fl = 0;
if(((sp & 0xFF) + (val & 0xFF)) > 0xFF)
Fl |= FLAGC;
if(((sp & 0xF) + (val & 0xF)) > 0xF)
Fl |= FLAGH;
R[rL] = val32;
R[rH] = val32 >> 8;
Fl = 0;
if(val32 < 0 || val32 > 0xFFFF)
Fl = FLAGC;
return 12;
case 0xF9:
sp = lohi(R[rL], R[rH]);

View file

@ -1,7 +1,7 @@
extern u16int pc, curpc, sp;
extern u8int R[8], Fl;
extern int halt, IME, keys;
extern int clock, ppuclock, divclock, timerclock, syncclock, timerfreq, timer;
extern int clock, ppuclock, divclock, timerclock, timerfreq, timer;
extern int rombank, rambank, ramen, battery, ramrom;
extern uchar mem[], *ram;
@ -72,4 +72,7 @@ enum {
IF = 0xFF0F,
IE = 0xFFFF,
CPUFREQ = 4194304,
MILLION = 1000000,
BILLION = 1000000000,
};

View file

@ -8,3 +8,4 @@ void message(char *, ...);
void flushram(void);
void savestate(char *);
void loadstate(char *);
void initaudio(void);

View file

@ -9,7 +9,7 @@
#include "fns.h"
uchar *cart, *ram;
int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, syncclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq;
int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, syncclock, syncfreq, sleeps, checkclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq;
Rectangle picr;
Image *bg, *tmp;
Mousectl *mc;
@ -87,6 +87,11 @@ loadrom(char *file)
case 0x11: case 0x12:
mbc = 3;
break;
case 0x1B: case 0x1E:
battery = 1;
case 0x19: case 0x1A: case 0x1C: case 0x1D:
mbc = 5;
break;
default:
sysfatal("%s: unknown cartridge type %.2x", file, cart[0x147]);
}
@ -226,6 +231,9 @@ threadmain(int argc, char** argv)
Point p;
ARGBEGIN{
case 'a':
initaudio();
break;
default:
sysfatal("unknown flag -%c", ARGC());
}ARGEND;
@ -244,6 +252,7 @@ threadmain(int argc, char** argv)
if(mc == nil)
sysfatal("init mouse: %r");
proccreate(keyproc, nil, 8192);
syncfreq = CPUFREQ / 50;
old = nsec();
for(;;){
if(savereq){
@ -260,6 +269,7 @@ threadmain(int argc, char** argv)
divclock += t;
timerclock += t;
syncclock += t;
checkclock += t;
if(ppuclock >= 456){
ppustep();
ppuclock -= 456;
@ -285,16 +295,23 @@ threadmain(int argc, char** argv)
}
timerclock = 0;
}
if(syncclock >= CPUFREQ / 100){
new = nsec();
diff = new - old;
diff = 10000000 - diff;
diff /= 1000000;
if(diff > 0)
sleep(diff);
old = new;
if(syncclock >= syncfreq){
sleep(10);
sleeps++;
syncclock = 0;
}
if(checkclock >= CPUFREQ){
new = nsec();
diff = new - old - sleeps * 10 * MILLION;
diff = BILLION - diff;
if(diff <= 0)
syncfreq = CPUFREQ;
else
syncfreq = ((vlong)CPUFREQ) * 10 * MILLION / diff;
old = new;
checkclock = 0;
sleeps = 0;
}
if(msgclock > 0){
msgclock -= t;
if(msgclock <= 0){

View file

@ -117,6 +117,26 @@ memwrite(u16int p, u8int v)
return;
}
return;
case 5:
switch(p >> 13){
case 0:
if((v & 0x0F) == 0x0A)
ramswitch(1, rambank);
else
ramswitch(0, rambank);
return;
case 1:
romswitch((rombank & 0x100) | v);
return;
case 2:
romswitch((((int)v & 1) << 8) | (rombank & 0xFF));
return;
case 3:
ramswitch(ramen, v & 15);
return;
}
return;
default:
sysfatal("mbc %d unimplemented", mbc);
}

View file

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

View file

@ -79,24 +79,33 @@ drawbg(void)
static void
drawsprites(void)
{
u8int x, y, tnl1, tnl2, dx, ddx, val, pal;
u8int y, t, tnl1, tnl2, dx, ddx, val, pal;
schar dy;
u16int tnli;
int i;
int i, x, big;
struct { u8int y, x, t, f; } *s;
y = mem[LY];
big = mem[LCDC] & SPRITE16;
s = (void*)(mem + 0xFE00);
for(i = 0; i < 40; i++, s++){
if(s->y == 0 && s->x == 0)
if(s->y == 0 || s->x == 0)
continue;
dy = y - s->y + 16;
if(dy < 0 || dy >= 8)
if(dy < 0 || dy >= (big ? 16 : 8))
continue;
pal = (s->f & (1<<4)) ? mem[OBP1] : mem[OBP0];
if(s->f & (1<<6))
dy = 7 - dy;
tnli = 0x8000 + 2 * (u16int)dy + 16 * (u16int) s->t;
dy = (big ? 15 : 7) - dy;
t = s->t;
if(big){
if(dy >= 8){
t |= 1;
dy -= 8;
}else
t &= ~1;
}
tnli = 0x8000 + 2 * (u16int)dy + 16 * (u16int) t;
tnl1 = mem[tnli];
tnl2 = mem[tnli + 1];
x = s->x - 9;
@ -105,14 +114,14 @@ drawsprites(void)
if((s->f & (1<<5)) == 0)
ddx = 7 - dx;
val = ((tnl1 >> ddx) & 1) | (((tnl2 >> ddx) & 1) << 1);
if(val == 0)
if(x < 0 || val == 0)
continue;
val = (pal >> (2 * val)) & 3;
if(x >= 160)
break;
if(s->f & (1<<7)){
if(s->f & (1<<7))
pixelbelow(x, y, val);
}else
else
pixel(x, y, val, 0);
}
}
@ -167,8 +176,9 @@ ppustep(void)
interrupt(INTLCDC);
}else
mem[STAT] &= ~4;
if(mem[LY] < 144 && (mem[LCDC] & LCDOP)){
if(mem[LY] < 144)
mem[STAT] &= ~3;
if(mem[LY] < 144 && (mem[LCDC] & LCDOP)){
if(mem[LCDC] & BGDISP)
drawbg();
if(mem[LCDC] & WINDOWDISP)

View file

@ -81,7 +81,6 @@ loadstate(char *file)
clock = get32();
ppuclock = get32();
divclock = get32();
syncclock = get32();
timerfreq = get32();
timer = get32();
rombank = get32();
@ -114,7 +113,6 @@ savestate(char *file)
put32(ppuclock);
put32(divclock);
put32(timerclock);
put32(syncclock);
put32(timerfreq);
put32(timer);
put32(rombank);