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)
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\n", invok, s);
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)
145 {
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)
161 {
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 }
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)
245 {
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)
261 {
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)
276 {
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)
291 {
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)
364 {
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)
405 {
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)
420 {
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)
442 {
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)
481 {
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)
521 {
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)
534 {
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 */
556 /**************************************************************************************
557 * FUNCTION PURPOSE: Main
558 **************************************************************************************
559 * DESCRIPTION: Provides the top level program flow.
560 **************************************************************************************/
561 int main (int argc, char *argv[])
562 {
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);
583 return (-1);
584 }
586 /* Read the raw data file */
587 data = readBFile (fin, &n, &errflag);
588 if (data == NULL) {
589 showErr (errflag);
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);
600 return(-1);
601 }
604 /* The sections */
605 do {
607 /* Get the section byte count */
608 v = value32bit (endian, data, n, &p, &errflag);
609 if (errflag) {
610 showErr (errflag);
611 return(-1);
612 }
614 if (v) {
615 /* Convert the start address (adjusts the array index) */
616 value32bit (endian, data, n, &p, &errflag);
617 if (errflag) {
618 showErr (errflag);
619 return(-1);
620 }
621 }
623 /* Determine how many bytes form complete 32 bit fields, and how many are left over */
624 n32 = v & 0xfffffffc;
625 r32 = v & 0x00000003;
627 /* Convert the data to big endian format */
628 for (i = 0; i < n32; i += 4) {
629 data32bit (endian, data, n, &p, v-i, &errflag);
630 if (errflag) {
631 showErr (errflag);
632 return (-1);
633 }
634 }
636 /* Convert any remaining bytes. */
637 if (r32) {
638 remain32bit (endian, data, n, &p, r32, &errflag);
639 if (errflag) {
640 showErr (errflag);
641 return (-1);
642 }
643 }
645 } while (v);
647 /* Write out the data file */
648 writeBFile (fout, data, n);
650 /* Return resources */
651 free (data);
653 return (0);
655 }