1
0
mirror of https://github.com/simh/simh.git synced 2026-05-05 23:34:21 +00:00

Notes For V3.2-1

RESTRICTION: The PDP-15 FPP is only partially debugged.  Do NOT
enable this feature for normal operations.

1. New Features in 3.2-1

1.1 SCP and libraries

- Added SET CONSOLE subhierarchy.
- Added SHOW CONSOLE subhierarchy.
- Added limited keyboard mapping capability.

1.2 HP2100 (new features from Dave Bryan)

- Added instruction printout to HALT message.
- Added M and T internal registers.
- Added N, S, and U breakpoints.

1.3 PDP-11 and VAX

- Added DHQ11 support (from John Dundas)

2. Bugs Fixed in 3.2-1

2.1 HP2100 (most fixes from Dave Bryan)

- SBT increments B after store.
- DMS console map must check dms_enb.
- SFS x,C and SFC x,C work.
- MP violation clears automatically on interrupt.
- SFS/SFC 5 is not gated by protection enabled.
- DMS enable does not disable mem prot checks.
- DMS status inconsistent at simulator halt.
- Examine/deposit are checking wrong addresses.
- Physical addresses are 20b not 15b.
- Revised DMS to use memory rather than internal format.
- Revised IBL facility to conform to microcode.
- Added DMA EDT I/O pseudo-opcode.
- Separated DMA SRQ (service request) from FLG.
- Revised peripherals to make SFS x,C and SFC x,C work.
- Revised boot ROMs to use IBL facility.
- Revised IBL treatment of SR to preserve SR<5:3>.
- Fixed LPS, LPT timing.
- Fixed DP boot interpretation of SR<0>.
- Revised DR boot code to use IBL algorithm.
- Fixed TTY input behavior during typeout for RTE-IV.
- Suppressed nulls on TTY output for RTE-IV.
- Added SFS x,C and SFC x,C to print/parse routines.
- Fixed spurious timing error in magtape reads.

2.2 All DEC console devices

- Removed SET TTI CTRL-C option.

2.3 PDP-11/VAX peripherals

- Fixed bug in TQ reporting write protect status (reported by Lyle Bickley).
- Fixed TK70 model number and media ID (found by Robert Schaffrath).
- Fixed bug in autoconfigure (found by John Dundas).

2.4 VAX

- Fixed bug in DIVBx and DIVWx (reported by Peter Trimmel).
This commit is contained in:
Bob Supnik
2004-07-10 06:13:00 -07:00
committed by Mark Pizzolato
parent 26aa6de663
commit e2ba672610
75 changed files with 14174 additions and 2343 deletions

View File

