root/src/dps8/dps8_faults.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. emCallReportFault
  2. clearFaultCycle
  3. ia_port
  4. doFault
  5. do_FFV_fault
  6. dlyDoFault
  7. bG7Pending
  8. bG7PendingNoTRO
  9. setG7fault
  10. press_execute_switches
  11. set_FFV_fault
  12. clearTROFault
  13. doG7Fault
  14. advanceG7Faults

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * SPDX-License-Identifier: Multics
   5  * scspell-id: 4182f303-f62e-11ec-9475-80ee73e9b8e7
   6  *
   7  * ---------------------------------------------------------------------------
   8  *
   9  * Copyright (c) 2007-2013 Michael Mondy
  10  * Copyright (c) 2012-2016 Harry Reed
  11  * Copyright (c) 2013-2016 Charles Anthony
  12  * Copyright (c) 2017 Michal Tomek
  13  * Copyright (c) 2021-2026 The DPS8M Development Team
  14  *
  15  * This software is made available under the terms of the ICU License.
  16  * See the LICENSE.md file at the top-level directory of this distribution.
  17  *
  18  * ---------------------------------------------------------------------------
  19  *
  20  * This source file may contain code comments that adapt, include, and/or
  21  * incorporate Multics program code and/or documentation distributed under
  22  * the Multics License.  In the event of any discrepancy between code
  23  * comments herein and the original Multics materials, the original Multics
  24  * materials should be considered authoritative unless otherwise noted.
  25  * For more details and historical background, see the LICENSE.md file at
  26  * the top-level directory of this distribution.
  27  *
  28  * ---------------------------------------------------------------------------
  29  */
  30 
  31 #include <stdio.h>
  32 
  33 #include "dps8.h"
  34 #include "dps8_sys.h"
  35 #include "dps8_iom.h"
  36 #include "dps8_cable.h"
  37 #include "dps8_cpu.h"
  38 #include "dps8_faults.h"
  39 #include "dps8_scu.h"
  40 #include "dps8_append.h"
  41 #include "dps8_ins.h"
  42 #include "dps8_utils.h"
  43 #if defined(THREADZ) || defined(LOCKLESS)
  44 # include "threadz.h"
  45 #endif
  46 
  47 #define DBG_CTR cpu.cycleCnt
  48 
  49 /*
  50  * FAULT RECOGNITION
  51  * For the discussion following, the term "function" is defined as a major processor functional
  52  * cycle. Examples are: APPEND CYCLE, CA CYCLE, INSTRUCTION FETCH CYCLE, OPERAND STORE CYCLE,
  53  * DIVIDE EXECUTION CYCLE. Some of these cycles are discussed in various sections of this manual.
  54  * Faults in groups 1 and 2 cause the processor to abort all functions immediately by entering a
  55  * FAULT CYCLE. Faults in group 3 cause the processor to "close out" current functions without
  56  * taking any irrevocable action (such as setting PTW.U in an APPEND CYCLE or modifying an
  57  * indirect word in a CA CYCLE), then to discard any pending functions (such as an APPEND CYCLE
  58  * needed during a CA CYCLE), and to enter a FAULT CYCLE. Faults in group 4 cause the processor
  59  * to suspend overlapped operation, to complete current and pending functions for the current
  60  * instruction, and then to enter a FAULT CYCLE. Faults in groups 5 or 6 are normally detected
  61  * during virtual address formation and instruction decode. These faults cause the processor to
  62  * suspend overlapped operation, to complete the current and pending instructions, and to enter
  63  * a FAULT CYCLE. If a fault in a higher priority group is generated by the execution of the
  64  * current or pending instructions, that higher priority fault will take precedence and the
  65  * group 5 or 6 fault will be lost. If a group 5 or 6 fault is detected during execution of the
  66  * current instruction (e.g., an access violation, out of segment bounds, fault during certain
  67  * interruptible EIS instructions), the instruction is considered "complete" upon detection of
  68  * the fault. Faults in group 7 are held and processed (with interrupts) at the completion of
  69  * the current instruction pair. Group 7 faults are inhibitable by setting bit 28 of the
  70  * instruction word. Faults in groups 3 through 6 must wait for the system controller to
  71  * acknowledge the last access request before entering the FAULT CYCLE.
  72  */
  73 
  74 /*
  75  *                                Table 7-1. List of Faults
  76  *
  77  * Decimal fault     Octal (1)      Fault   Fault name            Priority    Group
  78  *    number      fault address   mnemonic
  79  *       0      ;         0     ;      sdf  ;   Shutdown             ;   27     ;     7
  80  *       1      ;         2     ;      str  ;   Store                ;   10     ;     4
  81  *       2      ;         4     ;      mme  ;   Master mode entry 1  ;   11     ;     5
  82  *       3      ;         6     ;      f1   ;   Fault tag 1          ;   17     ;     5
  83  *       4      ;        10     ;      tro  ;   Timer runout         ;   26     ;     7
  84  *       5      ;        12     ;      cmd  ;   Command              ;   9      ;     4
  85  *       6      ;        14     ;      drl  ;   Derail               ;   15     ;     5
  86  *       7      ;        16     ;      luf  ;   Lockup               ;   5      ;     4
  87  *       8      ;        20     ;      con  ;   Connect              ;   25     ;     7
  88  *       9      ;        22     ;      par  ;   Parity               ;   8      ;     4
  89  *       10     ;        24     ;      ipr  ;   Illegal procedure    ;   16     ;     5
  90  *       11     ;        26     ;      onc  ;   Operation not complete ; 4      ;     2
  91  *       12     ;        30     ;      suf  ;   Startup              ;   1      ;     1
  92  *       13     ;        32     ;      ofl  ;   Overflow             ;   7      ;     3
  93  *       14     ;        34     ;      div  ;   Divide check         ;   6      ;     3
  94  *       15     ;        36     ;      exf  ;   Execute              ;   2      ;     1
  95  *       16     ;        40     ;      df0  ;   Directed fault 0     ;   20     ;     6
  96  *       17     ;        42     ;      df1  ;   Directed fault 1     ;   21     ;     6
  97  *       18     ;        44     ;      df2  ;   Directed fault 2     ;   22     ;     6
  98  *       19     ;        46     ;      df3  ;   Directed fault 3     ;   23     ;     6
  99  *       20     ;        50     ;      acv  ;   Access violation     ;   24     ;     6
 100  *       21     ;        52     ;      mme2 ;   Master mode entry 2  ;   12     ;     5
 101  *       22     ;        54     ;      mme3 ;   Master mode entry 3  ;   13     ;     5
 102  *       23     ;        56     ;      mme4 ;   Master mode entry 4  ;   14     ;     5
 103  *       24     ;        60     ;      f2   ;   Fault tag 2          ;   18     ;     5
 104  *       25     ;        62     ;      f3   ;   Fault tag 3          ;   19     ;     5
 105  *       26     ;        64     ;           ;   Unassigned           ;          ;
 106  *       27     ;        66     ;           ;   Unassigned           ;          ;
 107  */
 108 
 109 #if !defined(QUIET_UNUSED)
 110 static dps8faults _faultsP[] = { // sorted by priority
 111 //      number  address  mnemonic  name                   Priority   Group
 112     {   12,     030,     "suf",    "Startup",                   1,      1,     false },
 113     {   15,     036,     "exf",    "Execute",                   2,      1,     false },
 114     {   31,     076,     "trb",    "Trouble",                   3,      2,     false },
 115     {   11,     026,     "onc",    "Operation not complete",    4,      2,     false },
 116     {    7,     016,     "luf",    "Lockup",                    5,      4,     false },
 117     {   14,     034,     "div",    "Divide check",              6,      3,     false },
 118     {   13,     032,     "ofl",    "Overflow",                  7,      3,     false },
 119     {    9,     022,     "par",    "Parity",                    8,      4,     false },
 120     {    5,     012,     "cmd",    "Command",                   9,      4,     false },
 121     {    1,       2,     "str",    "Store",                    10,      4,     false },
 122     {    2,       4,     "mme",    "Master mode entry 1",      11,      5,     false },
 123     {   21,     052,    "mme2",    "Master mode entry 2",      12,      5,     false },
 124     {   22,     054,    "mme3",    "Master mode entry 3",      13,      5,     false },
 125     {   23,     056,    "mme4",    "Master mode entry 4",      14,      5,     false },
 126     {    6,     014,     "drl",    "Derail",                   15,      5,     false },
 127     {   10,     024,     "ipr",    "Illegal procedure",        16,      5,     false },
 128     {    3,      06,      "f1",    "Fault tag 1",              17,      5,     false },
 129     {   24,     060,      "f2",    "Fault tag 2",              18,      5,     false },
 130     {   25,     062,      "f3",    "Fault tag 3",              19,      5,     false },
 131     {   16,     040,     "df0",    "Directed fault 0",         20,      6,     false },
 132     {   17,     042,     "df1",    "Directed fault 1",         21,      6,     false },
 133     {   18,     044,     "df2",    "Directed fault 2",         22,      6,     false },
 134     {   19,     046,     "df3",    "Directed fault 3",         23,      6,     false },
 135     {   20,     050,     "acv",    "Access violation",         24,      6,     false },
 136     {    8,     020,     "con",    "Connect",                  25,      7,     false },
 137     {    4,     010,     "tro",    "Timer runout",             26,      7,     false },
 138     {    0,       0,     "sdf",    "Shutdown",                 27,      7,     false },
 139     {   26,     064,     "???",    "Unassigned",               -1,     -1,     false },
 140     {   27,     066,     "???",    "Unassigned",               -1,     -1,     false },
 141     {   -1,      -1,      NULL,     NULL,                      -1,     -1,     false }
 142 };
 143 
 144 static dps8faults _faults[] = {    // sorted by number
 145 //      number  address  mnemonic  name                   Priority   Group
 146     {   0,        0,     "sdf",    "Shutdown",                 27,      7,     false },
 147     {   1,        2,     "str",    "Store",                    10,      4,     false },
 148     {   2,        4,     "mme",    "Master mode entry 1",      11,      5,     false },
 149     {   3,       06,      "f1",    "Fault tag 1",              17,      5,     false },
 150     {   4,      010,     "tro",    "Timer runout",             26,      7,     false },
 151     {   5,      012,     "cmd",    "Command",                  9,       4,     false },
 152     {   6,      014,     "drl",    "Derail",                   15,      5,     false },
 153     {   7,      016,     "luf",    "Lockup",                   5,       4,     false },
 154     {   8,      020,     "con",    "Connect",                  25,      7,     false },
 155     {   9,      022,     "par",    "Parity",                   8,       4,     false },
 156     {   10,     024,     "ipr",    "Illegal procedure",        16,      5,     false },
 157     {   11,     026,     "onc",    "Operation not complete",   4,       2,     false },
 158     {   12,     030,     "suf",    "Startup",                  1,       1,     false },
 159     {   13,     032,     "ofl",    "Overflow",                 7,       3,     false },
 160     {   14,     034,     "div",    "Divide check",             6,       3,     false },
 161     {   15,     036,     "exf",    "Execute",                  2,       1,     false },
 162     {   16,     040,     "df0",    "Directed fault 0",         20,      6,     false },
 163     {   17,     042,     "df1",    "Directed fault 1",         21,      6,     false },
 164     {   18,     044,     "df2",    "Directed fault 2",         22,      6,     false },
 165     {   19,     046,     "df3",    "Directed fault 3",         23,      6,     false },
 166     {   20,     050,     "acv",    "Access violation",         24,      6,     false },
 167     {   21,     052,    "mme2",    "Master mode entry 2",      12,      5,     false },
 168     {   22,     054,    "mme3",    "Master mode entry 3",      13,      5,     false },
 169     {   23,     056,    "mme4",    "Master mode entry 4",      14,      5,     false },
 170     {   24,     060,      "f2",    "Fault tag 2",              18,      5,     false },
 171     {   25,     062,      "f3",    "Fault tag 3",              19,      5,     false },
 172     {   26,     064,     "???",    "Unassigned",               -1,     -1,     false },
 173     {   27,     066,     "???",    "Unassigned",               -1,     -1,     false },
 174     {   28,     070,     "???",    "Unassigned",               -1,     -1,     false },
 175     {   29,     072,     "???",    "Unassigned",               -1,     -1,     false },
 176     {   30,     074,     "???",    "Unassigned",               -1,     -1,     false },
 177     {   31,     076,     "trb",    "Trouble",                   3,      2,     false },
 178     {   -1,     -1,       NULL,     NULL,                      -1,     -1,     false }
 179 };
 180 #endif /* if !defined(QUIET_UNUSED) */
 181 
 182 char * faultNames [N_FAULTS] =
 183   {
 184     "Shutdown",
 185     "Store",
 186     "Master mode entry 1",
 187     "Fault tag 1",
 188     "Timer runout",
 189     "Command",
 190     "Derail",
 191     "Lockup",
 192     "Connect",
 193     "Parity",
 194     "Illegal procedure",
 195     "Operation not complete",
 196     "Startup",
 197     "Overflow",
 198     "Divide check",
 199     "Execute",
 200     "Directed fault 0",
 201     "Directed fault 1",
 202     "Directed fault 2",
 203     "Directed fault 3",
 204     "Access violation",
 205     "Master mode entry 2",
 206     "Master mode entry 3",
 207     "Master mode entry 4",
 208     "Fault tag 2",
 209     "Fault tag 3",
 210     "Unassigned 26",
 211     "Unassigned 27",
 212     "Unassigned 28",
 213     "Unassigned 29",
 214     "Unassigned 30",
 215     "Trouble"
 216   };
 217 //bool pending_fault = false;     // true when a fault has been signalled, but not processed
 218 
 219 #if !defined(QUIET_UNUSED)
 220 static bool port_interrupts[8] = { false, false, false, false, false, false, false, false };
 221 #endif /* if !defined(QUIET_UNUSED) */
 222 
 223 //-----------------------------------------------------------------------------
 224 // ***  Constants, unchanging lookup tables, etc
 225 
 226 #if !defined (QUIET_UNUSED)
 227 static int fault2group[32] = {
 228     // from AL39, page 7-3
 229     7, 4, 5, 5, 7, 4, 5, 4,
 230     7, 4, 5, 2, 1, 3, 3, 1,
 231     6, 6, 6, 6, 6, 5, 5, 5,
 232     5, 5, 0, 0, 0, 0, 0, 2
 233 };
 234 
 235 static int fault2prio[32] = {
 236     // from AL39, page 7-3
 237     27, 10, 11, 17, 26,  9, 15,  5,
 238     25,  8, 16,  4,  1,  7,  6,  2,
 239     20, 21, 22, 23, 24, 12, 13, 14,
 240     18, 19,  0,  0,  0,  0,  0,  3
 241 };
 242 #endif /* if !defined(QUIET_UNUSED) */
 243 
 244 /*
 245  * fault handler(s).
 246  */
 247 
 248 #if defined(TESTING)
 249 // We stash a few things for debugging; they are accessed by emCall.
 250 static word18 fault_ic;
 251 static word15 fault_psr;
 252 static char fault_msg [1024];
 253 
 254 void emCallReportFault (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 255   {
 256            cpu_state_t * cpup = _cpup;
 257            sim_printf ("fault report:\r\n");
 258            sim_printf ("  fault number %d (%o)\r\n", cpu . faultNumber, cpu . faultNumber);
 259            sim_printf ("  subfault number %llu (%llo)\r\n", (unsigned long long) cpu.subFault.bits,
 260                    (unsigned long long)cpu.subFault.bits);
 261            sim_printf ("  faulting address %05o:%06o\r\n", fault_psr, fault_ic);
 262            sim_printf ("  msg %s\r\n", fault_msg);
 263   }
 264 #endif /* if defined(TESTING) */
 265 
 266 void clearFaultCycle (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
 267   {
 268     cpu . bTroubleFaultCycle = false;
 269   }
 270 
 271 /*
 272 
 273 Faults in groups 1 and 2 cause the processor to abort all functions immediately
 274 by entering a FAULT CYCLE.
 275 
 276 Faults in group 3 cause the processor to "close out" current functions without
 277 taking any irrevocable action (such as setting PTW.U in an APPEND CYCLE or
 278 modifying an indirect word in a CA CYCLE), then to discard any pending
 279 functions (such as an APPEND CYCLE needed during a CA CYCLE), and to enter a
 280 FAULT CYCLE.
 281 
 282 Faults in group 4 cause the processor to suspend overlapped operation, to
 283 complete current and pending functions for the current instruction, and then to
 284 enter a FAULT CYCLE.
 285 
 286 Faults in groups 5 or 6 are normally detected during virtual address formation
 287 and instruction decode. These faults cause the processor to suspend overlapped
 288 operation, to complete the current and pending instructions, and to enter a
 289 FAULT CYCLE. If a fault in a higher priority group is generated by the
 290 execution of the current or pending instructions, that higher priority fault
 291 will take precedence and the group 5 or 6 fault will be lost. If a group 5 or 6
 292 fault is detected during execution of the current instruction (e.g., an access
 293 violation, out of segment bounds, fault during certain interruptible EIS
 294 instructions), the instruction is considered "complete" upon detection of the
 295 fault.
 296 
 297 Faults in group 7 are held and processed (with interrupts) at the completion
 298 of the current instruction pair.
 299 
 300 Group 7 faults are inhibitable by setting bit 28 of the instruction word.
 301 
 302 Faults in groups 3 through 6 must wait for the system controller to acknowledge
 303 the last access request before entering the FAULT CYCLE.
 304 
 305 After much rumination here are my thoughts for fault processing .....
 306 
 307 For now, at least, we must remember a few things:
 308 
 309 1) We only have 1 cpu so we have few & limited async faults - shutdown, TRO,
 310 etc.
 311 2) We have no overlapping instruction execution
 312 3) Because of 2) we have no pending instructions
 313 4) We have no system controller to wait for
 314 
 315 Group 1 & 2 faults can be processed immediately and then proceed to next
 316 instruction as long as no transfer prevents us from returning from the XED pair.
 317 
 318 Group 3 faults will probably also execute immediately since a G3 fault causes
 319 "the processor to "close out" current functions without taking any irrevocable
 320 action (such as setting PTW.U in an APPEND CYCLE or modifying an indirect word
 321 in a CA CYCLE), then to discard any pending functions (such as an APPEND CYCLE
 322 needed during a CA CYCLE), and to enter a FAULT CYCLE."
 323 
 324 Group 4 faults will probably also execute immediately since a G4 fault causes
 325 "the processor to suspend overlapped operation, to complete current and pending
 326 functions for the current instruction, and then to enter a FAULT CYCLE."
 327 
 328 Group 5 & 6 faults will probably also execute immediately because "if a group 5
 329 or 6 fault is detected during execution of the current instruction (e.g., an
 330 access violation, out of segment bounds, fault during certain interruptible EIS
 331 instructions), the instruction is considered "complete" upon detection of the
 332 fault." However, remember "If a fault in a higher priority group is generated
 333 by the execution of the current or pending instructions, that higher priority
 334 fault will take precedence and the group 5 or 6 fault will be lost. If a group
 335 5 or 6 fault is detected during execution of the current instruction (e.g., an
 336 access violation, out of segment bounds, fault during certain interruptible EIS
 337 instructions), the instruction is considered "complete" upon detection of the
 338 fault."
 339 
 340 For further justification of immediate execution since "Faults in groups 3
 341 through 6 must wait for the system controller to acknowledge the last access
 342 request before entering the FAULT CYCLE."
 343 
 344 Group 7 faults will be processed after next even instruction decode instruction
 345 decode, but before instruction execution. In this way we can actually use
 346 bit-28 tp inhibit interrupts
 347 
 348 */
 349 
 350 #if defined(LOOPTRC)
 351 # include <time.h>
 352 void elapsedtime (void);
 353 #endif /* if defined(LOOPRTC) */
 354 
 355 // SCU word 1 IACHN, the processor port of a system controller illegal
 356 // action: the DPS8 reports it; an L68 does not (SM781-SM784 add the port
 357 // to the expected fault data only when RSW 2 says DPS8; SM783 10A)
 358 static word3 ia_port (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
 359   {
 360     return cpu.tweaks.l68_mode ? 0 : cpu.neaPort;
 361   }
 362 
 363 #if !defined(NEED_128)
 364 const _fault_subtype fst_zero      = (_fault_subtype) {.bits=0};
 365 const _fault_subtype fst_acv9      = (_fault_subtype) {.fault_acv_subtype=ACV9};
 366 const _fault_subtype fst_acv15     = (_fault_subtype) {.fault_acv_subtype=ACV15};
 367 const _fault_subtype fst_ill_mod   = (_fault_subtype) {.fault_ipr_subtype=FR_ILL_MOD};
 368 const _fault_subtype fst_ill_proc  = (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC};
 369 const _fault_subtype fst_ill_dig   = (_fault_subtype) {.fault_ipr_subtype=FR_ILL_DIG};
 370 const _fault_subtype fst_ill_op    = (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP};
 371 const _fault_subtype fst_str_oob   = (_fault_subtype) {.fault_str_subtype=flt_str_oob};
 372 const _fault_subtype fst_str_nea   = (_fault_subtype) {.fault_str_subtype=flt_str_nea};
 373 const _fault_subtype fst_str_ptr   = (_fault_subtype) {.fault_str_subtype=flt_str_ill_ptr};
 374 const _fault_subtype fst_cmd_lprpn = (_fault_subtype) {.fault_cmd_subtype=flt_cmd_lprpn_bits};
 375 const _fault_subtype fst_cmd_ctl   = (_fault_subtype) {.fault_cmd_subtype=flt_cmd_not_control};
 376 const _fault_subtype fst_onc_nem   = (_fault_subtype) {.fault_onc_subtype=flt_onc_nem};
 377 #endif /* if !defined(NEED_128) */
 378 // CANFAULT
 379 void doFault (_fault faultNumber, _fault_subtype subFault,
     /* [previous][next][first][last][top][bottom][index][help] */
 380               const char * faultMsg)
 381   {
 382   cpu_state_t * cpup = _cpup;
 383 
 384 #if defined(LOOPTRC)
 385 if (faultNumber == FAULT_TRO)
 386 {
 387  elapsedtime ();
 388  sim_printf (" TRO PSR:IC %05o:%06o\r\n", cpu.PPR.PSR, cpu.PPR.IC);
 389 }
 390 else if (faultNumber == FAULT_ACV)
 391 {
 392  elapsedtime ();
 393  sim_printf (" ACV %012llo PSR:IC %05o:%06o\r\n", subFault.bits, cpu.PPR.PSR, cpu.PPR.IC);
 394 }
 395 #endif /* if defined(LOOPRTC) */
 396 //if (current_running_cpu_idx)
 397     //sim_printf ("Fault %d(0%0o), sub %ld(0%lo), dfc %c, '%s'\r\n",
 398                //faultNumber, faultNumber, subFault, subFault,
 399                //cpu . bTroubleFaultCycle ? 'Y' : 'N', faultMsg);
 400 //if (current_running_cpu_idx)
 401     //sim_printf ("xde %d xdo %d\r\n", cpu.cu.xde, cpu.cu.xdo);
 402     sim_debug (DBG_FAULT, & cpu_dev,
 403                "Fault %d(0%0o), sub %"PRIu64"(0%"PRIo64"), dfc %c, '%s'\r\n",
 404                faultNumber, faultNumber, subFault.bits, subFault.bits,
 405                cpu . bTroubleFaultCycle ? 'Y' : 'N', faultMsg);
 406 #if defined(PROFILER)
 407 # if !defined(GNU_ATOMICS)
 408 #  error PROFILER requires GNU_ATOMICS
 409 # endif /* if !defined(GNU_ATOMICS) */
 410     //__atomic_add_fetch (& cpu.faults[faultNumber], 1u, __ATOMIC_ACQUIRE);
 411     (void)atomic_fetch_add_explicit(&cpu.faults[faultNumber], 1u, memory_order_acquire);
 412 #endif /* if defined(PROFILER) */
 413 #if defined(TESTING)
 414     HDBGFault (faultNumber, subFault, faultMsg, "");
 415 #endif /* if defined(TESTING) */
 416 #if !defined(SPEED)
 417     if_sim_debug (DBG_FAULT, & cpu_dev)
 418       traceInstruction (DBG_FAULT);
 419 #endif /* if !defined(SPEED) */
 420 
 421     PNL (cpu.DACVpDF = faultNumber >=  FAULT_DF0 && faultNumber <= FAULT_ACV;)
 422 
 423 #if defined(TESTING)
 424     // some debugging support stuff
 425     fault_psr = cpu . PPR.PSR;
 426     fault_ic  = cpu . PPR.IC;
 427     strcpy (fault_msg, faultMsg);
 428 #endif /* if defined(TESTING) */
 429 
 430     //if (faultNumber < 0 || faultNumber > 31)
 431     if (faultNumber & ~037U)  // quicker?
 432     {
 433         sim_printf ("fault(out-of-range): %d %llo '%s'\r\n",
 434                     faultNumber, (unsigned long long)subFault.bits,
 435                     faultMsg ? faultMsg : "?");
 436         sim_warn ("fault out-of-range\r\n");
 437         faultNumber = FAULT_TRB; // XXX Really? this is a simulator bug, not a trouble fault
 438     }
 439 
 440     cpu.faultNumber = faultNumber;
 441     cpu.subFault    = subFault;
 442     cpu.faultCnt [faultNumber] ++;
 443 
 444     // "The occurrence of a fault or interrupt sets the cache-to-register mode bit to OFF." a:AL39/cmr1
 445     CPTUR (cptUseCMR);
 446     cpu.CMR.csh_reg = 0;
 447 
 448     // Increment FCT
 449 
 450     word3 FCT = cpu.cu.APUCycleBits & MASK3;
 451     FCT = (FCT + 1u) & MASK3;
 452     cpu.cu.APUCycleBits = (word12) ((cpu.cu.APUCycleBits & 07770) | FCT);
 453 
 454     // Set fault register bits
 455 
 456     CPTUR (cptUseFR);
 457     if (faultNumber == FAULT_IPR)
 458       {
 459 
 460 
 461 
 462 
 463 
 464 
 465 
 466 
 467 
 468 
 469         cpu . faultRegister [0] |= subFault.bits;
 470 
 471       }
 472     else if (faultNumber == FAULT_ONC && subFault.fault_onc_subtype == flt_onc_nem)
 473       {
 474         cpu . faultRegister [0] |= FR_NEM;
 475       }
 476     else if (faultNumber == FAULT_STR)
 477       {
 478         if (subFault.fault_str_subtype == flt_str_oob)
 479           cpu . faultRegister [0] |= FR_OOB;
 480         //else if (subFault.fault_str_subtype == flt_str_ill_ptr)
 481           //cpu . faultRegister [0] |= ?;    // XXX
 482         //else if (subFault.fault_str_subtype == flt_str_nea)
 483           //cpu . faultRegister [0] |= ?;    // XXX
 484       }
 485     else if (faultNumber == FAULT_CON)
 486       {
 487         switch (subFault.fault_con_subtype)
 488           {
 489             case con_a:
 490               cpu . faultRegister [0] |= FR_CON_A;
 491               break;
 492             case con_b:
 493               cpu . faultRegister [0] |= FR_CON_B;
 494               break;
 495             case con_c:
 496               cpu . faultRegister [0] |= FR_CON_C;
 497               break;
 498             case con_d:
 499               cpu . faultRegister [0] |= FR_CON_D;
 500               break;
 501             default:
 502               sim_warn ("FAULT_CON can't map port %lo\r\n", (long unsigned) subFault.fault_con_subtype);
 503               break;
 504           }
 505       }
 506 
 507     // Set cu word1 fault bits
 508 
 509     cpu . cu . IRO_ISN          = 0;
 510     cpu . cu . OEB_IOC          = 0;
 511     cpu . cu . EOFF_IAIM        = 0;
 512     cpu . cu . ORB_ISP          = 0;
 513     cpu . cu . ROFF_IPR         = 0;
 514     cpu . cu . OWB_NEA          = 0;
 515     cpu . cu . WOFF_OOB         = 0;
 516     cpu . cu . NO_GA            = 0;
 517     cpu . cu . OCB              = 0;
 518     cpu . cu . OCALL            = 0;
 519     cpu . cu . BOC              = 0;
 520     DPS8M_ (cpu . cu . PTWAM_ER = 0;)
 521     cpu . cu . CRT              = 0;
 522     cpu . cu . RALR             = 0;
 523     cpu . cu . SDWAM_ER         = 0;
 524     cpu . cu . OOSB             = 0;
 525     cpu . cu . PARU             = 0;
 526     cpu . cu . PARL             = 0;
 527     cpu . cu . ONC1             = 0;
 528     cpu . cu . ONC2             = 0;
 529     cpu . cu . IA               = 0;
 530     cpu . cu . IACHN            = 0;
 531     cpu . cu . CNCHN            = (faultNumber == FAULT_CON) ? subFault.fault_con_subtype & MASK3 : 0;
 532 
 533     // Set control unit 'fault occurred during instruction fetch' flag
 534     cpu . cu . FIF       = cpu . cycle == FETCH_cycle ? 1 : 0;
 535     cpu . cu . FI_ADDR   = (word5) faultNumber;
 536 
 537     // L68 CU overlap: once an odd instruction's operand cycle has started,
 538     // the control unit has fetched the next pair, so a fault in it (directed
 539     // fault, ACV, ...) stores that pair's odd word as SCU word 7 (PA870 01A,
 540     // 02A); an MME or derail faults at decode, before that (PA885 01A)
 541     cpu.l68OddFault = cpu.tweaks.l68_mode && cpu.cycle == EXEC_cycle &&
 542                       (cpu.PPR.IC & 1) && cpu.l68PairValid &&
 543                       ! (cpu.cu.xde || cpu.cu.xdo || cpu.cu.rpt ||
 544                          cpu.cu.rd || cpu.cu.rl) &&
 545                       faultNumber != FAULT_MME && faultNumber != FAULT_MME2 &&
 546                       faultNumber != FAULT_MME3 && faultNumber != FAULT_MME4 &&
 547                       faultNumber != FAULT_DRL;
 548 
 549     // A fault in the append cycle of an instruction fetch, before the
 550     // final address (an SDW or PTW fetch), adds PI-AP to the APU status
 551     // (PA885 06A: PI-AP+PTW)
 552     if (cpu.cycle == FETCH_cycle && (cpu.cu.APUCycleBits & 03700) &&
 553         ! (cpu.cu.APUCycleBits & 00070))
 554       cpu.cu.APUCycleBits |= 04000;
 555 
 556     // XXX Under what conditions should this be set?
 557     // Assume no
 558     // Reading Multics source, it seems like Multics is setting this bit; I'm going
 559     // to assume that the h/w also sets it to 0, and the s/w has to explicitly set it on.
 560     cpu . cu . rfi = 0;
 561     if (cpu.lufRFI)       // T&D: lockup on a transfer, g7 fault at a fetch
 562       {
 563         cpu.cu.rfi = 1;
 564         cpu.lufRFI = false;
 565       }
 566     // A fault during an instruction fetch reports "refetch this
 567     // instruction" as well (PA885 10A, PA865 03A, PA885 06A); RCU of a FIF
 568     // fault refetches in any case
 569     cpu.scuRFI = cpu.cu.FIF;
 570 
 571     // A fault in the first repetition, before the instruction completes,
 572     // leaves the Xn the repetition set up unchanged (PA885 06B)
 573     if (cpu.rptXnSaved)
 574       {
 575         if (faultNumber != FAULT_OFL && faultNumber != FAULT_DIV)
 576           cpu.rX[cpu.rptXn] = cpu.rptXnOld;
 577         cpu.rptXnSaved = false;
 578       }
 579     // Likewise a later repetition: the delta dps8m added ahead for the
 580     // instructions not yet completed (PA885 06D)
 581     if ((cpu.cu.rpt || cpu.cu.rd) && cpu.cycle == EXEC_cycle &&
 582         faultNumber != FAULT_OFL && faultNumber != FAULT_DIV)
 583       for (int k = 0; k < 2; k ++)
 584         if (cpu.rptUndo[k])
 585           cpu.rX[cpu.rptUndo[k] - 1] =
 586             (cpu.rX[cpu.rptUndo[k] - 1] - cpu.cu.delta) & AMASK;
 587     cpu.rptUndo[0] = cpu.rptUndo[1] = 0;
 588 
 589     // A fault fetching the instruction(s) an rpt/rpd/rpl repeats is
 590     // reported as a fault of the repeat instruction: the IC back at it
 591     // (the word before), the repeat not started, RFI on (PA885 06A; the
 592     // ISOLTS SCU rewrite table has the same expected data)
 593     if (cpu.cycle == FETCH_cycle && cpu.cu.repeat_first &&
 594         (cpu.cu.rpt || cpu.cu.rd || cpu.cu.rl))
 595       {
 596         cpu.PPR.IC = (cpu.PPR.IC - 1) & MASK18;
 597         cpu.cu.repeat_first = 0;
 598         cpu.cu.rpt = 0;
 599         cpu.cu.rd  = 0;
 600         cpu.cu.rl  = 0;
 601         cpu.scuRFI = true;
 602       }
 603 
 604 // Try to decide if this a MIF fault (fault during EIS instruction)
 605 // EIS instructions are not used in fault/interrupt pairs, so the
 606 // only time an EIS instruction could be executing is during EXEC_cycle.
 607 // I am also assuming that only multi-word EIS instructions are of interest.
 608 // Testing faultNumber fixes ISOLTS 890-04a
 609     // fixes 890-04a and 791 / 792
 610     SC_I_MIF (cpu.cycle == EXEC_cycle &&
 611               (cpu.currentInstruction.info->ndes > 0 ||
 612                (faultNumber == FAULT_IPR && (subFault.fault_ipr_subtype & FR_ILL_OP_CONST) &&
 613                 cpu.currentInstruction.opcodeX &&
 614                 (cpu.currentInstruction.opcode & 0410) == 0)));
 615     sim_debug (DBG_TRACEEXT, & cpu_dev, "MIF %o\r\n", TST_I_MIF);
 616 
 617     // An overflow fault at the close-out of an EIS instruction reports
 618     // MIF and RFI. The T&D PAS executive (pm061 L20202) takes
 619     // MIF+RFI+^FIF as "instruction completed" and resumes after it;
 620     // with RFI off it resumes at the instruction, which overflows
 621     // again (PS810 01L). Multics's fim sets rfi+if itself, and RCU of
 622     // an overflow fault resumes after the instruction regardless.
 623     if (faultNumber == FAULT_OFL && TST_I_MIF)
 624       cpu.scuRFI = true;
 625 
 626 
 627 
 628 
 629 
 630 
 631 
 632 
 633 
 634 
 635 
 636 
 637     if (faultNumber == FAULT_ACV)
 638       {
 639         // This is annoyingly inefficient since the subFault value
 640         // is bitwise the same as the upper half of CU word1;
 641         // if the upper half were not broken out, then this would be
 642         // cpu . cu . word1_upper_half = subFault.
 643 
 644         if (subFault.fault_acv_subtype & ACV0)
 645           cpu . cu . IRO_ISN   = 1;
 646         if (subFault.fault_acv_subtype & ACV1)
 647           cpu . cu . OEB_IOC   = 1;
 648         if (subFault.fault_acv_subtype & ACV2)
 649           cpu . cu . EOFF_IAIM = 1;
 650         if (subFault.fault_acv_subtype & ACV3)
 651           cpu . cu . ORB_ISP   = 1;
 652         if (subFault.fault_acv_subtype & ACV4)
 653           cpu . cu . ROFF_IPR  = 1;
 654         if (subFault.fault_acv_subtype & ACV5)
 655           cpu . cu . OWB_NEA   = 1;
 656         if (subFault.fault_acv_subtype & ACV6)
 657           cpu . cu . WOFF_OOB  = 1;
 658         if (subFault.fault_acv_subtype & ACV7)
 659           cpu . cu . NO_GA     = 1;
 660         if (subFault.fault_acv_subtype & ACV8)
 661           cpu . cu . OCB       = 1;
 662         if (subFault.fault_acv_subtype & ACV9)
 663           cpu . cu . OCALL     = 1;
 664         if (subFault.fault_acv_subtype & ACV10)
 665           cpu . cu . BOC       = 1;
 666         if (subFault.fault_acv_subtype & ACV11)
 667           cpu . cu . PTWAM_ER  = 1;
 668         if (subFault.fault_acv_subtype & ACV12)
 669           cpu . cu . CRT       = 1;
 670         if (subFault.fault_acv_subtype & ACV13)
 671           cpu . cu . RALR      = 1;
 672         if (subFault.fault_acv_subtype & ACV14)
 673           cpu . cu . SDWAM_ER  = 1;
 674         if (subFault.fault_acv_subtype & ACV15)
 675           cpu . cu . OOSB      = 1;
 676       }
 677     else if (faultNumber == FAULT_STR)
 678       {
 679         if (subFault.fault_str_subtype == flt_str_oob)
 680           cpu . cu . WOFF_OOB  = 1;
 681         //else if (subFault.fault_str_subtype == flt_str_ill_ptr)
 682           //cpu . cu . ??? = 1; // XXX
 683         else if (subFault.fault_str_subtype == flt_str_nea)
 684           {
 685             // T&D (SM781 13A): an address in a port's window but beyond
 686             // the SCU's store: the SCU reports illegal action 02 on the
 687             // port (IACHN). In no port's window, the CPU reports it with
 688             // OWB/NEA (PA885 10B).
 689             if (cpu.tweaks.tandd_mode && ! cpu.neaNoPort)
 690               {
 691                 cpu.cu.IA    = 02;
 692                 cpu.cu.IACHN = ia_port (cpup);
 693               }
 694             else
 695               cpu . cu . OWB_NEA   = 1;
 696           }
 697         else if (subFault.fault_str_subtype == flt_str_nrdy)
 698           {
 699             cpu.cu.IA    = 013;   // store unit not ready (T&D)
 700             cpu.cu.IACHN = ia_port (cpup);
 701           }
 702       }
 703     else if (faultNumber == FAULT_PAR && subFault.bits)
 704       {
 705         // T&D: system controller illegal action code (sdpap/separ, bad
 706         // parity read); 0100/0200: the processor saw it in the upper/lower
 707         // word. No illegal action (processor only): no port.
 708         cpu.cu.IA    = (word4) (subFault.bits & 017);
 709         cpu.cu.IACHN = cpu.cu.IA ? ia_port (cpup) : 0;
 710         if (subFault.bits & 0100)
 711           cpu.cu.PARU = 1;
 712         if (subFault.bits & 0200)
 713           cpu.cu.PARL = 1;
 714       }
 715     else if (faultNumber == FAULT_IPR)
 716       {
 717         if (subFault.fault_ipr_subtype & FR_ILL_OP_CONST)
 718           cpu . cu . OEB_IOC   = 1;
 719         if (subFault.fault_ipr_subtype & FR_ILL_MOD_CONST)
 720           cpu . cu . EOFF_IAIM = 1;
 721         if (subFault.fault_ipr_subtype & FR_ILL_SLV_CONST)
 722           cpu . cu . ORB_ISP   = 1;
 723         if (subFault.fault_ipr_subtype & FR_ILL_DIG)
 724           cpu . cu . ROFF_IPR  = 1;
 725       }
 726     else if (faultNumber == FAULT_CMD)
 727       {
 728         if (subFault.fault_cmd_subtype == flt_cmd_lprpn_bits)
 729           cpu . cu . IA        = 0;
 730         else if (subFault.fault_cmd_subtype == flt_cmd_not_control)
 731           cpu . cu . IA        = 010;
 732       }
 733 
 734     L68_ (
 735       // History registers
 736       // IHRRS; AL39 pg 47
 737       // History register lock control. If this bit is set ON, set STROBE C|
 738       // (bit 30, key k) OFF, locking the history registers for all faults
 739       // including the floating faults.
 740       CPTUR (cptUseMR);
 741       if (cpu.MR.emr && cpu.MR.ihrrs)
 742         {
 743           cpu.MR.ihr = 0;
 744         }
 745     )
 746     DPS8M_ (
 747       // History registers
 748       // IHRRS; AL39 pg 49
 749       // Additional resetting of bit 30. If bit 31 = 1, the following faults also
 750       // reset bit 30:
 751       //   Lock Up
 752       //   Parity
 753       //   Command
 754       //   Store
 755       //   Illegal Procedure
 756       //   Shutdown
 757       if (cpu.MR.emr && cpu.MR.ihrrs)
 758         {
 759           if (faultNumber == FAULT_LUF ||
 760               faultNumber == FAULT_PAR ||
 761               faultNumber == FAULT_CMD ||
 762               faultNumber == FAULT_STR ||
 763               faultNumber == FAULT_IPR ||
 764               faultNumber == FAULT_SDF)
 765             {
 766               cpu.MR.ihr = 0;
 767             }
 768         }
 769       // Enable History Registers.  This bit will be reset by ... an Op Not
 770       // Complete fault. It may be reset by other faults (see bit 31).
 771       if (faultNumber == FAULT_ONC)
 772         {
 773           cpu.MR.ihr = 0;
 774         }
 775     )
 776 
 777     // If already in a FAULT CYCLE then signal trouble fault
 778 
 779     if (cpu.cycle == FAULT_EXEC_cycle)
 780       {
 781         sim_debug (DBG_CYCLE, & cpu_dev, "Changing fault number to Trouble fault\r\n");
 782 
 783         cpu.faultNumber   = FAULT_TRB;
 784         cpu.cu.FI_ADDR    = FAULT_TRB;
 785         cpu.subFault.bits = 0; // XXX ???
 786         if (cpu.bTroubleFaultCycle)
 787           {
 788 #if !defined(THREADZ) && !defined(LOCKLESS)
 789 # if !defined(PANEL68)
 790             if ((! sample_interrupts (cpup)) &&
 791                 (sim_qcount () == 0))  // XXX If clk_svc is implemented it will
 792                                        // break this logic
 793               {
 794                 sim_printf \
 795                     ("Fault cascade @0%06o with no interrupts pending and no events in queue\r\n",
 796                      cpu.PPR.IC);
 797                 sim_printf("\r\nCycles = %"PRId64"\r\n", cpu.cycleCnt);
 798                 sim_printf("\r\nInstructions = %"PRId64"\r\n", cpu.instrCnt);
 799                 //stop_reason = STOP_FLT_CASCADE;
 800                 longjmp (cpu.jmpMain, JMP_STOP);
 801               }
 802 # endif /* if !defined(PANEL68) */
 803 #endif
 804           }
 805         else
 806           {
 807 //--            f = &_faults[FAULT_TRB];
 808             cpu . bTroubleFaultCycle = true;
 809           }
 810       }
 811     else
 812       {
 813         cpu . bTroubleFaultCycle = false;
 814       }
 815 
 816     // If doInstruction faults, the instruction cycle counter doesn't get
 817     // bumped.
 818     if (cpu . cycle == EXEC_cycle)
 819       cpu.instrCnt ++;
 820 
 821     cpu . cycle = FAULT_cycle;
 822     sim_debug (DBG_CYCLE, & cpu_dev, "Setting cycle to FAULT_cycle\r\n");
 823     longjmp (cpu.jmpMain, JMP_REENTRY);
 824 #if !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
 825     /*NOTREACHED*/ /* unreachable */
 826     abort(); /* not reached */
 827 #endif
 828 }
 829 
 830 void do_FFV_fault (cpu_state_t * cpup, uint fault_number, const char * fault_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 831   {
 832     sim_debug (DBG_FAULT, & cpu_dev,
 833                "Floating fault %d '%s'\r\n",
 834                fault_number, fault_msg);
 835 #if !defined(SPEED)
 836     if_sim_debug (DBG_FAULT, & cpu_dev)
 837       traceInstruction (DBG_FAULT);
 838 #endif /* if !defined(SPEED) */
 839 
 840     if (fault_number < 1 || fault_number > 3)
 841       {
 842         sim_printf ("floating fault(out-of-range): %d '%s'\r\n",
 843                     fault_number, fault_msg ? fault_msg : "?");
 844         sim_warn ("fault out-of-range\r\n");
 845       }
 846 
 847     cpu.FFV_fault_number = fault_number;
 848     cpu.faultNumber      = fault_number;
 849 
 850     // Only the highest priority floating fault is taken (OPCODE trap, then
 851     // CU history overflow, then address match): drop the pending ones
 852     // below it (PM701 02B: an OPCODE trap with an address match pending)
 853     if (fault_number >= 1 && fault_number <= 3)
 854       {
 855         uint lower = 07u & ~((1u << fault_number) - 1u);
 856         cpu.FFV_faults        &= ~lower;
 857         cpu.FFV_faults_preset &= ~lower;
 858       }
 859 
 860     // "The occurrence of a fault or interrupt sets the
 861     // cache-to-register mode bit to OFF." a:AL39/cmr1
 862     CPTUR (cptUseCMR);
 863     cpu.CMR.csh_reg = 0;
 864 
 865     // Increment FCT
 866 
 867     word3 FCT = cpu.cu.APUCycleBits & MASK3;
 868     FCT = (FCT + 1) & MASK3;
 869     cpu.cu.APUCycleBits = (word12) ((cpu.cu.APUCycleBits & 07770) | FCT);
 870 
 871     // Set fault register bits
 872     CPTUR (cptUseFR);
 873     cpu.faultRegister [0] = 0;
 874 
 875     // Set cu word1 fault bits
 876 
 877     cpu.cu.IRO_ISN   = 0;
 878     cpu.cu.OEB_IOC   = 0;
 879     cpu.cu.EOFF_IAIM = 0;
 880     cpu.cu.ORB_ISP   = 0;
 881     cpu.cu.ROFF_IPR  = 0;
 882     cpu.cu.OWB_NEA   = 0;
 883     cpu.cu.WOFF_OOB  = 0;
 884     cpu.cu.NO_GA     = 0;
 885     cpu.cu.OCB       = 0;
 886     cpu.cu.OCALL     = 0;
 887     cpu.cu.BOC       = 0;
 888 // FFVs are L68 only, so we don't need this:
 889 //# if defined(DPS8M)
 890   //cpu.cu.PTWAM_ER  = 0;
 891 //# endif /* if defined(DPS8M) */
 892     cpu.cu.CRT       = 0;
 893     cpu.cu.RALR      = 0;
 894     cpu.cu.SDWAM_ER  = 0;
 895     cpu.cu.OOSB      = 0;
 896     cpu.cu.PARU      = 0;
 897     cpu.cu.PARL      = 0;
 898     cpu.cu.ONC1      = 0;
 899     cpu.cu.ONC2      = 0;
 900     cpu.cu.IA        = 0;
 901     cpu.cu.IACHN     = 0;
 902     cpu.cu.CNCHN     = 0;
 903 
 904     // Set control unit 'fault occurred during instruction fetch' flag
 905     cpu.cu.FIF       = 0;
 906     cpu.cu.FI_ADDR   = (word5) fault_number & MASK5;
 907 
 908     // XXX Under what conditions should this be set?
 909     // Assume no
 910     // Reading Multics source, it seems like Multics is setting this bit; I'm going
 911     // to assume that the h/w also sets it to 0, and the s/w has to explicitly set it on.
 912     cpu.cu.rfi = 0;
 913     // T&D: a floating fault at a fetch consumes the refetch request made
 914     // for it; left set, the next ordinary fault would report RFI (PS720
 915     // 02A: overflow fault after a CU-HR overflow trap)
 916     cpu.lufRFI = false;
 917 
 918 // Try to decide if this a MIF fault (fault during EIS instruction)
 919 // EIS instructions are not used in fault/interrupt pairs, so the
 920 // only time an EIS instruction could be executing is during EXEC_cycle.
 921 // I am also assuming that only multi-word EIS instructions are of interest.
 922 
 923     SC_I_MIF (cpu.cycle == EXEC_cycle &&
 924         cpu.currentInstruction.info->ndes > 0);
 925     sim_debug (DBG_TRACEEXT, & cpu_dev, "MIF %o\r\n", TST_I_MIF);
 926 
 927 
 928     // History registers
 929     // IHRRS; AL39 pg 47
 930     // History register lock control. If this bit is set ON, set STROBE C|
 931     // (bit 30, key k) OFF, locking the history registers for all faults
 932     // including the floating faults.
 933     CPTUR (cptUseMR);
 934     if (cpu.MR.emr && cpu.MR.ihrrs)
 935       {
 936         cpu.MR.ihr = 0;
 937       }
 938 
 939     if (cpu.cycle == FAULT_EXEC_cycle)
 940       {
 941         cpu.faultNumber   = FAULT_TRB;
 942         cpu.cu.FI_ADDR    = FAULT_TRB;
 943         cpu.subFault.bits = 0; // XXX ???
 944         if (cpu.bTroubleFaultCycle)
 945           {
 946 #if !defined(THREADZ) && !defined(LOCKLESS)
 947 # if !defined(PANEL68)
 948             if ((! sample_interrupts (cpup)) &&
 949                 (sim_qcount () == 0))  // XXX If clk_svc is implemented it will
 950                                        // break this logic
 951               {
 952                 sim_printf \
 953                     ("Fault cascade @0%06o with no interrupts pending and no events in queue\r\n",
 954                      cpu.PPR.IC);
 955                 sim_printf("\r\nCycles = %"PRId64"\r\n", cpu.cycleCnt);
 956                 sim_printf("\r\nInstructions = %"PRId64"\r\n", cpu.instrCnt);
 957                 longjmp (cpu.jmpMain, JMP_STOP);
 958               }
 959 # endif /* if !defined(PANEL68) */
 960 #endif /* if !defined(THREADZ) && !defined(LOCKLESS) */
 961           }
 962         else
 963           {
 964             cpu.bTroubleFaultCycle = true;
 965           }
 966         cpu.cycle = FAULT_cycle;
 967         sim_debug (DBG_CYCLE, & cpu_dev, "Setting cycle to FAULT_cycle\r\n");
 968         longjmp (cpu.jmpMain, JMP_REENTRY);
 969       }
 970     cpu.bTroubleFaultCycle = false;
 971 
 972     // If doInstruction faults, the instruction cycle counter doesn't get
 973     // bumped.
 974     if (cpu . cycle == EXEC_cycle)
 975       cpu.instrCnt ++;
 976 
 977     cpu.is_FFV = true;
 978     cpu.cycle  = FAULT_cycle;
 979     longjmp (cpu.jmpMain, JMP_REENTRY);
 980 }
 981 
 982 void dlyDoFault (_fault faultNumber, _fault_subtype subFault,
     /* [previous][next][first][last][top][bottom][index][help] */
 983                 const char * faultMsg)
 984   {
 985     cpu_state_t * cpup = _cpup;
 986     cpu.dlyFlt       = true;
 987     cpu.dlyFltNum    = faultNumber;
 988     cpu.dlySubFltNum = subFault;
 989     cpu.dlyCtx       = faultMsg;
 990   }
 991 
 992 //
 993 // return true if group 7 faults are pending ...
 994 //
 995 
 996 // Note: The DIS code assumes that the only G7 fault is TRO. Adding any
 997 // other G7 faults will potentially require changing the DIS code.
 998 
 999 bool bG7Pending (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1000   {
1001     if (cpu.tweaks.l68_mode)
1002       return cpu.g7Faults != 0 || cpu.FFV_faults != 0; // L68
1003 
1004     return cpu.g7Faults != 0; // DPS8M
1005   }
1006 
1007 bool bG7PendingNoTRO (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1008   {
1009     if (cpu.tweaks.l68_mode)
1010       return (cpu.g7Faults & (~ (1u << FAULT_TRO))) != 0 || cpu.FFV_faults != 0; // L68
1011 
1012     return (cpu.g7Faults & (~ (1u << FAULT_TRO))) != 0; // DPS8M
1013   }
1014 
1015 void setG7fault (uint cpuNo, _fault faultNo)
     /* [previous][next][first][last][top][bottom][index][help] */
1016   {
1017     cpu_state_t * cpup = &cpus[cpuNo];
1018     sim_debug (DBG_FAULT, & cpu_dev, "setG7fault CPU %d fault %d (%o)\r\n",
1019                cpuNo, faultNo, faultNo);
1020 #if defined(THREADZ) || defined(LOCKLESS)
1021     //__atomic_or_fetch (& cpup->g7FaultsPreset, (1u << faultNo), __ATOMIC_ACQUIRE);
1022     (void)atomic_fetch_or_explicit(&cpup->g7FaultsPreset, (1u << faultNo), memory_order_acquire);
1023 #else
1024     cpup->g7FaultsPreset |= (1u << faultNo);
1025 #endif
1026 #if defined(THREADZ) || defined(LOCKLESS)
1027     // An execute fault (the EXECUTE button: SIGUSR1, the XF command)
1028     // comes from outside the CPU, whose thread may be asleep in a DIS;
1029     // current_running_cpu_idx is 0 in those threads, so compare isn't
1030     // enough (T&D: EXECUTE continues the operator halts in GCOS mode)
1031     if (cpuNo != current_running_cpu_idx || faultNo == FAULT_EXF)
1032       wakeCPU(cpuNo);
1033 #endif
1034   }
1035 
1036 // The maintenance panel's EXECUTE button with the selector at EXECUTE
1037 // DATA SWITCHES (the XS command): the processor executes the instruction
1038 // in the data switches (XED Y: the pair at Y, as for the Multics "XED
1039 // 10000" bootload; T&D: continuing the bootstrap's operator halts in GCOS
1040 // mode). At EXECUTE FAULT it raises an execute fault (setG7fault
1041 // (FAULT_EXF): the XF command, SIGUSR1).
1042 void press_execute_switches (uint cpuNo)
     /* [previous][next][first][last][top][bottom][index][help] */
1043   {
1044     cpu_state_t * cpup = &cpus[cpuNo];
1045     cpup->execSwitchesReq = true;
1046 #if defined(THREADZ) || defined(LOCKLESS)
1047     wakeCPU (cpuNo);
1048 #endif
1049   }
1050 
1051 void set_FFV_fault (cpu_state_t * cpup, uint f_fault_no)
     /* [previous][next][first][last][top][bottom][index][help] */
1052   {
1053     sim_debug (DBG_FAULT, & cpu_dev, "set_FFV_fault CPU f_fault_no %u\r\n",
1054                f_fault_no);
1055     // Map fault number (2/4/6) to bit mask  01/02/04
1056     cpu.FFV_faults_preset |= 1u << ((f_fault_no / 2) - 1);
1057   }
1058 
1059 void clearTROFault (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1060   {
1061     cpu . g7Faults &= ~(1u << FAULT_TRO);
1062   }
1063 
1064 void doG7Fault (cpu_state_t * cpup, bool allowTR)
     /* [previous][next][first][last][top][bottom][index][help] */
1065   {
1066     // sim_printf ("doG7fault %08o [%"PRId64"]\r\n", cpu . g7Faults, cpu.cycleCnt);
1067     // if (cpu . g7Faults)
1068       // {
1069         // sim_debug (DBG_FAULT, & cpu_dev, "doG7Fault %08o\r\n", cpu . g7Faults);
1070       // }
1071     // According AL39,  Table 7-1. List of Faults, priority of connect is 25
1072     // and priority of Timer runout is 26, lower number means higher priority
1073 #if defined(THREADZ) || defined(LOCKLESS)
1074     lock_scu ();
1075 #endif
1076      if (cpu.g7Faults & (1u << FAULT_CON))
1077        {
1078          cpu.g7Faults &= ~(1u << FAULT_CON);
1079 
1080 #if defined(THREADZ) || defined(LOCKLESS)
1081          unlock_scu ();
1082 #endif
1083          doFault (FAULT_CON, fst_zero, "Connect");
1084        }
1085 
1086      if (allowTR && (cpu.g7Faults & (1u << FAULT_TRO)))
1087        {
1088          cpu . g7Faults &= ~(1u << FAULT_TRO);
1089 
1090          //sim_printf("timer runout %12o\r\n",cpu.PPR.IC);
1091 #if defined(THREADZ) || defined(LOCKLESS)
1092          unlock_scu ();
1093 #endif
1094          doFault (FAULT_TRO, fst_zero, "Timer runout");
1095        }
1096 
1097      // Strictly speaking EXF isn't a G7 fault, but if we treat is as one,
1098      // we are allowing the current instruction to complete, simplifying
1099      // implementation
1100      if (cpu . g7Faults & (1u << FAULT_EXF))
1101        {
1102          cpu . g7Faults &= ~(1u << FAULT_EXF);
1103 
1104 #if defined(THREADZ) || defined(LOCKLESS)
1105          unlock_scu ();
1106 #endif
1107          doFault (FAULT_EXF, fst_zero, "Execute fault");
1108        }
1109 
1110      if (cpu.tweaks.l68_mode) {  // L68
1111        if (cpu.FFV_faults & 1u)  // FFV + 2 OC TRAP
1112          {
1113            cpu.FFV_faults &= ~1u;
1114 #if defined(THREADZ) || defined(LOCKLESS)
1115            unlock_scu ();
1116 #endif
1117            do_FFV_fault (cpup, 1, "OC TRAP");
1118          }
1119        if (cpu.FFV_faults & 2u)  // FFV + 4 CU HISTORY OVERFLOW TRAP
1120          {
1121            cpu.FFV_faults &= ~2u;
1122 #if defined(THREADZ) || defined(LOCKLESS)
1123            unlock_scu ();
1124 #endif
1125            do_FFV_fault (cpup, 2, "CU HIST OVF TRAP");
1126          }
1127        if (cpu.FFV_faults & 4u)  // FFV + 6 ADR TRAP
1128          {
1129            cpu.FFV_faults &= ~4u;
1130 #if defined(THREADZ) || defined(LOCKLESS)
1131            unlock_scu ();
1132 #endif
1133            do_FFV_fault (cpup, 3, "ADR TRAP");
1134          }
1135      }
1136 #if defined(THREADZ) || defined(LOCKLESS)
1137      unlock_scu ();
1138 #endif
1139      doFault (FAULT_TRB, (_fault_subtype) {.bits=cpu.g7Faults}, "Dazed and confused in doG7Fault");
1140   }
1141 
1142 void advanceG7Faults (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1143   {
1144 // This is potentially stale cached, but we don't care, we will see eventually ZZZ
1145     if (!cpu.g7FaultsPreset && !cpu.FFV_faults_preset)
1146       return;
1147 
1148 #if defined(THREADZ) || defined(LOCKLESS)
1149     lock_scu ();
1150     uint zero = 0;
1151     //__atomic_exchange (& cpu.g7FaultsPreset, & zero, & cpu.g7Faults, __ATOMIC_ACQUIRE);
1152     cpu.g7Faults = atomic_exchange_explicit(&cpu.g7FaultsPreset, zero, memory_order_acquire);
1153 #else
1154     cpu.g7Faults       |= cpu.g7FaultsPreset;
1155     cpu.g7FaultsPreset  = 0;
1156 #endif
1157     L68_ (
1158       cpu.FFV_faults |= cpu.FFV_faults_preset;
1159       cpu.FFV_faults_preset = 0;
1160     )
1161 #if defined(THREADZ) || defined(LOCKLESS)
1162     unlock_scu ();
1163 #endif
1164   }

/* [previous][next][first][last][top][bottom][index][help] */