games/snes: audio support (kind of)
This commit is contained in:
parent
f783587f05
commit
f14b49f8bf
|
@ -1,3 +1,6 @@
|
||||||
|
typedef signed char s8int;
|
||||||
|
typedef signed short s16int;
|
||||||
|
|
||||||
extern u16int pc;
|
extern u16int pc;
|
||||||
extern u32int rPB, curpc;
|
extern u32int rPB, curpc;
|
||||||
extern u8int dma, nmi, irq;
|
extern u8int dma, nmi, irq;
|
||||||
|
@ -13,9 +16,10 @@ extern u16int cgram[256];
|
||||||
extern int ppux, ppuy, rx;
|
extern int ppux, ppuy, rx;
|
||||||
extern u16int vtime, htime, subcolor, oamaddr;
|
extern u16int vtime, htime, subcolor, oamaddr;
|
||||||
extern u16int hofs[5], vofs[5];
|
extern u16int hofs[5], vofs[5];
|
||||||
typedef signed short s16int;
|
|
||||||
extern s16int m7[6];
|
extern s16int m7[6];
|
||||||
|
|
||||||
|
extern u8int spcmem[65536];
|
||||||
|
|
||||||
extern int battery, saveclock, scale, mouse;
|
extern int battery, saveclock, scale, mouse;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
602
sys/src/games/snes/dsp.c
Normal file
602
sys/src/games/snes/dsp.c
Normal file
|
@ -0,0 +1,602 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
static u8int dsp[256], dspstate;
|
||||||
|
static u16int counter, noise;
|
||||||
|
static s16int samp[2], echoin[2];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VOLL = 0,
|
||||||
|
VOLR = 1,
|
||||||
|
PITCHL = 2,
|
||||||
|
PITCHH = 3,
|
||||||
|
SRCN = 4,
|
||||||
|
ADSR1 = 5,
|
||||||
|
ADSR2 = 6,
|
||||||
|
GAIN = 7,
|
||||||
|
ENVX = 8,
|
||||||
|
OUTX = 9,
|
||||||
|
MVOLL = 0x0c,
|
||||||
|
EFB = 0x0d,
|
||||||
|
MVOLR = 0x1c,
|
||||||
|
EVOLL = 0x2c,
|
||||||
|
EVOLR = 0x2d,
|
||||||
|
PMON = 0x2d,
|
||||||
|
NON = 0x3d,
|
||||||
|
EON = 0x4d,
|
||||||
|
KON = 0x4c,
|
||||||
|
KOFF = 0x5c,
|
||||||
|
DIR = 0x5d,
|
||||||
|
FLG = 0x6c,
|
||||||
|
ENDX = 0x7c,
|
||||||
|
NEWKON = 0x8e,
|
||||||
|
INT = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
READY = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { RELEASE, ATTACK, DECAY, SUSTAIN };
|
||||||
|
|
||||||
|
static s16int sbuf[2*2000], *sbufp;
|
||||||
|
static int fd;
|
||||||
|
|
||||||
|
void
|
||||||
|
audioinit(void)
|
||||||
|
{
|
||||||
|
int cfd;
|
||||||
|
static char c[] = "speed 32000";
|
||||||
|
|
||||||
|
fd = open("/dev/audio", OWRITE);
|
||||||
|
if(fd < 0)
|
||||||
|
return;
|
||||||
|
cfd = open("/dev/volume", OWRITE);
|
||||||
|
if(cfd >= 0)
|
||||||
|
write(cfd, c, sizeof(c));
|
||||||
|
sbufp = sbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
audiosample(s16int *s)
|
||||||
|
{
|
||||||
|
if(sbufp < sbuf + nelem(sbuf)){
|
||||||
|
*sbufp++ = s[0];
|
||||||
|
*sbufp++ = s[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
audioout(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if(sbufp == nil)
|
||||||
|
return -1;
|
||||||
|
if(sbufp == sbuf)
|
||||||
|
return 0;
|
||||||
|
rc = write(fd, sbuf, (sbufp - sbuf) * 2);
|
||||||
|
if(rc > 0)
|
||||||
|
sbufp -= (rc+1)/2;
|
||||||
|
if(sbufp < sbuf)
|
||||||
|
sbufp = sbuf;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16int
|
||||||
|
spc16(u16int p)
|
||||||
|
{
|
||||||
|
u16int v;
|
||||||
|
|
||||||
|
v = spcmem[p++];
|
||||||
|
v |= spcmem[p] << 8;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8int
|
||||||
|
dspread(u8int p)
|
||||||
|
{
|
||||||
|
p &= 0x7f;
|
||||||
|
return dsp[p];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dspwrite(u8int p, u8int v)
|
||||||
|
{
|
||||||
|
if(p >= 0x80)
|
||||||
|
return;
|
||||||
|
switch(p){
|
||||||
|
case 0x4c:
|
||||||
|
dsp[NEWKON] = v;
|
||||||
|
break;
|
||||||
|
case 0x7c:
|
||||||
|
v = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dsp[p] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
envyes(int r)
|
||||||
|
{
|
||||||
|
static u16int modulus[] = {
|
||||||
|
0, 2048, 1536, 1280, 1024, 768, 640, 512, 384,
|
||||||
|
320, 256, 192, 160, 128, 96, 80, 64, 48,
|
||||||
|
40, 32, 24, 20, 16, 12, 10, 8, 6, 5, 4, 3,
|
||||||
|
};
|
||||||
|
u16int c;
|
||||||
|
|
||||||
|
if(r == 0)
|
||||||
|
return 0;
|
||||||
|
if(r >= 30){
|
||||||
|
if(r == 31)
|
||||||
|
return 1;
|
||||||
|
return (counter & 1) == 0;
|
||||||
|
}
|
||||||
|
c = counter;
|
||||||
|
switch(r % 3){
|
||||||
|
case 0: c += 536; break;
|
||||||
|
case 2: c += 1040; break;
|
||||||
|
}
|
||||||
|
return c % modulus[r] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s16int
|
||||||
|
clamp16(int v)
|
||||||
|
{
|
||||||
|
if(v < -32768)
|
||||||
|
return -32768;
|
||||||
|
if(v > 32767)
|
||||||
|
return 32767;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int n;
|
||||||
|
u8int *r;
|
||||||
|
|
||||||
|
u16int hdrp, dp, sp;
|
||||||
|
u8int hdr;
|
||||||
|
u16int brr;
|
||||||
|
|
||||||
|
u8int envst;
|
||||||
|
u16int env, envbent;
|
||||||
|
|
||||||
|
u8int init;
|
||||||
|
u16int interp;
|
||||||
|
s16int buf[12];
|
||||||
|
|
||||||
|
u16int pitch;
|
||||||
|
s16int sample, modin;
|
||||||
|
} vctxt;
|
||||||
|
vctxt vctxts[8];
|
||||||
|
|
||||||
|
static void
|
||||||
|
env(vctxt *p)
|
||||||
|
{
|
||||||
|
u8int *r, a, g;
|
||||||
|
|
||||||
|
r = p->r;
|
||||||
|
a = r[INT|ADSR1];
|
||||||
|
if((a & 0x80) != 0)
|
||||||
|
g = r[ADSR2];
|
||||||
|
else
|
||||||
|
g = r[GAIN];
|
||||||
|
if(p->envst == RELEASE)
|
||||||
|
p->env -= 8;
|
||||||
|
else if((a & 0x80) != 0){
|
||||||
|
switch(p->envst){
|
||||||
|
case ATTACK:
|
||||||
|
if(envyes((a & 0xf) << 1 | 1))
|
||||||
|
p->env += (a & 0xf) == 0xf ? 1024 : 32;
|
||||||
|
break;
|
||||||
|
case DECAY:
|
||||||
|
if(envyes(a >> 3 & 0xe | 0x10))
|
||||||
|
p->env -= ((p->env - 1) >> 8) + 1;
|
||||||
|
break;
|
||||||
|
case SUSTAIN:
|
||||||
|
if(envyes(g & 0x1f))
|
||||||
|
p->env -= ((p->env - 1) >> 8) + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if((g & 0x80) != 0){
|
||||||
|
if(envyes(g & 0x1f))
|
||||||
|
switch((g >> 5) & 3){
|
||||||
|
case 0: p->env -= 32; break;
|
||||||
|
case 1: p->env -= ((p->env - 1) >> 8) + 1; break;
|
||||||
|
case 2: p->env += 32; break;
|
||||||
|
case 3:
|
||||||
|
if(p->envbent < 0x600)
|
||||||
|
p->env += 32;
|
||||||
|
else
|
||||||
|
p->env += 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
p->env = g << 4;
|
||||||
|
}
|
||||||
|
p->envbent = p->env & 0x7ff;
|
||||||
|
if((p->env & 0x8000) != 0)
|
||||||
|
p->env = 0;
|
||||||
|
else if(p->env > 0x7ff){
|
||||||
|
p->env = 0x7ff;
|
||||||
|
if(p->envst == ATTACK){
|
||||||
|
p->envst = DECAY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(p->envst == DECAY && (p->env >> 8) == (g >> 5))
|
||||||
|
p->envst = SUSTAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
decode(vctxt *p)
|
||||||
|
{
|
||||||
|
int i, d, s1, s2;
|
||||||
|
u8int f, s;
|
||||||
|
s16int brr;
|
||||||
|
|
||||||
|
f = (p->hdr >> 2) & 3;
|
||||||
|
s = p->hdr >> 4;
|
||||||
|
brr = p->brr;
|
||||||
|
s1 = p->buf[7];
|
||||||
|
s2 = p->buf[6];
|
||||||
|
for(i = 0; i < 4; i++){
|
||||||
|
d = brr >> 12;
|
||||||
|
if(s >= 13)
|
||||||
|
d = d & ~0x7ff;
|
||||||
|
else{
|
||||||
|
d <<= s;
|
||||||
|
d >>= 1;
|
||||||
|
}
|
||||||
|
s2 >>= 1;
|
||||||
|
switch(f){
|
||||||
|
case 1:
|
||||||
|
d += s1 >> 1;
|
||||||
|
d += (-s1) >> 5;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
d += s1;
|
||||||
|
d -= s2;
|
||||||
|
d += s2 >> 4;
|
||||||
|
d += (s1 * -3) >> 6;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
d += s1;
|
||||||
|
d -= s2;
|
||||||
|
d += (s1 * -13) >> 7;
|
||||||
|
d += (s2 * 3) >> 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d = (s16int)(clamp16(d) << 1);
|
||||||
|
p->buf[8 + i] = d;
|
||||||
|
s1 = d;
|
||||||
|
s2 = s1;
|
||||||
|
brr <<= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static s16int
|
||||||
|
interp(u16int x, s16int *s)
|
||||||
|
{
|
||||||
|
extern u16int gauss[];
|
||||||
|
int v;
|
||||||
|
u8int i, d;
|
||||||
|
|
||||||
|
i = x >> 12;
|
||||||
|
d = x >> 4;
|
||||||
|
v = ((int)gauss[255 - d] * s[i]) >> 11;
|
||||||
|
v += ((int)gauss[511 - d] * s[i+1]) >> 11;
|
||||||
|
v += ((int)gauss[256 + d] * s[i+2]) >> 11;
|
||||||
|
v = (s16int)v;
|
||||||
|
v += ((int)gauss[d] * s[i+3]) >> 11;
|
||||||
|
return clamp16(v) & ~1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
voice(int n, int s)
|
||||||
|
{
|
||||||
|
vctxt *p;
|
||||||
|
u8int *r, m;
|
||||||
|
u16int a;
|
||||||
|
int v;
|
||||||
|
|
||||||
|
p = vctxts + n;
|
||||||
|
r = p->r;
|
||||||
|
switch(s){
|
||||||
|
case 1:
|
||||||
|
r[INT|SRCN] = r[SRCN];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
a = (dsp[INT|DIR] << 8) + (r[INT|SRCN] << 2);
|
||||||
|
if(p->init == READY)
|
||||||
|
a += 2;
|
||||||
|
p->sp = spc16(a);
|
||||||
|
p->pitch = r[PITCHL];
|
||||||
|
r[INT|ADSR1] = r[ADSR1];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
p->pitch |= r[PITCHH] << 8 & 0x3f00;
|
||||||
|
if(n == 0)
|
||||||
|
break;
|
||||||
|
case 0x31:
|
||||||
|
p->hdr = spcmem[p->hdrp];
|
||||||
|
p->brr = spcmem[p->dp] << 8;
|
||||||
|
if(n == 0)
|
||||||
|
break;
|
||||||
|
case 0x32:
|
||||||
|
if((dsp[INT|PMON] & 0xfe & 1<<n) != 0)
|
||||||
|
p->pitch += ((p[-1].modin >> 5) * p->pitch) >> 10;
|
||||||
|
if(p->init < READY){
|
||||||
|
p->pitch = 0;
|
||||||
|
p->env = 0;
|
||||||
|
}
|
||||||
|
if((dsp[INT|NON] & 1<<n) != 0)
|
||||||
|
p->sample = noise;
|
||||||
|
p->sample = (((int)p->sample * p->env) >> 11) & ~1;
|
||||||
|
p->modin = p->sample;
|
||||||
|
r[INT|OUTX] = p->sample >> 8;
|
||||||
|
r[INT|ENVX] = p->env >> 4;
|
||||||
|
if((dsp[FLG] & 0x80) != 0 || (p->hdr & 3) == 1){
|
||||||
|
p->envst = RELEASE;
|
||||||
|
p->env = 0;
|
||||||
|
}
|
||||||
|
if((dsp[INT|KOFF] & 1<<n) != 0)
|
||||||
|
p->envst = RELEASE;
|
||||||
|
if((dsp[INT|KON] & 1<<n) != 0){
|
||||||
|
p->envst = ATTACK;
|
||||||
|
p->init = 0;
|
||||||
|
}
|
||||||
|
if(p->init >= READY - 1)
|
||||||
|
env(p);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
v = (p->sample * ((s8int)r[VOLL])) >> 7;
|
||||||
|
samp[0] = clamp16(samp[0] + v);
|
||||||
|
if((dsp[INT|EON] & (1<<n)) != 0)
|
||||||
|
echoin[0] = clamp16(echoin[0] + v);
|
||||||
|
if(p->init == 1){
|
||||||
|
p->hdrp = p->sp;
|
||||||
|
p->dp = p->hdrp + 1;
|
||||||
|
}
|
||||||
|
if(p->interp >= 0x4000 || p->init <= 4 && p->init >= 2){
|
||||||
|
memmove(p->buf, p->buf + 4, 8 * sizeof(s16int));
|
||||||
|
p->brr |= spcmem[++p->dp];
|
||||||
|
if(++p->dp == p->hdrp + 9){
|
||||||
|
if((p->hdr & 1) != 0){
|
||||||
|
dsp[INT|ENDX] |= 1<<n;
|
||||||
|
p->hdrp = p->sp;
|
||||||
|
}else
|
||||||
|
p->hdrp += 9;
|
||||||
|
p->dp = p->hdrp + 1;
|
||||||
|
}
|
||||||
|
decode(p);
|
||||||
|
}
|
||||||
|
if(p->interp >= 0x4000)
|
||||||
|
p->interp -= 0x4000;
|
||||||
|
p->interp += p->pitch;
|
||||||
|
if(p->interp >= 0x7fff)
|
||||||
|
p->interp = 0x7fff;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
v = (p->sample * ((s8int)r[VOLR])) >> 7;
|
||||||
|
samp[1] = clamp16(samp[1] + v);
|
||||||
|
if((dsp[INT|EON] & (1<<n)) != 0)
|
||||||
|
echoin[1] = clamp16(echoin[1] + v);
|
||||||
|
p->sample = interp(p->interp, p->buf);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
m = 1<<n;
|
||||||
|
if(p->init == 0)
|
||||||
|
dsp[INT|ENDX] &= ~m;
|
||||||
|
dsp[ENDX] = dsp[ENDX] & ~m | dsp[INT|ENDX] & m;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
r[OUTX] = r[INT|OUTX];
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
r[ENVX] = r[INT|ENVX];
|
||||||
|
if(p->init < READY)
|
||||||
|
p->init++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
echo(int s)
|
||||||
|
{
|
||||||
|
static s16int echoout[2];
|
||||||
|
static u8int fir[8];
|
||||||
|
int a, b;
|
||||||
|
|
||||||
|
switch(s){
|
||||||
|
case 22:
|
||||||
|
echoout[0] = 0;
|
||||||
|
fir[0] = dsp[0x0f];
|
||||||
|
break;
|
||||||
|
case 23:
|
||||||
|
fir[1] = dsp[0x1f];
|
||||||
|
fir[2] = dsp[0x2f];
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
fir[3] = dsp[0x3f];
|
||||||
|
fir[4] = dsp[0x4f];
|
||||||
|
fir[5] = dsp[0x5f];
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
fir[6] = dsp[0x6f];
|
||||||
|
fir[7] = dsp[0x7f];
|
||||||
|
break;
|
||||||
|
case 26:
|
||||||
|
a = (samp[0] * (s8int)dsp[MVOLL]) >> 7;
|
||||||
|
b = (echoout[0] * (s8int)dsp[EVOLL]) >> 7;
|
||||||
|
samp[0] = clamp16(a + b);
|
||||||
|
echoin[0] = (echoin[0] * (s8int)dsp[EFB]) >> 7;
|
||||||
|
echoin[1] = (echoin[1] * (s8int)dsp[EFB]) >> 7;
|
||||||
|
break;
|
||||||
|
case 27:
|
||||||
|
a = (samp[1] * (s8int)dsp[MVOLR]) >> 7;
|
||||||
|
b = (echoout[1] * (s8int)dsp[EVOLR]) >> 7;
|
||||||
|
samp[1] = clamp16(a + b);
|
||||||
|
break;
|
||||||
|
case 28:
|
||||||
|
dsp[INT|FLG] = dsp[FLG];
|
||||||
|
break;
|
||||||
|
case 29:
|
||||||
|
dsp[INT|FLG] = dsp[FLG];
|
||||||
|
break;
|
||||||
|
case 30:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dspstep(void)
|
||||||
|
{
|
||||||
|
if(sbufp == nil)
|
||||||
|
return;
|
||||||
|
switch(dspstate++ & 31){
|
||||||
|
case 0: voice(0, 5); voice(1, 2); break;
|
||||||
|
case 1: voice(0, 6); voice(1, 3); break;
|
||||||
|
case 2: voice(0, 7); voice(1, 4); voice(3, 1); break;
|
||||||
|
case 3: voice(0, 8); voice(1, 5); voice(2, 2); break;
|
||||||
|
case 4: voice(0, 9); voice(1, 6); voice(2, 3); break;
|
||||||
|
case 5: voice(1, 7); voice(2, 4); voice(4, 1); break;
|
||||||
|
case 6: voice(1, 8); voice(2, 5); voice(3, 2); break;
|
||||||
|
case 7: voice(1, 9); voice(2, 6); voice(3, 3); break;
|
||||||
|
case 8: voice(2, 7); voice(3, 4); voice(5, 1); break;
|
||||||
|
case 9: voice(2, 8); voice(3, 5); voice(4, 2); break;
|
||||||
|
case 10: voice(2, 9); voice(3, 6); voice(4, 3); break;
|
||||||
|
case 11: voice(3, 7); voice(4, 4); voice(6, 1); break;
|
||||||
|
case 12: voice(3, 8); voice(4, 5); voice(5, 2); break;
|
||||||
|
case 13: voice(3, 9); voice(4, 6); voice(5, 3); break;
|
||||||
|
case 14: voice(4, 7); voice(5, 4); voice(7, 1); break;
|
||||||
|
case 15: voice(4, 8); voice(5, 5); voice(6, 2); break;
|
||||||
|
case 16: voice(4, 9); voice(5, 6); voice(6, 3); break;
|
||||||
|
case 17: voice(5, 7); voice(6, 4); voice(0, 1); break;
|
||||||
|
case 18: voice(5, 8); voice(6, 5); voice(7, 2); break;
|
||||||
|
case 19: voice(5, 9); voice(6, 6); voice(7, 3); break;
|
||||||
|
case 20: voice(6, 7); voice(7, 4); voice(1, 1); break;
|
||||||
|
case 21: voice(6, 8); voice(7, 5); voice(0, 2); break;
|
||||||
|
case 22: voice(6, 9); voice(7, 6); voice(0, 3); echo(22); break;
|
||||||
|
case 23: voice(7, 7); echo(23); break;
|
||||||
|
case 24: voice(7, 8); echo(24); break;
|
||||||
|
case 25: voice(7, 9); voice(0, 0x31); echo(25); break;
|
||||||
|
case 26: echo(26); break;
|
||||||
|
case 27:
|
||||||
|
dsp[INT|PMON] = dsp[PMON];
|
||||||
|
echo(27);
|
||||||
|
if((dsp[FLG] & 0x40) != 0)
|
||||||
|
samp[0] = samp[1] = 0;
|
||||||
|
audiosample(samp);
|
||||||
|
samp[0] = samp[1] = 0;
|
||||||
|
break;
|
||||||
|
case 28:
|
||||||
|
dsp[INT|NON] = dsp[NON];
|
||||||
|
dsp[INT|EON] = dsp[EON];
|
||||||
|
dsp[INT|DIR] = dsp[DIR];
|
||||||
|
echo(28);
|
||||||
|
break;
|
||||||
|
case 29:
|
||||||
|
echo(29);
|
||||||
|
if((dspstate & 64) == 0)
|
||||||
|
dsp[NEWKON] &= ~dsp[INT|KON];
|
||||||
|
break;
|
||||||
|
case 30:
|
||||||
|
voice(0, 0x32);
|
||||||
|
echo(30);
|
||||||
|
if((dspstate & 64) == 0){
|
||||||
|
dsp[INT|KOFF] = dsp[KOFF];
|
||||||
|
dsp[INT|KON] = dsp[NEWKON];
|
||||||
|
}
|
||||||
|
if(counter-- == 0)
|
||||||
|
counter = 0x77ff;
|
||||||
|
break;
|
||||||
|
case 31: voice(0, 4); voice(2, 1); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dspreset(void)
|
||||||
|
{
|
||||||
|
vctxt *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < 8; i++){
|
||||||
|
p = vctxts + i;
|
||||||
|
p->n = i;
|
||||||
|
p->r = dsp + (i << 4);
|
||||||
|
}
|
||||||
|
dsp[FLG] = 0xe0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16int gauss[512] = {
|
||||||
|
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||||
|
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||||
|
0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
|
||||||
|
0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002,
|
||||||
|
0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004,
|
||||||
|
0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005,
|
||||||
|
0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008,
|
||||||
|
0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A,
|
||||||
|
0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E,
|
||||||
|
0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011,
|
||||||
|
0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016,
|
||||||
|
0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B,
|
||||||
|
0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021,
|
||||||
|
0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028,
|
||||||
|
0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030,
|
||||||
|
0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038,
|
||||||
|
0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042,
|
||||||
|
0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D,
|
||||||
|
0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059,
|
||||||
|
0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066,
|
||||||
|
0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075,
|
||||||
|
0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084,
|
||||||
|
0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096,
|
||||||
|
0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8,
|
||||||
|
0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC,
|
||||||
|
0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2,
|
||||||
|
0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9,
|
||||||
|
0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101,
|
||||||
|
0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B,
|
||||||
|
0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137,
|
||||||
|
0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153,
|
||||||
|
0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172,
|
||||||
|
0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191,
|
||||||
|
0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2,
|
||||||
|
0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5,
|
||||||
|
0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8,
|
||||||
|
0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C,
|
||||||
|
0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241,
|
||||||
|
0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267,
|
||||||
|
0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E,
|
||||||
|
0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5,
|
||||||
|
0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC,
|
||||||
|
0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304,
|
||||||
|
0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B,
|
||||||
|
0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353,
|
||||||
|
0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379,
|
||||||
|
0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F,
|
||||||
|
0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5,
|
||||||
|
0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9,
|
||||||
|
0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C,
|
||||||
|
0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E,
|
||||||
|
0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E,
|
||||||
|
0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C,
|
||||||
|
0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488,
|
||||||
|
0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2,
|
||||||
|
0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA,
|
||||||
|
0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0,
|
||||||
|
0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3,
|
||||||
|
0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3,
|
||||||
|
0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500,
|
||||||
|
0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B,
|
||||||
|
0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512,
|
||||||
|
0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517,
|
||||||
|
0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519
|
||||||
|
};
|
|
@ -11,3 +11,9 @@ void memreset(void);
|
||||||
int hdmastep(void);
|
int hdmastep(void);
|
||||||
void flush(void);
|
void flush(void);
|
||||||
void message(char *, ...);
|
void message(char *, ...);
|
||||||
|
void dspstep(void);
|
||||||
|
u8int dspread(u8int);
|
||||||
|
void dspwrite(u8int, u8int);
|
||||||
|
void dspreset(void);
|
||||||
|
void audioinit(void);
|
||||||
|
int audioout(void);
|
||||||
|
|
|
@ -288,12 +288,12 @@ regwrite(u16int p, u8int v)
|
||||||
if((v & 0x40) != 0) subcolor = subcolor & 0x7c1f | (v & 0x1f) << 5;
|
if((v & 0x40) != 0) subcolor = subcolor & 0x7c1f | (v & 0x1f) << 5;
|
||||||
if((v & 0x20) != 0) subcolor = subcolor & 0x03ff | (v & 0x1f) << 10;
|
if((v & 0x20) != 0) subcolor = subcolor & 0x03ff | (v & 0x1f) << 10;
|
||||||
return;
|
return;
|
||||||
|
case 0x213e:
|
||||||
|
return;
|
||||||
case 0x2180:
|
case 0x2180:
|
||||||
memwrite(0x7e0000 | reg[0x2181] | reg[0x2182] << 8 | (reg[0x2183] & 1) << 16, v);
|
memwrite(0x7e0000 | reg[0x2181] | reg[0x2182] << 8 | (reg[0x2183] & 1) << 16, v);
|
||||||
incwram();
|
incwram();
|
||||||
return;
|
return;
|
||||||
case 0x213e:
|
|
||||||
return;
|
|
||||||
case 0x4016:
|
case 0x4016:
|
||||||
if((reg[0x4016] & 1) != 0 && (v & 1) == 0){
|
if((reg[0x4016] & 1) != 0 && (v & 1) == 0){
|
||||||
if(mouse)
|
if(mouse)
|
||||||
|
|
|
@ -8,6 +8,7 @@ OFILES=\
|
||||||
mem.$O\
|
mem.$O\
|
||||||
ppu.$O\
|
ppu.$O\
|
||||||
spc.$O\
|
spc.$O\
|
||||||
|
dsp.$O\
|
||||||
|
|
||||||
HFILES=dat.h fns.h
|
HFILES=dat.h fns.h
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
uchar *prg, *sram;
|
uchar *prg, *sram;
|
||||||
int nprg, nsram, hirom, battery;
|
int nprg, nsram, hirom, battery;
|
||||||
|
|
||||||
int ppuclock, spcclock, stimerclock, saveclock, msgclock, paused, perfclock;
|
int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, paused, perfclock;
|
||||||
Mousectl *mc;
|
Mousectl *mc;
|
||||||
QLock pauselock;
|
QLock pauselock;
|
||||||
u32int keys;
|
u32int keys;
|
||||||
|
@ -57,11 +57,14 @@ loadrom(char *file)
|
||||||
if(readn(fd, prg, size) < size)
|
if(readn(fd, prg, size) < size)
|
||||||
sysfatal("read: %r");
|
sysfatal("read: %r");
|
||||||
close(fd);
|
close(fd);
|
||||||
if((memread(0xffd5) & ~0x10) != 0x20)
|
if(hirom < 0){
|
||||||
if((memread(0x1ffd5) & ~0x10) == 0x21)
|
hirom = 0;
|
||||||
hirom = 1;
|
if((memread(0xffd5) & ~0x10) != 0x20)
|
||||||
else
|
if((memread(0x1ffd5) & ~0x10) == 0x21)
|
||||||
sysfatal("invalid rom (neither hirom nor lorom)");
|
hirom = 1;
|
||||||
|
else
|
||||||
|
sysfatal("invalid rom (ffd5 = %.2x, 1ffd5 = %.2x)", memread(0xffd5), memread(0x1ffd5));
|
||||||
|
}
|
||||||
if(hirom)
|
if(hirom)
|
||||||
nprg >>= 1;
|
nprg >>= 1;
|
||||||
switch(memread(0xffd6)){
|
switch(memread(0xffd6)){
|
||||||
|
@ -201,6 +204,7 @@ threadmain(int argc, char **argv)
|
||||||
extern u16int pc;
|
extern u16int pc;
|
||||||
|
|
||||||
scale = 1;
|
scale = 1;
|
||||||
|
hirom = -1;
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case '2':
|
case '2':
|
||||||
scale = 2;
|
scale = 2;
|
||||||
|
@ -208,6 +212,9 @@ threadmain(int argc, char **argv)
|
||||||
case '3':
|
case '3':
|
||||||
scale = 3;
|
scale = 3;
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
audioinit();
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
battery++;
|
battery++;
|
||||||
break;
|
break;
|
||||||
|
@ -215,6 +222,9 @@ threadmain(int argc, char **argv)
|
||||||
mouse++;
|
mouse++;
|
||||||
keys = 1<<16;
|
keys = 1<<16;
|
||||||
break;
|
break;
|
||||||
|
case 'h':
|
||||||
|
hirom++;
|
||||||
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
profile++;
|
profile++;
|
||||||
break;
|
break;
|
||||||
|
@ -239,6 +249,7 @@ usage:
|
||||||
cpureset();
|
cpureset();
|
||||||
memreset();
|
memreset();
|
||||||
spcreset();
|
spcreset();
|
||||||
|
dspreset();
|
||||||
for(;;){
|
for(;;){
|
||||||
if(paused){
|
if(paused){
|
||||||
qlock(&pauselock);
|
qlock(&pauselock);
|
||||||
|
@ -248,6 +259,7 @@ usage:
|
||||||
spcclock -= t;
|
spcclock -= t;
|
||||||
stimerclock += t;
|
stimerclock += t;
|
||||||
ppuclock += t;
|
ppuclock += t;
|
||||||
|
dspclock += t;
|
||||||
perfclock -= t;
|
perfclock -= t;
|
||||||
|
|
||||||
while(ppuclock >= 4){
|
while(ppuclock >= 4){
|
||||||
|
@ -260,6 +272,10 @@ usage:
|
||||||
spctimerstep();
|
spctimerstep();
|
||||||
stimerclock -= SPCDIV*16;
|
stimerclock -= SPCDIV*16;
|
||||||
}
|
}
|
||||||
|
if(dspclock >= SPCDIV){
|
||||||
|
dspstep();
|
||||||
|
dspclock -= SPCDIV;
|
||||||
|
}
|
||||||
if(saveclock > 0){
|
if(saveclock > 0){
|
||||||
saveclock -= t;
|
saveclock -= t;
|
||||||
if(saveclock <= 0)
|
if(saveclock <= 0)
|
||||||
|
@ -307,6 +323,7 @@ flush(void)
|
||||||
loadimage(tmp, tmp->r, pic, 256*239*2*scale*scale);
|
loadimage(tmp, tmp->r, pic, 256*239*2*scale*scale);
|
||||||
draw(screen, picr, tmp, nil, ZP);
|
draw(screen, picr, tmp, nil, ZP);
|
||||||
flushimage(display, 1);
|
flushimage(display, 1);
|
||||||
|
audioout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -30,6 +30,8 @@ spcread(u16int p)
|
||||||
return ipl[p - 0xffc0];
|
return ipl[p - 0xffc0];
|
||||||
if((p & 0xfff0) == 0x00f0)
|
if((p & 0xfff0) == 0x00f0)
|
||||||
switch(p){
|
switch(p){
|
||||||
|
case 0xf3:
|
||||||
|
return dspread(spcmem[0xf2]);
|
||||||
case 0xf4:
|
case 0xf4:
|
||||||
case 0xf5:
|
case 0xf5:
|
||||||
case 0xf6:
|
case 0xf6:
|
||||||
|
@ -70,6 +72,9 @@ spcwrite(u16int p, u8int v)
|
||||||
if((spcmem[0xf1] & 4) == 0 && (v & 4) != 0)
|
if((spcmem[0xf1] & 4) == 0 && (v & 4) != 0)
|
||||||
spctimer[2] = spcmem[0xff] = 0;
|
spctimer[2] = spcmem[0xff] = 0;
|
||||||
break;
|
break;
|
||||||
|
case 0xf3:
|
||||||
|
dspwrite(spcmem[0xf2], v);
|
||||||
|
return;
|
||||||
case 0xfd:
|
case 0xfd:
|
||||||
case 0xfe:
|
case 0xfe:
|
||||||
case 0xff:
|
case 0xff:
|
||||||
|
|
Loading…
Reference in a new issue