Changes from Mike Line's 0.5 version
[keystone-rtos/ibl.git] / src / util / bconvert / bconvert64x.c
1 /************************************************************************************
2  * FILE PURPOSE: Convert a hex6x boot table file into the format required
3  *               by the c6x chip boot loader. 
4  ************************************************************************************
5  * FILE NAME: bconvert.c
6  *
7  * DESCRIPTION: Converts a boot table. The boot table format is:
8  *
9  *    /--------------------------------------------------------\
10  *    |              32 bit entry point address                |
11  *    +--------------------------------------------------------+
12  *    |              32 bit section byte count                 | \
13  *    +--------------------------------------------------------+  \
14  *    |         32 bit section byte start address              |   \
15  *    +-------------+-------------+-------------+--------------+    repeat each section
16  *    |  Data byte  |  Data byte  |  Data byte  |  Data byte   |   /
17  *    +-------------+-------------+-------------+--------------+  /
18  *    |  Data byte  |  Data byte  |  Data byte  |  Data byte   | /
19  *    +-------------+-------------+-------------+--------------+ 
20  *    |        32 bit zero byte count (end of boot table)      | 
21  *    \--------------------------------------------------------/
22  *
23  *
24  *  The C6x boot loader expects all 32 bit values to be in big endian
25  *  (most significant byte arrives first). Data bytes are also arranged to be 32 bit
26  *  big endian represented.
27  *
28  *  This program handles conversion of data values that are in sections that are
29  *  not multiples of 4 bytes. For example, a program compiled in big endian format
30  *  with a 1 byte section will have the following table entry (address 0x22222222), value
31  *  0x33
32  *
33  *  00 00 00 01   22 22 22 22   33 00 00 00
34  *
35  *  The same file compiled with little endian mode will have the entry
36  *
37  *  00 00 00 01   22 22 22 22   00 00 00 33
38  *
39  *
40  *  Since the boot loader has no idea what endianness the code was compiled for, this
41  *  program performs an endian conversion on any section that does not have a length
42  *  that is a multiple of 4 bytes, if the little endian option is specified. Nothing
43  *  is changed for the big endian mode.
44  *
45  *  Invokation:
46  *
47  *  bconvert -be|-le [input_file] [output_file]
48  *
49  ***************************************************************************************/
51 #include "stdio.h"
52 #include "malloc.h"
53 #include "string.h"
55 /* Global variable storing the invokation name */
56 char *invok;
58 /* Error values */
59 enum {
60   ERR_PARSE_TOO_MANY_ARGS = 1000,
61   ERR_PARSE_NO_ENDIAN,
62   ERR_PARSE_INPUT_OPEN_FAIL,
63   ERR_PARSE_OUTPUT_OPEN_FAIL,
64   ERR_READ_BFILE_INITIAL_MALLOC_FAIL,
65   ERR_READ_BFILE_REALLOC_FAIL,
66   ERR_VALUE32_SIZE_ERR,
67   ERR_VALUE16_SIZE_ERR,
68   ERR_DATA32_SIZE_ERR,
69   ERR_REG32_PARSE_ERROR,
70   ERR_DATA32_REMAIN_ERR 
71 };
73 enum {
74   LITTLE,
75   BIG
76 };
78 /************************************************************************************
79  * FUNTION PURPOSE: Send an error string
80  ************************************************************************************
81  * DESCRIPTION: Prints an error to stderr
82  ************************************************************************************/
83 void showErr (int errflag, int line)
84 {
85   char *s;
87   switch (errflag)  {
88     case ERR_PARSE_TOO_MANY_ARGS:
89        s = "Parse error: too many args specified";
90        break;
92     case ERR_PARSE_NO_ENDIAN:
93        s = "Parse error: no endian mode specified";
94        break;
96     case ERR_PARSE_INPUT_OPEN_FAIL:
97        s = "File error: failed to open specified input file";
98        break;
100     case ERR_PARSE_OUTPUT_OPEN_FAIL:
101        s = "File error: Failed to open specified output file";
102        break;
104     case ERR_READ_BFILE_INITIAL_MALLOC_FAIL:
105        s = "Memory error: Initial malloc call failed";
106        break;
108     case ERR_READ_BFILE_REALLOC_FAIL:
109        s = "Memory error: Subsequent realloc call failed";
110        break;
112     case ERR_VALUE32_SIZE_ERR:
113        s = "Data format error: End of data on 32 bit value read";
114        break;
116     case ERR_VALUE16_SIZE_ERR:
117        s = "Data format error: End of data on 16 bit value read";
118        break;
120     case ERR_REG32_PARSE_ERROR:
121        s = "Parse error: error parsing after reg32 arg";
122        break;
124     case ERR_DATA32_REMAIN_ERR:
125        s = "Parse error: A remainder size greater then four was found";
126        break;
128     default:
129        s = "Unspecified error";
130        break;
132   }
134   fprintf (stderr, "%s: %s, line %d\n", invok, s, line);
136 } /* showErr */
139 /*************************************************************************************
140  * FUNCTION PURPOSE: Check if a string is prefixed with "0x".
141  *************************************************************************************
142  * DESCRIPTION: Returns non-zero if the string begins with "0x"
143  *************************************************************************************/
144 int isChex (char *s)
146   if ((s[0] == '0') && (s[1] == 'x'))
147     return (1);
149   return (0);
151 } /* isChex */
155 /*************************************************************************************
156  * FUNCTION PURPOSE: Parse the input parameters
157  *************************************************************************************
158  * DESCRIPTION: Checks for required args, opens source and destination streams.
159  *************************************************************************************/
160 int parseit (int argc, char *argv[], FILE **fin, FILE **fout, int *endian)
162   int inspec  = 0;
163   int outspec = 0;
164   int espec   = 0;
165   int c       = 1;
167   char *iname;
168   char *oname;
170   *endian = -1;
172   /* Store the invokation name */
173   invok = argv[0];
175   while (c < argc)  {
177     /* -be | -le */
178     if (!espec)  {
179       if (!strcmp (argv[c], "-be"))  {
180         *endian = BIG;
181         espec = 1;
182         c += 1;
183         continue;
184       } else if (!strcmp (argv[c], "-le"))  {
185         *endian = LITTLE;
186         espec = 1;
187         c += 1;
188         continue;
189       }
190     }
193     /* input file */
194     if (!inspec)  {
195       inspec = 1;
196       iname = argv[c];
197       c += 1;
198       continue;
199     }
201     /* output file */
202     if (!outspec)  {
203       outspec = 1;
204       oname = argv[c];
205       c += 1;
206       continue;
207     }
209     /* Don't know what to do with the arg */
210     return (ERR_PARSE_TOO_MANY_ARGS);
212   }
215   /* Make sure endian is known */
216   if (!espec) 
217     return (ERR_PARSE_NO_ENDIAN);
219   /* Open input file if not stdin */
220   if (inspec)  {
221     *fin = fopen (iname, "r");
222     if (*fin == NULL)
223       return (ERR_PARSE_INPUT_OPEN_FAIL);
224   }
226   /* Open output file if not stdin */
227   if (outspec)  {
228     *fout = fopen (oname, "w");
229     if (*fout == NULL)
230       return (ERR_PARSE_OUTPUT_OPEN_FAIL);
231   }
232  
233   return (0);
235 } /* parseit */
239 /***************************************************************************************
240  * FUNCTION PURPOSE: Check if data is ascii
241  ***************************************************************************************
242  * DESCRIPTION: Returns 1 if a byte is 0-9, a-f, 0 otherwise
243  ***************************************************************************************/
244 int asciiByte (unsigned char c)
246   if ((c >= '0') && (c <= '9'))
247     return (1);
249   if ((c >= 'A') && (c <= 'F'))
250     return (1);
252   return (0);
253 } /* asciiByte */
255 /**************************************************************************************
256  * FUNCTION PURPOSE: Returns the binary equivalent of an ascii byte
257  **************************************************************************************
258  * DESCRIPTION: Conversion from ascii to binary
259  **************************************************************************************/
260 int toNum (unsigned char c)
262   if ((c >= '0') && (c <= '9'))
263     return (c - '0');
265   return (c - 'A' + 10);
267 } /* toNum */
270 /**********************************************************************************
271  * FUNCTION PURPOSE: Read a line from a file, toss it
272  **********************************************************************************
273  * DESCRIPTION: Reads a line, including the newline character, and throws it away.
274  **********************************************************************************/
275 void  stripLine (FILE *s)
277   char iline[132];
279   fgets (iline, 131, s);
281 } /* stripLine */
283 /************************************************************************************
284  * FILE PURPOSE: Read the hex55 data file
285  ************************************************************************************
286  * DESCRIPTION: Reads the input data file. Strips the first two lines, reads
287  *              the byte stream.
288  ************************************************************************************/
289 #define MALLOC_BLOCK_SIZE   512000
290 unsigned char *readBFile (FILE *fin, unsigned *n, int *errcode)
292   unsigned char *d;
293   unsigned allocSize;
294   unsigned m;
295   unsigned char x, y;
297   /* Create a block of data */
298   allocSize = MALLOC_BLOCK_SIZE;
299   d = malloc (allocSize * sizeof (unsigned char));
300   if (d == NULL)  {
301     *errcode = ERR_READ_BFILE_INITIAL_MALLOC_FAIL;
302     if (fin != stdin)
303       fclose (fin);
304     return (NULL);
305   }
307   /* Strip the 1st two lines */
308   stripLine (fin);
309   stripLine (fin);
311   *errcode = 0;
312   m = 0;
314   for (;;)  {
316     /* Read the 1st ascii char */
317     do  {
318       x = fgetc (fin);
319       if (x == (unsigned char)EOF)  {
320         *errcode = 0;
321         *n = m;
322         if (fin != stdin)
323           fclose (fin);
324         return (d);
325       }
326     } while (!asciiByte(x));
328     /* Read the next ascii char */
329     y = fgetc(fin);
330     if (y == (unsigned char)EOF)  {
331       *errcode = 0;
332       *n = m;
333       if (fin != stdin)
334         fclose (fin);
335       return (d);
336     }
338     /* Convert the two characters into a byte */
339     if (asciiByte(y))
340       d[m++] = (toNum(x) << 4) | toNum(y);
342     /* Verify memory bounds */
343     if (m >= allocSize)  {
344       allocSize += MALLOC_BLOCK_SIZE;
345       d= realloc (d, allocSize);
346       if (d== NULL)  {
347         *errcode = ERR_READ_BFILE_REALLOC_FAIL;
348         if (fin != stdin)
349           fclose (fin);
350         return (NULL);
351       }
352     }
354   } /* end for */
356 } /* readBFile */
358 /**************************************************************************************
359  * FUNCTION PURPOSE: converts four bytes into an unsigned value
360  **************************************************************************************
361  * DESCRIPTION: Converts bytes to a value
362  **************************************************************************************/
363 unsigned value32bitAdd (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag, unsigned add)
365   unsigned v;
366   unsigned w;
367   unsigned q;
369   /* Verify that there are 4 values still in the character array */
370   if ((*p + 4) > n)  {
371     *errflag = ERR_VALUE32_SIZE_ERR;
372     return (0);
373   }
375   /* Store the original pointer */
376   q = w = *p;
378   v = (unsigned)data[w+0] << 24 |
379       (unsigned)data[w+1] << 16 |
380       (unsigned)data[w+2] <<  8 |
381       (unsigned)data[w+3] <<  0 ; 
383   *errflag = 0;
385   /* Add any additional value */
386   v = v + add;
388   /* Write the data back in big endian format */
389   data[q+0] = (v >> 24) & 0xff;
390   data[q+1] = (v >> 16) & 0xff;
391   data[q+2] = (v >>  8) & 0xff;
392   data[q+3] = (v >>  0) & 0xff;
394   *p = q+4;
395   return (v);
397 } /* value32bitAdd */
399 /**************************************************************************************
400  * FUNCTION PURPOSE: converts four bytes into an unsigned value
401  **************************************************************************************
402  * DESCRIPTION: Converts bytes to a value, depending on the endian configuration.
403  **************************************************************************************/
404 unsigned value32bit (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag)
406   return (value32bitAdd (endian, data, n, p, errflag, 0));
408 } /* value32bit */
413 /*********************************************************************************
414  * FUNCTION PURPOSE: Convert up to four bytes to big endian 
415  *********************************************************************************
416  * DESCRIPTION: Data bytes are converted. 
417  *********************************************************************************/
418 #define SWAP(x,y,z)  (z)=(x);(x)=(y);(y)=(z)
419 void data32bit (int endian, unsigned char *data, unsigned n, unsigned *p, unsigned m, int *errflag)
422   /* Calculate the number of bytes to convert, limited to four bytes */
423   if (m > 4)
424     m = 4;
426   /* return an error if there are not enough values in the array */
427   if ((*p + m) > n)  {
428     *errflag = ERR_DATA32_SIZE_ERR;
429     return;
430   }
432   /* Clear the error flag */
433   *errflag = 0;
436   /* The data is always already in big endian, there is nothing to do but advance the pointer */
437   *p += m;
439 } /* data32bit */
441 void remain32bit (int endian, unsigned char *data, unsigned n, unsigned *p, unsigned m, int *errflag)
443   unsigned w;
444   unsigned char h;
446   /* return an error if the size is greater then or equal to 4 */
447   if (m >= 4)  {
448     *errflag = ERR_DATA32_REMAIN_ERR;
449     return;
450   }
452   /* return an error if there are not enough values in the array */
453   if ((*p + m) > n)  {
454     *errflag = ERR_DATA32_SIZE_ERR;
455     return;
456   }
458   w = *p;
460   /* Only swap if endianness is little */
461   if (endian == LITTLE)  {
462     /* Swap the next four bytes */
463     SWAP(data[w+0], data[w+3], h);
464     SWAP(data[w+1], data[w+2], h);
465   }
467   /* Update the full four elements */
468   *p = *p + 4;
471 } /* remain32bit */
474 /*********************************************************************************
475  * FUNCTION PURPOSE: Convert 2 bytes into an unsigned value
476  *********************************************************************************
477  * DESCRIPTION: Converts the next two bytes into an unsigned value based on
478  *              the endian configuration.
479  *********************************************************************************/
480 unsigned value16bit (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag)
482   unsigned v;
483   unsigned q;
485   /* Verify that there are 4 values still in the character array */
486   if ((*p + 2) > n)  {
487     *errflag = ERR_VALUE16_SIZE_ERR;
488     return (0);
489   }
491   /* Store the original pointer */
492   q = *p;
494   /* convert based on endianness. For little endain the 16 bit words are actually
495    * big endian, but the bytes in those words are not */
496   if (endian == BIG)  {
497     v = data[(*p)++] <<  8 |
498         data[(*p)++] <<  0 ;
500   }  else  {
501     v = data[(*p)++] <<  0 |
502         data[(*p)++] <<  8 ;
503   }
505   *errflag = 0;
507   /* Write the data back in big endian format */
508   data[q++] = (v >>  8) & 0xff;
509   data[q++] = (v >>  0) & 0xff;
511   return (v);
513 } /* value16bit */
515 /**************************************************************************************
516  * FUNCTION PURPOSE: Writes a 16 bit value into the array
517  **************************************************************************************
518  * DESCRIPTION: Writes a big endian 16 bit value, increments the array pointer.
519  **************************************************************************************/
520 void write16bit (unsigned value, unsigned char *data, unsigned *p)
522   data[(*p)++] = (value >> 8) & 0xff;
523   data[(*p)++] = (value >> 0) & 0xff;
525 } /* write16bit */
528 /*************************************************************************************
529  * FUNCTION PURPOSE: Write the output file
530  *************************************************************************************
531  * DESCRIPTION: Writes the resulting output.
532  *************************************************************************************/
533 void writeBFile (FILE *fout, unsigned char *data, unsigned n)
535   unsigned i;
537   /* Write the two line header */
538   fprintf (fout, "%c\n$A000000\n", (unsigned char)2);
540   for (i = 0; i < n; i++)  {
541     if ( ((i+1)%24)  )
542       fprintf (fout, "%02X ", data[i]);
543     else
544       fprintf (fout, "%02X\n", data[i]);
545   }
547   /* Write the close character */
548   fprintf (fout, "\n%c", (unsigned char)3);
550   if (fout != stdout)
551     fclose (fout);
553 } /* writeBFile */
554   
556 /**************************************************************************************
557  * FUNCTION PURPOSE: Main 
558  **************************************************************************************
559  * DESCRIPTION: Provides the top level program flow.
560  **************************************************************************************/
561 int main (int argc, char *argv[])
563   FILE *fin;            /* input stream  */
564   FILE *fout;           /* output stream */
566   unsigned char *data;  /* The data set  */
567   unsigned n;           /* Data set size */
568   unsigned p;           /* Data index    */
569   unsigned v;           /* Data value    */
570   unsigned n32;         /* Number of bytes that form complete 32 bit values */
571   unsigned r32;         /* Number of bytes remaining (0-3) */
573   int endian;           /* Endian          */  
574   int errflag;          /* error indicator */
575   int i, j;             /* loop var        */
576   int origRegs;         /* original reg count */
577   int shift;            /* data shift amount  */
580   /* Parse the input */
581   if (errflag = parseit (argc, argv, &fin, &fout, &endian))  {
582     showErr (errflag, __LINE__);
583     return (-1);
584   }
586   /* Read the raw data file */
587   data = readBFile (fin, &n, &errflag);
588   if (data == NULL)  {
589     showErr (errflag, __LINE__);
590     return(-1);
591   }
593   /* Parse the sections */
594   p = 0;
596   /* The entry point */
597   v = value32bit (endian, data, n, &p, &errflag);
598   if (errflag)  {
599     showErr (errflag, __LINE__);
600     return(-1);
601   }
603   /* The sections */
604   do  {
605   
606     /* Get the section byte count */   
607     v = value32bit (endian, data, n, &p, &errflag);
608     if (errflag)  {
609       showErr (errflag, __LINE__);
610       return(-1);
611     }
613     if (v)  {
614       /* Convert the start address (adjusts the array index) */
615       value32bit (endian, data, n, &p, &errflag);
616       if (errflag)  {
617         showErr (errflag, __LINE__);
618         return(-1);
619       }
620     }
622     /* Determine how many bytes form complete 32 bit fields, and how many are left over */
623     n32 = v & 0xfffffffc;
624     r32 = v & 0x00000003;
626     /* Convert the data to big endian format  */
627     for (i = 0; i < n32; i += 4)  {
628       data32bit (endian, data, n, &p, v-i, &errflag);
629       if (errflag)  {
630         showErr (errflag, __LINE__);
631         return (-1);
632       }
633     }
635     /* Convert any remaining bytes. */
636     if (r32)  {
637       remain32bit (endian, data, n, &p, r32, &errflag);
638       if (errflag)  {
639         showErr (errflag, __LINE__);
640         return (-1);
641       }
642     }
644   } while (v);
646   /*  Write out the data file */
647   writeBFile (fout, data, n);
649   /* Return resources */
650   free (data);
652   return (0); 
655     
662