bcm963xx: add cfe image tagging utility
[openwrt/svn-archive/archive.git] / tools / firmware-utils / src / srec2bin.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4
5 //Rev 0.1 Original
6 // 8 Jan 2001 MJH Added code to write data to Binary file
7 // note: outputfile is name.bin, where name is first part
8 // of input file. ie tmp.rec -> tmp.bin
9 //
10 // srec2bin <input SREC file> <Output Binary File> <If Present, Big Endian>
11 //
12 // TAG
13 // bit32u TAG_BIG = 0xDEADBE42;
14 // bit32u TAG_LITTLE = 0xFEEDFA42;
15 //
16 // File Structure
17 //
18 // TAG : 32 Bits
19 // [DATA RECORDS]
20 //
21 // Data Records Structure
22 //
23 // LENGTH : 32 Bits <- Length of DATA, excludes ADDRESS and CHECKSUM
24 // ADDRESS : 32 Bits
25 // DATA : 8 Bits * LENGTH
26 // CHECKSUM: 32 Bits <- 0 - (Sum of Length --> End of Data)
27 //
28 // Note : If Length == 0, Address will be Program Start
29 //
30 //
31 //
32 //
33 //
34
35 #define MajRevNum 0
36 #define MinRevNum 2
37
38
39 #define EndianSwitch(x) ((x >> 24) | (x << 24) | ((x << 8) & (0x00FF0000)) | ((x >> 8) & (0x0000FF00)) )
40
41 typedef unsigned char bit8u;
42 typedef unsigned int bit32u;
43 typedef int bit32;
44
45 #define FALSE 0
46 #define TRUE (!FALSE)
47
48
49 bit32u CheckSum;
50 int RecStart;
51 int debug;
52 int verbose;
53
54 FILE *OpenOutputFile( char *Name );
55 FILE *fOut;
56 bit32u RecLength=0;
57
58 bit32u AddressCurrent;
59
60 bit32u gh(char *cp,int nibs);
61
62 int BigEndian;
63
64 int inputline;
65
66 // char buf[16*1024];
67
68 char buffer[2048];
69 char *cur_ptr;
70 int cur_line=0;
71 int cur_len=0;
72
73 int s1s2s3_total=0;
74
75 bit32u PBVal;
76 int PBValid;
77 bit32u PBAdr;
78
79
80 void dumpfTell(char *s, bit32u Value)
81 {
82 int Length;
83 Length = (int) RecLength;
84 if (debug)
85 printf("[%s ] ftell()[0x%08lX] Length[0x%4X] Length[%4d] Value[0x%08x]\n",
86 s, ftell(fOut), Length, Length, Value);
87 }
88
89 void DispHex(bit32u Hex)
90 {
91 // printf("%X", Hex);
92 }
93
94 void WaitDisplay(void)
95 {
96 static int Count=0;
97 static int Index=0;
98 char iline[]={"-\\|/"};
99
100 Count++;
101 if ((Count % 32)==0)
102 {
103 if (verbose)
104 printf("%c%c",iline[Index++],8);
105 Index &= 3;
106 }
107 }
108
109
110 void binOut32 ( bit32u Data )
111 {
112 // On UNIX machine all 32bit writes need ENDIAN switched
113 // Data = EndianSwitch(Data);
114 // fwrite( &Data, sizeof(bit32u), 1, fOut);
115
116 char sdat[4];
117 int i;
118
119 for(i=0;i<4;i++)
120 sdat[i]=(char)(Data>>(i*8));
121 fwrite( sdat, 1, 4, fOut);
122 dumpfTell("Out32" , Data);
123 }
124
125 // Only update RecLength on Byte Writes
126 // All 32 bit writes will be for Length etc
127
128 void binOut8 ( bit8u Data )
129 {
130 int n;
131 dumpfTell("B4Data" , (bit32u) (Data & 0xFF) );
132 n = fwrite( &Data, sizeof(bit8u), 1, fOut);
133 if (n != 1)
134 printf("Error in writing %X for Address 0x%8X\n", Data, AddressCurrent);
135 RecLength += 1;
136 }
137
138 // Currently ONLY used for outputting Program Start
139
140 void binRecStart(bit32u Address)
141 {
142 RecLength = 0;
143 CheckSum = Address;
144 RecStart = TRUE;
145
146 if (debug)
147 printf("[RecStart] CheckSum[0x%08X] Length[%4d] Address[0x%08X]\n",
148 CheckSum, RecLength, Address);
149
150
151 dumpfTell("RecLength", RecLength);
152 binOut32( RecLength );
153 dumpfTell("Address", Address);
154 binOut32( Address );
155 }
156
157 void binRecEnd(void)
158 {
159 long RecEnd;
160
161 if (!RecStart) // if no record started, do not end it
162 {
163 return;
164 }
165
166 RecStart = FALSE;
167
168
169 RecEnd = ftell(fOut); // Save Current position
170
171 if (debug)
172 printf("[RecEnd ] CheckSum[0x%08X] Length[%4d] Length[0x%X] RecEnd[0x%08lX]\n",
173 CheckSum, RecLength, RecLength, RecEnd);
174
175 fseek( fOut, -((long) RecLength), SEEK_CUR); // move back Start Of Data
176
177 dumpfTell("Data ", -1);
178
179 fseek( fOut, -4, SEEK_CUR); // move back Start Of Address
180
181 dumpfTell("Address ", -1);
182
183 fseek( fOut, -4, SEEK_CUR); // move back Start Of Length
184
185 dumpfTell("Length ", -1);
186
187 binOut32( RecLength );
188
189 fseek( fOut, RecEnd, SEEK_SET); // move to end of Record
190
191 CheckSum += RecLength;
192
193 CheckSum = ~CheckSum + 1; // Two's complement
194
195 binOut32( CheckSum );
196
197 if (verbose)
198 printf("[Created Record of %d Bytes with CheckSum [0x%8X]\n", RecLength, CheckSum);
199 }
200
201 void binRecOutProgramStart(bit32u Address)
202 {
203 if (Address != (AddressCurrent+1))
204 {
205 binRecEnd();
206 binRecStart(Address);
207 }
208 AddressCurrent = Address;
209 }
210 void binRecOutByte(bit32u Address, bit8u Data)
211 {
212 // If Address is one after Current Address, output Byte
213 // If not, close out last record, update Length, write checksum
214 // Then Start New Record, updating Current Address
215
216 if (Address != (AddressCurrent+1))
217 {
218 binRecEnd();
219 binRecStart(Address);
220 }
221 AddressCurrent = Address;
222 CheckSum += Data;
223 binOut8( Data );
224 }
225
226 //=============================================================================
227 // SUPPORT FUNCTIONS
228 //=============================================================================
229 int readline(FILE *fil,char *buf,int len)
230 {
231 int rlen;
232
233 rlen=0;
234 if (len==0) return(0);
235 while(1)
236 {
237 if (cur_len==0)
238 {
239 cur_len=fread(buffer, 1, sizeof(buffer), fil);
240 if (cur_len==0)
241 {
242 if (rlen)
243 {
244 *buf=0;
245 return(rlen);
246 }
247 return(-1);
248 }
249 cur_ptr=buffer;
250 }
251 if (cur_len)
252 {
253 if (*cur_ptr=='\n')
254 {
255 *buf=0;
256 cur_ptr++;
257 cur_len--;
258 return(rlen);
259 }
260 else
261 {
262 if ((len>1)&&(*cur_ptr!='\r'))
263 {
264 *buf++=*cur_ptr++;
265 len--;
266 }
267 else
268 cur_ptr++;
269
270 rlen++;
271 cur_len--;
272 }
273 }
274 else
275 {
276 *buf=0;
277 cur_ptr++;
278 cur_len--;
279 return(rlen);
280 }
281 }
282 }
283
284
285 int SRLerrorout(char *c1,char *c2)
286 {
287 printf("\nERROR: %s - '%s'.",c1,c2);
288 return(FALSE);
289 }
290
291
292 int checksum(char *cp,int count)
293 {
294 char *scp;
295 int cksum;
296 int dum;
297
298 scp=cp;
299 while(*scp)
300 {
301 if (!isxdigit(*scp++))
302 return(SRLerrorout("Invalid hex digits",cp));
303 }
304 scp=cp;
305
306 cksum=count;
307
308 while(count)
309 {
310 cksum += gh(scp,2);
311 if (count == 2)
312 dum = ~cksum;
313 scp += 2;
314 count--;
315 }
316 cksum&=0x0ff;
317 // printf("\nCk:%02x",cksum);
318 return(cksum==0x0ff);
319 }
320
321 bit32u gh(char *cp,int nibs)
322 {
323 int i;
324 bit32u j;
325
326 j=0;
327
328 for(i=0;i<nibs;i++)
329 {
330 j<<=4;
331 if ((*cp>='a')&&(*cp<='z')) *cp &= 0x5f;
332 if ((*cp>='0')&&(*cp<='9'))
333 j += (*cp-0x30);
334 else
335 if ((*cp>='A')&&(*cp<='F'))
336 j += (*cp-0x37);
337 else
338 SRLerrorout("Bad Hex char", cp);
339 cp++;
340 }
341 return(j);
342 }
343
344
345 //=============================================================================
346 // PROCESS SREC LINE
347 //=============================================================================
348
349 int srecLine(char *pSrecLine)
350 {
351 char *scp,ch;
352 int itmp,count,dat;
353 bit32u adr;
354 static bit32u RecordCounter=0;
355
356 cur_line++;
357 scp=pSrecLine;
358
359 if (*pSrecLine!='S')
360 return(SRLerrorout("Not an Srecord file",scp));
361 pSrecLine++;
362 if (strlen(pSrecLine)<4)
363 return(SRLerrorout("Srecord too short",scp));
364
365 ch=*pSrecLine++;
366
367 count=gh(pSrecLine,2);
368
369 pSrecLine += 2;
370
371 // if(debug)
372 // printf("count %d, strlen(pSrecLine) = %d, pSrecLine =[%s]\n", count, strlen(pSrecLine), pSrecLine);
373 RecordCounter++;
374 DispHex(RecordCounter);
375
376 if ((count*2) != strlen(pSrecLine)) return(SRLerrorout("Count field larger than record",scp));
377
378 if (!checksum(pSrecLine, count)) return(SRLerrorout("Bad Checksum",scp));
379
380 switch(ch)
381 {
382 case '0': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
383 itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
384 if (itmp) return(SRLerrorout("Srecord 1 address not zero",scp));
385 break;
386 case '1': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
387 return(SRLerrorout("Srecord Not valid for MIPS",scp));
388 break;
389 case '2': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
390 return(SRLerrorout("Srecord Not valid for MIPS",scp));
391 break;
392 case '3': if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
393 adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
394 count--;
395 while(count)
396 {
397 dat=gh(pSrecLine,2); pSrecLine+=2; count--;
398 binRecOutByte(adr, (char) (dat & 0xFF));
399 adr++;
400 }
401 s1s2s3_total++;
402 break;
403 case '4': return(SRLerrorout("Invalid Srecord type",scp));
404 break;
405 case '5': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
406 itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
407 if (itmp|=s1s2s3_total) return(SRLerrorout("Incorrect number of S3 Record processed",scp));
408 break;
409 case '6': return(SRLerrorout("Invalid Srecord type",scp));
410 break;
411 case '7': // PROGRAM START
412 if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
413 adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
414 if (count!=1) return(SRLerrorout("Invalid Srecord count field",scp));
415 binRecOutProgramStart(adr);
416 break;
417 case '8': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
418 return(SRLerrorout("Srecord Not valid for MIPS",scp));
419 break;
420 case '9': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
421 return(SRLerrorout("Srecord Not valid for MIPS",scp));
422 break;
423 default:
424 break;
425 }
426 return(TRUE);
427 }
428
429
430 //=============================================================================
431 // MAIN LOGIC, READS IN LINE AND OUTPUTS BINARY
432 //=============================================================================
433
434 int srec2bin(int argc,char *argv[],int verbose)
435 {
436 int i,rlen,sts;
437 FILE *fp;
438 char ac;
439 char buff[256];
440 bit32u TAG_BIG = 0xDEADBE42;
441 bit32u TAG_LITTLE = 0xFEEDFA42;
442
443 bit32u Tag;
444
445
446 if(argc < 3)
447 {
448 printf("\nError: <srec2bin <srec input file> <bin output file>\n\n");
449 return(0);
450 }
451
452 if (argc > 3) BigEndian=TRUE; else BigEndian=FALSE;
453
454 if (BigEndian)
455 Tag = TAG_BIG;
456 else
457 Tag = TAG_LITTLE;
458
459 if (verbose)
460 printf("\nEndian: %s, Tag is 0x%8X\n",(BigEndian)?"BIG":"LITTLE", Tag);
461
462 fp = fopen(argv[1],"rt");
463
464 if (fp==NULL)
465 {
466 printf("\nError: Opening input file, %s.", argv[1]);
467 return(0);
468 }
469
470 fOut = fopen( argv[2], "wb");
471
472 if (fOut==NULL)
473 {
474 printf("\nError: Opening Output file, %s.", argv[2]);
475 if(fp) fclose(fp);
476 return(0);
477 }
478
479 RecStart = FALSE;
480
481 AddressCurrent = 0xFFFFFFFFL;
482
483 // Setup Tag
484
485 dumpfTell("Tag", Tag);
486
487 binOut32(Tag);
488
489
490 inputline=0;
491 sts=TRUE;
492
493 rlen = readline(fp,buff,sizeof buff);
494
495 while( (sts) && (rlen != -1))
496 {
497 if (strlen(buff))
498 {
499 sts &= srecLine(buff);
500 WaitDisplay();
501 }
502 rlen = readline(fp,buff,sizeof buff);
503 }
504
505
506 // printf("PC: 0x%08X, Length 0x%08X, Tag 0x%08X\n", ProgramStart, RecLength, TAG_LITTLE);
507
508 binRecEnd();
509
510 if(fp) fclose(fp);
511 if(fOut) fclose(fOut);
512
513 return(1);
514 }
515
516 main(int argc, char *argv[])
517 {
518 debug = TRUE;
519 debug = FALSE;
520 verbose = FALSE;
521 srec2bin(argc,argv,verbose);
522 return 0;
523 }
524