/* * 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: */