PDQ-3: Latest update from Holger Veit

- removed cycle counting in CPU, the sim_interval issue
- fixed the Console multiplexer logic; it now works with SET REMOTE TELNET= and SET CONSOLE TELNET=
- commented testhdt.sim
- changed run.cmd to try to execute either VStudio or mingw executable, in this order.
- changed printf messages to use sim_printf

Possible issues remaining:
- timer device polling, not yet debugged, the rate of 1.25MHz is likely still incorrect, so UCSD wall clock is surely wrong
- few instructions still to be trapped by opcode.debug - I haven't seen them in life code yet
- HD device still not yet finished; I'll pick this up again soon
This commit is contained in:
Mark Pizzolato 2014-11-03 15:48:25 -08:00
parent 94486c1286
commit 1817504052
6 changed files with 121 additions and 302 deletions

View file

@ -310,7 +310,7 @@ static t_stat rom_ignore(t_addr ea, uint16 data) {
t_stat cpu_boot(int32 unitnum, DEVICE *dptr) { t_stat cpu_boot(int32 unitnum, DEVICE *dptr) {
t_stat rc; t_stat rc;
uint16 ctp, ssv, rq; uint16 ctp, ssv, rq;
sim_printf("BOOT CPU\n"); // sim_printf("BOOT CPU\n");
cpu_reset(dptr); cpu_reset(dptr);
dbg_init(); dbg_init();
@ -343,7 +343,7 @@ void cpu_finishAutoload() {
/* CPU reset */ /* CPU reset */
t_stat cpu_reset (DEVICE *dptr) { t_stat cpu_reset (DEVICE *dptr) {
sim_printf("CPU RESET\n"); // sim_printf("CPU RESET\n");
sim_brk_types = SWMASK('E')|SWMASK('R')|SWMASK('W'); sim_brk_types = SWMASK('E')|SWMASK('R')|SWMASK('W');
sim_brk_dflt = SWMASK('E'); sim_brk_dflt = SWMASK('E');
@ -709,7 +709,7 @@ static void DoCXG(uint8 segno, uint8 procno) {
// sim_printf("CXG: ptbl=%x, reg_segb=%x\n",ptbl,reg_segb); // sim_printf("CXG: ptbl=%x, reg_segb=%x\n",ptbl,reg_segb);
reg_ipc = createMSCW(ptbl, procno, reg_bp, osegno, osegb); /* call new segment */ reg_ipc = createMSCW(ptbl, procno, reg_bp, osegno, osegb); /* call new segment */
sim_interval -= 63; /* actually 63.2 */ sim_interval--;
} }
static t_stat Raise(uint16 err) { static t_stat Raise(uint16 err) {
@ -788,7 +788,7 @@ static uint16 enque(uint16 qhead, uint16 qtask) {
/* perform a task switch. If no task ready to run, wait for an interrupt */ /* perform a task switch. If no task ready to run, wait for an interrupt */
static t_stat taskswitch6() { static t_stat taskswitch6() {
uint16 vector, sem; uint16 vector, sem;
int level; int level, kbdc;
t_stat rc = SCPE_OK; t_stat rc = SCPE_OK;
// int kbdc; // int kbdc;
sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "Taskswitch6: ctp=$%04x rq=$%04x\n",DBG_PC, reg_ctp, reg_rq); sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "Taskswitch6: ctp=$%04x rq=$%04x\n",DBG_PC, reg_ctp, reg_rq);
@ -804,7 +804,6 @@ static t_stat taskswitch6() {
rc = DoSIGNAL(sem); rc = DoSIGNAL(sem);
return rc; return rc;
} else { } else {
#if 0
kbdc = sim_poll_kbd(); /* check keyboard */ kbdc = sim_poll_kbd(); /* check keyboard */
if (kbdc == SCPE_STOP) return kbdc; /* handle CTRL-E */ if (kbdc == SCPE_STOP) return kbdc; /* handle CTRL-E */
/* process timer */ /* process timer */
@ -812,10 +811,7 @@ static t_stat taskswitch6() {
if ((rc = sim_process_event()) != SCPE_OK) if ((rc = sim_process_event()) != SCPE_OK)
return rc; return rc;
} }
sim_interval -= 4; /* actually 3.6, NOP cycle */
#else
sim_idle(TMR_IDLE, TRUE); sim_idle(TMR_IDLE, TRUE);
#endif
} }
} }
@ -864,7 +860,7 @@ static t_stat DoSIGNAL(uint16 sem) {
sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "SIGNAL: reg_rq=$%x, reg_ctp=$%x\n", DBG_PC, reg_rq, reg_ctp); sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "SIGNAL: reg_rq=$%x, reg_ctp=$%x\n", DBG_PC, reg_rq, reg_ctp);
if (reg_ctp == NIL) { /* no current task (marker for int processing */ if (reg_ctp == NIL) { /* no current task (marker for int processing */
sim_interval -= 135; /* actually 134.8, consume time */ sim_interval--; /* consume time */
return taskswitch6(); /* and switch task */ return taskswitch6(); /* and switch task */
} }
if (Getb(reg_ctp+OFFB_PRIOR,0) < Getb(qtask+OFFB_PRIOR,0)) { /* is qtask higher prio than current task? */ if (Getb(reg_ctp+OFFB_PRIOR,0) < Getb(qtask+OFFB_PRIOR,0)) { /* is qtask higher prio than current task? */
@ -873,7 +869,7 @@ static t_stat DoSIGNAL(uint16 sem) {
} else { } else {
/* else: nothing is waiting on this semaphore, discard argument, and continue */ /* else: nothing is waiting on this semaphore, discard argument, and continue */
reg_sp++; reg_sp++;
sim_interval -= 52; /* correct: 52.0 */ sim_interval--;
} }
return rc; return rc;
} }
@ -882,11 +878,11 @@ static t_stat DoSIGNAL(uint16 sem) {
sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "SIGNAL: Sem=$%x(count=%d): increment\n",DBG_PC, sem, count); sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "SIGNAL: Sem=$%x(count=%d): increment\n",DBG_PC, sem, count);
Put(sem+OFF_SEMCOUNT,count+1); Put(sem+OFF_SEMCOUNT,count+1);
if (reg_ctp == NIL) { /* if no active task, get one from ready queue */ if (reg_ctp == NIL) { /* if no active task, get one from ready queue */
sim_interval -= 135; /* actually 134.8 */ sim_interval--;
return taskswitch6(); return taskswitch6();
} }
reg_sp++; reg_sp++;
sim_interval -= 18; /* correct: 18.0 */ sim_interval--;
return rc; return rc;
} }
@ -905,14 +901,14 @@ static t_stat DoWAIT(uint16 sem) {
// sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "WAIT: new qhead=%x\n",DBG_PC, qhead); // sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "WAIT: new qhead=%x\n",DBG_PC, qhead);
rc = taskswitch5(); /* save context in TIB, and switch to new task from ready queue */ rc = taskswitch5(); /* save context in TIB, and switch to new task from ready queue */
sim_interval -= 91; /* actually 90.8 */ sim_interval--;
sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "WAIT: DONE, switch to newTIB=$%04x\n",DBG_PC, reg_ctp); sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "WAIT: DONE, switch to newTIB=$%04x\n",DBG_PC, reg_ctp);
return rc; return rc;
} else { } else {
sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "WAIT: Sem=$%04x(count=%d): decrement\n", DBG_PC, sem, count); sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "WAIT: Sem=$%04x(count=%d): decrement\n", DBG_PC, sem, count);
Put(sem+OFF_SEMCOUNT,count-1); Put(sem+OFF_SEMCOUNT,count-1);
} }
sim_interval -= 12; /* actually 11.6 */ sim_interval--;
sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "WAIT: DONE, continue\n",DBG_PC); sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "WAIT: DONE, continue\n",DBG_PC);
return SCPE_OK; return SCPE_OK;
} }
@ -933,7 +929,6 @@ static t_stat DoInstr(void) {
uint8 ub1, ub2; uint8 ub1, ub2;
uint8 segno, osegno, procno; uint8 segno, osegno, procno;
float tf1, tf2; float tf1, tf2;
double cyc = 0.0;
int i; int i;
/* set PCX: current instr in progress */ /* set PCX: current instr in progress */
@ -959,229 +954,179 @@ static t_stat DoInstr(void) {
case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
/* SLDCi */ /* SLDCi */
Push(opcode & 0x1f); Push(opcode & 0x1f);
cyc = 2.8;
break; break;
case 0x98: /* LDCN */ case 0x98: /* LDCN */
Push(NIL); Push(NIL);
cyc = 6.4;
break; break;
case 0x80: /* LDCB */ case 0x80: /* LDCB */
Push(UB()); Push(UB());
cyc = 5.6;
break; break;
case 0x81: /* LDCI */ case 0x81: /* LDCI */
Push(W()); Push(W());
cyc = 8.4;
break; break;
case 0x82: /* LCA */ case 0x82: /* LCA */
Push(reg_segb + B()); Push(reg_segb + B());
cyc = 8.0;
break; break;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
/* SLDLi */ /* SLDLi */
Push(Get(reg_mp + MSCW_SZ + (opcode & 0x0f))); Push(Get(reg_mp + MSCW_SZ + (opcode & 0x0f)));
cyc = 6.4;
break; break;
case 0x87: /* LDL */ case 0x87: /* LDL */
Push(Get(reg_mp + MSCW_SZ -1 + B())); Push(Get(reg_mp + MSCW_SZ -1 + B()));
cyc = 9.6;
break; break;
case 0x84: /* LLA */ case 0x84: /* LLA */
Push(reg_mp + MSCW_SZ -1 + B()); Push(reg_mp + MSCW_SZ -1 + B());
cyc = 7.6;
break; break;
case 0xa4: /* STL */ case 0xa4: /* STL */
Put(reg_mp + MSCW_SZ -1 + B(), Pop()); Put(reg_mp + MSCW_SZ -1 + B(), Pop());
cyc = 9.6;
break; break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
/* SLDOi */ /* SLDOi */
Push(Get(reg_bp + MSCW_SZ + (opcode & 0x0f))); Push(Get(reg_bp + MSCW_SZ + (opcode & 0x0f)));
cyc = 7.2;
break; break;
case 0x85: /* LDO */ case 0x85: /* LDO */
Push(Get(reg_bp + MSCW_SZ -1 + B())); Push(Get(reg_bp + MSCW_SZ -1 + B()));
cyc = 10.0;
break; break;
case 0x86: /* LAO */ case 0x86: /* LAO */
Push(reg_bp + MSCW_SZ -1 + B()); Push(reg_bp + MSCW_SZ -1 + B());
cyc = 8.0;
break; break;
case 0xa5: /* SRO */ case 0xa5: /* SRO */
Put(reg_bp + MSCW_SZ -1 + B(),Pop()); Put(reg_bp + MSCW_SZ -1 + B(),Pop());
cyc = 13.2;
break; break;
case 0x89: /* LOD */ case 0x89: /* LOD */
db = DB(); reg_lm = TraverseMSstat(DB());
reg_lm = TraverseMSstat(db);
Push(Get(reg_lm + MSCW_SZ -1 + B())); Push(Get(reg_lm + MSCW_SZ -1 + B()));
cyc = 17.2 + 3.2*db;
break; break;
case 0x88: /* LDA */ case 0x88: /* LDA */
db = DB(); reg_lm = TraverseMSstat(DB());
reg_lm = TraverseMSstat(db);
Push(reg_lm + MSCW_SZ -1 + B()); Push(reg_lm + MSCW_SZ -1 + B());
cyc = 15.2 + 3.2*db;
break; break;
case 0xa6: /* STR */ case 0xa6: /* STR */
db = DB(); reg_lm = TraverseMSstat(DB());
reg_lm = TraverseMSstat(db);
Put(reg_lm + MSCW_SZ -1 + B(),Pop()); Put(reg_lm + MSCW_SZ -1 + B(),Pop());
cyc = 16.8 * 3.2*db;
break; break;
case 0xc4: /* STO */ case 0xc4: /* STO */
t1 = Pop(); Put(Pop(),t1); t1 = Pop(); Put(Pop(),t1);
cyc = 8.0;
break; break;
case 0x9a: /* LDE */ case 0x9a: /* LDE */
t2 = GetSegbase(UB()); Push(Get(t2 + B())); t2 = GetSegbase(UB()); Push(Get(t2 + B()));
cyc = 26.8;
break; break;
case 0x9b: /* LAE */ case 0x9b: /* LAE */
ub1 = UB(); ub1 = UB();
Push(GetSegbase(ub1) + B()); Push(GetSegbase(ub1) + B());
cyc = 24.8;
break; break;
case 0xd9: /* STE */ case 0xd9: /* STE */
ub1 = UB(); ub1 = UB();
Put(GetSegbase(ub1) + B(), Pop()); Put(GetSegbase(ub1) + B(), Pop());
cyc = 26.0;
break; break;
case 0x83: /* LDC */ case 0x83: /* LDC */
b = B(); ub1 = UB(); b = B(); ub1 = UB();
src = reg_segb + b + ub1; src = reg_segb + b + ub1;
for (i=1; i<=ub1; i++) Put(reg_sp-i,Get(src-i)); for (i=1; i<=ub1; i++) Put(reg_sp-i,Get(src-i));
reg_sp -= ub1; reg_sp -= ub1;
cyc = 18.0 + 4.0*ub1;
break; break;
case 0xd0: /* LDM */ case 0xd0: /* LDM */
ub1 = UB(); src = Pop() + ub1; ub1 = UB(); src = Pop() + ub1;
for (i=1; i<=ub1; i++) Put(reg_sp-i,Get(src-i)); for (i=1; i<=ub1; i++) Put(reg_sp-i,Get(src-i));
reg_sp -= ub1; reg_sp -= ub1;
cyc = 10.4 + 6.0*ub1;
break; break;
case 0x8e: /* STM */ case 0x8e: /* STM */
ub1 = UB(); dst = Get(reg_sp+ub1); ub1 = UB(); dst = Get(reg_sp+ub1);
for (i=0; i<=(ub1-1); i++) Put(dst+i,Pick(i)); for (i=0; i<=(ub1-1); i++) Put(dst+i,Pick(i));
reg_sp += (ub1+1); reg_sp += (ub1+1);
cyc = 12.4 + 6.0*ub1;
break; break;
case 0xa7: /* LDB */ case 0xa7: /* LDB */
b = Pop(); b = Pop();
Push(Getb(Pop(), b)); Push(Getb(Pop(), b));
cyc = 12.0;
break; break;
case 0xc8: /* STB */ case 0xc8: /* STB */
ub1 = Pop() & 0xff; /* index */ b = Pop(); /* byteaddr */ ub1 = Pop() & 0xff; /* index */ b = Pop(); /* byteaddr */
Putb(Pop(), b, ub1); Putb(Pop(), b, ub1);
cyc = 13.6;
break; break;
case 0xc5: /* MOV */ case 0xc5: /* MOV */
b = B(); src = Pop(); dst = Pop(); b = B(); src = Pop(); dst = Pop();
for (i=0; i<=(b-1); i++) Put(dst+i,Get(src+i)); for (i=0; i<=(b-1); i++) Put(dst+i,Get(src+i));
cyc = 13.2 + 6.0*b;
break; break;
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
/* SINDi */ /* SINDi */
Push(Get(Pop() + (opcode & 0x07))); Push(Get(Pop() + (opcode & 0x07)));
cyc = 8.4;
break; break;
case 0xe6: /* IND */ case 0xe6: /* IND */
Push(Get(Pop() + B())); Push(Get(Pop() + B()));
cyc = 12.4;
break; break;
case 0xe7: /* INC */ case 0xe7: /* INC */
Push(Pop() + B()); Push(Pop() + B());
cyc = 9.6;
break; break;
case 0xd7: /* IXA */ case 0xd7: /* IXA */
b = B(); t1 = Pop(); Push(Pop() + t1*b); b = B(); t1 = Pop(); Push(Pop() + t1*b);
cyc = 9.6 + b/16384.*46.4;
break; break;
case 0xd8: /* IXP */ case 0xd8: /* IXP */
ub1 = UB(); ub2 = UB(); inx = Pop(); ub1 = UB(); ub2 = UB(); inx = Pop();
Push(Pop() + inx / ub1); Push(Pop() + inx / ub1);
Push(ub2); Push((inx % ub1) * ub2); Push(ub2); Push((inx % ub1) * ub2);
cyc = 35.6; /* inaccurate */
break; break;
case 0xc9: /* LDP */ case 0xc9: /* LDP */
t1 = Pop(); /*start*/ t2 = Pop(); /*nbits*/ t1 = Pop(); /*start*/ t2 = Pop(); /*nbits*/
/* Bogus warning: WD9693_PasIII_OSref_Jul82 is wrong here: /* Bogus warning: WD9693_PasIII_OSref_Jul82 is wrong here:
* (sp+2) is an address not a value, so must be dereferenced first */ * (sp+2) is an address not a value, so must be dereferenced first */
Push((Get(Pop() /*addr*/) & GetMask(t1,t2)) >> t1); Push((Get(Pop() /*addr*/) & GetMask(t1,t2)) >> t1);
cyc = 18.4 + 2.0*(t1+t2);
break; break;
case 0xca: /* STP */ case 0xca: /* STP */
t4 = Pop(); /*data*/ t1 = Pop(); /*start*/ t2 = Pop(); /*nbits*/ t4 = Pop(); /*data*/ t1 = Pop(); /*start*/ t2 = Pop(); /*nbits*/
t3 = Pop(); /*addr*/ t5 = Get(t3); t3 = Pop(); /*addr*/ t5 = Get(t3);
clrbit(t5,GetMask(t1,t2)); t4 = (t4 & masks[t2]) << t1; clrbit(t5,GetMask(t1,t2)); t4 = (t4 & masks[t2]) << t1;
Put(t3, t5 | t4); Put(t3, t5 | t4);
cyc = 20.4 + 2.0*t2 + 2.8*t1;
break; break;
case 0xa1: /* LAND */ case 0xa1: /* LAND */
Push(Pop() & Pop()); Push(Pop() & Pop());
cyc = 8.0;
break; break;
case 0xa0: /* LOR */ case 0xa0: /* LOR */
Push(Pop() | Pop()); Push(Pop() | Pop());
cyc = 8.0;
break; break;
case 0xe5: /* LNOT */ case 0xe5: /* LNOT */
Push(~Pop()); Push(~Pop());
cyc = 5.2;
break; break;
case 0x9f: /* BNOT */ case 0x9f: /* BNOT */
Push((~Pop()) & 1); Push((~Pop()) & 1);
cyc = 6.0;
break; break;
case 0xb4: /* LEUSW */ case 0xb4: /* LEUSW */
t1 = Pop(); t2 = Pop() <= t1 ? 1 : 0; t1 = Pop(); t2 = Pop() <= t1 ? 1 : 0;
Push(t2); Push(t2);
cyc = t2 ? 9.6 : 10.4;
break; break;
case 0xb5: /* GEUSW */ case 0xb5: /* GEUSW */
t1 = Pop(); t2 = Pop() >= t1 ? 1 : 0; t1 = Pop(); t2 = Pop() >= t1 ? 1 : 0;
Push(t2); Push(t2);
cyc = t2 ? 9.6 : 10.4;
break; break;
case 0xe0: /* ABI */ case 0xe0: /* ABI */
ts1 = PopS(); ts1 = PopS();
PushS(ts1 < 0 ? -ts1 : ts1); PushS(ts1 < 0 ? -ts1 : ts1);
cyc = ts1 < 0 ? 6.0 : 4.8;
break; break;
case 0xe1: /* NGI */ case 0xe1: /* NGI */
PushS(-PopS()); PushS(-PopS());
cyc = 5.2;
break; break;
case 0xe2: /* DUP1 */ case 0xe2: /* DUP1 */
Push(Tos()); Push(Tos());
cyc = 5.2;
break; break;
case 0xa2: /* ADI */ case 0xa2: /* ADI */
PushS(PopS() + Pop()); PushS(PopS() + Pop());
cyc = 8.0;
break; break;
case 0xa3: /* SBI */ case 0xa3: /* SBI */
ts1 = PopS(); PushS(PopS() - ts1); ts1 = PopS(); PushS(PopS() - ts1);
cyc = 8.0;
break; break;
case 0x8c: /* MPI */ case 0x8c: /* MPI */
PushS(Pop() * Pop()); PushS(Pop() * Pop());
cyc = 28.0; /* average */
break; break;
case 0x8d: /* DVI */ case 0x8d: /* DVI */
ts1 = PopS(); if (ts1 == 0) { Raise(PASERROR_DIVZERO); break; } ts1 = PopS(); if (ts1 == 0) { Raise(PASERROR_DIVZERO); break; }
ts2 = PopS() / ts1; ts2 = PopS() / ts1;
PushS(ts2); PushS(ts2);
cyc = ts2 == 0 ? 8.4 : (ts2 > 0 ? 89.2 : 91.2);
break; break;
case 0x8f: /* MODI */ case 0x8f: /* MODI */
ts1 = PopS(); if (ts1 <= 0) { Raise(PASERROR_DIVZERO); /* XXX */ break; } ts1 = PopS(); if (ts1 <= 0) { Raise(PASERROR_DIVZERO); /* XXX */ break; }
ts2 = Pop() % ts1; ts2 = Pop() % ts1;
PushS(ts2); PushS(ts2);
cyc = ts2 == 0 ? 8.4 : (ts2 > 0 ? 89.2 : 91.2);
break; break;
case 0xcb: /* CHK */ case 0xcb: /* CHK */
t1 = Tos(); t2 = Pick(1); t3 = Pick(2); t1 = Tos(); t2 = Pick(1); t3 = Pick(2);
@ -1189,102 +1134,81 @@ static t_stat DoInstr(void) {
reg_sp += 2; reg_sp += 2;
else else
Raise(PASERROR_VALRANGE); Raise(PASERROR_VALRANGE);
cyc = 14.4;
break; break;
case 0xb0: /* EQUI */ case 0xb0: /* EQUI */
t1 = PopS()==PopS() ? 1 : 0; t1 = PopS()==PopS() ? 1 : 0;
Push(t1); Push(t1);
cyc = t1 ? 9.6 : 10.4;
break; break;
case 0xb1: /* NEQI */ case 0xb1: /* NEQI */
t1 = PopS()==PopS() ? 0 : 1; t1 = PopS()==PopS() ? 0 : 1;
Push(t1); Push(t1);
cyc = t1 ? 9.6 : 10.4;
break; break;
case 0xb2: /* LEQI */ case 0xb2: /* LEQI */
ts1 = PopS(); t2 = PopS() <= ts1 ? 1 : 0; ts1 = PopS(); t2 = PopS() <= ts1 ? 1 : 0;
Push(t2); Push(t2);
cyc = t2 ? 10.4 : 11.2;
break; break;
case 0xb3: /* GEQI */ case 0xb3: /* GEQI */
ts1 = PopS(); t2 = PopS() >= ts1 ? 1 : 0; ts1 = PopS(); t2 = PopS() >= ts1 ? 1 : 0;
Push(t2); Push(t2);
cyc = t2 ? 10.4 : 11.2;
break; break;
case 0xcc: /* FLT */ case 0xcc: /* FLT */
t1 = PopS(); t1 = PopS();
PushF((float)t1); PushF((float)t1);
cyc = t1 ? 30.8 : 10.8;
break; break;
case 0xbe: /* TNC */ case 0xbe: /* TNC */
tf1 = PopF(); tf1 = PopF();
PushS((int16)tf1); PushS((int16)tf1);
cyc = tf1 ? (fabs(tf1)<0.5 ? 15.6 : 37.4) : 12.4; /* approximate */
break; break;
case 0xbf: /* RND */ case 0xbf: /* RND */
tf1 = PopF(); tf1 = PopF();
PushS((int16)(tf1+0.5)); PushS((int16)(tf1+0.5));
cyc = tf1 ? (fabs(tf1)<0.5 ? 15.6 : 37.4) : 12.4; /* approximate */
break; break;
case 0xe3: /* ABR */ case 0xe3: /* ABR */
PushF((float)fabs(PopF())); PushF((float)fabs(PopF()));
cyc = 5.2;
break; break;
case 0xe4: /* NGR */ case 0xe4: /* NGR */
PushF(-PopF()); PushF(-PopF());
cyc = 5.2;
break; break;
case 0xc0: /* ADR */ case 0xc0: /* ADR */
tf1 = PopF(); tf1 = PopF();
PushF(tf1 + PopF()); PushF(tf1 + PopF());
cyc = tf1 ? 106.8 : 18.8; /* average */
break; break;
case 0xc1: /* SBR */ case 0xc1: /* SBR */
tf1 = PopF(); PushF(PopF() - tf1); tf1 = PopF(); PushF(PopF() - tf1);
cyc = tf1 ? 110.0 : 19.2; /* average */
break; break;
case 0xc2: /* MPR */ case 0xc2: /* MPR */
tf1 = PopF(); tf1 = PopF();
PushF(tf1 * PopF()); PushF(tf1 * PopF());
cyc = tf1 ? 168.6 : 26.4; /* average */
break; break;
case 0xc3: /* DVR */ case 0xc3: /* DVR */
tf1 = PopF(); if (tf1 == 0) { Raise(PASERROR_DIVZERO); break; } tf1 = PopF(); if (tf1 == 0) { Raise(PASERROR_DIVZERO); break; }
tf2 = PopF(); tf2 = PopF();
PushF(tf2 / tf1); PushF(tf2 / tf1);
cyc = tf2 ? 217.2 : 32.4; /* average */
break; break;
case 0xcd: /* EQUREAL */ case 0xcd: /* EQUREAL */
tf1 = PopF(); tf1 = PopF();
t1 = tf1==PopF() ? 1 : 0; t1 = tf1==PopF() ? 1 : 0;
Push(t1); Push(t1);
cyc = t1 ? 16.4 : (tf1 ? 18.4 : 14.8); /* average */
break; break;
case 0xce: /* LEQREAL */ case 0xce: /* LEQREAL */
tf1 = PopF(); tf2 = PopF(); tf1 = PopF(); tf2 = PopF();
t1 = tf2 <= tf1 ? 1 : 0; t1 = tf2 <= tf1 ? 1 : 0;
Push(t1); Push(t1);
cyc = tf1==tf2 ? 16.4 : (tf1 < tf2 ? 18.2 : 19.4); /* average */
break; break;
case 0xcf: /* GEQREAL */ case 0xcf: /* GEQREAL */
tf1 = PopF(); tf2 = PopF(); tf1 = PopF(); tf2 = PopF();
Push(tf2 >= tf1 ? 1 : 0); Push(tf2 >= tf1 ? 1 : 0);
cyc = tf1==tf2 ? 16.4 : 18.2; /* average */
break; break;
case 0xc6: /* DUP2 */ case 0xc6: /* DUP2 */
Push(Pick(1)); Push(Pick(1)); Push(Pick(1)); Push(Pick(1));
cyc = 12.0;
break; break;
case 0xc7: /* ADJ */ case 0xc7: /* ADJ */
ub1 = UB(); len0 = Tos(); src = reg_sp+1; dst = reg_sp + len0 - ub1 +1; ub1 = UB(); len0 = Tos(); src = reg_sp+1; dst = reg_sp + len0 - ub1 +1;
cyc = 14.4;
if (len0 > ub1) { if (len0 > ub1) {
for (i=1; i<=ub1; i++) Put(dst + ub1 -i, Get(src + ub1 - i)); for (i=1; i<=ub1; i++) Put(dst + ub1 -i, Get(src + ub1 - i));
cyc = 13.6 + 6.8*ub1;
} else { } else {
for (i=0; i<len0; i++) Put(dst + i, Get(src + i)); for (i=0; i<len0; i++) Put(dst + i, Get(src + i));
for (i=len0; i<ub1; i++) Put(dst+i,0); for (i=len0; i<ub1; i++) Put(dst+i,0);
cyc = 16.4 + 5.6*len0 + 2.8*(ub1-len0);
} }
reg_sp += (len0-ub1+1); reg_sp += (len0-ub1+1);
break; break;
@ -1294,7 +1218,6 @@ static t_stat DoInstr(void) {
if (hi <= (BSET_SZ-1) && lo <= (BSET_SZ-1)) { if (hi <= (BSET_SZ-1) && lo <= (BSET_SZ-1)) {
if (lo > hi) { if (lo > hi) {
reg_sp++; Put(reg_sp,0); reg_sp++; Put(reg_sp,0);
cyc = 18.0;
} else { } else {
len0 = hi / WORD_SZ +1; len0 = hi / WORD_SZ +1;
reg_sp -= (len0-1); Put(reg_sp,len0); reg_sp -= (len0-1); Put(reg_sp,len0);
@ -1309,7 +1232,6 @@ static t_stat DoInstr(void) {
Put(t2, src); Put(t2, src);
} }
} }
cyc = t1==1 ? 80.4 : (t1==2 ? 83.2 : (45.6 + 3.6*hi/WORD_SZ + 2.0*((hi+lo)%WORD_SZ))); /*approx*/
} }
} else } else
Raise(PASERROR_VALRANGE); Raise(PASERROR_VALRANGE);
@ -1319,7 +1241,6 @@ static t_stat DoInstr(void) {
t2 = (0 <= ts1 && ts1 <= (len0*WORD_SZ -1)) ? GetBit(reg_sp+1, ts1) : 0; t2 = (0 <= ts1 && ts1 <= (len0*WORD_SZ -1)) ? GetBit(reg_sp+1, ts1) : 0;
Put(reg_sp + len0 + 1,t2); Put(reg_sp + len0 + 1,t2);
reg_sp += (len0+1); reg_sp += (len0+1);
cyc = t2 ? (22.8 + len0 % WORD_SZ) : 18.4;
break; break;
case 0xdb: /* UNI */ case 0xdb: /* UNI */
len0 = Tos(); len1 = Pick(len0 + 1); len0 = Tos(); len1 = Pick(len0 + 1);
@ -1329,14 +1250,12 @@ static t_stat DoInstr(void) {
src = reg_sp + 1; dst = reg_sp + len0 + 2; src = reg_sp + 1; dst = reg_sp + len0 + 2;
for (i=0; i<len0; i++) Put(dst+i, Get(dst+i) | Get(src+i)); for (i=0; i<len0; i++) Put(dst+i, Get(dst+i) | Get(src+i));
reg_sp += (len0+1); reg_sp += (len0+1);
cyc = len0==0 ? 6.6 : (12.4 + 7.2*len0);
} else { } else {
src = reg_sp + len0 + 2; dst = reg_sp + 1; src = reg_sp + len0 + 2; dst = reg_sp + 1;
for (i=0; i<len1; i++) Put(dst+i, Get(dst+i) | Get(src+i)); for (i=0; i<len1; i++) Put(dst+i, Get(dst+i) | Get(src+i));
src = reg_sp + len0; dst = reg_sp + len0 + len1 + 1; src = reg_sp + len0; dst = reg_sp + len0 + len1 + 1;
for (i=0; i<= len0; i++) Put(dst-i, Get(src-i)); for (i=0; i<= len0; i++) Put(dst-i, Get(src-i));
reg_sp += (len1+1); reg_sp += (len1+1);
cyc = len1==0 ? (22.4 + 6.8*len0) : (24.0 + 14.0*len0 + 6.8*(len1-len0));
} }
break; break;
case 0xdc: /* INT */ case 0xdc: /* INT */
@ -1345,21 +1264,17 @@ static t_stat DoInstr(void) {
len0 = Tos(); len1 = Pick(len0 + 1); len0 = Tos(); len1 = Pick(len0 + 1);
if (len0==0) { if (len0==0) {
reg_sp += (len1+1); Put(reg_sp,0); reg_sp += (len1+1); Put(reg_sp,0);
cyc = len1 ? 12.0 : 11.6;
} else if (len1==0) { } else if (len1==0) {
reg_sp += (len0+1); reg_sp += (len0+1);
cyc = len0 ? 11.6 : 12.0;
} else if (len1 > len0) { } else if (len1 > len0) {
src = reg_sp+1; dst = reg_sp+len0 + 2; src = reg_sp+1; dst = reg_sp+len0 + 2;
for (i=0; i<len0; i++) Put(dst+i,Get(dst+i) & Get(src+i)); for (i=0; i<len0; i++) Put(dst+i,Get(dst+i) & Get(src+i));
for (i=len0; i<len1; i++) Put(dst+i,0); for (i=len0; i<len1; i++) Put(dst+i,0);
reg_sp += (len0+1); reg_sp += (len0+1);
cyc = 15.2 + 7.2*len0;
} else { } else {
dst = reg_sp+ len0 + 2; src = reg_sp +1; dst = reg_sp+ len0 + 2; src = reg_sp +1;
for (i=0; i<len1; i++) Put(dst+i,Get(dst+i) & Get(src+i)); for (i=0; i<len1; i++) Put(dst+i,Get(dst+i) & Get(src+i));
reg_sp += (len0+1); reg_sp += (len0+1);
cyc = 15.2 + 7.2*len0 + 2.8*(len1-len0);
} }
break; break;
case 0xdd: /* DIF */ case 0xdd: /* DIF */
@ -1368,20 +1283,16 @@ static t_stat DoInstr(void) {
* src and dst are not addresses on stack (^p) but addresses OF stack */ * src and dst are not addresses on stack (^p) but addresses OF stack */
if (len0==0) { if (len0==0) {
reg_sp++; reg_sp++;
cyc = 6.0;
} else if (len1==0) { } else if (len1==0) {
reg_sp += (len0+1); reg_sp += (len0+1);
cyc = 12.0;
} else if (len1 > len0) { } else if (len1 > len0) {
src = reg_sp + 1; dst = reg_sp + len0 + 2; src = reg_sp + 1; dst = reg_sp + len0 + 2;
for (i=0; i<len0; i++) Put(dst+i, Get(dst+i) & ~Get(src+i)); for (i=0; i<len0; i++) Put(dst+i, Get(dst+i) & ~Get(src+i));
reg_sp += (len0+1); reg_sp += (len0+1);
cyc = 14.0 + 7.2*len0;
} else { } else {
dst = reg_sp + len0 + 2; src = reg_sp + 1; dst = reg_sp + len0 + 2; src = reg_sp + 1;
for (i=0; i<len1; i++) Put(dst+i,Get(dst+i) & ~Get(src+i)); for (i=0; i<len1; i++) Put(dst+i,Get(dst+i) & ~Get(src+i));
reg_sp += (len0+1); reg_sp += (len0+1);
cyc = 13.6 + 7.2*len1;
} }
break; break;
case 0xb6: /* EQUPWR */ case 0xb6: /* EQUPWR */
@ -1406,7 +1317,6 @@ static t_stat DoInstr(void) {
} }
} }
reg_sp += (len0+len1+1); Put(reg_sp,(i >= max1 ? 1 : 0)); reg_sp += (len0+len1+1); Put(reg_sp,(i >= max1 ? 1 : 0));
cyc = 16.0 + 7.6*min1 + 4.0*max1; /* inaccurate */
break; break;
case 0xb7: /* LEQPWR */ case 0xb7: /* LEQPWR */
len0 = Tos(); len1 = Pick(len0 + 1); i=0; len0 = Tos(); len1 = Pick(len0 + 1); i=0;
@ -1425,7 +1335,6 @@ static t_stat DoInstr(void) {
} }
} else i = max1; } else i = max1;
reg_sp += (len0+len1+1); Put(reg_sp,(i >= max1 ? 1 : 0)); reg_sp += (len0+len1+1); Put(reg_sp,(i >= max1 ? 1 : 0));
cyc = 16.0 + 8.4*min1 + 4.0*max1; /* inaccurate */
break; break;
case 0xb8: /* GEQPWR */ case 0xb8: /* GEQPWR */
len0 = Tos(); len1 = Pick(len0 + 1); i=0; len0 = Tos(); len1 = Pick(len0 + 1); i=0;
@ -1444,88 +1353,64 @@ static t_stat DoInstr(void) {
} }
} else i = max1; } else i = max1;
reg_sp += (len0+len1+1); Put(reg_sp,(i >= max1 ? 1 : 0)); reg_sp += (len0+len1+1); Put(reg_sp,(i >= max1 ? 1 : 0));
cyc = 21.6 + 8.4*min1 + 4.0*max1; /* inaccurate */
break; break;
case 0xb9: /* EQUBYT */ case 0xb9: /* EQUBYT */
b = B(); src = Pop(); dst = Pop(); i = 0; b = B(); src = Pop(); dst = Pop(); i = 0;
while (i < b && Getb(src,i) == Getb(dst,i)) i++; while (i < b && Getb(src,i) == Getb(dst,i)) i++;
t1 = i >= b ? 1 : 0; t1 = i >= b ? 1 : 0;
Push(t1); Push(t1);
cyc = t1 ? (19.2 + 5.1*b) : (11.4 + 5.1*i); /* inaccurate */
break; break;
case 0xba: /* LEQBYT */ case 0xba: /* LEQBYT */
b = B(); src = Pop(); dst = Pop(); i = 0; b = B(); src = Pop(); dst = Pop(); i = 0;
while (i < b && Getb(src,i) <= Getb(dst,i)) i++; while (i < b && Getb(src,i) <= Getb(dst,i)) i++;
Push(i >= b ? 1 : 0); Push(i >= b ? 1 : 0);
cyc = 18.4 + 10.4*b; /* inaccurate */
break; break;
case 0xbb: /* GEQBYT */ case 0xbb: /* GEQBYT */
b = B(); src = Pop(); dst = Pop(); i = 0; b = B(); src = Pop(); dst = Pop(); i = 0;
while (i < b && Getb(src,i) >= Getb(dst,i)) i++; while (i < b && Getb(src,i) >= Getb(dst,i)) i++;
Push(i >= b ? 1 : 0); Push(i >= b ? 1 : 0);
cyc = 18.4 + 10.4*b; /* inaccurate */
break; break;
case 0x8a: /* UJP */ case 0x8a: /* UJP */
b = SB(); reg_ipc += b; b = SB(); reg_ipc += b;
cyc = 12.4;
break; break;
case 0xd4: /* FJP */ case 0xd4: /* FJP */
b = SB(); t1 = Pop(); b = SB(); t1 = Pop();
cyc = 10.8; if ((t1 & 1)==0)
if ((t1 & 1)==0) {
reg_ipc += b; reg_ipc += b;
cyc += 6.0;
}
break; break;
case 0xd2: /* EFJ */ case 0xd2: /* EFJ */
b = SB(); t1 = Pop(); t2 = Pop(); b = SB(); t1 = Pop(); t2 = Pop();
cyc = 11.8; if (t2 != t1)
if (t2 != t1) {
reg_ipc += b; reg_ipc += b;
cyc += 7.4;
}
break; break;
case 0xd3: /* NFJ */ case 0xd3: /* NFJ */
b = SB(); t1 = Pop(); t2 = Pop(); b = SB(); t1 = Pop(); t2 = Pop();
cyc = 12.0; if (t2 == t1)
if (t2 == t1) {
reg_ipc += b; reg_ipc += b;
cyc += 7.2;
}
break; break;
case 0x8b: /* UJPL */ case 0x8b: /* UJPL */
w = W(); reg_ipc += w; w = W(); reg_ipc += w;
cyc = 12.8;
break; break;
case 0xd5: /* FJPL */ case 0xd5: /* FJPL */
w = W(); t1 = Pop(); w = W(); t1 = Pop();
cyc = 10.0; if ((t1 & 1)== 0)
if ((t1 & 1)== 0) {
reg_ipc += w; reg_ipc += w;
cyc += 8.8;
}
break; break;
case 0xd6: /* XJP */ case 0xd6: /* XJP */
b = B(); t1 = Pop(); b = B(); t1 = Pop();
t2 = Get(reg_segb + b); t2 = Get(reg_segb + b);
if (t2 <= t1 && Get(reg_segb + b + 1) >= t1) { if (t2 <= t1 && Get(reg_segb + b + 1) >= t1)
reg_ipc += Get(reg_segb + b + 2 + (t1-t2)); reg_ipc += Get(reg_segb + b + 2 + (t1-t2));
cyc = 32.0;
} else {
cyc = t1 < t2 ? 29.2 : 34.0;
}
break; break;
case 0x90: /* CPL */ case 0x90: /* CPL */
procno = UB(); procno = UB();
ptbl = GetPtbl(); ptbl = GetPtbl();
reg_ipc = createMSCW(ptbl, procno, reg_mp, 0, reg_segb); reg_ipc = createMSCW(ptbl, procno, reg_mp, 0, reg_segb);
cyc = 45.6;
break; break;
case 0x91: /* CPG */ case 0x91: /* CPG */
procno = UB(); procno = UB();
ptbl = GetPtbl(); ptbl = GetPtbl();
reg_ipc = createMSCW(ptbl, procno, reg_bp, 0, reg_segb); reg_ipc = createMSCW(ptbl, procno, reg_bp, 0, reg_segb);
cyc = 44.8;
break; break;
case 0x92: /* CPI */ case 0x92: /* CPI */
db = DB(); procno = UB(); db = DB(); procno = UB();
@ -1537,7 +1422,6 @@ static t_stat DoInstr(void) {
for (i=1; i<= db; i++) for (i=1; i<= db; i++)
reg_lm = Get(reg_lm+OFF_MSSTAT); reg_lm = Get(reg_lm+OFF_MSSTAT);
Put(reg_mp+OFF_MSSTAT,reg_lm); /* fix stat link */ Put(reg_mp+OFF_MSSTAT,reg_lm); /* fix stat link */
cyc = 53.6 + 3.2*db;
break; break;
case 0x93: /* CXL */ case 0x93: /* CXL */
segno = UB(); procno = UB(); segno = UB(); procno = UB();
@ -1546,7 +1430,6 @@ static t_stat DoInstr(void) {
ptbl = SetSEGB(segno); ptbl = SetSEGB(segno);
AdjustRefCount(segno, 1); AdjustRefCount(segno, 1);
reg_ipc = createMSCW(ptbl, procno, reg_mp, osegno, osegb); reg_ipc = createMSCW(ptbl, procno, reg_mp, osegno, osegb);
cyc = 64.4;
break; break;
case 0x94: /* CXG */ case 0x94: /* CXG */
ub1 = UB(); ub2 = UB(); ub1 = UB(); ub2 = UB();
@ -1562,7 +1445,6 @@ static t_stat DoInstr(void) {
reg_lm = reg_mp; reg_lm = reg_mp;
for (i=1; i<= db; i++) reg_lm = Get(reg_lm+OFF_MSSTAT); for (i=1; i<= db; i++) reg_lm = Get(reg_lm+OFF_MSSTAT);
Put(reg_mp+OFF_MSSTAT,reg_lm); /* fix stat link */ Put(reg_mp+OFF_MSSTAT,reg_lm); /* fix stat link */
cyc = 73.2 + 3.2*db;
break; break;
case 0x97: /* CPF */ case 0x97: /* CPF */
t1 = Pop(); reg_lm = Pop(); t1 = Pop(); reg_lm = Pop();
@ -1573,7 +1455,6 @@ static t_stat DoInstr(void) {
ptbl = SetSEGB(segno); ptbl = SetSEGB(segno);
AdjustRefCount(segno, 1); AdjustRefCount(segno, 1);
reg_ipc = createMSCW(ptbl, procno, reg_lm, osegno, osegb); reg_ipc = createMSCW(ptbl, procno, reg_lm, osegno, osegb);
cyc = 75.6;
break; break;
case 0x96: /* RPU */ case 0x96: /* RPU */
dbg_procleave(); dbg_procleave();
@ -1587,13 +1468,11 @@ static t_stat DoInstr(void) {
(void)SetSEGB(segno); (void)SetSEGB(segno);
} }
reg_sp += (b + MSCW_SZ); reg_sp += (b + MSCW_SZ);
cyc = 26.0;
break; break;
case 0x99: /* LSL */ case 0x99: /* LSL */
db = DB(); reg_lm = reg_mp; db = DB(); reg_lm = reg_mp;
for (i=1; i<= db; i++) reg_lm = Get(reg_lm+OFF_MSSTAT); for (i=1; i<= db; i++) reg_lm = Get(reg_lm+OFF_MSSTAT);
Push(reg_lm); Push(reg_lm);
cyc = 12.4 + 3.2*db;
break; break;
case 0xde: /* SIGNAL */ case 0xde: /* SIGNAL */
t1 = Pick(0); t1 = Pick(0);
@ -1604,12 +1483,8 @@ static t_stat DoInstr(void) {
DoWAIT(t1); break; DoWAIT(t1); break;
case 0x9d: /* LPR */ case 0x9d: /* LPR */
w = Tos(); w = Tos();
cyc = 0.0; if (w >= 0)
if (w >= 0) {
save_to_tib(); save_to_tib();
cyc = 55.2;
} else
cyc = 8.4;
if (w == -3) Put(reg_sp, reg_rq); if (w == -3) Put(reg_sp, reg_rq);
else if (w == -2) Put(reg_sp, reg_ssv); else if (w == -2) Put(reg_sp, reg_ssv);
else if (w == -1) Put(reg_sp, reg_ctp); else if (w == -1) Put(reg_sp, reg_ctp);
@ -1620,7 +1495,6 @@ static t_stat DoInstr(void) {
w = (int16)Pick(1); w = (int16)Pick(1);
if (w >= -1) if (w >= -1)
save_to_tib(); save_to_tib();
cyc = 8.4;
if (w == -3) { if (w == -3) {
reg_rq = t1; reg_rq = t1;
} else if (w == -2) { } else if (w == -2) {
@ -1630,10 +1504,8 @@ static t_stat DoInstr(void) {
reg_rq = t1; reg_rq = t1;
taskswitch5(); taskswitch5();
// sim_printf("SPR Taskswitch done reg_ctp=%x reg_rq=%x\n",reg_ctp,reg_rq); // sim_printf("SPR Taskswitch done reg_ctp=%x reg_rq=%x\n",reg_ctp,reg_rq);
cyc = 53.2;
break; /* mustn't fall through reg_sp +=2 */ break; /* mustn't fall through reg_sp +=2 */
} else if (w >= 1) { } else if (w >= 1) {
cyc = 54.8;
switch (w) { switch (w) {
case OFF_SP: reg_sp = t1; break; case OFF_SP: reg_sp = t1; break;
case OFF_MP: reg_mp = t1; break; case OFF_MP: reg_mp = t1; break;
@ -1649,17 +1521,14 @@ static t_stat DoInstr(void) {
break; break;
case 0x9e: /* BPT */ case 0x9e: /* BPT */
Raise(PASERROR_USERBRK); Raise(PASERROR_USERBRK);
cyc = 0; /* added in Raise() -> DoCXG() */
return STOP_BPT; return STOP_BPT;
// break; // break;
case 0x9c: /* NOP */ case 0x9c: /* NOP */
cyc = 3.6;
break; break;
case 0xbd: /* SWAP */ case 0xbd: /* SWAP */
t1 = Tos(); t1 = Tos();
Put(reg_sp, Pick(1)); Put(reg_sp, Pick(1));
Put(reg_sp+1, t1); Put(reg_sp+1, t1);
cyc = 12.4;
break; break;
default: default:
// Raise(PASERROR_UNIMPL); // Raise(PASERROR_UNIMPL);
@ -1673,7 +1542,7 @@ static t_stat DoInstr(void) {
if (dbg_check(opcode, DEBUG_POST)) return STOP_DBGPOST; if (dbg_check(opcode, DEBUG_POST)) return STOP_DBGPOST;
/* count cycles */ /* count cycles */
sim_interval -= (int)(cyc+0.5); sim_interval--;
return SCPE_OK; return SCPE_OK;
} }
@ -1710,12 +1579,7 @@ t_stat sim_instr(void)
if ((rc = DoInstr()) != SCPE_OK) break; if ((rc = DoInstr()) != SCPE_OK) break;
} }
else { else {
#if 0
/* waste time by doing a NOP */
sim_interval -= 4; /* actually 3.6 */
#else
sim_idle(TMR_IDLE, TRUE); sim_idle(TMR_IDLE, TRUE);
#endif
} }
/* process interrupts /* process interrupts

View file

@ -204,9 +204,8 @@
#define CON_TERMUNIT 1 #define CON_TERMUNIT 1
#define CON_POLLFIRST 1 /* immediate */ #define CON_POLLFIRST 1 /* immediate */
#define CON_POLLRATE 100 #define CON_POLLRATE 100
#define CON_POLLWAIT 12500 #define CON_TPS 100
//#define CON_TERMRATE 1300 #define CON_TERMRATE 100
#define CON_TERMRATE 300
/* floppy size */ /* floppy size */
#define FDC_MAX_TRACKS 77 #define FDC_MAX_TRACKS 77
@ -324,18 +323,6 @@ typedef union flcvt {
uint16 i[2]; uint16 i[2];
} T_FLCVT; } T_FLCVT;
/* wrapper structure for terminal multiplexer,
pointer to pointer stored in device->ctxt */
typedef struct {
int pfirst, prate; /* pollrate first time, later */
TMLN ldsc;
TMXR desc;
UNIT* term;
UNIT* poll;
} SERMUX;
extern t_stat mux_attach(UNIT*, char*, SERMUX*);
extern t_stat mux_detach(UNIT*, SERMUX*);
/* externals */ /* externals */
extern DEVICE cpu_dev; extern DEVICE cpu_dev;
extern UNIT cpu_unit; extern UNIT cpu_unit;

View file

@ -39,8 +39,6 @@ extern UNIT con_unit[];
static t_stat con_termsvc(UNIT *uptr); static t_stat con_termsvc(UNIT *uptr);
static t_stat con_pollsvc(UNIT *uptr); static t_stat con_pollsvc(UNIT *uptr);
static t_stat con_attach(UNIT*, char*);
static t_stat con_detach(UNIT*);
static t_stat con_reset(DEVICE* dptr); static t_stat con_reset(DEVICE* dptr);
static t_stat tim_reset(DEVICE *dptr); static t_stat tim_reset(DEVICE *dptr);
@ -86,27 +84,6 @@ static uint8 con_status;
static uint8 con_xmit; static uint8 con_xmit;
static uint8 con_rcv; static uint8 con_rcv;
/************************************************************************************************
* Utilities
***********************************************************************************************/
t_stat mux_attach(UNIT* uptr, char* cptr, SERMUX* mux) {
t_stat rc;
mux->desc.ldsc = &mux->ldsc;
if ((rc = tmxr_attach(&mux->desc, uptr, cptr)) == SCPE_OK) {
mux->poll->wait = mux->pfirst;
sim_activate(mux->poll, mux->poll->wait);
}
return rc;
}
t_stat mux_detach(UNIT* uptr, SERMUX* mux) {
t_stat rc = tmxr_detach(&mux->desc, uptr);
mux->ldsc.rcve = 0;
sim_cancel(mux->poll);
sim_cancel(mux->term);
return rc;
}
/************************************************************************************************ /************************************************************************************************
* Onboard Console * Onboard Console
***********************************************************************************************/ ***********************************************************************************************/
@ -125,6 +102,8 @@ UNIT con_unit[] = {
{ UDATA (&con_pollsvc, UNIT_ATTABLE, 0), CON_POLLRATE, }, { UDATA (&con_pollsvc, UNIT_ATTABLE, 0), CON_POLLRATE, },
{ UDATA (&con_termsvc, UNIT_IDLE, 0), CON_TERMRATE, } { UDATA (&con_termsvc, UNIT_IDLE, 0), CON_TERMRATE, }
}; };
static UNIT* con_tti = &con_unit[0]; /* shorthand for console input and output units */
static UNIT* con_tto = &con_unit[1];
REG con_reg[] = { REG con_reg[] = {
{ HRDATA (CTRL1, con_ctrl1, 8) }, { HRDATA (CTRL1, con_ctrl1, 8) },
@ -147,16 +126,6 @@ DEBTAB con_dflags[] = {
{ 0, 0 } { 0, 0 }
}; };
SERMUX con_mux[1] = {
{ CON_POLLFIRST, /*pfirst*/
CON_POLLRATE, /*prate*/
{ 0 }, /*ldsc*/
{ 1,0,0,0 }, /*desc*/
&con_unit[1], /*term*/
&con_unit[0] /*poll*/
}
};
DEVICE con_dev = { DEVICE con_dev = {
"CON", /*name*/ "CON", /*name*/
con_unit, /*units*/ con_unit, /*units*/
@ -172,8 +141,8 @@ DEVICE con_dev = {
NULL, /*deposit*/ NULL, /*deposit*/
&con_reset, /*reset*/ &con_reset, /*reset*/
NULL, /*boot*/ NULL, /*boot*/
con_attach, /*attach*/ NULL, /*attach*/
con_detach, /*detach*/ NULL, /*detach*/
&con_ctxt, /*ctxt*/ &con_ctxt, /*ctxt*/
DEV_DEBUG|DEV_DISABLE, /*flags*/ DEV_DEBUG|DEV_DISABLE, /*flags*/
0, /*dctrl*/ 0, /*dctrl*/
@ -184,10 +153,8 @@ DEVICE con_dev = {
/* bus reset handler */ /* bus reset handler */
t_stat con_binit() { t_stat con_binit() {
SERMUX *mux = &con_mux[0];
con_status = CONS_THRE; con_status = CONS_THRE;
if (mux->ldsc.conn) setbit(con_status, CONS_DSR); setbit(con_status, CONS_DSR);
con_ctrl1 = 0; /* no echo, receiver disabled, transmitter disabled */ con_ctrl1 = 0; /* no echo, receiver disabled, transmitter disabled */
con_ctrl2 = 0; /* ASYNC mode, 8bits, Clock 1X */ con_ctrl2 = 0; /* ASYNC mode, 8bits, Clock 1X */
@ -199,37 +166,33 @@ t_stat con_binit() {
/* common handlers */ /* common handlers */
static t_stat con_reset(DEVICE* dptr) static t_stat con_reset(DEVICE* dptr)
{ {
int32 wait;
SERMUX * mux = &con_mux[0];
UNIT *term = mux->term;
UNIT *poll = mux->poll;
DEVCTXT* ctxt = (DEVCTXT*)dptr->ctxt; DEVCTXT* ctxt = (DEVCTXT*)dptr->ctxt;
int32 wait = con_tti->wait = CON_POLLRATE;
wait = poll->wait = CON_POLLWAIT;
sim_rtcn_init (wait, TMR_CONPOLL); /* init poll timer */ sim_rtcn_init (wait, TMR_CONPOLL); /* init poll timer */
sim_cancel(term); sim_cancel(con_tto); /* disable output service */
/* register/deregister I/O handlers */ /* register/deregister I/O handlers */
if (dptr->flags & DEV_DIS) { if (dptr->flags & DEV_DIS) {
del_ioh(ctxt->ioi); del_ioh(ctxt->ioi);
} else { } else {
add_ioh(ctxt->ioi); add_ioh(ctxt->ioi);
poll->buf = 0; con_tti->buf = 0;
sim_activate (poll, wait); sim_activate (con_tti, wait);
} }
return con_binit(); return con_binit();
} }
t_stat con_attach(UNIT* uptr, char* cptr) { t_stat con_attach(UNIT* uptr, char* cptr) {
setbit(con_status, CONS_DSR|CONS_DSC); setbit(con_status, CONS_DSR|CONS_DSC);
return mux_attach(uptr, cptr, &con_mux[0]); return SCPE_OK;
} }
t_stat con_detach(UNIT* uptr) { t_stat con_detach(UNIT* uptr) {
clrbit(con_status, CONS_DSR); clrbit(con_status, CONS_DSR);
setbit(con_status, CONS_DSC); setbit(con_status, CONS_DSC);
return mux_detach(uptr, &con_mux[0]); return SCPE_OK;
} }
#define XMITENABLED() (isbitset(con_ctrl1,CONC1_RTS)) #define XMITENABLED() (isbitset(con_ctrl1,CONC1_RTS))
@ -262,79 +225,46 @@ t_stat con_detach(UNIT* uptr) {
/* Terminal output service */ /* Terminal output service */
t_stat con_termsvc (UNIT *uptr) { t_stat con_termsvc (UNIT *uptr) {
SERMUX *mux = &con_mux[0]; t_stat rc = SCPE_OK;
t_bool isnetwork = (mux->poll->flags & UNIT_ATT);
t_stat rc;
int ch = uptr->buf & 0xff;
// sim_debug(DBG_CON_SVC, &con_dev, "termsvc: isnetwork=%d\n",isnetwork);
/* TODO? sim_tt_outcvt */
int ch = sim_tt_outcvt(uptr->buf, TT_GET_MODE(uptr->flags));
if (XMITENABLED()) { /* tranmitter enabled */ if (XMITENABLED()) { /* tranmitter enabled */
/* attached to a telnet port? */ if (ch >= 0) {
// printf("*** Emit: %02x ***\n",uptr->buf & 0xff);
if (isnetwork) {
if ((rc=tmxr_putc_ln(&mux->ldsc, ch)) != SCPE_OK) {
sim_activate(uptr, uptr->wait);
return SCPE_OK;
} else
tmxr_poll_tx(&mux->desc);
} else {
if ((rc = sim_putchar_s(ch)) != SCPE_OK) { if ((rc = sim_putchar_s(ch)) != SCPE_OK) {
sim_activate(uptr, uptr->wait); sim_activate(uptr, uptr->wait); /* did not emit char, reschedule termsvc */
return rc == SCPE_STALL ? SCPE_OK : rc; return rc == SCPE_STALL ? SCPE_OK : rc;
} }
} }
}
uptr->pos = uptr->pos + 1;
setbit(con_status, CONS_THRE); /* set transmitter holding reg empty */ setbit(con_status, CONS_THRE); /* set transmitter holding reg empty */
cpu_assertInt(INT_CONT, TRUE); /* generate an interrupt because of DRQO */ cpu_assertInt(INT_CONT, TRUE); /* generate an interrupt because of DRQO */
}
return SCPE_OK; return SCPE_OK;
} }
/* Terminal input service */ /* Terminal input service */
t_stat con_pollsvc(UNIT *uptr) { t_stat con_pollsvc(UNIT *uptr) {
int32 c, kbdc; int32 ch;
SERMUX *mux = &con_mux[0];
t_bool isnetwork = (mux->poll->flags & UNIT_ATT);
uptr->wait = sim_rtcn_calb(mux->prate, TMR_CONPOLL); /* calibrate timer */ uptr->wait = sim_rtcn_calb(CON_TPS, TMR_CONPOLL); /* calibrate timer */
sim_activate(uptr, uptr->wait); /* restart polling */ sim_activate(uptr, uptr->wait); /* restart polling */
kbdc = sim_poll_kbd(); /* check keyboard */ if ((ch = sim_poll_kbd()) < SCPE_KFLAG) /* check keyboard */
if (kbdc == SCPE_STOP) return kbdc; /* handle CTRL-E */ return ch;
uptr->buf = (ch & SCPE_BREAK) ? 0 : sim_tt_inpcvt(ch, TT_GET_MODE(uptr->flags));
/* network-redirected input? */
if (isnetwork) {
if (tmxr_poll_conn(&mux->desc) >= 0) /* incoming connection */
mux->ldsc.rcve = 1;
tmxr_poll_rx(&mux->desc); /* poll for input */
if (!tmxr_rqln(&mux->ldsc)) return SCPE_OK;
/* input ready */
c = tmxr_getc_ln(&mux->ldsc);
if ((c & TMXR_VALID) == 0) return SCPE_OK;
} else {
c = kbdc; /* use char polled from keyboard */
if (c < SCPE_KFLAG) return c; /* ignore data if not valid */
}
c = sim_tt_inpcvt(c, TT_GET_MODE(uptr->flags));
uptr->buf = c & 0xff;
uptr->pos = uptr->pos + 1; uptr->pos = uptr->pos + 1;
if (RCVENABLED()) { /* receiver enabled? */ if (RCVENABLED()) { /* receiver enabled? */
if (RCVFULL()) /* handle data overrun */ if (RCVFULL()) /* handle data overrun */
setbit(con_status, CONS_OE); setbit(con_status, CONS_OE);
con_rcv = c & 0xff; /* put in receiver register */ con_rcv = ch & 0xff; /* put in receiver register */
setbit(con_status, CONS_DR); /* notify: data received */ setbit(con_status, CONS_DR); /* notify: data received */
cpu_assertInt(INT_CONR, TRUE); /* generate interrupt because of DRQI */ cpu_assertInt(INT_CONR, TRUE); /* generate interrupt because of DRQI */
if (isbitset(con_ctrl1, CONC1_ECHO)) { /* echo? XXX handle in telnet handler? */ if (isbitset(con_ctrl1, CONC1_ECHO)) { /* echo? XXX handle in telnet handler? */
/* XXX use direct send here, not sending via con_termsvc */ /* XXX use direct send here, not sending via con_termsvc */
if (isnetwork) sim_putchar_s(ch);
tmxr_putc_ln(&mux->ldsc, c);
else
sim_putchar_s(c);
} }
} }
return SCPE_OK; return SCPE_OK;
@ -368,9 +298,6 @@ static int get_parity(int c, int even)
// The logic in here uses the positive logic conventions as // The logic in here uses the positive logic conventions as
// described in the WD1931 data sheet, not the ones in the PDQ-3_Hardware_Users_Manual // described in the WD1931 data sheet, not the ones in the PDQ-3_Hardware_Users_Manual
t_stat con_write(t_addr ioaddr, uint16 data) { t_stat con_write(t_addr ioaddr, uint16 data) {
SERMUX * mux = &con_mux[0];
UNIT *term = mux->term;
UNIT *poll = mux->poll;
/* note usart has inverted bus, so all data is inverted */ /* note usart has inverted bus, so all data is inverted */
data = (~data) & 0xff; data = (~data) & 0xff;
@ -379,9 +306,9 @@ t_stat con_write(t_addr ioaddr, uint16 data) {
con_ctrl1 = data & 0xff; con_ctrl1 = data & 0xff;
if (!RCVENABLED()) { /* disable receiver */ if (!RCVENABLED()) { /* disable receiver */
clrbit(con_status,CONS_FE|CONS_PE|CONS_OE|CONS_DR); clrbit(con_status,CONS_FE|CONS_PE|CONS_OE|CONS_DR);
sim_cancel(poll); sim_cancel(con_tti);
} else { } else {
sim_activate(poll, poll->wait); /* start poll service, will raise interrupt if buffer full */ sim_activate(con_tti, con_tti->wait); /* start poll service, will raise interrupt if buffer full */
} }
if (!XMITENABLED()) { /* disable transmitter */ if (!XMITENABLED()) { /* disable transmitter */
/* will drain current pending xmit service. RTS output is assumed to become inactive /* will drain current pending xmit service. RTS output is assumed to become inactive
@ -390,7 +317,7 @@ t_stat con_write(t_addr ioaddr, uint16 data) {
if (XMITEMPTY()) { if (XMITEMPTY()) {
} else { } else {
/* some char in THR, start service to emit */ /* some char in THR, start service to emit */
sim_activate(term, term->wait); sim_activate(con_tto, con_tto->wait);
} }
} }
break; break;
@ -411,10 +338,10 @@ t_stat con_write(t_addr ioaddr, uint16 data) {
case CONC2_CLEN8: data &= 0xff; break; case CONC2_CLEN8: data &= 0xff; break;
} }
con_xmit = data & 0xff; con_xmit = data & 0xff;
term->buf = data; con_tto->buf = data;
clrbit(con_status,CONS_THRE); clrbit(con_status,CONS_THRE);
if (XMITENABLED()) if (XMITENABLED())
sim_activate(term,term->wait); sim_activate(con_tto, con_tto->wait);
} }
// RCVINTR(); // RCVINTR();
XMITINTR(); XMITINTR();
@ -425,8 +352,6 @@ t_stat con_write(t_addr ioaddr, uint16 data) {
} }
t_stat con_read(t_addr ioaddr, uint16 *data) { t_stat con_read(t_addr ioaddr, uint16 *data) {
SERMUX *mux = &con_mux[0];
switch (ioaddr & 0x0003) { switch (ioaddr & 0x0003) {
case 0: /* CTRL1 */ case 0: /* CTRL1 */
*data = con_ctrl1; *data = con_ctrl1;
@ -435,8 +360,9 @@ t_stat con_read(t_addr ioaddr, uint16 *data) {
*data = con_ctrl2; *data = con_ctrl2;
break; break;
case 2: case 2:
if (mux->ldsc.conn) setbit(con_status, CONS_DSR); /* XXX find out whether terminal is attached to console? */
else clrbit(con_status, CONS_DSR); setbit(con_status, CONS_DSR);
// else clrbit(con_status, CONS_DSR);
*data = con_status; *data = con_status;
clrbit(con_status,CONS_DSC); /* acknowledge change in DSR/DCD */ clrbit(con_status,CONS_DSC); /* acknowledge change in DSR/DCD */
break; break;
@ -569,19 +495,19 @@ t_stat tim_write(t_addr ioaddr, uint16 data)
sim_debug(DBG_TIM_WRITE, &tim_dev, DBG_PCFORMAT0 "Timer%d: mode=%d\n", sim_debug(DBG_TIM_WRITE, &tim_dev, DBG_PCFORMAT0 "Timer%d: mode=%d\n",
DBG_PC, n, (data >> 1) & 7); DBG_PC, n, (data >> 1) & 7);
if (n == 3) { if (n == 3) {
printf("Unimplemented: Mode=0xc0\n"); sim_printf("Unimplemented: Mode=0xc0\n");
return STOP_IMPL; return STOP_IMPL;
} }
if (data & 0x01) { if (data & 0x01) {
printf("Unimplemented: BCD mode: timer=%d\n",n); sim_printf("Unimplemented: BCD mode: timer=%d\n",n);
return STOP_IMPL; return STOP_IMPL;
} }
if (!( (data & 0x0e)==0x00 || (data & 0x0e)==0x04)) { if (!( (data & 0x0e)==0x00 || (data & 0x0e)==0x04)) {
printf("Unimplemented: Mode not 0 or 2: timer=%d\n",n); sim_printf("Unimplemented: Mode not 0 or 2: timer=%d\n",n);
return STOP_IMPL; return STOP_IMPL;
} }
if ((data & 0x30) != 0x30) { if ((data & 0x30) != 0x30) {
printf("Unimplemented: not 16 bit load: timer=%d\n",n); sim_printf("Unimplemented: not 16 bit load: timer=%d\n",n);
return STOP_IMPL; return STOP_IMPL;
} }
tim[n].mode = data; tim[n].mode = data;

View file

@ -191,12 +191,12 @@ static t_stat pdq3_cmd_exstack(int32 arg, char *buf)
int i; int i;
int n = buf[0] ? atol(buf) : 0; int n = buf[0] ? atol(buf) : 0;
if (n < 0) n = 0; if (n < 0) n = 0;
printf("SP: $%04x LOW: $%04x UPR: $%04x\n", sim_printf("SP: $%04x LOW: $%04x UPR: $%04x\n",
reg_sp, reg_splow, reg_spupr); reg_sp, reg_splow, reg_spupr);
for (i=n; i>=0; i--) { for (i=n; i>=0; i--) {
if ((rc=Read(reg_sp+i, 0, &data, 0)) != SCPE_OK) continue; if ((rc=Read(reg_sp+i, 0, &data, 0)) != SCPE_OK) continue;
if (i==0) printf(" TOS: "); else printf(" %3d: ",i); if (i==0) sim_printf(" TOS: "); else sim_printf(" %3d: ",i);
printf("%04x ($%04x)\n", data, reg_sp+i); sim_printf("%04x ($%04x)\n", data, reg_sp+i);
} }
return SCPE_OK; return SCPE_OK;
} }

View file

@ -1,2 +1,11 @@
@echo off @echo off
pdq3.exe testhdt.sim if not exist "..\BIN\NT\Win32-Debug\pdq3.exe" goto try_mingw
..\BIN\NT\Win32-Debug\pdq3.exe testhdt.sim
goto done
:try_mingw
.\PDQ3.exe testhdt.sim
goto done
:done

View file

@ -1,5 +1,9 @@
;**** some possible debugging options
;set debug debug.log ;set debug debug.log
set debug stdout ;set debug stdout
;**** debugging of FDC
;**** read/write operations, attach&detach, FDC service, IMD handling, DMA/verbose, FDC cmds
;set fdc debug=read ;set fdc debug=read
;set fdc debug=write ;set fdc debug=write
;set fdc debug=verbose ;set fdc debug=verbose
@ -8,6 +12,9 @@ set debug stdout
;set fdc debug=dma ;set fdc debug=dma
;set fdc debug=dmavb ;set fdc debug=dmavb
;set fdc debug=cmd ;set fdc debug=cmd
;**** debugging of CPU: exceptions, tracing, memory read/write
;**** opcode fetch, stack push/pull, concurrency
;set cpu exc ;set cpu exc
;set cpu debug=int ;set cpu debug=int
;set cpu debug=trace ;set cpu debug=trace
@ -16,19 +23,37 @@ set debug stdout
;set cpu debug=fetch ;set cpu debug=fetch
;set cpu debug=stack ;set cpu debug=stack
;set cpu debug=conc ;set cpu debug=conc
;set con debug=svc
;**** debugging of console: read/write to registers
;set con debug=read ;set con debug=read
;set con debug=write ;set con debug=write
;**** debugging of timer: read/write, service
;set tim debug=read ;set tim debug=read
;set tim debug=write ;set tim debug=write
;set tim debug=svc ;set tim debug=svc
att con 8000 ;**** you should attach a telnet terminal emulator to PDQ-3 console
;**** to avoid mess with SIMH's control panel
set console telnet=8000
;**** you might remote control SIMH's control panel
;set remote telnet=7000,telnet=buffered
;**** you need a boot disk
att fdc0 master.imd att fdc0 master.imd
;**** make this write protected currently while emulator is still being debugged
set fdc0 wrtlck set fdc0 wrtlck
;**** disable the second FDC
set fdc1 disable set fdc1 disable
;************************************************************************
;**** The following is pure f***ing magic - you must have the source code
;**** and a commented object dump of boot loader, SYSTEM.PASCAL, SYSTEM.DRIVERS etc.
; otherwise you won't understand where I had checkpoints for debugging.
; HDT boot ; HDT boot
;break f418:368 ;break f418:368
;break f418:36a ;break f418:36a
@ -112,14 +137,22 @@ set fdc1 disable
;break d488:ed0 ;break d488:ed0
;****
;**** end of PFM section
;************************************************************************
;**** load the boot PROM code for HD support
load hdt/CPU_C5.BIN load hdt/CPU_C5.BIN
;
;**** set the INIT bit of SSR
dep _ssr 80 dep _ssr 80
dep _ses 80 dep _ses 80
;**** load some symbolic names for debuging (not needed in production)
do names.sim do names.sim
boot cpu
set debug stdout
;**** run
boot cpu
;**** reset debug mode to normal when boot fails.
set debug stdout