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 14

Go to most recent revision | 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
   Copyright(C) 2008 Nathan Yawn
3
 
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
          entityname = (char *) malloc(strlen(token));
107
          if(entityname != NULL) strcpy(entityname, token);
108
          debug("Found entity \'%s\'\n", entityname);
109
        } else {
110
          printf("Parse error near ENTITY token in file %s\n", bsdlfilename);
111
        }
112
      }
113
      else if(!strcmp(strtoupper(token), "CONSTANT")) {
114
        // Parse a constant declaration...we ignore them, just get lines until we find a ';' char
115
        // assume nothing else useful comes on the line after the ';'
116
        // Slightly awkward, since we have to search the rest of the line after the strtok, then possible
117
        // new lines as well.
118
        token = strtok_r(NULL, " \t", &last);  // debug...don't worry about error, token only used in printf
119
        debug("Ignoring constant \'%s\'\n", token);  // debug
120
        while(strchr(last, ';') == NULL) {
121
          filepos = get_line(filedata, filepos, &last, filesize);
122
        }
123
      }
124
      else if(!strcmp(strtoupper(token), "GENERIC")) {
125
        // Parse a generic declaration...we ignore them, just get lines until we find a ';' char
126
        // assume nothing else useful comes on the line after the ';'
127
        // Slightly awkward, since we have to search the rest of the line after the strtok, then possible
128
        // new lines as well.
129
        token = strtok_r(NULL, " \t", &last);  // debug...don't worry about error, token only used in printf
130
        debug("Ignoring generic \'%s\'\n", token);  // debug
131
        while(strchr(last, ';') == NULL) {
132
          filepos = get_line(filedata, filepos, &last, filesize);
133
        }
134
      }
135
      else if(!strcmp(strtoupper(token), "USE")) {
136
        // Parse a 'use' declaration...we ignore them, just get lines until we find a ';' char
137
        // assume nothing else useful comes on the line after the ';'
138
        // Note that there may be no space after the token, so add ';' to the tokenizing list in the debug bits.
139
        // Slightly awkward, since we have to search the rest of the line after the strtok, then possible
140
        // new lines as well.
141
        token = strtok_r(NULL, " \t;", &last);  // debug ...don't worry about error, token only used in printf
142
        debug("Ignoring use \'%s\'\n", token);  // debug
143
        while(strchr(last, ';') == NULL) {
144
          filepos = get_line(filedata, filepos, &last, filesize);
145
        }
146
      }
147
      else if(!strcmp(strtoupper(token), "END")) {
148
        // We're done, whether we've found what we want or not.  Eject eject eject...
149
        debug("Found END token, stopping parser\n");
150
        break;
151
      }
152
      else if(!strcmp(strtoupper(token), "PORT")) {
153
        // Parse a port list.  Find a '(', find a ')', find a ';'.
154
        // Note that "()" pairs may occur in between.
155
        // 'last' must be set in the first two strchr() calls so that the next strchr() call will
156
        // begin parsing after the previous char position.  Otherwise, e.g. a ';' before the ')' but on the same
157
        // line would (incorrectly) satisfy the search.
158
        while((last = strchr(last, '(')) == NULL) {
159
          filepos = get_line(filedata, filepos, &last, filesize);
160
        }
161
        opens = 1;
162
        last++;  // don't leave 'last' pointing at the '(' char, since we're looking for another
163
 
164
        do {
165
          while((last = strchr_s(last, "()")) == NULL) {
166
            filepos = get_line(filedata, filepos, &last, filesize); // *** abort if new line is empty
167
          }
168
          if(*last == '(') opens++;
169
          else if(*last == ')') opens--;
170
          last++;  // don't leave last pointing at the same "()" char, since we're looking for another
171
        } while(opens);
172
 
173
 
174
        while(strchr(last, ';') == NULL) {
175
          filepos = get_line(filedata, filepos, &last, filesize);
176
        }
177
        debug("Ignored port statement\n");
178
      }
