/*
|
/*
|
* unhex
|
* unhex
|
* convert a hex file to binary equivalent. If more than one file name
|
* convert a hex file to binary equivalent. If more than one file name
|
* is given, then the output will be logically concatenated together.
|
* is given, then the output will be logically concatenated together.
|
* stdin and stdout are defaults. Verbose will enable checksum output.
|
* stdin and stdout are defaults. Verbose will enable checksum output.
|
*
|
*
|
* Supported input formats are Intel hex, Motorola S records, and TI 'B'
|
* Supported input formats are Intel hex, Motorola S records, and TI 'B'
|
* records.
|
* records.
|
*
|
*
|
* Intel hex input format is
|
* Intel hex input format is
|
* Byte
|
* Byte
|
* 1 Colon :
|
* 1 Colon :
|
* 2..3 Record length, eg: "20"
|
* 2..3 Record length, eg: "20"
|
* 4..7 load address nibbles
|
* 4..7 load address nibbles
|
* 8..9 record type: "00" (data) or "02" base addr
|
* 8..9 record type: "00" (data) or "02" base addr
|
* 10..x data bytes in ascii-hex
|
* 10..x data bytes in ascii-hex
|
* x+1..x+2 cksum (2's compl of (len+addr+data))
|
* x+1..x+2 cksum (2's compl of (len+addr+data))
|
* x+3 \n -- newline
|
* x+3 \n -- newline
|
*
|
*
|
* $Id: unhex.c,v 1.2 2001-09-27 12:02:53 chris Exp $
|
* $Id: unhex.c,v 1.2 2001-09-27 12:02:53 chris Exp $
|
*/
|
*/
|
|
|
char *USAGE = "\
|
char *USAGE = "\
|
usage: unhex [-va] [ -o file ] [ file [file ... ] ]\n\
|
usage: unhex [-va] [ -o file ] [ file [file ... ] ]\n\
|
-v -- verbose\n\
|
-v -- verbose\n\
|
-a base -- 1st byte of output corresponds to this address\n\
|
-a base -- 1st byte of output corresponds to this address\n\
|
-l -- linear, just writes data out\n\
|
-l -- linear, just writes data out\n\
|
-o file -- output file; must not be input file\n\
|
-o file -- output file; must not be input file\n\
|
-F k_bits -- \"holes\" in input will be filled with 0xFF's\n\
|
-F k_bits -- \"holes\" in input will be filled with 0xFF's\n\
|
up to \"k_bits\" * 1024 bits\n\
|
up to \"k_bits\" * 1024 bits\n\
|
";
|
";
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
#include <string.h>
|
#include <string.h>
|
#include <unistd.h>
|
#include <unistd.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <stdarg.h>
|
#include <stdarg.h>
|
#include <errno.h>
|
#include <errno.h>
|
|
|
#include "config.h"
|
#include "config.h"
|
|
|
#ifndef VMS
|
#ifndef VMS
|
#ifndef HAVE_STRERROR
|
#ifndef HAVE_STRERROR
|
extern int sys_nerr;
|
extern int sys_nerr;
|
extern char *sys_errlist[];
|
extern char *sys_errlist[];
|
|
|
#define strerror( _err ) \
|
#define strerror( _err ) \
|
((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error"
|
((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error"
|
|
|
#else /* HAVE_STRERROR */
|
#else /* HAVE_STRERROR */
|
char *strerror ();
|
char *strerror ();
|
#endif
|
#endif
|
#else /* VMS */
|
#else /* VMS */
|
char *strerror (int,...);
|
char *strerror (int,...);
|
#endif
|
#endif
|
|
|
|
|
#define OK 0
|
#define OK 0
|
#define FAILURE (-1)
|
#define FAILURE (-1)
|
#define Failed(x) ((x) == FAILURE)
|
#define Failed(x) ((x) == FAILURE)
|
#define TRUE 1
|
#define TRUE 1
|
#define FALSE 0
|
#define FALSE 0
|
typedef char bool;
|
typedef char bool;
|
#define STREQ(a,b) (strcmp(a,b) == 0)
|
#define STREQ(a,b) (strcmp(a,b) == 0)
|
|
|
typedef unsigned char u8;
|
typedef unsigned char u8;
|
typedef unsigned short u16;
|
typedef unsigned short u16;
|
typedef unsigned long u32;
|
typedef unsigned long u32;
|
|
|
/*
|
/*
|
* Pick out designated bytes
|
* Pick out designated bytes
|
*/
|
*/
|
|
|
#define B0(x) ((x) & 0xff)
|
#define B0(x) ((x) & 0xff)
|
#define B1(x) B0((x) >> 8)
|
#define B1(x) B0((x) >> 8)
|
#define B2(x) B0((x) >> 16)
|
#define B2(x) B0((x) >> 16)
|
#define B3(x) B0((x) >> 24)
|
#define B3(x) B0((x) >> 24)
|
|
|
typedef struct buffer_rec {
|
typedef struct buffer_rec {
|
u32 dl_destaddr;
|
u32 dl_destaddr;
|
u32 dl_jumpaddr;
|
u32 dl_jumpaddr;
|
int dl_count;
|
int dl_count;
|
u8 dl_buf[512];
|
u8 dl_buf[512];
|
} buffer_rec;
|
} buffer_rec;
|
|
|
/*
|
/*
|
* vars controlled by command line options
|
* vars controlled by command line options
|
*/
|
*/
|
|
|
bool verbose = FALSE; /* be verbose */
|
bool verbose = FALSE; /* be verbose */
|
bool linear = FALSE; /* just write out linear data */
|
bool linear = FALSE; /* just write out linear data */
|
char *outfilename = "-"; /* default output is stdout */
|
char *outfilename = "-"; /* default output is stdout */
|
u32 base = 0L; /* base address */
|
u32 base = 0L; /* base address */
|
u32 FFfill = 0L; /* how far to fill w 0xFF's */
|
u32 FFfill = 0L; /* how far to fill w 0xFF's */
|
|
|
extern char *optarg; /* getopt(3) control vars */
|
extern char *optarg; /* getopt(3) control vars */
|
extern int optind;
|
extern int optind;
|
|
|
char *progname; /* for error() */
|
char *progname; /* for error() */
|
|
|
void error(int errn, ...);
|
void error(int errn, ...);
|
#define ERR_ERRNO (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
|
#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_FATAL (ERR_ERRNO / 2) /* error is fatal; no return */
|
#define ERR_ABORT (ERR_ERRNO / 4) /* error is fatal; abort */
|
#define ERR_ABORT (ERR_ERRNO / 4) /* error is fatal; abort */
|
#define ERR_MASK (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
|
#define ERR_MASK (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
|
|
|
#ifdef HAVE_STRTOUL
|
#ifdef HAVE_STRTOUL
|
#define stol(p) strtoul(p, (char **) NULL, 0)
|
#define stol(p) strtoul(p, (char **) NULL, 0)
|
#else
|
#else
|
#define stol(p) strtol(p, (char **) NULL, 0)
|
#define stol(p) strtol(p, (char **) NULL, 0)
|
#endif
|
#endif
|
|
|
int unhex(FILE *ifp, char *inm, FILE *ofp, char *onm);
|
int unhex(FILE *ifp, char *inm, FILE *ofp, char *onm);
|
int convert_Intel_records(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_S_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
|
int convert_TI_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);
|
void write_record(buffer_rec *tb, FILE *fp);
|
int getnibble(char **p);
|
int getnibble(char **p);
|
int getbyte(char **p);
|
int getbyte(char **p);
|
long getNbytes(char **p, int n);
|
long getNbytes(char **p, int n);
|
void badformat(char *s, char *fname, char *msg);
|
void badformat(char *s, char *fname, char *msg);
|
|
|
#define get1bytes(p) ((int) getbyte(p))
|
#define get1bytes(p) ((int) getbyte(p))
|
#define get2bytes(p) ((int) getNbytes(p, 2))
|
#define get2bytes(p) ((int) getNbytes(p, 2))
|
#define get3bytes(p) getNbytes(p, 3)
|
#define get3bytes(p) getNbytes(p, 3)
|
#define get4bytes(p) getNbytes(p, 4)
|
#define get4bytes(p) getNbytes(p, 4)
|
|
|
char *BADADDR = "Invalid record address";
|
char *BADADDR = "Invalid record address";
|
char *BADLEN = "Invalid record length";
|
char *BADLEN = "Invalid record length";
|
char *BADBASE = "Bad base or starting address";
|
char *BADBASE = "Bad base or starting address";
|
char *BADFMT = "Unrecognized record type";
|
char *BADFMT = "Unrecognized record type";
|
char *BADDATA = "Invalid data byte";
|
char *BADDATA = "Invalid data byte";
|
char *BADCSUM = "Invalid checksum";
|
char *BADCSUM = "Invalid checksum";
|
char *MISCSUM = "Checksum mismatch";
|
char *MISCSUM = "Checksum mismatch";
|
char *BADTYPE = "Unrecognized record type";
|
char *BADTYPE = "Unrecognized record type";
|
char *MISTYPE = "Incompatible record types";
|
char *MISTYPE = "Incompatible record types";
|
|
|
int main(
|
int main(
|
int argc,
|
int argc,
|
char **argv
|
char **argv
|
)
|
)
|
{
|
{
|
register int c;
|
register int c;
|
bool showusage = FALSE; /* usage error? */
|
bool showusage = FALSE; /* usage error? */
|
int rc = 0;
|
int rc = 0;
|
FILE *outfp, *infp;
|
FILE *outfp, *infp;
|
|
|
/*
|
/*
|
* figure out invocation leaf-name
|
* figure out invocation leaf-name
|
*/
|
*/
|
|
|
if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
|
if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
|
progname = argv[0];
|
progname = argv[0];
|
else
|
else
|
progname++;
|
progname++;
|
|
|
argv[0] = progname; /* for getopt err reporting */
|
argv[0] = progname; /* for getopt err reporting */
|
|
|
/*
|
/*
|
* Check options and arguments.
|
* Check options and arguments.
|
*/
|
*/
|
|
|
progname = argv[0];
|
progname = argv[0];
|
while ((c = getopt(argc, argv, "F:a:o:vl")) != EOF)
|
while ((c = getopt(argc, argv, "F:a:o:vl")) != EOF)
|
switch (c)
|
switch (c)
|
{
|
{
|
case 'a': /* base address */
|
case 'a': /* base address */
|
base = stol(optarg);
|
base = stol(optarg);
|
break;
|
break;
|
|
|
case 'l': /* linear output */
|
case 'l': /* linear output */
|
linear = TRUE;
|
linear = TRUE;
|
break;
|
break;
|
|
|
case 'v': /* toggle verbose */
|
case 'v': /* toggle verbose */
|
verbose = ! verbose;
|
verbose = ! verbose;
|
break;
|
break;
|
|
|
case 'o': /* output file */
|
case 'o': /* output file */
|
outfilename = optarg;
|
outfilename = optarg;
|
break;
|
break;
|
|
|
case 'F': /* 0xFF fill amount (bytes) */
|
case 'F': /* 0xFF fill amount (bytes) */
|
FFfill = stol(optarg) * 1024L / 8L;
|
FFfill = stol(optarg) * 1024L / 8L;
|
break;
|
break;
|
|
|
case '?':
|
case '?':
|
showusage = TRUE;
|
showusage = TRUE;
|
}
|
}
|
|
|
if (showusage)
|
if (showusage)
|
{
|
{
|
(void) fprintf(stderr, "%s", USAGE);
|
(void) fprintf(stderr, "%s", USAGE);
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
if (linear && (base != 0))
|
if (linear && (base != 0))
|
{
|
{
|
error(0, "-l and -a may not be specified in combination");
|
error(0, "-l and -a may not be specified in combination");
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
if (STREQ(outfilename, "-"))
|
if (STREQ(outfilename, "-"))
|
{
|
{
|
outfp = stdout;
|
outfp = stdout;
|
outfilename = "stdout";
|
outfilename = "stdout";
|
}
|
}
|
else
|
else
|
if ((outfp = fopen(outfilename, "w")) == (FILE *) NULL)
|
if ((outfp = fopen(outfilename, "w")) == (FILE *) NULL)
|
{
|
{
|
error(-1, "couldn't open '%s' for output", outfilename);
|
error(-1, "couldn't open '%s' for output", outfilename);
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
/*
|
/*
|
* Now process the input files (or stdin, if none specified)
|
* Now process the input files (or stdin, if none specified)
|
*/
|
*/
|
|
|
if (argv[optind] == (char *) NULL) /* just stdin */
|
if (argv[optind] == (char *) NULL) /* just stdin */
|
exit(unhex(stdin, "stdin", outfp, outfilename));
|
exit(unhex(stdin, "stdin", outfp, outfilename));
|
else
|
else
|
for (; (optarg = argv[optind]); optind++)
|
for (; (optarg = argv[optind]); optind++)
|
{
|
{
|
if (STREQ(optarg, "-"))
|
if (STREQ(optarg, "-"))
|
rc += unhex(stdin, "stdin", outfp, outfilename);
|
rc += unhex(stdin, "stdin", outfp, outfilename);
|
else
|
else
|
{
|
{
|
if ((infp = fopen(optarg, "r")) == (FILE *) NULL)
|
if ((infp = fopen(optarg, "r")) == (FILE *) NULL)
|
{
|
{
|
error(-1, "couldn't open '%s' for input", optarg);
|
error(-1, "couldn't open '%s' for input", optarg);
|
exit(1);
|
exit(1);
|
}
|
}
|
rc += unhex(infp, optarg, outfp, outfilename);
|
rc += unhex(infp, optarg, outfp, outfilename);
|
}
|
}
|
}
|
}
|
|
|
return(rc);
|
return(rc);
|
}
|
}
|
|
|
u16 filesum;
|
u16 filesum;
|
|
|
int
|
int
|
unhex(FILE *ifp,
|
unhex(FILE *ifp,
|
char *inm,
|
char *inm,
|
FILE *ofp,
|
FILE *ofp,
|
char *onm)
|
char *onm)
|
{
|
{
|
int c;
|
int c;
|
|
|
filesum = 0;
|
filesum = 0;
|
|
|
/*
|
/*
|
* Make sure holes will be filled with 0xFF's if requested. We
|
* 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
|
* 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
|
* 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
|
* more difficult since the user can skip around as much as he/she
|
* likes in the input hex file addressing.
|
* likes in the input hex file addressing.
|
*
|
*
|
* We'll clean this up later (after this program has run) with
|
* We'll clean this up later (after this program has run) with
|
* 'stripffs'
|
* 'stripffs'
|
*/
|
*/
|
|
|
if (FFfill)
|
if (FFfill)
|
{
|
{
|
(void) fseek(ofp, 0, 0);
|
(void) fseek(ofp, 0, 0);
|
for (c = FFfill; c > 0; c--)
|
for (c = FFfill; c > 0; c--)
|
(void) fputc(0xFF, ofp);
|
(void) fputc(0xFF, ofp);
|
}
|
}
|
|
|
/*
|
/*
|
* Read the first char from file and determine record types
|
* Read the first char from file and determine record types
|
*/
|
*/
|
|
|
if ((c = getc(ifp)) != EOF)
|
if ((c = getc(ifp)) != EOF)
|
{
|
{
|
ungetc(c, ifp);
|
ungetc(c, ifp);
|
switch(c)
|
switch(c)
|
{
|
{
|
case 'S':
|
case 'S':
|
convert_S_records(ifp, inm, ofp, onm);
|
convert_S_records(ifp, inm, ofp, onm);
|
break;
|
break;
|
|
|
case ':':
|
case ':':
|
convert_Intel_records(ifp, inm, ofp, onm);
|
convert_Intel_records(ifp, inm, ofp, onm);
|
break;
|
break;
|
|
|
case '9':
|
case '9':
|
case 'B':
|
case 'B':
|
convert_TI_records(ifp, inm, ofp, onm);
|
convert_TI_records(ifp, inm, ofp, onm);
|
break;
|
break;
|
|
|
default:
|
default:
|
{
|
{
|
char tmp[2];
|
char tmp[2];
|
tmp[0] = c; tmp[1] = 0;
|
tmp[0] = c; tmp[1] = 0;
|
badformat(tmp, inm, BADFMT);
|
badformat(tmp, inm, BADFMT);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
if (verbose)
|
if (verbose)
|
fprintf(stderr, "'%s' checksum is 0x%04x\n", inm, filesum);
|
fprintf(stderr, "'%s' checksum is 0x%04x\n", inm, filesum);
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int
|
int
|
convert_Intel_records(
|
convert_Intel_records(
|
FILE *ifp,
|
FILE *ifp,
|
char *inm,
|
char *inm,
|
FILE *ofp,
|
FILE *ofp,
|
char *onm)
|
char *onm)
|
{
|
{
|
char buff[512];
|
char buff[512];
|
char *p;
|
char *p;
|
u8 cksum;
|
u8 cksum;
|
int incksum;
|
int incksum;
|
int c;
|
int c;
|
int rectype; /* record type */
|
int rectype; /* record type */
|
int len; /* data length of current line */
|
int len; /* data length of current line */
|
u32 addr;
|
u32 addr;
|
u32 base_address = 0;
|
u32 base_address = 0;
|
bool endrecord = FALSE;
|
bool endrecord = FALSE;
|
buffer_rec tb;
|
buffer_rec tb;
|
|
|
while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
|
while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
|
{
|
{
|
p = &buff[0];
|
p = &buff[0];
|
|
|
if (p[strlen(p)-1] == '\n') /* get rid of newline */
|
if (p[strlen(p)-1] == '\n') /* get rid of newline */
|
p[strlen(p)-1] = '\0';
|
p[strlen(p)-1] = '\0';
|
|
|
if (p[strlen(p)-1] == '\r') /* get rid of any CR */
|
if (p[strlen(p)-1] == '\r') /* get rid of any CR */
|
p[strlen(p)-1] = '\0';
|
p[strlen(p)-1] = '\0';
|
|
|
tb.dl_count = 0;
|
tb.dl_count = 0;
|
|
|
if (*p != ':')
|
if (*p != ':')
|
badformat(p, inm, BADFMT);
|
badformat(p, inm, BADFMT);
|
p++;
|
p++;
|
|
|
if ((len = getbyte(&p)) == -1) /* record len */
|
if ((len = getbyte(&p)) == -1) /* record len */
|
badformat(buff, inm, BADLEN);
|
badformat(buff, inm, BADLEN);
|
|
|
if ((addr = get2bytes(&p)) == -1L) /* record addr */
|
if ((addr = get2bytes(&p)) == -1L) /* record addr */
|
badformat(buff, inm, BADADDR);
|
badformat(buff, inm, BADADDR);
|
|
|
rectype = getbyte(&p);
|
rectype = getbyte(&p);
|
|
|
cksum = len + B0(addr) + B1(addr) + rectype;
|
cksum = len + B0(addr) + B1(addr) + rectype;
|
|
|
switch (rectype)
|
switch (rectype)
|
{
|
{
|
case 0x00: /* normal data record */
|
case 0x00: /* normal data record */
|
tb.dl_destaddr = base_address + addr;
|
tb.dl_destaddr = base_address + addr;
|
while (len--)
|
while (len--)
|
{
|
{
|
if ((c = getbyte(&p)) == -1)
|
if ((c = getbyte(&p)) == -1)
|
badformat(buff, inm, BADDATA);
|
badformat(buff, inm, BADDATA);
|
cksum += c;
|
cksum += c;
|
filesum += c;
|
filesum += c;
|
tb.dl_buf[tb.dl_count++] = c;
|
tb.dl_buf[tb.dl_count++] = c;
|
}
|
}
|
break;
|
break;
|
|
|
case 0x01: /* execution start address */
|
case 0x01: /* execution start address */
|
base_address = addr;
|
base_address = addr;
|
endrecord = TRUE;
|
endrecord = TRUE;
|
break;
|
break;
|
|
|
case 0x02: /* new base */
|
case 0x02: /* new base */
|
if ((base_address = get2bytes(&p)) == -1L)
|
if ((base_address = get2bytes(&p)) == -1L)
|
badformat(buff, inm, BADBASE);
|
badformat(buff, inm, BADBASE);
|
cksum += B0(base_address) + B1(base_address);
|
cksum += B0(base_address) + B1(base_address);
|
base_address <<= 4;
|
base_address <<= 4;
|
break;
|
break;
|
|
|
case 0x03: /* seg/off execution start address */
|
case 0x03: /* seg/off execution start address */
|
{
|
{
|
u32 seg, off;
|
u32 seg, off;
|
|
|
seg = get2bytes(&p);
|
seg = get2bytes(&p);
|
off = get2bytes(&p);
|
off = get2bytes(&p);
|
if ((seg == -1L) || (off == -1L))
|
if ((seg == -1L) || (off == -1L))
|
badformat(buff, inm, BADADDR);
|
badformat(buff, inm, BADADDR);
|
|
|
cksum += B0(seg) + B1(seg) + B0(off) + B1(off);
|
cksum += B0(seg) + B1(seg) + B0(off) + B1(off);
|
|
|
tb.dl_jumpaddr = (seg << 4) + off;
|
tb.dl_jumpaddr = (seg << 4) + off;
|
break;
|
break;
|
}
|
}
|
|
|
default:
|
default:
|
error(0, "unknown Intel-hex record type: 0x%02x", rectype);
|
error(0, "unknown Intel-hex record type: 0x%02x", rectype);
|
badformat(buff, inm, BADTYPE);
|
badformat(buff, inm, BADTYPE);
|
}
|
}
|
|
|
/*
|
/*
|
* Verify checksums are correct in file.
|
* Verify checksums are correct in file.
|
*/
|
*/
|
|
|
cksum = (-cksum) & 0xff;
|
cksum = (-cksum) & 0xff;
|
if ((incksum = getbyte(&p)) == -1)
|
if ((incksum = getbyte(&p)) == -1)
|
badformat(buff, inm, BADCSUM);
|
badformat(buff, inm, BADCSUM);
|
if (((u8) incksum) != cksum)
|
if (((u8) incksum) != cksum)
|
badformat(buff, inm, MISCSUM);
|
badformat(buff, inm, MISCSUM);
|
|
|
if (tb.dl_count)
|
if (tb.dl_count)
|
write_record(&tb, ofp);
|
write_record(&tb, ofp);
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int
|
int
|
convert_S_records(
|
convert_S_records(
|
FILE *ifp,
|
FILE *ifp,
|
char *inm,
|
char *inm,
|
FILE *ofp,
|
FILE *ofp,
|
char *onm)
|
char *onm)
|
{
|
{
|
char buff[512];
|
char buff[512];
|
char *p;
|
char *p;
|
u8 cksum;
|
u8 cksum;
|
int incksum;
|
int incksum;
|
int c;
|
int c;
|
int len; /* data length of current line */
|
int len; /* data length of current line */
|
int rectype; /* record type */
|
int rectype; /* record type */
|
u32 addr;
|
u32 addr;
|
bool endrecord = FALSE;
|
bool endrecord = FALSE;
|
buffer_rec tb;
|
buffer_rec tb;
|
|
|
while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
|
while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
|
{
|
{
|
p = &buff[0];
|
p = &buff[0];
|
|
|
if (p[strlen(p)-1] == '\n') /* get rid of newline */
|
if (p[strlen(p)-1] == '\n') /* get rid of newline */
|
p[strlen(p)-1] = '\0';
|
p[strlen(p)-1] = '\0';
|
|
|
if (p[strlen(p)-1] == '\r') /* get rid of any CR */
|
if (p[strlen(p)-1] == '\r') /* get rid of any CR */
|
p[strlen(p)-1] = '\0';
|
p[strlen(p)-1] = '\0';
|
|
|
tb.dl_count = 0;
|
tb.dl_count = 0;
|
|
|
if (*p != 'S')
|
if (*p != 'S')
|
badformat(p, inm, BADFMT);
|
badformat(p, inm, BADFMT);
|
p++;
|
p++;
|
|
|
if ((rectype = getnibble(&p)) == -1) /* record type */
|
if ((rectype = getnibble(&p)) == -1) /* record type */
|
badformat(buff, inm, BADTYPE);
|
badformat(buff, inm, BADTYPE);
|
|
|
if ((len = getbyte(&p)) == -1) /* record len */
|
if ((len = getbyte(&p)) == -1) /* record len */
|
badformat(buff, inm, BADLEN);
|
badformat(buff, inm, BADLEN);
|
cksum = len;
|
cksum = len;
|
|
|
switch (rectype)
|
switch (rectype)
|
{
|
{
|
case 0x00: /* comment field, ignored */
|
case 0x00: /* comment field, ignored */
|
goto write_it;
|
goto write_it;
|
|
|
case 0x01: /* data record, 16 bit addr */
|
case 0x01: /* data record, 16 bit addr */
|
if ((addr = get2bytes(&p)) == -1L)
|
if ((addr = get2bytes(&p)) == -1L)
|
badformat(buff, inm, BADADDR);
|
badformat(buff, inm, BADADDR);
|
len -= 3;
|
len -= 3;
|
goto doit;
|
goto doit;
|
|
|
case 0x02: /* ... 24 bit addr */
|
case 0x02: /* ... 24 bit addr */
|
if ((addr = get3bytes(&p)) == -1L)
|
if ((addr = get3bytes(&p)) == -1L)
|
badformat(buff, inm, BADADDR);
|
badformat(buff, inm, BADADDR);
|
len -= 4;
|
len -= 4;
|
goto doit;
|
goto doit;
|
|
|
case 0x03: /* ... 32 bit addr */
|
case 0x03: /* ... 32 bit addr */
|
if ((addr = get4bytes(&p)) == -1L)
|
if ((addr = get4bytes(&p)) == -1L)
|
badformat(buff, inm, BADADDR);
|
badformat(buff, inm, BADADDR);
|
len -= 5;
|
len -= 5;
|
doit:
|
doit:
|
cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
|
cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
|
|
|
tb.dl_destaddr = addr;
|
tb.dl_destaddr = addr;
|
while (len--)
|
while (len--)
|
{
|
{
|
if ((c = getbyte(&p)) == -1)
|
if ((c = getbyte(&p)) == -1)
|
badformat(buff, inm, BADDATA);
|
badformat(buff, inm, BADDATA);
|
cksum += c;
|
cksum += c;
|
filesum += c;
|
filesum += c;
|
tb.dl_buf[tb.dl_count++] = c;
|
tb.dl_buf[tb.dl_count++] = c;
|
}
|
}
|
break;
|
break;
|
|
|
case 0x07: /* 32 bit end record */
|
case 0x07: /* 32 bit end record */
|
if ((addr = get4bytes(&p)) == -1L)
|
if ((addr = get4bytes(&p)) == -1L)
|
badformat(buff, inm, BADADDR);
|
badformat(buff, inm, BADADDR);
|
goto end_rec;
|
goto end_rec;
|
|
|
case 0x08: /* 24 bit end record */
|
case 0x08: /* 24 bit end record */
|
if ((addr = get3bytes(&p)) == -1L)
|
if ((addr = get3bytes(&p)) == -1L)
|
badformat(buff, inm, BADADDR);
|
badformat(buff, inm, BADADDR);
|
goto end_rec;
|
goto end_rec;
|
|
|
case 0x09: /* 16 bit end record */
|
case 0x09: /* 16 bit end record */
|
if ((addr = get2bytes(&p)) == -1L)
|
if ((addr = get2bytes(&p)) == -1L)
|
badformat(buff, inm, BADADDR);
|
badformat(buff, inm, BADADDR);
|
|
|
end_rec:
|
end_rec:
|
cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
|
cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
|
tb.dl_jumpaddr = addr;
|
tb.dl_jumpaddr = addr;
|
break;
|
break;
|
|
|
default:
|
default:
|
error(0, "unknown Motorola-S record type: 0x%02x", rectype);
|
error(0, "unknown Motorola-S record type: 0x%02x", rectype);
|
badformat(buff, inm, BADTYPE);
|
badformat(buff, inm, BADTYPE);
|
break;
|
break;
|
}
|
}
|
|
|
/*
|
/*
|
* Verify checksums are correct in file.
|
* Verify checksums are correct in file.
|
*/
|
*/
|
|
|
cksum = (~cksum) & 0xff;
|
cksum = (~cksum) & 0xff;
|
if ((incksum = getbyte(&p)) == -1)
|
if ((incksum = getbyte(&p)) == -1)
|
badformat(buff, inm, BADCSUM);
|
badformat(buff, inm, BADCSUM);
|
if (((u8) incksum) != cksum)
|
if (((u8) incksum) != cksum)
|
badformat(buff, inm, MISCSUM);
|
badformat(buff, inm, MISCSUM);
|
|
|
write_it:
|
write_it:
|
if (tb.dl_count)
|
if (tb.dl_count)
|
write_record(&tb, ofp);
|
write_record(&tb, ofp);
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int
|
int
|
convert_TI_records(
|
convert_TI_records(
|
FILE *ifp,
|
FILE *ifp,
|
char *inm,
|
char *inm,
|
FILE *ofp,
|
FILE *ofp,
|
char *onm)
|
char *onm)
|
{
|
{
|
char buff[512];
|
char buff[512];
|
char *p;
|
char *p;
|
int c;
|
int c;
|
bool endrecord = FALSE;
|
bool endrecord = FALSE;
|
bool eol;
|
bool eol;
|
buffer_rec tb;
|
buffer_rec tb;
|
|
|
while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
|
while ( ! endrecord && (fgets(buff, sizeof(buff), ifp)))
|
{
|
{
|
if (p[strlen(p)-1] == '\n') /* get rid of newline */
|
if (p[strlen(p)-1] == '\n') /* get rid of newline */
|
p[strlen(p)-1] = '\0';
|
p[strlen(p)-1] = '\0';
|
|
|
if (p[strlen(p)-1] == '\r') /* get rid of any CR */
|
if (p[strlen(p)-1] == '\r') /* get rid of any CR */
|
p[strlen(p)-1] = '\0';
|
p[strlen(p)-1] = '\0';
|
|
|
tb.dl_count = 0;
|
tb.dl_count = 0;
|
|
|
p = &buff[0];
|
p = &buff[0];
|
eol = FALSE;
|
eol = FALSE;
|
while ( ! eol && ! endrecord)
|
while ( ! eol && ! endrecord)
|
{
|
{
|
switch (*p++)
|
switch (*p++)
|
{
|
{
|
case '9':
|
case '9':
|
if (tb.dl_count)
|
if (tb.dl_count)
|
write_record(&tb, ofp);
|
write_record(&tb, ofp);
|
tb.dl_destaddr = get2bytes(&p);
|
tb.dl_destaddr = get2bytes(&p);
|
break;
|
break;
|
|
|
case 'B':
|
case 'B':
|
c = getbyte(&p);
|
c = getbyte(&p);
|
filesum += c;
|
filesum += c;
|
tb.dl_buf[tb.dl_count++] = c;
|
tb.dl_buf[tb.dl_count++] = c;
|
c = getbyte(&p);
|
c = getbyte(&p);
|
filesum += c;
|
filesum += c;
|
tb.dl_buf[tb.dl_count++] = c;
|
tb.dl_buf[tb.dl_count++] = c;
|
break;
|
break;
|
|
|
case 'F':
|
case 'F':
|
eol = TRUE;
|
eol = TRUE;
|
break;
|
break;
|
|
|
case ':':
|
case ':':
|
endrecord = TRUE;
|
endrecord = TRUE;
|
break;
|
break;
|
|
|
default:
|
default:
|
badformat(p, inm, BADFMT);
|
badformat(p, inm, BADFMT);
|
}
|
}
|
}
|
}
|
if (tb.dl_count)
|
if (tb.dl_count)
|
write_record(&tb, ofp);
|
write_record(&tb, ofp);
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
void
|
void
|
write_record(buffer_rec *tb,
|
write_record(buffer_rec *tb,
|
FILE *fp)
|
FILE *fp)
|
{
|
{
|
if ( ! linear)
|
if ( ! linear)
|
{
|
{
|
if (tb->dl_destaddr < base)
|
if (tb->dl_destaddr < base)
|
error(ERR_FATAL, "record at address 0x%x precedes base of 0x%x",
|
error(ERR_FATAL, "record at address 0x%x precedes base of 0x%x",
|
tb->dl_destaddr, base);
|
tb->dl_destaddr, base);
|
(void) fseek(fp, tb->dl_destaddr - base, 0);
|
(void) fseek(fp, tb->dl_destaddr - base, 0);
|
}
|
}
|
|
|
(void) fwrite(tb->dl_buf, tb->dl_count, 1, fp);
|
(void) fwrite(tb->dl_buf, tb->dl_count, 1, fp);
|
tb->dl_destaddr += tb->dl_count;
|
tb->dl_destaddr += tb->dl_count;
|
tb->dl_count = 0;
|
tb->dl_count = 0;
|
}
|
}
|
|
|
int
|
int
|
getnibble(char **p)
|
getnibble(char **p)
|
{
|
{
|
register int val;
|
register int val;
|
|
|
**p = toupper(**p);
|
**p = toupper(**p);
|
switch (**p)
|
switch (**p)
|
{
|
{
|
case '0': case '1': case '2': case '3': case '4':
|
case '0': case '1': case '2': case '3': case '4':
|
case '5': case '6': case '7': case '8': case '9':
|
case '5': case '6': case '7': case '8': case '9':
|
val = **p - '0';
|
val = **p - '0';
|
break;
|
break;
|
|
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
val = 10 + (**p - 'A');
|
val = 10 + (**p - 'A');
|
break;
|
break;
|
|
|
default:
|
default:
|
return(-1);
|
return(-1);
|
}
|
}
|
*p += 1;
|
*p += 1;
|
|
|
return(val & 0x0f);
|
return(val & 0x0f);
|
}
|
}
|
|
|
int
|
int
|
getbyte(char **p)
|
getbyte(char **p)
|
{
|
{
|
int n0, n1;
|
int n0, n1;
|
|
|
if ((n0 = getnibble(p)) == -1)
|
if ((n0 = getnibble(p)) == -1)
|
return(-1);
|
return(-1);
|
if ((n1 = getnibble(p)) == -1)
|
if ((n1 = getnibble(p)) == -1)
|
return(-1);
|
return(-1);
|
|
|
return(((n0 << 4) + n1) & 0xff);
|
return(((n0 << 4) + n1) & 0xff);
|
}
|
}
|
|
|
long
|
long
|
getNbytes(char **p,
|
getNbytes(char **p,
|
int n)
|
int n)
|
{
|
{
|
int t;
|
int t;
|
u32 val = 0;
|
u32 val = 0;
|
|
|
while (n--)
|
while (n--)
|
{
|
{
|
if ((t = getbyte(p)) == -1)
|
if ((t = getbyte(p)) == -1)
|
return(-1L);
|
return(-1L);
|
val <<= 8;
|
val <<= 8;
|
val += t;
|
val += t;
|
}
|
}
|
|
|
return(val);
|
return(val);
|
}
|
}
|
|
|
void
|
void
|
badformat(char *s,
|
badformat(char *s,
|
char *fname,
|
char *fname,
|
char *msg)
|
char *msg)
|
{
|
{
|
if (s[strlen(s)-1] == '\n') /* get rid of newline */
|
if (s[strlen(s)-1] == '\n') /* get rid of newline */
|
s[strlen(s)-1] = '\0';
|
s[strlen(s)-1] = '\0';
|
error(0, "line '%s'::\n\tfrom file '%s'; %s", s, fname, msg);
|
error(0, "line '%s'::\n\tfrom file '%s'; %s", s, fname, msg);
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
/*
|
/*
|
* error(errn, arglist)
|
* error(errn, arglist)
|
* report an error to stderr using printf(3) conventions.
|
* report an error to stderr using printf(3) conventions.
|
* Any output is preceded by '<progname>: '
|
* Any output is preceded by '<progname>: '
|
*
|
*
|
* Uses ERR_EXIT bit to request exit(errn)
|
* Uses ERR_EXIT bit to request exit(errn)
|
* ERR_ABORT to request abort()
|
* ERR_ABORT to request abort()
|
* ERR_ERRNO to indicate use of errno instead of argument.
|
* 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
|
* If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
|
* associated error message is appended to the output.
|
* associated error message is appended to the output.
|
*/
|
*/
|
|
|
/*VARARGS*/
|
/*VARARGS*/
|
|
|
void
|
void
|
error(int error_flag, ...)
|
error(int error_flag, ...)
|
{
|
{
|
va_list arglist;
|
va_list arglist;
|
register char *format;
|
register char *format;
|
int local_errno;
|
int local_errno;
|
|
|
extern int errno;
|
extern int errno;
|
|
|
(void) fflush(stdout); /* in case stdout/stderr same */
|
(void) fflush(stdout); /* in case stdout/stderr same */
|
|
|
local_errno = error_flag & ~ERR_MASK;
|
local_errno = error_flag & ~ERR_MASK;
|
if (error_flag & ERR_ERRNO) /* use errno? */
|
if (error_flag & ERR_ERRNO) /* use errno? */
|
local_errno = errno;
|
local_errno = errno;
|
|
|
va_start(arglist, error_flag);
|
va_start(arglist, error_flag);
|
format = va_arg(arglist, char *);
|
format = va_arg(arglist, char *);
|
(void) fprintf(stderr, "%s: ", progname);
|
(void) fprintf(stderr, "%s: ", progname);
|
(void) vfprintf(stderr, format, arglist);
|
(void) vfprintf(stderr, format, arglist);
|
va_end(arglist);
|
va_end(arglist);
|
|
|
if (local_errno)
|
if (local_errno)
|
(void) fprintf(stderr, " (%s)\n", strerror(local_errno));
|
(void) fprintf(stderr, " (%s)\n", strerror(local_errno));
|
else
|
else
|
(void) fprintf(stderr, "\n");
|
(void) fprintf(stderr, "\n");
|
|
|
(void) fflush(stderr);
|
(void) fflush(stderr);
|
|
|
if (error_flag & (ERR_FATAL | ERR_ABORT))
|
if (error_flag & (ERR_FATAL | ERR_ABORT))
|
{
|
{
|
if (error_flag & ERR_FATAL)
|
if (error_flag & ERR_FATAL)
|
{
|
{
|
error(0, "fatal error, exiting");
|
error(0, "fatal error, exiting");
|
exit(local_errno ? local_errno : 1);
|
exit(local_errno ? local_errno : 1);
|
}
|
}
|
else
|
else
|
{
|
{
|
error(0, "fatal error, aborting");
|
error(0, "fatal error, aborting");
|
abort();
|
abort();
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|