From 9158d2ec26068bda5f3dbaaf792b02624d9b1a84 Mon Sep 17 00:00:00 2001 From: brad Date: Sun, 10 May 2009 23:53:55 +0000 Subject: [PATCH] focal --- sim/Makefile | 3 + sim/a.out | Bin 0 -> 9039 bytes sim/io.c | 1 + sim/m.c | 9 + sim/pdp8.c | 680 +++++++++++++++++++++++++++++++++++++++++++++++++++ sim/pdp8i | Bin 0 -> 18788 bytes 6 files changed, 693 insertions(+) create mode 100644 sim/Makefile create mode 100755 sim/a.out create mode 100644 sim/io.c create mode 100644 sim/m.c create mode 100644 sim/pdp8.c create mode 100755 sim/pdp8i diff --git a/sim/Makefile b/sim/Makefile new file mode 100644 index 0000000..11c06d0 --- /dev/null +++ b/sim/Makefile @@ -0,0 +1,3 @@ + +pdp8i: pdp8.c io.c + cc -o pdp8i pdp8.c io.c diff --git a/sim/a.out b/sim/a.out new file mode 100755 index 0000000000000000000000000000000000000000..d9cf09916c801539a3ca16c9deb3b81b1b8b39d3 GIT binary patch literal 9039 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 (31-(h-l)+1)) + +main() +{ +#define bitmask(l) ((unsigned int)0xffffffff >> (32-(l))) + printf("%08x ", bitmask(3)); + printf("%08x ", bitmask(2)); + printf("%08x ", bitmask(1)); +} diff --git a/sim/pdp8.c b/sim/pdp8.c new file mode 100644 index 0000000..50cefb0 --- /dev/null +++ b/sim/pdp8.c @@ -0,0 +1,680 @@ +/* + * basic pdp-8i behavioral model + * ment to look and act like the verilog model + * brad@heeltoe.com + */ + +#include +#include +#include + +typedef unsigned char u8; +typedef unsigned short u12; +typedef unsigned short u15; +typedef unsigned char u3; + +u8 binfile[16*1024]; +int binfile_size; + +#define MEMSIZE (32*1024) +u12 mem[32*1024]; + +int d_load = 0; +int d_fetch = 0; +int d_decode = 0; +int d_cycle = 0; +int d_mem = 0; +int d_trace = 0; + +int loadbin(char *fn) +{ + int f, ch, o; + int rubout, newfield, state, high, low, done; + int word, csum; + u12 origin, field; + + f = open(fn, O_RDONLY); + if (f < 0) { + perror(fn); + return -1; + } + + binfile_size = read(f, binfile, sizeof(binfile)); + + if (d_load) printf("binload: %d bytes\n", binfile_size); + + done = 0; + for (o = 0; o < binfile_size && !done; o++) { + ch = binfile[o]; + + if (rubout) { + rubout = 0; + continue; + } + + if (ch == 0377) { + rubout = 1; + continue; + } + + if (ch > 0200) { + newfield = (ch & 070) << 9; + continue; + } + + switch (state) { + case 0: + /* leader */ + if ((ch != 0) && (ch != 0200)) state = 1; + high = ch; + break; + + case 1: + /* low byte */ + low = ch; + state = 2; + break; + + case 2: + /* high with test */ + word = (high << 6) | low; + if (ch == 0200) { + if ((csum - word) & 07777) { + printf("loadbin: checksum error\n"); + } + done = 1; + continue; + } + csum = csum + low + high; + if (word >= 010000) { + origin = word & 07777; + } else { + if ((field | origin) >= MEMSIZE) { + printf("loadbin: too big\n"); + } + + if (d_load) printf("mem[%o] = %o\n", field|origin, word&07777); + + mem[field | origin] = word & 07777; + origin = (origin + 1) & 07777; + } + field = newfield; + high = ch; + state = 1; + break; + } + } + + close(f); + return 0; +} + +char *disassem(int pc, int mb) +{ + static char buf[128]; + char b1[64]; + int i, b[12]; + + for (i = 0; i < 12; i++) + b[i] = mb & (1 << i); + + buf[0] = 0; + + switch ((mb & 07000) >> 9) { + case 0: sprintf(buf, "and "); goto d; + case 1: sprintf(buf, "tad "); goto d;; + case 2: sprintf(buf, "isz "); goto d;; + case 3: sprintf(buf, "dca "); goto d;; + case 4: sprintf(buf, "jms "); goto d;; + case 5: sprintf(buf, "jmp "); + d: + if (b[8]) strcat(buf, "I "); + if (!b[7]) strcat(buf, "Z "); + sprintf(b1, "%o", mb & 0177); + strcat(buf, b1); + break; + + case 6: sprintf(buf, "iot "); break; + + case 7: + if (b[8] == 0) { + if (b[7]) strcat(buf, "cla "); + if (b[6]) strcat(buf, "clf "); + if (b[5]) strcat(buf, "cma "); + if (b[4]) strcat(buf, "cmla "); + switch ((mb & 016) >> 1) { + case 1: strcat(buf, "bsw "); break; + case 2: strcat(buf, "ral "); break; + case 3: strcat(buf, "rtl "); break; + case 4: strcat(buf, "rar "); break; + case 5: strcat(buf, "rtr "); break; + } + if (b[0]) strcat(buf, "iac "); + } else + if (b[8] && b[0] == 0) { + if (b[7]) strcat(buf, "cla "); + + if (b[6]) strcat(buf, "sma "); + if (b[5]) strcat(buf, "sza "); + if (b[4]) strcat(buf, "snl "); + if (b[3]) strcat(buf, "skp "); + + if (b[2]) strcat(buf, "osr "); + if (b[1]) strcat(buf, "hlt "); + } else { + if (b[7]) strcat(buf, "cla "); + if (b[6]) strcat(buf, "mqa "); + if (b[5]) strcat(buf, "sca "); + if (b[4]) strcat(buf, "mql "); + } + break; + } + + return buf; +} + +typedef unsigned char wire; +typedef unsigned char reg; + +u15 pc; +u12 ac; +u3 UF, DF, IF, IB, SF; +reg l; + +u12 ma; +u12 mq; + +u12 switches; +wire run; +wire interrupt; +wire user_interrupt; +wire interrupt_enable; +wire interrupt_inhibit; +wire interrupt_cycle; +wire interrupt_skip; +wire ib_pending; +wire io_interrupt; +wire io_skip, condition_mux, skip_condition, pc_incr, pc_skip; + +int tt_data; +int tt_countdown; +//int io_cycle_count; +wire io_data_avail; +u12 io_data; + +wire ram_we; + +void +execute(void) +{ + u12 memory_bus, mb; + wire ir; + wire and, tad, isz, dca, jms, jmp, iot, opr; + u12 io_select; + +F0: + memory_bus = mem[(IF<<12) | pc]; + + interrupt_skip = 0; + if (interrupt && interrupt_enable && + !interrupt_inhibit && !interrupt_cycle) + { + interrupt_cycle = 1; + interrupt = 0; + interrupt_enable = 0; + mb = 04000; + memory_bus = mb; + ir = 4; + SF = (IF<<3)|DF; + IF = 0; + DF = 0; + printf("xxx interrupt @ %o\n", pc); + } else { + interrupt_cycle = 0; + mb = memory_bus; + } + + if (d_fetch) { + printf("\n"); + printf("fetch: if=%o, pc=%04o %04o %s\n", IF, pc, mb, disassem(pc, mb)); + printf(" l=%d ac=%04o\n", l, ac); + } + + if (d_trace) { + printf("pc %4o ir %4o l %o ac %4o ion %d\n", + pc, mb, l, ac, interrupt_enable); + } + +#define bitmask(l) ((unsigned int)0xffffffff >> (31-(l))) +#define mb_bit(n) ((mb & (1<> l) & bitmask(h-l)) + + ir = (memory_bus >> 9) & 7; + + and = ir == 0; + tad = ir == 1; + isz = ir == 2; + dca = ir == 3; + jms = ir == 4; + jmp = ir == 5; + iot = ir == 6; + opr = ir == 7; + + skip_condition = + ((mb_bit(6) && (ac & 04000)) || + (mb_bit(5) && (ac == 0)) || + (mb_bit(4) && (l == 1))) ? 1 : 0; + + pc_incr = + (opr & !mb_bit(8)) || + (opr && (mb_bit(8) && !mb_bit(0)) && (skip_condition == mb_bit(3))) || + iot || + (!(opr || iot) && !interrupt_cycle); + + pc_skip = + (opr && (mb_bit(8) && !mb_bit(0)) && (skip_condition ^ mb_bit(3))) || + (iot && (io_skip || interrupt_skip)); +// (iot && mb_bit(0) && io_skip); + + if (d_decode) { + printf("and %d tad %d isz %d dca %d jms %d jmp %d ito %d opr %d\n", + and, tad, isz, dca, jms, jmp, iot, opr); + printf("skip %d, pc_incr %d, pc_skip %d\n", + skip_condition, pc_incr, pc_skip); + + printf("condition_mux %o, skip_condition %o; %o %o %o\n", + condition_mux, skip_condition, + mb_bit(3), + (skip_condition == mb_bit(3)), + (skip_condition ^ mb_bit(3))); + } + +F1: + if (opr) { + /* group 1 */ + if (mb_bit(8) == 0) { + if (mb_bit(7)) ac = 0; + if (mb_bit(6)) l = 0; + if (mb_bit(5)) ac = ~ac & 07777; + if (mb_bit(4)) l = ~l & 1; + } + /* group 2 */ + if (mb_bit(8) && !mb_bit(0)) { + if (mb_bit(7)) ac = 0; + } + + /* group 3 */ + if (mb_bit(8) & mb_bit(0)) { + if (mb_bit(7)) ac = 0; + } + } + + io_select = (mb >> 3) & 077; + + if (iot) { + if (d_cycle) printf("iot; io_select %o\n", io_select); + + switch (io_select) { + case 0: // ION, IOF + switch (mb & 7) { + case 1: + //printf("xxx ints on\n"); + interrupt_enable = 1; + break; + case 2: + if (d_fetch) printf("xxx ints off\n"); + interrupt_enable = 0; + break; + case 3: if (interrupt_enable) interrupt_skip = 1; break; + } + break; + + case 020: case 021: case 022: case 023: // CDF..RMF + case 024: case 025: case 026: case 027: + switch (mb & 7) { + case 1: + DF = (mb >> 3) & 7; // CDF + break; + case 2: // CIF + IB = (mb >> 3) & 7; + ib_pending = 1; + interrupt_inhibit = 1; + break; + case 4: + switch (io_select & 7) { + case 1: ac = DF << 3;break;// RDF + case 2: ac = IF << 3;break;// RIF + case 3: ac = SF;break; // RIB + case 4: // RMF + IB = (SF >> 3) & 7; + DF = SF & 7; + break; + } + break; + } + } + +#if 1 + switch (io_select) { + case 004: + if (mb_bit(0)) { + printf("tls; tt_countdown %d\n", tt_countdown); + if (tt_countdown <= 0) + io_skip = 1; + } + if (mb_bit(1)) { + } + if (mb_bit(2)) { + tt_data = ac; + tt_countdown = 98/*100*/; + } + break; + } + +#endif + } + + if (tt_countdown > 0) { + tt_countdown--; + if (tt_countdown == 0) { + printf("xxx tx_data %o\n", tt_data); + io_interrupt = 1; + } + } + +// io_cycle_count++; +// if (io_cycle_count > 100) { +// io_cycle_count = 0; +// io_interrupt = 1; +// //printf("xxx io_interrupt\n"); +// } + + if (io_interrupt) { + interrupt = 1; + io_interrupt = 0; + } + + if (pc_skip || io_skip) + pc = pc + 2; + else + if (pc_incr) + pc = pc + 1; + + io_skip = 0; + +F2: + if (opr) { + + ma = (IF<<12) | pc; + + // group 3 + if (mb_bit(8) & mb_bit(0)) + switch (mb_bits(6,4)) { + case 1: mq = ac; break; + case 2: ac = ac | mq; break; +// case 5: tmq <= mq; break; + case 4: ac = mq; break; + case 5: ac = mq; break; + } + } + + if (iot) + ma = (IF<<12) | pc; + + if (!(opr || iot)) { +// ma = (DF<<12) | ((mb_bit(7) ? (ma & 07600) : 0) | mb_bits(6,0)); + ma = (IF<<12) | ((mb_bit(7) ? (pc & 07600) : 0) | mb_bits(6,0)); + if (d_cycle) printf("ea if=%o df=%o, pc %o, ma=%05o (bits %o)\n", + IF, DF, pc, ma, mb_bits(6,0)); + } + +#define get_l_ac() ( (l << 12) | ac ) +#define set_l_ac(v) do { unsigned int vv = (v); \ + l = (vv >> 12) & 1; ac = vv & 07777; } while(0); + +F3: + if (opr) { + + // group 1 + if (!mb_bit(8)) { + if (mb_bit(0)) // IAC + set_l_ac( get_l_ac() + 1 ); + + switch (mb_bits(3,1)) { + case 1: // BSW + set_l_ac( ((get_l_ac() & 077) << 6) | + ((get_l_ac() & 07700) >> 6) ); + break; + + case 2: // RAL + //printf("ral\n"); + set_l_ac( ((get_l_ac() & 010000) >> 12) | + (ac << 1) ); + break; + + case 3: // RTL + //printf("rtl\n"); + set_l_ac( ((get_l_ac() & 010000) ? 2 : 0) | + ((get_l_ac() & 004000) ? 1 : 0) | + (ac << 2) ); + break; + + case 4: // RAR + //printf("rar\n"); + set_l_ac( ((ac & 1) << 12) | + (get_l_ac() >> 1) ); + break; + + case 5: // RTR + //printf("rtr\n"); + set_l_ac( ((ac & 1) ? 004000 : 0) | + ((ac & 2) ? 010000 : 0) | + (get_l_ac() >> 2) ); + break; + } + } + + if (!UF) { + // group 2 + if (mb_bit(8) & !mb_bit(0)) { + if (mb_bit(2)) + ac = ac | switches; + if (mb_bit(1)) { + printf("halt!\n"); + run = 0; + } + } + } + + if (UF) { + // group 2 - user mode (halt & osr) + if (mb_bit(8) & !mb_bit(0)) { + if (mb_bit(2)) + user_interrupt = 1; + if (mb_bit(1)) + user_interrupt = 1; + } + } + + // group 3 + if (mb_bit(8) && mb_bit(0)) + if (mb_bits(7,4) == 016) mq = 0; + + ir = 0; + mb = 0; + return; + } + + if (iot) { + ir = 0; + mb = 0; + return; + } + + if (!(opr || iot)) { + + if (!mb_bit(8) & jmp) { + pc = ma; + ir = 0; + mb = 0; + return; + } + + if (mb_bit(8)) { + mb = 0; + goto D0; + } + + if (!mb_bit(8) & !jmp) { + mb = 0; + goto E0; + } + } + + // DEFER + +D0: + memory_bus = mem[ma]; + if (d_cycle) printf("D0: "); + if (d_mem) printf("mem read [%o] -> %o\n", ma, memory_bus); + mb = memory_bus; + + ram_we = 0; + // auto increment regs + + if (((ma >> 3) & 0377) == 1) { + mb++; + ram_we = 1; + } + + if (ram_we) { + if (d_cycle) printf("D0: "); + if (d_mem) printf("mem write [%o] <- %o\n", ma, mb); + mem[ma] = mb & 07777; + } + ram_we = 0; + + ma = (DF << 12) | mb; + + if (jmp) { + pc = mb; + ir = 0; + mb = 0; + return; + } + + if (!jmp) { + mb = 0; + } + + // EXECUTE +E0: + mb = mem[ma]; + if (d_cycle) printf("E0: "); + if (d_mem) printf("mem read [%o] -> %o\n", ma, mb); + + if (isz) { + if (mb == 07777) pc++; + mb++; + } + + if (dca) + mb = ac; + + if (jms) + mb = pc; + + if (isz || dca || jms) { + ram_we = 1; + } + + if (ram_we) { + if (d_cycle) printf("E0: "); + if (d_mem) printf("mem write [%o] <- %o\n", ma, mb); + mem[ma] = mb & 07777; + } + ram_we = 0; + + // note timing here; ma above is different + + if (!jms) + ma = (IF << 12) | pc; + + if (jms) + ma = ((ma & 070000) << 12) | ((ma & 07777) + 1); + + if (and) + ac = ac & mb; + + if (tad) { + set_l_ac( get_l_ac() + mb ); + } + + if (dca) + ac = 0; + + if (jms) { + if (d_fetch) printf("jms - ma %o\n", ma); + pc = ma; + } + + ir = 0; + +} + +void +loop(void) +{ + run = 1; + + IF = (pc & 070000) >> 12; + DF = IF; + pc &= 07777; + + while (1) { + if (!run) + break; + execute(); + } +} + +main() +{ + if (1) { + d_load = 0; + d_fetch = 0; + d_decode = 0; + d_cycle = 0; + d_trace = 1; + d_mem = 1; + } + + if (0) { + d_load = 0; + d_fetch = 1; + d_decode = 1; + d_cycle = 1; + d_trace = 0; + d_mem = 1; + } + + if (0) { + loadbin("../tss8/tss8_init.bin"); + pc = 024200; + } + + if (1) { + loadbin("../images/focal569.bin"); + pc = 0200; + } + + loop(); +} + + +/* + * Local Variables: + * indent-tabs-mode:nil + * c-basic-offset:4 + * End: +*/ diff --git a/sim/pdp8i b/sim/pdp8i new file mode 100755 index 0000000000000000000000000000000000000000..359c967cbeaa323904d230c6cc473f61c09c76ea GIT binary patch literal 18788 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