OpenCores
URL https://opencores.org/ocsvn/adv_debug_sys/adv_debug_sys/trunk

Subversion Repositories adv_debug_sys

[/] [adv_debug_sys/] [trunk/] [Software/] [adv_jtag_bridge/] [bsdl_parse.c] - Blame information for rev 57

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 nyawn
/* bsdl_parse.c - BSDL parser for the advanced JTAG bridge
2 32 nyawn
   Copyright(C) 2008 - 2010 Nathan Yawn
3 4 nyawn
 
4
   This program is free software; you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; either version 2 of the License, or
7
   (at your option) any later version.
8
 
9
   This program is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
 
14
   You should have received a copy of the GNU General Public License
15
   along with this program; if not, write to the Free Software
16
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
*/
18
 
19
#include <stdio.h>
20
#include <string.h>
21
#include <ctype.h>  // isspace(), etc.
22
#include <stdlib.h>  // malloc(), strtoul(), etc.
23
#include "bsdl.h"  // has constants
24
 
25
 
26
#define debug(...) //fprintf(stderr, __VA_ARGS__ )
27
 
28
char * strtoupper(char *str);
29
int get_line(char *filedata, int startpos, char **linedata, int filesize);
30
char * strchr_s(char *str, char *chars);
31
void parse_opcodes(char *cmdbuf, uint32_t *debug_cmd, uint32_t *user1_cmd, uint32_t *idcode_cmd);
32
 
33
// We assume that no value will be more than 128 chars
34
char tmpbuf[128];
35
 
36
 
37
 /////////////////////////////////////////////////////////////////
38
 // API call: extract desired info from 1 BSDL fise
39
 
