code: plan9front

Download patch

ref: 03eeebb97f014c29a4dd25d873fc6ad50da48f15
parent: f1d29a9d12fa6d89015735ea010ac4b02f1b80b5
author: Michael Forney <mforney@mforney.org>
date: Wed Feb 17 06:20:05 EST 2021

games/snes: implement DSP echo

--- a/sys/src/games/snes/dsp.c
+++ b/sys/src/games/snes/dsp.c
@@ -7,7 +7,9 @@
 
 u8int dsp[256], dspstate;
 u16int dspcounter, noise = 0x8000;
-static s16int samp[2], echoin[2];
+static s16int samp[2], echoin[2], echobuf[2*2*8];
+static u16int echoaddr;
+static int echobp, echopos;
 
 enum {
 	VOLL = 0,
@@ -24,8 +26,8 @@
 	EFB = 0x0d,
 	MVOLR = 0x1c,
 	EVOLL = 0x2c,
-	EVOLR = 0x2d,
 	PMON = 0x2d,
+	EVOLR = 0x3c,
 	NON = 0x3d,
 	EON = 0x4d,
 	KON = 0x4c,
@@ -32,7 +34,9 @@
 	KOFF = 0x5c,
 	DIR = 0x5d,
 	FLG = 0x6c,
+	ESA = 0x6d,
 	ENDX = 0x7c,
+	EDL = 0x7d,
 	NEWKON = 0x8e,
 	INT = 0x80,
 };
@@ -96,6 +100,13 @@
 	return v;
 }
 
+static void
+spcput16(u16int p, u16int v)
+{
+	spcmem[p++] = v;
+	spcmem[p] = v >> 8;
+}
+
 u8int
 dspread(u8int p)
 {
@@ -412,33 +423,57 @@
 echo(int s)
 {
 	static s16int echoout[2];
-	static u8int fir[8];
+	s16int *x;
+	s8int h;
 	int a, b;
 
+	x = echobuf + echobp;
 	switch(s){
 	case 22:
-		echoout[0] = 0;
-		fir[0] = dsp[0x0f];
+		echoaddr = (dsp[INT|ESA] << 8) + echopos;
+		x[0] = x[16] = spc16(echoaddr);
+		h = dsp[0x0f];
+		echoout[0] = x[2] * h >> 7;
+		echoout[1] = x[3] * h >> 7;
 		break;
 	case 23:
-		fir[1] = dsp[0x1f];
-		fir[2] = dsp[0x2f];
+		h = dsp[0x1f];
+		echoout[0] += x[4] * h >> 7;
+		echoout[1] += x[5] * h >> 7;
+		h = dsp[0x2f];
+		echoout[0] += x[6] * h >> 7;
+		echoout[1] += x[7] * h >> 7;
+		x[1] = x[17] = spc16(echoaddr + 2);
 		break;
 	case 24:
-		fir[3] = dsp[0x3f];
-		fir[4] = dsp[0x4f];
-		fir[5] = dsp[0x5f];
+		h = dsp[0x3f];
+		echoout[0] += x[8] * h >> 7;
+		echoout[1] += x[9] * h >> 7;
+		h = dsp[0x4f];
+		echoout[0] += x[10] * h >> 7;
+		echoout[1] += x[11] * h >> 7;
+		h = dsp[0x5f];
+		echoout[0] += x[12] * h >> 7;
+		echoout[1] += x[13] * h >> 7;
 		break;
 	case 25:
-		fir[6] = dsp[0x6f];
-		fir[7] = dsp[0x7f];
+		h = dsp[0x6f];
+		echoout[0] += x[14] * h >> 7;
+		echoout[1] += x[15] * h >> 7;
+		h = dsp[0x7f];
+		echoout[0] += x[16] * h >> 7;
+		echoout[1] += x[17] * h >> 7;
+		echoout[0] &= ~1;
+		echoout[1] &= ~1;
 		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;
+		a = echoout[0] * (s8int)dsp[EFB] >> 7;
+		echoin[0] = clamp16(echoin[0] + a) & ~1;
+		a = echoout[1] * (s8int)dsp[EFB] >> 7;
+		echoin[1] = clamp16(echoin[1] + a) & ~1;
 		break;
 	case 27:
 		a = (samp[1] * (s8int)dsp[MVOLR]) >> 7;
@@ -449,9 +484,22 @@
 		dsp[INT|FLG] = dsp[FLG];
 		break;
 	case 29:
+		dsp[INT|ESA] = dsp[ESA];
+		if(echopos == 0)
+			dsp[INT|EDL] = dsp[EDL] & 0xf;
+		echopos += 4;
+		if(echopos >= dsp[INT|EDL] << 11)
+			echopos = 0;
+		if((dsp[INT|FLG] & 0x20) == 0)
+			spcput16(echoaddr, echoin[0]);
+		echoin[0] = 0;
 		dsp[INT|FLG] = dsp[FLG];
 		break;
 	case 30:
+		if((dsp[INT|FLG] & 0x20) == 0)
+			spcput16(echoaddr + 2, echoin[1]);
+		echoin[1] = 0;
+		echobp = echobp + 2 & 15;
 		break;
 	}
 }