GPLv2
[s3load.git] / s3load.c
1 /* s3load.c
2  * Main program for s3load
3  * s3load, a free SVF loader for Digilent NEXYS2 boards
4  *
5  * Copyright (c) 2007-2008 Joshua Wise
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License.
10  *
11  * Commercial licenses are available by request.
12  */
13
14 #include "libnexys.h"
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <assert.h>
20
21 enum TAPSTATE {
22         TAP_UNKNOWN,
23         TAP_RESET,
24         TAP_IDLE,
25         TAP_DRSEL,
26         TAP_DRCAP,
27         TAP_DRSHIFT,
28         TAP_DREXIT1,
29         TAP_DRPAUSE,
30         TAP_DREXIT2,
31         TAP_DRUPDATE,
32         TAP_IRSEL,
33         TAP_IRCAP,
34         TAP_IRSHIFT,
35         TAP_IREXIT1,
36         TAP_IRPAUSE,
37         TAP_IREXIT2,
38         TAP_IRUPDATE,
39 };
40
41 typedef struct tap {
42         nexys2_t nexys;
43         int tapstate;
44 } tap_t;
45
46 int s3l_tap_reset(tap_t *tap)
47 {
48         unsigned char reset[] = {0xAA, 0x02};
49         tap->tapstate = TAP_RESET;
50         return nexys2_jtag_puttmstdi(tap->nexys, 5, reset, NULL);
51 }
52
53 int s3l_tap_idle(tap_t *tap)
54 {
55         switch (tap->tapstate)
56         {
57         case TAP_UNKNOWN:
58                 printf("Resetting TAP from unknown state...\n");
59                 s3l_tap_reset(tap);
60         case TAP_RESET:
61         {
62                 unsigned char idle[] = {0x00};
63                 printf("Placing TAP in idle state...\n");
64                 tap->tapstate = TAP_IDLE;
65                 return nexys2_jtag_puttmstdi(tap->nexys, 1, idle, NULL);
66         }
67         case TAP_IDLE:
68                 return 0;
69         default:
70                 printf("cannot transition to idle from %d\n", tap->tapstate);
71                 abort();
72         }
73 }
74
75 enum TOKENTYPE {
76         TOK_TRST = 0,
77         TOK_OFF = 1,
78         TOK_ENDIR = 2,
79         TOK_IDLE = 3,
80         TOK_ENDDR = 4,
81         TOK_STATE = 5,
82         TOK_RESET = 6,
83         TOK_FREQUENCY = 7,
84         TOK_1E6 = 8,
85         TOK_HZ = 9,
86         TOK_SEMICOLON = 10,
87         TOK_TIR = 11,
88         TOK_HIR = 12,
89         TOK_TDR = 13,
90         TOK_HDR = 14,
91         TOK_SIR = 15,
92         TOK_SDR = 16,
93         TOK_TDI = 17,
94         TOK_TDO = 18, 
95         TOK_MASK = 19,
96         TOK_SMASK = 20,
97         TOK_NUMBER = 21,
98         TOK_BITSTRING = 22,
99         TOK_RUNTEST = 23,
100         TOK_TCK = 24,
101 };
102
103 typedef struct token {
104         int token;
105         union {
106                 int i;
107                 char *s;
108         } data;
109         struct token *next;
110 } token_t;
111
112 int hex2nyb(char c)
113 {
114         if (c >= '0' && c <= '9')
115                 return c-'0';
116         if (c >= 'a' && c <= 'f')
117                 return c-'a'+10;
118         if (c >= 'A' && c <= 'F')
119                 return c-'A'+10;
120         printf("Bad hex nybble %c\n", c);
121         abort();
122 }
123
124 token_t *tokenize(int fd)
125 {
126         /* First off, suck in ALL of the file */
127         char *f = NULL, *fst;
128         int sz = 0;
129         token_t *start = NULL, *cur = NULL;
130         
131         while (1)
132         {
133                 int rsz;
134                 f = realloc(f, sz + 16385);
135                 if ((rsz = read(fd, &(f[sz]), 16384)) < 16384)
136                 {
137                         sz += rsz;
138                         break;
139                 }
140                 sz += rsz;
141         }
142         f[sz] = 0;
143         fst = f;
144         
145         while (f && *f)
146         {
147                 if (!strncmp(f, "//", 2))
148                 {
149                         // Comment, eat the rest of the line
150                         f = strchr(f, '\n');
151                         if (f && f[1] == '\r')
152                                 f += 2;
153                         else if (f)
154                                 f++;
155                 } else if (*f == '\n' || *f == '\r' || *f == '\t' || *f == ' ')
156                         f++;
157 #define NEWTOKEN \
158         if (!cur) \
159         { \
160                 start = cur = malloc(sizeof(*cur)); \
161                 start->next = NULL; \
162         } else { \
163                 cur->next = malloc(sizeof(*cur)); \
164                 cur = cur->next; \
165                 cur->next = NULL; \
166         }
167 #define MATCHSTRING(str, tok) \
168         if (!strncmp(f, str, strlen(str))) { \
169                 NEWTOKEN \
170                 cur->token = tok; \
171                 f += strlen(str); \
172         }
173                 else MATCHSTRING("TRST", TOK_TRST)
174                 else MATCHSTRING("OFF", TOK_OFF)
175                 else MATCHSTRING("ENDIR", TOK_ENDIR)
176                 else MATCHSTRING("IDLE", TOK_IDLE)
177                 else MATCHSTRING("ENDDR", TOK_ENDDR)
178                 else MATCHSTRING("STATE", TOK_STATE)
179                 else MATCHSTRING("RESET", TOK_RESET)
180                 else MATCHSTRING("FREQUENCY", TOK_FREQUENCY)
181                 else MATCHSTRING("1E6", TOK_1E6)
182                 else MATCHSTRING("HZ", TOK_HZ)
183                 else MATCHSTRING(";", TOK_SEMICOLON)
184                 else MATCHSTRING("TIR", TOK_TIR)
185                 else MATCHSTRING("HIR", TOK_HIR)
186                 else MATCHSTRING("TDR", TOK_TDR)
187                 else MATCHSTRING("HDR", TOK_HDR)
188                 else MATCHSTRING("TDI", TOK_TDI)
189                 else MATCHSTRING("SMASK", TOK_SMASK)
190                 else MATCHSTRING("SIR", TOK_SIR)
191                 else MATCHSTRING("MASK", TOK_MASK)
192                 else MATCHSTRING("TDO", TOK_TDO)
193                 else MATCHSTRING("SDR", TOK_SDR)
194                 else MATCHSTRING("RUNTEST", TOK_RUNTEST)
195                 else MATCHSTRING("TCK", TOK_TCK)
196                 else if (isdigit(*f)) {
197                         NEWTOKEN
198                         cur->token = TOK_NUMBER;
199                         cur->data.i = *f - '0';
200                         f++;
201                         while (isdigit(*f))
202                         {
203                                 cur->data.i *= 10;
204                                 cur->data.i += *f - '0';
205                                 f++;
206                         }
207                 } else if (*f == '(') {
208                         int asz = 0;
209                         int l = 0;
210                         NEWTOKEN
211                         cur->token = TOK_BITSTRING;
212                         cur->data.s = NULL;
213                         f++;
214                         while (*f && *f != ')')
215                         {
216                                 char c1, c2;
217                                 while (isspace(*f) && *f && *f != ')')
218                                         f++;
219                                 if (!*f || *f == ')')
220                                         break;
221                                 c1 = *(f++);
222                                 
223                                 while (isspace(*f) && *f && *f != ')')
224                                         f++;
225                                 if (!*f || *f == ')')
226                                 {
227                                         printf("Unpaired hex digit in bitstring\n");
228                                         abort();
229                                 }
230                                 c2 = *(f++);
231                                 
232                                 if (l == asz)
233                                 {
234                                         asz += 128;
235                                         cur->data.s = realloc(cur->data.s, asz);
236                                 }
237                                 cur->data.s[l++] = hex2nyb(c1) << 4 | hex2nyb(c2);
238                         } 
239                         f++;
240                 } else {
241                         printf("Tokenizing error, unhandled: %s\n", f);
242                         abort();
243                 }
244         }
245         
246         free(fst);
247         
248         return start;
249 }
250
251 typedef struct blitval {
252         int len;
253         char *tdi, *tdo, *mask, *smask;
254 } blitval_t;
255
256 /* Copies bits from an input in format:
257  *  (msb first) 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15 | ...
258  * To an output in format:
259  *  7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 | ...
260  */
261 void bitcopy(int len, unsigned char *inbits, int inpos, int indir, unsigned char *outbits, int outpos, int outdir)
262 {
263         int i;
264         if (!inbits || !outbits)
265                 return;
266         for (i = 0; i < len; i++)
267         {
268                 int inbit;
269                 inbit = inbits[(inpos + i * indir) / 8] & (1 << (7 - ((inpos + i * indir) % 8)));
270                 outbits[(outpos + i * outdir) / 8] |= inbit ? (1 << ((outpos + i * outdir) % 8)) : 0;
271         }
272 }
273
274 void printprog(int done, int total)
275 {
276         int i;
277         int progresscounter = done * 32 / total;
278         static int spinnerstate;
279         char *spinner = "_.oOo.";
280         
281         printf("[");
282         for (i=0; i < progresscounter; i++)
283                 printf("=");
284         if (progresscounter != 32)
285                 printf(">");
286         for (i=0; i < (31 - progresscounter); i++)
287                 printf(" ");
288         printf("] %c %d/%d", spinner[(spinnerstate++) % 6], done, total);
289 }
290
291 void pokethrough(tap_t *tap, blitval_t *tbv, blitval_t *sbv, blitval_t *hbv)
292 {
293         int totlen = tbv->len + sbv->len + hbv->len;
294         int lenb = (totlen / 4) + ((totlen % 4) != 0) + 1;      // Number of nexys2_* bytes
295         unsigned char *inb = calloc(lenb, 1);                   // Bitstream to be fed to nexys2_*
296         unsigned char *outb = calloc(lenb, 1);
297         unsigned char *expoutb = calloc(lenb, 1);
298         int bitp = 0;                                   // Position in the "inb" bitstream
299         int txp = 0;
300         int needout = 0;
301         
302         if (!totlen)
303                 return;
304         
305         printf("t:%d, s:%d, h:%d\n", tbv->len, sbv->len, hbv->len);
306         
307         bitp = 0;
308 #define ROUNDUP(x) (((x / 8) + ((x % 8) != 0)) * 8 - 1)
309         bitcopy(hbv->len, hbv->tdi, ROUNDUP(hbv->len), -1, inb, bitp*2, 2); bitp += hbv->len;
310         bitcopy(sbv->len, sbv->tdi, ROUNDUP(sbv->len), -1, inb, bitp*2, 2); bitp += sbv->len;
311         bitcopy(tbv->len, tbv->tdi, ROUNDUP(tbv->len), -1, inb, bitp*2, 2); bitp += tbv->len;
312         inb[(bitp*2-2)/8] |= 2 << ((bitp*2-2) % 8);
313         assert(bitp == totlen);
314         
315         if (sbv->tdo)
316                 needout = 1;
317         bitp = 0;       /* Have to throw away one bit :( */
318         bitcopy(tbv->len, tbv->tdo, ROUNDUP(tbv->len), -1, expoutb, bitp, 1); bitp += tbv->len;
319         bitcopy(sbv->len, sbv->tdo, ROUNDUP(sbv->len), -1, expoutb, bitp, 1); bitp += sbv->len;
320         bitcopy(hbv->len, hbv->tdo, ROUNDUP(hbv->len), -1, expoutb, bitp, 1); bitp += hbv->len;
321         
322         
323         for (txp = 0; txp < totlen; txp += 0x8000)
324         {
325                 int len = (((txp + 0x8000) > totlen) ? totlen : (txp + 0x8000)) - txp;
326                 printf("Shifting: "); printprog(txp + len, totlen); printf("\r");
327                 fflush(stdout);
328                 nexys2_jtag_puttmstdi(tap->nexys, len, inb + ((txp * 2) / 8), needout ? (outb + (txp / 8)) : NULL);
329         }
330         printf("\n");
331         
332         printf("I: %02x, %02x, %02x, %02x\n", (int)inb[0], (int)inb[1], (int) inb[2], (int)inb[3]);
333         printf("O: %02x, %02x, %02x, %02x\n", (int)outb[0], (int)outb[1], (int)outb[2], (int)outb[3]);
334         printf("X: %02x, %02x, %02x, %02x\n", (int)expoutb[0], (int)expoutb[1], (int)expoutb[2], (int)expoutb[3]);
335         
336         free(inb);
337         free(outb);
338         free(expoutb);
339 }
340
341 void runsvf(tap_t *tap, token_t *tlist)
342 {
343         int trst = 0;
344         int endir = TOK_IDLE, enddr = TOK_IDLE;
345         blitval_t tir, tdr, hir, hdr;
346         
347         tir.len = 0;
348         tdr.len = 0;
349         hir.len = 0;
350         hdr.len = 0;
351         
352 #define NEXT tlist = tlist->next
353 #define REQUIRENEXT do { NEXT; if (!tlist) { printf("Unexpected end of stream\n"); abort(); } } while(0)
354 #define EXPECT(tok) \
355                 if (tlist->token != tok) \
356                 { \
357                         printf("Expected " #tok ", got %d\n", tok); \
358                         abort(); \
359                 }
360         
361         while (tlist)
362         {
363                 switch (tlist->token)
364                 {
365                 case TOK_TRST:
366                         REQUIRENEXT; EXPECT(TOK_OFF);
367                         trst = 0;
368                         REQUIRENEXT; EXPECT(TOK_SEMICOLON);
369                         NEXT;
370                         break;
371                 case TOK_ENDIR:
372                         REQUIRENEXT; EXPECT(TOK_IDLE);
373                         endir = TOK_IDLE;
374                         REQUIRENEXT; EXPECT(TOK_SEMICOLON);
375                         NEXT;
376                         break;
377                 case TOK_ENDDR:
378                         REQUIRENEXT; EXPECT(TOK_IDLE);
379                         enddr = TOK_IDLE;
380                         REQUIRENEXT; EXPECT(TOK_SEMICOLON);
381                         NEXT;
382                         break;
383                 case TOK_STATE:
384                         REQUIRENEXT;
385                         printf("Changing state...\n");
386                         if (tlist->token == TOK_RESET)
387                                 s3l_tap_reset(tap);
388                         else if (tlist->token == TOK_IDLE)
389                                 s3l_tap_idle(tap);
390                         else {
391                                 printf("Unknown token after TOK_STATE\n");
392                                 abort();
393                         }
394                         REQUIRENEXT; EXPECT(TOK_SEMICOLON);
395                         NEXT;
396                         break;
397                 case TOK_FREQUENCY:
398                         REQUIRENEXT; EXPECT(TOK_1E6);
399                         REQUIRENEXT; EXPECT(TOK_HZ);
400                         REQUIRENEXT; EXPECT(TOK_SEMICOLON);
401                         NEXT;
402                         break;
403                 case TOK_TIR:
404                 case TOK_TDR:
405                 case TOK_HIR:
406                 case TOK_HDR:
407                 case TOK_SIR:
408                 case TOK_SDR:
409                 {
410                         int oldtok = tlist->token;
411                         blitval_t *bv;
412                         blitval_t s;
413                                                 
414                         if (oldtok == TOK_TIR)
415                                 bv = &tir;
416                         else if (oldtok == TOK_HIR)
417                                 bv = &hir;
418                         else if (oldtok == TOK_TDR)
419                                 bv = &tdr;
420                         else if (oldtok == TOK_HDR)
421                                 bv = &hdr;
422                         else
423                                 bv = &s;
424                         
425                         REQUIRENEXT; EXPECT(TOK_NUMBER);
426                         bv->len = tlist->data.i;
427                         bv->tdi = NULL;
428                         bv->tdo = NULL;
429                         bv->mask = NULL;
430                         bv->smask = NULL;
431                         REQUIRENEXT;
432                         
433                         while (tlist->token != TOK_SEMICOLON)
434                         {
435                                 switch (tlist->token)
436                                 {
437                                 case TOK_TDI:
438                                         REQUIRENEXT; EXPECT(TOK_BITSTRING);
439                                         bv->tdi = tlist->data.s;
440                                         REQUIRENEXT;
441                                         break;
442                                 case TOK_TDO:
443                                         REQUIRENEXT; EXPECT(TOK_BITSTRING);
444                                         bv->tdo = tlist->data.s;
445                                         REQUIRENEXT;
446                                         break;
447                                 case TOK_MASK:
448                                         REQUIRENEXT; EXPECT(TOK_BITSTRING);
449                                         bv->mask = tlist->data.s;
450                                         REQUIRENEXT;
451                                         break;
452                                 case TOK_SMASK:
453                                         REQUIRENEXT; EXPECT(TOK_BITSTRING);
454                                         bv->smask = tlist->data.s;
455                                         REQUIRENEXT;
456                                         break;
457                                 default:
458                                         abort();
459                                 }
460                         }
461                         EXPECT(TOK_SEMICOLON);
462                         NEXT;
463                         
464                         if (oldtok == TOK_SIR || oldtok == TOK_SDR)
465                         {
466                                 char *capturedr = "\x02";
467                                 char *captureir = "\x0A";
468                                 char *returnidle = "\x02";
469                                 s3l_tap_idle(tap);
470                                 /* Enter capture DR is TMS 1 0  */
471                                 /* Enter capture IR is TMS 1 1 0 */
472                                 /* Return to RTI is TMS 1 0 */
473                                 
474                                 if (oldtok == TOK_SIR)
475                                 {
476                                         printf("Shifting IR (%d bits)...\n", tir.len + s.len + hdr.len);
477                                         nexys2_jtag_puttmstdi(tap->nexys, 4, captureir, NULL);
478                                         pokethrough(tap, &tir, &s, &hir);
479                                 } else {
480                                         printf("Shifting DR (%d bits)...\n", tdr.len + s.len + hdr.len);
481                                         nexys2_jtag_puttmstdi(tap->nexys, 3, capturedr, NULL);
482                                         pokethrough(tap, &tdr, &s, &hdr);
483                                 }
484                                 nexys2_jtag_puttmstdi(tap->nexys, 2, returnidle, NULL);
485                         }
486                         break;
487                 }
488                 case TOK_RUNTEST:
489                 {
490                         int n;
491                         char *loss;
492                         
493                         REQUIRENEXT; EXPECT(TOK_NUMBER);
494                         n = tlist->data.i;
495                         REQUIRENEXT; EXPECT(TOK_TCK);
496                         REQUIRENEXT; EXPECT(TOK_SEMICOLON);
497                         NEXT;
498                         
499                         loss = malloc(64);
500                         memset(loss, 0, 64);
501                         s3l_tap_idle(tap);
502                         
503                         printf("Going RTI for %d clocks...\n", n);
504                         
505                         while (n)
506                         {
507                                 int b = (n < 512) ? n : 512;
508                                 nexys2_jtag_puttdi(tap->nexys, 0, n, loss, NULL);
509                                 n -= b;
510                         }
511                         free(loss);
512                         
513                         break;
514                 }
515                 default:
516                         printf("Unknown top level token %d\n", tlist->token);
517                         abort();
518                 }
519         }
520 }
521
522 int main(int argc, char **argv)
523 {
524         tap_t tap;
525         token_t *tlist;
526         int fd;
527         
528         if (argc < 2)
529         {
530                 printf("usage: s3load <file.svf>\n");
531                 return 1;
532         }
533         if ((fd = open(argv[1], O_RDONLY)) < 0)
534         {
535                 perror("open");
536                 return 1;
537         }
538         tlist = tokenize(fd);
539         close(fd);
540         
541         
542         tap.tapstate = TAP_UNKNOWN;
543         tap.nexys = nexys2_init();
544         if (!tap.nexys)
545         {
546                 fprintf(stderr, "Board init failed :(\n");
547                 return 1;
548         }
549         
550         if (nexys2_jtag_enable(tap.nexys) < 0)
551                 return 1;
552         
553         runsvf(&tap, tlist);
554         
555         nexys2_jtag_disable(tap.nexys);
556         
557         return 0;
558 }
This page took 0.043326 seconds and 4 git commands to generate.