GPLv2
[s3load.git] / s3load.c
CommitLineData
de1916b0
JW
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
5ee943f9
JW
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
21enum 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
41typedef struct tap {
42 nexys2_t nexys;
43 int tapstate;
44} tap_t;
45
46int 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
53int 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
75enum 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
103typedef struct token {
104 int token;
105 union {
106 int i;
107 char *s;
108 } data;
109 struct token *next;
110} token_t;
111
112int 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
124token_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
251typedef 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 */
261void 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
274void 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
291void 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
341void 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
522int 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.061556 seconds and 4 git commands to generate.