Makefile cleanup
[keystone-rtos/ibl.git] / src / util / bconvert / bconvert64x.c
1 /*
2  *
3  * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 
4  * 
5  * 
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions 
8  *  are met:
9  *
10  *    Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  *    Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the   
16  *    distribution.
17  *
18  *    Neither the name of Texas Instruments Incorporated nor the names of
19  *    its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
23  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
24  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
26  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
27  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
28  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
31  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
32  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34 */
38 /************************************************************************************
39  * FILE PURPOSE: Convert a hex6x boot table file into the format required
40  *               by the c6x chip boot loader. 
41  ************************************************************************************
42  * FILE NAME: bconvert.c
43  *
44  * DESCRIPTION: Converts a boot table. The boot table format is:
45  *
46  *    /--------------------------------------------------------\
47  *    |              32 bit entry point address                |
48  *    +--------------------------------------------------------+
49  *    |              32 bit section byte count                 | \
50  *    +--------------------------------------------------------+  \
51  *    |         32 bit section byte start address              |   \
52  *    +-------------+-------------+-------------+--------------+    repeat each section
53  *    |  Data byte  |  Data byte  |  Data byte  |  Data byte   |   /
54  *    +-------------+-------------+-------------+--------------+  /
55  *    |  Data byte  |  Data byte  |  Data byte  |  Data byte   | /
56  *    +-------------+-------------+-------------+--------------+ 
57  *    |        32 bit zero byte count (end of boot table)      | 
58  *    \--------------------------------------------------------/
59  *
60  *
61  *  The C6x boot loader expects all 32 bit values to be in big endian
62  *  (most significant byte arrives first). Data bytes are also arranged to be 32 bit
63  *  big endian represented.
64  *
65  *  This program handles conversion of data values that are in sections that are
66  *  not multiples of 4 bytes. For example, a program compiled in big endian format
67  *  with a 1 byte section will have the following table entry (address 0x22222222), value
68  *  0x33
69  *
70  *  00 00 00 01   22 22 22 22   33 00 00 00
71  *
72  *  The same file compiled with little endian mode will have the entry
73  *
74  *  00 00 00 01   22 22 22 22   00 00 00 33
75  *
76  *
77  *  Since the boot loader has no idea what endianness the code was compiled for, this
78  *  program performs an endian conversion on any section that does not have a length
79  *  that is a multiple of 4 bytes, if the little endian option is specified. Nothing
80  *  is changed for the big endian mode.
81  *
82  *  Invokation:
83  *
84  *  bconvert -be|-le [input_file] [output_file]
85  *
86  ***************************************************************************************/
88 #include "stdio.h"
89 #include "malloc.h"
90 #include "string.h"
92 /* Global variable storing the invokation name */
93 char *invok;
95 /* Error values */
96 enum {
97   ERR_PARSE_TOO_MANY_ARGS = 1000,
98   ERR_PARSE_NO_ENDIAN,
99   ERR_PARSE_INPUT_OPEN_FAIL,
100   ERR_PARSE_OUTPUT_OPEN_FAIL,
101   ERR_READ_BFILE_INITIAL_MALLOC_FAIL,
102   ERR_READ_BFILE_REALLOC_FAIL,
103   ERR_VALUE32_SIZE_ERR,
104   ERR_VALUE16_SIZE_ERR,
105   ERR_DATA32_SIZE_ERR,
106   ERR_REG32_PARSE_ERROR,
107   ERR_DATA32_REMAIN_ERR 
108 };
110 enum {
111   LITTLE,
112   BIG
113 };
115 /************************************************************************************
116  * FUNTION PURPOSE: Send an error string
117  ************************************************************************************
118  * DESCRIPTION: Prints an error to stderr
119  ************************************************************************************/
120 void showErr (int errflag, int line)
122   char *s;
124   switch (errflag)  {
125     case ERR_PARSE_TOO_MANY_ARGS:
126        s = "Parse error: too many args specified";
127        break;
129     case ERR_PARSE_NO_ENDIAN:
130        s = "Parse error: no endian mode specified";
131        break;
133     case ERR_PARSE_INPUT_OPEN_FAIL:
134        s = "File error: failed to open specified input file";
135        break;
137     case ERR_PARSE_OUTPUT_OPEN_FAIL:
138        s = "File error: Failed to open specified output file";
139        break;
141     case ERR_READ_BFILE_INITIAL_MALLOC_FAIL:
142        s = "Memory error: Initial malloc call failed";
143        break;
145     case ERR_READ_BFILE_REALLOC_FAIL:
146        s = "Memory error: Subsequent realloc call failed";
147        break;
149     case ERR_VALUE32_SIZE_ERR:
150        s = "Data format error: End of data on 32 bit value read";
151        break;
153     case ERR_VALUE16_SIZE_ERR:
154        s = "Data format error: End of data on 16 bit value read";
155        break;
157     case ERR_REG32_PARSE_ERROR:
158        s = "Parse error: error parsing after reg32 arg";
159        break;
161     case ERR_DATA32_REMAIN_ERR:
162        s = "Parse error: A remainder size greater then four was found";
163        break;
165     default:
166        s = "Unspecified error";
167        break;
169   }
171   fprintf (stderr, "%s: %s, line %d\n", invok, s, line);
173 } /* showErr */
176 /*************************************************************************************
177  * FUNCTION PURPOSE: Check if a string is prefixed with "0x".
178  *************************************************************************************
179  * DESCRIPTION: Returns non-zero if the string begins with "0x"
180  *************************************************************************************/
181 int isChex (char *s)
183   if ((s[0] == '0') && (s[1] == 'x'))
184     return (1);
186   return (0);
188 } /* isChex */
192 /*************************************************************************************
193  * FUNCTION PURPOSE: Parse the input parameters
194  *************************************************************************************
195  * DESCRIPTION: Checks for required args, opens source and destination streams.
196  *************************************************************************************/
197 int parseit (int argc, char *argv[], FILE **fin, FILE **fout, int *endian)
199   int inspec  = 0;
200   int outspec = 0;
201   int espec   = 0;
202   int c       = 1;
204   char *iname;
205   char *oname;
207   *endian = -1;
209   /* Store the invokation name */
210   invok = argv[0];
212   while (c < argc)  {
214     /* -be | -le */
215     if (!espec)  {
216       if (!strcmp (argv[c], "-be"))  {
217         *endian = BIG;
218         espec = 1;
219         c += 1;
220         continue;
221       } else if (!strcmp (argv[c], "-le"))  {
222         *endian = LITTLE;
223         espec = 1;
224         c += 1;
225         continue;
226       }
227     }
230     /* input file */
231     if (!inspec)  {
232       inspec = 1;
233       iname = argv[c];
234       c += 1;
235       continue;
236     }
238     /* output file */
239     if (!outspec)  {
240       outspec = 1;
241       oname = argv[c];
242       c += 1;
243       continue;
244     }
246     /* Don't know what to do with the arg */
247     return (ERR_PARSE_TOO_MANY_ARGS);
249   }
252   /* Make sure endian is known */
253   if (!espec) 
254     return (ERR_PARSE_NO_ENDIAN);
256   /* Open input file if not stdin */
257   if (inspec)  {
258     *fin = fopen (iname, "r");
259     if (*fin == NULL)
260       return (ERR_PARSE_INPUT_OPEN_FAIL);
261   }
263   /* Open output file if not stdin */
264   if (outspec)  {
265     *fout = fopen (oname, "w");
266     if (*fout == NULL)
267       return (ERR_PARSE_OUTPUT_OPEN_FAIL);
268   }
269  
270   return (0);
272 } /* parseit */
276 /***************************************************************************************
277  * FUNCTION PURPOSE: Check if data is ascii
278  ***************************************************************************************
279  * DESCRIPTION: Returns 1 if a byte is 0-9, a-f, 0 otherwise
280  ***************************************************************************************/
281 int asciiByte (unsigned char c)
283   if ((c >= '0') && (c <= '9'))
284     return (1);
286   if ((c >= 'A') && (c <= 'F'))
287     return (1);
289   return (0);
290 } /* asciiByte */
292 /**************************************************************************************
293  * FUNCTION PURPOSE: Returns the binary equivalent of an ascii byte
294  **************************************************************************************
295  * DESCRIPTION: Conversion from ascii to binary
296  **************************************************************************************/
297 int toNum (unsigned char c)
299   if ((c >= '0') && (c <= '9'))
300     return (c - '0');
302   return (c - 'A' + 10);
304 } /* toNum */
307 /**********************************************************************************
308  * FUNCTION PURPOSE: Read a line from a file, toss it
309  **********************************************************************************
310  * DESCRIPTION: Reads a line, including the newline character, and throws it away.
311  **********************************************************************************/
312 void  stripLine (FILE *s)
314   char iline[132];
316   fgets (iline, 131, s);
318 } /* stripLine */
320 /************************************************************************************
321  * FILE PURPOSE: Read the hex55 data file
322  ************************************************************************************
323  * DESCRIPTION: Reads the input data file. Strips the first two lines, reads
324  *              the byte stream.
325  ************************************************************************************/
326 #define MALLOC_BLOCK_SIZE   512000
327 unsigned char *readBFile (FILE *fin, unsigned *n, int *errcode)
329   unsigned char *d;
330   unsigned allocSize;
331   unsigned m;
332   unsigned char x, y;
334   /* Create a block of data */
335   allocSize = MALLOC_BLOCK_SIZE;
336   d = malloc (allocSize * sizeof (unsigned char));
337   if (d == NULL)  {
338     *errcode = ERR_READ_BFILE_INITIAL_MALLOC_FAIL;
339     if (fin != stdin)
340       fclose (fin);
341     return (NULL);
342   }
344   /* Strip the 1st two lines */
345   stripLine (fin);
346   stripLine (fin);
348   *errcode = 0;
349   m = 0;
351   for (;;)  {
353     /* Read the 1st ascii char */
354     do  {
355       x = fgetc (fin);
356       if (x == (unsigned char)EOF)  {
357         *errcode = 0;
358         *n = m;
359         if (fin != stdin)
360           fclose (fin);
361         return (d);
362       }
363     } while (!asciiByte(x));
365     /* Read the next ascii char */
366     y = fgetc(fin);
367     if (y == (unsigned char)EOF)  {
368       *errcode = 0;
369       *n = m;
370       if (fin != stdin)
371         fclose (fin);
372       return (d);
373     }
375     /* Convert the two characters into a byte */
376     if (asciiByte(y))
377       d[m++] = (toNum(x) << 4) | toNum(y);
379     /* Verify memory bounds */
380     if (m >= allocSize)  {
381       allocSize += MALLOC_BLOCK_SIZE;
382       d= realloc (d, allocSize);
383       if (d== NULL)  {
384         *errcode = ERR_READ_BFILE_REALLOC_FAIL;
385         if (fin != stdin)
386           fclose (fin);
387         return (NULL);
388       }
389     }
391   } /* end for */
393 } /* readBFile */
395 /**************************************************************************************
396  * FUNCTION PURPOSE: converts four bytes into an unsigned value
397  **************************************************************************************
398  * DESCRIPTION: Converts bytes to a value
399  **************************************************************************************/
400 unsigned value32bitAdd (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag, unsigned add)
402   unsigned v;
403   unsigned w;
404   unsigned q;
406   /* Verify that there are 4 values still in the character array */
407   if ((*p + 4) > n)  {
408     *errflag = ERR_VALUE32_SIZE_ERR;
409     return (0);
410   }
412   /* Store the original pointer */
413   q = w = *p;
415   v = (unsigned)data[w+0] << 24 |
416       (unsigned)data[w+1] << 16 |
417       (unsigned)data[w+2] <<  8 |
418       (unsigned)data[w+3] <<  0 ; 
420   *errflag = 0;
422   /* Add any additional value */
423   v = v + add;
425   /* Write the data back in big endian format */
426   data[q+0] = (v >> 24) & 0xff;
427   data[q+1] = (v >> 16) & 0xff;
428   data[q+2] = (v >>  8) & 0xff;
429   data[q+3] = (v >>  0) & 0xff;
431   *p = q+4;
432   return (v);
434 } /* value32bitAdd */
436 /**************************************************************************************
437  * FUNCTION PURPOSE: converts four bytes into an unsigned value
438  **************************************************************************************
439  * DESCRIPTION: Converts bytes to a value, depending on the endian configuration.
440  **************************************************************************************/
441 unsigned value32bit (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag)
443   return (value32bitAdd (endian, data, n, p, errflag, 0));
445 } /* value32bit */
450 /*********************************************************************************
451  * FUNCTION PURPOSE: Convert up to four bytes to big endian 
452  *********************************************************************************
453  * DESCRIPTION: Data bytes are converted. 
454  *********************************************************************************/
455 #define SWAP(x,y,z)  (z)=(x);(x)=(y);(y)=(z)
456 void data32bit (int endian, unsigned char *data, unsigned n, unsigned *p, unsigned m, int *errflag)
459   /* Calculate the number of bytes to convert, limited to four bytes */
460   if (m > 4)
461     m = 4;
463   /* return an error if there are not enough values in the array */
464   if ((*p + m) > n)  {
465     *errflag = ERR_DATA32_SIZE_ERR;
466     return;
467   }
469   /* Clear the error flag */
470   *errflag = 0;
473   /* The data is always already in big endian, there is nothing to do but advance the pointer */
474   *p += m;
476 } /* data32bit */
478 void remain32bit (int endian, unsigned char *data, unsigned n, unsigned *p, unsigned m, int *errflag)
480   unsigned w;
481   unsigned char h;
483   /* return an error if the size is greater then or equal to 4 */
484   if (m >= 4)  {
485     *errflag = ERR_DATA32_REMAIN_ERR;
486     return;
487   }
489   /* return an error if there are not enough values in the array */
490   if ((*p + m) > n)  {
491     *errflag = ERR_DATA32_SIZE_ERR;
492     return;
493   }
495   w = *p;
497   /* Only swap if endianness is little */
498   if (endian == LITTLE)  {
499     /* Swap the next four bytes */
500     SWAP(data[w+0], data[w+3], h);
501     SWAP(data[w+1], data[w+2], h);
502   }
504   /* Update the full four elements */
505   *p = *p + 4;
508 } /* remain32bit */
511 /*********************************************************************************
512  * FUNCTION PURPOSE: Convert 2 bytes into an unsigned value
513  *********************************************************************************
514  * DESCRIPTION: Converts the next two bytes into an unsigned value based on
515  *              the endian configuration.
516  *********************************************************************************/
517 unsigned value16bit (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag)
519   unsigned v;
520   unsigned q;
522   /* Verify that there are 4 values still in the character array */
523   if ((*p + 2) > n)  {
524     *errflag = ERR_VALUE16_SIZE_ERR;
525     return (0);
526   }
528   /* Store the original pointer */
529   q = *p;
531   /* convert based on endianness. For little endain the 16 bit words are actually
532    * big endian, but the bytes in those words are not */
533   if (endian == BIG)  {
534     v = data[(*p)++] <<  8 |
535         data[(*p)++] <<  0 ;
537   }  else  {
538     v = data[(*p)++] <<  0 |
539         data[(*p)++] <<  8 ;
540   }
542   *errflag = 0;
544   /* Write the data back in big endian format */
545   data[q++] = (v >>  8) & 0xff;
546   data[q++] = (v >>  0) & 0xff;
548   return (v);
550 } /* value16bit */
552 /**************************************************************************************
553  * FUNCTION PURPOSE: Writes a 16 bit value into the array
554  **************************************************************************************
555  * DESCRIPTION: Writes a big endian 16 bit value, increments the array pointer.
556  **************************************************************************************/
557 void write16bit (unsigned value, unsigned char *data, unsigned *p)
559   data[(*p)++] = (value >> 8) & 0xff;
560   data[(*p)++] = (value >> 0) & 0xff;
562 } /* write16bit */
565 /*************************************************************************************
566  * FUNCTION PURPOSE: Write the output file
567  *************************************************************************************
568  * DESCRIPTION: Writes the resulting output.
569  *************************************************************************************/
570 void writeBFile (FILE *fout, unsigned char *data, unsigned n)
572   unsigned i;
574   /* Write the two line header */
575   fprintf (fout, "%c\n$A000000\n", (unsigned char)2);
577   for (i = 0; i < n; i++)  {
578     if ( ((i+1)%24)  )
579       fprintf (fout, "%02X ", data[i]);
580     else
581       fprintf (fout, "%02X\n", data[i]);
582   }
584   /* Write the close character */
585   fprintf (fout, "\n%c", (unsigned char)3);
587   if (fout != stdout)
588     fclose (fout);
590 } /* writeBFile */
591   
593 /**************************************************************************************
594  * FUNCTION PURPOSE: Main 
595  **************************************************************************************
596  * DESCRIPTION: Provides the top level program flow.
597  **************************************************************************************/
598 int main (int argc, char *argv[])
600   FILE *fin;            /* input stream  */
601   FILE *fout;           /* output stream */
603   unsigned char *data;  /* The data set  */
604   unsigned n;           /* Data set size */
605   unsigned p;           /* Data index    */
606   unsigned v;           /* Data value    */
607   unsigned n32;         /* Number of bytes that form complete 32 bit values */
608   unsigned r32;         /* Number of bytes remaining (0-3) */
610   int endian;           /* Endian          */  
611   int errflag;          /* error indicator */
612   int i, j;             /* loop var        */
613   int origRegs;         /* original reg count */
614   int shift;            /* data shift amount  */
617   /* Parse the input */
618   if (errflag = parseit (argc, argv, &fin, &fout, &endian))  {
619     showErr (errflag, __LINE__);
620     return (-1);
621   }
623   /* Read the raw data file */
624   data = readBFile (fin, &n, &errflag);
625   if (data == NULL)  {
626     showErr (errflag, __LINE__);
627     return(-1);
628   }
630   /* Parse the sections */
631   p = 0;
633   /* The entry point */
634   v = value32bit (endian, data, n, &p, &errflag);
635   if (errflag)  {
636     showErr (errflag, __LINE__);
637     return(-1);
638   }
640   /* The sections */
641   do  {
642   
643     /* Get the section byte count */   
644     v = value32bit (endian, data, n, &p, &errflag);
645     if (errflag)  {
646       showErr (errflag, __LINE__);
647       return(-1);
648     }
650     if (v)  {
651       /* Convert the start address (adjusts the array index) */
652       value32bit (endian, data, n, &p, &errflag);
653       if (errflag)  {
654         showErr (errflag, __LINE__);
655         return(-1);
656       }
657     }
659     /* Determine how many bytes form complete 32 bit fields, and how many are left over */
660     n32 = v & 0xfffffffc;
661     r32 = v & 0x00000003;
663     /* Convert the data to big endian format  */
664     for (i = 0; i < n32; i += 4)  {
665       data32bit (endian, data, n, &p, v-i, &errflag);
666       if (errflag)  {
667         showErr (errflag, __LINE__);
668         return (-1);
669       }
670     }
672     /* Convert any remaining bytes. */
673     if (r32)  {
674       remain32bit (endian, data, n, &p, r32, &errflag);
675       if (errflag)  {
676         showErr (errflag, __LINE__);
677         return (-1);
678       }
679     }
681   } while (v);
683   /*  Write out the data file */
684   writeBFile (fout, data, n);
686   /* Return resources */
687   free (data);
689   return (0); 
692     
699