/* * PDP-8 format converter. * * Usage: p8bin2hex tape.bin > tape.hex * * Assumes tape.bin is a SIMH-compatible paper tape image in "BIN" or "RIM" * formats. * * RIM format: * 10.000.000 leader/trailer (at least an inch of these) * 01.aaa.aaa address hi (bits 5:0 contain address 11:6) * 00.aaa.aaa address lo (bits 5:0 contain address 5:0) * 00.xxx.xxx data hi (bits 5:0 contain data 11:6) * 00.xxx.xxx data lo (bits 5:0 contain data 5:0) * * * FIXME: RIM format currently almost always fails with bad checksum * * BIN format: * 10.000.000 leader/trailer (at least an inch of these) * 11.011.000 "field" (bits 6:4 specify address 14:12) * 01.000.010 origin hi bits: bits 5:0 contain origin 11:6 * 00.011.100 origin lo bits: bits 5:0 contain origin 5:0 * 00.xxx.xxx data hi bits: bits 5:0 contain data word 11:6 * 00.xxx.xxx data lo bits: bits 5:0 contain data word 5:0 * * 00.xxx.xxx chucksum hi - sum of all data and origin frames, but * 00.xxx.xxx chucksum lo - excluding field and leader/trailer * * Some tapes may contain assembler error messages. These are are text * delimited by 0377 bytes. The BIN loader ignores bytes from starting * at any 0377 byte, until another 0377 byte is seen. */ #include #include #include uint16_t mem[32768]; int load(FILE *fp) { enum { Addr, Data, Leader, Fetch, Skip , Start } s = Start; int c = 0, n, v = 0; uint16_t a = 0, d = 0, t = 0, u = 0; for (n = 0; (c = getc(fp)) != EOF; ++n) { switch (s) { case Addr: u += c; a |= c; s = Fetch; break; case Data: u += c; d |= 0x8000 | c; s = Fetch; break; case Fetch: fetch: if (c == 0200) { if ((d & 0x8000) != 0) { if ((d & 07777) != (t & 07777)) fprintf(stderr, "\nbad checksum %05o\n", t & 07777); else v = 1; } goto leadout; } t += u; u = 0; if (d & 0x8000) { mem[a] = d & 07777; a = (a & ~07777) | ((a + 1) & 07777); d = 0; } if ((c & 0300) == 0000) { u = c; d = (c & 077) << 6; s = Data; break; } if ((c & 0300) == 0100) { u = c; a = (a & ~07777) | (c & 077) << 6; s = Addr; break; } if ((c & 0307) == 0300) { a = ((c & 0070) << 9) | (a & 07777); break; } if (c == 0377) { s = Skip; break; } break; case Leader: leader: if (c != 0200) { s= Fetch; goto fetch; } break; case Skip: if (c == 0377) { s = Fetch; putchar('\n'); } else { putchar(c); } break; case Start: if (c == 0200) { s = Leader; goto leader; } break; } } leadout: while ((c = getc(fp)) != EOF) ; putchar('\n'); return v; } void dump() { printf("// Generated by p8bin2hex"); unsigned int nextaddr = -1; for (uint_fast32_t a = 0; a < 32768; ++a) { if (mem[a] == 0) continue; if (nextaddr != a) printf("\n@%x", (unsigned int)a); nextaddr = a + 1; printf(" %03x", mem[a]); } printf("\n"); } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: p8 filename.bin\n"); exit(EXIT_FAILURE); } FILE *fp = fopen(argv[1], "rb"); if (!fp) { perror(argv[1]); exit(EXIT_FAILURE); } if (!load(fp)) exit(EXIT_FAILURE); fclose(fp); dump(); exit(EXIT_SUCCESS); }