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
41typedef unsigned char bit8u;
42typedef unsigned int bit32u;
43typedef int bit32;
44
45#define FALSE 0
46#define TRUE (!FALSE)
47
48
49bit32u CheckSum;
50int RecStart;
51int debug;
52int verbose;
53
54FILE *OpenOutputFile( char *Name );
55FILE *fOut;
56bit32u RecLength=0;
57
58bit32u AddressCurrent;
59
60bit32u gh(char *cp,int nibs);
61
62int BigEndian;
63
64int inputline;
65
66// char buf[16*1024];
67
68char buffer[2048];
69char *cur_ptr;
70int cur_line=0;
71int cur_len=0;
72
73int s1s2s3_total=0;
74
75bit32u PBVal;
76int    PBValid;
77bit32u PBAdr;
78
79
80void 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
89void DispHex(bit32u Hex)
90{
91//    printf("%X", Hex);
92}
93
94void 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
110void 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
128void 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
140void 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
157void 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
201void binRecOutProgramStart(bit32u Address)
202{
203    if (Address != (AddressCurrent+1))
204    {
205        binRecEnd();
206        binRecStart(Address);
207    }
208    AddressCurrent = Address;
209}
210void 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//=============================================================================
229int 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
285int SRLerrorout(char *c1,char *c2)
286{
287  printf("\nERROR: %s - '%s'.",c1,c2);
288  return(FALSE);
289}
290
291
292int 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
321bit32u 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
349int 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
434int 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
516main(int argc, char *argv[])
517{
518    debug = TRUE;
519    debug = FALSE;
520    verbose = FALSE;
521    srec2bin(argc,argv,verbose);
522    return 0;
523}
524
525