+/*
+ * © 2020 Aaron Taylor <ataylor at subgeniuskitty dot com>
+ * See LICENSE.txt file for copyright and license details.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#define VERSION 1
+
+void
+print_usage( char ** argv )
+{
+ printf( "bin2load v%d (www.subgeniuskitty.com)\n"
+ "Usage: %s i <file> -o <file> [-a <address>]\n"
+ " -i <file> Binary file to be written to tape.\n"
+ " For example, binary executable from 'pdp11-aout-objdump'.\n"
+ " -o <file> New paper tape image for use with SIMH.\n"
+ " -a <address> Address on PDP-11 at which to load paper tape contents.\n"
+ , VERSION, argv[0]
+ );
+}
+
+
+int
+main( int argc, char ** argv)
+{
+ int c;
+ FILE * src = NULL;
+ FILE * dst = NULL;
+ uint16_t address = 01000; /* Default address to load tape contents. */
+
+ while ((c = getopt(argc, argv, "i:o:a:h")) != -1) {
+ switch (c) {
+ case 'i':
+ if ((src = fopen(optarg, "r")) == NULL ) {
+ fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
+ }
+ break;
+ case 'o':
+ if ((dst = fopen(optarg, "w+")) == NULL ) {
+ fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
+ }
+ break;
+ case 'a':
+ address = (uint16_t) strtol(optarg, NULL, 0);
+ break;
+ case 'h':
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (src == NULL || dst == NULL) {
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+ printf("Paper tape will load at address 0%o.\n", address);
+
+ /*
+ * Paper tape format(bytes, not words):
+ * 01
+ * 00
+ * Low byte of packet length (binary length + 6 for header)
+ * High byte of packet length
+ * Low byte of address to load binary data at
+ * High byte of address
+ * DataBegin
+ * |
+ * |
+ * DataEnd
+ * Checksum
+ *
+ * I am unsure of the checksum format and need to check the SIMH source.
+ * In the meantime a zero checksum still functions, albeit with a warning.
+ */
+
+ uint16_t size = 6;
+
+ uint16_t header[] = {1,0,01000};
+ fwrite(header,6,1,dst);
+
+ 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);
+
+ uint16_t footer[] = {0,1,6,01000,0};
+ fwrite(footer,10,1,dst);
+
+ fseek(dst,2,SEEK_SET);
+ fwrite(&size,2,1,dst);
+
+ fclose(src);
+ fclose(dst);
+}