179
      else if(!strcmp(strtoupper(token), "ATTRIBUTE")) {
180
        // Parse an attribute
181
        token = strtok_r(NULL, " \t", &last);  // *** check for error
182
        if(!strcmp(strtoupper(token), "INSTRUCTION_LENGTH")) {
183
          // Find ':', then "entity", then "is", then take anything before the ';' as the value
184
          while((last = strchr(last, ':')) == NULL) {
185
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
186
          }
187
          while((last = strstr(last, "entity")) == NULL) { // don't do strtoupper() here, that would do the entire line
188
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
189
          }
190
          while((last = strstr(last, "is")) == NULL) {
191
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
192
          }
193
 
194
          // scan until the end of the line looking for data
195
          j = 0;
196
          done = 0;
197
          while(*last != '\0') {
198
            if(isdigit(*last)) tmpbuf[j++] = *last;
199
            else if(*last == ';') { done = 1; break;}
200
            last++;
201
          }
202
          // May need to go to additional lines
203
          while(!done) {
204
            filepos = get_line(filedata, filepos, &linedata, filesize);  // *** break if linedata has no data
205
            while(*linedata != '\0') {
206
              if(isdigit(*linedata)) tmpbuf[j++] = *linedata;
207
              else if(*linedata == ';') { done = 1; break;}
208
              linedata++;
209
            }
210
          }
211
 
212
          tmpbuf[j] = '\0';
213
          IR_size = strtoul(tmpbuf, NULL, 0);
214
          found_IR_size = 1;
215
          debug("Found IR size %i (%s)\n", IR_size, tmpbuf);
216
        }  // end if INSTRUCTION_LENGTH
217
 
218
        else if(!strcmp(strtoupper(token), "INSTRUCTION_OPCODE")) {
219
          // Find ": entity is"
220
          while((last = strchr(last, ':')) == NULL) {
221
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
222
          }
223
          while((last = strstr(last, "entity")) == NULL) { // don't do strtoupper() here, that would do the entire line
224
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
225
          }
226
          while((last = strstr(last, "is")) == NULL) {
227
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
228
          }
229
 
230
          // We're going to copy the entire attribute (all commands) into a temp. buffer.  We need a big enough buffer,
231
          // and we can't just scan for ';' to find out because there's a '\0' at the end of this line.
232
          // But, it can't be bigger than the entire rest of the file, so...
233
          cmdbuf = (char *) malloc(filesize-filepos);
234
          // Parse until ';', and grab everything between each pair of "" found
235
          // Note that 'last' still points at "is"
236
          j = 0;
237
          done = 0;
238
          valid = 0;
239
          while(*last != '\0') {
240
            if(*last == ';') { done = 1; break;}  // Put this first in case of badly formed BSDL files
241
            else if(valid && (*last != '\"')) cmdbuf[j++] = *last;
242
            else if(*last == '\"') valid = !valid;
243
            last++;
244
          }
245
          // May need to go to additional lines
246
          while(!done) {
247
            filepos = get_line(filedata, filepos, &linedata, filesize); // *** break if linedata has no data
248
            while(*linedata != '\0') {
249
              if(valid && (*linedata != '\"')) cmdbuf[j++] = *linedata;
250
              else if(*linedata == '\"') valid = !valid;
251
              else if(*linedata == ';') { done = 1; break;}
252
              linedata++;
253
            }
254
          }
255
          cmdbuf[j] = '\0';
256
 
257
          // Parse the opcodes attribute.  This is an exercise unto itself, so do it in another function.
258
          parse_opcodes(cmdbuf, &debug_cmd, &user1_cmd, &idcode_cmd);
259
          found_cmds = 1;
260
          free(cmdbuf);
261
 
262
        }   // end if INSTRUCTION_OPCODE
263
 
264
        else if(!strcmp(strtoupper(token), "IDCODE_REGISTER")) {
265
          // Find : entity is
266
          while((last = strchr(last, ':')) == NULL) {
267
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
268
          }
269
          while((last = strstr(last, "entity")) == NULL) { // don't do strtoupper() here, that would do the entire line
270
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
271
          }
272
          while((last = strstr(last, "is")) == NULL) {
273
            filepos = get_line(filedata, filepos, &last, filesize); // *** check last actually has data?
274
          }
275
 
276
          // Parse until ';', and grab everything between each pair of "" found
277
          // Note that 'last' still points at "is"
278
          j = 0;
279
          done = 0;
280
          valid = 0;
281
          while(*last != '\0') {
282
            if(*last == ';') { done = 1; break;}  // Put this first in case of badly formed BSDL files
283
            else if(valid && (*last != '\"')) tmpbuf[j++] = *last;
284
            else if(*last == '\"') valid = !valid;
285
            last++;
286
          }
287
          // May need to go to additional lines
288
          while(!done) {
289
            filepos = get_line(filedata, filepos, &linedata, filesize); // *** break if linedata has no data
290
            while(*linedata != '\0') {
291
              if(valid && (*linedata != '\"')) tmpbuf[j++] = *linedata;
292
              else if(*linedata == '\"') valid = !valid;
293
              else if(*linedata == ';') { done = 1; break;}
294
              linedata++;
295
            }
296
          }
297
          tmpbuf[j] = '\0';
298
 
299
          // Parse the tmpbuf
300
          if(j != 32) printf("Warning:  found %i chars (expected 32) while getting IDCODE in BSDL file %s.\n", j, bsdlfilename);  // Sanity check
301
          debug("Got IDCODE string \'%s\'\n", tmpbuf);
302
          for(i = 0; i < j; i++) {
303
            if(tmpbuf[i] == '1') idcode |= 0x1<<(31-i);
304
            else if(toupper(tmpbuf[i]) == 'X') idcode_mask &= ~(0x1<<(31-i));
305
          }
306
          debug("Found IDCODE 0x%08X (%s), mask is 0x%08X\n", idcode, tmpbuf, idcode_mask);
307
          found_idcode = 1;
308
 
309
        }  // end if IDCODE_REGISTER
310
 
311
        else {
312
          debug("Ignoring attribute \'%s\'\n", token);
313
          // Consume chars until ';' found
314
          while(strchr(last, ';') == NULL) {
315
            filepos = get_line(filedata, filepos, &last, filesize);
316
          }
317
        }
318
      }
