xref: /inferno-os/os/mpc/dsp.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth /*
2*74a4d8c2SCharles.Forsyth  * DSP support functions
3*74a4d8c2SCharles.Forsyth  */
4*74a4d8c2SCharles.Forsyth 
5*74a4d8c2SCharles.Forsyth #include	"u.h"
6*74a4d8c2SCharles.Forsyth #include	"../port/lib.h"
7*74a4d8c2SCharles.Forsyth #include	"mem.h"
8*74a4d8c2SCharles.Forsyth #include	"dat.h"
9*74a4d8c2SCharles.Forsyth #include	"fns.h"
10*74a4d8c2SCharles.Forsyth #include	"../port/error.h"
11*74a4d8c2SCharles.Forsyth 
12*74a4d8c2SCharles.Forsyth #include	"io.h"
13*74a4d8c2SCharles.Forsyth 
14*74a4d8c2SCharles.Forsyth #include	"dsp.h"
15*74a4d8c2SCharles.Forsyth 
16*74a4d8c2SCharles.Forsyth enum {
17*74a4d8c2SCharles.Forsyth 	Ndsp = 2,		/* determined by hardware */
18*74a4d8c2SCharles.Forsyth 
19*74a4d8c2SCharles.Forsyth 	NHOLES=	64
20*74a4d8c2SCharles.Forsyth };
21*74a4d8c2SCharles.Forsyth 
22*74a4d8c2SCharles.Forsyth typedef struct DSPparam DSPparam;
23*74a4d8c2SCharles.Forsyth struct DSPparam {
24*74a4d8c2SCharles.Forsyth 	ulong	fdbase;	/* function descriptor table physical base address */
25*74a4d8c2SCharles.Forsyth 	ulong	fd_ptr;	/* function descriptor pointer */
26*74a4d8c2SCharles.Forsyth 	ulong	dstate;	/* DSP state */
27*74a4d8c2SCharles.Forsyth 	ulong	resvd[2];
28*74a4d8c2SCharles.Forsyth 	ushort	dstatus;	/* current function descriptor status */
29*74a4d8c2SCharles.Forsyth 	ushort	i;	/* number of iterations */
30*74a4d8c2SCharles.Forsyth 	ushort	tap;	/* number of TAPs */
31*74a4d8c2SCharles.Forsyth 	ushort	cbase;
32*74a4d8c2SCharles.Forsyth 	ushort	anon1;	/* sample buffer size-1 */
33*74a4d8c2SCharles.Forsyth 	ushort	xptr;	/* pointer to sample */
34*74a4d8c2SCharles.Forsyth 	ushort	anon2;	/* output buffer size-1 */
35*74a4d8c2SCharles.Forsyth 	ushort	yptr;	/* pointer to output */
36*74a4d8c2SCharles.Forsyth 	ushort	m;	/* sample buffer size-1 */
37*74a4d8c2SCharles.Forsyth 	ushort	anon3;	/* sample buffer pointer */
38*74a4d8c2SCharles.Forsyth 	ushort	n;	/* output buffer size -1 */
39*74a4d8c2SCharles.Forsyth 	ushort	anon4;	/* output buffer pointer */
40*74a4d8c2SCharles.Forsyth 	ushort	k;	/* coefficient buffer size - 1 */
41*74a4d8c2SCharles.Forsyth 	ushort	anon5;	/* coefficient buffer pointer */
42*74a4d8c2SCharles.Forsyth };
43*74a4d8c2SCharles.Forsyth 
44*74a4d8c2SCharles.Forsyth struct DSP {
45*74a4d8c2SCharles.Forsyth 	Lock;	/* protects state */
46*74a4d8c2SCharles.Forsyth 	void	(*done)(void*);
47*74a4d8c2SCharles.Forsyth 	void*	arg;
48*74a4d8c2SCharles.Forsyth 	DSPparam*	par;
49*74a4d8c2SCharles.Forsyth 	CPMdev*	cpm;
50*74a4d8c2SCharles.Forsyth 
51*74a4d8c2SCharles.Forsyth 	QLock;	/* protects busyr */
52*74a4d8c2SCharles.Forsyth 	int	busy;
53*74a4d8c2SCharles.Forsyth 	Rendez	busyr;
54*74a4d8c2SCharles.Forsyth };
55*74a4d8c2SCharles.Forsyth 
56*74a4d8c2SCharles.Forsyth static	DSP	dsps[Ndsp];
57*74a4d8c2SCharles.Forsyth static	Lock	dsplock;
58*74a4d8c2SCharles.Forsyth static	int	dspinit;
59*74a4d8c2SCharles.Forsyth static struct {
60*74a4d8c2SCharles.Forsyth 	QLock;
61*74a4d8c2SCharles.Forsyth 	ulong	avail;
62*74a4d8c2SCharles.Forsyth 	Rendez	wantr;
63*74a4d8c2SCharles.Forsyth } dspalloc;
64*74a4d8c2SCharles.Forsyth 
65*74a4d8c2SCharles.Forsyth static	Map	fndmapv[NHOLES];
66*74a4d8c2SCharles.Forsyth static	RMap	fndmap = {"DSP function descriptors"};
67*74a4d8c2SCharles.Forsyth 
68*74a4d8c2SCharles.Forsyth static void
dspinterrupt(Ureg *,void *)69*74a4d8c2SCharles.Forsyth dspinterrupt(Ureg*, void*)
70*74a4d8c2SCharles.Forsyth {
71*74a4d8c2SCharles.Forsyth 	int i;
72*74a4d8c2SCharles.Forsyth 	ushort events;
73*74a4d8c2SCharles.Forsyth 	DSP *dsp;
74*74a4d8c2SCharles.Forsyth 
75*74a4d8c2SCharles.Forsyth 	events = m->iomem->sdsr;
76*74a4d8c2SCharles.Forsyth 	m->iomem->sdsr = events;
77*74a4d8c2SCharles.Forsyth 	if(events & (1<<7))
78*74a4d8c2SCharles.Forsyth 		panic("dsp: SDMA channel bus error sdar=#%lux", m->iomem->sdar);
79*74a4d8c2SCharles.Forsyth 	for(i=0; i<Ndsp; i++)
80*74a4d8c2SCharles.Forsyth 		if(events & (1<<i)){
81*74a4d8c2SCharles.Forsyth 			dsp = &dsps[i];
82*74a4d8c2SCharles.Forsyth 			if(dsp->busy){
83*74a4d8c2SCharles.Forsyth 				dsp->busy = 0;
84*74a4d8c2SCharles.Forsyth 				if(dsp->done)
85*74a4d8c2SCharles.Forsyth 					dsp->done(dsp->arg);
86*74a4d8c2SCharles.Forsyth 				else
87*74a4d8c2SCharles.Forsyth 					wakeup(&dsp->busyr);
88*74a4d8c2SCharles.Forsyth 			}else
89*74a4d8c2SCharles.Forsyth 				print("dsp%d: empty interrupt\n", i);
90*74a4d8c2SCharles.Forsyth 		}
91*74a4d8c2SCharles.Forsyth }
92*74a4d8c2SCharles.Forsyth 
93*74a4d8c2SCharles.Forsyth /*
94*74a4d8c2SCharles.Forsyth  * called by system initialisation to set up the DSPs
95*74a4d8c2SCharles.Forsyth  */
96*74a4d8c2SCharles.Forsyth void
dspinitialise(void)97*74a4d8c2SCharles.Forsyth dspinitialise(void)
98*74a4d8c2SCharles.Forsyth {
99*74a4d8c2SCharles.Forsyth 	CPMdev *d;
100*74a4d8c2SCharles.Forsyth 
101*74a4d8c2SCharles.Forsyth 	ilock(&dsplock);
102*74a4d8c2SCharles.Forsyth 	if(dspinit == 0){
103*74a4d8c2SCharles.Forsyth 		mapinit(&fndmap, fndmapv, sizeof(fndmapv));
104*74a4d8c2SCharles.Forsyth 		d = cpmdev(CPdsp1);
105*74a4d8c2SCharles.Forsyth 		dsps[0].cpm = d;
106*74a4d8c2SCharles.Forsyth 		dsps[0].par = d->param;
107*74a4d8c2SCharles.Forsyth 		d = cpmdev(CPdsp2);
108*74a4d8c2SCharles.Forsyth 		dsps[1].cpm = d;
109*74a4d8c2SCharles.Forsyth 		dsps[1].par = d->param;
110*74a4d8c2SCharles.Forsyth 		intrenable(VectorCPIC+d->irq, dspinterrupt, nil, BUSUNKNOWN, "dsp");
111*74a4d8c2SCharles.Forsyth 		dspalloc.avail = (1<<Ndsp)-1;
112*74a4d8c2SCharles.Forsyth 		dspinit = 1;
113*74a4d8c2SCharles.Forsyth 	}
114*74a4d8c2SCharles.Forsyth 	iunlock(&dsplock);
115*74a4d8c2SCharles.Forsyth }
116*74a4d8c2SCharles.Forsyth 
117*74a4d8c2SCharles.Forsyth static int
dspavail(void *)118*74a4d8c2SCharles.Forsyth dspavail(void*)
119*74a4d8c2SCharles.Forsyth {
120*74a4d8c2SCharles.Forsyth 	return dspalloc.avail != 0;
121*74a4d8c2SCharles.Forsyth }
122*74a4d8c2SCharles.Forsyth 
123*74a4d8c2SCharles.Forsyth /*
124*74a4d8c2SCharles.Forsyth  * wait for a DSP to become available, and return a reference to it.
125*74a4d8c2SCharles.Forsyth  * if done is not nil, it will be called (with the given arg) when that
126*74a4d8c2SCharles.Forsyth  * DSP completes each function (if set to interrupt).
127*74a4d8c2SCharles.Forsyth  */
128*74a4d8c2SCharles.Forsyth DSP*
dspacquire(void (* done)(void *),void * arg)129*74a4d8c2SCharles.Forsyth dspacquire(void (*done)(void*), void *arg)
130*74a4d8c2SCharles.Forsyth {
131*74a4d8c2SCharles.Forsyth 	DSP *dsp;
132*74a4d8c2SCharles.Forsyth 	int i;
133*74a4d8c2SCharles.Forsyth 
134*74a4d8c2SCharles.Forsyth 	if(dspinit == 0)
135*74a4d8c2SCharles.Forsyth 		dspinitialise();
136*74a4d8c2SCharles.Forsyth 	qlock(&dspalloc);
137*74a4d8c2SCharles.Forsyth 	if(waserror()){
138*74a4d8c2SCharles.Forsyth 		qunlock(&dspalloc);
139*74a4d8c2SCharles.Forsyth 		nexterror();
140*74a4d8c2SCharles.Forsyth 	}
141*74a4d8c2SCharles.Forsyth 	for(i=0;; i++){
142*74a4d8c2SCharles.Forsyth 		if(i >= Ndsp){
143*74a4d8c2SCharles.Forsyth 			sleep(&dspalloc.wantr, dspavail, nil);
144*74a4d8c2SCharles.Forsyth 			i = 0;
145*74a4d8c2SCharles.Forsyth 		}
146*74a4d8c2SCharles.Forsyth 		if(dspalloc.avail & (1<<i))
147*74a4d8c2SCharles.Forsyth 			break;
148*74a4d8c2SCharles.Forsyth 	}
149*74a4d8c2SCharles.Forsyth 	dsp = &dsps[i];
150*74a4d8c2SCharles.Forsyth 	if(dsp->busy)
151*74a4d8c2SCharles.Forsyth 		panic("dspacquire");
152*74a4d8c2SCharles.Forsyth 	dsp->done = done;
153*74a4d8c2SCharles.Forsyth 	dsp->arg = arg;
154*74a4d8c2SCharles.Forsyth 	poperror();
155*74a4d8c2SCharles.Forsyth 	qunlock(&dspalloc);
156*74a4d8c2SCharles.Forsyth 	return dsp;
157*74a4d8c2SCharles.Forsyth }
158*74a4d8c2SCharles.Forsyth 
159*74a4d8c2SCharles.Forsyth /*
160*74a4d8c2SCharles.Forsyth  * relinquish access to the given DSP
161*74a4d8c2SCharles.Forsyth  */
162*74a4d8c2SCharles.Forsyth void
dsprelease(DSP * dsp)163*74a4d8c2SCharles.Forsyth dsprelease(DSP *dsp)
164*74a4d8c2SCharles.Forsyth {
165*74a4d8c2SCharles.Forsyth 	ulong bit;
166*74a4d8c2SCharles.Forsyth 
167*74a4d8c2SCharles.Forsyth 	if(dsp == nil)
168*74a4d8c2SCharles.Forsyth 		return;
169*74a4d8c2SCharles.Forsyth 	bit = 1 << (dsp-dsps);
170*74a4d8c2SCharles.Forsyth 	if(dspalloc.avail & bit)
171*74a4d8c2SCharles.Forsyth 		panic("dsprelease");
172*74a4d8c2SCharles.Forsyth 	dspalloc.avail |= bit;
173*74a4d8c2SCharles.Forsyth 	wakeup(&dspalloc.wantr);
174*74a4d8c2SCharles.Forsyth }
175*74a4d8c2SCharles.Forsyth 
176*74a4d8c2SCharles.Forsyth /*
177*74a4d8c2SCharles.Forsyth  * execute f[0] to f[n-1] on the given DSP
178*74a4d8c2SCharles.Forsyth  */
179*74a4d8c2SCharles.Forsyth void
dspexec(DSP * dsp,FnD * f,ulong n)180*74a4d8c2SCharles.Forsyth dspexec(DSP *dsp, FnD *f, ulong n)
181*74a4d8c2SCharles.Forsyth {
182*74a4d8c2SCharles.Forsyth 	dspsetfn(dsp, f, n);
183*74a4d8c2SCharles.Forsyth 	dspstart(dsp);
184*74a4d8c2SCharles.Forsyth }
185*74a4d8c2SCharles.Forsyth 
186*74a4d8c2SCharles.Forsyth /*
187*74a4d8c2SCharles.Forsyth  * set the DSP to execute f[0] to f[n-1]
188*74a4d8c2SCharles.Forsyth  */
189*74a4d8c2SCharles.Forsyth void
dspsetfn(DSP * dsp,FnD * f,ulong n)190*74a4d8c2SCharles.Forsyth dspsetfn(DSP *dsp, FnD *f, ulong n)
191*74a4d8c2SCharles.Forsyth {
192*74a4d8c2SCharles.Forsyth 	f[n-1].status |= FnWrap;
193*74a4d8c2SCharles.Forsyth 	ilock(dsp);
194*74a4d8c2SCharles.Forsyth 	dsp->par->fdbase = PADDR(f);
195*74a4d8c2SCharles.Forsyth 	iunlock(dsp);
196*74a4d8c2SCharles.Forsyth 	cpmop(dsp->cpm, InitDSP, 0);
197*74a4d8c2SCharles.Forsyth }
198*74a4d8c2SCharles.Forsyth 
199*74a4d8c2SCharles.Forsyth /*
200*74a4d8c2SCharles.Forsyth  * start execution of the preset function(s)
201*74a4d8c2SCharles.Forsyth  */
202*74a4d8c2SCharles.Forsyth void
dspstart(DSP * dsp)203*74a4d8c2SCharles.Forsyth dspstart(DSP *dsp)
204*74a4d8c2SCharles.Forsyth {
205*74a4d8c2SCharles.Forsyth 	ilock(dsp);
206*74a4d8c2SCharles.Forsyth 	dsp->busy = 1;
207*74a4d8c2SCharles.Forsyth 	iunlock(dsp);
208*74a4d8c2SCharles.Forsyth 	cpmop(dsp->cpm, StartDSP, 0);
209*74a4d8c2SCharles.Forsyth }
210*74a4d8c2SCharles.Forsyth 
211*74a4d8c2SCharles.Forsyth static int
dspdone(void * a)212*74a4d8c2SCharles.Forsyth dspdone(void *a)
213*74a4d8c2SCharles.Forsyth {
214*74a4d8c2SCharles.Forsyth 	return ((DSP*)a)->busy;
215*74a4d8c2SCharles.Forsyth }
216*74a4d8c2SCharles.Forsyth 
217*74a4d8c2SCharles.Forsyth /*
218*74a4d8c2SCharles.Forsyth  * wait until the DSP has completed execution
219*74a4d8c2SCharles.Forsyth  */
220*74a4d8c2SCharles.Forsyth void
dspsleep(DSP * dsp)221*74a4d8c2SCharles.Forsyth dspsleep(DSP *dsp)
222*74a4d8c2SCharles.Forsyth {
223*74a4d8c2SCharles.Forsyth 	sleep(&dsp->busyr, dspdone, dsp);
224*74a4d8c2SCharles.Forsyth }
225*74a4d8c2SCharles.Forsyth 
226*74a4d8c2SCharles.Forsyth /*
227*74a4d8c2SCharles.Forsyth  * allocate n function descriptors
228*74a4d8c2SCharles.Forsyth  */
229*74a4d8c2SCharles.Forsyth FnD*
fndalloc(ulong n)230*74a4d8c2SCharles.Forsyth fndalloc(ulong n)
231*74a4d8c2SCharles.Forsyth {
232*74a4d8c2SCharles.Forsyth 	ulong a, nb, pgn;
233*74a4d8c2SCharles.Forsyth 	FnD *f;
234*74a4d8c2SCharles.Forsyth 
235*74a4d8c2SCharles.Forsyth 	if(n == 0)
236*74a4d8c2SCharles.Forsyth 		return nil;
237*74a4d8c2SCharles.Forsyth 	if(dspinit == 0)
238*74a4d8c2SCharles.Forsyth 		dspinitialise();
239*74a4d8c2SCharles.Forsyth 	nb = n*sizeof(FnD);
240*74a4d8c2SCharles.Forsyth 	while((a = rmapalloc(&fndmap, 0, nb, sizeof(FnD))) != 0){
241*74a4d8c2SCharles.Forsyth 		/* expected to loop just once, but might lose a race with another dsp user */
242*74a4d8c2SCharles.Forsyth 		pgn = (nb+BY2PG-1)&~(BY2PG-1);
243*74a4d8c2SCharles.Forsyth 		a = PADDR(xspanalloc(pgn, sizeof(FnD), 0));
244*74a4d8c2SCharles.Forsyth 		if(a == 0)
245*74a4d8c2SCharles.Forsyth 			return nil;
246*74a4d8c2SCharles.Forsyth 		mapfree(&fndmap, a, pgn);
247*74a4d8c2SCharles.Forsyth 	}
248*74a4d8c2SCharles.Forsyth 	f = KADDR(a);
249*74a4d8c2SCharles.Forsyth 	f[n-1].status = FnWrap;
250*74a4d8c2SCharles.Forsyth 	return f;
251*74a4d8c2SCharles.Forsyth }
252*74a4d8c2SCharles.Forsyth 
253*74a4d8c2SCharles.Forsyth /*
254*74a4d8c2SCharles.Forsyth  * free n function descriptors
255*74a4d8c2SCharles.Forsyth  */
256*74a4d8c2SCharles.Forsyth void
fndfree(FnD * f,ulong n)257*74a4d8c2SCharles.Forsyth fndfree(FnD *f, ulong n)
258*74a4d8c2SCharles.Forsyth {
259*74a4d8c2SCharles.Forsyth 	if(f != nil)
260*74a4d8c2SCharles.Forsyth 		mapfree(&fndmap, PADDR(f), n*sizeof(FnD));
261*74a4d8c2SCharles.Forsyth }
262*74a4d8c2SCharles.Forsyth 
263*74a4d8c2SCharles.Forsyth /*
264*74a4d8c2SCharles.Forsyth  * allocate an IO buffer region in shared memory for use by the DSP
265*74a4d8c2SCharles.Forsyth  */
266*74a4d8c2SCharles.Forsyth void*
dspmalloc(ulong n)267*74a4d8c2SCharles.Forsyth dspmalloc(ulong n)
268*74a4d8c2SCharles.Forsyth {
269*74a4d8c2SCharles.Forsyth 	ulong i;
270*74a4d8c2SCharles.Forsyth 
271*74a4d8c2SCharles.Forsyth 	n = (n+3)&~4;
272*74a4d8c2SCharles.Forsyth 	i = n;
273*74a4d8c2SCharles.Forsyth 	if(n & (n-1)){
274*74a4d8c2SCharles.Forsyth 		/* align on a power of two */
275*74a4d8c2SCharles.Forsyth 		for(i=1; i < n; i <<= 1)
276*74a4d8c2SCharles.Forsyth 			;
277*74a4d8c2SCharles.Forsyth 	}
278*74a4d8c2SCharles.Forsyth 	return cpmalloc(n, i);	/* this seems to be what 16.3.3.2 is trying to say */
279*74a4d8c2SCharles.Forsyth }
280*74a4d8c2SCharles.Forsyth 
281*74a4d8c2SCharles.Forsyth /*
282*74a4d8c2SCharles.Forsyth  * free DSP buffer memory
283*74a4d8c2SCharles.Forsyth  */
284*74a4d8c2SCharles.Forsyth void
dspfree(void * p,ulong n)285*74a4d8c2SCharles.Forsyth dspfree(void *p, ulong n)
286*74a4d8c2SCharles.Forsyth {
287*74a4d8c2SCharles.Forsyth 	if(p != nil)
288*74a4d8c2SCharles.Forsyth 		cpmfree(p, (n+3)&~4);
289*74a4d8c2SCharles.Forsyth }
290