1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h> /* BUG: yes I know... ascii*/
4 #include <bio.h>
5 #include "debug.h"
6 #include "tap.h"
7 #include "jtag.h"
8 #include "icert.h" /* BUG: separate medium and ice */
9 #include "mpsse.h"
10
11 /*
12 * Mpsse assembler
13 * Based on AN2232C-01 Command Processor for MPSSE and MCU Host Bus
14 * and various magical commands from source code all around.
15 */
16
17
18 enum{
19 /* MPSSE */
20
21 /*
22 * This are used only to make opcodes
23 * for Clocking in/out data to TD0 to TDI
24 */
25 OpModOut = 0x10,
26 OpTmsCs = 0x4a, /* clock data to TmsCs */
27
28 /* Modifiers for both */
29 OpModShort = 0x02, /* len only one byte */
30 OpModOutFalling = 0x01,
31 OpModInFalling = 0x04,
32 OpModLSB = 0x08,
33 OpModIn = 0x20,
34
35 OpModBitsH = 0x02,
36 OpModBitsIn = 0x01,
37 OpSetBits = 0x80, /* value(?)/direction on pins*/
38
39 OpLoop = 0x84, /* loop connect TDI/DO with TDO/DI */
40 OpBreakLoop = 0x85, /* break loop */
41 OpTckSkDiv = 0x86, /* valL valH, ?? description of reset */
42
43 OpDiv5ClkEnab = 0x8b,
44 OpDiv5ClkDisab = 0x8a,
45
46
47 /* MCU host emulation */
48 OpModLong = 0x01, /* addrH addrL */
49
50 OpMCURd = 0x90, /* addr */
51 OpMCUWr = 0x92, /* addr Data */
52
53 OpBad = 0, /* made this up */
54
55 /* Both modes */
56 OpSendImm = 0x87, /* flush buffer back to PC ??? */
57 OpWaitIOHigh = 0x88, /* IO high, GPIOH in MPSSE, I/O1 on MCU */
58 OpWaitIOLow = 0x89, /* IO low, GPIOH in MPSSE, I/O1 on MCU */
59
60 OpAdaptClkEnab = 0x96,
61 OpAdaptClkDisab = 0x97,
62 RBad = 0xFA, /* followed by the bad command */
63
64 MaxDataSz = 0xffff+1,
65 };
66
67 typedef struct Inst Inst;
68 struct Inst{
69 int hasresp;
70 int isshort;
71 int islsb; /* bits come/go LSB */
72 int nedge;
73 uchar edge[2];
74 uchar opcode;
75 int lensz;
76 uchar len[2];
77 int immsz;
78 uchar imm[3];
79 int datasz;
80 uchar data[1];
81 };
82
83 enum{
84 DataIn,
85 DataOut,
86 DataOutIn,
87 TmsCsOut,
88 TmsCsOutIn,
89 SetBitsL,
90 SetBitsH,
91 TckSkDiv,
92 MCURd, /* from this down, no param */
93 MCUWr,
94 SendImm,
95 WaitIOHigh,
96 WaitIOLow,
97 AdaptClkEnab,
98 AdaptClkDisab,
99 Div5ClkEnab,
100 Div5ClkDisab,
101 GetBitsL,
102 GetBitsH,
103 Loop,
104 BreakLoop,
105 ILast,
106 };
107
108 static char *inst[] = {
109 [DataIn] "DataIn",
110 [DataOut] "DataOut",
111 [DataOutIn] "DataOutIn",
112 [TmsCsOut] "TmsCsOut",
113 [TmsCsOutIn] "TmsCsOutIn",
114 [SetBitsL] "SetBitsL",
115 [SetBitsH] "SetBitsH",
116 [TckSkDiv] "TckSkDiv",
117 [MCURd] "MCURd",
118 [MCUWr] "MCUWr",
119 [SendImm] "SendImm",
120 [WaitIOHigh] "WaitIOHigh",
121 [WaitIOLow] "WaitIOLow",
122 [AdaptClkEnab] "AdaptClkEnab",
123 [AdaptClkDisab] "AdaptClkDisab",
124 [Div5ClkEnab] "Div5ClkEnab",
125 [Div5ClkDisab] "Div5ClkDisab",
126 [GetBitsL] "GetBitsL",
127 [GetBitsH] "GetBitsH",
128 [Loop] "Loop",
129 [BreakLoop] "BreakLoop",
130 [ILast] nil,
131
132 };
133
134
135 enum{
136 EdgeNone,
137 EdgeUp,
138 EdgeDown,
139 EdgeBad,
140 };
141
142 static uchar
dataopcode(Inst * inst,int instid,int issh,int islsb)143 dataopcode(Inst *inst, int instid, int issh, int islsb)
144 {
145 uchar opcode = 0;
146
147 switch(instid){
148 case DataOutIn:
149 if(inst->edge[1] == EdgeDown)
150 opcode = OpModInFalling;
151 /* fall through */
152 case DataOut:
153 opcode |= OpModOut;
154 if (inst->edge[0] == EdgeDown)
155 opcode |= OpModOutFalling;
156 break;
157 case DataIn:
158 if (inst->edge[0] == EdgeDown)
159 opcode |= OpModInFalling;
160 break;
161 }
162
163 opcode |= inst->hasresp? OpModIn : 0;
164 opcode |= issh? OpModShort : 0;
165 opcode |= islsb? OpModLSB : 0;
166
167 return opcode;
168 }
169
170
171 static uchar
opcode(Inst * inst,int instid)172 opcode(Inst *inst, int instid)
173 {
174 int issh, islsb;
175 uchar opcode;
176
177 opcode = 0;
178 issh = inst->isshort;
179 islsb = inst->islsb;
180
181 if(instid != TmsCsOutIn && instid != TmsCsOut&& instid != DataOutIn)
182 if(inst->edge[1] != EdgeNone){
183 werrstr("should not have edge");
184 return OpBad;
185 }
186
187 switch(instid){
188 case DataOutIn:
189 case DataOut:
190 case DataIn:
191 opcode = dataopcode(inst, instid, issh, islsb);
192 break;
193
194 case TmsCsOutIn:
195 opcode = OpModIn;
196 if (inst->edge[1] == EdgeDown)
197 opcode |= OpModInFalling;
198 /* fall through */
199 case TmsCsOut:
200 opcode |= OpTmsCs;
201 if(!issh || (inst->len[0] + 1) > 7){
202 werrstr("len too big: %d, issh:%d",
203 inst->len[0]+1, issh);
204 return OpBad;
205 }
206 if (inst->edge[0] == EdgeDown)
207 opcode |= OpModOutFalling;
208 opcode |= OpModShort;
209 opcode |= OpModLSB;
210 break;
211 case MCURd:
212 opcode = OpMCURd;
213 opcode |= !issh? OpModLong : 0;
214 break;
215 case MCUWr:
216 opcode = OpMCUWr;
217 opcode |= !issh? OpModLong : 0;
218 break;
219 case SendImm:
220 opcode = OpSendImm;
221 break;
222 case WaitIOHigh:
223 opcode = OpWaitIOHigh;
224 break;
225 case TckSkDiv:
226 opcode = OpTckSkDiv;
227 break;
228 case WaitIOLow:
229 opcode = OpWaitIOLow;
230 break;
231 case AdaptClkEnab:
232 opcode = OpAdaptClkEnab;
233 break;
234 case AdaptClkDisab:
235 opcode = OpAdaptClkDisab;
236 break;
237 case Div5ClkEnab:
238 opcode = OpDiv5ClkEnab;
239 break;
240 case Div5ClkDisab:
241 opcode = OpDiv5ClkDisab;
242 break;
243 case GetBitsH:
244 case SetBitsH:
245 opcode = OpModBitsH;
246 case GetBitsL:
247 /* fall through */
248 if(instid == GetBitsL || instid == GetBitsH)
249 opcode |= OpModBitsIn;
250 case SetBitsL:
251 opcode |= OpSetBits;
252 break;
253 case Loop:
254 opcode = OpLoop;
255 break;
256 case BreakLoop:
257 opcode = OpBreakLoop;
258 break;
259 default:
260 werrstr("unknown instruction");
261 return OpBad;
262 }
263 return opcode;
264 }
265
266 enum {
267 ParLen = 'L', /* Data len 2 bytes or 1 byte (bit len) */
268 ParShLen = 'l', /* bit len Bnumber */
269 ParData = 'D', /* data or @ to place data later */
270 ParShData = 'd', /* short data, 1 byte at most */
271 ParImm = 'I', /* immediate operator, 2/1 bytes */
272 ParLImm = 'i', /* immediate operator, 2 bytes */
273 ParShImm = 'c', /* immediate operator, 1 byte */
274 ParEdge = 'E', /* EdgeUp or EdgeDown */
275 ParEndian = 'N', /* LSB or MSB */
276 ParLsb = 'n', /* LSB */
277 };
278
279 typedef struct InstDesc InstDesc;
280 struct InstDesc
281 {
282 char *name;
283 char *desc;
284 int hasresp;
285 };
286
287 static InstDesc idesc[] = {
288 [DataIn] {"DataIn", "ENL", 1},
289 [DataOut] {"DataOut", "ENLD", 0},
290 [DataOutIn] {"DataOutIn", "EENLD", 1},
291 [TmsCsOut] {"TmsCsOut", "ENld", 0},
292 [TmsCsOutIn] {"TmsCsOutIn", "EENld", 1},
293 [MCURd] {"MCURd", "I", 1},
294 [MCUWr] {"MCUWr", "Id", 0},
295 [SendImm] {"SendImm", "", 0},
296 [WaitIOHigh] {"WaitIOHigh", "", 0},
297 [WaitIOLow] {"WaitIOLow", "", 0},
298 [AdaptClkEnab] {"AdaptClkEnab", "", 0},
299 [AdaptClkDisab] {"AdaptClkDisab", "", 0},
300 [Div5ClkEnab] {"Div5ClkEnab", "", 0},
301 [Div5ClkDisab] {"Div5ClkDisab", "", 0},
302 [SetBitsL] {"SetBitsL", "cc", 0},
303 [GetBitsL] {"GetBitsL", "c", 0},
304 [SetBitsH] {"SetBitsH", "cc", 0},
305 [GetBitsH] {"GetBitsH", "c", 0},
306 [TckSkDiv] {"TckSkDiv", "i", 0},
307 [Loop] {"Loop", "", 0},
308 [BreakLoop] {"BreakLoop", "", 0},
309 [ILast] {nil, nil, 0},
310 };
311
312
313 static int
nametoid(char * name)314 nametoid(char *name)
315 {
316 int i;
317 for (i = 0; i < ILast; i++){
318 if(strcmp(inst[i], name) == 0)
319 break;
320 }
321 if(i == ILast)
322 return -1;
323 return i;
324 }
325
326 static int
edgetoid(char * edgename)327 edgetoid(char *edgename)
328 {
329 if(strcmp(edgename, "EdgeUp") == 0)
330 return EdgeUp;
331 else if(strcmp(edgename, "EdgeDown") == 0)
332 return EdgeDown;
333
334 return EdgeBad;
335 }
336
337 static int
isendian(char * endianname)338 isendian(char *endianname)
339 {
340 if(strcmp(endianname, "LSB") == 0)
341 return 1;
342 else if(strcmp(endianname, "MSB") == 0)
343 return 1;
344
345 return 0;
346 }
347
348
349 static int
datalen(Inst * inst,char * p)350 datalen(Inst *inst, char *p)
351 {
352 int len;
353 if(p[0] == 'B'){
354 inst->isshort++;
355 p++;
356 }
357 else
358 inst->isshort = 0;
359 len = atoi(p); //strtol and check
360 if(inst->isshort && len > 8)
361 return -1;
362 if(len > MaxDataSz)
363 return -1;
364 return len;
365 }
366
367 static void
setlen(Inst * inst,int dlen)368 setlen(Inst *inst, int dlen)
369 {
370 if(dlen != 0){
371 inst->lensz++;
372 inst->len[0] = (dlen - 1 ) & 0xff;
373 if(!inst->isshort){
374 inst->len[1] = 0xff & ((dlen - 1) >> 8);
375 inst->lensz++;
376 }
377 }
378 }
379
380
381 static int
setdata(Inst * inst,char * nm,char * p,char * te,int bdlen)382 setdata(Inst *inst, char *nm, char *p, char *te, int bdlen)
383 {
384 int i;
385 char *e;
386
387 if(p == nil){
388 werrstr("%s: should have data", nm);
389 return -1;
390 }
391 if(*p == '@'){
392 inst->datasz = bdlen;
393 return 0;
394 }
395
396 if(te != p)
397 p[strlen(p)] = ' '; /* untokenize */
398
399 for (i = 0; i < bdlen; i++){
400 inst->data[i] = strtol(p, &e, 0);
401 if(!isspace(*e) && i != bdlen-1)
402 return -1;
403 p = e;
404 }
405 inst->datasz = i;
406 return 0;
407
408 }
409
410 static int
hasresp(int instid)411 hasresp(int instid)
412 {
413 return idesc[instid].hasresp;
414 }
415
416
417 static int
hasnoparam(int instid)418 hasnoparam(int instid)
419 {
420 return strlen(idesc[instid].desc) == 0;
421 }
422
423 static char *
endfield(char * p)424 endfield(char *p)
425 {
426 char *s;
427
428 s = p;
429 if(*p =='\0')
430 return nil;
431 while(*p != '\0'){
432 if(isspace(*p)){
433 if(s == p)
434 return nil;
435 return p;
436 }
437 p++;
438 }
439 return p;
440 }
441
442 enum{
443 LongSz,
444 ShortSz,
445 AnySz,
446 };
447
448 static int
setimm(Inst * inst,int imm,int kindsz)449 setimm(Inst *inst, int imm, int kindsz)
450 {
451 int isl, immh, imml;
452
453 isl = imm&~0xff;
454
455 if(isl && kindsz == ShortSz)
456 return -1;
457
458
459 if(isl || kindsz == LongSz){
460 immh = (imm >> 8)&0xff;
461 inst->imm[inst->immsz++] = immh; /* High, then low */
462 }
463 imml = imm&0xff;
464 inst->imm[inst->immsz++] = imml;
465 return 0;
466 }
467
468 static Inst*
parseinst(int instid,char * pars,char * idname)469 parseinst(int instid, char *pars, char *idname)
470 {
471 char *tok[15], *err, *e;
472 char tf;
473 int i, ntok, tnf, dlen, bdlen, imm, ndata;
474 Inst *inst;
475
476 tf = '\0';
477 dlen = bdlen = 0;
478 err = "";
479 inst = mallocz(sizeof(Inst) + 1, 1);
480 if(inst == nil)
481 return nil;
482 tnf = strlen(idesc[instid].desc);
483 e = pars + strlen(pars) + 1;
484 ntok = tokenize(pars, tok, tnf);
485 if(tnf != ntok){
486 werrstr("%s: bad nr param %d!=%d", idname, tnf, ntok);
487 return nil;
488 }
489
490 for(i = 0; i < tnf; i++){
491 tf = idesc[instid].desc[i];
492 switch(tf){
493 case ParLen:
494 dlen = datalen(inst, tok[i]);
495 if(dlen < 0){
496 err = "bad len";
497 goto Err;
498 }
499 if(inst->isshort)
500 bdlen = 1;
501 else {
502 bdlen = dlen;
503 inst = realloc(inst, sizeof(Inst) + bdlen);
504 if(inst == nil)
505 return nil;
506 }
507 break;
508 case ParShLen:
509 dlen = datalen(inst, tok[i]);
510 if(dlen < 0){
511 err = "bad len";
512 goto Err;
513 }
514 bdlen = 1;
515 if(!inst->isshort) {
516 err = "should be short";
517 goto Err;
518 }
519 break;
520 case ParData:
521 if(bdlen != 0){
522 ndata = setdata(inst, idname, tok[i], e, bdlen);
523 if(ndata < 0){
524 err = "short data";
525 goto Err;
526 }
527 }
528 else {
529 err = "no data";
530 goto Err;
531 }
532 break;
533 case ParShData:
534 if(bdlen != 0){
535 ndata = setdata(inst, idname, tok[i], e, bdlen);
536 if(ndata < 0){
537 err = "short data";
538 goto Err;
539 }
540 }
541 else {
542 err = "no data";
543 goto Err;
544 }
545 if(ndata > 1){
546 err = "more than 1 byte data";
547 goto Err;
548 }
549 break;
550 case ParImm:
551 imm = atoi(tok[i]);
552 if(setimm(inst, imm, AnySz) < 0)
553 goto Err;
554 break;
555 case ParLImm:
556 imm = atoi(tok[i]);
557 if(setimm(inst, imm, LongSz) < 0)
558 goto Err;
559 break;
560 case ParShImm:
561 imm = atoi(tok[i]);
562 if(setimm(inst, imm, ShortSz) < 0)
563 goto Err;
564 break;
565 case ParEdge:
566 inst->edge[inst->nedge] = edgetoid(tok[i]);
567 if(inst->edge[inst->nedge] == EdgeBad)
568 goto Err;
569 inst->nedge++;
570 break;
571 case ParEndian:
572 inst->islsb = strcmp(tok[i], "LSB") == 0;
573 if(!isendian(tok[i])){
574 err = "bad endianness";
575 goto Err;
576 }
577 break;
578 case ParLsb:
579 inst->islsb = strcmp(tok[i], "LSB") == 0;
580 if(inst->islsb){
581 err = "bad endianness: not LSB";
582 goto Err;
583 }
584 break;
585 default:
586 err = "bad param";
587 goto Err;
588 }
589
590 if(bdlen > MaxDataSz || (inst->isshort && dlen > 8)){
591 err = "len too big";
592 goto Err;
593 }
594 }
595
596 setlen(inst, dlen);
597 inst->hasresp = hasresp(instid);
598 inst->opcode = opcode(inst, instid);
599 if(inst->opcode == OpBad){
600 err = "bad opcode";
601 goto Err;
602 }
603 return inst;
604 Err:
605 werrstr("inst:%s, nf:%d, ftype:%c, fval:%s:%s\n", idname, i, tf, tok[i], err);
606 free(inst);
607 return nil;
608 }
609
610 static Inst *
parseassln(char * assline)611 parseassln(char *assline)
612 {
613 int instid, lnsz;
614 Inst *inst;
615 char *ef, inm[32];
616
617 dprint(Dassln, "%s\n", assline);
618
619 lnsz = strlen(assline);
620 if(lnsz == 0){
621 werrstr("%s: line does not match instruction", assline);
622 return nil;
623 }
624
625 ef = endfield(assline);
626 if(ef == nil){
627 werrstr("%s: empty inst", assline);
628 return nil;
629 }
630 strncpy(inm, assline, ef-assline);
631 inm[ef-assline] = '\0';
632 instid = nametoid(inm);
633 if(instid < 0){
634 werrstr("unrecognized instruction %s", inm);
635 return nil;
636 }
637 inst = parseinst(instid, ef, inm);
638 return inst;
639 }
640
641 static int
unpacklen(Inst * inst)642 unpacklen(Inst *inst)
643 {
644 int len;
645
646 if (inst->lensz == 0)
647 return 0;
648 len = ((inst->len[1]<<8) | inst->len[0]) + 1;
649
650 return len;
651 }
652
653 static int
instpacksz(Inst * inst)654 instpacksz(Inst *inst)
655 {
656 return 1 + inst->immsz + inst->lensz + inst->datasz;
657 }
658
659 static void
sdumpinst(char * s,int ssz,Inst * inst)660 sdumpinst(char *s, int ssz, Inst *inst)
661 {
662 int i;
663 char *e, *te;
664
665 e = s + ssz - 1;
666 te = e;
667
668 e = seprint(s, te, "op: %#2.2ux\n", inst->opcode);
669 if(e >= te)
670 return;
671 if(inst->hasresp){
672 e = seprint(e, te, "hasresp: %d\n", inst->hasresp);
673 if(e >= te)
674 return;
675 }
676 if(inst->isshort){
677 e = seprint(e, te, "isshort: %d\n", inst->isshort);
678 if(e >= te)
679 return;
680 }
681 e = seprint(e, te, "islsb: %d\n", inst->islsb);
682 if(e >= te)
683 return;
684
685 for(i = 0; i < inst->immsz; i++){
686 e = seprint(e, te, "imm%d: %#2.2ux\n", i, inst->imm[i]);
687 if(e >= te)
688 return;
689 }
690
691 if(inst->lensz != 0){
692 e = seprint(e, te, "lensz: %d\n", inst->lensz);
693 if(e >= te)
694 return;
695 e = seprint(e, te, "len: %d\n", unpacklen(inst));
696 if(e >= te)
697 return;
698 e = seprint(e, te, "datasz: %d\n", inst->datasz);
699 if(e >= te)
700 return;
701 for(i = 0; i < inst->datasz; i++){
702 e = seprint(e, te, "%#2.2ux ", inst->data[i]);
703 if(e >= te)
704 return;
705 }
706 }
707 }
708
709 static void
debpack(Inst * inst)710 debpack(Inst *inst)
711 {
712 int i;
713 if(!debug[Dmach] && !debug[DAll])
714 return;
715 fprint(2, "%#2.2ux ", inst->opcode);
716
717 for(i = 0; i < inst->immsz; i++)
718 fprint(2, "%#2.2ux ", inst->imm[i]);
719 for(i = 0; i < inst->lensz; i++)
720 fprint(2, "%#2.2ux ", inst->len[i]);
721 fprint(2, "\n");
722 dumpbuf(Dmach, inst->data, inst->datasz);
723 fprint(2, "\n");
724 }
725
726
727 static int
instpack(Mpsse * mpsse,Inst * inst)728 instpack(Mpsse *mpsse, Inst *inst)
729 {
730 int n;
731 int sz;
732 Biobufhdr *bp;
733
734 bp = &mpsse->bout;
735
736 sz = instpacksz(inst);
737 if(sz + Bbuffered(bp) > MpsseBufSz){
738 n = mpsseflush(mpsse);
739 if(n < 0)
740 return -1;
741 }
742 debpack(inst);
743 n = Bwrite(bp, &inst->opcode, 1);
744 if(n < 0)
745 return -1;
746 n = Bwrite(bp, inst->imm, inst->immsz);
747 if(n < 0)
748 return -1;
749 n = Bwrite(bp, inst->len, inst->lensz);
750 if(n < 0)
751 return -1;
752 n = Bwrite(bp, inst->data, inst->datasz);
753 if(n < 0)
754 return -1;
755 return 0;
756 }
757
758 int
pushcmd(Mpsse * mpsse,char * ln)759 pushcmd(Mpsse *mpsse, char *ln)
760 {
761 Inst *inst;
762 int res;
763 char *dmp, *lln;
764
765 res = 0;
766 lln = strdup(ln);
767 inst = parseassln(lln);
768 free(lln);
769
770 if(inst == nil)
771 return -1;
772 if(debug[Dinst]){
773 dmp = malloc(255);
774 if(dmp == nil)
775 return -1;
776 sdumpinst(dmp, 255, inst);
777 fprint(2, "%s\n", dmp);
778 free(dmp);
779 }
780
781 if(instpack(mpsse, inst) < 0)
782 res = -1;
783 free(inst);
784 return res;
785 }
786
787 int
pushcmdwdata(Mpsse * mpsse,char * ln,uchar * buf,int buflen)788 pushcmdwdata(Mpsse *mpsse, char *ln, uchar *buf, int buflen)
789 {
790 Inst *inst;
791 int res;
792 char *dmp, *lln;
793
794 res = 0;
795 lln = strdup(ln);
796 inst = parseassln(lln);
797 free(lln);
798
799 if(inst == nil)
800 return -1;
801 if(inst->datasz != buflen){
802 werrstr("wrong data in cmd %d != %d", inst->datasz, buflen);
803 return -1;
804 }
805 memmove(inst->data, buf, inst->datasz);
806 if(debug[Dinst]){
807 dmp = malloc(255);
808 if(dmp == nil)
809 return -1;
810 sdumpinst(dmp, 255, inst);
811 fprint(2, "%s\n", dmp);
812 free(dmp);
813 }
814
815 if(instpack(mpsse, inst) < 0)
816 res = -1;
817 free(inst);
818 return res;
819 }
820
821