40
bsdlinfo *parse_extract_values(char *bsdlfilename)
41
{
42
  FILE *fd;
43
  int filesize;
44
  bsdlinfo *ret;
45
  char *filedata;
46
  char *linedata;
47
  char *token;
48
  char *last;
49
  char *cmdbuf;
50
  int filepos = 0;
51
  int i,j;
52
  char done,valid,opens;
53
 
54
  int IR_size = -1;
55
  uint8_t found_IR_size = 0;
56
  uint32_t debug_cmd = TAP_CMD_INVALID;
57
  uint32_t user1_cmd = TAP_CMD_INVALID;
58
  uint32_t idcode_cmd = TAP_CMD_INVALID;
59
  uint8_t found_cmds = 0;
60
  uint32_t idcode = 0;
61
  uint32_t idcode_mask = 0xFFFFFFFF;  // 'X' is a valid char in an IDCODE, set 0's here for X's.
62
  uint8_t found_idcode = 0;
63
  char *entityname = NULL;
64
 
65
  // Open the file
66
  fd = fopen(bsdlfilename, "r");
67
  if(fd == NULL) {
68
    printf("ERROR:  failed to open BSDL file %s\n", bsdlfilename);
69
    return NULL;
70
  }
71
 
72
  fseek(fd, 0, SEEK_END);
73
  filesize = ftell(fd);
74
  fseek(fd, 0, SEEK_SET);
75
 
76
  filedata = (char *) malloc(filesize);
77
  if(filedata == NULL) {
78
    printf("ERROR: failed to allocate memory for BSDL file %s\n", bsdlfilename);
79
    return NULL;
80
  }
81
 
82
  if(fread(filedata, 1, filesize, fd) < filesize) {  // 1 long read will be faster than many short ones
83
    printf("Warning: failed to read entire BSDL file %s\n", bsdlfilename);
84
  }
85
 
86
  fclose(fd);
87
 
88
 
89
  // while there's more data and not all values have been found
90
  while((filepos < filesize) && (!found_IR_size || !found_cmds || !found_idcode))
91
    {
92
      // Get a line.  Replace any "--" with a \0 char
93
      filepos = get_line(filedata, filepos, &linedata, filesize);
94
 
95
      // look for each value
96
      token = strtok_r(linedata, " \t", &last);
97
      if(token == NULL) {
98
        printf("ERROR: End of file reached before END statement is BSDL file \'%s\'\n", bsdlfilename);
99
        break;
100
      }
101
 
102
      if(!strcmp(strtoupper(token), "ENTITY")) {
103
        // Parse an entity line
104
        token = strtok_r(NULL, " \t", &last);
105
        if(token != NULL) {
106 57 nyawn
          entityname = strdup(token);
107
          if(entityname != NULL)
108
            {
109
              debug("Found entity \'%s\'\n", entityname);
110
            }
111 4 nyawn
        } else {
112
          printf("Parse error near ENTITY token in file %s\n", bsdlfilename);
113
        }
114
      }
115
      else if(!strcmp(strtoupper(token), "CONSTANT")) {
116
        // Parse a constant declaration...we ignore them, just get lines until we find a ';' char
117
        // assume nothing else useful comes on the line after the ';'
118
        // Slightly awkward, since we have to search the rest of the line after the strtok, then possible
119
        // new lines as well.
120
        token = strtok_r(NULL, " \t", &last);  // debug...don't worry about error, token only used in printf
121
        debug("Ignoring constant \'%s\'\n", token);  // debug
122
        while(strchr(last, ';') == NULL) {
123
          filepos = get_line(filedata, filepos, &last, filesize);
124
        }
125
      }
126
      else if(!strcmp(strtoupper(token), "GENERIC")) {
127
        // Parse a generic declaration...we ignore them, just get lines until we find a ';' char
128
        // assume nothing else useful comes on the line after the ';'
129
        // Slightly awkward, since we have to search the rest of the line after the strtok, then possible
130
        // new lines as well.
131
        token = strtok_r(NULL, " \t", &last);  // debug...don't worry about error, token only used in printf
132
        debug("Ignoring generic \'%s\'\n", token);  // debug
133
        while(strchr(last, ';') == NULL) {
134
          filepos = get_line(filedata, filepos, &last, filesize);
135
        }
136
      }
137
      else if(!strcmp(strtoupper(token), "USE")) {
138
        // Parse a 'use' declaration...we ignore them, just get lines until we find a ';' char
139
        // assume nothing else useful comes on the line after the ';'
140
        // Note that there may be no space after the token, so add ';' to the tokenizing list in the debug bits.
141
        // Slightly awkward, since we have to search the rest of the line after the strtok, then possible
142
        // new lines as well.
143
        token = strtok_r(NULL, " \t;", &last);  // debug ...don't worry about error, token only used in printf
144
        debug("Ignoring use \'%s\'\n", token);  // debug
145
        while(strchr(last, ';') == NULL) {
146
          filepos = get_line(filedata, filepos, &last, filesize);
147
        }
148
      }
149
      else if(!strcmp(strtoupper(token), "END")) {
150
        // We're done, whether we've found what we want or not.  Eject eject eject...
151
        debug("Found END token, stopping parser\n");
152
        break;
153
      }
154
      else if(!strcmp(strtoupper(token), "PORT")) {
155
        // Parse a port list.  Find a '(', find a ')', find a ';'.
156
        // Note that "()" pairs may occur in between.
157
        // 'last' must be set in the first two strchr() calls so that the next strchr() call will
158
        // begin parsing after the previous char position.  Otherwise, e.g. a ';' before the ')' but on the same
159
        // line would (incorrectly) satisfy the search.
160
        while((last = strchr(last, '(')) == NULL) {
161
          filepos = get_line(filedata, filepos, &last, filesize);
162
        }
163
        opens = 1;
164
        last++;  // don't leave 'last' pointing at the '(' char, since we're looking for another
165
 
166
        do {
167
          while((last = strchr_s(last, "()")) == NULL) {
168
            filepos = get_line(filedata, filepos, &last, filesize); // *** abort if new line is empty
169
          }
170
          if(*last == '(') opens++;
171
          else if(*last == ')') opens--;
172
          last++;  // don't leave last pointing at the same "()" char, since we're looking for another
173
        } while(opens);
174
 
175
 
176
        while(strchr(last, ';') == NULL) {
177
          filepos = get_line(filedata, filepos, &last, filesize);
178
        }
179
        debug("Ignored port statement\n");
180
      }
181
      else if(!strcmp(strtoupper(token), "ATTRIBUTE")) {
182
        // Parse an attribute
183
        token = strtok_r(NULL, " \t", &last);  // *** check for error
184
        if(!strcmp(strtoupper(token), "INSTRUCTION_LENGTH")) {
185
          // Find ':', then "entity", then "is", then take anything before the ';' as the value
186
          while((last = strchr(last, ':')) == NULL) {
187
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
188
          }
189
          while((last = strstr(last, "entity")) == NULL) { // don't do strtoupper() here, that would do the entire line
190
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
191
          }
192
          while((last = strstr(last, "is")) == NULL) {
193
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
194
          }
195
 
196
          // scan until the end of the line looking for data
197
          j = 0;
198
          done = 0;
199
          while(*last != '\0') {
200
            if(isdigit(*last)) tmpbuf[j++] = *last;
201
            else if(*last == ';') { done = 1; break;}
202
            last++;
203
          }
204
          // May need to go to additional lines
205
          while(!done) {
206
            filepos = get_line(filedata, filepos, &linedata, filesize);  // *** break if linedata has no data
207
            while(*linedata != '\0') {
208
              if(isdigit(*linedata)) tmpbuf[j++] = *linedata;
209
              else if(*linedata == ';') { done = 1; break;}
210
              linedata++;
211
            }
212
          }
213
 
214
          tmpbuf[j] = '\0';
215
          IR_size = strtoul(tmpbuf, NULL, 0);
216
          found_IR_size = 1;
217
          debug("Found IR size %i (%s)\n", IR_size, tmpbuf);
218
        }  // end if INSTRUCTION_LENGTH
219
 
220
        else if(!strcmp(strtoupper(token), "INSTRUCTION_OPCODE")) {
221
          // Find ": entity is"
222
          while((last = strchr(last, ':')) == NULL) {
223
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
224
          }
225
          while((last = strstr(last, "entity")) == NULL) { // don't do strtoupper() here, that would do the entire line
226
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
227
          }
228
          while((last = strstr(last, "is")) == NULL) {
229
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
230
          }
231
 
232
          // We're going to copy the entire attribute (all commands) into a temp. buffer.  We need a big enough buffer,
233
          // and we can't just scan for ';' to find out because there's a '\0' at the end of this line.
234
          // But, it can't be bigger than the entire rest of the file, so...
235
          cmdbuf = (char *) malloc(filesize-filepos);
236 57 nyawn
          debug("Malloc'd %i bytes for INSTRUCTION_OPCODE\n", filesize-filepos);
237
 
238 4 nyawn
          // Parse until ';', and grab everything between each pair of "" found
239
          // Note that 'last' still points at "is"
240
          j = 0;
241
          done = 0;
242
          valid = 0;
243
          while(*last != '\0') {
244
            if(*last == ';') { done = 1; break;}  // Put this first in case of badly formed BSDL files
245
            else if(valid && (*last != '\"')) cmdbuf[j++] = *last;
246
            else if(*last == '\"') valid = !valid;
247
            last++;
248
          }
249
          // May need to go to additional lines
250
          while(!done) {
251
            filepos = get_line(filedata, filepos, &linedata, filesize); // *** break if linedata has no data
252
            while(*linedata != '\0') {
253
              if(valid && (*linedata != '\"')) cmdbuf[j++] = *linedata;
254
              else if(*linedata == '\"') valid = !valid;
255
              else if(*linedata == ';') { done = 1; break;}
256
              linedata++;
257
            }
258
          }
259
          cmdbuf[j] = '\0';
260 57 nyawn
          debug("Finished copying INSTRUCTION_OPCODE, copied %i bytes", j+1);
261 4 nyawn
 
262
          // Parse the opcodes attribute.  This is an exercise unto itself, so do it in another function.
263
          parse_opcodes(cmdbuf, &debug_cmd, &user1_cmd, &idcode_cmd);
264
          found_cmds = 1;
265
          free(cmdbuf);
266
 
267
        }   // end if INSTRUCTION_OPCODE
268
 
269
        else if(!strcmp(strtoupper(token), "IDCODE_REGISTER")) {
270
          // Find : entity is
271
          while((last = strchr(last, ':')) == NULL) {
272
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
273
          }
274
          while((last = strstr(last, "entity")) == NULL) { // don't do strtoupper() here, that would do the entire line
275
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
276
          }
277
          while((last = strstr(last, "is")) == NULL) {
278
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
279
          }
280
 
281
          // Parse until ';', and grab everything between each pair of "" found
282
          // Note that 'last' still points at "is"
283
          j = 0;
284
          done = 0;
285
          valid = 0;
286
          while(*last != '\0') {
287
            if(*last == ';') { done = 1; break;}  // Put this first in case of badly formed BSDL files
288
            else if(valid && (*last != '\"')) tmpbuf[j++] = *last;
289
            else if(*last == '\"') valid = !valid;
290
            last++;
291
          }
292
          // May need to go to additional lines
293
          while(!done) {
294
            filepos = get_line(filedata, filepos, &linedata, filesize); // *** break if linedata has no data
295
            while(*linedata != '\0') {
296
              if(valid && (*linedata != '\"')) tmpbuf[j++] = *linedata;
297
              else if(*linedata == '\"') valid = !valid;
298
              else if(*linedata == ';') { done = 1; break;}
299
              linedata++;
300
            }
301
          }
302
          tmpbuf[j] = '\0';
303
 
304
          // Parse the tmpbuf
305
          if(j != 32) printf("Warning:  found %i chars (expected 32) while getting IDCODE in BSDL file %s.\n", j, bsdlfilename);  // Sanity check
306
          debug("Got IDCODE string \'%s\'\n", tmpbuf);
307
          for(i = 0; i < j; i++) {
308
            if(tmpbuf[i] == '1') idcode |= 0x1<<(31-i);
309
            else if(toupper(tmpbuf[i]) == 'X') idcode_mask &= ~(0x1<<(31-i));
310
          }
311
          debug("Found IDCODE 0x%08X (%s), mask is 0x%08X\n", idcode, tmpbuf, idcode_mask);
312
          found_idcode = 1;
313
 
314
        }  // end if IDCODE_REGISTER
315
 
316
        else {
317
          debug("Ignoring attribute \'%s\'\n", token);
318
          // Consume chars until ';' found
319
          while(strchr(last, ';') == NULL) {
320
            filepos = get_line(filedata, filepos, &last, filesize);
321
          }
322
        }
323
      }
324
      else {
325
        debug("Unknown token \'%s\' found in BSDL file %s\n", token, bsdlfilename);
326
      }
327
    }
328
 
329
  free(filedata);
330
 
331
  // Put the data in a struct for return and storage
332
  ret = (bsdlinfo *) malloc(sizeof(bsdlinfo));
333
  if(ret == NULL) {
334
       printf("Error: out of memory, unable to store BSDL info for file %s\n", bsdlfilename);
335
       return NULL;
336
  }
337
 
338
  ret->name = entityname;  // this was malloc'd, so it's persistant, this is safe
339
  ret->idcode = idcode;
340
  ret->idcode_mask = idcode_mask;
341
  ret->IR_size = IR_size;
342
  ret->cmd_debug = debug_cmd;
343
  ret->cmd_user1 = user1_cmd;
344
  ret->cmd_idcode = idcode_cmd;
345
  ret->next = NULL;
346
 
347
  return ret;
348
}
349
 
