PDP11: numerous 11/70 compatibility fixes

This commit is contained in:
Bob Supnik 2022-12-12 12:00:00 -05:00 committed by Paul Koning
parent 8e13ea1d21
commit 86a995b863
7 changed files with 139 additions and 66 deletions

View file

@ -25,6 +25,20 @@
cpu PDP-11 CPU
30-Nov022 RMS More 11/45,11/70 trap hackery (Walter Mueller)
29-Nov-22 RMS Trap stack abort must clear other traps/aborts (Walter Mueller)
23-Oct-22 RMS Fixed priority of MME traps (Walter Mueller)
02-Sep-22 RMS Fixed handling of PDR<A> (Walter Mueller)
31-Aug-22 RMS MMR0<15:13> != 0 locks bits<15:13> (Walter Mueller)
MMR0<12> = 1 disables further traps (Walter Mueller)
25-Aug-22 RMS 11/45,70 clear MMR1 in trap sequence (Walter Mueller)
23-Aug-22 RMS 11/45,70 detect red stack abort before memory write
in JSR, MFPx (Walter Mueller)
20-Aug-22 RMS MMR1 reads as 0 on subset memory mmgt systems
11/44, 45, 70 track PC changes (Walter Mueller)
J11 tracks PC changes on -(PC) and @-(PC)
25-Jul-22 RMS Removed deprecated CPU models (Q22, UHR11, URH70)
04-Jun-18 RMS Removed CPU model entries for UC15 (Mark Pizzolato)
04-Dec-16 RMS Removed duplicate IDLE entries in MTAB
30-Aug-16 RMS Fixed overloading of -d in ex/mod
14-Mar-16 RMS Added UC15 support
@ -373,22 +387,35 @@ extern int32 get_vector (int32 nipl);
/* Trap data structures */
int32 trap_vec[TRAP_V_MAX] = { /* trap req to vector */
VEC_RED, VEC_ODD, VEC_MME, VEC_NXM,
VEC_RED, VEC_ODD, VEC_NXM, VEC_MME,
VEC_PAR, VEC_PRV, VEC_ILL, VEC_BPT,
VEC_IOT, VEC_EMT, VEC_TRAP, VEC_TRC,
VEC_YEL, VEC_PWRFL, VEC_FPE
};
t_bool trap_load_mmr2[TRAP_V_MAX + 1] = { /* do trap requests load MMR2? */
TRUE, TRUE, TRUE, TRUE,
TRUE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, TRUE,
TRUE, TRUE, TRUE, TRUE /* last is interrupt */
};
int32 trap_clear[TRAP_V_MAX] = { /* trap clears */
TRAP_RED+TRAP_PAR+TRAP_YEL+TRAP_TRC+TRAP_ODD+TRAP_NXM,
TRAP_ODD+TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_MME+TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_NXM+TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_PAR+TRAP_TRC, TRAP_PRV+TRAP_TRC,
TRAP_ILL+TRAP_TRC, TRAP_BPT+TRAP_TRC,
TRAP_IOT+TRAP_TRC, TRAP_EMT+TRAP_TRC,
TRAP_TRAP+TRAP_TRC, TRAP_TRC,
TRAP_YEL, TRAP_PWRFL, TRAP_FPE
TRAP_RED+TRAP_ODD+TRAP_NXM+TRAP_PAR+TRAP_YEL+TRAP_TRC+TRAP_MME, /* red stack abort */
TRAP_ODD+TRAP_NXM+TRAP_PAR+TRAP_YEL+TRAP_TRC+TRAP_MME, /* odd address abort */
TRAP_NXM+TRAP_PAR+TRAP_YEL+TRAP_TRC+TRAP_MME, /* nxm abort */
TRAP_MME+TRAP_PAR+TRAP_YEL+TRAP_TRC, /* mme abort or trap */
TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_PRV+TRAP_TRC, /* instruction traps */
TRAP_ILL+TRAP_TRC, /* occur in fetch or */
TRAP_BPT+TRAP_TRC, /* initial decode */
TRAP_IOT+TRAP_TRC, /* no yelstk possible */
TRAP_EMT+TRAP_TRC,
TRAP_TRAP+TRAP_TRC,
TRAP_TRC,
TRAP_YEL,
TRAP_PWRFL,
TRAP_FPE
};
/* CPU data structures
@ -729,7 +756,7 @@ isenable = calc_is (cm);
dsenable = calc_ds (cm);
put_PIRQ (PIRQ); /* rewrite PIRQ */
STKLIM = STKLIM & STKLIM_RW; /* clean up STKLIM */
MMR0 = MMR0 | MMR0_IC; /* usually on */
MMR0 = MMR0 & ~MMR0_IC; /* usually off */
trap_req = calc_ints (ipl, trap_req); /* upd int req */
trapea = 0;
@ -791,7 +818,8 @@ else {
(CPUT (STOP_STKA) || stop_spabort))
reason = STOP_SPABORT;
if (trapea == ~MD_KER) { /* kernel stk abort? */
setTRAP (TRAP_RED);
trap_req = trap_req & ~trap_clear[TRAP_RED];/* clear all traps */
setTRAP (TRAP_RED); /* set red stack trap */
setCPUERR (CPUE_RED);
STACKFILE[MD_KER] = 4;
if (cm == MD_KER)
@ -879,20 +907,19 @@ while (reason == 0) {
6. Update SP, PSW, and PC
7. If not stack overflow, check for stack overflow
If the reads in step 3, or the writes in step 5, match a data breakpoint,
the breakpoint status will be set but the interrupt actions will continue.
The breakpoint stop will occur at the beginning of the next instruction
cycle.
If the MMU registers are not frozen, the 11/45 and 11/70 will
also clear MMR1 and store the trap vector in MMR2, <except>
for the four instruction traps (EMT, TRAP, IOT, BPT).
*/
wait_state = 0; /* exit wait state */
STACKFILE[cm] = SP;
PSW = get_PSW (); /* assemble PSW */
oldrs = rs;
if (CPUT (HAS_MMTR)) { /* 45,70? */
if (update_MM) /* save vector */
MMR2 = trapea;
MMR0 = MMR0 & ~MMR0_IC; /* clear IC */
if ((CPUT (HAS_MMTR)) && (update_MM)) { /* 45,70, not frozen? */
MMR1 = 0; /* clear MMR1 */
if (trap_load_mmr2[trapnum]) /* load MMR2? */
MMR2 = trapea; /* save vector */
}
src = ReadCW (trapea | calc_ds (MD_KER)); /* new PC */
src2 = ReadCW ((trapea + 2) | calc_ds (MD_KER)); /* new PSW */
@ -917,7 +944,6 @@ while (reason == 0) {
if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y)) &&
(trapnum != TRAP_V_RED) && (trapnum != TRAP_V_YEL))
set_stack_trap (SP);
MMR0 = MMR0 | MMR0_IC; /* back to instr */
continue; /* end if traps */
}
@ -2887,14 +2913,16 @@ switch (apr & PDR_ACF) { /* case on ACF */
case 1: case 4: /* trap read */
if (CPUT (HAS_MMTR)) { /* traps implemented? */
APRFILE[apridx] = APRFILE[apridx] | PDR_A; /* set A */
if (MMR0 & MMR0_TENB) { /* traps enabled? */
int32 old_mmr0 = MMR0;
APRFILE[apridx] |= PDR_A; /* set A */
MMR0 = MMR0 | MMR0_TRAP; /* set trap flag */
if ((MMR0 & MMR0_TENB) != 0) { /* traps enabled? */
if (update_MM) /* update MMR0 */
MMR0 = (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE);
MMR0 = MMR0 | MMR0_TRAP; /* set trap flag */
setTRAP (TRAP_MME); /* set trap */
if ((old_mmr0 & MMR0_TRAP) == 0) /* first trap? */
setTRAP (TRAP_MME); /* set trap */
}
return; /* continue op */
return; /* continue */
} /* not impl, abort NR */
case 0: case 3: case 7: /* non-resident */
err = MMR0_NR; /* set MMR0 */
@ -2920,10 +2948,10 @@ return ((apr & PDR_ED)? (dbn < plf): (dbn > plf)); /* pg lnt error? */
void reloc_abort (int32 err, int32 apridx)
{
if (update_MM) MMR0 = /* update MMR0 */
(MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE);
APRFILE[apridx] = APRFILE[apridx] | PDR_A; /* set A */
MMR0 = MMR0 | err; /* set aborts */
if (update_MM) { /* MMR0 not frozen? */
MMR0 = (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE); /* record page */
MMR0 = MMR0 | err; /* OR in aborts */
}
ABORT (TRAP_MME); /* abort ref */
return;
}
@ -2955,7 +2983,7 @@ if (MMR0 & MMR0_MME) { /* if mmgt */
relocW_test (va, apridx); /* long test */
if (PLF_test (va, apr)) /* pg lnt error? */
reloc_abort (MMR0_PL, apridx);
APRFILE[apridx] = apr | PDR_W; /* set W */
APRFILE[apridx] |= PDR_W; /* set W */
pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK;
if ((MMR3 & MMR3_M22E) == 0) {
pa = pa & 0777777;
@ -2995,14 +3023,16 @@ switch (apr & PDR_ACF) { /* case on ACF */
case 4: case 5: /* trap write */
if (CPUT (HAS_MMTR)) { /* traps implemented? */
APRFILE[apridx] = APRFILE[apridx] | PDR_A; /* set A */
if (MMR0 & MMR0_TENB) { /* traps enabled? */
int32 old_mmr0 = MMR0;
APRFILE[apridx] |= PDR_A; /* set PDR <A> */
MMR0 = MMR0 | MMR0_TRAP; /* set trap flag */
if ((MMR0 & MMR0_TENB) != 0) { /* traps enabled? */
if (update_MM) /* update MMR0 */
MMR0 = (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE);
MMR0 = MMR0 | MMR0_TRAP; /* set trap flag */
setTRAP (TRAP_MME); /* set trap */
if ((old_mmr0 & MMR0_TRAP) == 0) /* first trap? */
setTRAP (TRAP_MME); /* set trap */
}
return; /* continue op */
return; /* continue, set A */
} /* not impl, abort NR */
case 0: case 3: case 7: /* non-resident */
err = MMR0_NR; /* MMR0 status */

View file

@ -1,6 +1,6 @@
/* pdp11_cpumod.c: PDP-11 CPU model-specific features
Copyright (c) 2004-2020, Robert M Supnik
Copyright (c) 2004-2022, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
system PDP-11 model-specific registers
19-Nov-22 RMS Fixed byte access errors in PIRQ, STKLIM, CDR (Walter Mueller)
15-Sep-20 RMS Fixed problem in KDJ11E programmable clock (Paul Koning)
04-Mar-16 RMS Fixed maximum memory sizes to exclude IO page
14-Mar-16 RMS Modified to keep cpu_memsize in sync with MEMSIZE
@ -49,12 +50,21 @@
#include "pdp11_defs.h"
#include "pdp11_cpumod.h"
/* Byte write macros for system registers */
/* Byte write macros for system registers
EVN_IGN byte writes to the even byte are ignored
ODD_IGN byte writes to the odd byte are ignored
ODD_SHF byte writes to the odd byte zero the even byte
ODD_MRG byte writes write appropriate byte
*/
#define EVN_IGN(cur) \
if ((access == WRITEB) && ((pa & 1) == 0)) \
return SCPE_OK
#define ODD_IGN(cur) \
if ((access == WRITEB) && (pa & 1)) \
return SCPE_OK
#define ODD_WO(cur) \
#define ODD_SHF(cur) \
if ((access == WRITEB) && (pa & 1)) \
cur = cur << 8
#define ODD_MRG(prv,cur) \
@ -475,7 +485,8 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */
return SCPE_OK;
case 015: /* PIRQ */
ODD_WO (data);
EVN_IGN (data);
ODD_SHF (data);
put_PIRQ (data);
return SCPE_OK;
}
@ -511,12 +522,14 @@ t_stat CPU45_wr (int32 data, int32 pa, int32 access)
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 015: /* PIRQ */
ODD_WO (data);
EVN_IGN (data);
ODD_SHF (data);
put_PIRQ (data);
return SCPE_OK;
case 016: /* STKLIM */
ODD_WO (data);
EVN_IGN (data);
ODD_SHF (data);
STKLIM = data & STKLIM_RW;
return SCPE_OK;
} /* end switch pa */
@ -590,7 +603,8 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */
return SCPE_OK;
case 016: /* STKLIM */
ODD_WO (data);
EVN_IGN (data);
ODD_SHF (data);
STKLIM = data & STKLIM_RW;
return SCPE_OK;
} /* end switch pa */
@ -661,12 +675,19 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */
return SCPE_NXM; /* unimplemented */
}
/* From Walter Mueller: MEMERR is always written using the standard data
on the bus: the whole word for DATO, the high byte for DATOB odd,
and the low byte with DATOB even. The simulator always puts a byte
in the low 8 bits, so for an odd byte reference, it must be shifted
to the high byte.
*/
t_stat CPU70_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 002: /* MEMERR */
ODD_WO (data);
ODD_SHF (data);
MEMERR = MEMERR & ~data;
return SCPE_OK;
@ -697,12 +718,14 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */
return SCPE_OK;
case 015: /* PIRQ */
ODD_WO (data);
EVN_IGN (data);
ODD_SHF (data);
put_PIRQ (data);
return SCPE_OK;
case 016: /* STKLIM */
ODD_WO (data);
EVN_IGN (data);
ODD_SHF (data);
STKLIM = data & STKLIM_RW;
return SCPE_OK;
} /* end switch pa */
@ -779,7 +802,8 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */
return SCPE_OK;
case 015: /* PIRQ */
ODD_WO (data);
EVN_IGN (data);
ODD_SHF (data);
put_PIRQ (data);
return SCPE_OK;
} /* end switch pa */
@ -818,12 +842,14 @@ switch ((pa >> 1) & 03) { /* decode pa<2:1> */
ODD_MRG (JPCR, data);
JPCR = data & PCRFB_RW;
return SCPE_OK;
case 1: /* MAINT */
ODD_MRG (MAINT, data);
MAINT = data;
return SCPE_OK;
case 2: /* CDR */
ODD_WO (data);
ODD_IGN (data);
DR = data & CDRFB_WR;
return SCPE_OK;
}
@ -881,7 +907,7 @@ switch ((pa >> 1) & 03) { /* decode pa<2:1> */
return SCPE_OK;
case 2: /* CDR */
ODD_WO (data);
ODD_IGN (data);
DR = data & CDRJB_WR;
return SCPE_OK;
}
@ -972,7 +998,7 @@ switch ((pa >> 1) & 03) { /* decode pa<2:1> */
return SCPE_OK;
case 2: /* CDR */
ODD_WO (data);
ODD_IGN (data);
DR = data & CDRJE_WR;
return SCPE_OK;

View file

@ -26,6 +26,8 @@
The author gratefully acknowledges the help of Max Burnet, Megan Gentry,
and John Wilson in resolving questions about the PDP-11
23-Oct-22 RMS Moved NXM abort priority above MME trap priority
25-Jul-22 RMS Removed OPT_RH11 (Mark Pizzolato)
10-Feb-17 RMS Fixed RJS11 register block length (Mark Hill)
19-Jan-17 RMS Moved CR11 to BR6, leaving CD11 at BR4 (Mark Pizzolato)
10-Mar-16 RMS Added UC15 support
@ -409,14 +411,17 @@ typedef struct {
#define CSR_BUSY (1u << CSR_V_BUSY)
#define CSR_ERR (1u << CSR_V_ERR)
/* Trap masks, descending priority order, following J-11
An interrupt summary bit is kept with traps, to minimize overhead
/* Trap masks, descending priority order. Rules:
- Aborts are mutually exclusive, no more than one per instrution.
- Aborts must be higher priority than traps. Because MME can be
either an abort or a trap, it is lower priority than NXM.
*/
#define TRAP_V_RED 0 /* red stk abort 4 */
#define TRAP_V_ODD 1 /* odd address 4 */
#define TRAP_V_MME 2 /* mem mgt 250 */
#define TRAP_V_NXM 3 /* nx memory 4 */
#define TRAP_V_NXM 2 /* nx memory 4 */
#define TRAP_V_MME 3 /* mem mgt 250 */
#define TRAP_V_PAR 4 /* parity err 114 */
#define TRAP_V_PRV 5 /* priv inst 4 */
#define TRAP_V_ILL 6 /* illegal inst 10 */

View file

@ -23,6 +23,9 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
10-Dec-22 RMS Fixed bug in FUIV operation (James Fehlinger)
21-Aug-22 RMS Restored MMR1 operation for 11/44, 11/45-70 (Walter Mueller)
28-May-18 RMS Fixed FPCHG macro to avoid undefined operation (Mark Pizzolato)
24-Mar-15 RMS MMR1 does not track register changes (Johnny Billquist)
20-Apr-13 RMS MMR1 does not track PC changes (Johnny Billquist)
22-Sep-05 RMS Fixed declarations (Sterling Garwood)
@ -86,12 +89,17 @@
accessed; if the operand is 32b or 64b, these
are the high order 16b of the operand.
The FP11 cannot update MMR1 on specifier changes, because the
quantity field is too narrow for +8 or -8. Instead, the simulator
records changes to be made and only commits them at instruction
completion. Instructions that can overwrite a general register
(STFPS, STST, STEXP, STCFi in mode 0) need not check for conflicts;
in mode 0, no general register changes occur in the specifier flow.
The J11 cannot update MMR1 on specifier changes, because the
quantity field is too narrow for +8 or -8. However, the 11/44 and
11/70 can. So the simulator treats the two cases differently.
On the J11, the simulator records changes to be made and only
commits them at instruction. On all other systems, changes occur
as they happen and are recorded in MMR1. However, all systems
update the general registers on floating point exceptions. Thus,
when an exception occurs, the simulator in most cases cannot
abort but must let the instruction "run to completion." For
undefined variable and divide by zero, this means skipping
the actual processing logic.
*/
#include "pdp11_defs.h"
@ -536,7 +544,7 @@ switch ((IR >> 8) & 017) { /* decode IR<11:8> */
case 003: /* MODf */
if (ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf)) {
F_LOAD (qdouble, FR[ac], fac);
F_LOAD (qdouble, FR[ac], fac);
newV = modfp11 (&fac, &fsrc, &modfrac);
F_STORE (qdouble, fac, FR[ac | 1]);
F_STORE (qdouble, modfrac, FR[ac]);
@ -787,8 +795,9 @@ else {
}
if ((GET_SIGN (fptr->h) != 0) &&
(GET_EXP (fptr->h) == 0) &&
(fpnotrap (FEC_UNDFV) == 0))
return FALSE;
!fpnotrap (FEC_UNDFV)) { /* trap enabled? */
return FALSE; /* NOP instruction */
}
return TRUE;
}

View file

@ -573,7 +573,7 @@ for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
massbus[mb].wc = (massbus[mb].wc + (bc >> 1)) & DMASK; /* update wc */
massbus[mb].ba = ba & DMASK; /* update ba */
massbus[mb].bae = (ba >> 16) & ~AE_MBZ; /* upper 6b */
massbus[mb].cs1 = (massbus[mb].cs1 & ~ CS1_UAE) | /* update CS1 */
massbus[mb].cs1 = (massbus[mb].cs1 & ~ CS1_UAE) | /* update CS1 */
((massbus[mb].bae << CS1_V_UAE) & CS1_UAE);
return i;
}

