1 /* Jedec .jed file parser
2
3 Copyright (C) Uwe Bonnes 2009 bon@elektron.ikp.physik.tu-darmstadt.de
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18 /*
19 * Using a slightly corrected version from IPAL libjedec
20 * Copyright (c) 2000 Stephen Williams (steve@icarus.com)
21 */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <strings.h>
26 #include <errno.h>
27 #include <cstdio>
28 #include <time.h>
29
30 #include "jedecfile.h"
31 #include "io_exception.h"
32
allocate_fusemap(unsigned size)33 static unsigned char*allocate_fusemap(unsigned size)
34 {
35 unsigned char*ptr = (unsigned char*) calloc(size/8 + ((size%8)?1:0), 1);
36 return ptr;
37 }
38
jedec_get_fuse(jedec_data_t jed,unsigned idx)39 int jedec_get_fuse(jedec_data_t jed, unsigned idx)
40 {
41 unsigned int bval, bit;
42 if(idx >= jed->fuse_count)
43 throw io_exception(std::string("jedec_get_fuse"));
44
45 bval = idx / 8;
46 bit = idx % 8;
47 return (jed->fuse_list[bval] & (1 << bit))? 1 : 0;
48 }
49
jedec_set_fuse(jedec_data_t jed,unsigned idx,int blow)50 void jedec_set_fuse(jedec_data_t jed, unsigned idx, int blow)
51 {
52 unsigned int bval, bit;
53 if(idx >= jed->fuse_count)
54 throw io_exception(std::string("jedec_set_fuse"));
55
56 bval = idx / 8;
57 bit = idx % 8;
58
59 if (blow)
60 jed->fuse_list[bval] |= (1 << bit);
61 else
62 jed->fuse_list[bval] &= ~(1 << bit);
63 }
64
65 struct state_mach {
66 jedec_data_t jed;
67
68 void (*state)(int ch, struct state_mach*m);
69
70 unsigned int checksum;
71 union {
72 struct {
73 unsigned cur_fuse;
74 } l;
75 } m;
76 };
77
78 static void m_startup(int ch, struct state_mach*m);
79 static void m_header(int ch, struct state_mach*m);
80 static void m_base(int ch, struct state_mach*m);
81 static void m_C(int ch, struct state_mach*m);
82 static void m_L(int ch, struct state_mach*m);
83 static void m_Lfuse(int ch, struct state_mach*m);
84 static void m_Q(int ch, struct state_mach*m);
85 static void m_QF(int ch, struct state_mach*m);
86 static void m_QP(int ch, struct state_mach*m);
87 static void m_skip(int ch, struct state_mach*m);
88 static void m_N(int ch, struct state_mach*m);
89
90 int m_N_item;
91 int m_N_pos;
92 int m_H_pos = 0;
93 char m_H_string[MAX_SIZE];
94 char m_N_strings[MAX_ITEM][MAX_SIZE];
95
m_startup(int ch,struct state_mach * m)96 static void m_startup(int ch, struct state_mach*m)
97 {
98 switch (ch)
99 {
100 case '\002':
101 m->state = m_base;
102 break;
103
104 case 'D':
105 m->state = m_header;
106 break;
107
108 default:
109 break;
110 }
111 }
112
m_header(int ch,struct state_mach * m)113 static void m_header(int ch, struct state_mach*m)
114 {
115 switch (ch)
116 {
117 case '\n':
118 case '\r':
119 if (m_H_pos)
120 {
121 char * ptr = strchr( m_H_string, ':');
122 if (ptr)
123 strncpy(m->jed->date, ptr, MAX_SIZE);
124 }
125 m->state = m_startup;
126 break;
127 default:
128 m_H_string[m_H_pos] = ch;
129 m_H_pos++;
130 }
131 }
132
m_base(int ch,struct state_mach * m)133 static void m_base(int ch, struct state_mach*m)
134 {
135 if (isspace(ch))
136 return;
137
138 switch (ch) {
139 case 'L':
140 m->state = m_L;
141 m->m.l.cur_fuse = 0;
142 break;
143 case 'Q':
144 m->state = m_Q;
145 break;
146 case 'C':
147 m->state = m_C;
148 m->jed->checksum = 0;
149 break;
150 case 'N':
151 m->state = m_N;
152 m_N_item = -1;
153 break;
154 default:
155 m->state = m_skip;
156 break;
157 }
158 }
159
m_C(int ch,struct state_mach * m)160 static void m_C(int ch, struct state_mach*m)
161 {
162 if (isspace(ch))
163 return;
164
165 if (ch == '*') {
166 m->state = m_base;
167 return;
168 }
169
170 if(ch >='0' && ch <='9')
171 {
172 m->jed->checksum <<=4;
173 m->jed->checksum += ch - '0';
174 return;
175 }
176 ch &= 0x5f;
177 if(ch >='A' && ch <= 'F')
178 {
179 m->jed->checksum <<=4;
180 m->jed->checksum += ch - '7';
181 return;
182 }
183
184 fprintf(stderr, "m_C: Dangling '%c' 0x%02x\n", ch, ch);
185 fflush(stderr);
186 throw io_exception(std::string("m_C"));
187 }
m_L(int ch,struct state_mach * m)188 static void m_L(int ch, struct state_mach*m)
189 {
190 if (isdigit(ch)) {
191 m->m.l.cur_fuse *= 10;
192 m->m.l.cur_fuse += ch - '0';
193 return;
194 }
195
196 if (isspace(ch)) {
197 m->state = m_Lfuse;
198 return;
199 }
200
201 if (ch == '*') {
202 m->state = m_base;
203 return;
204 }
205
206 fprintf(stderr, "m_L: Dangling '%c' 0x%02x\n", ch, ch);
207 fflush(stderr);
208 m->state = 0;
209 }
210
m_Lfuse(int ch,struct state_mach * m)211 static void m_Lfuse(int ch, struct state_mach*m)
212 {
213 switch (ch) {
214
215 case '*':
216 m->state = m_base;
217 break;
218
219 case '0':
220 jedec_set_fuse(m->jed, m->m.l.cur_fuse, 0);
221 m->m.l.cur_fuse += 1;
222 break;
223
224 case '1':
225 jedec_set_fuse(m->jed, m->m.l.cur_fuse, 1);
226 m->m.l.cur_fuse += 1;
227 break;
228
229 case ' ':
230 case '\n':
231 case '\r':
232 break;
233
234 default:
235 fprintf(stderr, "m_LFuse: Dangling '%c' 0x%02x\n", ch, ch);
236 fflush(stderr);
237 m->state = 0;
238 break;
239 }
240 }
241
242 #ifdef __unix__
243 #define stricmp strcasecmp
244 #define strnicmp strncasecmp
245 #endif
246
m_N(int ch,struct state_mach * m)247 static void m_N(int ch, struct state_mach*m)
248 {
249 switch (ch) {
250
251 case '*':
252 if ((stricmp(m_N_strings[0], "DEVICE")) == 0)
253 {
254 m_N_strings[m_N_item][m_N_pos] = 0;
255 strncpy(m->jed->device, m_N_strings[1], MAX_SIZE);
256 }
257 if ((stricmp(m_N_strings[0], "VERSION")) == 0)
258 {
259 m_N_strings[m_N_item][m_N_pos] = 0;
260 strncpy(m->jed->version, m_N_strings[1], MAX_SIZE);
261 }
262 m->state = m_base;
263 m_N_item= -1;
264 break;
265 case ' ':
266 if(m_N_item >=0)
267 m_N_strings[m_N_item][m_N_pos] = 0;
268 if (m_N_item < MAX_ITEM)
269 {
270 /* Don't stumble on too many items like in ISE XC2C Jedecfiles */
271 m_N_item++;
272 }
273 m_N_pos = 0;
274 case '\n':
275 case '\r':
276 break;
277
278 default:
279 if((m_N_item >=0) && (m_N_item <MAX_ITEM) && (m_N_pos < MAX_SIZE-1))
280 m_N_strings[m_N_item][m_N_pos] = ch;
281 m_N_pos++;
282 break;
283 }
284 }
285
m_Q(int ch,struct state_mach * m)286 static void m_Q(int ch, struct state_mach*m)
287 {
288 switch (ch) {
289 case 'F':
290 if (m->jed->fuse_count != 0) {
291 m->state = 0;
292 return;
293 }
294 m->state = m_QF;
295 m->jed->fuse_count = 0;
296 break;
297 case 'P':
298 if (m->jed->pin_count != 0) {
299 m->state = 0;
300 return;
301 }
302 m->state = m_QP;
303 m->jed->pin_count = 0;
304 break;
305 default:
306 m->state = m_skip;
307 break;
308 }
309 }
310
m_QF(int ch,struct state_mach * m)311 static void m_QF(int ch, struct state_mach*m)
312 {
313 if (isspace(ch))
314 return;
315
316 if (isdigit(ch)) {
317 m->jed->fuse_count *= 10;
318 m->jed->fuse_count += ch - '0';
319 return;
320 }
321
322 if (ch == '*') {
323 m->state = m_base;
324 m->jed->fuse_list = allocate_fusemap(m->jed->fuse_count);
325 return;
326 }
327
328 throw io_exception(std::string("m_QF"));
329 }
330
m_QP(int ch,struct state_mach * m)331 static void m_QP(int ch, struct state_mach*m)
332 {
333 if (isspace(ch))
334 return;
335
336 if (isdigit(ch)) {
337 m->jed->pin_count *= 10;
338 m->jed->pin_count += ch - '0';
339 return;
340 }
341
342 if (ch == '*') {
343 m->state = m_base;
344 return;
345 }
346
347 throw io_exception(std::string("m_QP"));
348 }
349
m_skip(int ch,struct state_mach * m)350 static void m_skip(int ch, struct state_mach*m)
351 {
352 switch (ch) {
353 case '*':
354 m->state = m_base;
355 break;
356
357 default:
358 break;
359 }
360 }
JedecFile(void)361 JedecFile::JedecFile(void)
362 : Error(false), logfile(stderr)
363 {
364 jed.checksum = 0;
365 jed.fuse_count = 0;
366 jed.pin_count = 0;
367 jed.fuse_list = 0;
368 jed.device[0] = 0;
369 jed.version[0] = 0;
370 jed.date[0] = 0;
371 }
372
~JedecFile(void)373 JedecFile::~JedecFile(void)
374 {
375 if(jed.fuse_list)
376 free(jed.fuse_list);
377 }
378
readFile(FILE * fp)379 int JedecFile::readFile(FILE *fp)
380 {
381 int ch;
382 struct state_mach m;
383
384 if(!fp)
385 return 1;
386
387 //jed = (jedec_data_t)calloc(1, sizeof(struct jedec_data));
388 m.jed = &jed;
389 m.state = m_startup;
390 while ((ch = fgetc(fp)) != EOF) {
391 m.state(ch, &m);
392 if (m.state == 0) {
393 /* Some sort of error happened. */
394 return 2;
395 }
396 }
397 if (!jed.fuse_count)
398 return 3;
399 return 0;
400 }
401
saveAsJed(const char * device,FILE * fp)402 void JedecFile::saveAsJed(const char *device, FILE *fp)
403 {
404 unsigned int i, b=0, l=0 ,w=0;
405 unsigned short chksum=0;
406 unsigned int DRegLength;
407 int type=-1;
408
409 if (!fp)
410 return;
411 if (strnicmp("XC9536",device, sizeof("XC9536X")-1) == 0)
412 {
413 type = JED_XC95;
414 }
415 else if (strnicmp("XC9572",device, sizeof("XC9572X")-1) == 0)
416 {
417 type = JED_XC95;
418 }
419 else if (strnicmp("XC95108",device, sizeof("XC95144X")-1) == 0)
420 {
421 type = JED_XC95;
422 }
423 else if (strnicmp("XC95144",device, sizeof("XC95288X")-1) == 0)
424 {
425 type = JED_XC95;
426 }
427 else if (strnicmp("XC95216",device, sizeof("XC95288X")-1) == 0)
428 {
429 type = JED_XC95;
430 }
431 else if (strnicmp("XC95288",device, sizeof("XC95288X")-1) == 0)
432 {
433 type = JED_XC95;
434 }
435 else if (strnicmp("XC9536X",device, sizeof("XC9536X")-1) == 0)
436 {
437 type = JED_XC95X;
438 DRegLength=2;
439 }
440 else if (strnicmp("XC9572X",device, sizeof("XC9572X")-1) == 0)
441 {
442 type = JED_XC95X;
443 DRegLength=4;
444 }
445 else if (strnicmp("XC95144X",device, sizeof("XC95144X")-1) == 0)
446 {
447 type = JED_XC95X;
448 DRegLength=8;
449 }
450 else if (strnicmp("XC95288X",device, sizeof("XC95288X")-1) == 0)
451 {
452 type = JED_XC95X;
453 DRegLength=16;
454 }
455 else if (strnicmp("XC2C",device, sizeof("XC2C")-1) == 0)
456 {
457 type = JED_XC2C;
458 }
459
460 if (strlen(jed.date) == 0)
461 {
462 time_t t;
463 struct tm *tmp;
464 char outstr[200];
465 t = time(NULL);
466 tmp = localtime(&t);
467 if (tmp != NULL)
468 {
469 if (strftime(outstr, sizeof(outstr), "%a %b %d %T %Y", tmp))
470 fprintf(fp, "Date Extracted: %s\n\n", outstr);
471 }
472 }
473 else
474 fprintf(fp, "Date Extracted%s\n\n",jed.date);
475 fprintf(fp, "\2QF%d*\nQV0*\nF0*\nX0*\nJ0 0*\n",jed.fuse_count);
476 if (strlen(jed.version) == 0)
477 fprintf(fp, "N VERSION XC3SPROG*\n");
478 else
479 fprintf(fp, "N VERSION %s*\n",jed.version);
480 fprintf(fp, "N DEVICE %s*\n", device);
481
482 if(type == JED_XC95X)
483 {
484 /* Xilinx Impact (10.1) needs following additional items
485 to recognizes as a valid Jedec File
486 * the 4 Digits as total Checksum
487 * N DEVICE
488 */
489
490 for (i=0; i<jed.fuse_count; i++)
491 {
492 if(!w && !b)
493 fprintf(fp, "L%07d",i);
494 if (!b)
495 fprintf(fp, " ");
496 fprintf(fp, "%d", get_fuse(i));
497 if (l<9)
498 {
499 if(b==7)
500 b=0;
501 else
502 b++;
503 }
504 else
505 {
506 if (b == 5)
507 b = 0;
508 else
509 b++;
510 }
511 if(!b)
512 {
513 if (w == (DRegLength-1))
514 {
515 fprintf(fp, "*\n");
516 w = 0;
517 l++;
518 }
519 else
520 w++;
521 }
522 if (l==15)
523 l =0;
524 }
525 }
526 else if(type == JED_XC95)
527 {
528 for (i=0; i<jed.fuse_count; i++)
529 {
530 if(!b && w%5 == 0)
531 fprintf(fp, "L%07d",i);
532 if (!b)
533 fprintf(fp, " ");
534 fprintf(fp, "%d", get_fuse(i));
535 if( b == (((i%9072)<7776) ? ((w %15 < 9)?7:5):((w%5== 0)?7:6)))
536 {
537 b=0;
538 w++;
539 }
540 else
541 b++;
542 if(!b && (w %5 == 0 ))
543 fprintf(fp, "*\n");
544 }
545 }
546 else if (type == JED_XC2C)
547 {
548 for (i=0; i<jed.fuse_count; i++)
549 {
550 if ((i %64) == 0)
551 fprintf(fp, "L%07d ",i);
552 fprintf(fp, "%d", get_fuse(i));
553 if ((i %64) == 63)
554 fprintf(fp, "*\n");
555 }
556 fprintf(fp, "*\n");
557 }
558
559 for(i=0; i<(jed.fuse_count/8 + ((jed.fuse_count%8)?1:0)); i++)
560 chksum += jed.fuse_list[i];
561 fprintf(fp, "C%04X*\n%c0000\n", chksum, 3);
562 }
563
setLength(unsigned int f_count)564 void JedecFile::setLength(unsigned int f_count)
565 {
566 if(f_count > jed.fuse_count)
567 {
568 if (jed.fuse_list)
569 free(jed.fuse_list);
570 jed.fuse_list = new byte[f_count/8 + ((f_count%8)?1:0)];
571 memset(jed.fuse_list, 0xff, f_count/8 + ((f_count%8)?1:0));
572 }
573 else
574 {
575 for (unsigned int i = f_count; i < jed.fuse_count; i++)
576 set_fuse(i, 0);
577 }
578 jed.fuse_count = f_count;
579 }
580
set_fuse(unsigned int idx,int blow)581 void JedecFile::set_fuse(unsigned int idx, int blow)
582 {
583 jedec_set_fuse(&jed, idx,blow);
584 }
585
get_fuse(unsigned int idx)586 int JedecFile::get_fuse(unsigned int idx)
587 {
588 return jedec_get_fuse(&jed, idx);
589 }
590
calcChecksum()591 unsigned short JedecFile::calcChecksum()
592 {
593 unsigned int i;
594 unsigned short cc=0;
595
596 for(i=0; i<(jed.fuse_count/8 + ((jed.fuse_count%8)?1:0)); i++)
597 cc += jed.fuse_list[i];
598 return cc;
599 }
600