350
 
351
 
352
//////////////////////////////////////////////////////////////////////////////////////////////
353
// Local / helper functions
354
 
355
 
356
// Returns 1 line from a complete file buffer pointed to by *filedata.  Removes leading
357
// whitespace, ignores comment lines, removes trailing comments (comments denoted by "--")
358
// startpos: index in filedata[] to start looking for a new line.
359
// linedata:  set to point to the first char of the new line.
360
// filesize:  used so we don't go past the end of filedata[]
361
// The return value is the first index after the returned line.  This may be 1 past the end of the buffer.
362
int get_line(char *filedata, int startpos, char **linedata, int filesize)
363
{
364
  int lineidx = startpos;
365
  unsigned char loop;
366
  char *commentptr;
367
 
368
  do {
369
    loop = 0;
370
    while(isspace(filedata[lineidx]) && (lineidx < filesize)) lineidx++;  // burn leading whitespace chars
371
 
372
    if(lineidx >= (filesize-1)) { // We look at the data at lineidx and lineidx+1...don't look at invalid offsets. 
373
      lineidx = filesize-1;
374
      break;
375
    }
376
 
377
    if((filedata[lineidx] == '-') && (filedata[lineidx+1] == '-'))
378
      {  // then this is a full-line comment, with no useful data
379
        while(((filedata[lineidx] != '\n') && (filedata[lineidx] != '\r')) && (lineidx < filesize))
380
          lineidx++;  // burn comment line up to CR/LF
381
        loop = 1;
382
      }
383
  } while(loop);
384
 
385
  // Set the line pointer
386
  *linedata = &filedata[lineidx];
387
 
388
  // Put a NULL char at the newline
389
  while(!iscntrl(filedata[lineidx]) && (lineidx < filesize)) lineidx++;
390
  if(lineidx >= filesize) { // Don't write past the end of the array.
391
    lineidx = filesize-1;
392
  }
393
  filedata[lineidx] = '\0';
394
 
395
  // Put a NULL at the first "--" string, if any
396
  commentptr = strstr(*linedata, "--");
397
  if(commentptr != NULL) *commentptr = '\0';
398
 
399
  return lineidx+1;
400
}
401
 
