Added checksum generation to bin2load, compatible with SIMH 'load' command.
authorAaron Taylor <ataylor@subgeniuskitty.com>
Mon, 28 Dec 2020 07:05:00 +0000 (23:05 -0800)
committerAaron Taylor <ataylor@subgeniuskitty.com>
Mon, 28 Dec 2020 07:05:00 +0000 (23:05 -0800)
README.md
bin2load.c

index c433f67..1f14f40 100644 (file)
--- 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
 # 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
 
 
 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 #
 
 
 # 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
 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).
 
 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).
index baf98a2..f28c6de 100644 (file)
@@ -10,7 +10,7 @@
 #include <errno.h>
 #include <getopt.h>
 
 #include <errno.h>
 #include <getopt.h>
 
-#define VERSION 1
+#define VERSION 
 
 void
 print_usage( char ** argv )
 
 void
 print_usage( char ** argv )
@@ -91,25 +91,87 @@ main( int argc, char ** argv)
      * the starting PC.
      */
 
      * 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);
 }
     fclose(dst);
 }