Updated changes for GA RC1
[keystone-rtos/mcsdk-tools.git] / boot_loader / examples / ethernet / Utilities / bconvert64x.c
1 /******************************************************************************
2  * Copyright (c) 2011 Texas Instruments Incorporated - http://www.ti.com
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions
6  *  are met:
7  *
8  *    Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *
11  *    Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the
14  *    distribution.
15  *
16  *    Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  *****************************************************************************/
34 /************************************************************************************
35  * FILE PURPOSE: Convert a hex6x boot table file into the format required
36  *               by the c6x chip boot loader.
37  ************************************************************************************
38  * FILE NAME: bconvert.c
39  *
40  * DESCRIPTION: Converts a boot table. The boot table format is:
41  *
42  *    /--------------------------------------------------------\
43  *    |              32 bit entry point address                |
44  *    +--------------------------------------------------------+
45  *    |              32 bit section byte count                 | \
46  *    +--------------------------------------------------------+  \
47  *    |         32 bit section byte start address              |   \
48  *    +-------------+-------------+-------------+--------------+    repeat each section
49  *    |  Data byte  |  Data byte  |  Data byte  |  Data byte   |   /
50  *    +-------------+-------------+-------------+--------------+  /
51  *    |  Data byte  |  Data byte  |  Data byte  |  Data byte   | /
52  *    +-------------+-------------+-------------+--------------+
53  *    |        32 bit zero byte count (end of boot table)      |
54  *    \--------------------------------------------------------/
55  *
56  *
57  *  The C6x boot loader expects all 32 bit values to be in big endian
58  *  (most significant byte arrives first). Data bytes are also arranged to be 32 bit
59  *  big endian represented.
60  *
61  *  This program handles conversion of data values that are in sections that are
62  *  not multiples of 4 bytes. For example, a program compiled in big endian format
63  *  with a 1 byte section will have the following table entry (address 0x22222222), value
64  *  0x33
65  *
66  *  00 00 00 01   22 22 22 22   33 00 00 00
67  *
68  *  The same file compiled with little endian mode will have the entry
69  *
70  *  00 00 00 01   22 22 22 22   00 00 00 33
71  *
72  *
73  *  Since the boot loader has no idea what endianness the code was compiled for, this
74  *  program performs an endian conversion on any section that does not have a length
75  *  that is a multiple of 4 bytes, if the little endian option is specified. Nothing
76  *  is changed for the big endian mode.
77  *
78  *  Invokation:
79  *
80  *  bconvert -be|-le [input_file] [output_file]
81  *
82  ***************************************************************************************/
84 #include "stdio.h"
85 #include "malloc.h"
86 #include "string.h"
88 /* Global variable storing the invokation name */
89 char *invok;
91 /* Error values */
92 enum {
93   ERR_PARSE_TOO_MANY_ARGS = 1000,
94   ERR_PARSE_NO_ENDIAN,
95   ERR_PARSE_INPUT_OPEN_FAIL,
96   ERR_PARSE_OUTPUT_OPEN_FAIL,
97   ERR_READ_BFILE_INITIAL_MALLOC_FAIL,
98   ERR_READ_BFILE_REALLOC_FAIL,
99   ERR_VALUE32_SIZE_ERR,
100   ERR_VALUE16_SIZE_ERR,
101   ERR_DATA32_SIZE_ERR,
102   ERR_REG32_PARSE_ERROR,
103   ERR_DATA32_REMAIN_ERR
104 };
106 enum {
107   LITTLE,
108   BIG
109 };
111 /************************************************************************************
112  * FUNTION PURPOSE: Send an error string
113  ************************************************************************************
114  * DESCRIPTION: Prints an error to stderr
115  ************************************************************************************/
116 void showErr (int errflag)
118   char *s;
120   switch (errflag)  {
121     case ERR_PARSE_TOO_MANY_ARGS:
122        s = "Parse error: too many args specified";
123        break;
125     case ERR_PARSE_NO_ENDIAN:
126        s = "Parse error: no endian mode specified";
127        break;
129     case ERR_PARSE_INPUT_OPEN_FAIL:
130        s = "File error: failed to open specified input file";
131        break;
133     case ERR_PARSE_OUTPUT_OPEN_FAIL:
134        s = "File error: Failed to open specified output file";
135        break;
137     case ERR_READ_BFILE_INITIAL_MALLOC_FAIL:
138        s = "Memory error: Initial malloc call failed";
139        break;
141     case ERR_READ_BFILE_REALLOC_FAIL:
142        s = "Memory error: Subsequent realloc call failed";
143        break;
145     case ERR_VALUE32_SIZE_ERR:
146        s = "Data format error: End of data on 32 bit value read";
147        break;
149     case ERR_VALUE16_SIZE_ERR:
150        s = "Data format error: End of data on 16 bit value read";
151        break;
153     case ERR_REG32_PARSE_ERROR:
154        s = "Parse error: error parsing after reg32 arg";
155        break;
157     case ERR_DATA32_REMAIN_ERR:
158        s = "Parse error: A remainder size greater then four was found";
159        break;
161     default:
162        s = "Unspecified error";
163        break;
165   }
167   fprintf (stderr, "%s: %s\n", invok, s);
169 } /* showErr */
172 /*************************************************************************************
173  * FUNCTION PURPOSE: Check if a string is prefixed with "0x".
174  *************************************************************************************
175  * DESCRIPTION: Returns non-zero if the string begins with "0x"
176  *************************************************************************************/
177 int isChex (char *s)
179   if ((s[0] == '0') && (s[1] == 'x'))
180     return (1);
182   return (0);
184 } /* isChex */
188 /*************************************************************************************
189  * FUNCTION PURPOSE: Parse the input parameters
190  *************************************************************************************
191  * DESCRIPTION: Checks for required args, opens source and destination streams.
192  *************************************************************************************/
193 int parseit (int argc, char *argv[], FILE **fin, FILE **fout, int *endian)
195   int inspec  = 0;
196   int outspec = 0;
197   int espec   = 0;
198   int c       = 1;
200   char *iname;
201   char *oname;
203   *endian = -1;
205   /* Store the invokation name */
206   invok = argv[0];
208   while (c < argc)  {
210     /* -be | -le */
211     if (!espec)  {
212       if (!strcmp (argv[c], "-be"))  {
213         *endian = BIG;
214         espec = 1;
215         c += 1;
216         continue;
217       } else if (!strcmp (argv[c], "-le"))  {
218         *endian = LITTLE;
219         espec = 1;
220         c += 1;
221         continue;
222       }
223     }
226     /* input file */
227     if (!inspec)  {
228       inspec = 1;
229       iname = argv[c];
230       c += 1;
231       continue;
232     }
234     /* output file */
235     if (!outspec)  {
236       outspec = 1;
237       oname = argv[c];
238       c += 1;
239       continue;
240     }
242     /* Don't know what to do with the arg */
243     return (ERR_PARSE_TOO_MANY_ARGS);
245   }
248   /* Make sure endian is known */
249   if (!espec)
250     return (ERR_PARSE_NO_ENDIAN);
252   /* Open input file if not stdin */
253   if (inspec)  {
254     *fin = fopen (iname, "r");
255     if (*fin == NULL)
256       return (ERR_PARSE_INPUT_OPEN_FAIL);
257   }
259   /* Open output file if not stdin */
260   if (outspec)  {
261     *fout = fopen (oname, "w");
262     if (*fout == NULL)
263       return (ERR_PARSE_OUTPUT_OPEN_FAIL);
264   }
266   return (0);
268 } /* parseit */
272 /***************************************************************************************
273  * FUNCTION PURPOSE: Check if data is ascii
274  ***************************************************************************************
275  * DESCRIPTION: Returns 1 if a byte is 0-9, a-f, 0 otherwise
276  ***************************************************************************************/
277 int asciiByte (unsigned char c)
279   if ((c >= '0') && (c <= '9'))
280     return (1);
282   if ((c >= 'A') && (c <= 'F'))
283     return (1);
285   return (0);
286 } /* asciiByte */
288 /**************************************************************************************
289  * FUNCTION PURPOSE: Returns the binary equivalent of an ascii byte
290  **************************************************************************************
291  * DESCRIPTION: Conversion from ascii to binary
292  **************************************************************************************/
293 int toNum (unsigned char c)
295   if ((c >= '0') && (c <= '9'))
296     return (c - '0');
298   return (c - 'A' + 10);
300 } /* toNum */
303 /**********************************************************************************
304  * FUNCTION PURPOSE: Read a line from a file, toss it
305  **********************************************************************************
306  * DESCRIPTION: Reads a line, including the newline character, and throws it away.
307  **********************************************************************************/
308 void  stripLine (FILE *s)
310   char iline[132];
312   fgets (iline, 131, s);
314 } /* stripLine */
316 /************************************************************************************
317  * FILE PURPOSE: Read the hex55 data file
318  ************************************************************************************
319  * DESCRIPTION: Reads the input data file. Strips the first two lines, reads
320  *              the byte stream.
321  ************************************************************************************/
322 #define MALLOC_BLOCK_SIZE   512000
323 unsigned char *readBFile (FILE *fin, unsigned *n, int *errcode)
325   unsigned char *d;
326   unsigned allocSize;
327   unsigned m;
328   unsigned char x, y;
330   /* Create a block of data */
331   allocSize = MALLOC_BLOCK_SIZE;
332   d = malloc (allocSize * sizeof (unsigned char));
333   if (d == NULL)  {
334     *errcode = ERR_READ_BFILE_INITIAL_MALLOC_FAIL;
335     if (fin != stdin)
336       fclose (fin);
337     return (NULL);
338   }
340   /* Strip the 1st two lines */
341   stripLine (fin);
342   stripLine (fin);
344   *errcode = 0;
345   m = 0;
347   for (;;)  {
349     /* Read the 1st ascii char */
350     do  {
351       x = fgetc (fin);
352       if (x == (unsigned char)EOF)  {
353         *errcode = 0;
354         *n = m;
355         if (fin != stdin)
356           fclose (fin);
357         return (d);
358       }
359     } while (!asciiByte(x));
361     /* Read the next ascii char */
362     y = fgetc(fin);
363     if (y == (unsigned char)EOF)  {
364       *errcode = 0;
365       *n = m;
366       if (fin != stdin)
367         fclose (fin);
368       return (d);
369     }
371     /* Convert the two characters into a byte */
372     if (asciiByte(y))
373       d[m++] = (toNum(x) << 4) | toNum(y);
375     /* Verify memory bounds */
376     if (m >= allocSize)  {
377       allocSize += MALLOC_BLOCK_SIZE;
378       d= realloc (d, allocSize);
379       if (d== NULL)  {
380         *errcode = ERR_READ_BFILE_REALLOC_FAIL;
381         if (fin != stdin)
382           fclose (fin);
383         return (NULL);
384       }
385     }
387   } /* end for */
389 } /* readBFile */
391 /**************************************************************************************
392  * FUNCTION PURPOSE: converts four bytes into an unsigned value
393  **************************************************************************************
394  * DESCRIPTION: Converts bytes to a value
395  **************************************************************************************/
396 unsigned value32bitAdd (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag, unsigned add)
398   unsigned v;
399   unsigned w;
400   unsigned q;
402   /* Verify that there are 4 values still in the character array */
403   if ((*p + 4) > n)  {
404     *errflag = ERR_VALUE32_SIZE_ERR;
405     return (0);
406   }
408   /* Store the original pointer */
409   q = w = *p;
411   v = (unsigned)data[w+0] << 24 |
412       (unsigned)data[w+1] << 16 |
413       (unsigned)data[w+2] <<  8 |
414       (unsigned)data[w+3] <<  0 ;
416   *errflag = 0;
418   /* Add any additional value */
419   v = v + add;
421   /* Write the data back in big endian format */
422   data[q+0] = (v >> 24) & 0xff;
423   data[q+1] = (v >> 16) & 0xff;
424   data[q+2] = (v >>  8) & 0xff;
425   data[q+3] = (v >>  0) & 0xff;
427   *p = q+4;
428   return (v);
430 } /* value32bitAdd */
432 /**************************************************************************************
433  * FUNCTION PURPOSE: converts four bytes into an unsigned value
434  **************************************************************************************
435  * DESCRIPTION: Converts bytes to a value, depending on the endian configuration.
436  **************************************************************************************/
437 unsigned value32bit (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag)
439   return (value32bitAdd (endian, data, n, p, errflag, 0));
441 } /* value32bit */
446 /*********************************************************************************
447  * FUNCTION PURPOSE: Convert up to four bytes to big endian
448  *********************************************************************************
449  * DESCRIPTION: Data bytes are converted.
450  *********************************************************************************/
451 #define SWAP(x,y,z)  (z)=(x);(x)=(y);(y)=(z)
452 void data32bit (int endian, unsigned char *data, unsigned n, unsigned *p, unsigned m, int *errflag)
455   /* Calculate the number of bytes to convert, limited to four bytes */
456   if (m > 4)
457     m = 4;
459   /* return an error if there are not enough values in the array */
460   if ((*p + m) >= n)  {
461     *errflag = ERR_DATA32_SIZE_ERR;
462     return;
463   }
465   /* Clear the error flag */
466   *errflag = 0;
469   /* The data is always already in big endian, there is nothing to do but advance the pointer */
470   *p += m;
472 } /* data32bit */
474 void remain32bit (int endian, unsigned char *data, unsigned n, unsigned *p, unsigned m, int *errflag)
476   unsigned w;
477   unsigned char h;
479   /* return an error if the size is greater then or equal to 4 */
480   if (m >= 4)  {
481     *errflag = ERR_DATA32_REMAIN_ERR;
482     return;
483   }
485   /* return an error if there are not enough values in the array */
486   if ((*p + m) >= n)  {
487     *errflag = ERR_DATA32_SIZE_ERR;
488     return;
489   }
491   w = *p;
493   /* Only swap if endianness is little */
494   if (endian == LITTLE)  {
495     /* Swap the next four bytes */
496     SWAP(data[w+0], data[w+3], h);
497     SWAP(data[w+1], data[w+2], h);
498   }
500   /* Update the full four elements */
501   *p = *p + 4;
504 } /* remain32bit */
507 /*********************************************************************************
508  * FUNCTION PURPOSE: Convert 2 bytes into an unsigned value
509  *********************************************************************************
510  * DESCRIPTION: Converts the next two bytes into an unsigned value based on
511  *              the endian configuration.
512  *********************************************************************************/
513 unsigned value16bit (int endian, unsigned char *data, unsigned n, unsigned *p, int *errflag)
515   unsigned v;
516   unsigned q;
518   /* Verify that there are 4 values still in the character array */
519   if ((*p + 2) > n)  {
520     *errflag = ERR_VALUE16_SIZE_ERR;
521     return (0);
522   }
524   /* Store the original pointer */
525   q = *p;
527   /* convert based on endianness. For little endain the 16 bit words are actually
528    * big endian, but the bytes in those words are not */
529   if (endian == BIG)  {
530     v = data[(*p)++] <<  8 |
531         data[(*p)++] <<  0 ;
533   }  else  {
534     v = data[(*p)++] <<  0 |
535         data[(*p)++] <<  8 ;
536   }
538   *errflag = 0;
540   /* Write the data back in big endian format */
541   data[q++] = (v >>  8) & 0xff;
542   data[q++] = (v >>  0) & 0xff;
544   return (v);
546 } /* value16bit */
548 /**************************************************************************************
549  * FUNCTION PURPOSE: Writes a 16 bit value into the array
550  **************************************************************************************
551  * DESCRIPTION: Writes a big endian 16 bit value, increments the array pointer.
552  **************************************************************************************/
553 void write16bit (unsigned value, unsigned char *data, unsigned *p)
555   data[(*p)++] = (value >> 8) & 0xff;
556   data[(*p)++] = (value >> 0) & 0xff;
558 } /* write16bit */
561 /*************************************************************************************
562  * FUNCTION PURPOSE: Write the output file
563  *************************************************************************************
564  * DESCRIPTION: Writes the resulting output.
565  *************************************************************************************/
566 void writeBFile (FILE *fout, unsigned char *data, unsigned n)
568   unsigned i;
570   /* Write the two line header */
571   fprintf (fout, "%c\n$A000000\n", (unsigned char)2);
573   for (i = 0; i < n; i++)  {
574     if ( ((i+1)%24)  )
575       fprintf (fout, "%02X ", data[i]);
576     else
577       fprintf (fout, "%02X\n", data[i]);
578   }
580   /* Write the close character */
581   fprintf (fout, "\n%c", (unsigned char)3);
583   if (fout != stdout)
584     fclose (fout);
586 } /* writeBFile */
589 /**************************************************************************************
590  * FUNCTION PURPOSE: Main
591  **************************************************************************************
592  * DESCRIPTION: Provides the top level program flow.
593  **************************************************************************************/
594 int main (int argc, char *argv[])
596   FILE *fin;            /* input stream  */
597   FILE *fout;           /* output stream */
599   unsigned char *data;  /* The data set  */
600   unsigned n;           /* Data set size */
601   unsigned p;           /* Data index    */
602   unsigned v;           /* Data value    */
603   unsigned n32;         /* Number of bytes that form complete 32 bit values */
604   unsigned r32;         /* Number of bytes remaining (0-3) */
606   int endian;           /* Endian          */
607   int errflag;          /* error indicator */
608   int i, j;             /* loop var        */
609   int origRegs;         /* original reg count */
610   int shift;            /* data shift amount  */
613   /* Parse the input */
614   if (errflag = parseit (argc, argv, &fin, &fout, &endian))  {
615     showErr (errflag);
616     return (-1);
617   }
619   /* Read the raw data file */
620   data = readBFile (fin, &n, &errflag);
621   if (data == NULL)  {
622     showErr (errflag);
623     return(-1);
624   }
626   /* Parse the sections */
627   p = 0;
629   /* The entry point */
630   v = value32bit (endian, data, n, &p, &errflag);
631   if (errflag)  {
632     showErr (errflag);
633     return(-1);
634   }
637   /* The sections */
638   do  {
640     /* Get the section byte count */
641     v = value32bit (endian, data, n, &p, &errflag);
642     if (errflag)  {
643       showErr (errflag);
644       return(-1);
645     }
647     if (v)  {
648       /* Convert the start address (adjusts the array index) */
649       value32bit (endian, data, n, &p, &errflag);
650       if (errflag)  {
651         showErr (errflag);
652         return(-1);
653       }
654     }
656     /* Determine how many bytes form complete 32 bit fields, and how many are left over */
657     n32 = v & 0xfffffffc;
658     r32 = v & 0x00000003;
660     /* Convert the data to big endian format  */
661     for (i = 0; i < n32; i += 4)  {
662       data32bit (endian, data, n, &p, v-i, &errflag);
663       if (errflag)  {
664         showErr (errflag);
665         return (-1);
666       }
667     }
669     /* Convert any remaining bytes. */
670     if (r32)  {
671       remain32bit (endian, data, n, &p, r32, &errflag);
672       if (errflag)  {
673         showErr (errflag);
674         return (-1);
675       }
676     }
678   } while (v);
680   /*  Write out the data file */
681   writeBFile (fout, data, n);
683   /* Return resources */
684   free (data);
686   return (0);