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