402
 
403
// In-place string capitalizer
404
char * strtoupper(char *str)
405
{
406
  int i = 0;
407
 
408
  while(str[i] != '\0') {
409
    str[i] = toupper(str[i]);
410
    i++;
411
  }
412
 
413
  return str;
414
}
415
 
416
// Searches a string 'str' for the first occurance of any 
417
// character in the string 'chars'.  Returns a pointer to
418
// the char in 'str' if one is found, returns NULL if
419
// none of the chars in 'chars' are present in 'str'.
420
char * strchr_s(char *str, char *chars)
421
{
422
  int slen = strlen(chars);
423
  char *ptr = str;
424
  int i;
425
 
426
  while(*ptr != '\0') {
427
    for(i = 0; i < slen; i++) {
428
      if(*ptr == chars[i])
429
        return ptr;
430
    }
431
    ptr++;
432
  }
433
 
434
  return NULL;
435
}
436
 
437
 
438
// Parses a string with command name / opcode pairs of the format
439
// EXTEST    (1111000000),SAMPLE    (1111000001), [...]
440
// There may or may not be a space between the name and the open paren.
441
// We do not assume a comma after the last close paren.
442
#define TARGET_DEBUG  1
443
#define TARGET_USER1  2
444
#define TARGET_IDCODE 3
445
void parse_opcodes(char *cmdbuf, uint32_t *debug_cmd, uint32_t *user1_cmd, uint32_t *idcode_cmd)
446
{
447 14 nyawn
  char *saveptr = NULL;
448 4 nyawn
  char *cmd;
449
  char *token;
450
  char *saveptr2;
451
  int target;
452
  int opcode;
453
 
454
  cmd = strtok_r(cmdbuf, ",", &saveptr);
455
  while(cmd != NULL)
456
    {
457
      // 'cmd' should now have one pair in the form "EXTEST    (1111000000)"
458
      target = 0;
459
      token = strtok_r(cmd, " \t(", &saveptr2);
460
      if(!strcmp(strtoupper(token), "DEBUG")) {
461
        target = TARGET_DEBUG;
462
        debug("Found DEBUG opcode: ");
463
      }
464
      else if(!strcmp(strtoupper(token), "USER1")) {
465
        target = TARGET_USER1;
466
        debug("Found USER1 opcode:");
467
      }
468
      else if(!strcmp(strtoupper(token), "IDCODE")) {
469
        target = TARGET_IDCODE;
470
        debug("Found IDCODE opcode: ");
471
      }
472
 
473
      if(target) {  // don't parse opcode number unless necessary
474
        token = strtok_r(NULL, " \t()", &saveptr2);
475
        if(token != NULL) {
476
          opcode = strtoul(token, NULL, 2); // *** Test for errors
477
          debug("0x%X (%s)\n", opcode, token);
478
 
479
          if(target == TARGET_DEBUG) *debug_cmd = opcode;
480
          else if(target == TARGET_USER1) *user1_cmd = opcode;
481
          else if(target == TARGET_IDCODE) *idcode_cmd = opcode;
482
        }
483
        else {
484
          printf("Error:  failed to find opcode value after identifier.\n");
485
        }
486
      }
487
 
488
      cmd = strtok_r(NULL,  ",", &saveptr);
489
    }
490
 
491
 
492
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.