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