diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 7103c07d..7042bdb2 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -25,6 +25,12 @@ 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 (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) @@ -370,22 +376,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 @@ -684,7 +703,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; @@ -716,7 +735,8 @@ if (abortval != 0) { (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) @@ -779,18 +799,20 @@ while (reason == 0) { 5. Push the old PC and PSW on the new stack 6. Update SP, PSW, and PC 7. If not stack overflow, check for stack overflow + + If the MMU registers are not frozen, the 11/45 and 11/70 will + also clear MMR1 and store the trap vector in MMR2, + 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) { /* if not frozen */ - MMR1 = 0; /* clear MMR1 */ + 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 */ - } - MMR0 = MMR0 & ~MMR0_IC; /* clear IC */ } src = ReadW (trapea | calc_ds (MD_KER)); /* new PC */ src2 = ReadW ((trapea + 2) | calc_ds (MD_KER)); /* new PSW */ @@ -815,7 +837,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 */ } @@ -2557,14 +2578,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 */ @@ -2590,10 +2613,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; } @@ -2625,7 +2648,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; @@ -2665,14 +2688,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 */ + 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 */ diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index 3d6f1124..db44c038 100644 --- a/PDP11/pdp11_cpumod.c +++ b/PDP11/pdp11_cpumod.c @@ -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 @@ -50,12 +51,21 @@ #include "pdp11_cpumod.h" #include -/* 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) \ @@ -436,7 +446,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; } @@ -472,12 +483,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 */ @@ -551,7 +564,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 */ @@ -622,12 +636,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; @@ -658,12 +679,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 */ @@ -740,7 +763,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 */ @@ -779,12 +803,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; } @@ -842,7 +868,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; } @@ -933,7 +959,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; diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 52e9a1bf..64a849da 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -26,6 +26,7 @@ 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) @@ -410,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 */ diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index 60fc030e..af3d57f3 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -23,6 +23,7 @@ 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) @@ -88,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" @@ -535,7 +541,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]); @@ -802,7 +808,6 @@ else { if ((GET_SIGN (fptr->h) != 0) && /* undef variable? */ (GET_EXP (fptr->h) == 0) && !fpnotrap (FEC_UNDFV)) { /* trap enabled? */ - fp_change = 0; /* J11, no reg changes */ return FALSE; /* NOP instruction */ } return TRUE; diff --git a/PDP11/pdp11_rh.c b/PDP11/pdp11_rh.c index 5d2d5cb7..ccc841a4 100644 --- a/PDP11/pdp11_rh.c +++ b/PDP11/pdp11_rh.c @@ -577,7 +577,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; } diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index 368212a4..f501ba99 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -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 06-Sep-13 RMS Fixed RKDS content for non-existent disk (Mark Pizzolato) @@ -589,7 +590,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 >> 1); /* adj wd cnt */ } @@ -642,7 +643,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; +uptr->CYL = track / RK_NUMSF; /* update position */ rkda = (rkda & RKDA_DRIVE) | (track << RKDA_V_TRACK) | (sect << RKDA_V_SECT); rk_set_done (0); diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 4231b875..05dcf260 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -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 diff --git a/doc/pdp11_doc.doc b/doc/pdp11_doc.doc index e2fdbe0c..67fd6b66 100644 Binary files a/doc/pdp11_doc.doc and b/doc/pdp11_doc.doc differ diff --git a/doc/simh_doc.doc b/doc/simh_doc.doc index a62660c3..f94035b8 100644 Binary files a/doc/simh_doc.doc and b/doc/simh_doc.doc differ