/* * @(#)lda2bin.c 1.4 20/07/25 * * lda2bin * * Converts a .LDA file to a binary file suitable * for burning to a ROM. The file is generated by * issuing the "LINK /LDA" command, specifying the * desired .OBJ file to link. * * The information on the LDA file format came from the * Digital Equipment Corporation AA-PD6PA-TC "RT-11 Volume * and File Formats Manual" for RT-11 V5.6. * * This file is provided "as-is", with no warranty or support * expressed or implied. */ #include #include #include #include #include #include #define min(a, b) (a < b ? a : b) #define max(a, b) (a > b ? a : b) #define MEM 65536 char *program; int debug, quiet; FILE *logfile; void usage(void) { fprintf(stderr, "usage: %s [-a addr] [-p pad] [-q] [-x] [-i infile] [-o outfile]\n", program); exit(1); } void process(FILE *infile, FILE *outfile, unsigned int saddr, int pad, int hflag) { int i, n, r; unsigned short count, addr, lowaddr, highaddr; unsigned char c, h[6], *data; r = 0; /* * Allocate 64K of memory, since the records could end up anywhere. */ data = calloc(MEM / sizeof(*data), sizeof(*data)); lowaddr = MEM - 1; highaddr = 0; /* * Process each record in the file. */ do { /* * Read the record header */ if ((n = fread(h, sizeof(*h), sizeof(h), infile)) != sizeof(h)) { fprintf(logfile, "%s: %s\n", program, strerror(errno)); break; } r++; /* * Check the record type */ if (h[0] != 1 && h[1] != 0) { fprintf(logfile, "%s: bad record\n", program); break; } /* * Get the record size and starting address */ count = h[2] + h[3] * 256; addr = h[4] + h[5] * 256; if (debug) fprintf(stderr, "Record %d: addr=0%6.6o, count=%d.\n", r, addr, count); /* * Count only the data in the record. */ count -= sizeof(h); /* * The last record will be empty. */ if (count == 0) break; /* * Check for an even starting address. */ if (addr % 2 == 1) break; /* * Read the record into memory. */ if ((n = fread(&data[addr], sizeof(*data), count, infile)) != count) { fprintf(logfile, "%s: %s\n", program, strerror(errno)); break; } /* * Read the checksum. */ n = fgetc(infile); /* * Calculate the checksum */ for (c = 0, i = 0; i < sizeof(h); i++) c += h[i]; for (i = addr; i < addr + count; i++) c += data[i]; c = -c; /* * Check for a match */ if (c != n) { fprintf(logfile, "%s: bad checksum in record %d.\n", program, r); break; } /* * Update the starting and ending addresses */ lowaddr = min(lowaddr, addr); highaddr = max(highaddr, addr + count); /* * Output Intel HEX. */ if (hflag) { fprintf(outfile, ":%2.2d%4.4X00", count, addr); for (i = addr; i < addr + count; i++) fprintf(outfile, "%2.2X", data[i]); fprintf(outfile, "%2.2X\r\n", c); } } while (count); /* * Output Intel HEX. */ if (hflag) fprintf(outfile, ":00000001FF\r\n"); if (debug) fprintf(stderr, "records=%d, lowaddr=0%6.6o, highaddr=0%6.6o\n", r, lowaddr, highaddr); /* * If a starting address was specified, then override start */ if (saddr) lowaddr = saddr; /* * Calculate the number of bytes in the file */ count = highaddr - lowaddr; if (!quiet || debug) fprintf(stderr, "ADDR: 0%6.6o\nSIZE: %d\n", lowaddr, count); /* * Output binary data. */ if (!hflag) { /* * Write the image to the output. */ fwrite(&data[lowaddr], sizeof(*data), count, outfile); /* * Pad the remaining image, if required. */ for (i = count; i < pad; i++) fputc(0xff, outfile); } /* * Cleanup and leave. */ free(data); return; } int main(int argc, char *argv[]) { int c, pad, hflag; unsigned int saddr; char *inname, *outname; FILE *infile, *outfile; program = basename(argv[0]); inname = NULL; /* no input file specified */ outname = NULL; /* out output file specified */ logfile = stderr; /* errors go to stderr */ /* * Set the defaults. */ saddr = 0; hflag = 0; /* binary output */ infile = stdin; /* use stdin for the input */ outfile = stdout; /* use stdout for the output */ pad = 0; /* no padding */ quiet = 0; /* verbose */ debug = 0; /* no debugging */ /* * Parse the command line. */ while ((c = getopt(argc, argv, "a:hi:o:p:qx?")) != EOF) switch (c) { case 'a': /* specify the starting address */ sscanf(optarg, "%o", &saddr); break; case 'h': /* generate an Intel HEX output */ hflag = 1; break; case 'i': /* input filename */ inname = optarg; break; case 'o': /* output filename */ outname = optarg; break; case 'p': /* pad the output with the specified # of bytes */ pad = atoi(optarg); break; case 'q': /* quiet mode */ quiet = 1; break; case 'x': /* debug mode */ debug = 1; break; case '?': default: usage(); /* NOTREACHED */ break; }; /* * If not using stdin, open the input file for reading. */ if (inname) if ((infile = fopen(inname, "r")) == NULL) { perror(program); exit(2); } /* * If not using stdout, open the output file for writing. */ if (outname) if ((outfile = fopen(outname, "w")) == NULL) { perror(program); exit(3); } /* * Process the input file. */ process(infile, outfile, saddr, pad, hflag); /* * Cleanup. */ if (inname) fclose(infile); if (outname) fclose(outfile); /* * Done. */ return (0); }