#include <errno.h>
#include <getopt.h>
-#define VERSION 1
+#define VERSION 2
void
-print_usage( char ** argv )
+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"
+ "Usage: %s -i <file> -o <file> [-a <address>]\n"
+ " -i <file> Raw binary file to be written to tape.\n"
+ " For example, output from 'pdp11-aout-objdump' (see README.md).\n"
+ " -o <file> Output file created by bin2load containing tape image for use with SIMH.\n"
+ " -a <address> (optional) Address on PDP-11 at which to load tape contents.\n"
, VERSION, argv[0]
);
}
-
int
-main( int argc, char ** argv)
+main(int argc, char ** argv)
{
int c;
FILE * src = NULL;
FILE * dst = NULL;
- uint16_t address = 01000; /* Default address to load tape contents. */
+ uint16_t address = 01000; /* Default address to load tape contents in RAM. */
while ((c = getopt(argc, argv, "i:o:a:h")) != -1) {
switch (c) {
print_usage(argv);
exit(EXIT_FAILURE);
}
+
printf("Paper tape will load at address 0%o.\n", address);
/*
* 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);
}