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 0000000..d9cf099 Binary files /dev/null and b/sim/a.out differ diff --git a/sim/io.c b/sim/io.c new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/sim/io.c @@ -0,0 +1 @@ + diff --git a/sim/m.c b/sim/m.c new file mode 100644 index 0000000..7796265 --- /dev/null +++ b/sim/m.c @@ -0,0 +1,9 @@ +#define bitmask(h,l) ((unsigned int)0xffffffff >> (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 0000000..359c967 Binary files /dev/null and b/sim/pdp8i differ