/* This file is in the public domain. */ #undef RANDOMSTATE /* define to get random memory contents, registers, etc on startup */ #include #include #include #include #include extern const char *__progname; #define NEED_NAME #define NEED_FUNCTIONS #define NEED_OPFORMATS #define NEED_DEFS #define NEED_ALT_DEFS #include "instrtbl.h" #include "odt.h" #include "pdp11.h" #include "disas.h" #include "instrs.h" #include "deftbl.h" #include "heapsort.h" #include "driverint.h" extern DRIVER *driverlist[]; unsigned char core[CORESIZE]; word genregs[2][6]; word *regset; word sps[4]; word *spp; word pc; word *regs[8]; word psw; word cpu_error; word pirq; word maint; word fps; word fec; word fea; dfword facc[6]; pagedesc pdesc[4][2][8]; word mmr0; word mmr1; word mmr2; word mmr3; word cache_control; word hitmiss; word mem_sys_err; word stack_limit; word micro_break; word console_switch; ubamap ubam[8]; int pswc_cm; int pswc_pri; int pending; int halted; int dma_inhibit; typedef enum odt_state ODT_STATE; enum odt_state { ODT_PROMPT = 1, ODT_R, ODT_OPENLOC, ODT_OPENREG, ODT_OPENINST, ODT_LOC, ODT_REG, ODT_NEWVAL_LOC, ODT_NEWVAL_REG, ODT_PROMPT_PREV_REG, ODT_PROMPT_PREV_LOC, } ; int notraps; jmp_buf notraps_jmp; static jmp_buf trap_jmp; #if 0 static jmp_buf odtdone; static struct sigvec oldsigio; static ODT_STATE odt_state; static unsigned long int odt_xaddr; static unsigned long int odt_xaddrinc; static word odt_xregno; static word odt_newvalue; static int odt_singlestep; #endif static DRIVER *drivers; DRIVER *drivermask[8192]; static INTRQ *intrq_head[8]; static INTRQ **intrq_tail[8]; int intrq_pri; static char *initialfn; void bugchk(const char *, ...) __attribute__((__noreturn__)); void bugchk(const char *fmt, ...) { va_list ap; va_start(ap,fmt); fprintf(stderr,"%s: INTERNAL BUG: ",__progname); vfprintf(stderr,fmt,ap); fprintf(stderr,"\n"); va_end(ap); abort(); } void busreset(void) { DRIVER *d; for (d=drivers;d;d=d->link) if (d->busreset) (*d->busreset)(d); } void checkpsw(void) { int i; psw &= ~PSW_MBZ; i = (psw & PSW_CM) >> PSW_CM_SHIFT; if (i != pswc_cm) { clearpac(); pswc_cm = i; } pswc_pri = (psw & PSW_PRI) >> PSW_PRI_SHIFT; regset = &genregs[(psw&PSW_RS)?1:0][0]; spp = &sps[pswc_cm]; for (i=0;i<6;i++) regs[i] = ®set[i]; regs[6] = spp; regs[7] = &pc; } static void adddriver(DRIVER *d) { int i; d->link = drivers; drivers = d; for (i=0;i<8192;i++) d->iomask[i] = 0; (*d->init)(d,&d->iomask[0]); for (i=0;i<8192;i++) { if (d->iomask[i]) { if (drivermask[i]) { fprintf(stderr,"%o claimed by both %s driver and %s driver\n",0760000|i,drivermask[i]->name,d->name); } drivermask[i] = d; } } } static void initinstrs(void) { deftbl_init(); } static void initdrivers(void) { int i; drivers = 0; for (i=0;i<8192;i++) drivermask[i] = 0; for (i=0;driverlist[i];i++) adddriver(driverlist[i]); for (i=0;i<8;i++) { intrq_head[i] = 0; intrq_tail[i] = &intrq_head[i]; } } static void initmachine(void) { #ifdef RANDOMSTATE { int i; for (i=0;i0;count--) { if (fscanf(f,"%x",&value) != 1) break; if (addr < CORESIZE) core[addr] = value & 0xff; addr ++; } } fclose(f); } void unimpl(void) { trapto(010); } static int checkinterrupt(void) { INTRQ *irq; while (intrq_pri > pswc_pri) { irq = intrq_head[intrq_pri]; if (irq == 0) { intrq_tail[intrq_pri] = &intrq_head[intrq_pri]; intrq_pri --; continue; } if ((irq->driver->intchk == 0) || (*irq->driver->intchk)(irq)) return(1); if (halted) { printf("\r\n[dismissing level %d interrupt from `%s']",intrq_pri,irq->driver->name); } irq->flags &= ~IRQ_F_ACTIVE; intrq_head[intrq_pri] = irq->pri_link; } return(0); } static void takeinterrupt(void) { INTRQ *irq; word oldpc; word oldpsw; irq = intrq_head[intrq_pri]; if (halted) { printf("\r\n[taking interrupt: driver `%s' pri %d vec %o]",irq->driver->name,intrq_pri,irq->vec); } intrq_head[intrq_pri] = irq->pri_link; if (intrq_head[intrq_pri] == 0) { intrq_tail[intrq_pri] = &intrq_head[intrq_pri]; for (intrq_pri--;(intrq_pri>0)&&(intrq_head[intrq_pri]==0);intrq_pri--) ; } if (irq->driver->intack) (*irq->driver->intack)(irq); oldpc = pc; oldpsw = psw; psw = MODE_K << PSW_CM_SHIFT; checkpsw(); pc = fetchword(irq->vec,MMAN_DSPACE); /* this makes more sense to me, but apparently real machines use the uncommented line following.... psw = (fetchword(irq->vec+2,MMAN_DSPACE) & ~(PSW_MBZ|PSW_PRI)) | ((irq->pri << PSW_PRI_SHIFT) & PSW_PRI); */ psw = fetchword(irq->vec+2,MMAN_DSPACE) & ~PSW_MBZ; checkpsw(); sp_push(oldpsw); sp_push(oldpc); irq->flags &= ~IRQ_F_ACTIVE; } static void do_pending(void) { register int pend; pend = pending; pending = 0; if (pend & PEND_YSTACK) { cpu_error |= CPUERR_Y_STACK; trapto(4); } if (pend & PEND_TRACE) { trapto(014); } } static void step(void) { register word iaddr; register word inst; register int dno; register DRIVER *d; static int last_pri = 7; /*dumpstate();*/ if (pswc_pri > last_pri) last_pri = pswc_pri; if (intrq_pri > last_pri) { if (checkinterrupt()) takeinterrupt(); return; } last_pri = pswc_pri; for (d=drivers;d;d=d->link) { void (*f)(DRIVER *); f = d->tick; if (f) (*f)(d); } iaddr = pc; if (! MMR_FROZEN) { mmr1 = 0; mmr2 = iaddr; } pc += 2; inst = fetchword(iaddr,MMAN_ISPACE); if (psw & PSW_T) pending |= PEND_TRACE; dno = get_deftbl(inst); if (dno == DEF_UNUSED) unimpl(); (*instr_defs[dno].fxn)(inst); if (pending) do_pending(); } static void dohalt(void) { if (maint & MAINT_HALTOPT) { sps[MODE_K] = 4; trapto(04); halted = 0; } else { odt(); } } static void run(void) { halted = 0; notraps = 0; switch (maint & MAINT_POWEROPT) { case MAINT_POWEROPT_TRAP24: pc = fetchword(024,MMAN_DSPACE); psw = fetchword(026,MMAN_DSPACE) & ~PSW_MBZ; break; case MAINT_POWEROPT_ODT: odt(); break; case MAINT_POWEROPT_173000: pc = 0173000; psw = PSW_PRI; break; case MAINT_POWEROPT_USERBOOT: pc = maint & MAINT_BOOTADDR; psw = PSW_PRI; break; } checkpsw(); while (setjmp(trap_jmp)) { if (halted) dohalt(); } while (1) { step(); if (halted) dohalt(); } } void trapto(word trapv) { static int doing_trap = 0; word newpsw; word oldpc; word oldpsw; if (notraps) longjmp(notraps_jmp,1); oldpc = pc; oldpsw = psw; doing_trap ++; switch (doing_trap) { case 1: psw = MODE_K << PSW_CM_SHIFT; checkpsw(); pc = fetchword(trapv,MMAN_DSPACE); newpsw = fetchword(trapv+2,MMAN_DSPACE); psw = newpsw & ~PSW_MBZ; checkpsw(); sp_push(oldpsw); sp_push(oldpc); break; case 2: psw = MODE_K << PSW_CM_SHIFT; checkpsw(); pc = fetchword(04,MMAN_DSPACE); newpsw = fetchword(06,MMAN_DSPACE); psw = newpsw & ~PSW_MBZ; checkpsw(); storeword(2,MMAN_DSPACE,oldpsw); storeword(0,MMAN_DSPACE,oldpc); sp = 0; break; default: mmr0 &= ~MMR0_MM_ENB; pc = core[4] | (core[5] << 8); newpsw = core[6] | (core[7] << 8); psw = (newpsw & ~(PSW_MBZ|PSW_CM|PSW_PRI)) | (MODE_K << PSW_CM_SHIFT) | (7 << PSW_PRI_SHIFT); checkpsw(); core[0] = oldpc & 0xff; core[1] = (oldpc >> 8) & 0xff; core[2] = oldpsw & 0xff; core[3] = (oldpsw >> 8) & 0xff; sp = 0; break; } doing_trap --; longjmp(trap_jmp,1); } void interrupt(DRIVER *d, int vec, int pri) { INTRQ *irq; irq = &d->irq[pri]; if (irq->flags & IRQ_F_ACTIVE) return; irq->driver = d; irq->vec = vec; irq->pri = pri; irq->pri_link = 0; irq->flags |= IRQ_F_ACTIVE; *intrq_tail[pri] = irq; intrq_tail[pri] = &irq->pri_link; if (pri > intrq_pri) intrq_pri = pri; } int main(int, char **); int main(int ac, char **av) { int skip; int errs; int argno; if (0) { usage:; fprintf(stderr,"Usage: %s initial-core-file\n",__progname); exit(1); } skip = 0; errs = 0; argno = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av == '-') { for (++*av;**av;++*av) { fprintf(stderr,"%s: bad flag -%c\n",__progname,**av); errs ++; } } else { switch (argno++) { default: fprintf(stderr,"%s: extra argument %s\n",__progname,*av); errs ++; break; case 0: initialfn = *av; break; } } } if (errs) goto usage; if (! initialfn) goto usage; initinstrs(); initdrivers(); initmachine(); loadcore(initialfn); run(); exit(0); } #if 0 dumpstate() { printf("\r\n"); printf("r0=%06o r2=%06o r4=%06o sp=%06o\r\n",r0,r2,r4,r6); printf("r1=%06o r3=%06o r5=%06o pc=%06o\r\n",r1,r3,r5,r7); printf("psw=%06o: cm=%c pm=%c rs=%d pri=%d t=%d n=%d z=%d v=%d c=%d\r\n", psw, "ks?u"[(psw&PSW_CM)>>PSW_CM_SHIFT], "ks?u"[(psw&PSW_PM)>>PSW_PM_SHIFT], (psw&PSW_RS) ? 1 : 0, (psw&PSW_PRI) >> PSW_PRI_SHIFT, (psw&PSW_T) ? 1 : 0, (psw&PSW_N) ? 1 : 0, (psw&PSW_Z) ? 1 : 0, (psw&PSW_V) ? 1 : 0, (psw&PSW_C) ? 1 : 0 ); } #define state odt_state #define xaddr odt_xaddr #define xaddrinc odt_xaddrinc #define xregno odt_xregno #define newvalue odt_newvalue #define singlestep odt_singlestep static Gcmd(addr) word addr; { mmr0 = 0; mmr3 = 0; pirq = 0; fps = 0; cpu_error = 0; /* set ccr<8> (flush), clear mem_sys_err */ psw = 0; pc = addr; halted = 0; longjmp(odtdone,1); } static Pcmd() { halted = 0; longjmp(odtdone,1); } static Scmd() { halted = 1; singlestep = 1; longjmp(odtdone,1); } static signaltype nullh() { } static setsigio() { struct sigvec sv; sv.sv_handler = nullh; sv.sv_mask = 0; sv.sv_flags = 0; sigvec(SIGIO,&sv,&oldsigio); } static resetsigio() { sigvec(SIGIO,&oldsigio,(struct sigvec *)0); } static flushin() { char ch; while (read(0,&ch,1) == 1) ; } static int get() { char ch; fflush(stdout); while (1) { if (read(0,&ch,1) == 1) return(ch); sigpause(0); } } void put(char ch) { putchar(ch); } void put_s(const char *s) { for (;*s;s++) put(*s); } void put_q(void) { put_s("?\r\n@"); } void put_8(unsigned long int val) { int i; val &= 017777777; for (i=21;i>=0;i-=3) put('0'+((val>>i)&7)); } void put_6(word val) { int i; val &= 0xffff; for (i=15;i>=0;i-=3) put('0'+((val>>i)&7)); } void put_3(word val) { put('0'+((val>>6)&3)); put('0'+((val>>3)&7)); put('0'+(val&7)); } void put_2(word val) { put('0'+((val>>3)&7)); put('0'+(val&7)); } odt() { setsigio(); if (setjmp(odtdone)) { fflush(stdout); resetsigio(); notraps = 0; return; } flushin(); cons__flush(); state = ODT_PROMPT; notraps = 1; while (setjmp(notraps_jmp)) { char obuf[64]; sprintf(&obuf[0],"(trap from %d)",state); puts(&obuf[0]); state = ODT_PROMPT; } puts("\r\n"); if (singlestep) { singlestep = 0; if (intrq_pri > pswc_pri) { puts("[possible level "); put('0'+intrq_pri); puts(" interrupt pending]\r\n"); } disas(pc); } else { put6(pc); } puts("\r\n@"); fflush(stdout); while (1) { int ch; ch = 0x7f & get(); if (ch == 3) { cons__reset(); exit(0); } if (ch != 012) put(ch); switch (state) { case ODT_PROMPT: case ODT_PROMPT_PREV_REG: case ODT_PROMPT_PREV_LOC: switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': state = ODT_LOC; xaddr = ch - '0'; break; case 'r': case 'R': case '$': state = ODT_R; xregno = 0; break; case 'g': case 'G': Gcmd((word)0); break; case 'p': case 'P': Pcmd(); break; case 's': case 'S': Scmd(); break; case 'Q': cons__reset(); exit(0); break; case 'Z': kill(getpid(),SIGTSTP); break; case '/': switch (state) { case ODT_PROMPT: putq(); break; case ODT_PROMPT_PREV_REG: xregno &= 0377; if (xregno != 077) xregno &= 7; state = ODT_OPENREG; put6((xregno>7)?psw:*regs[xregno]); put(' '); break; case ODT_PROMPT_PREV_LOC: xaddr &= 017777776; state = ODT_OPENLOC; put6(fetchphys(xaddr)); put(' '); break; } break; default: state = ODT_PROMPT; putq(); break; } break; case ODT_R: switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': state = ODT_REG; xregno = (xregno << 3) | (ch - '0'); break; case 's': case 'S': state = ODT_REG; xregno = 077; break; default: state = ODT_PROMPT; putq(); break; } break; case ODT_OPENLOC: switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': state = ODT_NEWVAL_LOC; newvalue = ch - '0'; break; case '\r': state = ODT_PROMPT_PREV_LOC; puts("\n@"); break; case '\n': xaddr = (xaddr & ~0xffff) | ((xaddr + 2) & 0xfffe); state = ODT_OPENLOC; puts("\r\n@"); put8(xaddr,8); put('/'); put6(fetchphys(xaddr)); put(' '); break; default: state = ODT_PROMPT; putq(); break; } break; case ODT_OPENREG: switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': state = ODT_NEWVAL_REG; newvalue = ch - '0'; break; case '\r': state = ODT_PROMPT_PREV_REG; puts("\n@"); break; case '\n': if (xregno > 7) { state = ODT_PROMPT_PREV_REG; puts("\r\n@"); } else { xregno = (xregno + 1) & 7; state = ODT_OPENREG; puts("\r\n@R"); put('0'+xregno); put('/'); put6(*regs[xregno]); put(' '); } break; default: state = ODT_PROMPT; putq(); break; } break; case ODT_OPENINST: switch (ch) { case '\r': state = ODT_PROMPT_PREV_LOC; puts("\n@"); break; case '\n': xaddr += xaddrinc; puts("\r\n"); xaddrinc = disas(xaddr&0xfffe); put(' '); break; default: state = ODT_PROMPT; putq(); break; } break; case ODT_LOC: switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': xaddr = (xaddr << 3) | (ch - '0'); break; case '/': xaddr &= 017777776; state = ODT_OPENLOC; put6(fetchphys(xaddr)); put(' '); break; case 'g': case 'G': Gcmd(xaddr&0xffff); break; case 's': case 'S': pc = xaddr & 0xffff; Scmd(); break; case 'i': puts("\r\n"); state = ODT_OPENINST; xaddrinc = disas(xaddr&0xfffe); put(' '); break; default: state = ODT_PROMPT; putq(); break; } break; case ODT_REG: switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': xregno = (xregno << 3) | (ch - '0'); break; case 's': case 'S': xregno = 077; break; case '/': xregno &= 0377; if (xregno != 077) xregno &= 7; state = ODT_OPENREG; put6((xregno>7)?psw:*regs[xregno]); put(' '); break; default: state = ODT_PROMPT; putq(); break; } break; case ODT_NEWVAL_LOC: switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': newvalue = (newvalue << 3) | (ch - '0'); break; case '\r': storephys(xaddr,newvalue); state = ODT_PROMPT_PREV_LOC; puts("\n@"); break; case '\n': storephys(xaddr,newvalue); xaddr = (xaddr & ~0xffff) | ((xaddr + 2) & 0xfffe); state = ODT_OPENLOC; puts("\r\n@"); put8(xaddr,8); put('/'); put6(fetchphys(xaddr)); put(' '); break; default: state = ODT_PROMPT; putq(); break; } break; case ODT_NEWVAL_REG: switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': newvalue = (newvalue << 3) | (ch - '0'); break; case '\r': if (xregno > 7) { psw = (psw & PSW_T) | (newvalue & ~(PSW_T|PSW_MBZ)); } else { *regs[xregno] = newvalue; } state = ODT_PROMPT_PREV_REG; puts("\n@"); break; case '\n': if (xregno > 7) { psw = (psw & PSW_T) | (newvalue & ~(PSW_T|PSW_MBZ)); state = ODT_PROMPT_PREV_REG; puts("\r\n@"); } else { *regs[xregno] = newvalue; xregno = (xregno + 1) & 7; state = ODT_OPENREG; puts("\r\n@R"); put('0'+xregno); put('/'); put6(*regs[xregno]); put(' '); } break; default: state = ODT_PROMPT; putq(); break; } break; } } } #endif