319
      else {
320
        debug("Unknown token \'%s\' found in BSDL file %s\n", token, bsdlfilename);
321
      }
322
    }
323
 
324
  free(filedata);
325
 
326
  // Put the data in a struct for return and storage
327
  ret = (bsdlinfo *) malloc(sizeof(bsdlinfo));
328
  if(ret == NULL) {
329
       printf("Error: out of memory, unable to store BSDL info for file %s\n", bsdlfilename);
330
       return NULL;
331
  }
332
 
333
  ret->name = entityname;  // this was malloc'd, so it's persistant, this is safe
334
  ret->idcode = idcode;
335
  ret->idcode_mask = idcode_mask;
336
  ret->IR_size = IR_size;
337
  ret->cmd_debug = debug_cmd;
338
  ret->cmd_user1 = user1_cmd;
339
  ret->cmd_idcode = idcode_cmd;
340
  ret->next = NULL;
341
 
342
  return ret;
343
}
344
 
345
 
346
 
347
//////////////////////////////////////////////////////////////////////////////////////////////
348
// Local / helper functions
349
 
350
 
351
// Returns 1 line from a complete file buffer pointed to by *filedata.  Removes leading
352
// whitespace, ignores comment lines, removes trailing comments (comments denoted by "--")
353
// startpos: index in filedata[] to start looking for a new line.
354
// linedata:  set to point to the first char of the new line.
355
// filesize:  used so we don't go past the end of filedata[]
356
// The return value is the first index after the returned line.  This may be 1 past the end of the buffer.
357
int get_line(char *filedata, int startpos, char **linedata, int filesize)
358
{
359
  int lineidx = startpos;
360
  unsigned char loop;
361
  char *commentptr;
362
 
363
  do {
364
    loop = 0;
365
    while(isspace(filedata[lineidx]) && (lineidx < filesize)) lineidx++;  // burn leading whitespace chars
366
 
367
    if(lineidx >= (filesize-1)) { // We look at the data at lineidx and lineidx+1...don't look at invalid offsets. 
368
      lineidx = filesize-1;
369
      break;
370
    }
371
 
372
    if((filedata[lineidx] == '-') && (filedata[lineidx+1] == '-'))
373
      {  // then this is a full-line comment, with no useful data
374
        while(((filedata[lineidx] != '\n') && (filedata[lineidx] != '\r')) && (lineidx < filesize))
375
          lineidx++;  // burn comment line up to CR/LF
376
        loop = 1;
377
      }
378
  } while(loop);
379
 
380
  // Set the line pointer
381
  *linedata = &filedata[lineidx];
382
 
383
  // Put a NULL char at the newline
384
  while(!iscntrl(filedata[lineidx]) && (lineidx < filesize)) lineidx++;
385
  if(lineidx >= filesize) { // Don't write past the end of the array.
386
    lineidx = filesize-1;
387
  }
388
  filedata[lineidx] = '\0';
389
 
390
  // Put a NULL at the first "--" string, if any
391
  commentptr = strstr(*linedata, "--");
392
  if(commentptr != NULL) *commentptr = '\0';
393
 
394
  return lineidx+1;
395
}
396
 
