1 // SPDX-License-Identifier: GPL-2.0-only
7 // 8 Jan 2001 MJH Added code to write data to Binary file
8 // note: outputfile is name.bin, where name is first part
9 // of input file. ie tmp.rec -> tmp.bin
11 // srec2bin <input SREC file> <Output Binary File> <If Present, Big Endian>
14 // bit32u TAG_BIG = 0xDEADBE42;
15 // bit32u TAG_LITTLE = 0xFEEDFA42;
22 // Data Records Structure
24 // LENGTH : 32 Bits <- Length of DATA, excludes ADDRESS and CHECKSUM
26 // DATA : 8 Bits * LENGTH
27 // CHECKSUM: 32 Bits <- 0 - (Sum of Length --> End of Data)
29 // Note : If Length == 0, Address will be Program Start
40 #define EndianSwitch(x) ((x >> 24) | (x << 24) | ((x << 8) & (0x00FF0000)) | ((x >> 8) & (0x0000FF00)) )
42 typedef unsigned char bit8u
;
43 typedef unsigned int bit32u
;
55 FILE *OpenOutputFile( char *Name
);
59 bit32u AddressCurrent
;
61 bit32u
gh(char *cp
,int nibs
);
81 void dumpfTell(char *s
, bit32u Value
)
84 Length
= (int) RecLength
;
86 printf("[%s ] ftell()[0x%08lX] Length[0x%4X] Length[%4d] Value[0x%08x]\n",
87 s
, ftell(fOut
), Length
, Length
, Value
);
90 void DispHex(bit32u Hex
)
95 void WaitDisplay(void)
99 char iline
[]={"-\\|/"};
105 printf("%c%c",iline
[Index
++],8);
111 void binOut32 ( bit32u Data
)
113 // On UNIX machine all 32bit writes need ENDIAN switched
114 // Data = EndianSwitch(Data);
115 // fwrite( &Data, sizeof(bit32u), 1, fOut);
121 sdat
[i
]=(char)(Data
>>(i
*8));
122 fwrite( sdat
, 1, 4, fOut
);
123 dumpfTell("Out32" , Data
);
126 // Only update RecLength on Byte Writes
127 // All 32 bit writes will be for Length etc
129 void binOut8 ( bit8u Data
)
132 dumpfTell("B4Data" , (bit32u
) (Data
& 0xFF) );
133 n
= fwrite( &Data
, sizeof(bit8u
), 1, fOut
);
135 printf("Error in writing %X for Address 0x%8X\n", Data
, AddressCurrent
);
139 // Currently ONLY used for outputting Program Start
141 void binRecStart(bit32u Address
)
148 printf("[RecStart] CheckSum[0x%08X] Length[%4d] Address[0x%08X]\n",
149 CheckSum
, RecLength
, Address
);
152 dumpfTell("RecLength", RecLength
);
153 binOut32( RecLength
);
154 dumpfTell("Address", Address
);
162 if (!RecStart
) // if no record started, do not end it
170 RecEnd
= ftell(fOut
); // Save Current position
173 printf("[RecEnd ] CheckSum[0x%08X] Length[%4d] Length[0x%X] RecEnd[0x%08lX]\n",
174 CheckSum
, RecLength
, RecLength
, RecEnd
);
176 fseek( fOut
, -((long) RecLength
), SEEK_CUR
); // move back Start Of Data
178 dumpfTell("Data ", -1);
180 fseek( fOut
, -4, SEEK_CUR
); // move back Start Of Address
182 dumpfTell("Address ", -1);
184 fseek( fOut
, -4, SEEK_CUR
); // move back Start Of Length
186 dumpfTell("Length ", -1);
188 binOut32( RecLength
);
190 fseek( fOut
, RecEnd
, SEEK_SET
); // move to end of Record
192 CheckSum
+= RecLength
;
194 CheckSum
= ~CheckSum
+ 1; // Two's complement
196 binOut32( CheckSum
);
199 printf("[Created Record of %d Bytes with CheckSum [0x%8X]\n", RecLength
, CheckSum
);
202 void binRecOutProgramStart(bit32u Address
)
204 if (Address
!= (AddressCurrent
+1))
207 binRecStart(Address
);
209 AddressCurrent
= Address
;
211 void binRecOutByte(bit32u Address
, bit8u Data
)
213 // If Address is one after Current Address, output Byte
214 // If not, close out last record, update Length, write checksum
215 // Then Start New Record, updating Current Address
217 if (Address
!= (AddressCurrent
+1))
220 binRecStart(Address
);
222 AddressCurrent
= Address
;
227 //=============================================================================
229 //=============================================================================
230 int readline(FILE *fil
,char *buf
,int len
)
235 if (len
==0) return(0);
240 cur_len
=fread(buffer
, 1, sizeof(buffer
), fil
);
263 if ((len
>1)&&(*cur_ptr
!='\r'))
286 int SRLerrorout(char *c1
,char *c2
)
288 printf("\nERROR: %s - '%s'.",c1
,c2
);
293 int checksum(char *cp
,int count
)
302 if (!isxdigit(*scp
++))
303 return(SRLerrorout("Invalid hex digits",cp
));
318 // printf("\nCk:%02x",cksum);
319 return(cksum
==0x0ff);
322 bit32u
gh(char *cp
,int nibs
)
332 if ((*cp
>='a')&&(*cp
<='z')) *cp
&= 0x5f;
333 if ((*cp
>='0')&&(*cp
<='9'))
336 if ((*cp
>='A')&&(*cp
<='F'))
339 SRLerrorout("Bad Hex char", cp
);
346 //=============================================================================
348 //=============================================================================
350 int srecLine(char *pSrecLine
)
355 static bit32u RecordCounter
=0;
361 return(SRLerrorout("Not an Srecord file",scp
));
363 if (strlen(pSrecLine
)<4)
364 return(SRLerrorout("Srecord too short",scp
));
368 count
=gh(pSrecLine
,2);
373 // printf("count %d, strlen(pSrecLine) = %d, pSrecLine =[%s]\n", count, strlen(pSrecLine), pSrecLine);
375 DispHex(RecordCounter
);
377 if ((count
*2) != strlen(pSrecLine
)) return(SRLerrorout("Count field larger than record",scp
));
379 if (!checksum(pSrecLine
, count
)) return(SRLerrorout("Bad Checksum",scp
));
383 case '0': if (count
<3) return(SRLerrorout("Invalid Srecord count field",scp
));
384 itmp
=gh(pSrecLine
,4); pSrecLine
+=4; count
-=2;
385 if (itmp
) return(SRLerrorout("Srecord 1 address not zero",scp
));
387 case '1': if (count
<3) return(SRLerrorout("Invalid Srecord count field",scp
));
388 return(SRLerrorout("Srecord Not valid for MIPS",scp
));
390 case '2': if (count
<4) return(SRLerrorout("Invalid Srecord count field",scp
));
391 return(SRLerrorout("Srecord Not valid for MIPS",scp
));
393 case '3': if (count
<5) return(SRLerrorout("Invalid Srecord count field",scp
));
394 adr
=gh(pSrecLine
,8); pSrecLine
+=8; count
-=4;
398 dat
=gh(pSrecLine
,2); pSrecLine
+=2; count
--;
399 binRecOutByte(adr
, (char) (dat
& 0xFF));
404 case '4': return(SRLerrorout("Invalid Srecord type",scp
));
406 case '5': if (count
<3) return(SRLerrorout("Invalid Srecord count field",scp
));
407 itmp
=gh(pSrecLine
,4); pSrecLine
+=4; count
-=2;
408 if (itmp
|=s1s2s3_total
) return(SRLerrorout("Incorrect number of S3 Record processed",scp
));
410 case '6': return(SRLerrorout("Invalid Srecord type",scp
));
412 case '7': // PROGRAM START
413 if (count
<5) return(SRLerrorout("Invalid Srecord count field",scp
));
414 adr
=gh(pSrecLine
,8); pSrecLine
+=8; count
-=4;
415 if (count
!=1) return(SRLerrorout("Invalid Srecord count field",scp
));
416 binRecOutProgramStart(adr
);
418 case '8': if (count
<4) return(SRLerrorout("Invalid Srecord count field",scp
));
419 return(SRLerrorout("Srecord Not valid for MIPS",scp
));
421 case '9': if (count
<3) return(SRLerrorout("Invalid Srecord count field",scp
));
422 return(SRLerrorout("Srecord Not valid for MIPS",scp
));
431 //=============================================================================
432 // MAIN LOGIC, READS IN LINE AND OUTPUTS BINARY
433 //=============================================================================
435 int srec2bin(int argc
,char *argv
[],int verbose
)
440 bit32u TAG_BIG
= 0xDEADBE42;
441 bit32u TAG_LITTLE
= 0xFEEDFA42;
448 printf("\nError: <srec2bin <srec input file> <bin output file>\n\n");
452 if (argc
> 3) BigEndian
=TRUE
; else BigEndian
=FALSE
;
460 printf("\nEndian: %s, Tag is 0x%8X\n",(BigEndian
)?"BIG":"LITTLE", Tag
);
462 fp
= fopen(argv
[1],"rt");
466 printf("\nError: Opening input file, %s.", argv
[1]);
470 fOut
= fopen( argv
[2], "wb");
474 printf("\nError: Opening Output file, %s.", argv
[2]);
481 AddressCurrent
= 0xFFFFFFFFL
;
485 dumpfTell("Tag", Tag
);
493 rlen
= readline(fp
,buff
,sizeof buff
);
495 while( (sts
) && (rlen
!= -1))
499 sts
&= srecLine(buff
);
502 rlen
= readline(fp
,buff
,sizeof buff
);
506 // printf("PC: 0x%08X, Length 0x%08X, Tag 0x%08X\n", ProgramStart, RecLength, TAG_LITTLE);
511 if(fOut
) fclose(fOut
);
516 int main(int argc
, char *argv
[])
521 srec2bin(argc
,argv
,verbose
);