more games/gb fun
This commit is contained in:
parent
4950b5468b
commit
8ebb846fb2
9 changed files with 236 additions and 31 deletions
152
sys/src/games/gb/audio.c
Normal file
152
sys/src/games/gb/audio.c
Normal 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);
|
||||
}
|
|
@ -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]);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -8,3 +8,4 @@ void message(char *, ...);
|
|||
void flushram(void);
|
||||
void savestate(char *);
|
||||
void loadstate(char *);
|
||||
void initaudio(void);
|
|
@ -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){
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ OFILES=\
|
|||
ppu.$O\
|
||||
daa.$O\
|
||||
state.$O\
|
||||
audio.$O\
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue