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)
121 {
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)
182 {
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)
198 {
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 }
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)
282 {
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)
298 {
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)
313 {
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)
328 {
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)
401 {
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)
442 {
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)
457 {
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)
479 {
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)
518 {
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)
558 {
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)
571 {
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 */
593 /**************************************************************************************
594 * FUNCTION PURPOSE: Main
595 **************************************************************************************
596 * DESCRIPTION: Provides the top level program flow.
597 **************************************************************************************/
598 int main (int argc, char *argv[])
599 {
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 {
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);
691 }