1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "debug.h"
5 #include "lebo.h"
6 #include "tap.h"
7 #include "chain.h"
8 #include "jtag.h"
9 #include "icert.h"
10 #include "mpsse.h"
11
12 /*
13 See schematics, openocd code.
14 Guessing for the GuruDisp...
15 */
16
17 static uchar cablingH[][4] = {
18 [Sheeva] {[TRST] 0x2, [SRST] 0x0, [TRSTnOE]0x0, [SRSTnOE] 0x04,},
19 [GuruDisp] {[TRST] 0x2, [SRST] 0x0, [TRSTnOE]0x0, [SRSTnOE] 0x04,},
20 };
21
22 static uchar cablingL[][5] = {
23 [Sheeva] {[TCK] 0x01, [TDI] 0x02, [TDO]0x04, [TMS] 0x08, [nOE] 0x10,},
24 [GuruDisp] {[TCK] 0x01, [TDI] 0x02, [TDO]0x04, [TMS] 0x08, [nOE] 0x10,},
25 };
26
27 static uchar valcabling[][2] = {
28 [Sheeva] {isPushPull, isOpenDrain},
29 [GuruDisp] {isPushPull, isPushPull},
30 };
31
32 static u32int cpuids[] = {
33 [Sheeva] FeroceonId,
34 [GuruDisp] ArmadaId,
35 };
36
37 static uchar
hinitvalH(int motherb,int trst,int srst)38 hinitvalH(int motherb, int trst, int srst)
39 {
40 uchar hout;
41
42 hout = 0;
43
44 if(trst){
45 hout |= cablingH[motherb][TRSTnOE];
46 hout &= ~cablingH[motherb][TRST];
47 }
48 else{
49 hout &= ~cablingH[motherb][TRSTnOE];
50 hout |= cablingH[motherb][TRST];
51 }
52 if(srst){
53 hout &= ~cablingH[motherb][SRSTnOE];
54 hout |= cablingH[motherb][SRST];
55 }
56 else{
57 hout |= cablingH[motherb][SRSTnOE];
58 hout &= ~cablingH[motherb][SRST];
59 }
60
61 return hout;
62 }
63
64 static uchar
hinitdirH(int motherb)65 hinitdirH(int motherb)
66 {
67 USED(motherb);
68 //int i;
69 //uchar dir;
70 //dir = 0;
71 //for(i = 0; i < 4; i++)
72 // dir |= cablingH[motherb][i]; /* BUG: TODO */
73 return 0xf;
74 }
75
76 int
mpsseflush(void * mdata)77 mpsseflush(void *mdata)
78 {
79 int r, nb;
80 ushort s;
81 Mpsse *mpsse;
82
83 mpsse = mdata;
84 s = 0xbebe;
85
86 r = 0;
87
88 nb = Bbuffered(&mpsse->bout);
89 if(debug[DFile] || debug[DAll])
90 fprint(2, "Flush %d\n", nb);
91
92 if(debug[DXFlush])
93 Bwrite(&mpsse->bout, &s, sizeof s);
94 if(nb && Bflush(&mpsse->bout) == Beof)
95 r = -1;
96
97 return r;
98 }
99
100 static int
mpsseresets(void * mdata,int trst,int srst)101 mpsseresets(void *mdata, int trst, int srst)
102 {
103 char cmd[128];
104 uchar hout, hdir;
105 int motherb;
106 Mpsse *mpsse;
107
108 mpsse = mdata;
109 motherb = mpsse->motherb;
110
111 hdir = hinitdirH(motherb);
112 hout = hinitvalH(motherb, trst, srst);
113
114 snprint(cmd, sizeof(cmd), "SetBitsH %#2.2ux %#2.2ux", hout, hdir);
115 if(pushcmd(mpsse, cmd) < 0)
116 return -1;
117 if(mpsseflush(mpsse) < 0)
118 return -1;
119 return 0;
120 }
121
122
123 static int
initpins(Mpsse * mpsse)124 initpins(Mpsse *mpsse)
125 {
126 char cmd[128];
127 uchar hout, hdir;
128 int motherb;
129 Biobufhdr *bout;
130
131 motherb = mpsse->motherb;
132 bout = &mpsse->bout;
133
134 /* value of this also depends on opendrain etc?, seems it does not */
135 hout = cablingL[motherb][TMS];
136 hdir = cablingL[motherb][TCK]|cablingL[motherb][TDI];
137 hdir |= cablingL[motherb][TMS]|cablingL[motherb][nOE];
138 snprint(cmd, sizeof(cmd), "SetBitsL %#2.2ux %#2.2ux", hout, hdir);
139 if(pushcmd(mpsse, cmd) < 0){
140 Bterm(bout);
141 return -1;
142 }
143 if(mpsseflush(mpsse) < 0)
144 return -1;
145
146 /* is this Board dependant? */
147 if(mpsseresets(mpsse, 0, 0) < 0)
148 return -1;
149
150 return 0;
151 }
152
153 static int
mpsseterm(void * mdata)154 mpsseterm(void *mdata)
155 {
156 Mpsse *mpsse;
157 int r;
158
159 mpsse = mdata;
160 r = Bterm(&mpsse->bout);
161 free(mpsse);
162
163 return r;
164 }
165
166 /* I always work with bits on the lsb side, nbits count the
167 * n less significant bits, no matter msb or lsb order
168 * I know that mpsse works with lsb on the lsb side and
169 * msb I am not sure how it is codified msb on lsb side would be
170 * 00001234, instead of lsb on msb side 12340000
171 * In any case I never use msb on the mpsse,
172 * just on the paths for convenience and they are lsb side
173 * like 000001234
174 * in other words, nbits always counts from lsb bit
175 */
176 static ulong
msb2lsb(ulong msbl,int nbits)177 msb2lsb(ulong msbl, int nbits)
178 {
179 int i;
180 ulong lsbl, bit;
181
182 lsbl = 0;
183 for(i = 0; i < nbits; i++){
184 bit = (msbl >> (nbits - i - 1))&1;
185 lsbl |= bit << i;
186 }
187 return lsbl;
188 }
189
190 /* how many clk bits takes to clock out a data bit */
191 static int
tmsdata2clk(int nbits)192 tmsdata2clk(int nbits)
193 {
194 return ((nbits + 6)/7) * 3;
195 }
196
197 #define takebits(byte, nbits, offset) (((byte) >> (offset)) & ((1U << (nbits))-1))
198
199 static void
dropbits(Mpsse * mpsse,int nbits)200 dropbits(Mpsse *mpsse, int nbits)
201 {
202 int nby, nbi;
203
204 nby = nbits / 8;
205 nbi = nbits % 8;
206
207 assert(mpsse->nbits >= nbits);
208
209 mpsse->nbits -= 8*nby;
210 mpsse->rb += nby;
211
212 mpsse->rbits = (mpsse->rbits + nbi) %8;
213
214 mpsse->nbits -= nbi;
215 }
216
217 static int
runpath(JMedium * jmed,SmPath * pth,int isrd,int issend)218 runpath(JMedium *jmed, SmPath *pth, int isrd, int issend)
219 {
220 SmPath pref;
221 uchar tmslsb, lastbit;
222 int nclkbits;
223 char cmd[128];
224 Mpsse *mpsse;
225
226 mpsse = jmed->mdata;
227 lastbit = 0;
228 nclkbits = 0;
229 if(issend && mpsse->nbits != 0){
230 lastbit = mpsse->lastbit;
231 mpsse->nbits--;
232 nclkbits = 1;
233 }
234
235 while(pth->ptmslen != 0){
236 pref = takepathpref(pth, MaxNbitsT);
237 tmslsb = msb2lsb(pref.ptms, pref.ptmslen);
238
239 if(issend && nclkbits--){
240 tmslsb |= lastbit<<7;
241 }
242 if(isrd)
243 snprint(cmd, sizeof(cmd), "TmsCsOutIn EdgeDown EdgeUp LSB B%#2.2ux %#2.2ux",
244 (uchar)pref.ptmslen, tmslsb);
245 else
246 snprint(cmd, sizeof(cmd), "TmsCsOut EdgeDown LSB B%#2.2ux %#2.2ux",
247 (uchar)pref.ptmslen, tmslsb);
248
249 if(pushcmd(mpsse, cmd) < 0)
250 return -1;
251 }
252
253 moveto(jmed, pth->st);
254 return 0;
255 }
256
257 static int
sendbytes(Mpsse * mpsse,int nbytes,int op)258 sendbytes(Mpsse *mpsse, int nbytes, int op)
259 {
260 char cmd[128];
261 int totbytes, nwbytes;
262 uchar *buf;
263
264 buf = mpsse->rb;
265 totbytes = mpsse->nbits/8;
266 nwbytes = nbytes;
267 if(totbytes < nbytes){
268 werrstr("sendbytes: not enough %d<%d", totbytes, nbytes);
269 return -1;
270 }
271 if( (op&ShiftIn ) && !(op&ShiftOut) ){
272 snprint(cmd, sizeof(cmd), "DataIn EdgeUp LSB %#2.2ux",
273 nbytes);
274 nwbytes = 0;
275 }
276 else if( !(op&ShiftIn) && (op&ShiftOut) )
277 snprint(cmd, sizeof(cmd), "DataOut EdgeDown LSB %#2.2ux @",
278 nbytes);
279 else if( (op&ShiftIn) && (op&ShiftOut) )
280
281 snprint(cmd, sizeof(cmd), "DataOutIn EdgeDown EdgeUp LSB %#2.2ux @",
282 nbytes);
283 else
284 return -1;
285
286
287 if(pushcmdwdata(mpsse, cmd, buf, nwbytes) < 0)
288 return -1;
289
290 dropbits(mpsse, 8*nbytes);
291 return 0;
292 }
293
294
295 static int
sendbits(Mpsse * mpsse,int nbits,int op)296 sendbits(Mpsse *mpsse, int nbits, int op)
297 {
298 char cmd[128];
299 uchar lastbyte, obyte;
300
301 lastbyte = *mpsse->rb;
302 if(nbits > 8){
303 werrstr("too many bits %d>%d", nbits, MaxNbitsS);
304 return -1;
305 }
306
307
308 obyte = takebits(lastbyte, nbits, mpsse->rbits);
309
310 if( (op&ShiftIn ) && !(op&ShiftOut) )
311 snprint(cmd, sizeof(cmd), "DataIn EdgeUp LSB B%#2.2ux",
312 nbits);
313 else if( !(op&ShiftIn) && (op&ShiftOut) )
314 snprint(cmd, sizeof(cmd), "DataOut EdgeDown LSB B%#2.2ux %#2.2ux",
315 nbits, obyte);
316 else if( (op&ShiftIn) && (op&ShiftOut) )
317
318 snprint(cmd, sizeof(cmd), "DataOutIn EdgeDown EdgeUp LSB B%#2.2ux %#2.2ux",
319 nbits, obyte);
320 else
321 return -1;
322
323
324 if(pushcmd(mpsse, cmd) < 0)
325 return -1;
326
327 dropbits(mpsse, nbits);
328 return 0;
329 }
330
331 static int
movetost(JMedium * jmed,int dst,int isrd,int issend)332 movetost(JMedium *jmed, int dst, int isrd, int issend)
333 {
334 SmPath pth;
335 int len;
336
337 pth = pathto(jmed, dst);
338 len = pth.ptmslen;
339 if(runpath(jmed, &pth, isrd, issend) < 0)
340 return -1;
341 return len;
342 }
343
344 static int
stayinst(JMedium * jmed,int nclock)345 stayinst(JMedium *jmed, int nclock)
346 {
347 SmPath pth;
348
349 pth.ptms = 0;
350 pth.ptmslen = nclock;
351 if(runpath(jmed, &pth, 0, 0) < 0)
352 return -1;
353 return nclock;
354 }
355
356 static int
mpsserdshiftrep(JMedium * jmed,uchar * buf,ShiftRDesc * rep)357 mpsserdshiftrep(JMedium *jmed, uchar *buf, ShiftRDesc *rep)
358 {
359 int nr, npartial, nby;
360 uchar msk;
361
362 Mpsse *mpsse;
363
364 mpsse = jmed->mdata;
365 dprint(DFile, "Reading %d\n", rep->nbyread);
366
367 nr = readn(mpsse->jtagfd, buf, rep->nbyread);
368
369 npartial = 0;
370
371 dprint(DFile, "Read %d\n", nr);
372 dumpbuf(DFile, buf, nr);
373 if(nr <= 0)
374 return -1;
375 if(rep->nbiprelast != 0){
376 npartial++;
377 }
378 if(rep->nbilast != 0){
379 npartial++;
380 }
381 nby = rep->nbyread - npartial;
382 if(rep->nbiprelast != 0){
383 buf[nby] = buf[nby] >> (8 - rep->nbiprelast);
384 }
385 if(rep->nbilast != 0){
386 msk = MSK(rep->nbilast);
387 buf[nby] |= (buf[nby+1] & msk) << (8 - rep->nbilast);
388 }
389 return (7 + nby + npartial) / 8; /* readjust after compacting */
390 }
391
392 /*
393 * May need a couple of two or three bytes of margin for reading,
394 * do not call it with just enough bytes
395 */
396
397 static int
mpsseregshift(JMedium * jmed,ShiftTDesc * req,ShiftRDesc * rep)398 mpsseregshift(JMedium *jmed, ShiftTDesc *req, ShiftRDesc *rep)
399 {
400 int npsend, nr, nl, isrd, nback, nby, ntrail, reg, nbits, op;
401 ShiftRDesc rr;
402 uchar *buf;
403 Mpsse *mpsse;
404
405 reg = req->reg;
406 buf = req->buf;
407 nbits = req->nbits;
408 op = req->op;
409
410 mpsse = jmed->mdata;
411 if(rep == nil)
412 rep = &rr;
413
414 nr = 0;
415 nby = 0;
416 nback = 0;
417 npsend = 0;
418
419
420 if(reg != TapDR && reg != TapIR)
421 sysfatal("unknown register");
422
423 isrd = op&ShiftIn;
424
425 /*
426 * May need to go to Pause to cross capture before starting
427 * May still have a trailing bit from last shifting
428 */
429
430 if(op&ShiftPauseIn){
431 nl = movetost(jmed, TapPauseDR+reg, 0, mpsse->nbits != 0);
432 if(nl < 0){
433 werrstr("regshift: going to pause in");
434 return -1;
435 }
436 }
437
438 if(movetost(jmed, TapShiftDR+reg, 0, mpsse->nbits != 0) < 0){
439 werrstr("regshift: going to shift");
440 return -1;
441 }
442
443 mpsse->nbits = nbits;
444 mpsse->rb = buf;
445 mpsse->rbits = 0;
446
447 if((mpsse->nbits / 8) > 1){
448 nby = mpsse->nbits / 8;
449 if(mpsse->nbits % 8 == 0)
450 nby--;
451 if(sendbytes(mpsse, nby, op) < 0){
452 werrstr("regshift: shifting bytes");
453 return -1;
454 }
455 nback = nby;
456 }
457
458
459 if(mpsse->nbits > 1){
460 nback++; /* each op gives a partial byte */
461 npsend = mpsse->nbits;
462 if(mpsse->nbits > 7) /* apparently hw does not like 8 bytes */
463 npsend = MaxNbitsS;
464 npsend -= 1; /* one is for the way */
465 if(sendbits(mpsse, npsend, op) < 0){
466 werrstr("regshift: shifting bits");
467 return -1;
468 }
469 mpsse->lastbit = takebits(*mpsse->rb, 1, mpsse->rbits);
470 }
471
472
473 /* I only go through pause if I need extra time to shift
474 * for example, I need a command to read or if I am told
475 */
476
477 if(isrd || (op&ShiftPauseOut)){
478 nback++;
479 nl = movetost(jmed, TapPauseDR+reg, isrd, mpsse->nbits != 0);
480 if(nl < 0){
481 werrstr("regshift: going to pause out");
482 return -1;
483 }
484 }
485
486 if(! (op&ShiftNoCommit)){
487 nl = movetost(jmed, TapIdle, 0, mpsse->nbits != 0);
488 if(nl < 0){
489 werrstr("regshift: going to idle out");
490 return -1;
491 }
492 }
493 if(isrd){
494 if(mpsseflush(mpsse) < 0){
495 werrstr("regshift: flushing");
496 return -1;
497 }
498
499 ntrail = nbits - npsend - 8*nby;
500 rep->nbyread = nback;
501 rep->nbiprelast = npsend;
502 rep->nbilast = ntrail;
503 if( !(op&ShiftAsync) )
504 nr = mpsserdshiftrep(jmed, buf, rep);
505 }
506 return nr;
507 }
508
509 JMedium *
newmpsse(int fd,int motherb)510 newmpsse(int fd, int motherb)
511 {
512 Mpsse *mpsse;
513 Biobufhdr *bout;
514 JMedium *jmed;
515 int i;
516
517 jmed = mallocz(sizeof(JMedium), 1);
518 if(jmed == nil)
519 return nil;
520
521 mpsse = malloc(sizeof(Mpsse));
522 if(mpsse == nil)
523 return nil;
524
525 jmed->motherb = motherb;
526 jmed->mdata = mpsse;
527 jmed->regshift = mpsseregshift;
528 jmed->rdshiftrep = mpsserdshiftrep;
529 jmed->flush = mpsseflush;
530 jmed->term = mpsseterm;
531 jmed->resets = mpsseresets;
532
533 /* BUG: configuration file? */
534 if(motherb == Sheeva){
535 jmed->ntaps = 1;
536 jmed->tapcpu = 0;
537 jmed->taps[0].hwid = FeroceonId;
538 jmed->taps[0].irlen = InLen;
539 }
540 else if(motherb == GuruDisp){
541 /* BUG: set concatenating mode */
542 jmed->ntaps = 3;
543 jmed->taps[0].hwid = 0;
544 jmed->taps[0].irlen = 1;
545 jmed->tapcpu = 1;
546 jmed->taps[1].hwid = ArmadaId;
547 jmed->taps[1].irlen = InLen;
548 jmed->taps[2].hwid = 0;
549 jmed->taps[2].irlen = 9;
550 }
551 else
552 sysfatal("Unkwown motherboard");
553
554 for(i = 0; i < jmed->ntaps; i++)
555 jmed->taps[i].state = TapUnknown;
556 jmed->state = TapUnknown;
557
558 mpsse->jtagfd = fd;
559 mpsse->motherb = motherb;
560
561
562 bout = &mpsse->bout;
563
564 if(Binits(bout, fd, OWRITE, mpsse->bp, MpsseBufSz) == Beof){
565 free(mpsse);
566 return nil;
567 }
568 return jmed;
569 }
570
571 JMedium *
initmpsse(int fd,int motherb)572 initmpsse(int fd, int motherb)
573 {
574 Mpsse *mpsse;
575 JMedium *jmed;
576 uchar buf[32];
577 ShiftTDesc req;
578
579
580 jmed = newmpsse(fd, motherb);
581 if(jmed == nil){
582 free(jmed);
583 return nil;
584 }
585 mpsse = jmed->mdata;
586
587 if(initpins(mpsse) < 0)
588 goto Err;
589
590 if(pushcmd(mpsse, "TckSkDiv 0x0200") < 0)
591 goto Err;
592 if(mpsseflush(mpsse) < 0)
593 goto Err;
594
595 if(pushcmd(mpsse, "BreakLoop") < 0)
596 goto Err;
597 if(mpsseflush(mpsse) < 0)
598 goto Err;
599
600 /* Board dependant ? */
601 if(mpsseresets(mpsse, 0, 0) < 0)
602 goto Err;
603
604 if(motherb == GuruDisp){ /* set concat mode */
605 req.reg = TapIR;
606 hleputs(buf, InGuruTapctl);
607 req.buf = buf;
608 req.nbits = InGuruLen;
609 req.op = ShiftOut;
610
611 jmed->regshift(jmed, &req, nil);
612 req.reg = TapDR;
613 hleputs(buf, DrGuruTapctl);
614 req.buf = buf;
615 req.nbits = 16;
616 req.op = ShiftOut;
617 jmed->regshift(jmed, &req, nil);
618 jmed->taps[2].TapSm = jmed->TapSm;
619 }
620 return jmed;
621 Err:
622 mpsseterm(mpsse);
623 free(jmed);
624 return nil;
625 }
626
627 static void
termmpsse(JMedium * jmed)628 termmpsse(JMedium *jmed)
629 {
630 mpsseterm(jmed->mdata);
631 free(jmed);
632 }
633
634
635 JMedium *
resetmpsse(JMedium * jmed)636 resetmpsse(JMedium *jmed)
637 {
638 Mpsse mpsse;
639 JMedium *jmnew;
640
641 mpsse = *(Mpsse *)jmed->mdata;
642 mpsseflush((Mpsse *)jmed->mdata);
643 free(jmed->mdata);
644
645 jmnew = initmpsse(mpsse.jtagfd, mpsse.motherb);
646 return jmnew;
647 }
648
649