1
0
mirror of https://github.com/open-simh/simh.git synced 2026-04-28 12:57:40 +00:00

PDP11: CPU MMR1 and FP changes

There are a lot of niggling fixes, mostly for incompatibility issues
found by Walter Mueller. Working out the 11/70 behavior is still not
fully done, but it's a lot better than it was, and it passes more of the
11/70 MMU diagnostic.

- Floating point. Now model sensitive in treating MMR1, for 2.11 BSD.
- MMR1 now tracks PC changes on 11/44, 11/45, 11/70, and J11 -(PC) and @-(PC).
- MMR1 is cleared at start of trap sequence on 11/45, 11/70.
- Red stack abort occurs before memory writes on 11/45, 11/70 (no other model has them).
This commit is contained in:
Bob Supnik
2022-09-04 19:13:38 -06:00
committed by Mark Pizzolato
parent e93d21ac79
commit a847ee13a3
2 changed files with 107 additions and 54 deletions

View File

@@ -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)
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)
@@ -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);
@@ -603,33 +605,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);
@@ -684,33 +678,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);
@@ -731,6 +719,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:
@@ -782,10 +799,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;
}
@@ -1332,7 +1351,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 };