1*74a4d8c2SCharles.Forsyth #include "u.h"
2*74a4d8c2SCharles.Forsyth #include "../port/lib.h"
3*74a4d8c2SCharles.Forsyth #include "mem.h"
4*74a4d8c2SCharles.Forsyth #include "dat.h"
5*74a4d8c2SCharles.Forsyth #include "fns.h"
6*74a4d8c2SCharles.Forsyth #include "../port/error.h"
7*74a4d8c2SCharles.Forsyth
8*74a4d8c2SCharles.Forsyth #include "io.h"
9*74a4d8c2SCharles.Forsyth #include "archipe.h"
10*74a4d8c2SCharles.Forsyth
11*74a4d8c2SCharles.Forsyth enum {
12*74a4d8c2SCharles.Forsyth FPGASIZE = 8*1024*1024,
13*74a4d8c2SCharles.Forsyth FPGATMR = 2-1, /* BCLK timer number (mapped to origin 0) */
14*74a4d8c2SCharles.Forsyth TIMERSH = FPGATMR*4, /* timer field shift */
15*74a4d8c2SCharles.Forsyth
16*74a4d8c2SCharles.Forsyth COM3= IBIT(1)|IBIT(2), /* sccr: clock output disabled */
17*74a4d8c2SCharles.Forsyth
18*74a4d8c2SCharles.Forsyth ConfDone = 1<<1,
19*74a4d8c2SCharles.Forsyth nStatus = 1<<0,
20*74a4d8c2SCharles.Forsyth };
21*74a4d8c2SCharles.Forsyth
22*74a4d8c2SCharles.Forsyth /*
23*74a4d8c2SCharles.Forsyth * provisional FPGA interface for simple development work;
24*74a4d8c2SCharles.Forsyth * for more complex things, use this to load the device then have a
25*74a4d8c2SCharles.Forsyth * purpose-built device driver or module
26*74a4d8c2SCharles.Forsyth */
27*74a4d8c2SCharles.Forsyth
28*74a4d8c2SCharles.Forsyth enum{
29*74a4d8c2SCharles.Forsyth Qdir,
30*74a4d8c2SCharles.Forsyth Qmemb,
31*74a4d8c2SCharles.Forsyth Qmemw,
32*74a4d8c2SCharles.Forsyth Qprog,
33*74a4d8c2SCharles.Forsyth Qctl,
34*74a4d8c2SCharles.Forsyth Qclk,
35*74a4d8c2SCharles.Forsyth Qstatus,
36*74a4d8c2SCharles.Forsyth };
37*74a4d8c2SCharles.Forsyth
38*74a4d8c2SCharles.Forsyth static struct {
39*74a4d8c2SCharles.Forsyth QLock;
40*74a4d8c2SCharles.Forsyth int clkspeed;
41*74a4d8c2SCharles.Forsyth } fpga;
42*74a4d8c2SCharles.Forsyth
43*74a4d8c2SCharles.Forsyth static void resetfpga(void);
44*74a4d8c2SCharles.Forsyth static void startfpga(int);
45*74a4d8c2SCharles.Forsyth static int endfpga(void);
46*74a4d8c2SCharles.Forsyth static int fpgastatus(void);
47*74a4d8c2SCharles.Forsyth static void powerfpga(int);
48*74a4d8c2SCharles.Forsyth static void vclkenable(int);
49*74a4d8c2SCharles.Forsyth static void vclkset(char*, char*, char*, char*);
50*74a4d8c2SCharles.Forsyth static void memmovew(ushort*, ushort*, long);
51*74a4d8c2SCharles.Forsyth
52*74a4d8c2SCharles.Forsyth static Dirtab fpgadir[]={
53*74a4d8c2SCharles.Forsyth ".", {Qdir, 0, QTDIR}, 0, 0555,
54*74a4d8c2SCharles.Forsyth "fpgamemb", {Qmemb, 0}, FPGASIZE, 0666,
55*74a4d8c2SCharles.Forsyth "fpgamemw", {Qmemw, 0}, FPGASIZE, 0666,
56*74a4d8c2SCharles.Forsyth "fpgaprog", {Qprog, 0}, 0, 0222,
57*74a4d8c2SCharles.Forsyth "fpgastatus", {Qstatus, 0}, 0, 0444,
58*74a4d8c2SCharles.Forsyth "fpgactl", {Qctl, 0}, 0, 0666,
59*74a4d8c2SCharles.Forsyth "fpgaclk", {Qclk, 0}, 0, 0666,
60*74a4d8c2SCharles.Forsyth };
61*74a4d8c2SCharles.Forsyth
62*74a4d8c2SCharles.Forsyth static char Eodd[] = "odd count or offset";
63*74a4d8c2SCharles.Forsyth
64*74a4d8c2SCharles.Forsyth static void
fpgareset(void)65*74a4d8c2SCharles.Forsyth fpgareset(void)
66*74a4d8c2SCharles.Forsyth {
67*74a4d8c2SCharles.Forsyth powerfpga(0);
68*74a4d8c2SCharles.Forsyth }
69*74a4d8c2SCharles.Forsyth
70*74a4d8c2SCharles.Forsyth static Chan*
fpgaattach(char * spec)71*74a4d8c2SCharles.Forsyth fpgaattach(char *spec)
72*74a4d8c2SCharles.Forsyth {
73*74a4d8c2SCharles.Forsyth return devattach('G', spec);
74*74a4d8c2SCharles.Forsyth }
75*74a4d8c2SCharles.Forsyth
76*74a4d8c2SCharles.Forsyth static Walkqid*
fpgawalk(Chan * c,Chan * nc,char ** name,int nname)77*74a4d8c2SCharles.Forsyth fpgawalk(Chan *c, Chan *nc, char **name, int nname)
78*74a4d8c2SCharles.Forsyth {
79*74a4d8c2SCharles.Forsyth return devwalk(c, nc, name, nname, fpgadir, nelem(fpgadir), devgen);
80*74a4d8c2SCharles.Forsyth }
81*74a4d8c2SCharles.Forsyth
82*74a4d8c2SCharles.Forsyth static int
fpgastat(Chan * c,uchar * dp,int n)83*74a4d8c2SCharles.Forsyth fpgastat(Chan *c, uchar *dp, int n)
84*74a4d8c2SCharles.Forsyth {
85*74a4d8c2SCharles.Forsyth return devstat(c, dp, n, fpgadir, nelem(fpgadir), devgen);
86*74a4d8c2SCharles.Forsyth }
87*74a4d8c2SCharles.Forsyth
88*74a4d8c2SCharles.Forsyth static Chan*
fpgaopen(Chan * c,int omode)89*74a4d8c2SCharles.Forsyth fpgaopen(Chan *c, int omode)
90*74a4d8c2SCharles.Forsyth {
91*74a4d8c2SCharles.Forsyth return devopen(c, omode, fpgadir, nelem(fpgadir), devgen);
92*74a4d8c2SCharles.Forsyth }
93*74a4d8c2SCharles.Forsyth
94*74a4d8c2SCharles.Forsyth static void
fpgaclose(Chan *)95*74a4d8c2SCharles.Forsyth fpgaclose(Chan*)
96*74a4d8c2SCharles.Forsyth {
97*74a4d8c2SCharles.Forsyth }
98*74a4d8c2SCharles.Forsyth
99*74a4d8c2SCharles.Forsyth static long
fpgaread(Chan * c,void * buf,long n,vlong offset)100*74a4d8c2SCharles.Forsyth fpgaread(Chan *c, void *buf, long n, vlong offset)
101*74a4d8c2SCharles.Forsyth {
102*74a4d8c2SCharles.Forsyth int v;
103*74a4d8c2SCharles.Forsyth char stat[32], *p;
104*74a4d8c2SCharles.Forsyth
105*74a4d8c2SCharles.Forsyth if(c->qid.type & QTDIR)
106*74a4d8c2SCharles.Forsyth return devdirread(c, buf, n, fpgadir, nelem(fpgadir), devgen);
107*74a4d8c2SCharles.Forsyth
108*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
109*74a4d8c2SCharles.Forsyth case Qmemb:
110*74a4d8c2SCharles.Forsyth if(offset >= FPGASIZE)
111*74a4d8c2SCharles.Forsyth return 0;
112*74a4d8c2SCharles.Forsyth if(offset+n >= FPGASIZE)
113*74a4d8c2SCharles.Forsyth n = FPGASIZE-offset;
114*74a4d8c2SCharles.Forsyth memmove(buf, KADDR(FPGAMEM+offset), n);
115*74a4d8c2SCharles.Forsyth return n;
116*74a4d8c2SCharles.Forsyth case Qmemw:
117*74a4d8c2SCharles.Forsyth if((n | offset) & 1)
118*74a4d8c2SCharles.Forsyth error(Eodd);
119*74a4d8c2SCharles.Forsyth if(offset >= FPGASIZE)
120*74a4d8c2SCharles.Forsyth return 0;
121*74a4d8c2SCharles.Forsyth if(offset+n >= FPGASIZE)
122*74a4d8c2SCharles.Forsyth n = FPGASIZE-offset;
123*74a4d8c2SCharles.Forsyth memmovew((ushort*)buf, (ushort*)KADDR(FPGAMEM+offset), n);
124*74a4d8c2SCharles.Forsyth return n;
125*74a4d8c2SCharles.Forsyth case Qstatus:
126*74a4d8c2SCharles.Forsyth v = fpgastatus();
127*74a4d8c2SCharles.Forsyth p = seprint(stat, stat+sizeof(stat), "%sconfig", v&ConfDone?"":"!");
128*74a4d8c2SCharles.Forsyth seprint(p, stat+sizeof(stat), " %sstatus\n", v&nStatus?"":"!");
129*74a4d8c2SCharles.Forsyth return readstr(offset, buf, n, stat);
130*74a4d8c2SCharles.Forsyth case Qclk:
131*74a4d8c2SCharles.Forsyth return readnum(offset, buf, n, fpga.clkspeed, NUMSIZE);
132*74a4d8c2SCharles.Forsyth case Qctl:
133*74a4d8c2SCharles.Forsyth case Qprog:
134*74a4d8c2SCharles.Forsyth return 0;
135*74a4d8c2SCharles.Forsyth }
136*74a4d8c2SCharles.Forsyth error(Egreg);
137*74a4d8c2SCharles.Forsyth return 0; /* not reached */
138*74a4d8c2SCharles.Forsyth }
139*74a4d8c2SCharles.Forsyth
140*74a4d8c2SCharles.Forsyth static long
fpgawrite(Chan * c,void * buf,long n,vlong offset)141*74a4d8c2SCharles.Forsyth fpgawrite(Chan *c, void *buf, long n, vlong offset)
142*74a4d8c2SCharles.Forsyth {
143*74a4d8c2SCharles.Forsyth int i, j, v;
144*74a4d8c2SCharles.Forsyth ulong w;
145*74a4d8c2SCharles.Forsyth Cmdbuf *cb;
146*74a4d8c2SCharles.Forsyth ulong *cfg;
147*74a4d8c2SCharles.Forsyth uchar *cp;
148*74a4d8c2SCharles.Forsyth
149*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
150*74a4d8c2SCharles.Forsyth case Qmemb:
151*74a4d8c2SCharles.Forsyth if(offset >= FPGASIZE)
152*74a4d8c2SCharles.Forsyth return 0;
153*74a4d8c2SCharles.Forsyth if(offset+n >= FPGASIZE)
154*74a4d8c2SCharles.Forsyth n = FPGASIZE-offset;
155*74a4d8c2SCharles.Forsyth memmove(KADDR(FPGAMEM+offset), buf, n);
156*74a4d8c2SCharles.Forsyth return n;
157*74a4d8c2SCharles.Forsyth case Qmemw:
158*74a4d8c2SCharles.Forsyth if((n | offset) & 1)
159*74a4d8c2SCharles.Forsyth error(Eodd);
160*74a4d8c2SCharles.Forsyth if(offset >= FPGASIZE)
161*74a4d8c2SCharles.Forsyth return 0;
162*74a4d8c2SCharles.Forsyth if(offset+n >= FPGASIZE)
163*74a4d8c2SCharles.Forsyth n = FPGASIZE-offset;
164*74a4d8c2SCharles.Forsyth memmovew((ushort*)KADDR(FPGAMEM+offset), (ushort*)buf, n);
165*74a4d8c2SCharles.Forsyth return n;
166*74a4d8c2SCharles.Forsyth case Qctl:
167*74a4d8c2SCharles.Forsyth cb = parsecmd(buf, n);
168*74a4d8c2SCharles.Forsyth if(waserror()){
169*74a4d8c2SCharles.Forsyth free(cb);
170*74a4d8c2SCharles.Forsyth nexterror();
171*74a4d8c2SCharles.Forsyth }
172*74a4d8c2SCharles.Forsyth if(cb->nf < 1)
173*74a4d8c2SCharles.Forsyth error(Ebadarg);
174*74a4d8c2SCharles.Forsyth if(strcmp(cb->f[0], "reset") == 0)
175*74a4d8c2SCharles.Forsyth resetfpga();
176*74a4d8c2SCharles.Forsyth else if(strcmp(cb->f[0], "bclk") == 0){
177*74a4d8c2SCharles.Forsyth v = 48;
178*74a4d8c2SCharles.Forsyth if(cb->nf > 1)
179*74a4d8c2SCharles.Forsyth v = strtoul(cb->f[1], nil, 0);
180*74a4d8c2SCharles.Forsyth if(v <= 0 || 48%v != 0)
181*74a4d8c2SCharles.Forsyth error(Ebadarg);
182*74a4d8c2SCharles.Forsyth startfpga(48/v-1);
183*74a4d8c2SCharles.Forsyth }else if(strcmp(cb->f[0], "vclk") == 0){
184*74a4d8c2SCharles.Forsyth if(cb->nf == 5){ /* vclk n m v r */
185*74a4d8c2SCharles.Forsyth vclkenable(1);
186*74a4d8c2SCharles.Forsyth vclkset(cb->f[1], cb->f[2], cb->f[3], cb->f[4]);
187*74a4d8c2SCharles.Forsyth }else
188*74a4d8c2SCharles.Forsyth vclkenable(cb->nf < 2 || strcmp(cb->f[1], "on") == 0);
189*74a4d8c2SCharles.Forsyth }else if(strcmp(cb->f[0], "power") == 0)
190*74a4d8c2SCharles.Forsyth powerfpga(cb->nf < 2 || strcmp(cb->f[1], "off") != 0);
191*74a4d8c2SCharles.Forsyth else
192*74a4d8c2SCharles.Forsyth error(Ebadarg);
193*74a4d8c2SCharles.Forsyth poperror();
194*74a4d8c2SCharles.Forsyth free(cb);
195*74a4d8c2SCharles.Forsyth return n;
196*74a4d8c2SCharles.Forsyth case Qprog:
197*74a4d8c2SCharles.Forsyth qlock(&fpga);
198*74a4d8c2SCharles.Forsyth if(waserror()){
199*74a4d8c2SCharles.Forsyth qunlock(&fpga);
200*74a4d8c2SCharles.Forsyth nexterror();
201*74a4d8c2SCharles.Forsyth }
202*74a4d8c2SCharles.Forsyth powerfpga(1);
203*74a4d8c2SCharles.Forsyth resetfpga();
204*74a4d8c2SCharles.Forsyth cfg = KADDR(FPGACR);
205*74a4d8c2SCharles.Forsyth cp = buf;
206*74a4d8c2SCharles.Forsyth for(i=0; i<n; i++){
207*74a4d8c2SCharles.Forsyth w = cp[i];
208*74a4d8c2SCharles.Forsyth for(j=0; j<8; j++){
209*74a4d8c2SCharles.Forsyth *cfg = w&1;
210*74a4d8c2SCharles.Forsyth w >>= 1;
211*74a4d8c2SCharles.Forsyth }
212*74a4d8c2SCharles.Forsyth }
213*74a4d8c2SCharles.Forsyth for(j=0; j<50; j++) /* Altera note says at least 10 clock cycles, but microblaster uses 50 */
214*74a4d8c2SCharles.Forsyth *cfg = 0;
215*74a4d8c2SCharles.Forsyth v = fpgastatus();
216*74a4d8c2SCharles.Forsyth if(v != (nStatus|ConfDone)){
217*74a4d8c2SCharles.Forsyth snprint(up->genbuf, sizeof(up->genbuf), "error loading fpga: status %d", v);
218*74a4d8c2SCharles.Forsyth error(up->genbuf);
219*74a4d8c2SCharles.Forsyth }
220*74a4d8c2SCharles.Forsyth poperror();
221*74a4d8c2SCharles.Forsyth qunlock(&fpga);
222*74a4d8c2SCharles.Forsyth return n;
223*74a4d8c2SCharles.Forsyth }
224*74a4d8c2SCharles.Forsyth error(Egreg);
225*74a4d8c2SCharles.Forsyth return 0; /* not reached */
226*74a4d8c2SCharles.Forsyth }
227*74a4d8c2SCharles.Forsyth
228*74a4d8c2SCharles.Forsyth /*
229*74a4d8c2SCharles.Forsyth * PDN seems to control power to the FPGA subsystem
230*74a4d8c2SCharles.Forsyth * but it is not documented nor is its scope clear (PLL as well?).
231*74a4d8c2SCharles.Forsyth * It will not run without it.
232*74a4d8c2SCharles.Forsyth */
233*74a4d8c2SCharles.Forsyth static void
powerfpga(int on)234*74a4d8c2SCharles.Forsyth powerfpga(int on)
235*74a4d8c2SCharles.Forsyth {
236*74a4d8c2SCharles.Forsyth IMM *io;
237*74a4d8c2SCharles.Forsyth
238*74a4d8c2SCharles.Forsyth io = ioplock();
239*74a4d8c2SCharles.Forsyth if(io->sccr & COM3){
240*74a4d8c2SCharles.Forsyth io->sccrk = KEEP_ALIVE_KEY;
241*74a4d8c2SCharles.Forsyth io->sccr &= ~ COM3; /* FPGA designs can use the clock */
242*74a4d8c2SCharles.Forsyth io->sccrk = ~KEEP_ALIVE_KEY;
243*74a4d8c2SCharles.Forsyth }
244*74a4d8c2SCharles.Forsyth io->pcpar &= ~PDN;
245*74a4d8c2SCharles.Forsyth io->pcdir |= PDN;
246*74a4d8c2SCharles.Forsyth if(on)
247*74a4d8c2SCharles.Forsyth io->pcdat &= ~PDN;
248*74a4d8c2SCharles.Forsyth else
249*74a4d8c2SCharles.Forsyth io->pcdat |= PDN;
250*74a4d8c2SCharles.Forsyth iopunlock();
251*74a4d8c2SCharles.Forsyth }
252*74a4d8c2SCharles.Forsyth
253*74a4d8c2SCharles.Forsyth static void
resetfpga(void)254*74a4d8c2SCharles.Forsyth resetfpga(void)
255*74a4d8c2SCharles.Forsyth {
256*74a4d8c2SCharles.Forsyth IMM *io;
257*74a4d8c2SCharles.Forsyth
258*74a4d8c2SCharles.Forsyth io = ioplock();
259*74a4d8c2SCharles.Forsyth io->pcpar &= ~nCONFIG;
260*74a4d8c2SCharles.Forsyth io->pcdir |= nCONFIG;
261*74a4d8c2SCharles.Forsyth io->pcdat &= ~nCONFIG;
262*74a4d8c2SCharles.Forsyth microdelay(200);
263*74a4d8c2SCharles.Forsyth io->pcdat |= nCONFIG;
264*74a4d8c2SCharles.Forsyth iopunlock();
265*74a4d8c2SCharles.Forsyth }
266*74a4d8c2SCharles.Forsyth
267*74a4d8c2SCharles.Forsyth static int
fpgastatus(void)268*74a4d8c2SCharles.Forsyth fpgastatus(void)
269*74a4d8c2SCharles.Forsyth {
270*74a4d8c2SCharles.Forsyth /* isolate status bits IP_B0 and IP_B1 */
271*74a4d8c2SCharles.Forsyth return (m->iomem->pipr>>14) & (ConfDone|nStatus);
272*74a4d8c2SCharles.Forsyth }
273*74a4d8c2SCharles.Forsyth
274*74a4d8c2SCharles.Forsyth static void
startfpga(int scale)275*74a4d8c2SCharles.Forsyth startfpga(int scale)
276*74a4d8c2SCharles.Forsyth {
277*74a4d8c2SCharles.Forsyth IMM *io;
278*74a4d8c2SCharles.Forsyth
279*74a4d8c2SCharles.Forsyth io = ioplock();
280*74a4d8c2SCharles.Forsyth io->tgcr &= ~(0xF<<TIMERSH);
281*74a4d8c2SCharles.Forsyth io->tmr2 = ((scale&0xFF)<<8) | 0x2A;
282*74a4d8c2SCharles.Forsyth io->tcn2 = 0;
283*74a4d8c2SCharles.Forsyth io->trr2 = 0;
284*74a4d8c2SCharles.Forsyth io->ter2 = 0xFFFF;
285*74a4d8c2SCharles.Forsyth io->tgcr |= 0x1<<TIMERSH;
286*74a4d8c2SCharles.Forsyth io->padir |= BCLK;
287*74a4d8c2SCharles.Forsyth io->papar |= BCLK;
288*74a4d8c2SCharles.Forsyth iopunlock();
289*74a4d8c2SCharles.Forsyth }
290*74a4d8c2SCharles.Forsyth
291*74a4d8c2SCharles.Forsyth static void
vclkenable(int i)292*74a4d8c2SCharles.Forsyth vclkenable(int i)
293*74a4d8c2SCharles.Forsyth {
294*74a4d8c2SCharles.Forsyth IMM *io;
295*74a4d8c2SCharles.Forsyth
296*74a4d8c2SCharles.Forsyth io = ioplock();
297*74a4d8c2SCharles.Forsyth io->padir &= ~VCLK;
298*74a4d8c2SCharles.Forsyth io->papar &= ~VCLK;
299*74a4d8c2SCharles.Forsyth io->pbdir |= EnableVCLK;
300*74a4d8c2SCharles.Forsyth io->pbpar &= ~EnableVCLK;
301*74a4d8c2SCharles.Forsyth if(i)
302*74a4d8c2SCharles.Forsyth io->pbdat |= EnableVCLK;
303*74a4d8c2SCharles.Forsyth else
304*74a4d8c2SCharles.Forsyth io->pbdat &= ~EnableVCLK;
305*74a4d8c2SCharles.Forsyth iopunlock();
306*74a4d8c2SCharles.Forsyth }
307*74a4d8c2SCharles.Forsyth
308*74a4d8c2SCharles.Forsyth static void
vclkin(ulong * clk,int v)309*74a4d8c2SCharles.Forsyth vclkin(ulong *clk, int v)
310*74a4d8c2SCharles.Forsyth {
311*74a4d8c2SCharles.Forsyth int i;
312*74a4d8c2SCharles.Forsyth
313*74a4d8c2SCharles.Forsyth for(i=0; i<7; i++)
314*74a4d8c2SCharles.Forsyth *clk = (v>>i) & 1;
315*74a4d8c2SCharles.Forsyth }
316*74a4d8c2SCharles.Forsyth
317*74a4d8c2SCharles.Forsyth static void
vclkset(char * ns,char * ms,char * vs,char * rs)318*74a4d8c2SCharles.Forsyth vclkset(char *ns, char *ms, char *vs, char *rs)
319*74a4d8c2SCharles.Forsyth {
320*74a4d8c2SCharles.Forsyth int n, m, v, r;
321*74a4d8c2SCharles.Forsyth ulong *clk;
322*74a4d8c2SCharles.Forsyth
323*74a4d8c2SCharles.Forsyth clk = KADDR(CLOCKCR);
324*74a4d8c2SCharles.Forsyth n = strtol(ns, nil, 0);
325*74a4d8c2SCharles.Forsyth m = strtol(ms, nil, 0);
326*74a4d8c2SCharles.Forsyth v = strtol(vs, nil, 0);
327*74a4d8c2SCharles.Forsyth r = strtol(rs, nil, 0);
328*74a4d8c2SCharles.Forsyth if(n < 3 || n > 127 || m < 3 || m > 127 || v != 1 && v != 8 ||
329*74a4d8c2SCharles.Forsyth r != 1 && r != 2 && r != 4 && r != 8)
330*74a4d8c2SCharles.Forsyth error(Ebadarg);
331*74a4d8c2SCharles.Forsyth vclkenable(0);
332*74a4d8c2SCharles.Forsyth vclkin(clk, n);
333*74a4d8c2SCharles.Forsyth vclkin(clk, m);
334*74a4d8c2SCharles.Forsyth *clk = (v==0) & 1;
335*74a4d8c2SCharles.Forsyth *clk = 1; *clk = 1;
336*74a4d8c2SCharles.Forsyth *clk = r == 2 || r == 8;
337*74a4d8c2SCharles.Forsyth *clk = r == 4 || r == 8;
338*74a4d8c2SCharles.Forsyth *clk = 1; /* clock out */
339*74a4d8c2SCharles.Forsyth *clk = 0; /* disable clk/x */
340*74a4d8c2SCharles.Forsyth *clk = 1; *clk = 0; *clk = 1;
341*74a4d8c2SCharles.Forsyth *clk = 0; *clk = 0; *clk = 0;
342*74a4d8c2SCharles.Forsyth vclkenable(1);
343*74a4d8c2SCharles.Forsyth }
344*74a4d8c2SCharles.Forsyth
345*74a4d8c2SCharles.Forsyth /*
346*74a4d8c2SCharles.Forsyth * copy data aligned on 16-bit word boundaries.
347*74a4d8c2SCharles.Forsyth */
348*74a4d8c2SCharles.Forsyth static void
memmovew(ushort * to,ushort * from,long count)349*74a4d8c2SCharles.Forsyth memmovew(ushort *to, ushort *from, long count)
350*74a4d8c2SCharles.Forsyth {
351*74a4d8c2SCharles.Forsyth int n;
352*74a4d8c2SCharles.Forsyth
353*74a4d8c2SCharles.Forsyth if(count <= 0)
354*74a4d8c2SCharles.Forsyth return;
355*74a4d8c2SCharles.Forsyth count >>= 1;
356*74a4d8c2SCharles.Forsyth n = (count+7) >> 3;
357*74a4d8c2SCharles.Forsyth switch(count&7) { /* Duff's device */
358*74a4d8c2SCharles.Forsyth case 0: do { *to++ = *from++;
359*74a4d8c2SCharles.Forsyth case 7: *to++ = *from++;
360*74a4d8c2SCharles.Forsyth case 6: *to++ = *from++;
361*74a4d8c2SCharles.Forsyth case 5: *to++ = *from++;
362*74a4d8c2SCharles.Forsyth case 4: *to++ = *from++;
363*74a4d8c2SCharles.Forsyth case 3: *to++ = *from++;
364*74a4d8c2SCharles.Forsyth case 2: *to++ = *from++;
365*74a4d8c2SCharles.Forsyth case 1: *to++ = *from++;
366*74a4d8c2SCharles.Forsyth } while(--n > 0);
367*74a4d8c2SCharles.Forsyth }
368*74a4d8c2SCharles.Forsyth }
369*74a4d8c2SCharles.Forsyth
370*74a4d8c2SCharles.Forsyth Dev fpgadevtab = {
371*74a4d8c2SCharles.Forsyth 'G',
372*74a4d8c2SCharles.Forsyth "fpga",
373*74a4d8c2SCharles.Forsyth
374*74a4d8c2SCharles.Forsyth fpgareset,
375*74a4d8c2SCharles.Forsyth devinit,
376*74a4d8c2SCharles.Forsyth devshutdown,
377*74a4d8c2SCharles.Forsyth fpgaattach,
378*74a4d8c2SCharles.Forsyth fpgawalk,
379*74a4d8c2SCharles.Forsyth fpgastat,
380*74a4d8c2SCharles.Forsyth fpgaopen,
381*74a4d8c2SCharles.Forsyth devcreate,
382*74a4d8c2SCharles.Forsyth fpgaclose,
383*74a4d8c2SCharles.Forsyth fpgaread,
384*74a4d8c2SCharles.Forsyth devbread,
385*74a4d8c2SCharles.Forsyth fpgawrite,
386*74a4d8c2SCharles.Forsyth devbwrite,
387*74a4d8c2SCharles.Forsyth devremove,
388*74a4d8c2SCharles.Forsyth devwstat,
389*74a4d8c2SCharles.Forsyth };
390