diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 1f383459..72f953a5 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -1,6 +1,6 @@ /* pdp11_cpu.c: PDP-11 CPU 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,14 @@ cpu PDP-11 CPU + 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 @@ -338,6 +346,7 @@ int32 relocR (int32 addr); int32 relocW (int32 addr); void relocR_test (int32 va, int32 apridx); void relocW_test (int32 va, int32 apridx); +int32 clean_MMR1 (int32 mmr1); t_bool PLF_test (int32 va, int32 apr); void reloc_abort (int32 err, int32 apridx); int32 ReadE (int32 addr); @@ -609,9 +618,9 @@ MTAB cpu_mod[] = { { MTAB_XTD|MTAB_VDV, MOD_1184, NULL, "11/84", &cpu_set_model, NULL, NULL, "Set CPU type to 11/84" }, { MTAB_XTD|MTAB_VDV, MOD_1193, NULL, "11/93", &cpu_set_model, NULL, NULL, "Set CPU type to 11/93" }, { MTAB_XTD|MTAB_VDV, MOD_1194, NULL, "11/94", &cpu_set_model, NULL, NULL, "Set CPU type to 11/94" }, - { MTAB_XTD|MTAB_VDV, MOD_1173, NULL, "Q22", &cpu_set_model, NULL, NULL, "deprecated: same as 11/73" }, - { MTAB_XTD|MTAB_VDV, MOD_1184, NULL, "URH11", &cpu_set_model, NULL, NULL, "deprecated: same as 11/84" }, - { MTAB_XTD|MTAB_VDV, MOD_1170, NULL, "URH70", &cpu_set_model, NULL, NULL, "deprecated: same as 11/70" }, +// { MTAB_XTD|MTAB_VDV, MOD_1173, NULL, "Q22", &cpu_set_model, NULL, NULL, "deprecated: same as 11/73" }, +// { MTAB_XTD|MTAB_VDV, MOD_1184, NULL, "URH11", &cpu_set_model, NULL, NULL, "deprecated: same as 11/84" }, +// { MTAB_XTD|MTAB_VDV, MOD_1170, NULL, "URH70", &cpu_set_model, NULL, NULL, "deprecated: same as 11/70" }, { MTAB_XTD|MTAB_VDV, MOD_1145, NULL, "U18", &cpu_set_model, NULL, NULL, "deprecated: same as 11/45" }, { MTAB_XTD|MTAB_VDV, OPT_EIS, NULL, "EIS", &cpu_set_opt, NULL, NULL, "enable EIS instructions" }, { MTAB_XTD|MTAB_VDV, OPT_EIS, NULL, "NOEIS", &cpu_clr_opt, NULL, NULL, "disable EIS instructions" }, @@ -888,8 +897,10 @@ while (reason == 0) { PSW = get_PSW (); /* assemble PSW */ oldrs = rs; if (CPUT (HAS_MMTR)) { /* 45,70? */ - if (update_MM) /* save vector */ - MMR2 = trapea; + if (update_MM) { /* if not frozen */ + MMR1 = 0; /* clear MMR1 */ + MMR2 = trapea; /* save vector */ + } MMR0 = MMR0 & ~MMR0_IC; /* clear IC */ } src = ReadCW (trapea | calc_ds (MD_KER)); /* new PC */ @@ -1222,9 +1233,9 @@ while (reason == 0) { reg_mods = calc_MMR1 (0366); if (update_MM) MMR1 = reg_mods; - WriteW (R[srcspec], SP | dsenable); if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y))) set_stack_trap (SP); + WriteW (R[srcspec], SP | dsenable); R[srcspec] = PC; if (hst_ent) hst_ent->dst = dst; @@ -1424,9 +1435,9 @@ while (reason == 0) { MMR1 = reg_mods; if (hst_ent) hst_ent->dst = dst; - WriteW (dst, SP | dsenable); if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y))) set_stack_trap (SP); + WriteW (dst, SP | dsenable); } else setTRAP (TRAP_ILL); break; @@ -1715,7 +1726,7 @@ while (reason == 0) { break; } if ((((uint32)src) == 020000000000) && (src2 == 0177777)) { - V = 1; /* J11,11/70 compat */ + V = 1; /* V = 1 */ N = Z = C = 0; /* N = Z = 0 */ break; } @@ -1730,7 +1741,7 @@ while (reason == 0) { } N = (dst < 0); /* N set on 32b result */ if ((dst > 077777) || (dst < -0100000)) { - V = 1; /* J11,11/70 compat */ + V = 1; /* V = 1 */ Z = C = 0; /* Z = C = 0 */ break; } @@ -2215,9 +2226,9 @@ while (reason == 0) { MMR1 = reg_mods; if (hst_ent) hst_ent->dst = dst; - WriteW (dst, SP | dsenable); if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y))) set_stack_trap (SP); + WriteW (dst, SP | dsenable); } else setTRAP (TRAP_ILL); break; @@ -2414,6 +2425,7 @@ for (i = 0; i < 6; i++) REGFILE[i][rs] = R[i]; STACKFILE[cm] = SP; saved_PC = PC & 0177777; +MMR1 = clean_MMR1 (MMR1); /* clean up MMR1 */ pcq_r->qptr = pcq_p; /* update pc q ptr */ set_r_display (rs, cm); return reason; @@ -2454,7 +2466,7 @@ return reason; explicitly reference the PC. For the J-11, this is only true for autodecrement operands, autodecrement deferred operands, and autoincrement destination operands that involve a write to memory. - The simulator follows the Handbook, for simplicity. + This is cleaned up at simulator exit or MMR1 read. Notes: @@ -2482,14 +2494,14 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 2: /* (R)+ */ R[reg] = ((adr = R[reg]) + 2) & 0177777; reg_mods = calc_MMR1 (020 | reg); - if (update_MM && (reg != 7)) + if (update_MM) MMR1 = reg_mods; return (adr | ds); case 3: /* @(R)+ */ R[reg] = ((adr = R[reg]) + 2) & 0177777; reg_mods = calc_MMR1 (020 | reg); - if (update_MM && (reg != 7)) + if (update_MM) MMR1 = reg_mods; adr = ReadW (adr | ds); return (adr | dsenable); @@ -2497,7 +2509,7 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 4: /* -(R) */ adr = R[reg] = (R[reg] - 2) & 0177777; reg_mods = calc_MMR1 (0360 | reg); - if (update_MM && (reg != 7)) + if (update_MM) MMR1 = reg_mods; if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); @@ -2506,7 +2518,7 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 5: /* @-(R) */ adr = R[reg] = (R[reg] - 2) & 0177777; reg_mods = calc_MMR1 (0360 | reg); - if (update_MM && (reg != 7)) + if (update_MM) MMR1 = reg_mods; if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); @@ -2551,7 +2563,7 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 3: /* @(R)+ */ R[reg] = ((adr = R[reg]) + 2) & 0177777; reg_mods = calc_MMR1 (020 | reg); - if (update_MM && (reg != 7)) + if (update_MM) MMR1 = reg_mods; adr = ReadW (adr | ds); return (adr | dsenable); @@ -2560,7 +2572,7 @@ switch (spec >> 3) { /* decode spec<5:3> */ delta = 1 + (reg >= 6); /* 2 if R6, PC */ adr = R[reg] = (R[reg] - delta) & 0177777; reg_mods = calc_MMR1 ((((-delta) & 037) << 3) | reg); - if (update_MM && (reg != 7)) + if (update_MM) MMR1 = reg_mods; if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); @@ -2569,7 +2581,7 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 5: /* @-(R) */ adr = R[reg] = (R[reg] - 2) & 0177777; reg_mods = calc_MMR1 (0360 | reg); - if (update_MM && (reg != 7)) + if (update_MM) MMR1 = reg_mods; if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); @@ -3087,7 +3099,8 @@ switch ((pa >> 1) & 3) { /* decode pa<2:1> */ break; case 2: /* MMR1 */ - *data = MMR1; + MMR1 = clean_MMR1 (MMR1); /* clean up MMR1 */ + *data = MMR1; /* return data */ break; case 3: /* MMR2 */ @@ -3133,6 +3146,29 @@ dsenable = calc_ds (cm); return SCPE_OK; } +/* Clean up MMR1 for presentation + + !HAS_SID MMR1 is 0 + HAS_SID && J11 MMR1 values corresponding to # and @# are cleared + HAS_SID && !J11 MMR1 is unchanged + + Note that # and @# always generate reg = 7 and change = 2; + no other specifier combination can do that. +*/ + +int32 clean_MMR1 (int32 mmr1) +{ +if (!CPUT (HAS_SID)) /* not full mmgt? */ + return 0; /* always 0 */ +if (CPUT (CPUT_J)) { /* J11? */ + if ((mmr1 >> 8) == 027) /* high byte # or @#? */ + mmr1 = mmr1 & 0377; /* erase high byte */ + if ((mmr1 & 0377) == 027) /* low byte # or @#? */ + mmr1 = mmr1 >> 8; /* erase low byte */ + } +return mmr1; +} + /* PARs and PDRs. These are grouped in I/O space as follows: 17772200 - 17772276 supervisor block diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index 89aa1639..c2363556 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -1,6 +1,6 @@ /* pdp11_fp.c: PDP-11 floating point simulator (32b version) - Copyright (c) 1993-2015, Robert M Supnik + Copyright (c) 1993-2018, 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"), @@ -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. + 21-Aug-22 RMS Restored MMR1 operation for 11/44, 11/45-70 (Walter Mueller) 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) @@ -248,9 +249,10 @@ static const uint32 and_mask[33] = { 0, int32 backup_PC; int32 fp_change; -int32 fpnotrap (int32 code); +t_bool fpnotrap (int32 code); int32 GeteaFW (int32 spec); int32 GeteaFP (int32 spec, int32 len); +void fp_reg_change (int32 len, int32 reg); uint32 ReadI (int32 addr, int32 spec, int32 len); t_bool ReadFP (fpac_t *fac, int32 addr, int32 spec, int32 len); void WriteI (int32 data, int32 addr, int32 spec, int32 len); @@ -606,33 +608,25 @@ switch (spec >> 3) { /* decode spec<5:3> */ case 2: /* (R)+ */ adr = R[reg]; /* post increment */ - if (reg == 7) /* commit PC chg now */ - R[reg] = (R[reg] + 2) & 0177777; - else fp_change = FPCHG (2, reg); /* others, update later */ + fp_reg_change (2, reg); /* update */ return (adr | ds); case 3: /* @(R)+ */ adr = R[reg]; /* post increment */ - if (reg == 7) /* commit PC chg now */ - R[reg] = (R[reg] + 2) & 0177777; - else fp_change = FPCHG (2, reg); /* others, update later */ + fp_reg_change (2, reg); /* update */ adr = ReadW (adr | ds); return (adr | dsenable); case 4: /* -(R) */ adr = (R[reg] - 2) & 0177777; /* predecrement */ - if (reg == 7) /* commit PC chg now */ - R[reg] = adr; - else fp_change = FPCHG (-2, reg); /* others, update later */ + fp_reg_change (-2, reg); /* update */ if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); return (adr | ds); case 5: /* @-(R) */ adr = (R[reg] - 2) & 0177777; /* predecrement */ - if (reg == 7) /* commit PC chg now */ - R[reg] = adr; - else fp_change = FPCHG (-2, reg); /* others, update later */ + fp_reg_change (-2, reg); /* update */ if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); adr = ReadW (adr | ds); @@ -687,33 +681,27 @@ switch (spec >> 3) { /* case on spec */ case 2: /* (R)+ */ adr = R[reg]; /* post increment */ - if (reg == 7) /* commit PC chg now */ - R[reg] = (R[reg] + 2) & 0177777; - else fp_change = FPCHG (len, reg); /* others, update later */ + if (reg == 7) /* # is always length 2 */ + len = 2; + fp_reg_change (len, reg); /* update */ return (adr | ds); case 3: /* @(R)+ */ adr = R[reg]; /* post increment */ - if (reg == 7) /* commit PC chg now */ - R[reg] = (R[reg] + 2) & 0177777; - else fp_change = FPCHG (2, reg); /* others, update later */ + fp_reg_change (2, reg); /* update */ adr = ReadW (adr | ds); return (adr | dsenable); case 4: /* -(R) */ adr = (R[reg] - len) & 0177777; /* predecrement */ - if (reg == 7) /* commit PC chg now */ - R[reg] = adr; - else fp_change = FPCHG (-len, reg); /* others, udpate later */ + fp_reg_change (-len, reg); /* update */ if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) set_stack_trap (adr); return (adr | ds); case 5: /* @-(R) */ adr = (R[reg] - 2) & 0177777; /* predecrement */ - if (reg == 7) /* commit PC chg now */ - R[reg] = adr; - else fp_change = FPCHG (-2, reg); /* others, update later */ + fp_reg_change (-2, reg); /* update */ if ((reg == 6) && (cm == MD_KER) && ((adr - 2) < (STKLIM + STKL_Y))) set_stack_trap (adr); adr = ReadW (adr | ds); @@ -734,6 +722,35 @@ switch (spec >> 3) { /* case on spec */ return 0; } +/* Specifier register change + + On systems with full memory management, the 11/44, 11/45, and 11/70 + operate differently than J11. The former do normal register modification + and track changes in MMR1; on an abort, the register modifications + are visible. The J11 does not perform normal register modification + and tracking. Instead, it tracks changes internally and only updates + the general registers upon successful completion of the instruction. + On an abort, the general registers are unchanged. + + This routine performs the appropriate bookkeeping for the different + models. +*/ + +void fp_reg_change (int32 len, int32 reg) +{ +if (CPUT (CPUT_J)) { /* J11? */ + if (reg == 7) + R[reg] = (R[reg] + len) & 0177777; /* commit PC changes now */ + else fp_change = FPCHG (len, reg); /* track other changes */ + } +else { /* all others */ + R[reg] = (R[reg] + len) & 0177777; /* commit reg changes */ + if (update_MM) /* if not frozen */ + MMR1 = ((len & 037) << 3) | reg; /* update MMR1 */ + } +return; +} + /* Read integer operand Inputs: @@ -785,10 +802,12 @@ else { (ReadW (exta | ((VA + 6) & 0177777)) << FP_V_F3); else fptr->l = 0; } -if ((GET_SIGN (fptr->h) != 0) && +if ((GET_SIGN (fptr->h) != 0) && /* undef variable? */ (GET_EXP (fptr->h) == 0) && - (fpnotrap (FEC_UNDFV) == 0)) - return FALSE; + !fpnotrap (FEC_UNDFV)) { /* trap enabled? */ + fp_change = 0; /* J11, no reg changes */ + return FALSE; /* NOP instruction */ + } return TRUE; } @@ -1393,7 +1412,7 @@ return 0; int = FALSE if interrupt enabled, TRUE if disabled */ -int32 fpnotrap (int32 code) +t_bool fpnotrap (int32 code) { static const int32 test_code[] = { 0, 0, 0, FPS_IC, FPS_IV, FPS_IU, FPS_IUV };