@@ -23,6 +23,23 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
14-May-04 RMS Fixed bugs and added features from Dave Bryan
- SBT increments B after store
- DMS console map must check dms_enb
- SFS x,C and SFC x,C work
- MP violation clears automatically on interrupt
- SFS/SFC 5 is not gated by protection enabled
- DMS enable does not disable mem prot checks
- DMS status inconsistent at simulator halt
- Examine/deposit are checking wrong addresses
- Physical addresses are 20b not 15b
- Revised DMS to use memory rather than internal format
- Added instruction printout to HALT message
- Added M and T internal registers
- Added N, S, and U breakpoints
Revised IBL facility to conform to microcode
Added DMA EDT I/O pseudo-opcode
Separated DMA SRQ (service request) from FLG
12-Mar-03 RMS Added logical name support
02-Feb-03 RMS Fixed last cycle bug in DMA output (found by Mike Gemeny)
22-Nov-02 RMS Added 21MX IOP support
@@ -55,6 +72,8 @@
BR<15:0> B register - addressable as location 1
PC<14:0> P register (program counter)
SR<15:0> S register
MR<14:0> M register - memory address
TR<15:0> T register - memory data
E extend flag (carry out)
O overflow flag
@@ -232,12 +251,13 @@
unknown I/O device and stop_dev flag set
I/O error in I/O simulator
2. Interrupts. I/O devices are modelled as four parallel arrays:
2. Interrupts. I/O devices are modelled as five parallel arrays:
device commands as bit array dev_cmd[2][31..0]
device flags as bit array dev_flg[2][31..0]
device flag buffers as bit array dev_fbf[2][31..0]
device controls as bit array dev_ctl[2][31..0]
device service requests as bit array dev_srq[3][31..0]
The HP 2100 interrupt structure is based on flag, flag buffer,.
and control. If a device flag is set, the flag buffer is set,
@@ -251,6 +271,8 @@
tells whether a device is active. It is set by STC and cleared
by CLC; it is also cleared when the device flag is set. Simple
devices don't need to track command separately from control.
Service requests are used to trigger the DMA service logic.
3. Non-existent memory. On the HP 2100, reads to non-existent memory
return zero, and writes are ignored. In the simulator, the
@@ -308,11 +330,15 @@
#define DMAR0 1
#define DMAR1 2
#define ALL_BKPTS (SWMASK('E')|SWMASK('N')|SWMASK('S')|SWMASK('U'))
uint16 *M = NULL; /* memory */
uint32 saved_AR = 0; /* A register */
uint32 saved_BR = 0; /* B register */
uint32 PC = 0; /* P register */
uint32 SR = 0; /* S register */
uint32 MR = 0; /* M register */
uint32 TR = 0; /* T register */
uint32 XR = 0; /* X register */
uint32 YR = 0; /* Y register */
uint32 E = 0; /* E register */
@@ -321,6 +347,7 @@ uint32 dev_cmd[2] = { 0 }; /* device command */
uint32 dev_ctl[2] = { 0 }; /* device control */
uint32 dev_flg[2] = { 0 }; /* device flags */
uint32 dev_fbf[2] = { 0 }; /* device flag bufs */
uint32 dev_srq[2] = { 0 }; /* device svc reqs */
struct DMA dmac[2] = { { 0 }, { 0 } }; /* DMA channels */
uint32 ion = 0; /* interrupt enable */
uint32 ion_defer = 0; /* interrupt defer */
@@ -334,7 +361,7 @@ uint32 dms_enb = 0; /* dms enable */
uint32 dms_ump = 0; /* dms user map */
uint32 dms_sr = 0; /* dms status reg */
uint32 dms_vr = 0; /* dms violation reg */
uint32 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */
uint16 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */
uint32 iop_sp = 0; /* iop stack */
uint32 ind_max = 16; /* iadr nest limit */
uint32 stop_inst = 1; /* stop on ill inst */
@@ -361,6 +388,7 @@ extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern FILE *sim_log;
extern DEVICE *sim_devices[];
extern char halt_msg[];
t_stat Ea (uint32 IR, uint32 *addr, uint32 irq);
t_stat Ea1 (uint32 *addr, uint32 irq);
@@ -390,6 +418,7 @@ void dma_cycle (uint32 chan, uint32 map);
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_boot (int32 unitno, DEVICE *dptr);
t_stat dma0_reset (DEVICE *dptr);
t_stat dma1_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
@@ -417,18 +446,20 @@ REG cpu_reg[] = {
{ ORDATA (P, PC, 15) },
{ ORDATA (A, saved_AR, 16) },
{ ORDATA (B, saved_BR, 16) },
{ ORDATA (M, MR, 15) },
{ ORDATA (T, TR, 16), REG_RO },
{ ORDATA (X, XR, 16) },
{ ORDATA (Y, YR, 16) },
{ ORDATA (S, SR, 16) },
{ ORDATA (F, mp_fence, 15) },
{ FLDATA (E, E, 0) },
{ FLDATA (O, O, 0) },
{ FLDATA (ION, ion, 0) },
{ FLDATA (ION_DEFER, ion_defer, 0) },
{ ORDATA (IADDR, intaddr, 6) },
{ ORDATA (CIR, intaddr, 6) },
{ FLDATA (MPCTL, dev_ctl[PRO/32], INT_V (PRO)) },
{ FLDATA (MPFLG, dev_flg[PRO/32], INT_V (PRO)) },
{ FLDATA (MPFBF, dev_fbf[PRO/32], INT_V (PRO)) },
{ ORDATA (MPFR, mp_fence, 15) },
{ ORDATA (MPVR, mp_viol, 16) },
{ FLDATA (MPMEV, mp_mevff, 0) },
{ FLDATA (MPEVR, mp_evrff, 0) },
@@ -436,7 +467,7 @@ REG cpu_reg[] = {
{ FLDATA (DMSCUR, dms_ump, VA_N_PAG) },
{ ORDATA (DMSSR, dms_sr, 16) },
{ ORDATA (DMSVR, dms_vr, 16) },
{ BRDATA (DMSMAP, dms_map, 8, PA_N_SIZE, MAP_NUM * MAP_LNT) },
{ BRDATA (DMSMAP, dms_map, 8, 16, MAP_NUM * MAP_LNT) },
{ ORDATA (IOPSP, iop_sp, 16) },
{ FLDATA (STOP_INST, stop_inst, 0) },
{ FLDATA (STOP_DEV, stop_dev, 1) },
@@ -452,6 +483,8 @@ REG cpu_reg[] = {
{ ORDATA (LFLG, dev_flg[1], 32), REG_HRO },
{ ORDATA (HFBF, dev_fbf[0], 32), REG_HRO },
{ ORDATA (LFBF, dev_fbf[1], 32), REG_HRO },
{ ORDATA (HSRQ, dev_srq[0], 32), REG_HRO },
{ ORDATA (LSRQ, dev_srq[1], 32), REG_HRO },
{ NULL } };
MTAB cpu_mod[] = {
@@ -499,9 +532,9 @@ MTAB cpu_mod[] = {
DEVICE cpu_dev = {
"CPU", &cpu_unit, cpu_reg, cpu_mod,
1, 8, 15, 1, 8, 16,
1, 8, PA_N_SIZE, 1, 8, 16,
&cpu_ex, &cpu_dep, &cpu_reset,
NULL, NULL, NULL };
&cpu_boot, NULL, NULL };
/* DMA controller data structures
@@ -663,6 +696,7 @@ int32 (*dtab[64])() = {
t_stat sim_instr (void)
{
uint32 intrq, dmarq; /* set after setjmp */
uint32 iotrap = 0; /* set after setjmp */
t_stat reason; /* set after setjmp */
int32 i, dev; /* temp */
DEVICE *dptr; /* temp */
@@ -684,6 +718,7 @@ dev_cmd[0] = dev_cmd[0] & M_FXDEV; /* clear dynamic info */
dev_ctl[0] = dev_ctl[0] & M_FXDEV;
dev_flg[0] = dev_flg[0] & M_FXDEV;
dev_fbf[0] = dev_fbf[0] & M_FXDEV;
dev_srq[0] = dev_srq[1] = 0; /* init svc requests */
dev_cmd[1] = dev_ctl[1] = dev_flg[1] = dev_fbf[1] = 0;
for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */
@@ -694,6 +729,7 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */
if (dibp->flg) { setFLG (dev); } /* restore flg */
clrFBF (dev); /* also sets fbf */
if (dibp->fbf) { setFBF (dev); } /* restore fbf */
if (dibp->srq) { setSRQ (dev); } /* restore srq */
dtab[dev] = dibp->iot; } } /* set I/O dispatch */
sim_rtc_init (clk_delay (0)); /* recalibrate clock */
@@ -719,7 +755,7 @@ while (reason == 0) { /* loop until halted */
uint32 IR, MA, M1, absel, v1, v2, t;
uint32 fop, eop, etype, eflag;
uint32 skip, mapi, mapj, qs, rs;
uint32 awc, sc, wc, hp, tp, iotrap;
uint32 awc, sc, wc, hp, tp;
int32 sop1, sop2;
if (sim_interval <= 0) { /* check clock queue */
@@ -733,9 +769,21 @@ if (dmarq) {
dmarq = calc_dma (); /* recalc DMA reqs */
intrq = calc_int (); } /* recalc interrupts */
/* (From Dave Bryan)
Unlike most other I/O devices, the MP flag flip-flop is cleared
automatically when the interrupt is acknowledged and not by a programmed
instruction (CLF and STF affect the parity error enable FF instead).
Section 4.4.3 "Memory Protect and I/O Interrupt Generation" of the "HP 1000
M/E/F-Series Computers Engineering and Reference Documentation" (HP
92851-90001) says:
"When IAK occurs and IRQ5 is asserted, the FLAGBFF is cleared, FLAGFF
clocked off at next T2, and IRQ5 will no longer occur." */
if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */
iotrap = 1; /* I/O trap cell instr */
clrFBF (intrq); /* clear flag buffer */
if (intrq == PRO) clrFLG (PRO); /* MP flag follows flag buffer */
intaddr = intrq; /* save int addr */
if (dms_enb) dms_sr = dms_sr | MST_ENBI; /* dms enabled? */
else dms_sr = dms_sr & ~MST_ENBI;
@@ -752,8 +800,12 @@ if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */
else { iotrap = 0; /* normal instruction */
err_PC = PC; /* save PC for error */
if (sim_brk_summ &&
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
if (sim_brk_summ && /* any breakpoints? */
sim_brk_test (PC, ALL_BKPTS) && /* at this location? */
(sim_brk_test (PC, SWMASK ('E')) || /* unconditional? */
sim_brk_test (PC, dms_enb? /* or right type for DMS? */
(dms_ump? SWMASK ('U'): SWMASK ('S')):
SWMASK ('N')))) {
reason = STOP_IBKPT; /* stop simulation */
break; }
if (mp_evrff) mp_viol = PC; /* if ok, upd mp_viol */
@@ -1200,19 +1252,23 @@ case 0203:case 0213: /* MAC1 ext */
break;
case 0221: /* IOP PRFIO (I_NO) */
case 0473: /* IOPX PFRIO (I_NO) */
IR = ReadW (PC); /* get IO instr */
t = ReadW (PC); /* get IO instr */
PC = (PC + 1) & VAMASK;
WriteW (PC, 1); /* set flag */
PC = (PC + 1) & VAMASK;
reason = iogrp (IR, 0); /* execute instr */
reason = iogrp (t, 0); /* execute instr */
dmarq = calc_dma (); /* recalc DMA */
intrq = calc_int (); /* recalc interrupts */
break;
case 0222: /* IOP PRFEI (I_NO) */
case 0471: /* IOPX PFREI (I_NO) */
IR = ReadW (PC); /* get IO instr */
t = ReadW (PC); /* get IO instr */
PC = (PC + 1) & VAMASK;
WriteW (PC, 1); /* set flag */
PC = (PC + 1) & VAMASK;
reason = iogrp (IR, 0); /* execute instr */
reason = iogrp (t, 0); /* execute instr */
dmarq = calc_dma (); /* recalc DMA */
intrq = calc_int (); /* recalc interrupts */
/* fall through */
case 0223: /* IOP PRFEX (I_NO) */
case 0472: /* IOPX PFREX (I_NO) */
@@ -1655,6 +1711,7 @@ case 0203:case 0213: /* MAC1 ext */
break;
case 0764: /* SBT (E_NO) */
WriteB (BR, AR); /* store byte */
BR = (BR + 1) & DMASK; /* incr ptr */
break;
IOP_MBYTE: /* IOP MBYTE (I_AZ) */
if (wc & SIGN) break; /* must be positive */
@@ -1763,8 +1820,12 @@ if (reason == STOP_INDINT) { /* indirect intr? */
/* Simulation halted */
if (iotrap && (reason == STOP_HALT)) MR = intaddr; /* HLT in trap cell? */
else MR = (PC - 1) & VAMASK; /* no, M = P - 1 */
TR = ReadIO (MR, dms_ump); /* last word fetched */
saved_AR = AR & DMASK;
saved_BR = BR & DMASK;
dms_upd_sr (); /* update dms_sr */
for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp) { /* exist? */
@@ -1772,7 +1833,8 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */
dibp->cmd = CMD (dev);
dibp->ctl = CTL (dev);
dibp->flg = FLG (dev);
dibp->fbf = FBF (dev); } }
dibp->fbf = FBF (dev);
dibp->srq = SRQ (dev); } }
pcq_r->qptr = pcq_p; /* update pc q ptr */
return reason;
}
@@ -1865,7 +1927,10 @@ iodata = devdisp (dev, sop, ir, ABREG[ab]); /* process I/O */
ion_defer = defer_tab[sop]; /* set defer */
if ((sop == ioMIX) || (sop == ioLIX)) /* store ret data */
ABREG[ab] = iodata & DMASK;
if (sop == ioHLT) return STOP_HALT; /* halt? */
if (sop == ioHLT) { /* halt? */
int32 len = strlen (halt_msg); /* find end msg */
sprintf (&halt_msg[len - 6], "%06o", ir); /* add the halt */
return STOP_HALT; }
return (iodata >> IOT_V_REASON); /* return status */
}
@@ -1883,9 +1948,9 @@ uint32 calc_dma (void)
{
uint32 r = 0;
if (CMD (DMA0) && FLG (dmac[0].cw1 & I_DEVMASK)) /* check DMA0 cycle */
if (CMD (DMA0) && SRQ (dmac[0].cw1 & I_DEVMASK)) /* check DMA0 cycle */
r = r | DMAR0;
if (CMD (DMA1) && FLG (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */
if (CMD (DMA1) && SRQ (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */
r = r | DMAR1;
return r;
}
@@ -1994,7 +2059,14 @@ else pa = va;
return M[pa];
}
/* Memory protection test for writes */
/* Memory protection test for writes
From Dave Bryan: The problem is that memory writes aren't being checked for
an MP violation if DMS is enabled, i.e., if DMS is enabled, and the page is
writable, then whether the target is below the MP fence is not checked. [The
simulator must] do MP check on all writes after DMS translation and violation
checks are done (so, to pass, the page must be writable AND the target must
be above the MP fence). */
#define MP_TEST(x) (CTL (PRO) && ((x) > 1) && ((x) < mp_fence))
@@ -2003,8 +2075,8 @@ void WriteB (uint32 va, uint32 dat)
uint32 pa;
if (dms_enb) pa = dms (va >> 1, dms_ump, WR);
else { if (MP_TEST (va >> 1)) ABORT (ABORT_PRO);
pa = va >> 1; }
else pa = va >> 1;
if (MP_TEST (va >> 1)) ABORT (ABORT_PRO);
if (MEM_ADDR_OK (pa)) {
if (va & 1) M[pa] = (M[pa] & 0177400) | (dat & 0377);
else M[pa] = (M[pa] & 0377) | ((dat & 0377) << 8); }
@@ -2018,8 +2090,8 @@ uint32 pa;
if (dms_enb) {
dms_viol (va >> 1, MVI_WPR); /* viol if prot */
pa = dms (va >> 1, dms_ump ^ MAP_LNT, WR); }
else { if (MP_TEST (va >> 1)) ABORT (ABORT_PRO);
pa = va >> 1; }
else pa = va >> 1;
if (MP_TEST (va >> 1)) ABORT (ABORT_PRO);
if (MEM_ADDR_OK (pa)) {
if (va & 1) M[pa] = (M[pa] & 0177400) | (dat & 0377);
else M[pa] = (M[pa] & 0377) | ((dat & 0377) << 8); }
@@ -2031,8 +2103,8 @@ void WriteW (uint32 va, uint32 dat)
uint32 pa;
if (dms_enb) pa = dms (va, dms_ump, WR);
else { if (MP_TEST (va)) ABORT (ABORT_PRO);
pa = va; }
else pa = va;
if (MP_TEST (va)) ABORT (ABORT_PRO);
if (MEM_ADDR_OK (pa)) M[pa] = dat;
return;
}
@@ -2044,8 +2116,8 @@ int32 pa;
if (dms_enb) {
dms_viol (va, MVI_WPR); /* viol if prot */
pa = dms (va, dms_ump ^ MAP_LNT, WR); }
else { if (MP_TEST (va)) ABORT (ABORT_PRO);
pa = va; }
else pa = va;
if (MP_TEST (va)) ABORT (ABORT_PRO);
if (MEM_ADDR_OK (pa)) M[pa] = dat;
return;
}
@@ -2076,8 +2148,8 @@ if (pgn == 0) { /* base page? */
if (prot == WR) dms_viol (va, MVI_BPG); /* if W, viol */
return va; } } /* no mapping */
mpr = dms_map[map + pgn]; /* get map reg */
if (mpr & prot) dms_viol (va, prot << (MVI_V_WPR - MAPA_V_WPR));
return (PA_GETPAG (mpr) | VA_GETOFF (va));
if (mpr & prot) dms_viol (va, prot); /* prot violation? */
return (MAP_GETPAG (mpr) | VA_GETOFF (va));
}
/* DMS relocation for IO access */
@@ -2095,19 +2167,24 @@ if (pgn == 0) { /* base page? */
(va < dms_fence)) { /* 0B10: < fence */
return va; } } /* no mapping */
mpr = dms_map[map + pgn]; /* get map reg */
return (PA_GETPAG (mpr) | VA_GETOFF (va));
return (MAP_GETPAG (mpr) | VA_GETOFF (va));
}
/* DMS relocation for console access */
uint32 dms_cons (uint32 va, int32 sw)
{
if (sw & SWMASK ("V")) return dms_io (va, dms_ump);
if (sw & SWMASK ("S")) return dms_io (va, SMAP);
if (sw & SWMASK ("U")) return dms_io (va, UMAP);
if (sw & SWMASK ("P")) return dms_io (va, PAMAP);
if (sw & SWMASK ("Q")) return dms_io (va, PBMAP);
return va;
uint32 map_sel;
if (sw & SWMASK ('V')) map_sel = dms_ump; /* switch? select map */
else if (sw & SWMASK ('S')) map_sel = SMAP;
else if (sw & SWMASK ('U')) map_sel = UMAP;
else if (sw & SWMASK ('P')) map_sel = PAMAP;
else if (sw & SWMASK ('Q')) map_sel = PBMAP;
else return va; /* no switch, physical */
if (va >= VASIZE) return MEMSIZE; /* virtual, must be 15b */
else if (dms_enb) return dms_io (va, map_sel); /* DMS on? go thru map */
else return va; /* else return virtual */
}
/* Mem protect and DMS validation for jumps */
@@ -2131,19 +2208,14 @@ return;
uint16 dms_rmap (uint32 mapi)
{
int32 t;
mapi = mapi & MAP_MASK;
t = (((dms_map[mapi] >> VA_N_OFF) & PA_M_PAG) |
((dms_map[mapi] & (RD | WR)) << (MAPM_V_WPR - MAPA_V_WPR)));
return (uint16) t;
return (dms_map[mapi] & ~MAP_MBZ);
}
void dms_wmap (uint32 mapi, uint32 dat)
{
mapi = mapi & MAP_MASK;
dms_map[mapi] = ((dat & PA_M_PAG) << VA_N_OFF) |
((dat >> (MAPM_V_WPR - MAPA_V_WPR)) & (RD | WR));
dms_map[mapi] = (uint16) (dat & ~MAP_MBZ);
return;
}
@@ -2172,7 +2244,24 @@ if (CTL (PRO)) dms_sr = dms_sr | MST_PRO;
return dms_sr;
}
/* Device 0 (CPU) I/O routine */
/* Device 0 (CPU) I/O routine
From Dave Bryan: RTE uses the undocumented instruction "SFS 0,C" to both test
and turn off the interrupt system. This is confirmed in the "RTE-6/VM
Technical Specifications" manual (HP 92084-90015), section 2.3.1 "Process
the Interrupt", subsection "A.1 $CIC":
"Test to see if the interrupt system is on or off. This is done with the
SFS 0,C instruction. In either case, turn it off (the ,C does it)."
...and in section 5.8, "Parity Error Detection":
"Because parity error interrupts can occur even when the interrupt system
is off, the code at $CIC must be able to save the complete system status.
The major hole in being able to save the complete state is in saving the
interrupt system state. In order to do this in both the 21MX and the 21XE
the instruction 103300 was used to both test the interrupt system and
turn it off." */
int32 cpuio (int32 inst, int32 IR, int32 dat)
{
@@ -2184,10 +2273,10 @@ case ioFLG: /* flag */
return dat;
case ioSFC: /* skip flag clear */
if (!ion) PC = (PC + 1) & VAMASK;
return dat;
break;
case ioSFS: /* skip flag set */
if (ion) PC = (PC + 1) & VAMASK;
return dat;
break;
case ioLIX: /* load */
dat = 0; /* returns 0 */
break;
@@ -2249,7 +2338,11 @@ default:
return dat;
}
/* Device 5 (memory protect) I/O routine */
/* Device 5 (memory protect) I/O routine
From Dave Bryan: Examination of the schematics for the MP card in the
engineering documentation shows that the SFS and SFC I/O backplane signals
gate the output of the MEVFF onto the SKF line unconditionally. */
int32 proio (int32 inst, int32 IR, int32 dat)
{
@@ -2257,13 +2350,11 @@ if ((cpu_unit.flags & UNIT_MPR) == 0) /* not installed? */
return nulio (inst, IR, dat); /* non-existent dev */
switch (inst) { /* case on opcode */
case ioSFC: /* skip flag clear */
if (FLG (PRO) && !mp_mevff) /* skip if mem prot */
PC = (PC + 1) & VAMASK;
return dat;
if (!mp_mevff) PC = (PC + 1) & VAMASK; /* skip if mem prot */
break;
case ioSFS: /* skip flag set */
if (FLG (PRO) && mp_mevff) /* skip if DMS */
PC = (PC + 1) & VAMASK;
return dat;
if (mp_mevff) PC = (PC + 1) & VAMASK; /* skip if DMS */
break;
case ioMIX: /* merge */
dat = dat | mp_viol;
break;
@@ -2329,10 +2420,10 @@ case ioFLG: /* flag */
break;
case ioSFC: /* skip flag clear */
if (FLG (DMA0 + ch) == 0) PC = (PC + 1) & VAMASK;
return dat;
break;
case ioSFS: /* skip flag set */
if (FLG (DMA0 + ch) != 0) PC = (PC + 1) & VAMASK;
return dat;
break;
case ioMIX: case ioLIX: /* load, merge */
dat = DMASK;
break;
@@ -2358,9 +2449,10 @@ return dat;
- CLC requested: issue CLC
Output cases:
- neither STC nor CLC requested: issue CLF
- CLC requested but not STC: issue CLC,C
- STC requested but not CLC: issue STC,C
- STC and CLC both requested: issue STC,C and CLC,C
- CLC requested but not STC: issue CLC,C
- STC and CLC both requested: issue STC,C and CLC,C, in that order
Either: issue EDT
*/
void dma_cycle (uint32 ch, uint32 map)
@@ -2380,20 +2472,24 @@ dmac[ch].cw3 = (dmac[ch].cw3 + 1) & DMASK; /* incr wcount */
if (dmac[ch].cw3) { /* more to do? */
if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */
devdisp (dev, ioCTL, I_HC + dev, 0); /* do STC,C dev */
else devdisp (dev, ioFLG, I_HC + dev, 0); } /* else CLF dev */
else devdisp (dev, ioFLG, I_HC + dev, 0); /* else CLF dev */
}
else { if (inp) { /* last cycle, input? */
if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */
devdisp (dev, ioCTL, I_CTL + dev, 0); /* yes */
} /* end input */
else { /* output */
devdisp (dev, ioFLG, I_HC + dev, 0); /* clear flag */
if ((dmac[ch].cw1 & (DMA1_STC | DMA1_CLC)) == 0)
devdisp (dev, ioFLG, I_HC + dev, 0); /* clear flag */
if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */
devdisp (dev, ioCTL, dev, 0); /* do STC dev */
devdisp (dev, ioCTL, I_HC + dev, 0); /* do STC,C dev */
if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */
devdisp (dev, ioCTL, I_CTL + dev, 0); /* yes */
devdisp (dev, ioCTL, I_HC + I_CTL + dev, 0); /* yes */
} /* end output */
setFLG (DMA0 + ch); /* set DMA flg */
clrCMD (DMA0 + ch); } /* clr DMA cmd */
clrCMD (DMA0 + ch); /* clr DMA cmd */
devdisp (dev, ioEDT, dev, 0); /* do EDT */
}
return;
}
@@ -2428,6 +2524,7 @@ clrCMD (PRO);
clrCTL (PRO);
clrFLG (PRO);
clrFBF (PRO);
dev_srq[0] = dev_srq[0] & ~M_FXDEV;
mp_fence = 0; /* init mprot */
mp_viol = 0;
mp_mevff = 0;
@@ -2436,7 +2533,8 @@ dms_enb = dms_ump = 0; /* init DMS */
dms_sr = 0;
dms_vr = 0;
pcq_r = find_reg ("PCQ", NULL, dptr);
sim_brk_types = sim_brk_dflt = SWMASK ('E');
sim_brk_types = ALL_BKPTS;
sim_brk_dflt = SWMASK ('E');
if (M == NULL) M = calloc (PASIZE, sizeof (unsigned int16));
if (M == NULL) return SCPE_MEM;
if (pcq_r) pcq_r->qptr = 0;
@@ -2449,6 +2547,7 @@ t_stat dma0_reset (DEVICE *tptr)
clrCMD (DMA0);
clrCTL (DMA0);
setFLG (DMA0);
clrSRQ (DMA0);
dmac[0].cw1 = dmac[0].cw2 = dmac[0].cw3 = 0;
return SCPE_OK;
}
@@ -2458,6 +2557,7 @@ t_stat dma1_reset (DEVICE *tptr)
clrCMD (DMA1);
clrCTL (DMA1);
setFLG (DMA1);
clrSRQ (DMA1);
dmac[1].cw1 = dmac[1].cw2 = dmac[1].cw3 = 0;
return SCPE_OK;
}
@@ -2468,8 +2568,8 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
int32 d;
if (addr >= MEMSIZE) return SCPE_NXM;
addr = dms_cons (addr, sw);
if (addr >= MEMSIZE) return SCPE_NXM;
if (addr == 0) d = saved_AR;
else if (addr == 1) d = saved_BR;
else d = M[addr];
@@ -2481,8 +2581,8 @@ return SCPE_OK;
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= MEMSIZE) return SCPE_NXM;
addr = dms_cons (addr, sw);
if (addr >= MEMSIZE) return SCPE_NXM;
if (addr == 0) saved_AR = val & DMASK;
else if (addr == 1) saved_BR = val & DMASK;
else M[addr] = val & DMASK;
@@ -2558,7 +2658,7 @@ t_bool dev_conflict (void)
{
DEVICE *dptr, *cdptr;
DIB *dibp, *chkp;
int32 i, j, dno;
uint32 i, j, dno;
for (i = 0; cdptr = sim_devices[i]; i++) {
chkp = (DIB *) cdptr->ctxt;
@@ -2599,4 +2699,59 @@ for (i = 0; opt_val[i].optf != 0; i++) {
return SCPE_OK; } }
return SCPE_NOFNC;
}
/* IBL routine (CPU boot) */
t_stat cpu_boot (int32 unitno, DEVICE *dptr)
{
extern const uint16 ptr_rom[IBL_LNT], dq_rom[IBL_LNT], ms_rom[IBL_LNT];
int32 dev = (SR >> IBL_V_DEV) & I_DEVMASK;
int32 sel = (SR >> IBL_V_SEL) & IBL_M_SEL;
if (dev < 010) return SCPE_NOFNC;
switch (sel) {
case 0: /* PTR boot */
ibl_copy (ptr_rom, dev);
break;
case 1: /* DP/DQ boot */
ibl_copy (dq_rom, dev);
break;
case 2: /* MS boot */
ibl_copy (ms_rom, dev);
break;
default:
return SCPE_NOFNC; }
return SCPE_OK;
}
/* IBL boot ROM copy
- Use memory size to set the initial PC and base of the boot area
- Copy boot ROM to memory, updating I/O instructions
- Place 2's complement of boot base in last location
Notes:
- SR settings are done by the caller
- Boot ROM's must be assembled with a device code of 10 (10 and 11 for
devices requiring two codes)
*/
t_stat ibl_copy (const uint16 pboot[IBL_LNT], int32 dev)
{
int32 i;
uint16 wd;
if (dev < 010) return SCPE_ARG; /* valid device? */
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */
wd = pboot[i]; /* get word */
if (((wd & I_NMRMASK) == I_IO) && /* IO instruction? */
((wd & I_DEVMASK) >= 010) && /* dev >= 10? */
(I_GETIOOP (wd) != ioHLT)) /* not a HALT? */
M[PC + i] = (wd + (dev - 010)) & DMASK; /* change dev code */
else M[PC + i] = wd; } /* leave unchanged */
M[PC + IBL_DPC] = (M[PC + IBL_DPC] + (dev - 010)) & DMASK; /* patch DMA ctrl */
M[PC + IBL_END] = (~PC + 1) & DMASK; /* fill in start of boot */
return SCPE_OK;
}