From f63b1e81c8b4ca50e2d6570af584b87dd4c1e342 Mon Sep 17 00:00:00 2001 From: Aaron Taylor Date: Sun, 27 Dec 2020 23:05:00 -0800 Subject: [PATCH] Added checksum generation to bin2load, compatible with SIMH 'load' command. --- README.md | 7 ++-- bin2load.c | 94 ++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 80 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c433f67..1f14f40 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,13 @@ # Overview # This is a simple program that converts raw binary data into a paper-tape image -compatible with SIMH. +compatible with SIMH's `load` command. For example, I commonly use it when transfering compiled PDP-11 code into SIMH with the output of: pdp11-aout-objcopy --only-section=.text --output-target binary program.out program.bin -It does not generate correct checksums, but this generates only a warning in -SIMH, not an error. - # Status # @@ -24,7 +21,7 @@ Edit the `Makefile` to set `$PREFIX` for alternate installation paths. By default it installs to `$HOME/bin`. Once compiled and added to your `$PATH`, simply provide a raw binary blob as -`input` and receive a SIMH compatible paper tape image at `output`. +`input` and receive a SIMH compatible paper tape image as `output`. If provided via the `-a` flag, the paper tape will load at the provided address in memory. If not provided, this defaults to `01000` (`1000` octal). diff --git a/bin2load.c b/bin2load.c index baf98a2..f28c6de 100644 --- a/bin2load.c +++ b/bin2load.c @@ -10,7 +10,7 @@ #include #include -#define VERSION 1 +#define VERSION 2 void print_usage( char ** argv ) @@ -91,25 +91,87 @@ main( int argc, char ** argv) * the starting PC. */ - uint16_t size = 6; + uint32_t checksum = 0; + uint32_t size = 6; + uint8_t data; - uint16_t header[] = {1,0,01000}; - fwrite(header,6,1,dst); + /* Write header for data block. */ + for (int i = 0; i < size; i++) { + switch (i) { + case 0: data = 0001; break; + case 1: data = 0000; break; + case 2: data = 0000; break; /* Size will be populated later */ + case 3: data = 0000; break; /* Size will be populated later */ + case 4: data = address & 0xff; break; + case 5: data = (address >> 8) & 0xff; break; + } + if (!fwrite(&data, 1, 1, dst)) { + fprintf(stderr, "ERROR: Failed to write block header.\n"); + exit(EXIT_FAILURE); + } + checksum += data; + } - uint8_t byte; - int read; - do { - read = fread(&byte,1,1,src); - if(read == 1) fwrite(&byte,1,1,dst); - size += read; - } while (read == 1); + /* Write contents of data block. */ + while (1) { + if (fread(&data, 1, 1, src)) { + if (!fwrite(&data, 1, 1, dst)) { + fprintf(stderr, "ERROR: Failed to write block data.\n"); + exit(EXIT_FAILURE); + } + size++; + checksum += data; + } else { + break; + } + } + fclose(src); - uint16_t footer[] = {0,1,6,01000,0}; - fwrite(footer,10,1,dst); + /* Now that block size is known, update block header. */ + if (fseek(dst, 2, SEEK_SET)) { + fprintf(stderr, "ERROR: Failed seek back to header of data block.\n"); + exit(EXIT_FAILURE); + } + for (int i = 0; i < 2; i++) { + switch (i) { + case 0: data = size & 0xff; break; + case 1: data = (size >> 8) & 0xff; break; + } + if (!fwrite(&data, 1, 1, dst)) { + fprintf(stderr, "ERROR: Failed to write block size into header.\n"); + exit(EXIT_FAILURE); + } + checksum += data; // Header is included in checksum. + } + if (fseek(dst, 0, SEEK_END)) { + fprintf(stderr, "ERROR: Failed seek to end of data block.\n"); + exit(EXIT_FAILURE); + } - fseek(dst,2,SEEK_SET); - fwrite(&size,2,1,dst); + /* Write checksum for data block. */ + checksum = (~checksum) + 1; + data = checksum & 0xff; + if (!fwrite(&data, 1, 1, dst)) { + fprintf(stderr, "ERROR: Failed to write checksum.\n"); + exit(EXIT_FAILURE); + } - fclose(src); + /* Write empty block to indicate end-of-tape. */ + for (int i = 0; i < 8; i++) { + switch (i) { + case 0: data = 0001; break; + case 1: data = 0000; break; + case 2: data = 0006; break; + case 3: data = 0000; break; + case 4: data = address & 0xff; break; + case 5: data = (address >> 8) & 0xff; break; + case 6: data = 0000; break; + case 7: data = 0000; break; + } + if (!fwrite(&data, 1, 1, dst)) { + fprintf(stderr, "ERROR: Failed to write end-of-tape block.\n"); + exit(EXIT_FAILURE); + } + } fclose(dst); } -- 2.20.1