2 * Main program for s3load
3 * s3load, a free SVF loader for Digilent NEXYS2 boards
5 * Copyright (c) 2007-2008 Joshua Wise
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.
11 * Commercial licenses are available by request.
46 int s3l_tap_reset(tap_t *tap)
48 unsigned char reset[] = {0xAA, 0x02};
49 tap->tapstate = TAP_RESET;
50 return nexys2_jtag_puttmstdi(tap->nexys, 5, reset, NULL);
53 int s3l_tap_idle(tap_t *tap)
55 switch (tap->tapstate)
58 printf("Resetting TAP from unknown state...\n");
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);
70 printf("cannot transition to idle from %d\n", tap->tapstate);
103 typedef struct token {
114 if (c >= '0' && c <= '9')
116 if (c >= 'a' && c <= 'f')
118 if (c >= 'A' && c <= 'F')
120 printf("Bad hex nybble %c\n", c);
124 token_t *tokenize(int fd)
126 /* First off, suck in ALL of the file */
127 char *f = NULL, *fst;
129 token_t *start = NULL, *cur = NULL;
134 f = realloc(f, sz + 16385);
135 if ((rsz = read(fd, &(f[sz]), 16384)) < 16384)
147 if (!strncmp(f, "//", 2))
149 // Comment, eat the rest of the line
151 if (f && f[1] == '\r')
155 } else if (*f == '\n' || *f == '\r' || *f == '\t' || *f == ' ')
160 start = cur = malloc(sizeof(*cur)); \
161 start->next = NULL; \
163 cur->next = malloc(sizeof(*cur)); \
167 #define MATCHSTRING(str, tok) \
168 if (!strncmp(f, str, strlen(str))) { \
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)) {
198 cur->token = TOK_NUMBER;
199 cur->data.i = *f - '0';
204 cur->data.i += *f - '0';
207 } else if (*f == '(') {
211 cur->token = TOK_BITSTRING;
214 while (*f && *f != ')')
217 while (isspace(*f) && *f && *f != ')')
219 if (!*f || *f == ')')
223 while (isspace(*f) && *f && *f != ')')
225 if (!*f || *f == ')')
227 printf("Unpaired hex digit in bitstring\n");
235 cur->data.s = realloc(cur->data.s, asz);
237 cur->data.s[l++] = hex2nyb(c1) << 4 | hex2nyb(c2);
241 printf("Tokenizing error, unhandled: %s\n", f);
251 typedef struct blitval {
253 char *tdi, *tdo, *mask, *smask;
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 | ...
261 void bitcopy(int len, unsigned char *inbits, int inpos, int indir, unsigned char *outbits, int outpos, int outdir)
264 if (!inbits || !outbits)
266 for (i = 0; i < len; i++)
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;
274 void printprog(int done, int total)
277 int progresscounter = done * 32 / total;
278 static int spinnerstate;
279 char *spinner = "_.oOo.";
282 for (i=0; i < progresscounter; i++)
284 if (progresscounter != 32)
286 for (i=0; i < (31 - progresscounter); i++)
288 printf("] %c %d/%d", spinner[(spinnerstate++) % 6], done, total);
291 void pokethrough(tap_t *tap, blitval_t *tbv, blitval_t *sbv, blitval_t *hbv)
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
305 printf("t:%d, s:%d, h:%d\n", tbv->len, sbv->len, hbv->len);
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);
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;
323 for (txp = 0; txp < totlen; txp += 0x8000)
325 int len = (((txp + 0x8000) > totlen) ? totlen : (txp + 0x8000)) - txp;
326 printf("Shifting: "); printprog(txp + len, totlen); printf("\r");
328 nexys2_jtag_puttmstdi(tap->nexys, len, inb + ((txp * 2) / 8), needout ? (outb + (txp / 8)) : NULL);
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]);
341 void runsvf(tap_t *tap, token_t *tlist)
344 int endir = TOK_IDLE, enddr = TOK_IDLE;
345 blitval_t tir, tdr, hir, hdr;
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) \
357 printf("Expected " #tok ", got %d\n", tok); \
363 switch (tlist->token)
366 REQUIRENEXT; EXPECT(TOK_OFF);
368 REQUIRENEXT; EXPECT(TOK_SEMICOLON);
372 REQUIRENEXT; EXPECT(TOK_IDLE);
374 REQUIRENEXT; EXPECT(TOK_SEMICOLON);
378 REQUIRENEXT; EXPECT(TOK_IDLE);
380 REQUIRENEXT; EXPECT(TOK_SEMICOLON);
385 printf("Changing state...\n");
386 if (tlist->token == TOK_RESET)
388 else if (tlist->token == TOK_IDLE)
391 printf("Unknown token after TOK_STATE\n");
394 REQUIRENEXT; EXPECT(TOK_SEMICOLON);
398 REQUIRENEXT; EXPECT(TOK_1E6);
399 REQUIRENEXT; EXPECT(TOK_HZ);
400 REQUIRENEXT; EXPECT(TOK_SEMICOLON);
410 int oldtok = tlist->token;
414 if (oldtok == TOK_TIR)
416 else if (oldtok == TOK_HIR)
418 else if (oldtok == TOK_TDR)
420 else if (oldtok == TOK_HDR)
425 REQUIRENEXT; EXPECT(TOK_NUMBER);
426 bv->len = tlist->data.i;
433 while (tlist->token != TOK_SEMICOLON)
435 switch (tlist->token)
438 REQUIRENEXT; EXPECT(TOK_BITSTRING);
439 bv->tdi = tlist->data.s;
443 REQUIRENEXT; EXPECT(TOK_BITSTRING);
444 bv->tdo = tlist->data.s;
448 REQUIRENEXT; EXPECT(TOK_BITSTRING);
449 bv->mask = tlist->data.s;
453 REQUIRENEXT; EXPECT(TOK_BITSTRING);
454 bv->smask = tlist->data.s;
461 EXPECT(TOK_SEMICOLON);
464 if (oldtok == TOK_SIR || oldtok == TOK_SDR)
466 char *capturedr = "\x02";
467 char *captureir = "\x0A";
468 char *returnidle = "\x02";
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 */
474 if (oldtok == TOK_SIR)
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);
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);
484 nexys2_jtag_puttmstdi(tap->nexys, 2, returnidle, NULL);
493 REQUIRENEXT; EXPECT(TOK_NUMBER);
495 REQUIRENEXT; EXPECT(TOK_TCK);
496 REQUIRENEXT; EXPECT(TOK_SEMICOLON);
503 printf("Going RTI for %d clocks...\n", n);
507 int b = (n < 512) ? n : 512;
508 nexys2_jtag_puttdi(tap->nexys, 0, n, loss, NULL);
516 printf("Unknown top level token %d\n", tlist->token);
522 int main(int argc, char **argv)
530 printf("usage: s3load <file.svf>\n");
533 if ((fd = open(argv[1], O_RDONLY)) < 0)
538 tlist = tokenize(fd);
542 tap.tapstate = TAP_UNKNOWN;
543 tap.nexys = nexys2_init();
546 fprintf(stderr, "Board init failed :(\n");
550 if (nexys2_jtag_enable(tap.nexys) < 0)
555 nexys2_jtag_disable(tap.nexys);