From 22e33dd3d4aef3b558d82d95801c296caddb314a Mon Sep 17 00:00:00 2001 From: Anders Magnusson Date: Sun, 14 May 2023 21:46:21 +0200 Subject: [PATCH] ND100: MMS-1 support (Memory Management 1) + other fixes for Nord-100. Can now boot the last test programs from floppy, and runs INSTRUCTION-C and PAGING-C without errors. --- ND100/nd100_cpu.c | 371 +++++++++++++++++++++++++------------------ ND100/nd100_defs.h | 65 ++++++-- ND100/nd100_floppy.c | 224 ++++++++++++++++++++------ ND100/nd100_mm.c | 284 +++++++++++++++++++++++++++++---- ND100/nd100_stddev.c | 15 +- ND100/nd100_sys.c | 17 +- 6 files changed, 718 insertions(+), 258 deletions(-) diff --git a/ND100/nd100_cpu.c b/ND100/nd100_cpu.c index 9e9030e4..a13537a3 100644 --- a/ND100/nd100_cpu.c +++ b/ND100/nd100_cpu.c @@ -30,12 +30,6 @@ #include "nd100_defs.h" #define MAXMEMSIZE 512*1024 -#undef TIMERHACK - -#ifdef TIMERHACK -int rtc_int_enabled, rtc_dev_ready, rtccnt; -void chkrtc(void); -#endif typedef struct { int ir; @@ -59,11 +53,11 @@ static Hist_entry *hist = NULL; static struct intr *ilnk[4]; /* level 10-13 */ jmp_buf env; -uint16 R[8], RBLK[16][8], regSTH; +uint16 R[8], RBLK[16][8], regSTH, oregP; int curlvl; /* current interrupt level */ int iic, iie, iid; /* IIC/IIE/IID register */ int pid, pie; /* PID/PIE register */ -int ald, eccr, pvl, lmp; +int ald, eccr, pvl, lmp, opr; #define SETC() (regSTL |= STS_C) #define CLRC() (regSTL &= ~STS_C) @@ -88,12 +82,10 @@ static int nd_tra(int reg); static int nd_mcl(int reg); static int nd_mst(int reg); static int highest_level(void); -static void intrpt14(int); static void identrm(int); static uint16 add3(uint16 a, uint16 d, uint16 c); int fls(int); - int ins_store(int ir, int addr); int ins_stdf(int ir, int addr); int ins_lddf(int ir, int addr); @@ -144,6 +136,7 @@ REG cpu_reg[] = { { ORDATA(A, regA, 16) }, { ORDATA(T, regT, 16) }, { ORDATA(X, regX, 16) }, + { ORDATA(oldP, oregP, 16) }, { DRDATA(LVL, curlvl, 4) }, { DRDATA(LMP, lmp, 16) }, { DRDATA(PVL, pvl, 4) }, @@ -151,6 +144,7 @@ REG cpu_reg[] = { { ORDATA(PIE, pie, 16) }, { ORDATA(IIC, iic, 4) }, { ORDATA(IIE, iie, 10) }, + { ORDATA(OPR, opr, 16) }, { NULL } }; @@ -176,16 +170,16 @@ sim_instr(void) int first = 1; uint16 off; - reason = setjmp(env); + (void)setjmp(env); + reason = 0; while (reason == 0) { if (sim_interval <= 0) if ((reason = sim_process_event ())) break; -#ifdef TIMERHACK - chkrtc(); -#endif + if (regSTL & STS_Z) + intrpt14(IIE_V, PM_DMA); /* no longjmp here */ if ((pid & pie) > (0177777 >> (15-curlvl)) && ISION()) { /* need to interrupt */ pvl = curlvl; @@ -199,10 +193,21 @@ while (reason == 0) { regT = SEXT8(IR); } - IR = rdmem(regP); + /* + * ND100 manual clause 2.3.8.3 says that the instruction faults happens + * after the P reg is incremented, hence will point to one instruction + * past the instruction causing the fault. + * But; if the fault is during fetch, P will not be incremented. + */ + IR = rdmem(regP, M_FETCH); + oregP = regP++; + sim_interval--; - if (first == 0 && sim_brk_summ && sim_brk_test (regP, SWMASK ('E'))) { + if (regSTH & STS_TG) + return STOP_BP; + + if (first == 0 && sim_brk_summ && sim_brk_test(oregP, SWMASK ('E'))) { reason = STOP_BP; break; } @@ -229,8 +234,6 @@ while (reason == 0) { off = getoff(IR); reason = (*ins_table[ID(IR)])(IR, off); - if (reason == 0) - regP++; } return reason; } @@ -248,7 +251,7 @@ cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { if (addr >= MAXMEMSIZE) return SCPE_ARG; - *vptr = rdmem(addr); + *vptr = rdmem(addr, M_PT); /* XXX */ return SCPE_OK; } @@ -279,7 +282,7 @@ int ins_store(int IR, int off) { int n = ((IR >> 11) & 03) + 4; - wrmem(off, n == 4 ? 0 : R[n]); + wrmem(off, n == 4 ? 0 : R[n], SELPT2(IR)); return SCPE_OK; } @@ -289,10 +292,12 @@ ins_store(int IR, int off) int ins_stdf(int IR, int off) { + int pt = SELPT2(IR); + if (ID(IR) == ID(ND_STF) /* && 48-bit */) - wrmem(off++, regT); - wrmem(off++, regA); - wrmem(off, regD); + wrmem(off++, regT, pt); + wrmem(off++, regA, pt); + wrmem(off, regD, pt); return SCPE_OK; } @@ -302,10 +307,11 @@ ins_stdf(int IR, int off) int ins_lddf(int IR, int off) { + int pt = SELPT2(IR); if (ID(IR) == ID(ND_LDF) /* && 48-bit */) - regT = rdmem(off++); - regA = rdmem(off++); - regD = rdmem(off); + regT = rdmem(off++, pt); + regA = rdmem(off++, pt); + regD = rdmem(off, pt); return SCPE_OK; } @@ -315,7 +321,7 @@ ins_lddf(int IR, int off) int ins_load(int IR, int off) { - R[((IR&014000) >> 11) + 4] = rdmem(off); + R[((IR&014000) >> 11) + 4] = rdmem(off, SELPT2(IR)); return SCPE_OK; } @@ -326,8 +332,9 @@ int ins_min(int IR, int off) { uint16 s; + int pt = SELPT2(IR); - wrmem(off, s = rdmem(off) + 1); + wrmem(off, s = rdmem(off, pt) + 1, pt); if (s == 0) regP++; return SCPE_OK; @@ -339,7 +346,7 @@ ins_min(int IR, int off) int ins_add(int IR, int off) { - uint16 d = rdmem(off); + uint16 d = rdmem(off, SELPT2(IR)); int n = 0; if (ID(IR) == ID(ND_SUB)) @@ -354,7 +361,7 @@ ins_add(int IR, int off) int ins_andor(int IR, int off) { - uint16 s = rdmem(off); + uint16 s = rdmem(off, SELPT2(IR)); regA = BIT11(IR) ? (regA | s) : (regA & s); return SCPE_OK; @@ -394,7 +401,7 @@ static void ins_bfill(int IR) { while (regT & 07777) { - wrbyte(regX, regA, BIT15(regT)); + wrbyte(regX, regA, BIT15(regT), M_APT); regT--; regT ^= 0100000; if (BIT15(regT) == 0) @@ -442,8 +449,8 @@ ins_movb(int IR) if (regX > regA) { /* copy bottom-top */ for (i = BYTELN(regD); i < BYTELN(regT); i++, regD++) { - int8 w = rdbyte(regA, BIT15(regD)); - wrbyte(regX, w, BIT15(regT)); + int8 w = rdbyte(regA, BIT15(regD), M_APT); + wrbyte(regX, w, BIT15(regT), M_APT); regD ^= 0100000; if (BIT15(regD) == 0) regA++; regT ^= 0100000; @@ -494,8 +501,8 @@ ins_movbf(int IR) } for (i = BYTELN(regD); i < BYTELN(regT); i++, regD++) { - int8 w = rdbyte(regA, BIT15(regD)); - wrbyte(regX, w, BIT15(regT)); + int8 w = rdbyte(regA, BIT15(regD), M_APT); + wrbyte(regX, w, BIT15(regT), M_APT); regD ^= 0100000; if (BIT15(regD) == 0) regA++; regT ^= 0100000; @@ -515,11 +522,41 @@ ins_skip_ext(int IR) uint16 d; int16 ss, sd; int32 shc; - int reason = 0; + int paddr, reason = 0; if ((IR & 0177707) == ND_SKP_CLEPT) { - intrpt14(IIE_II); - regP--; + intrpt14(IIE_II, PM_CPU); + } else if ((IR & 0177700) == ND_SKP_LDATX) { + /* Special physmem instructions */ + d = regX + ((IR & 070) >> 3); + paddr = ((unsigned int)regT << 16) | (unsigned int)d; + switch (IR & ~070) { + case ND_SKP_LDATX: + regA = prdmem(paddr, PM_CPU); + break; + case ND_SKP_STZTX: + pwrmem(paddr, 0, PM_CPU); + break; + case ND_SKP_STATX: + pwrmem(paddr, regA, PM_CPU); + break; + case ND_SKP_STDTX: + pwrmem(paddr++, regA, PM_CPU); + pwrmem(paddr, regD, PM_CPU); + break; + case ND_SKP_LDXTX: + regX = prdmem(paddr, PM_CPU); + break; + case ND_SKP_LDDTX: + regA = prdmem(paddr++, PM_CPU); + regD = prdmem(paddr, PM_CPU); + break; + case ND_SKP_LDBTX: + regB = (prdmem(paddr, PM_CPU) << 1) | 0177000; + break; + default: + intrpt14(IIE_II, PM_CPU); + } } else if (IR == ND_SKP_MIX3) { /* X = (A-1)*3 */ regX = (regA-1)*3; @@ -531,14 +568,22 @@ ins_skip_ext(int IR) identrm(12); } else if (IR == ND_SKP_IDENT13) { identrm(13); - } else if (IR == ND_SKP_BFILL) + } else if (IR == ND_SKP_ADDD) { + intrpt14(IIE_II, PM_CPU); + } else if (IR == ND_SKP_BFILL) { ins_bfill(IR); - else if (IR == ND_SKP_MOVB) + } else if (IR == ND_SKP_MOVB) { ins_movb(IR); - else if (IR == ND_SKP_MOVBF) + } else if (IR == ND_SKP_MOVBF) { ins_movbf(IR); - else if (IR == ND_SKP_LBYT) { - d = rdmem(regT + (regX >> 1)); + } else if (IR == ND_SKP_LWCS) { + ; + } else if (IR == 0140127) { /* XXX */ + intrpt14(IIE_II, PM_CPU); + } else if (IR == ND_SKP_VERSN) { + intrpt14(IIE_II, PM_CPU); + } else if (IR == ND_SKP_LBYT) { + d = rdmem(regT + (regX >> 1), M_APT); if (regX & 1) regA = d & 0377; else @@ -546,9 +591,9 @@ ins_skip_ext(int IR) } else if (IR == ND_SKP_SBYT) { d = regT + (regX >> 1); if (regX & 1) - wrmem(d, (rdmem(d) & 0xff00) | (regA & 0xff)); + wrmem(d, (rdmem(d, M_APT) & 0xff00) | (regA & 0xff), M_APT); else - wrmem(d, (rdmem(d) & 0xff) | (regA << 8)); + wrmem(d, (rdmem(d, M_APT) & 0xff) | (regA << 8), M_APT); } else if ((IR & 0177700) == ND_SKP_RMPY) { ss = R[(IR & 070) >> 3]; sd = R[IR & 07]; @@ -560,10 +605,9 @@ ins_skip_ext(int IR) shc = (regA << 16) | regD; regA = shc / ss; regD = shc % ss; - } else if (IR == 0142700) { + } else if (IR == 0142700 || IR == 0143700) { /* ??? what is this? */ - intrpt14(IIE_II); - regP--; + intrpt14(IIE_II, PM_CPU); } else reason = STOP_UNHINS; return reason; @@ -590,11 +634,10 @@ ins_srb(int IR) /* Save current level (maybe used) to reg block */ for (i = 0; i < 8; i++) RBLK[curlvl][i] = R[i]; - RBLK[curlvl][rnP]++; /* following insn */ /* store requested block to memory */ for (i = 0; i < 8; i++) - wrmem(regX+i, RBLK[n][s2r[i]]); + wrmem(regX+i, RBLK[n][s2r[i]], M_APT); } /* @@ -614,7 +657,7 @@ ins_lrb(int IR) /* fetch from memory */ for (i = 0; i < 8; i++) - RBLK[n][s2r[i]] = rdmem(regX+i); + RBLK[n][s2r[i]] = rdmem(regX+i, M_APT); RBLK[n][rnSTS] &= 0377; if (n == curlvl) @@ -623,6 +666,56 @@ ins_lrb(int IR) R[i] = RBLK[n][i]; } +/* + * Priv instructions, mostly for handling status reg. + */ +static int +nd_mis_opc(int IR) +{ + static int srbits[] = { 0, STS_IONI, STS_IONI, 0, + STS_PONI, (STS_PONI|STS_IONI), STS_SEXI, STS_SEXI, + STS_PONI, 0, (STS_PONI|STS_IONI) }; + int rv = 0; + + mm_privcheck(); + switch (IR) { + /* case ND_MIS_OPCOM: */ + /* break; */ + + case ND_MIS_IOF: + case ND_MIS_POF: + case ND_MIS_PIOF: + case ND_MIS_REX: + regSTH &= ~srbits[IR & 017]; + break; + + case ND_MIS_ION: + case ND_MIS_SEX: + case ND_MIS_PON: + case ND_MIS_PION: + regSTH |= srbits[IR & 017]; + break; + + case ND_MIS_IOXT: + rv = iox_check(regT); + break; + + case ND_MIS_EXAM: + regT = prdmem((regA << 16) | regD, M_FETCH); + break; + + case ND_MIS_DEPO: + pwrmem((regA << 16) | regD, regT, M_FETCH); + break; + + default: + rv = STOP_UNHINS; + break; + } + return rv; + +} + /* * Miscellaneous instructions. */ @@ -632,29 +725,9 @@ ins_mis(int IR, int off) int reason = 0; int n, i; - if (IR == ND_MIS_SEX) - regSTH |= STS_SEXI; - else if (IR == ND_MIS_DEPO) { - if ((n = ((regA << 16) | regD)) <= MAXMEMSIZE) - PM[n] = regT; - } else if (IR == ND_MIS_EXAM) { - if ((n = ((regA << 16) | regD)) <= MAXMEMSIZE) - regT = PM[n]; - } else if (IR == ND_MIS_REX) { - regSTH &= ~STS_SEXI; - } else if (IR == ND_MIS_PON) { - regSTH |= STS_PONI; - } else if (IR == ND_MIS_POF) { - regSTH &= ~STS_PONI; - } else if (IR == ND_MIS_ION) { - regSTH |= STS_IONI; - } else if (IR == ND_MIS_IOF) { - regSTH &= ~STS_IONI; - } else if (IR == ND_MIS_PIOF) { - regSTH &= ~(STS_IONI|STS_PONI); - } else if (IR == ND_MIS_IOXT) { - reason = iox_check(regT); - } else if ((IR & ND_MIS_TRMSK) == ND_MIS_TRA) + if ((IR & 0177760) == ND_MIS_OPCOM) + reason = nd_mis_opc(IR); + else if ((IR & ND_MIS_TRMSK) == ND_MIS_TRA) reason = nd_tra(IR & ~ND_MIS_TRMSK); else if ((IR & ND_MIS_TRMSK) == ND_MIS_TRR) reason = nd_trr(IR & ~ND_MIS_TRMSK); @@ -663,12 +736,14 @@ ins_mis(int IR, int off) else if ((IR & ND_MIS_TRMSK) == ND_MIS_MCL) reason = nd_mcl(IR & ~ND_MIS_TRMSK); else if ((IR & ND_MIS_IRRMSK) == ND_MIS_IRR) { + mm_privcheck(); n = (IR >> 3) & 017; if (n == curlvl) regA = R[IR & 07]; else regA = RBLK[n][IR & 07]; } else if ((IR & ND_MIS_IRRMSK) == ND_MIS_IRW) { + mm_privcheck(); n = (IR >> 3) & 017; RBLK[n][IR & 07] = regA; if (n == curlvl && (IR & 07) != rnP) @@ -679,21 +754,18 @@ ins_mis(int IR, int off) ins_lrb(IR); } else if ((IR & ND_MONMSK) == ND_MON) { RBLK[14][rnT] = SEXT8(IR); - intrpt14(IIE_MC); + intrpt14(IIE_MC, PM_CPU); } else if ((IR & ND_MONMSK) == ND_WAIT) { if (ISION() == 0) { - regP++; reason = STOP_WAIT; } else if (curlvl > 0) { pid &= ~(1 << curlvl); n = highest_level(); if (curlvl != n) { - regP++; for (i = 0; i < 8; i++) { RBLK[curlvl][i] = R[i]; R[i] = RBLK[n][i]; } - regP--; } curlvl = n; } @@ -794,6 +866,7 @@ ins_bop(int IR, int addr) int rd, n, reason = 0; + regSTL = (regSTL & 0377) | regSTH; /* Hack for bskp */ rd = IR & 7; n = (IR >> 3) & 017; switch ((IR >> 7) & 017) { @@ -826,7 +899,6 @@ ins_bop(int IR, int addr) regP++; break; - case 010: /* BSTA store ~K and set K */ R[rd] &= ~(1 << n); if ((regSTL & STS_K) == 0) @@ -885,6 +957,7 @@ ins_bop(int IR, int addr) reason = STOP_UNHINS; break; } + regSTL &= 0377; return reason; } @@ -1000,11 +1073,11 @@ int ins_fmu(int IR, int addr) { struct fp f1, f2; - int s3, e3; + int s3, e3, pt = SELPT2(IR); t_uint64 m3; /* Fetch from memory */ - mkfp48(&f1, rdmem(addr), rdmem(addr+1), rdmem(addr+2)); + mkfp48(&f1, rdmem(addr, pt), rdmem(addr+1, pt), rdmem(addr+2, pt)); /* From registers */ mkfp48(&f2, regT, regA, regD); @@ -1044,11 +1117,12 @@ int ins_fdv(int IR, int addr) { struct fp f1, f2; - int s3, e3; + int s3, e3, pt; t_uint64 m3; /* Fetch from memory */ - mkfp48(&f1, rdmem(addr), rdmem(addr+1), rdmem(addr+2)); + pt = SELPT2(IR); + mkfp48(&f1, rdmem(addr, pt), rdmem(addr+1, pt), rdmem(addr+2, pt)); /* From registers */ mkfp48(&f2, regT, regA, regD); @@ -1059,7 +1133,7 @@ ins_fdv(int IR, int addr) regSTL |= STS_Z; regT |= 077777; regA = regD = 0177777; - intrpt14(IIE_V); + intrpt14(IIE_V, PM_CPU); return SCPE_OK; } @@ -1177,8 +1251,9 @@ int ins_fad(int IR, int addr) { struct fp f1, f2; + int pt = SELPT2(IR); - mkfp48(&f1, rdmem(addr), rdmem(addr+1), rdmem(addr+2)); + mkfp48(&f1, rdmem(addr, pt), rdmem(addr+1, pt), rdmem(addr+2, pt)); mkfp48(&f2, regT, regA, regD); if (f1.s ^ f2.s) @@ -1192,8 +1267,9 @@ int ins_fsb(int IR, int addr) { struct fp f1, f2; + int pt = SELPT2(IR); - mkfp48(&f1, rdmem(addr), rdmem(addr+1), rdmem(addr+2)); + mkfp48(&f1, rdmem(addr, pt), rdmem(addr+1, pt), rdmem(addr+2, pt)); mkfp48(&f2, regT, regA, regD); f1.s ^= 1; /* swap sign of right op */ @@ -1233,7 +1309,7 @@ add3(uint16 a, uint16 d, uint16 c) int ins_mpy(int IR, int off) { - int res = (int)(int16)regA * (int)(int16)rdmem(off); + int res = (int)(int16)regA * (int)(int16)rdmem(off, SELPT2(IR)); regA = res; regSTL &= ~STS_Q; if (res > 32767) @@ -1248,12 +1324,13 @@ int ins_jmpl(int IR, int off) { if (BIT12(IR)) - regL = regP+1; - regP = off-1; + regL = regP; + regP = off; return SCPE_OK; } /* * Conditional jump. + * off is unused here. */ int ins_cjp(int IR, int off) @@ -1313,8 +1390,6 @@ ins_rop(int IR, int off) rd = IR & 07; s = rs ? R[rs] : 0; d = rd ? R[rd] : 0; - if (rs == 2) s++; - if (rd == 2) d++; if (BIT6(IR)) d = 0; /* clear dest */ if (BIT7(IR)) s = ~s; /* complement src */ if (BIT10(IR)) { /* add source to destination */ @@ -1335,7 +1410,6 @@ ins_rop(int IR, int off) } } if (rd) R[rd] = d; - if (rd == 2) regP--; return SCPE_OK; } @@ -1345,28 +1419,17 @@ ins_rop(int IR, int off) static int iox_check(int dev) { -#ifdef TIMERHACK - if ((dev & 03777) == 011) { - rtccnt = 0; - return SCPE_OK; - } - if ((dev & 03777) == 013) { - rtc_int_enabled = regA & 1; - if ((regA >> 13) & 1) - rtc_dev_ready = 0; - return SCPE_OK; - } -#else + + mm_privcheck(); + if ((dev & 0177774) == 010) return iox_clk(dev); -#endif if ((dev & 0177770) == 0300) return iox_tty(dev); if ((dev & 0177770) == 01560) return iox_floppy(dev); - intrpt14(IIE_IOX); - + intrpt14(IIE_IOX, PM_CPU); return SCPE_OK; } @@ -1376,15 +1439,15 @@ getoff(int ir) { int ea; - ea = BIT8(ir) ? regB : regP; - if (BIT10(ir) & !BIT9(ir)) + ea = BIT8(ir) ? regB : oregP; + if (BIT10(ir) & !BIT9(ir) & !BIT8(ir)) ea = 0; ea += SEXT8(ir); if (BIT9(ir)) - ea = rdmem(ea); + ea = rdmem(ea & 0177777, BIT8(ir) ? M_APT : M_PT); if (BIT10(ir)) ea += regX; - return ea; + return ea & 0177777; } /* @@ -1395,6 +1458,8 @@ nd_mcl(int reg) { int reason = SCPE_OK; + mm_privcheck(); + switch (reg) { case IR_STS: regSTL &= ~(regA & 0377); @@ -1421,14 +1486,16 @@ nd_mst(int reg) { int reason = SCPE_OK; + mm_privcheck(); + switch (reg) { case IR_STS: regSTL |= (regA & 0377); break; - case 006: /* PID */ + case IR_PID: /* PID */ pid |= regA; break; - case 007: /* PIE */ + case IR_PIE: /* PIE */ pie |= regA; break; @@ -1446,6 +1513,8 @@ nd_trr(int reg) { int reason = SCPE_OK; + mm_privcheck(); + switch (reg) { case IR_STS: regSTL = regA & 0377; @@ -1457,7 +1526,7 @@ nd_trr(int reg) mm_wrpcr(); break; case 005: /* IIE */ - iie = regA & 02776; + iie = regA & 03776; break; case 006: /* PID */ pid = regA; @@ -1465,6 +1534,12 @@ nd_trr(int reg) case 007: /* PIE */ pie = regA; break; + case IR_CCL: + break; + case IR_LCIL: + break; + case IR_UCIL: + break; case IR_ECCR: eccr = regA; break; @@ -1482,15 +1557,20 @@ nd_tra(int reg) { int reason = SCPE_OK; + mm_privcheck(); + switch (reg) { + case IR_PANS: + regA = 0; + break; case IR_STS: /* STS */ regA = regSTL | regSTH | (curlvl << 8); break; - case IR_PGS: /* 3 */ - regA = 0; /* XXX */ + case IRR_OPR: + regA = opr; break; - case IR_PVL: /* 4 */ - regA = pvl; + case IRR_PVL: + regA = (pvl << 3) | 0153602; break; case IR_IIC: /* read IIC. Clears IIC and IID */ regA = iic; @@ -1509,23 +1589,14 @@ nd_tra(int reg) case 012: /* ALD */ regA = ald; break; - case 013: /* PES */ - regA = 0; /* XXX */ - break; - case 014: /* read back PCR */ - mm_rdpcr(); - break; - case 015: /* */ - regA = 0; /* XXX */ - break; default: - reason = STOP_UNHINS; + reason = mm_tra(reg); } return reason; } int -highest_level(void) +highest_level() { int i, d = pid & pie; @@ -1555,14 +1626,19 @@ fls(int msk) * Post an internal interrupt for the given source. */ void -intrpt14(int src) +intrpt14(int src, int where) { iid |= src; /* set detect flipflop */ for (iic = 0; (src & 1) == 0; iic++, src >>= 1) ; - if (iid & iie) /* if internal int enabled, post priority int */ + if (iid & iie) { /* if internal int enabled, post priority int */ pid |= (1 << 14); + /* If we can interrupt, jump directly back */ + if (ISION() && curlvl < 14 && (pie & (1 << 14)) && + (where == PM_CPU)) + longjmp(env, 0); + } } void @@ -1587,7 +1663,8 @@ identrm(int id) struct intr *ip = ilnk[id-10]; if (ip == 0) { - intrpt14(IIE_IOX); + intrpt14(IIE_IOX, PM_CPU); + regA = 0; } else { regA = ip->ident; ilnk[id-10] = ip->next; @@ -1598,21 +1675,6 @@ identrm(int id) } } -#ifdef TIMERHACK -struct intr rtc_intx = { 0, 1 }; -void -chkrtc(void) -{ - if (rtccnt++ < 5001) - return; - rtccnt = 0; - rtc_dev_ready = 1; - if (rtc_int_enabled) { - extint(13, &rtc_intx); - } -} -#endif - static void hist_save(int ir) { @@ -1626,13 +1688,13 @@ hist_save(int ir) hist_ptr->ir = ir; hist_ptr->sts = regSTL | regSTH | (curlvl << 8); - hist_ptr->d = R[1]; - hist_ptr->p = R[2]; - hist_ptr->b = R[3]; - hist_ptr->l = R[4]; - hist_ptr->a = R[5]; - hist_ptr->t = R[6]; - hist_ptr->x = R[7]; + hist_ptr->d = regD; + hist_ptr->p = oregP; + hist_ptr->b = regB; + hist_ptr->l = regL; + hist_ptr->a = regA; + hist_ptr->t = regT; + hist_ptr->x = regX; } t_stat @@ -1732,4 +1794,3 @@ hist_show(FILE *st, UNIT *uptr, int32 val, CONST void *desc) } return SCPE_OK; } - diff --git a/ND100/nd100_defs.h b/ND100/nd100_defs.h index d956cb90..11783c8a 100644 --- a/ND100/nd100_defs.h +++ b/ND100/nd100_defs.h @@ -82,14 +82,24 @@ #define ND_SKP_CLEPT 0140301 #define ND_SKP_EXR 0140600 +#define ND_SKP_ADDD 0140120 /* CE/CX */ #define ND_SKP_BFILL 0140130 #define ND_SKP_MOVB 0140131 #define ND_SKP_MOVBF 0140132 +#define ND_SKP_VERSN 0140133 /* ND110 */ #define ND_SKP_RMPY 0141200 #define ND_SKP_RDIV 0141600 #define ND_SKP_LBYT 0142200 #define ND_SKP_SBYT 0142600 #define ND_SKP_MIX3 0143200 +#define ND_SKP_LDATX 0143300 /* ND100 */ +#define ND_SKP_LDXTX 0143301 /* ND100 */ +#define ND_SKP_LDDTX 0143302 /* ND100 */ +#define ND_SKP_LDBTX 0143303 /* ND100 */ +#define ND_SKP_STATX 0143304 /* ND100 */ +#define ND_SKP_STZTX 0143305 /* ND100 */ +#define ND_SKP_STDTX 0143306 /* ND100 */ +#define ND_SKP_LWCS 0143500 /* NOP on N110 */ #define ND_SKP_IDENT10 0143604 #define ND_SKP_IDENT11 0143611 #define ND_SKP_IDENT12 0143622 @@ -115,6 +125,7 @@ #define ND_WAIT 0151000 #define ND_MONMSK 0177400 +#define ND_MIS_OPCOM 0150400 #define ND_MIS_IOF 0150401 #define ND_MIS_ION 0150402 #define ND_MIS_POF 0150404 @@ -128,20 +139,32 @@ #define ND_MIS_DEPO 0150417 /* Internal registers */ +#define IR_PANS 000 /* Panel status */ #define IR_STS 001 /* Status reg (as in register stack) */ -#define IR_OPR 002 /* Operator reg */ #define IR_LMP 002 /* Display reg */ -#define IR_PGS 003 /* paging status reg */ #define IR_PCR 003 /* paging control reg */ -#define IR_PVL 004 /* Previous level */ #define IR_IIC 005 /* Internal interrupt code */ #define IR_IIE 005 /* Internal interrupt enable */ #define IR_PID 006 /* Priority interrupt detect */ #define IR_PIE 007 /* Priority interrupt enable */ #define IR_CSR 010 /* Cache status reg */ -#define IR_PCR14 014 /* paging control reg */ +#define IR_CCL 010 /* (W) Cache clear reg */ +#define IR_LCIL 011 /* (W) Lower cache inhibit limit register */ +#define IR_UCIL 012 /* (W) Upper cache inhibit limit register */ #define IR_ECCR 015 /* Error Correction Control Register */ +#define IRR_OPR 002 /* Operator reg */ +#define IRR_PGS 003 /* paging status reg */ +#define PGS_FF 0100000 /* fetch fault */ +#define PGS_PM 0040000 /* permit violation */ +#define IRR_PVL 004 /* Previous level (oddly encoded) */ +#define IRR_PES 013 /* Parity error status */ +#define PES_FETCH 0100000 /* Memory error during fetch, EXAM or DEPO */ +#define PES_DMA 0040000 /* Error occurred during DMA */ +#define IRR_PGC 014 /* Read paging control reg */ +#define IRR_PEA 015 /* Parity error address */ +int mm_tra(int reg); + /* internal interrupt enable register */ #define IIE_MC 0000002 /* Monitor call */ #define IIE_PV 0000004 /* Protect Violation */ @@ -172,7 +195,10 @@ #define ISPON() BIT14(regSTH) #define ISSEX() BIT13(regSTH) -/* paging bits */ +/* page table bits */ +#define PT_WPM 0100000 +#define PT_RPM 0040000 +#define PT_FPM 0020000 #define PT_WIP 0010000 #define PT_PGU 0004000 @@ -198,7 +224,8 @@ extern uint16 PM[]; extern uint16 R[8]; extern uint16 regSTH; /* common for all levels */ extern int ald; /* Automatic load descriptor - set by boot */ -extern int curlvl; +extern int curlvl; /* Current interrupt level */ +extern int userring; /* Current user ring */ /* * interrupt link per device. @@ -220,18 +247,31 @@ int iox_floppy(int addr); int iox_tty(int addr); int iox_clk(int addr); +/* virtual memory access */ #define M_PHYS 0 #define M_PT 1 #define M_APT 2 #define M_FETCH 3 -uint16 rdmem(int addr/* , int how*/); -uint8 rdbyte(int vaddr, int lr/* , int how*/); -void wrmem(int addr, int val/* , int how*/); -void wrbyte(int vaddr, int val, int lr/* , int how*/); -void mm_wrpcr(void); -void mm_rdpcr(void); +/* physical memory access */ +#define PM_CPU 10 /* CPU requesting (longjmp allowed) */ +#define PM_DMA 11 /* device requesting (no longjmp) */ +/* Decide page table for late read */ +#define SELPT2(IR) ((IR) & 03400 ? M_APT : M_PT) + +int dma_rdmem(int addr); +int dma_wrmem(int addr, int val); +uint16 prdmem(int addr, int how); +void pwrmem(int addr, int val, int how); +uint16 rdmem(int addr, int how); +uint8 rdbyte(int vaddr, int lr, int how); +void wrmem(int addr, int val, int how); +void wrbyte(int vaddr, int val, int lr, int how); +void mm_wrpcr(void); +void mm_privcheck(void); + +void intrpt14(int, int where); void extint(int lvl, struct intr *intr); #define STOP_UNHIOX 1 @@ -239,6 +279,7 @@ void extint(int lvl, struct intr *intr); #define STOP_CKSUM 3 #define STOP_BP 4 #define STOP_WAIT 5 +#define STOP_END 6 /* Useful bit extraction macros */ #define BIT0(x) ((x) & 1) diff --git a/ND100/nd100_floppy.c b/ND100/nd100_floppy.c index d7339ce0..c615e5a5 100644 --- a/ND100/nd100_floppy.c +++ b/ND100/nd100_floppy.c @@ -31,13 +31,21 @@ #include "nd100_defs.h" /* - * Floppy and Streamer Controller (3112). + * Floppy and Streamer Controller 3112. * ND documentation ND-11.021.1 * - * Currently only 5 1/4" DS/DD floppies implemented (no streamer). + * Also support Floppy Controller 3027 (Z80 version). + * ND documentation ND-11.015.1 + * + * Currently only floppies implemented (no streamer). * * The device uses eight IOX addresses, but the transfer commands * are given in a command block of 12 words in memory. + * + * ND uses three floppy formats (but in theory can handle a lot of formats). + * - SS/SD 8" (type 0): 77*8*512= 315392 bytes. + * - DS/DD 8" (type 017): 77*8*1024*2= 1261568 bytes. + * - DS/DD 5 1/4 (type 017?): 80*8*1024*2= 1261568 bytes. */ t_stat floppy_svc(UNIT *uptr); @@ -45,6 +53,9 @@ t_stat floppy_reset (DEVICE *dptr); t_stat floppy_boot (int32 unitno, DEVICE *dptr); t_stat floppy_attach (UNIT *uptr, CONST char *cptr); static int floppy_excmd(void); +static int floppy_test(UNIT *up); +static int dtomem(FILE *fp, int daddr, int maddr, int wcnt, int how); +static int getmval(void); #define FL_NTR 80 /* # tracks/side */ #define FL_NSC 8 /* # sectors/track */ @@ -59,7 +70,7 @@ static int floppy_excmd(void); #define FL_ST_RDY 0000010 /* device ready for transfer (RFT) */ #define FL_ST_ERR 0000020 /* OR of errors */ #define FL_ST_HE 0000100 /* Hard error (DMA) */ -#define FL_ST_DENS 0100000 /* Dual density ctlr */ +#define FL_ST_DENS 0140000 /* Dual density ctlr */ /* hardware control word */ #define FL_CW_IE 0000002 /* interrupt enable (RFT) */ @@ -128,6 +139,7 @@ static int fl_lpl; /* devno + 7 load pointer low */ /* Command word (000) */ #define CW_FL_RD 0000000 /* Read data */ #define CW_FL_WR 0000001 /* Write data */ +#define CW_FL_EXTST 0000036 /* Read extended status */ #define CW_FL_RDFMT 0000042 /* Read format */ #define CW_FL_CMDMSK 077 /* mask for command */ #define CW_FL_SELSH 6 /* shift for unit */ @@ -147,6 +159,7 @@ static int fl_lpl; /* devno + 7 load pointer low */ #define U_READ 01 /* unit reading */ #define U_WRITE 02 /* unit writing */ #define U_RDFMT 03 /* Read format */ +#define U_EXTST 04 /* Read extended status */ #define devaddr u4 /* unit offset (in words) */ #define wcnt u5 /* word count */ @@ -199,21 +212,21 @@ iox_floppy(int addr) int n; int rv = 0; - switch (addr & 07) { case 0: /* read data */ regA = 0; break; - case 1: - break; - case 2: regA = fl_rstatus; break; case 3: n = regA; + if (n & FL_CW_TEST) { + rv = floppy_test(&floppy_unit[0]); + break; + } if (n & FL_CW_FCE) { rv = floppy_excmd(); break; @@ -239,10 +252,10 @@ iox_floppy(int addr) break; default: - rv = STOP_UNHIOX; - break; + if ((addr & 1) == 0) + regA = 0; + break; /* Unused IOXes are ignored */ } - return rv; } @@ -253,32 +266,61 @@ floppy_reset(DEVICE *dptr) return 0; } +/* + * Estimate floppy format based on disk size and return status2 word. + * - SS/SD = 315392 bytes, c/h/s 77/1/8 (512b sectors) + * - DS/DD = 1261568 bytes, c/h/s 77/2/8 (1024b sectors) + * - DS/DD 5 1/4" = 1310720 bytes, c/h/s 80/2/8 (1024b sectors) + */ +static int +readfmt(UNIT *up) +{ + if (sim_fseek(up->fileref, 0, SEEK_END) < 0) + return -1; + switch (sim_ftell(up->fileref)) { + case 315392: + return 0; + case 1261568: + return ST2_FL_DD|ST2_FL_DS|ST2_FL_BS1K; + case 1310720: + return /* ST2_FL_514| */ST2_FL_DD|ST2_FL_DS|ST2_FL_BS1K; + default: + break; + } + return -1; +} + + t_stat floppy_svc(UNIT *uptr) { - unsigned char *wp; - int i, j; - int cbaddr = fl_lpl + ((fl_lph & 0377) << 8); + int cbaddr = getmval(); int lah = 0, lal = 0; + int status2 = 0; + int remwh = 0, remwl = 0; if ((fl_rstatus & FL_ST_ACT) == 0) return STOP_UNHIOX; switch (uptr->state) { case U_READ: - wp = malloc(uptr->wcnt * 2); - if (fseek(uptr->fileref, uptr->devaddr * 2, SEEK_SET) < 0) - goto err; - if (sim_fread(wp, uptr->wcnt, 2, uptr->fileref) < 0) - goto err; - for (i = 0, j = 0; i < uptr->wcnt; i++, j += 2) - wrmem(uptr->memaddr+i, (wp[j] << 8) | wp[j+1]); + dtomem(uptr->fileref, uptr->devaddr, + uptr->memaddr, uptr->wcnt, PM_DMA); lah = (uptr->memaddr + uptr->wcnt) >> 16; lal = (uptr->memaddr + uptr->wcnt) & 0177777; - free(wp); break; case U_RDFMT: + if ((status2 = readfmt(uptr)) < 0) + goto err; + break; + + case U_EXTST: /* XXX no docs found...? */ + lah = (uptr->memaddr + uptr->wcnt) >> 16; + lal = (uptr->memaddr + uptr->wcnt) & 0177777; + remwh = 0100000; /* XXX */ + remwl = 1; /* XXX */ + pwrmem(uptr->memaddr, 06201, PM_DMA); /* XXX */ break; case U_WRITE: @@ -286,13 +328,12 @@ floppy_svc(UNIT *uptr) return STOP_UNHIOX; } - wrmem(cbaddr+CB_ST1, FL_ST_RDY); - wrmem(cbaddr+CB_ST2, - ST2_FL_BS1K|ST2_FL_DS|ST2_FL_DD|ST2_FL_514); - wrmem(cbaddr+CB_LAH, lah); - wrmem(cbaddr+CB_LAL, lal); - wrmem(cbaddr+CB_REMWH, 0); - wrmem(cbaddr+CB_REMWL, 0); + pwrmem(cbaddr+CB_ST1, FL_ST_RDY, PM_DMA); + pwrmem(cbaddr+CB_ST2, status2, PM_DMA); /* set after error or rdfmt */ + pwrmem(cbaddr+CB_LAH, lah, PM_DMA); + pwrmem(cbaddr+CB_LAL, lal, PM_DMA); + pwrmem(cbaddr+CB_REMWH, remwh, PM_DMA); + pwrmem(cbaddr+CB_REMWL, remwl, PM_DMA); fl_rstatus &= ~FL_ST_ACT; fl_rstatus |= FL_ST_RDY; @@ -305,6 +346,38 @@ err: return STOP_UNHIOX; } +/* + * Get physical memory address for command block. + */ +static int +getmval(void) +{ + return fl_lpl + ((fl_lph & 0377) << 8); +} + +/* + * Read a block from file fp, position daddr (bytes) to ND100 memory maddr + * wcnt words. + * Return 0 or fail. + */ +static int +dtomem(FILE *fp, int daddr, int maddr, int wcnt, int how) +{ + unsigned char *wp; + int bcnt = wcnt *2; + int i; + + wp = malloc(wcnt * 2); /* bounce buffer */ + if (sim_fseek(fp, daddr, SEEK_SET) < 0) + return STOP_UNHIOX; + if (sim_fread(wp, bcnt, 1, fp) < 0) + return STOP_UNHIOX; + for (i = 0; i < bcnt; i += 2) + wrmem(maddr++, (wp[i] << 8) | wp[i+1], how); + free(wp); + return SCPE_OK; +} + t_stat floppy_boot(int32 unitno, DEVICE *dptr) { @@ -312,14 +385,63 @@ floppy_boot(int32 unitno, DEVICE *dptr) return 1; } +/* + * It seems that some of the boot programs uses the Z80 test programs + * on the controller card. We try to mimic the behaviour. + * + * This data structure (in ND100) is used in test T13 and T14. + * + * 15 8 7 0 + * +---------------------------------------------+ + * 0 | ND100 Load address | + * +---------------------------------------------+ + * 1 | Z80 address | + * +---------------------------------------------+ + * 2 | Byte count | + * +---------------------------------------------+ + */ +static int +floppy_test(UNIT *up) +{ + int cbaddr = getmval(); + int n100addr, z80addr, bcnt; + int rv = 0; + + if ((regA & FL_CW_FCE) == 0) + return STOP_UNHIOX; /* What to do? */ + switch (regA >> 9) { + case 016: /* T14, load from Z80 to ND100 */ + n100addr = prdmem(cbaddr, PM_CPU); + z80addr = prdmem(cbaddr+1, PM_CPU); + bcnt = prdmem(cbaddr+2, PM_CPU); + if (bcnt > 3584) + return STOP_UNHIOX; + printf("\r\n addr %06o nd100 %06o z80 %04x count %o\r\n", + cbaddr, prdmem(cbaddr, PM_CPU), + prdmem(cbaddr+1, PM_CPU), prdmem(cbaddr+2, PM_CPU)); + dtomem(up->fileref, up->devaddr + z80addr - 0x2200, + n100addr, bcnt/2, PM_CPU); + break; + + default: + return STOP_UNHIOX; + } + return rv; +} + +/* + * Execute. Fills in the unit local vars memaddr/wcnt/devaddr from the + * command block and setup for interrupt later. + */ static int floppy_excmd(void) { UNIT *unit; - int cw, u, cmd; - int cbaddr = fl_lpl + ((fl_lph & 0377) << 8); + int cw, u, cmd, i; + int cbaddr = getmval(); + int status2, sectsz; - cw = rdmem(cbaddr+CB_CW); + cw = prdmem(cbaddr+CB_CW, PM_CPU); u = (cw >> CW_FL_SELSH) & 03; cmd = cw & CW_FL_CMDMSK; @@ -327,26 +449,34 @@ floppy_excmd(void) if ((unit->flags & UNIT_ATT) == 0) goto err; /* floppy not inserted */ + status2 = readfmt(unit); + sectsz = (status2 & ST2_FL_BS1K) == 0 ? 512 : 1024; + /* XXX check disk size, word count etc... */ - unit->memaddr = ((rdmem(cbaddr+CB_DAHMAH) & 0377) << 16) | rdmem(cbaddr+CB_MAL); - unit->wcnt = ((rdmem(cbaddr+CB_OPTWCH) & 0377) << 16) | rdmem(cbaddr+CB_WCL); - unit->devaddr = ((rdmem(cbaddr+CB_DAHMAH) & 0177400) << 8) | - rdmem(cbaddr+CB_DAL); - - if (cmd == CW_FL_RDFMT) { - unit->state = U_RDFMT; - } else if (cmd == CW_FL_RD || cmd == CW_FL_WR) { - if (cmd == CW_FL_WR) - goto err; /* floppy write protected */ - - if ((cw & CW_FL_1K) != CW_FL_1K) - goto err; /* Require 1K sectors */ - if ((cw & (CW_FL_DS|CW_FL_DD)) != (CW_FL_DS|CW_FL_DD)) - goto err; /* Must be double sided/double density */ + unit->memaddr = ((prdmem(cbaddr+CB_DAHMAH, PM_CPU) & 0377) << 16) | + prdmem(cbaddr+CB_MAL, PM_CPU); + i = prdmem(cbaddr+CB_OPTWCH, PM_CPU); + unit->wcnt = ((i & 0377) << 16) | prdmem(cbaddr+CB_WCL, PM_CPU); + if ((i & CB_OPT_WC) == 0) + unit->wcnt *= (sectsz/2); + unit->devaddr = (((prdmem(cbaddr+CB_DAHMAH, PM_CPU) & 0177400) << 8) | + prdmem(cbaddr+CB_DAL, PM_CPU)) * sectsz; + switch (cmd) { + case CW_FL_RD: unit->state = U_READ; - } else + break; + case CW_FL_WR: + goto err; /* floppy write protected */ + case CW_FL_EXTST: + unit->state = U_EXTST; + break; + case CW_FL_RDFMT: + unit->state = U_RDFMT; + break; + default: goto err; + } sim_activate(&floppy_unit[u], 10); fl_rstatus &= ~FL_ST_RDY; diff --git a/ND100/nd100_mm.c b/ND100/nd100_mm.c index 7c8315b2..d114c9b5 100644 --- a/ND100/nd100_mm.c +++ b/ND100/nd100_mm.c @@ -23,12 +23,61 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include "sim_defs.h" - #include "nd100_defs.h" +/* + * Nord-100 Memory Management I + * + * The paging system on Nord-100 have two modes; normal and extended. + * In normal mode it is Nord-10-compatible (with a maximum of 512KW memory) + * and in extended it can handle up to 16MW. + * + * It is quite extensive with both individual page protection (RWX) and + * ring protection, where it has four rings. Ring 0 has lowest prio, ring 3 + * has highest. + * + * Page size is 1KW, so 64 pages per address space (page table, PT). + * A process can use an extra page table as well, called alternate page table. + * It is intended to allow large processes to use a separate data space. + * There are four page tables, the PCR tells which table(s) to use. + * + * Which protection ring and which page tables a user belongs to is + * configured in the internal Paging Control Register (PCR). There is + * one PCR per interrupt level. The PCR looks like this: + * + * +-------------------+-------+-----+----------+--+-----+ + * | Unused | PT | APT | Level | 0| Ring| + * +-------------------+-------+-----+----------+--+-----+ + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * + * PT/APT tells which page table should be used. There are four of them. + * Level is not stored in the PCR, it is only used to tell which level + * a PCR belongs to. + * Ring is the user ring. Must always be >= the page ring. + * + * The page tables are located in "shadow memory". Shadow memory is the + * top pages (>= 177400 in normal mode and >= 177000 in extended) only + * accessible when running as ring 3. + * Page table for normal mode looks as below: + * + * +---+---+---+---+---+-------+-------------------------+ + * |WPM|RPM|FPM|WIP|PGU| Ring | Physical Page Number | + * +---+---+---+---+---+-------+-------------------------+ + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * + * WPM/RPM/FPM allows for Write/Read/Fetch. + * WIP is set by HW and means "Written in page". + * PGU is set by HW and means "Page used". + * Ring is the ring the page belongs to. Must be <= User ring. + * + * Note that the executing program get its ring level from the page where + * the instruction were fetched from, so if the User ring is 3 but the + * page ring is 2 then the progra cannot access the page tables. + */ -#define MAXMEMSIZE 512*1024 +#define MAXMEMSIZE (512*1024) t_stat mm_reset(DEVICE *dptr); @@ -36,6 +85,11 @@ uint16 PM[MAXMEMSIZE]; uint16 PCR[16]; /* Paging control register */ uint16 ptmap[4][64]; /* protection */ uint16 pmmap[4][64]; /* memory mapping */ +uint16 pea, pes, pgs; +int pea_locked, pgs_locked; /* flag to lock register after error */ +int userring; /* current user ring */ + +extern jmp_buf env; #define ISDIS() (mm_dev.flags & DEV_DIS) @@ -43,6 +97,9 @@ UNIT mm_unit = { UDATA(NULL, UNIT_FIX+UNIT_DISABLE+UNIT_BINK, 0) }; REG mm_reg[] = { { BRDATA(PCR, PCR, 8, 16, 16) }, + { ORDATA(PEA, pea, 16) }, + { ORDATA(PES, pes, 16) }, + { ORDATA(PGS, pgs, 16) }, { NULL } }; @@ -52,16 +109,50 @@ DEVICE mm_dev = { 1, 8, 16, 1, 8, 16, 0, 0, &mm_reset, NULL, NULL, NULL, - NULL, DEV_DISABLE+DEV_DIS + NULL, DEV_DISABLE }; +/* + * Internal registers located on the MM module. + */ +int +mm_tra(int reg) +{ + int rv = 0; + + switch (reg) { + case IRR_PES: + regA = pes; + break; + + case IRR_PGS: + regA = pgs; + pgs_locked = 0; + break; + + case IRR_PGC: + regA = PCR[(regA >> 3) & 017]; + break; + + case IRR_PEA: + regA = pea; + pea_locked = 0; + break; + + default: + rv = STOP_UNHINS; + } + return rv; +} + + /* * Read a byte. 0 in lr is left byte, 1 is right byte. */ uint8 -rdbyte(int vaddr, int lr/* , int how*/) +rdbyte(int vaddr, int lr, int how) { - uint16 val = rdmem(vaddr); + uint16 val = rdmem(vaddr, how); return lr ? val & 0377 : val >> 8; } @@ -70,13 +161,13 @@ rdbyte(int vaddr, int lr/* , int how*/) * Write a byte. 0 in lr is left byte, 1 is right byte. */ void -wrbyte(int vaddr, int val, int lr/* , int how*/) +wrbyte(int vaddr, int val, int lr, int how) { - uint16 ov = rdmem(vaddr); + uint16 ov = rdmem(vaddr, how); val &= 0377; /* sanity */ ov = lr ? (ov & 0177400) | val : (ov & 0377) | (val << 8); - wrmem(vaddr, ov); + wrmem(vaddr, ov, how); } /* @@ -90,6 +181,8 @@ is_shadow(int vaddr) { if ((PCR[curlvl] & 03) < 3 && ISPON()) return 0; /* not valid */ + if (vaddr > 0177777) + return 0; if (ISSEX()) return 1; return (vaddr >= 0177400); @@ -139,57 +232,188 @@ shadowwr(int v, int dat) } } +/* + * MOR - memory out of range. Addressing non-existent memory. + */ +void +morerr(int addr, int why, int pesval) +{ + if (pea_locked == 0) { + pea = (uint16)addr; + pes = (uint16)(addr >> 16) | pesval; + pea_locked = 1; + } + intrpt14(IIE_MOR, why); +} + +/* + * Physical memory read when doing DMA. + * The only error that can occur is non-existent memory (MOR). + * returns -1 if MOR, value otherwise. + */ +int +dma_rdmem(int addr) +{ + addr &= 0xffffff; + if (addr < MAXMEMSIZE) + return PM[addr]; + morerr(addr, PM_DMA, PES_DMA); + return -1; +} + +int +dma_wrmem(int addr, int val) +{ + addr &= 0xffffff; + if (addr < MAXMEMSIZE) { + PM[addr] = val; + return 0; + } + morerr(addr, PM_DMA, PES_DMA); + return -1; +} + +/* + * Read direct from physical (24-bit-addr) memory. + */ +uint16 +prdmem(int vaddr, int how) +{ + if ((vaddr & 0xffffff) < MAXMEMSIZE) + return PM[vaddr]; + morerr(vaddr, PM_CPU, how == M_FETCH ? PES_FETCH : 0); + return 0; +} + +static void +pgsupd(int pgnr, int pnr, int flg) +{ + if (pgs_locked) + return; + pgs = (pgnr << 6) | pnr | flg; + pgs_locked = 1; +} uint16 -rdmem(int vaddr/* , int how*/) +rdmem(int vaddr, int how) { - int pt; + uint16 *ptmapp; + int sh, pagetablenr, pagering, pagenr, permit, p; - vaddr &= 0177777; + vaddr &= 0177777; /* Sanity */ + /* Shadow memory? */ if ((vaddr >= 0177000) && is_shadow(vaddr)) return shadowrd(vaddr); - /* Mark page as read */ - if (ISPON()) { - pt = (PCR[curlvl] >> 8) & 03; - ptmap[pt][vaddr >> 10] |= PT_PGU; + /* Physical memory? */ + if (ISPON() == 0) + return prdmem(vaddr, 0); + + /* Paging on. */ + permit = (how == M_FETCH ? PT_FPM : PT_RPM); + userring = PCR[curlvl] & 03; + sh = how == M_APT ? 7 : 9; + pagetablenr = (PCR[curlvl] >> sh) & 03; + pagenr = vaddr >> 10; + ptmapp = &ptmap[pagetablenr][pagenr]; + pagering = (*ptmapp >> 9) & 03; + p = (permit == PT_FPM ? PGS_FF : 0); + if ((*ptmapp & (PT_WPM|PT_RPM|PT_FPM)) == 0) { + /* page fault */ + pgsupd(pagetablenr, pagenr, p | PGS_PM); + intrpt14(IIE_PF, PM_CPU); + } else if ((*ptmapp & permit) == 0) { + pgsupd(pagetablenr, pagenr, p | PGS_PM); + intrpt14(IIE_PV, PM_CPU); + } else if (pagering > userring) { + pgsupd(pagetablenr, pagenr, p); + intrpt14(IIE_PV, PM_CPU); + } else { + /* Mark page as read */ + *ptmapp |= PT_PGU; + vaddr = (pmmap[pagetablenr][pagenr] << 10) | (vaddr & 01777); + return prdmem(vaddr, 0); } + return 0; +} -// if (ISPON() == 0) - return PM[vaddr]; - +/* + * Write direct to physical (24-bit-addr) memory. + */ +void +pwrmem(int vaddr, int val, int how) +{ + if ((vaddr & 0xffffff) < MAXMEMSIZE) + PM[vaddr] = val; + else + morerr(vaddr, PM_CPU, how == M_FETCH ? PES_FETCH : 0); } void -wrmem(int vaddr, int val/* , int how*/) +wrmem(int vaddr, int val, int how) { + uint16 *ptmapp; + int sh, pagetablenr, pagering, permit, pagenr; + vaddr &= 0177777; if ((vaddr >= 0177000) && is_shadow(vaddr)) { shadowwr(vaddr, val); return; } - PM[vaddr] = val; + if (ISPON() == 0) { + pwrmem(vaddr, val, PM_CPU); + return; + } + /* Paging on. */ + permit = PT_WPM; + userring = PCR[curlvl] & 03; + sh = how == M_APT ? 7 : 9; + pagetablenr = (PCR[curlvl] >> sh) & 03; + pagenr = vaddr >> 10; + ptmapp = &ptmap[pagetablenr][pagenr]; + pagering = (*ptmapp >> 9) & 03; + if ((*ptmapp & (PT_WPM|PT_RPM|PT_FPM)) == 0) { + /* page fault */ + pgsupd(pagetablenr, pagenr, PGS_PM); + intrpt14(IIE_PF, PM_CPU); + } else if ((*ptmapp & permit) == 0) { + pgsupd(pagetablenr, pagenr, PGS_PM); + intrpt14(IIE_PV, PM_CPU); + } else if (pagering > userring) { + pgsupd(pagetablenr, pagenr, 0); + intrpt14(IIE_PV, PM_CPU); + } else { + /* Mark page as written */ + *ptmapp |= (PT_PGU|PT_WIP); + vaddr = (pmmap[pagetablenr][pagenr] << 10) | (vaddr & 01777); + pwrmem(vaddr, val, PM_CPU); + } } void -mm_wrpcr(void) +mm_wrpcr() { if (ISDIS()) return; PCR[(regA >> 3) & 017] = regA & 03603; } -void -mm_rdpcr(void) -{ - if (ISDIS()) - return; - regA = PCR[(regA >> 3) & 017]; -} - - t_stat mm_reset(DEVICE *dptr) { return 0; } + +/* + * Check if instruction is privileged enough to execute, + * otherwise give priv instruction fault. + */ +void +mm_privcheck(void) +{ + if (ISPON() == 0) + return; + if (userring > 1) + return; + intrpt14(IIE_PI, PM_CPU); +} diff --git a/ND100/nd100_stddev.c b/ND100/nd100_stddev.c index da80c28d..a1012b7d 100644 --- a/ND100/nd100_stddev.c +++ b/ND100/nd100_stddev.c @@ -54,6 +54,8 @@ t_stat tty_setpar(UNIT *uptr); #define TT_OCTRL_ACT 0000004 /* set device active */ #define TT_OSTAT_IRDY 0000001 /* device ready gives interrupt */ +#define TT_OSTAT_EINT 0000002 /* error interrupt enabled */ +#define TT_OSTAT_ACT 0000004 /* device active */ #define TT_OSTAT_RDY 0000010 /* device ready for transfer */ UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; @@ -147,6 +149,7 @@ tto_svc(UNIT *uptr) sim_activate (uptr, uptr->wait); /* try again */ return ((r == SCPE_STALL)? SCPE_OK : r);/* !stall? report */ } + tto_status &= ~TT_OSTAT_ACT; tto_status |= TT_OSTAT_RDY; if (tto_ctrl & TT_OCTRL_EIRDY) extint(10, &tto_int); @@ -193,6 +196,7 @@ iox_tty(int addr) case 5: /* Write data */ tto_unit.buf = regA & 0177; tto_status &= ~TT_OSTAT_RDY; + tto_status |= TT_OSTAT_ACT; sim_activate (&tto_unit, tto_unit.wait); break; @@ -201,15 +205,8 @@ iox_tty(int addr) break; case 7: /* Write output control reg */ - tto_ctrl = regA; - if (tto_ctrl & TT_OCTRL_ACT) - tto_status |= TT_OSTAT_RDY; - else - tto_status &= ~TT_OSTAT_RDY; - if (tto_ctrl & TT_OCTRL_EIRDY) - tto_status |= TT_OSTAT_IRDY; - else - tto_status &= ~TT_OSTAT_IRDY; + /* Only interrupts are controlled */ + tto_status = (tto_status & ~03) | (regA & 03); break; } diff --git a/ND100/nd100_sys.c b/ND100/nd100_sys.c index 50f58265..716d3238 100644 --- a/ND100/nd100_sys.c +++ b/ND100/nd100_sys.c @@ -30,7 +30,7 @@ char sim_name[] = "ND100"; extern REG cpu_reg[]; -REG *sim_PC = &cpu_reg[2]; +REG *sim_PC = &cpu_reg[8]; int32 sim_emax = 1; DEVICE *sim_devices[] = { @@ -50,6 +50,7 @@ const char *sim_stop_messages[SCPE_BASE] = { "Checksum error", "Simulator breakpoint", "Wait at level 0", + "manual end", }; static int mlp; @@ -60,7 +61,7 @@ gb(FILE *f) int w; if (f == NULL) - return rdmem(mlp++); + return prdmem(mlp++, PM_CPU); w = getc(f) & 0377; return w; } @@ -106,7 +107,7 @@ sim_load(FILE *f, CONST char *buf, CONST char *fnam, t_bool flag) /* images have MSB first */ s = (getc(f) & 0377) << 8; s |= getc(f) & 0377; - wrmem(i, s); + pwrmem(i, s, PM_CPU); } f = NULL; } @@ -133,8 +134,8 @@ sim_load(FILE *f, CONST char *buf, CONST char *fnam, t_bool flag) printf("Load address %06o\n", E = gw(f)); printf("Word count %06o\n", F = gw(f)); for (i = s = 0; i < F; i++) { - wrmem(E+i, gw(f)); - s += rdmem(E+i); + pwrmem(E+i, gw(f), PM_CPU); + s += prdmem(E+i, PM_CPU); } printf("Checksum %06o\n", H = gw(f)); if (H != s) @@ -180,6 +181,10 @@ static char *trrtab[] = { "cclr", "lcil", "ucil", "err13", "err14", "eccr", "err16", "err17" }; +static char *mitab[] = { + "ldatx", "ldxtx", "lddtx", "ldbtx", "statx", "stztx", "stdtx", "ERR" +}; + t_stat fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { @@ -330,6 +335,8 @@ fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) fprintf(of, "sbyt"); else if ((op & 0177707) == ND_SKP_EXR) fprintf(of, "exr %s", dactab[(op & 070) >> 3]); + else if ((op & 0177700) == ND_SKP_LDATX) + fprintf(of, "%s", mitab[op & 07]); else if ((op & 0177700) == ND_SKP_RMPY) fprintf(of, "rmpy %s %s", dactab[(op & 070) >> 3], dactab[op & 07]);