View file

@ -1,6 +1,6 @@
/* pdp11_rk.c: RK11/RKV11 cartridge disk simulator
Copyright (c) 1993-2016, Robert M Supnik
Copyright (c) 1993-2022, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
rk RK11/RKV11/RK05 cartridge disk
28-Nov-22 RMS Fixed word count adjustment on NXM (Anthony Lawrence)
12-Mar-16 RMS Revised to support UC15 (18b IO)
23-Oct-13 RMS Revised for new boot setup routine
20-Mar-09 RMS Fixed bug in read header (Walter F Mueller)
@ -764,7 +765,7 @@ if (wc && (err == 0)) { /* seek ok? */
rkxb[i] = comp;
}
else { /* normal fetch */
if ((t = MAP_RDW (ma, wc << 1, rkxb))) { /* get buf */
if ((t = MAP_RDW (ma, wc << 1, rkxb))) { /* get buf */
rker = rker | RKER_NXM; /* NXM? set flg */
wc = wc - t; /* adj wd cnt */
}
@ -816,6 +817,7 @@ if ((uptr->FUNC == RKCS_READ) && (rkcs & RKCS_FMT)) /* read format? */
else da = da + wc + (RK_NUMWD - 1); /* count by words */
track = (da / RK_NUMWD) / RK_NUMSC;
sect = (da / RK_NUMWD) % RK_NUMSC;
uptr->CYL = track / RK_NUMSF; /* update position */
rkda = (rkda & RKDA_DRIVE) | (track << RKDA_V_TRACK) | (sect << RKDA_V_SECT);
rk_set_done (0);

View file

@ -25,6 +25,7 @@
rl RL11(RLV12)/RL01/RL02 cartridge disk
28-Nov-22 RMS Fixed word count adjustment on NXM
23-Oct-13 RMS Revised for new boot setup routine
24-Mar-11 JAD Various changes to support diagnostics, including:
- distinguish between RLV11 & 12