From d751cecbb1ca1b7ac0a7bc8492e0e61e6c5fc0c7 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Tue, 17 May 2011 20:39:40 +0000 Subject: * tools/build/.cvsignore, tools/build/ChangeLog, tools/build/Makefile.am, tools/build/README, tools/build/binpatch.c, tools/build/cklength.c, tools/build/config.h.in, tools/build/configure.ac, tools/build/cvsignore-add.sh, tools/build/doxy-filter, tools/build/eolstrip.c, tools/build/install-if-change.in, tools/build/multigen, tools/build/packhex.c, tools/build/rtems-bin2c.c, tools/build/search-id.sh, tools/build/unhex.c, tools/cpu/.cvsignore, tools/cpu/ChangeLog, tools/cpu/Makefile.am, tools/cpu/configure.ac, tools/cpu/generic/.cvsignore, tools/cpu/generic/ChangeLog, tools/cpu/generic/Makefile.am, tools/cpu/generic/configure.ac, tools/cpu/generic/size_rtems.in, tools/cpu/nios2/.cvsignore, tools/cpu/nios2/ChangeLog, tools/cpu/nios2/Makefile.am, tools/cpu/nios2/README, tools/cpu/nios2/bridges.c, tools/cpu/nios2/bridges.h, tools/cpu/nios2/clocks.c, tools/cpu/nios2/clocks.h, tools/cpu/nios2/configure.ac, tools/cpu/nios2/devices.c, tools/cpu/nios2/devices.h, tools/cpu/nios2/linkcmds.c, tools/cpu/nios2/linkcmds.h, tools/cpu/nios2/memory.c, tools/cpu/nios2/memory.h, tools/cpu/nios2/nios2gen.c, tools/cpu/nios2/output.c, tools/cpu/nios2/output.h, tools/cpu/nios2/ptf.c, tools/cpu/nios2/ptf.h, tools/cpu/nios2/sample.ptf, tools/cpu/sh/.cvsignore, tools/cpu/sh/AUTHORS, tools/cpu/sh/COPYING, tools/cpu/sh/ChangeLog, tools/cpu/sh/Makefile.am, tools/cpu/sh/TODO, tools/cpu/sh/configure.ac, tools/cpu/sh/sci.c, tools/cpu/sh/sci.h, tools/cpu/sh/shgen.c: New files. --- tools/build/unhex.c | 737 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 737 insertions(+) create mode 100644 tools/build/unhex.c (limited to 'tools/build/unhex.c') diff --git a/tools/build/unhex.c b/tools/build/unhex.c new file mode 100644 index 0000000000..693049f465 --- /dev/null +++ b/tools/build/unhex.c @@ -0,0 +1,737 @@ +/* + * unhex + * convert a hex file to binary equivalent. If more than one file name + * is given, then the output will be logically concatenated together. + * stdin and stdout are defaults. Verbose will enable checksum output. + * + * Supported input formats are Intel hex, Motorola S records, and TI 'B' + * records. + * + * Intel hex input format is + * Byte + * 1 Colon : + * 2..3 Record length, eg: "20" + * 4..7 load address nibbles + * 8..9 record type: "00" (data) or "02" base addr + * 10..x data bytes in ascii-hex + * x+1..x+2 cksum (2's compl of (len+addr+data)) + * x+3 \n -- newline + * + * $Id$ + */ + +char *USAGE = "\ +usage: unhex [-va] [ -o file ] [ file [file ... ] ]\n\ + -v -- verbose\n\ + -a base -- 1st byte of output corresponds to this address\n\ + -l -- linear, just writes data out\n\ + -o file -- output file; must not be input file\n\ + -F k_bits -- \"holes\" in input will be filled with 0xFF's\n\ + up to \"k_bits\" * 1024 bits\n\ +"; + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#ifndef VMS +#ifndef HAVE_STRERROR +extern int sys_nerr; +extern char *sys_errlist[]; + +#define strerror( _err ) \ + ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error" + +#else /* HAVE_STRERROR */ +char *strerror (); +#endif +#else /* VMS */ +char *strerror (int,...); +#endif + + +#define OK 0 +#define FAILURE (-1) +#define Failed(x) ((x) == FAILURE) +#define TRUE 1 +#define FALSE 0 +typedef char bool; +#define STREQ(a,b) (strcmp(a,b) == 0) + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +/* + * Pick out designated bytes + */ + +#define B0(x) ((x) & 0xff) +#define B1(x) B0((x) >> 8) +#define B2(x) B0((x) >> 16) +#define B3(x) B0((x) >> 24) + +typedef struct buffer_rec { + u32 dl_destaddr; + u32 dl_jumpaddr; + int dl_count; + u8 dl_buf[512]; +} buffer_rec; + +/* + * vars controlled by command line options + */ + +bool verbose = FALSE; /* be verbose */ +bool linear = FALSE; /* just write out linear data */ +char *outfilename = "-"; /* default output is stdout */ +u32 base = 0L; /* base address */ +u32 FFfill = 0L; /* how far to fill w 0xFF's */ + +extern char *optarg; /* getopt(3) control vars */ +extern int optind; + +char *progname; /* for error() */ + +void error(int errn, ...); +#define ERR_ERRNO (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */ +#define ERR_FATAL (ERR_ERRNO / 2) /* error is fatal; no return */ +#define ERR_ABORT (ERR_ERRNO / 4) /* error is fatal; abort */ +#define ERR_MASK (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */ + +#ifdef HAVE_STRTOUL +#define stol(p) strtoul(p, (char **) NULL, 0) +#else +#define stol(p) strtol(p, (char **) NULL, 0) +#endif + +int unhex(FILE *ifp, char *inm, FILE *ofp, char *onm); +int convert_Intel_records(FILE *ifp, char *inm, FILE *ofp, char *onm); +int convert_S_records(FILE *ifp, char *inm, FILE *ofp, char *onm); +int convert_TI_records(FILE *ifp, char *inm, FILE *ofp, char *onm); +void write_record(buffer_rec *tb, FILE *fp); +int getnibble(char **p); +int getbyte(char **p); +long getNbytes(char **p, int n); +void badformat(char *s, char *fname, char *msg); + +#define get1bytes(p) ((int) getbyte(p)) +#define get2bytes(p) ((int) getNbytes(p, 2)) +#define get3bytes(p) getNbytes(p, 3) +#define get4bytes(p) getNbytes(p, 4) + +char *BADADDR = "Invalid record address"; +char *BADLEN = "Invalid record length"; +char *BADBASE = "Bad base or starting address"; +char *BADFMT = "Unrecognized record type"; +char *BADDATA = "Invalid data byte"; +char *BADCSUM = "Invalid checksum"; +char *MISCSUM = "Checksum mismatch"; +char *BADTYPE = "Unrecognized record type"; +char *MISTYPE = "Incompatible record types"; + +int main( + int argc, + char **argv +) +{ + register int c; + bool showusage = FALSE; /* usage error? */ + int rc = 0; + FILE *outfp, *infp; + + /* + * figure out invocation leaf-name + */ + + if ((progname = strrchr(argv[0], '/')) == (char *) NULL) + progname = argv[0]; + else + progname++; + + argv[0] = progname; /* for getopt err reporting */ + + /* + * Check options and arguments. + */ + + progname = argv[0]; + while ((c = getopt(argc, argv, "F:a:o:vl")) != EOF) + switch (c) + { + case 'a': /* base address */ + base = stol(optarg); + break; + + case 'l': /* linear output */ + linear = TRUE; + break; + + case 'v': /* toggle verbose */ + verbose = ! verbose; + break; + + case 'o': /* output file */ + outfilename = optarg; + break; + + case 'F': /* 0xFF fill amount (bytes) */ + FFfill = stol(optarg) * 1024L / 8L; + break; + + case '?': + showusage = TRUE; + } + + if (showusage) + { + (void) fprintf(stderr, "%s", USAGE); + exit(1); + } + + if (linear && (base != 0)) + { + error(0, "-l and -a may not be specified in combination"); + exit(1); + } + + if (STREQ(outfilename, "-")) + { + outfp = stdout; + outfilename = "stdout"; + } + else + if ((outfp = fopen(outfilename, "w")) == (FILE *) NULL) + { + error(-1, "couldn't open '%s' for output", outfilename); + exit(1); + } + + /* + * Now process the input files (or stdin, if none specified) + */ + + if (argv[optind] == (char *) NULL) /* just stdin */ + exit(unhex(stdin, "stdin", outfp, outfilename)); + else + for (; (optarg = argv[optind]); optind++) + { + if (STREQ(optarg, "-")) + rc += unhex(stdin, "stdin", outfp, outfilename); + else + { + if ((infp = fopen(optarg, "r")) == (FILE *) NULL) + { + error(-1, "couldn't open '%s' for input", optarg); + exit(1); + } + rc += unhex(infp, optarg, outfp, outfilename); + } + } + + return(rc); +} + +u16 filesum; + +int +unhex(FILE *ifp, + char *inm, + FILE *ofp, + char *onm) +{ + int c; + + filesum = 0; + + /* + * Make sure holes will be filled with 0xFF's if requested. We + * do this the easy way by just filling the file with FF's before + * getting started. To do it more optimally would be quite a bit + * more difficult since the user can skip around as much as he/she + * likes in the input hex file addressing. + * + * We'll clean this up later (after this program has run) with + * 'stripffs' + */ + + if (FFfill) + { + (void) fseek(ofp, 0, 0); + for (c = FFfill; c > 0; c--) + (void) fputc(0xFF, ofp); + } + + /* + * Read the first char from file and determine record types + */ + + if ((c = getc(ifp)) != EOF) + { + ungetc(c, ifp); + switch(c) + { + case 'S': + convert_S_records(ifp, inm, ofp, onm); + break; + + case ':': + convert_Intel_records(ifp, inm, ofp, onm); + break; + + case '9': + case 'B': + convert_TI_records(ifp, inm, ofp, onm); + break; + + default: + { + char tmp[2]; + tmp[0] = c; tmp[1] = 0; + badformat(tmp, inm, BADFMT); + } + } + } + + if (verbose) + fprintf(stderr, "'%s' checksum is 0x%04x\n", inm, filesum); + + return 0; +} + +int +convert_Intel_records( + FILE *ifp, + char *inm, + FILE *ofp, + char *onm) +{ + char buff[512]; + char *p; + u8 cksum; + int incksum; + int c; + int rectype; /* record type */ + int len; /* data length of current line */ + u32 addr; + u32 base_address = 0; + bool endrecord = FALSE; + buffer_rec tb; + + while ( ! endrecord && (fgets(buff, sizeof(buff), ifp))) + { + p = &buff[0]; + + if (p[strlen(p)-1] == '\n') /* get rid of newline */ + p[strlen(p)-1] = '\0'; + + if (p[strlen(p)-1] == '\r') /* get rid of any CR */ + p[strlen(p)-1] = '\0'; + + tb.dl_count = 0; + + if (*p != ':') + badformat(p, inm, BADFMT); + p++; + + if ((len = getbyte(&p)) == -1) /* record len */ + badformat(buff, inm, BADLEN); + + if ((addr = get2bytes(&p)) == -1L) /* record addr */ + badformat(buff, inm, BADADDR); + + rectype = getbyte(&p); + + cksum = len + B0(addr) + B1(addr) + rectype; + + switch (rectype) + { + case 0x00: /* normal data record */ + tb.dl_destaddr = base_address + addr; + while (len--) + { + if ((c = getbyte(&p)) == -1) + badformat(buff, inm, BADDATA); + cksum += c; + filesum += c; + tb.dl_buf[tb.dl_count++] = c; + } + break; + + case 0x01: /* execution start address */ + base_address = addr; + endrecord = TRUE; + break; + + case 0x02: /* new base */ + if ((base_address = get2bytes(&p)) == -1L) + badformat(buff, inm, BADBASE); + cksum += B0(base_address) + B1(base_address); + base_address <<= 4; + break; + + case 0x03: /* seg/off execution start address */ + { + u32 seg, off; + + seg = get2bytes(&p); + off = get2bytes(&p); + if ((seg == -1L) || (off == -1L)) + badformat(buff, inm, BADADDR); + + cksum += B0(seg) + B1(seg) + B0(off) + B1(off); + + tb.dl_jumpaddr = (seg << 4) + off; + break; + } + + default: + error(0, "unknown Intel-hex record type: 0x%02x", rectype); + badformat(buff, inm, BADTYPE); + } + + /* + * Verify checksums are correct in file. + */ + + cksum = (-cksum) & 0xff; + if ((incksum = getbyte(&p)) == -1) + badformat(buff, inm, BADCSUM); + if (((u8) incksum) != cksum) + badformat(buff, inm, MISCSUM); + + if (tb.dl_count) + write_record(&tb, ofp); + } + return 0; +} + +int +convert_S_records( + FILE *ifp, + char *inm, + FILE *ofp, + char *onm) +{ + char buff[512]; + char *p; + u8 cksum; + int incksum; + int c; + int len; /* data length of current line */ + int rectype; /* record type */ + u32 addr; + bool endrecord = FALSE; + buffer_rec tb; + + while ( ! endrecord && (fgets(buff, sizeof(buff), ifp))) + { + p = &buff[0]; + + if (p[strlen(p)-1] == '\n') /* get rid of newline */ + p[strlen(p)-1] = '\0'; + + if (p[strlen(p)-1] == '\r') /* get rid of any CR */ + p[strlen(p)-1] = '\0'; + + tb.dl_count = 0; + + if (*p != 'S') + badformat(p, inm, BADFMT); + p++; + + if ((rectype = getnibble(&p)) == -1) /* record type */ + badformat(buff, inm, BADTYPE); + + if ((len = getbyte(&p)) == -1) /* record len */ + badformat(buff, inm, BADLEN); + cksum = len; + + switch (rectype) + { + case 0x00: /* comment field, ignored */ + goto write_it; + + case 0x01: /* data record, 16 bit addr */ + if ((addr = get2bytes(&p)) == -1L) + badformat(buff, inm, BADADDR); + len -= 3; + goto doit; + + case 0x02: /* ... 24 bit addr */ + if ((addr = get3bytes(&p)) == -1L) + badformat(buff, inm, BADADDR); + len -= 4; + goto doit; + + case 0x03: /* ... 32 bit addr */ + if ((addr = get4bytes(&p)) == -1L) + badformat(buff, inm, BADADDR); + len -= 5; + doit: + cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr); + + tb.dl_destaddr = addr; + while (len--) + { + if ((c = getbyte(&p)) == -1) + badformat(buff, inm, BADDATA); + cksum += c; + filesum += c; + tb.dl_buf[tb.dl_count++] = c; + } + break; + + case 0x07: /* 32 bit end record */ + if ((addr = get4bytes(&p)) == -1L) + badformat(buff, inm, BADADDR); + goto end_rec; + + case 0x08: /* 24 bit end record */ + if ((addr = get3bytes(&p)) == -1L) + badformat(buff, inm, BADADDR); + goto end_rec; + + case 0x09: /* 16 bit end record */ + if ((addr = get2bytes(&p)) == -1L) + badformat(buff, inm, BADADDR); + +end_rec: + cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr); + tb.dl_jumpaddr = addr; + break; + + default: + error(0, "unknown Motorola-S record type: 0x%02x", rectype); + badformat(buff, inm, BADTYPE); + break; + } + + /* + * Verify checksums are correct in file. + */ + + cksum = (~cksum) & 0xff; + if ((incksum = getbyte(&p)) == -1) + badformat(buff, inm, BADCSUM); + if (((u8) incksum) != cksum) + badformat(buff, inm, MISCSUM); + +write_it: + if (tb.dl_count) + write_record(&tb, ofp); + } + return 0; +} + +int +convert_TI_records( + FILE *ifp, + char *inm, + FILE *ofp, + char *onm) +{ + char buff[512]; + char *p; + int c; + bool endrecord = FALSE; + bool eol; + buffer_rec tb; + + while ( ! endrecord && (fgets(buff, sizeof(buff), ifp))) + { + if (p[strlen(p)-1] == '\n') /* get rid of newline */ + p[strlen(p)-1] = '\0'; + + if (p[strlen(p)-1] == '\r') /* get rid of any CR */ + p[strlen(p)-1] = '\0'; + + tb.dl_count = 0; + + p = &buff[0]; + eol = FALSE; + while ( ! eol && ! endrecord) + { + switch (*p++) + { + case '9': + if (tb.dl_count) + write_record(&tb, ofp); + tb.dl_destaddr = get2bytes(&p); + break; + + case 'B': + c = getbyte(&p); + filesum += c; + tb.dl_buf[tb.dl_count++] = c; + c = getbyte(&p); + filesum += c; + tb.dl_buf[tb.dl_count++] = c; + break; + + case 'F': + eol = TRUE; + break; + + case ':': + endrecord = TRUE; + break; + + default: + badformat(p, inm, BADFMT); + } + } + if (tb.dl_count) + write_record(&tb, ofp); + } + return 0; +} + +void +write_record(buffer_rec *tb, + FILE *fp) +{ + if ( ! linear) + { + if (tb->dl_destaddr < base) + error(ERR_FATAL, "record at address 0x%x precedes base of 0x%x", + tb->dl_destaddr, base); + (void) fseek(fp, tb->dl_destaddr - base, 0); + } + + (void) fwrite(tb->dl_buf, tb->dl_count, 1, fp); + tb->dl_destaddr += tb->dl_count; + tb->dl_count = 0; +} + +int +getnibble(char **p) +{ + register int val; + + **p = toupper(**p); + switch (**p) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + val = **p - '0'; + break; + + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + val = 10 + (**p - 'A'); + break; + + default: + return(-1); + } + *p += 1; + + return(val & 0x0f); +} + +int +getbyte(char **p) +{ + int n0, n1; + + if ((n0 = getnibble(p)) == -1) + return(-1); + if ((n1 = getnibble(p)) == -1) + return(-1); + + return(((n0 << 4) + n1) & 0xff); +} + +long +getNbytes(char **p, + int n) +{ + int t; + u32 val = 0; + + while (n--) + { + if ((t = getbyte(p)) == -1) + return(-1L); + val <<= 8; + val += t; + } + + return(val); +} + +void +badformat(char *s, + char *fname, + char *msg) +{ + if (s[strlen(s)-1] == '\n') /* get rid of newline */ + s[strlen(s)-1] = '\0'; + error(0, "line '%s'::\n\tfrom file '%s'; %s", s, fname, msg); + exit(1); +} + +/* + * error(errn, arglist) + * report an error to stderr using printf(3) conventions. + * Any output is preceded by ': ' + * + * Uses ERR_EXIT bit to request exit(errn) + * ERR_ABORT to request abort() + * ERR_ERRNO to indicate use of errno instead of argument. + * + * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its + * associated error message is appended to the output. + */ + +/*VARARGS*/ + +void +error(int error_flag, ...) +{ + va_list arglist; + register char *format; + int local_errno; + + extern int errno; + + (void) fflush(stdout); /* in case stdout/stderr same */ + + local_errno = error_flag & ~ERR_MASK; + if (error_flag & ERR_ERRNO) /* use errno? */ + local_errno = errno; + + va_start(arglist, error_flag); + format = va_arg(arglist, char *); + (void) fprintf(stderr, "%s: ", progname); + (void) vfprintf(stderr, format, arglist); + va_end(arglist); + + if (local_errno) + (void) fprintf(stderr, " (%s)\n", strerror(local_errno)); + else + (void) fprintf(stderr, "\n"); + + (void) fflush(stderr); + + if (error_flag & (ERR_FATAL | ERR_ABORT)) + { + if (error_flag & ERR_FATAL) + { + error(0, "fatal error, exiting"); + exit(local_errno ? local_errno : 1); + } + else + { + error(0, "fatal error, aborting"); + abort(); + } + } +} -- cgit v1.2.3