1
0
mirror of https://github.com/simh/simh.git synced 2026-01-11 23:52:58 +00:00

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.
This commit is contained in:
Anders Magnusson 2023-05-14 21:46:21 +02:00 committed by Mark Pizzolato
parent d57c67c4f5
commit 22e33dd3d4
6 changed files with 718 additions and 258 deletions

View File

@ -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;
}

View File

@ -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)

View File

@ -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;

View File

@ -23,12 +23,61 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <setjmp.h>
#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)
}
}
uint16
rdmem(int vaddr/* , int how*/)
/*
* MOR - memory out of range. Addressing non-existent memory.
*/
void
morerr(int addr, int why, int pesval)
{
int pt;
vaddr &= 0177777;
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;
if (pea_locked == 0) {
pea = (uint16)addr;
pes = (uint16)(addr >> 16) | pesval;
pea_locked = 1;
}
intrpt14(IIE_MOR, why);
}
// if (ISPON() == 0)
return PM[vaddr];
/*
* 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)
{
uint16 *ptmapp;
int sh, pagetablenr, pagering, pagenr, permit, p;
vaddr &= 0177777; /* Sanity */
/* Shadow memory? */
if ((vaddr >= 0177000) && is_shadow(vaddr))
return shadowrd(vaddr);
/* 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;
}
/*
* 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);
}

View File

@ -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;
}

View File

@ -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]);