/**************************************************************************** mload - convert an Intel hex file to a binary file Author: Peter Turnbull Address: Dept. of Computer Science, University of York, UK. Email: pnt@cs.york.ac.uk, pete@dunnington.u-net.com Program name: mload Description: multi-file loader; convert Intel hex files to a binary file. See also: CP/M load command Date started: 20-May-1997 Version: 0.2 Last modified: 17-Apr-1999 use multiple buffers, accept 02 code **************************************************************************** Uses multiple 16K buffers so that we can deal with out-of-order addressing, and larger-than-64KB address spaces. This version handles base address codes (type 02). Some fprintf's use the format string %X; this is an upper-case version of %x. ****************************************************************************/ #include /* Each buffer is 16K, ie a 14-bit address space */ /* and there are 64 of them, total 1MB = 20 bits */ #define BUFFSZ 16384 #define BBITS 14 #define NBUFFS 64 #define PAD 0xFF #define TRUE 1 #define FALSE 0 /* uncomment the following line for debugging output, or compile -Ddebug */ /* #define debug */ unsigned char checksum; unsigned char fillbyte = PAD; char *progname; unsigned int startaddr, endaddr; char *buff[NBUFFS]; typedef unsigned char boolean; /***************************************************************************/ void noop() {} /***************************************************************************/ unsigned char getbyte() { register int c; unsigned char x; c = getchar(); if (c >= '0' && c <= '9') x = c - '0'; else if (c >= 'A' && c <= 'F') x = c - 'A' + 10; else if (c >= 'a' && c <= 'f') x = c - 'a' + 10; else goto unusual; x <<= 4; c = getchar(); if (c >= '0' && c <= '9') x |= c - '0'; else if (c >= 'A' && c <= 'F') x |= c - 'A' + 10; else if (c >= 'a' && c <= 'f') x |= c - 'a' + 10; else { unusual: fprintf (stderr, "%s: Unusual hex digit %c\n", progname, c); exit (2); } checksum += x; return x; } /***************************************************************************/ boolean allocbuff(address) unsigned address; { int i; unsigned buffnum = address>>BBITS; #ifdef debug fprintf(stderr, "Allocating buffer %d... ", buffnum); #endif /* is it already already allocated? */ if (buff[buffnum] != NULL) { #ifdef debug fprintf(stderr, "already allocated\n"); #endif return TRUE; } if ((buff[buffnum] = malloc(BUFFSZ)) == NULL) { fprintf(stderr,"%s: can't allocate buffer %d for 0x%5X\n", progname, buffnum, address); return FALSE; } for (i=0; i 0) { if (address < startaddr) startaddr = address; bnum = address >> BBITS; last = address%BUFFSZ + n - 1; if (buff[bnum] == NULL && !allocbuff(address)) exit(1); if (last < BUFFSZ) { for (i = address%BUFFSZ; i <= last; i++) buff[bnum][i] = getbyte(); } else { for (i = address%BUFFSZ; i < BUFFSZ; i++) buff[bnum][i] = getbyte(); if (buff[bnum+1] == NULL && !allocbuff(address+n-1)) exit(1); for (i = 0; i <= last%BUFFSZ; i++) buff[bnum+1][i] = getbyte(); } if (address+n-1 > endaddr) endaddr = address+n-1; #ifdef debug fprintf(stderr," data record: endaddr is now %05X\n", endaddr); #endif } else { type = 1; #ifdef debug fprintf(stderr," old-style EOF record\n"); #endif } break; default: fprintf (stderr, "%s: unknown record type %d\n", progname, type); exit(1); } (void) getbyte(); if (checksum != 0) { fprintf (stderr, "%s: Checksum error\n", progname); exit (2); } } while (type != 1); } /***************************************************************************/ main(argc, argv) int argc; char *argv[]; { char c; unsigned address, baseaddr, filler; int i, n; char *infilename, *outfilename; char *opt; boolean patchfile = FALSE; boolean xfiles = FALSE; FILE *infile; /* set start/end to impossible values; adjust during loading */ endaddr = 0; startaddr = BUFFSZ * NBUFFS - 1; outfilename = NULL; infilename = NULL; /* in case first file is a binary, with no addr spec */ address = 0x0100; /*** parse the command line ***/ #ifdef debug fprintf(stderr,"%s has %d arguments\n", argv[0], argc); #endif progname = argv[0]; while (--argc > 0 && (*++argv)[0] == '-') { for (opt = argv[0]+1; *opt !='\0'; opt++) { switch (*opt) { case 'a': if (--argc > 1) { sscanf((*++argv), "%x", &address); argc--; infilename = *++argv; #ifdef debug fprintf(stderr,"binfile is %s at address %X\n", infilename, address); #endif } else { fprintf(stderr, "%s: -a needs address and filename\n", progname); exit(1); } patchfile = TRUE; break; case 'o': if (--argc > 0) { outfilename = *++argv; #ifdef debug fprintf(stderr,"Sending output to %s\n", outfilename); #endif } break; case 'f': if (--argc > 0) { sscanf((*++argv), "%x", &filler); fillbyte = filler % 256; #ifdef debug fprintf(stderr,"Filler byte value set to 0x%X\n", fillbyte); #endif } else { fprintf(stderr, "%s: -f needs a hex number\n", progname); exit(1); } break; case 'h': fprintf(stderr, "%s: multi-file Intel hex loader\n", progname); case '?': argc = -1; break; default: fprintf(stderr, "%s: illegal option %c\n", progname, *opt); argc = -1; break; } } } if (argc < 0) { fprintf(stderr, "Usage: %s [-o ofile] [-f value] [[-a startaddr] binfile]" " [file [file...]]\n", progname); fprintf(stderr, "\twhere value is the hex value (default: 0x%02X)" " of filler bytes,\n", fillbyte); fprintf(stderr, "\t binfile is a binary file to be patched,\n" "\t and startaddr (default: 0x0100) is in hexadecimal.\n" "\tI/O uses stdin/stdout if no files are specified.\n"); exit(1); } /*** set the buffer pointers ***/ for (i=0; i < NBUFFS; buff[i++] = NULL); /*** open output file if specified ***/ if (outfilename != NULL) if (freopen(outfilename, "w", stdout) == NULL) { fprintf(stderr,"%s: unable to open output file %s.\n", progname, outfilename); exit(1); } /*** if -a specified, open a binary file, else open first file and test for binary ***/ if (patchfile) { if ((infile = fopen(infilename, "r")) == NULL) { fprintf(stderr,"%s: unable to read file %s.\n", progname, infilename); exit(1); } } else { if (argc>0) { /* there is an input file, see if it's not hex */ #ifdef debug fprintf(stderr,"Opening input file %s\n", argv[0]); #endif infilename = argv[0]; if ((infile = fopen(infilename, "r")) == NULL) { fprintf(stderr,"%s: unable to read file %s.\n", progname, infilename); exit(1); } else { #ifdef debug fprintf(stderr,"Checking type of input file %s...", infilename); #endif patchfile = (ungetc(getc(infile),infile) != ':'); if (patchfile) { #ifdef debug fprintf(stderr," binary\n"); #endif --argc; ++argv; } else { #ifdef debug fprintf(stderr," hex\n"); #endif fclose(infile); } } } } if (patchfile) { #ifdef debug fprintf(stderr,"Reading patch file %s.\n", infilename); #endif if (!allocbuff(address)) exit(1); startaddr = endaddr = address; endaddr += fread(buff[startaddr>>BBITS] + startaddr%BUFFSZ, sizeof(char), BUFFSZ - startaddr%BUFFSZ, infile) - 1; while (!feof(infile)) { if (!allocbuff(endaddr+1)) exit(1); endaddr += fread(buff[(endaddr+1)>>BBITS], sizeof(char), BUFFSZ, infile); } #ifdef debug fprintf(stderr,"Read data to %X...%X\n", startaddr, endaddr); #endif fclose(infile); } /*** OK, let's do the hex... ***/ if (argc > 0) { /* files named on the command line, but not stdin */ while (--argc >= 0) { infilename = *argv++; #ifdef debug fprintf(stderr,"Loading file %s\n", infilename); #endif if ((infile = freopen(infilename, "r", stdin)) == NULL) { fprintf(stderr,"%s: unable to read file %s.\n", progname, infilename); exit(1); } loadfile(); } } else { /* stdin only */ loadfile(); } /* and write out the buffers */ if ( startaddr > endaddr) { fprintf(stderr,"%s: nothing to write!\n", progname); exit(1); } if (startaddr>>BBITS == endaddr>>BBITS) { #ifdef debug fprintf(stderr, "writing one block (#%d), from %05X (%04X) to %05X (%04X) with %04X chars\n", startaddr>>BBITS, startaddr, startaddr%BUFFSZ, endaddr, endaddr%BUFFSZ, endaddr-startaddr+1); #endif fwrite(buff[startaddr>>BBITS] + startaddr%BUFFSZ, sizeof(char), endaddr-startaddr+1, stdout); } else { #ifdef debug fprintf(stderr, "writing first block (#%d), from %05X (%04X) with %04X chars\n", startaddr>>BBITS, startaddr, startaddr%BUFFSZ, BUFFSZ-startaddr%BUFFSZ); #endif fwrite(buff[startaddr>>BBITS] + startaddr%BUFFSZ, sizeof(char), BUFFSZ-startaddr%BUFFSZ, stdout); for (i=(startaddr>>BBITS)+1; i < endaddr>>BBITS; i++) { #ifdef debug fprintf(stderr, "writing full block (#%d)\n", i); #endif if (buff[i] == NULL) { /* we don't want any malloc error now, so re-use other buffer */ #ifdef debug fprintf(stderr, " re-using block %d\n", startaddr>>BBITS); #endif for (n=0; n>BBITS][n++]=fillbyte); fwrite(buff[startaddr>>BBITS], sizeof(char), BUFFSZ, stdout); } else { fwrite(buff[i], sizeof(char), BUFFSZ, stdout); } } #ifdef debug fprintf(stderr, "writing last block (#%d) with %04X chars, up to %05X\n", endaddr>>BBITS, endaddr%BUFFSZ + 1, endaddr); #endif fwrite(buff[endaddr>>BBITS], sizeof(char), endaddr%BUFFSZ + 1, stdout); } noop("Copyright © 1997 Pete Turnbull"); }