From a835061e676b6d3e07adf5f366d7225b056452f9 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 19 Feb 2016 12:04:08 -0800 Subject: [PATCH] PDP10: Fix nested indirect address limit exceeded (from Bob Supnik) If the nested indirect/execute limit (INDMAX, XCTMAX) is set to 0, the simulator will loop indefinitely in an indirect address or execute loop, testing for interrupts before each memory reference. Thus, on an infinite loop, the simulator will never complete the instruction, but the instruction is interruptible. So for example, under TOPS-10: .r ddt 1/ 0 jrstf @1 1$g ^C ^C . The JRSTF will never finish, but it can be interrupted by any device, and double ^C will return control to the command line. If INDMAX or XCTMAX is non-zero, the previous behavior of limiting loops to a specific depth is retained. However, the default value is now 0. This closes issue #218. --- PDP10/pdp10_bug_history.txt | 3 ++ PDP10/pdp10_cpu.c | 68 ++++++++++++++++++++++++------------ doc/pdp10_doc.doc | Bin 84480 -> 87040 bytes 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/PDP10/pdp10_bug_history.txt b/PDP10/pdp10_bug_history.txt index b4a31144..3916d172 100644 --- a/PDP10/pdp10_bug_history.txt +++ b/PDP10/pdp10_bug_history.txt @@ -23,3 +23,6 @@ Bugs Found and Fixed During Simulator Debug 16. RHCS1: writing IE cannot trigger an interrupt 17. Tape bootstrap was set to 800bpi instead of 1600bpi 18. FIXR off by 1 in testing for lower limit to process +19. Indirect loops and XCT loops should run indefinitely, + test for interrupts on each memory reference + diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index 862bfcab..49cd435c 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -1,6 +1,6 @@ /* pdp10_cpu.c: PDP-10 CPU simulator - Copyright (c) 1993-2012, Robert M. Supnik + Copyright (c) 1993-2016, 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 @@ cpu KS10 central processor + 09-Feb-16 RMS Fixed nested indirects and executes (Tim Litt) 25-Mar-12 RMS Added missing parameters to prototypes (Mark Pizzolato) 17-Jul-07 RMS Fixed non-portable usage in SHOW HISTORY 28-Apr-07 RMS Removed clock initialization @@ -191,8 +192,8 @@ int32 flags = 0; /* flags */ int32 its_1pr = 0; /* ITS 1-proceed */ int32 stop_op0 = 0; /* stop on 0 */ int32 rlog = 0; /* extend fixup log */ -int32 ind_max = 32; /* nested ind limit */ -int32 xct_max = 32; /* nested XCT limit */ +int32 ind_max = 0; /* nested ind limit */ +int32 xct_max = 0; /* nested XCT limit */ int32 t20_idlelock = 0; /* TOPS-20 idle lock */ a10 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ @@ -387,8 +388,8 @@ REG cpu_reg[] = { { FLDATA (F1PR, its_1pr, 0) }, { BRDATA (PCQ, pcq, 8, VASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { DRDATA (INDMAX, ind_max, 8), PV_LEFT + REG_NZ }, - { DRDATA (XCTMAX, xct_max, 8), PV_LEFT + REG_NZ }, + { DRDATA (INDMAX, ind_max, 8), PV_LEFT }, + { DRDATA (XCTMAX, xct_max, 8), PV_LEFT }, { ORDATA (WRU, sim_int_char, 8) }, { FLDATA (STOP_ILL, stop_op0, 0) }, { BRDATA (REG, acs, 8, 36, AC_NUM * AC_NBLK) }, @@ -856,17 +857,23 @@ its_2pr = its_1pr; /* save 1-proc flag */ XCT: op = GET_OP (inst); /* get opcode */ ac = GET_AC (inst); /* get AC */ -for (indrct = inst, i = 0; i < ind_max; i++) { /* calc eff addr */ +for (indrct = inst, i = 0; ; i++) { /* calc eff addr */ ea = GET_ADDR (indrct); xr = GET_XR (indrct); if (xr) ea = (ea + ((a10) XR (xr, MM_EA))) & AMASK; - if (TST_IND (indrct)) - indrct = Read (ea, MM_EA); + if (TST_IND (indrct)) { /* indirect? */ + if (i != 0) { /* not first cycle? */ + int32 t = test_int (); /* test for intr */ + if (t != 0) /* err or intr? */ + ABORT (t); + if ((ind_max != 0) && (i >= ind_max)) /* limit exceeded? */ + ABORT (STOP_IND); + } + indrct = Read (ea, MM_EA); /* fetch indirect */ + } else break; } -if (i >= ind_max) - ABORT (STOP_IND); /* too many ind? stop */ if (hst_lnt) { /* history enabled? */ hst_p = (hst_p + 1); /* next entry */ if (hst_p >= hst_lnt) @@ -1071,10 +1078,15 @@ case 0255: if (flags & (ac << 14)) { /* JFCL */ CLRF (ac << 14); } break; -case 0256: if (xct_cnt++ >= xct_max) /* XCT */ - ABORT (STOP_XCT); - inst = Read (ea, MM_OPND); - if (ac && !TSTF (F_USR) && !Q_ITS) +case 0256: if (xct_cnt++ != 0) { /* XCT: not first? */ + int32 t = test_int (); /* test for intr */ + if (t != 0) /* intr or err? */ + ABORT (t); + if ((xct_max != 0) && (xct_cnt >= xct_max)) + ABORT (STOP_XCT); + } + inst = Read (ea, MM_OPND); /* get opnd */ + if (ac && !TSTF (F_USR) && !Q_ITS) /* PXCT? */ pflgs = pflgs | ac; goto XCT; case 0257: if (Q_ITS) goto MUUO; /* MAP */ @@ -1830,17 +1842,23 @@ a10 calc_ea (d10 inst, int32 prv) int32 i, ea, xr; d10 indrct; -for (indrct = inst, i = 0; i < ind_max; i++) { +for (indrct = inst, i = 0; ; i++) { ea = GET_ADDR (indrct); xr = GET_XR (indrct); if (xr) ea = (ea + ((a10) XR (xr, prv))) & AMASK; - if (TST_IND (indrct)) + if (TST_IND (indrct)) { /* indirect? */ + if (i != 0) { /* not first cycle? */ + int32 t = test_int (); /* test for intr */ + if (t != 0) /* intr or error? */ + ABORT (t); + if ((ind_max != 0) && (i >= ind_max)) /* limit exceeded? */ + ABORT (STOP_IND); + } indrct = Read (ea, prv); + } else break; } -if (i >= ind_max) - ABORT (STOP_IND); return ea; } @@ -1881,17 +1899,23 @@ d10 calc_jrstfea (d10 inst, int32 pflgs) int32 i, xr; d10 mb; -for (i = 0; i < ind_max; i++) { +for (i = 0; ; i++) { mb = inst; xr = GET_XR (inst); if (xr) mb = (mb & AMASK) + XR (xr, MM_EA); - if (TST_IND (inst)) + if (TST_IND (inst)) { /* indirect? */ + if (i != 0) { /* not first cycle? */ + int32 t = test_int (); /* test for intr */ + if (t != 0) /* intr or error? */ + ABORT (t); + if ((ind_max != 0) && (i >= ind_max)) /* limit exceeded? */ + ABORT (STOP_IND); + } inst = Read (((a10) mb) & AMASK, MM_EA); + } else break; } -if (i >= ind_max) - ABORT (STOP_IND); return (mb & DMASK); } diff --git a/doc/pdp10_doc.doc b/doc/pdp10_doc.doc index baddd5ff26c0ab48121769540f063bf439ad4206..3395c55160d7c0ba72b9b9bc339728a73a62d2b2 100644 GIT binary patch delta 9483 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 delta 8704 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