397
 
398
// In-place string capitalizer
399
char * strtoupper(char *str)
400
{
401
  int i = 0;
402
 
403
  while(str[i] != '\0') {
404
    str[i] = toupper(str[i]);
405
    i++;
406
  }
407
 
408
  return str;
409
}
410
 
411
// Searches a string 'str' for the first occurance of any 
412
// character in the string 'chars'.  Returns a pointer to
413
// the char in 'str' if one is found, returns NULL if
414
// none of the chars in 'chars' are present in 'str'.
415
char * strchr_s(char *str, char *chars)
416
{
417
  int slen = strlen(chars);
418
  char *ptr = str;
419
  int i;
420
 
421
  while(*ptr != '\0') {
422
    for(i = 0; i < slen; i++) {
423
      if(*ptr == chars[i])
424
        return ptr;
425
    }
426
    ptr++;
427
  }
428
 
429
  return NULL;
430
}
431
 
432
 
433
// Parses a string with command name / opcode pairs of the format
434
// EXTEST    (1111000000),SAMPLE    (1111000001), [...]
435
// There may or may not be a space between the name and the open paren.
436
// We do not assume a comma after the last close paren.
437
#define TARGET_DEBUG  1
438
#define TARGET_USER1  2
439
#define TARGET_IDCODE 3
440
void parse_opcodes(char *cmdbuf, uint32_t *debug_cmd, uint32_t *user1_cmd, uint32_t *idcode_cmd)
441
{
442 14 nyawn
  char *saveptr = NULL;
443 4 nyawn
  char *cmd;
444
  char *token;
445
  char *saveptr2;
446
  int target;
447
  int opcode;
448
 
449
  cmd = strtok_r(cmdbuf, ",", &saveptr);
450
  while(cmd != NULL)
451
    {
452
      // 'cmd' should now have one pair in the form "EXTEST    (1111000000)"
453
      target = 0;
454
      token = strtok_r(cmd, " \t(", &saveptr2);
455
      if(!strcmp(strtoupper(token), "DEBUG")) {
456
        target = TARGET_DEBUG;
457
        debug("Found DEBUG opcode: ");
458
      }
459
      else if(!strcmp(strtoupper(token), "USER1")) {
460
        target = TARGET_USER1;
461
        debug("Found USER1 opcode:");
462
      }
463
      else if(!strcmp(strtoupper(token), "IDCODE")) {
464
        target = TARGET_IDCODE;
465
        debug("Found IDCODE opcode: ");
466
      }
467
 
468
      if(target) {  // don't parse opcode number unless necessary
469
        token = strtok_r(NULL, " \t()", &saveptr2);
470
        if(token != NULL) {
471
          opcode = strtoul(token, NULL, 2); // *** Test for errors
472
          debug("0x%X (%s)\n", opcode, token);
473
 
474
          if(target == TARGET_DEBUG) *debug_cmd = opcode;
475
          else if(target == TARGET_USER1) *user1_cmd = opcode;
476
          else if(target == TARGET_IDCODE) *idcode_cmd = opcode;
477
        }
478
        else {
479
          printf("Error:  failed to find opcode value after identifier.\n");
480
        }
481
      }
482
 
483
      cmd = strtok_r(NULL,  ",", &saveptr);
484
    }
485
 
486
 
487
}

powered by: WebSVN 2.1.0

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