1 /*
2  * Copyright (c) 2007-2013 Michael Mondy
3  * Copyright (c) 2012-2016 Harry Reed
4  * Copyright (c) 2013-2016 Charles Anthony
5  * Copyright (c) 2017 Michal Tomek
6  * Copyright (c) 2021 The DPS8M Development Team
7  *
8  * All rights reserved.
9  *
10  * This software is made available under the terms of the ICU
11  * License, version 1.8.1 or later.  For more details, see the
12  * LICENSE.md file at the top-level directory of this distribution.
13  */
14 
15 #include <stdio.h>
16 
17 #include "dps8.h"
18 #include "dps8_sys.h"
19 #include "dps8_faults.h"
20 #include "dps8_scu.h"
21 #include "dps8_iom.h"
22 #include "dps8_cable.h"
23 #include "dps8_cpu.h"
24 #include "dps8_append.h"
25 #include "dps8_ins.h"
26 #include "dps8_utils.h"
27 #if defined(THREADZ) || defined(LOCKLESS)
28 # include "threadz.h"
29 #endif
30 
31 #define DBG_CTR cpu.cycleCnt
32 
33 /*
34  FAULT RECOGNITION
35  For the discussion following, the term "function" is defined as a major processor functional cycle. Examples are: APPEND CYCLE, CA CYCLE, INSTRUCTION FETCH CYCLE, OPERAND STORE CYCLE, DIVIDE EXECUTION CYCLE. Some of these cycles are discussed in various sections of this manual.
36  Faults in groups 1 and 2 cause the processor to abort all functions immediately by entering a FAULT CYCLE.
37  Faults in group 3 cause the processor to "close out" current functions without taking any irrevocable action (such as setting PTW.U in an APPEND CYCLE or modifying an indirect word in a CA CYCLE), then to discard any pending functions (such as an APPEND CYCLE needed during a CA CYCLE), and to enter a FAULT CYCLE.
38  Faults in group 4 cause the processor to suspend overlapped operation, to complete current and pending functions for the current instruction, and then to enter a FAULT CYCLE.
39  Faults in groups 5 or 6 are normally detected during virtual address formation and instruction decode. These faults cause the processor to suspend overlapped operation, to complete the current and pending instructions, and to enter a FAULT CYCLE. If a fault in a higher priority group is generated by the execution of the current or pending instructions, that higher priority fault will take precedence and the group 5 or 6 fault will be lost. If a group 5 or 6 fault is detected during execution of the current instruction (e.g., an access violation, out of segment bounds, fault
40  
41  during certain interruptible EIS instructions), the instruction is considered "complete" upon detection of the fault.
42  Faults in group 7 are held and processed (with interrupts) at the completion of the current instruction pair. Group 7 faults are inhibitable by setting bit 28 of the instruction word.
43  Faults in groups 3 through 6 must wait for the system controller to acknowledge the last access request before entering the FAULT CYCLE.
44  */
45 
46 /*
47 
48                                 Table 7-1. List of Faults
49 
50  Decimal fault     Octal (1)      Fault   Fault name            Priority    Group
51      number      fault address   mnemonic
52         0      ;         0     ;      sdf  ;   Shutdown             ;   27     ;     7
53         1      ;         2     ;      str  ;   Store                ;   10     ;     4
54         2      ;         4     ;      mme  ;   Master mode entry 1  ;   11     ;     5
55         3      ;         6     ;      f1   ;   Fault tag 1          ;   17     ;     5
56         4      ;        10     ;      tro  ;   Timer runout         ;   26     ;     7
57         5      ;        12     ;      cmd  ;   Command              ;   9      ;     4
58         6      ;        14     ;      drl  ;   Derail               ;   15     ;     5
59         7      ;        16     ;      luf  ;   Lockup               ;   5      ;     4
60         8      ;        20     ;      con  ;   Connect              ;   25     ;     7
61         9      ;        22     ;      par  ;   Parity               ;   8      ;     4
62         10     ;        24     ;      ipr  ;   Illegal procedure    ;   16     ;     5
63         11     ;        26     ;      onc  ;   Operation not complete ; 4      ;     2
64         12     ;        30     ;      suf  ;   Startup              ;   1      ;     1
65         13     ;        32     ;      ofl  ;   Overflow             ;   7      ;     3
66         14     ;        34     ;      div  ;   Divide check         ;   6      ;     3
67         15     ;        36     ;      exf  ;   Execute              ;   2      ;     1
68         16     ;        40     ;      df0  ;   Directed fault 0     ;   20     ;     6
69         17     ;        42     ;      df1  ;   Directed fault 1     ;   21     ;     6
70         18     ;        44     ;      df2  ;   Directed fault 2     ;   22     ;     6
71         19     ;        46     ;      df3  ;   Directed fault 3     ;   23     ;     6
72         20     ;        50     ;      acv  ;   Access violation     ;   24     ;     6
73         21     ;        52     ;      mme2 ;   Master mode entry 2  ;   12     ;     5
74         22     ;        54     ;      mme3 ;   Master mode entry 3  ;   13     ;     5
75         23     ;        56     ;      mme4 ;   Master mode entry 4  ;   14     ;     5
76         24     ;        60     ;      f2   ;   Fault tag 2          ;   18     ;     5
77         25     ;        62     ;      f3   ;   Fault tag 3          ;   19     ;     5
78         26     ;        64     ;           ;   Unassigned           ;          ;
79         27     ;        66     ;           ;   Unassigned           ;          ;
80 
81 */
82 
83 #ifndef QUIET_UNUSED
84 static dps8faults _faultsP[] = { // sorted by priority
85 //  number  address  mnemonic   name                 Priority    Group
86     {   12,     030,    "suf",  "Startup",                  1,       1,     false },
87     {   15,     036,    "exf",  "Execute",                  2,       1,     false },
88     {   31,     076,    "trb",  "Trouble",                  3,       2,     false },
89     {   11,     026,    "onc",  "Operation not complete",       4,           2,     false },
90     {   7,      016,    "luf",  "Lockup",                       5,           4,     false },
91     {   14,     034,    "div",  "Divide check",                 6,           3,     false },
92     {   13,     032,    "ofl",  "Overflow",                     7,           3,     false },
93     {   9,      022,    "par",  "Parity",                       8,           4,     false },
94     {   5,      012,    "cmd",  "Command",                      9,           4,     false },
95     {   1,       2 ,    "str",  "Store",                        10,          4,     false },
96     {   2,       4 ,    "mme",  "Master mode entry 1",          11,          5,     false },
97     {   21,     052,    "mme2", "Master mode entry 2",          12,          5,     false },
98     {   22,     054,    "mme3", "Master mode entry 3",          13,          5,     false },
99     {   23,     056,    "mme4", "Master mode entry 4",          14,          5,     false },
100     {   6,      014,    "drl",  "Derail",                       15,          5,     false },
101     {   10,     024,    "ipr",  "Illegal procedure",            16,          5,     false },
102     {   3,       06,    "f1",   "Fault tag 1",                  17,          5,     false },
103     {   24,     060,    "f2",   "Fault tag 2",                  18,          5,     false },
104     {   25,     062,    "f3",   "Fault tag 3",                  19,          5,     false },
105     {   16,     040,    "df0",  "Directed fault 0",             20,          6,     false },
106     {   17,     042,    "df1",  "Directed fault 1",             21,          6,     false },
107     {   18,     044,    "df2",  "Directed fault 2",             22,          6,     false },
108     {   19,     046,    "df3",  "Directed fault 3",             23,          6,     false },
109     {   20,     050,    "acv",  "Access violation",             24,          6,     false },
110     {   8,      020,    "con",  "Connect",                      25,          7,     false },
111     {   4,      010,    "tro",  "Timer runout",                 26,          7,     false },
112     {   0,       0 ,    "sdf",  "Shutdown",                     27,          7,     false },
113     {   26,     064,    "???",  "Unassigned",               -1,     -1,     false },
114     {   27,     066,    "???",  "Unassigned",               -1,     -1,     false },
115     {   -1,     -1,     NULL,   NULL,                       -1,     -1,     false }
116 };
117 #endif
118 #ifndef QUIET_UNUSED
119 static dps8faults _faults[] = {    // sorted by number
120     //  number  address  mnemonic   name                 Priority    Group
121     {   0,       0 ,    "sdf",  "Shutdown",                     27,          7,     false },
122     {   1,       2 ,    "str",  "Store",                        10,          4,     false },
123     {   2,       4 ,    "mme",  "Master mode entry 1",          11,          5,     false },
124     {   3,       06,    "f1",   "Fault tag 1",                  17,          5,     false },
125     {   4,      010,    "tro",  "Timer runout",                 26,          7,     false },
126     {   5,      012,    "cmd",  "Command",                      9,           4,     false },
127     {   6,      014,    "drl",  "Derail",                       15,          5,     false },
128     {   7,      016,    "luf",  "Lockup",                       5,           4,     false },
129     {   8,      020,    "con",  "Connect",                      25,          7,     false },
130     {   9,      022,    "par",  "Parity",                       8,           4,     false },
131     {   10,     024,    "ipr",  "Illegal procedure",            16,          5,     false },
132     {   11,     026,    "onc",  "Operation not complete",       4,           2,     false },
133     {   12,     030,    "suf",  "Startup",                  1,       1,     false },
134     {   13,     032,    "ofl",  "Overflow",                     7,           3,     false },
135     {   14,     034,    "div",  "Divide check",                 6,           3,     false },
136     {   15,     036,    "exf",  "Execute",                  2,       1,     false },
137     {   16,     040,    "df0",  "Directed fault 0",             20,          6,     false },
138     {   17,     042,    "df1",  "Directed fault 1",             21,          6,     false },
139     {   18,     044,    "df2",  "Directed fault 2",             22,          6,     false },
140     {   19,     046,    "df3",  "Directed fault 3",             23,          6,     false },
141     {   20,     050,    "acv",  "Access violation",             24,          6,     false },
142     {   21,     052,    "mme2", "Master mode entry 2",          12,          5,     false },
143     {   22,     054,    "mme3", "Master mode entry 3",          13,          5,     false },
144     {   23,     056,    "mme4", "Master mode entry 4",          14,          5,     false },
145     {   24,     060,    "f2",   "Fault tag 2",                  18,          5,     false },
146     {   25,     062,    "f3",   "Fault tag 3",                  19,          5,     false },
147     {   26,     064,    "???",  "Unassigned",               -1,     -1,     false },
148     {   27,     066,    "???",  "Unassigned",               -1,     -1,     false },
149     {   28,     070,    "???",  "Unassigned",               -1,     -1,     false },
150     {   29,     072,    "???",  "Unassigned",               -1,     -1,     false },
151     {   30,     074,    "???",  "Unassigned",               -1,     -1,     false },
152     {   31,     076,    "trb",  "Trouble",                  3,       2,     false },
153 
154     {   -1,     -1,     NULL,   NULL,                       -1,     -1,     false }
155 };
156 #endif
157 
158 char * faultNames [N_FAULTS] =
159   {
160     "Shutdown",
161     "Store",
162     "Master mode entry 1",
163     "Fault tag 1",
164     "Timer runout",
165     "Command",
166     "Derail",
167     "Lockup",
168     "Connect",
169     "Parity",
170     "Illegal procedure",
171     "Operation not complete",
172     "Startup",
173     "Overflow",
174     "Divide check",
175     "Execute",
176     "Directed fault 0",
177     "Directed fault 1",
178     "Directed fault 2",
179     "Directed fault 3",
180     "Access violation",
181     "Master mode entry 2",
182     "Master mode entry 3",
183     "Master mode entry 4",
184     "Fault tag 2",
185     "Fault tag 3",
186     "Unassigned 26",
187     "Unassigned 27",
188     "Unassigned 28",
189     "Unassigned 29",
190     "Unassigned 30",
191     "Trouble"
192   };
193 //bool pending_fault = false;     // true when a fault has been signalled, but not processed
194 
195 
196 #ifndef QUIET_UNUSED
197 static bool port_interrupts[8] = {false, false, false, false, false, false, false, false };
198 #endif
199 
200 //-----------------------------------------------------------------------------
201 // ***  Constants, unchanging lookup tables, etc
202 
203 #ifndef QUIET_UNUSED
204 static int fault2group[32] = {
205     // from AL39, page 7-3
206     7, 4, 5, 5, 7, 4, 5, 4,
207     7, 4, 5, 2, 1, 3, 3, 1,
208     6, 6, 6, 6, 6, 5, 5, 5,
209     5, 5, 0, 0, 0, 0, 0, 2
210 };
211 
212 static int fault2prio[32] = {
213     // from AL39, page 7-3
214     27, 10, 11, 17, 26,  9, 15,  5,
215     25,  8, 16,  4,  1,  7,  6,  2,
216     20, 21, 22, 23, 24, 12, 13, 14,
217     18, 19,  0,  0,  0,  0,  0,  3
218 };
219 #endif
220 
221 /*
222  * fault handler(s).
223  */
224 
225 #ifdef TESTING
226 // We stash a few things for debugging; they are accessed by emCall.
227 static word18 fault_ic;
228 static word15 fault_psr;
229 static char fault_msg [1024];
230 
231 
emCallReportFault(void)232 void emCallReportFault (void)
233   {
234            sim_printf ("fault report:\n");
235            sim_printf ("  fault number %d (%o)\n", cpu . faultNumber, cpu . faultNumber);
236            sim_printf ("  subfault number %"PRIu64" (%"PRIo64")\n", cpu.subFault.bits, cpu.subFault.bits);
237            sim_printf ("  faulting address %05o:%06o\n", fault_psr, fault_ic);
238            sim_printf ("  msg %s\n", fault_msg);
239   }
240 #endif
241 
242 
clearFaultCycle(void)243 void clearFaultCycle (void)
244   {
245     cpu . bTroubleFaultCycle = false;
246   }
247 
248 /*
249 
250 Faults in groups 1 and 2 cause the processor to abort all functions immediately
251 by entering a FAULT CYCLE.
252 
253 Faults in group 3 cause the processor to "close out" current functions without
254 taking any irrevocable action (such as setting PTW.U in an APPEND CYCLE or
255 modifying an indirect word in a CA CYCLE), then to discard any pending
256 functions (such as an APPEND CYCLE needed during a CA CYCLE), and to enter a
257 FAULT CYCLE.
258 
259 Faults in group 4 cause the processor to suspend overlapped operation, to
260 complete current and pending functions for the current instruction, and then to
261 enter a FAULT CYCLE.
262 
263 Faults in groups 5 or 6 are normally detected during virtual address formation
264 and instruction decode. These faults cause the processor to suspend overlapped
265 operation, to complete the current and pending instructions, and to enter a
266 FAULT CYCLE. If a fault in a higher priority group is generated by the
267 execution of the current or pending instructions, that higher priority fault
268 will take precedence and the group 5 or 6 fault will be lost. If a group 5 or 6
269 fault is detected during execution of the current instruction (e.g., an access
270 violation, out of segment bounds, fault during certain interruptible EIS
271 instructions), the instruction is considered "complete" upon detection of the
272 fault.
273 
274 Faults in group 7 are held and processed (with interrupts) at the completion
275 of the current instruction pair.
276 
277 Group 7 faults are inhibitable by setting bit 28 of the instruction word.
278 
279 Faults in groups 3 through 6 must wait for the system controller to acknowledge
280 the last access request before entering the FAULT CYCLE.
281 
282 After much rumination here are my thoughts for fault processing .....
283 
284 For now, at least, we must remember a few things:
285 
286 1) We only have 1 cpu so we have few & limited async faults - shutdown, TRO,
287 etc.
288 2) We have no overlapping instruction execution
289 3) Becuase of 2) we have no pending instructions
290 4) We have no system controller to wait for
291 
292 Group 1 & 2 faults can be processed immediately and then proceed to next
293 instruction as long as no transfer prevents us from returing from the XED pair.
294 
295 Group 3 faults will probably also execute immediately since a G3 fault causes
296 "the processor to "close out" current functions without taking any irrevocable
297 action (such as setting PTW.U in an APPEND CYCLE or modifying an indirect word
298 in a CA CYCLE), then to discard any pending functions (such as an APPEND CYCLE
299 needed during a CA CYCLE), and to enter a FAULT CYCLE."
300 
301 Group 4 faults will probably also execute immediately since a G4 fault causes
302 "the processor to suspend overlapped operation, to complete current and pending
303 functions for the current instruction, and then to enter a FAULT CYCLE."
304 
305 Group 5 & 6 faults will probably also execute immediately because "if a group 5
306 or 6 fault is detected during execution of the current instruction (e.g., an
307 access violation, out of segment bounds, fault during certain interruptible EIS
308 instructions), the instruction is considered "complete" upon detection of the
309 fault." However, remember "If a fault in a higher priority group is generated
310 by the execution of the current or pending instructions, that higher priority
311 fault will take precedence and the group 5 or 6 fault will be lost. If a group
312 5 or 6 fault is detected during execution of the current instruction (e.g., an
313 access violation, out of segment bounds, fault during certain interruptible EIS
314 instructions), the instruction is considered "complete" upon detection of the
315 fault."
316 
317 For furter justification of immediate execution since "Faults in groups 3
318 through 6 must wait for the system controller to acknowledge the last access
319 request before entering the FAULT CYCLE."
320 
321 Group 7 faults will be processed after next even instruction decode instruction
322 decode, but before instruction execution. In this way we can actually use
323 bit-28 tp inhibit interrupts
324 
325 */
326 
327 #ifdef LOOPTRC
328 # include <time.h>
329 void elapsedtime (void);
330 #endif
331 
332 #ifndef NEED_128
333 const _fault_subtype fst_zero = (_fault_subtype) {.bits=0};
334 const _fault_subtype fst_acv9 = (_fault_subtype) {.fault_acv_subtype=ACV9};
335 const _fault_subtype fst_acv15 = (_fault_subtype) {.fault_acv_subtype=ACV15};
336 const _fault_subtype fst_ill_mod = (_fault_subtype) {.fault_ipr_subtype=FR_ILL_MOD};
337 const _fault_subtype fst_ill_proc = (_fault_subtype) {.fault_ipr_subtype=FR_ILL_PROC};
338 const _fault_subtype fst_ill_dig = (_fault_subtype) {.fault_ipr_subtype=FR_ILL_DIG};
339 const _fault_subtype fst_ill_op = (_fault_subtype) {.fault_ipr_subtype=FR_ILL_OP};
340 const _fault_subtype fst_str_oob = (_fault_subtype) {.fault_str_subtype=flt_str_oob};
341 const _fault_subtype fst_str_nea = (_fault_subtype) {.fault_str_subtype=flt_str_nea};
342 const _fault_subtype fst_str_ptr = (_fault_subtype) {.fault_str_subtype=flt_str_ill_ptr};
343 const _fault_subtype fst_cmd_lprpn = (_fault_subtype) {.fault_cmd_subtype=flt_cmd_lprpn_bits};
344 const _fault_subtype fst_cmd_ctl = (_fault_subtype) {.fault_cmd_subtype=flt_cmd_not_control};
345 const _fault_subtype fst_onc_nem = (_fault_subtype) {.fault_onc_subtype=flt_onc_nem};
346 #endif
347 // CANFAULT
doFault(_fault faultNumber,_fault_subtype subFault,const char * faultMsg)348 void doFault (_fault faultNumber, _fault_subtype subFault,
349               const char * faultMsg)
350   {
351 #ifdef LOOPTRC
352 if (faultNumber == FAULT_TRO)
353 {
354  elapsedtime ();
355  sim_printf (" TRO PSR:IC %05o:%06o\r\n", cpu.PPR.PSR, cpu.PPR.IC);
356 }
357 else if (faultNumber == FAULT_ACV)
358 {
359  elapsedtime ();
360  sim_printf (" ACV %012llo PSR:IC %05o:%06o\r\n", subFault.bits, cpu.PPR.PSR, cpu.PPR.IC);
361 }
362 #endif
363 //if (current_running_cpu_idx)
364     //sim_printf ("Fault %d(0%0o), sub %ld(0%lo), dfc %c, '%s'\n",
365                //faultNumber, faultNumber, subFault, subFault,
366                //cpu . bTroubleFaultCycle ? 'Y' : 'N', faultMsg);
367 //if (current_running_cpu_idx)
368     //sim_printf ("xde %d xdo %d\n", cpu.cu.xde, cpu.cu.xdo);
369     sim_debug (DBG_FAULT, & cpu_dev,
370                "Fault %d(0%0o), sub %"PRIu64"(0%"PRIo64"), dfc %c, '%s'\n",
371                faultNumber, faultNumber, subFault.bits, subFault.bits,
372                cpu . bTroubleFaultCycle ? 'Y' : 'N', faultMsg);
373 #ifdef PROFILER
374     __atomic_add_fetch (& cpu.faults[faultNumber], 1u, __ATOMIC_ACQUIRE);
375 #endif
376 #ifdef TESTING
377     HDBGFault (faultNumber, subFault, faultMsg, "");
378 #endif
379 #ifndef SPEED
380     if_sim_debug (DBG_FAULT, & cpu_dev)
381       traceInstruction (DBG_FAULT);
382 #endif
383 
384     PNL (cpu.DACVpDF = faultNumber >=  FAULT_DF0 && faultNumber <= FAULT_ACV;)
385 
386 #ifdef TESTING
387     // some debugging support stuff
388     fault_psr = cpu . PPR.PSR;
389     fault_ic = cpu . PPR.IC;
390     strcpy (fault_msg, faultMsg);
391 #endif
392 
393     //if (faultNumber < 0 || faultNumber > 31)
394     if (faultNumber & ~037U)  // quicker?
395     {
396         sim_printf ("fault(out-of-range): %d %"PRIo64" '%s'\n",
397                     faultNumber, subFault.bits, faultMsg ? faultMsg : "?");
398         sim_warn ("fault out-of-range\n");
399         faultNumber = FAULT_TRB;
400     }
401 
402     cpu.faultNumber = faultNumber;
403     cpu.subFault = subFault;
404     cpu.faultCnt [faultNumber] ++;
405 
406     // "The occurrence of a fault or interrupt sets the cache-to-register mode bit to OFF." a:AL39/cmr1
407     CPTUR (cptUseCMR);
408     cpu.CMR.csh_reg = 0;
409 
410     // Increment FCT
411 
412     word3 FCT = cpu.cu.APUCycleBits & MASK3;
413     FCT = (FCT + 1u) & MASK3;
414     cpu.cu.APUCycleBits = (word12) ((cpu.cu.APUCycleBits & 07770) | FCT);
415 
416     // Set fault register bits
417 
418     CPTUR (cptUseFR);
419     if (faultNumber == FAULT_IPR)
420       {
421 #if 0
422         if (subFault == flt_ipr_ill_op)
423           cpu . faultRegister [0] |= FR_ILL_OP;
424         else if (subFault == flt_ipr_ill_mod)
425           cpu . faultRegister [0] |= FR_ILL_MOD;
426         else if (subFault == flt_ipr_ill_dig)
427           cpu . faultRegister [0] |= FR_ILL_DIG;
428         else /* if (subFault == flt_ipr_ill_proc) */ // and all others
429           cpu . faultRegister [0] |= FR_ILL_PROC;
430 #else
431         cpu . faultRegister [0] |= subFault.bits;
432 #endif
433       }
434     else if (faultNumber == FAULT_ONC && subFault.fault_onc_subtype == flt_onc_nem)
435       {
436         cpu . faultRegister [0] |= FR_NEM;
437       }
438     else if (faultNumber == FAULT_STR)
439       {
440         if (subFault.fault_str_subtype == flt_str_oob)
441           cpu . faultRegister [0] |= FR_OOB;
442         //else if (subFault.fault_str_subtype == flt_str_ill_ptr)
443           //cpu . faultRegister [0] |= ?;    // XXX
444         //else if (subFault.fault_str_subtype == flt_str_nea)
445           //cpu . faultRegister [0] |= ?;    // XXX
446       }
447     else if (faultNumber == FAULT_CON)
448       {
449         switch (subFault.fault_con_subtype)
450           {
451             case con_a:
452               cpu . faultRegister [0] |= FR_CON_A;
453               break;
454             case con_b:
455               cpu . faultRegister [0] |= FR_CON_B;
456               break;
457             case con_c:
458               cpu . faultRegister [0] |= FR_CON_C;
459               break;
460             case con_d:
461               cpu . faultRegister [0] |= FR_CON_D;
462               break;
463             default:
464               sim_warn ("FAULT_CON can't map port %lo\n", (long unsigned) subFault.fault_con_subtype);
465               break;
466           }
467       }
468 
469     // Set cu word1 fault bits
470 
471     cpu . cu . IRO_ISN = 0;
472     cpu . cu . OEB_IOC = 0;
473     cpu . cu . EOFF_IAIM = 0;
474     cpu . cu . ORB_ISP = 0;
475     cpu . cu . ROFF_IPR = 0;
476     cpu . cu . OWB_NEA = 0;
477     cpu . cu . WOFF_OOB = 0;
478     cpu . cu . NO_GA = 0;
479     cpu . cu . OCB = 0;
480     cpu . cu . OCALL = 0;
481     cpu . cu . BOC = 0;
482 #ifdef DPS8M
483     cpu . cu . PTWAM_ER = 0;
484 #endif
485     cpu . cu . CRT = 0;
486     cpu . cu . RALR = 0;
487     cpu . cu . SDWAM_ER = 0;
488     cpu . cu . OOSB = 0;
489     cpu . cu . PARU = 0;
490     cpu . cu . PARL = 0;
491     cpu . cu . ONC1 = 0;
492     cpu . cu . ONC2 = 0;
493     cpu . cu . IA = 0;
494     cpu . cu . IACHN = 0;
495     cpu . cu . CNCHN = (faultNumber == FAULT_CON) ? subFault.fault_con_subtype & MASK3 : 0;
496 
497     // Set control unit 'fault occured during instruction fetch' flag
498     cpu . cu . FIF = cpu . cycle == FETCH_cycle ? 1 : 0;
499     cpu . cu . FI_ADDR = (word5) faultNumber;
500 
501     // XXX Under what conditions should this be set?
502     // Assume no
503     // Reading Multics source, it seems like Multics is setting this bit; I'm going
504     // to assume that the h/w also sets it to 0, and the s/w has to explicitly set it on.
505     cpu . cu . rfi = 0;
506 
507 // Try to decide if this a MIF fault (fault during EIS instruction)
508 // EIS instructions are not used in fault/interrupt pairs, so the
509 // only time an EIS instruction could be executing is during EXEC_cycle.
510 // I am also assuming that only multi-word EIS instructions are of interest.
511 // Testing faultNumber fixes ISOLTS 890-04a
512     // fixes 890-04a and 791 / 792
513     SC_I_MIF (cpu.cycle == EXEC_cycle &&
514               (cpu.currentInstruction.info->ndes > 0 ||
515                (faultNumber == FAULT_IPR && (subFault.fault_ipr_subtype & FR_ILL_OP) &&
516                 cpu.currentInstruction.opcodeX &&
517                 (cpu.currentInstruction.opcode & 0410) == 0)));
518     sim_debug (DBG_TRACEEXT, & cpu_dev, "MIF %o\n", TST_I_MIF);
519 #if 0
520 sim_debug (DBG_FAULT, & cpu_dev, "cycle %u ndes %u fn %u v %u\n", cpu.cycle, cpu.currentInstruction.info->ndes, faultNumber, (cpu . cycle == EXEC_cycle && cpu . currentInstruction . info -> ndes > 0) || faultNumber == FAULT_IPR);
521     SC_I_MIF (cpu . cycle == EXEC_cycle &&
522         cpu . currentInstruction . info -> ndes > 0);
523     //SC_I_MIF ((cpu . cycle == EXEC_cycle &&
524         //cpu . currentInstruction . info -> ndes > 0) ||
525         //faultNumber == FAULT_IPR);
526 #endif
527 
528     if (faultNumber == FAULT_ACV)
529       {
530         // This is annoyingly inefficent since the subFault value
531         // is bitwise the same as the upper half of CU word1;
532         // if the upperhalf were not broken out, then this would be
533         // cpu . cu . word1_upper_half = subFault.
534 
535         if (subFault.fault_acv_subtype & ACV0)
536           cpu . cu . IRO_ISN = 1;
537         if (subFault.fault_acv_subtype & ACV1)
538           cpu . cu . OEB_IOC = 1;
539         if (subFault.fault_acv_subtype & ACV2)
540           cpu . cu . EOFF_IAIM = 1;
541         if (subFault.fault_acv_subtype & ACV3)
542           cpu . cu . ORB_ISP = 1;
543         if (subFault.fault_acv_subtype & ACV4)
544           cpu . cu . ROFF_IPR = 1;
545         if (subFault.fault_acv_subtype & ACV5)
546           cpu . cu . OWB_NEA = 1;
547         if (subFault.fault_acv_subtype & ACV6)
548           cpu . cu . WOFF_OOB = 1;
549         if (subFault.fault_acv_subtype & ACV7)
550           cpu . cu . NO_GA = 1;
551         if (subFault.fault_acv_subtype & ACV8)
552           cpu . cu . OCB = 1;
553         if (subFault.fault_acv_subtype & ACV9)
554           cpu . cu . OCALL = 1;
555         if (subFault.fault_acv_subtype & ACV10)
556           cpu . cu . BOC = 1;
557         if (subFault.fault_acv_subtype & ACV11)
558           cpu . cu . PTWAM_ER = 1;
559         if (subFault.fault_acv_subtype & ACV12)
560           cpu . cu . CRT = 1;
561         if (subFault.fault_acv_subtype & ACV13)
562           cpu . cu . RALR = 1;
563         if (subFault.fault_acv_subtype & ACV14)
564           cpu . cu . SDWAM_ER = 1;
565         if (subFault.fault_acv_subtype & ACV15)
566           cpu . cu . OOSB = 1;
567       }
568     else if (faultNumber == FAULT_STR)
569       {
570         if (subFault.fault_str_subtype == flt_str_oob)
571           cpu . cu . WOFF_OOB = 1;
572         //else if (subFault.fault_str_subtype == flt_str_ill_ptr)
573           //cpu . cu . ??? = 1; // XXX
574         else if (subFault.fault_str_subtype == flt_str_nea)
575           cpu . cu . OWB_NEA = 1;
576       }
577     else if (faultNumber == FAULT_IPR)
578       {
579         if (subFault.fault_ipr_subtype & FR_ILL_OP)
580           cpu . cu . OEB_IOC = 1;
581         if (subFault.fault_ipr_subtype & FR_ILL_MOD)
582           cpu . cu . EOFF_IAIM = 1;
583         if (subFault.fault_ipr_subtype & FR_ILL_SLV)
584           cpu . cu . ORB_ISP = 1;
585         if (subFault.fault_ipr_subtype & FR_ILL_DIG)
586           cpu . cu . ROFF_IPR = 1;
587       }
588     else if (faultNumber == FAULT_CMD)
589       {
590         if (subFault.fault_cmd_subtype == flt_cmd_lprpn_bits)
591           cpu . cu . IA = 0;
592         else if (subFault.fault_cmd_subtype == flt_cmd_not_control)
593           cpu . cu . IA = 010;
594       }
595 
596 #ifdef L68
597     // History registers
598     // IHRRS; AL39 pg 47
599     // History register lock control. If this bit is set ON, set STROBE ¢
600     // (bit 30, key k) OFF, locking the history registers for all faults
601     // including the floating faults.
602     CPTUR (cptUseMR);
603     if (cpu.MR.emr && cpu.MR.ihrrs)
604       {
605         cpu.MR.ihr = 0;
606       }
607 #endif
608 #ifdef DPS8M
609     // History registers
610     // IHRRS; AL39 pg 49
611     // Additional resetting of bit 30. If bit 31 = 1, the following faults also
612     // reset bit 30:
613     //   Lock Up
614     //   Parity
615     //   Command
616     //   Store
617     //   Illegal Procedure
618     //   Shutdown
619     if (cpu.MR.emr && cpu.MR.ihrrs)
620       {
621         if (faultNumber == FAULT_LUF ||
622             faultNumber == FAULT_PAR ||
623             faultNumber == FAULT_CMD ||
624             faultNumber == FAULT_STR ||
625             faultNumber == FAULT_IPR ||
626             faultNumber == FAULT_SDF)
627           {
628             cpu.MR.ihr = 0;
629           }
630       }
631     // Enable History Registers.  This bit will be reset by ... an Op Not
632     // Complete fault. It may be reset by other faults (see bit 31).
633     if (faultNumber == FAULT_ONC)
634       {
635         cpu.MR.ihr = 0;
636       }
637 #endif
638 
639     // If already in a FAULT CYCLE then signal trouble fault
640 
641     if (cpu.cycle == FAULT_EXEC_cycle)
642       {
643         sim_debug (DBG_CYCLE, & cpu_dev, "Changing fault number to Trouble fault\n");
644 
645         cpu.faultNumber = FAULT_TRB;
646         cpu.cu.FI_ADDR = FAULT_TRB;
647         cpu.subFault.bits = 0; // XXX ???
648         // XXX Does the CU or FR need fixing? ticket #36
649         if (cpu . bTroubleFaultCycle)
650           {
651 #if !defined(THREADZ) && !defined(LOCKLESS)
652 # ifndef PANEL
653 #  ifndef ROUND_ROBIN
654             if ((! sample_interrupts ()) &&
655                 (sim_qcount () == 0))  // XXX If clk_svc is implemented it will
656                                      // break this logic
657               {
658                 sim_printf ("Fault cascade @0%06o with no interrupts pending and no events in queue\n", cpu . PPR.IC);
659                 sim_printf("\nCycles = %"PRId64"\n", cpu.cycleCnt);
660                 sim_printf("\nInstructions = %"PRId64"\n", cpu.instrCnt);
661                 //stop_reason = STOP_FLT_CASCADE;
662                 longjmp (cpu.jmpMain, JMP_STOP);
663               }
664 #  endif
665 # endif
666 #endif
667           }
668         else
669           {
670 //--            f = &_faults[FAULT_TRB];
671             cpu . bTroubleFaultCycle = true;
672           }
673       }
674     else
675       {
676         cpu . bTroubleFaultCycle = false;
677       }
678 
679     // If doInstruction faults, the instruction cycle counter doesn't get
680     // bumped.
681     if (cpu . cycle == EXEC_cycle)
682       cpu.instrCnt ++;
683 
684     cpu . cycle = FAULT_cycle;
685     sim_debug (DBG_CYCLE, & cpu_dev, "Setting cycle to FAULT_cycle\n");
686     longjmp (cpu.jmpMain, JMP_REENTRY);
687 }
688 
689 #ifdef L68
do_FFV_fault(uint fault_number,const char * fault_msg)690 void do_FFV_fault (uint fault_number, const char * fault_msg)
691   {
692     sim_debug (DBG_FAULT, & cpu_dev,
693                "Floating fault %d '%s'\n",
694                fault_number, fault_msg);
695 # ifndef SPEED
696     if_sim_debug (DBG_FAULT, & cpu_dev)
697       traceInstruction (DBG_FAULT);
698 # endif
699 
700     if (fault_number < 1 || fault_number > 3)
701       {
702         sim_printf ("floating fault(out-of-range): %d '%s'\n",
703                     fault_number, fault_msg ? fault_msg : "?");
704         sim_warn ("fault out-of-range\n");
705       }
706 
707     cpu.FFV_fault_number = fault_number;
708     cpu.faultNumber = fault_number;
709 
710     // "The occurrence of a fault or interrupt sets the cache-to-register mode bit to OFF." a:AL39/cmr1
711     CPTUR (cptUseCMR);
712     cpu.CMR.csh_reg = 0;
713 
714     // Increment FCT
715 
716     word3 FCT = cpu.cu.APUCycleBits & MASK3;
717     FCT = (FCT + 1) & MASK3;
718     cpu.cu.APUCycleBits = (word12) ((cpu.cu.APUCycleBits & 07770) | FCT);
719 
720     // Set fault register bits
721     CPTUR (cptUseFR);
722     cpu.faultRegister [0] = 0;
723 
724     // Set cu word1 fault bits
725 
726     cpu.cu.IRO_ISN = 0;
727     cpu.cu.OEB_IOC = 0;
728     cpu.cu.EOFF_IAIM = 0;
729     cpu.cu.ORB_ISP = 0;
730     cpu.cu.ROFF_IPR = 0;
731     cpu.cu.OWB_NEA = 0;
732     cpu.cu.WOFF_OOB = 0;
733     cpu.cu.NO_GA = 0;
734     cpu.cu.OCB = 0;
735     cpu.cu.OCALL = 0;
736     cpu.cu.BOC = 0;
737 # ifdef DPS8M
738     cpu.cu.PTWAM_ER = 0;
739 # endif
740     cpu.cu.CRT = 0;
741     cpu.cu.RALR = 0;
742     cpu.cu.SDWAM_ER = 0;
743     cpu.cu.OOSB = 0;
744     cpu.cu.PARU = 0;
745     cpu.cu.PARL = 0;
746     cpu.cu.ONC1 = 0;
747     cpu.cu.ONC2 = 0;
748     cpu.cu.IA = 0;
749     cpu.cu.IACHN = 0;
750     cpu.cu.CNCHN = 0;
751 
752     // Set control unit 'fault occured during instruction fetch' flag
753     cpu.cu.FIF = 0;
754     cpu.cu.FI_ADDR = (word5) fault_number & MASK5;
755 
756     // XXX Under what conditions should this be set?
757     // Assume no
758     // Reading Multics source, it seems like Multics is setting this bit; I'm going
759     // to assume that the h/w also sets it to 0, and the s/w has to explicitly set it on.
760     cpu.cu.rfi = 0;
761 
762 // Try to decide if this a MIF fault (fault during EIS instruction)
763 // EIS instructions are not used in fault/interrupt pairs, so the
764 // only time an EIS instruction could be executing is during EXEC_cycle.
765 // I am also assuming that only multi-word EIS instructions are of interest.
766 # if 1
767     SC_I_MIF (cpu.cycle == EXEC_cycle &&
768         cpu.currentInstruction.info->ndes > 0);
769     sim_debug (DBG_TRACEEXT, & cpu_dev, "MIF %o\n", TST_I_MIF);
770 # endif
771 
772     // History registers
773     // IHRRS; AL39 pg 47
774     // History register lock control. If this bit is set ON, set STROBE ¢
775     // (bit 30, key k) OFF, locking the history registers for all faults
776     // including the floating faults.
777     CPTUR (cptUseMR);
778     if (cpu.MR.emr && cpu.MR.ihrrs)
779       {
780         cpu.MR.ihr = 0;
781       }
782 
783     if (cpu.cycle == FAULT_EXEC_cycle)
784       {
785         cpu.faultNumber = FAULT_TRB;
786         cpu.cu.FI_ADDR = FAULT_TRB;
787         cpu.subFault.bits = 0; // XXX ???
788         // XXX Does the CU or FR need fixing? ticket #36
789         if (cpu.bTroubleFaultCycle)
790           {
791 # if !defined(THREADZ) && !defined(LOCKLESS)
792 #  ifndef PANEL
793 #   ifndef ROUND_ROBIN
794             if ((! sample_interrupts ()) &&
795                 (sim_qcount () == 0))  // XXX If clk_svc is implemented it will
796                                      // break this logic
797               {
798                 sim_printf ("Fault cascade @0%06o with no interrupts pending and no events in queue\n", cpu.PPR.IC);
799                 sim_printf("\nCycles = %"PRId64"\n", cpu.cycleCnt);
800                 sim_printf("\nInstructions = %"PRId64"\n", cpu.instrCnt);
801                 //stop_reason = STOP_FLT_CASCADE;
802                 longjmp (cpu.jmpMain, JMP_STOP);
803               }
804 #   endif
805 #  endif
806 # endif
807           }
808         else
809           {
810             cpu.bTroubleFaultCycle = true;
811           }
812         cpu.cycle = FAULT_cycle;
813         sim_debug (DBG_CYCLE, & cpu_dev, "Setting cycle to FAULT_cycle\n");
814         longjmp (cpu.jmpMain, JMP_REENTRY);
815       }
816     cpu.bTroubleFaultCycle = false;
817 
818     // If doInstruction faults, the instruction cycle counter doesn't get
819     // bumped.
820     if (cpu . cycle == EXEC_cycle)
821       cpu.instrCnt ++;
822 
823     cpu.is_FFV = true;
824     cpu.cycle = FAULT_cycle;
825     longjmp (cpu.jmpMain, JMP_REENTRY);
826 }
827 #endif
828 
dlyDoFault(_fault faultNumber,_fault_subtype subFault,const char * faultMsg)829 void dlyDoFault (_fault faultNumber, _fault_subtype subFault,
830                 const char * faultMsg)
831   {
832     cpu.dlyFlt = true;
833     cpu.dlyFltNum = faultNumber;
834     cpu.dlySubFltNum = subFault;
835     cpu.dlyCtx = faultMsg;
836   }
837 
838 //
839 // return true if group 7 faults are pending ...
840 //
841 
842 // Note: The DIS code assumes that the only G7 fault is TRO. Adding any
843 // other G7 faults will potentailly require changing the DIS code.
844 
bG7Pending(void)845 bool bG7Pending (void)
846   {
847 #ifdef DPS8M
848     return cpu.g7Faults != 0;
849 #endif
850 #ifdef L68
851     return cpu.g7Faults != 0 || cpu.FFV_faults != 0;
852 #endif
853   }
854 
bG7PendingNoTRO(void)855 bool bG7PendingNoTRO (void)
856   {
857 #ifdef DPS8M
858     return (cpu.g7Faults & (~ (1u << FAULT_TRO))) != 0;
859 #endif
860 #ifdef L68
861     return (cpu.g7Faults & (~ (1u << FAULT_TRO))) != 0 || cpu.FFV_faults != 0;
862 #endif
863   }
864 
setG7fault(uint cpuNo,_fault faultNo,_fault_subtype subFault)865 void setG7fault (uint cpuNo, _fault faultNo, _fault_subtype subFault)
866   {
867     sim_debug (DBG_FAULT, & cpu_dev, "setG7fault CPU %d fault %d (%o) sub %"PRId64" %"PRIo64"\n",
868                cpuNo, faultNo, faultNo, subFault.bits, subFault.bits);
869     cpus[cpuNo].g7FaultsPreset |= (1u << faultNo);
870     //cpu.g7SubFaultsPreset [faultNo] = subFault;
871     cpus[cpuNo].g7SubFaults [faultNo] = subFault;
872 #if defined(THREADZ) || defined(LOCKLESS)
873     wakeCPU(cpuNo);
874 #endif
875   }
876 
877 #ifdef L68
set_FFV_fault(uint f_fault_no)878 void set_FFV_fault (uint f_fault_no)
879   {
880     sim_debug (DBG_FAULT, & cpu_dev, "set_FFV_fault CPU f_fault_no %u\n",
881                f_fault_no);
882     // Map fault number (2/4/6) to bit mask  01/02/04
883     cpu.FFV_faults_preset |= 1u << ((f_fault_no / 2) - 1);
884   }
885 #endif
886 
clearTROFault(void)887 void clearTROFault (void)
888   {
889     cpu . g7Faults &= ~(1u << FAULT_TRO);
890   }
891 
doG7Fault(bool allowTR)892 void doG7Fault (bool allowTR)
893   {
894     // sim_printf ("doG7fault %08o [%"PRId64"]\n", cpu . g7Faults, cpu.cycleCnt);
895     // if (cpu . g7Faults)
896       // {
897         // sim_debug (DBG_FAULT, & cpu_dev, "doG7Fault %08o\n", cpu . g7Faults);
898       // }
899     // According AL39,  Table 7-1. List of Faults, priority of connect is 25
900     // and priority of Timer runout is 26, lower number means higher priority
901 #if defined(THREADZ) || defined(LOCKLESS)
902     lock_scu ();
903 #endif
904      if (cpu.g7Faults & (1u << FAULT_CON))
905        {
906          cpu.g7Faults &= ~(1u << FAULT_CON);
907 
908 #if defined(THREADZ) || defined(LOCKLESS)
909          unlock_scu ();
910 #endif
911          doFault (FAULT_CON, cpu.g7SubFaults [FAULT_CON], "Connect");
912        }
913 
914      if (allowTR && (cpu.g7Faults & (1u << FAULT_TRO)))
915        {
916          cpu . g7Faults &= ~(1u << FAULT_TRO);
917 
918          //sim_printf("timer runout %12o\n",cpu.PPR.IC);
919 #if defined(THREADZ) || defined(LOCKLESS)
920          unlock_scu ();
921 #endif
922          doFault (FAULT_TRO, fst_zero, "Timer runout");
923        }
924 
925      // Strictly speaking EXF isn't a G7 fault, put if we treat is as one,
926      // we are allowing the current instruction to complete, simplifying
927      // implementation
928      if (cpu . g7Faults & (1u << FAULT_EXF))
929        {
930          cpu . g7Faults &= ~(1u << FAULT_EXF);
931 
932 #if defined(THREADZ) || defined(LOCKLESS)
933          unlock_scu ();
934 #endif
935          doFault (FAULT_EXF, fst_zero, "Execute fault");
936        }
937 
938 #ifdef L68
939      if (cpu.FFV_faults & 1u)  // FFV + 2 OC TRAP
940        {
941          cpu.FFV_faults &= ~1u;
942 # if defined(THREADZ) || defined(LOCKLESS)
943          unlock_scu ();
944 # endif
945          do_FFV_fault (1, "OC TRAP");
946        }
947      if (cpu.FFV_faults & 2u)  // FFV + 4 CU HISTORY OVERFLOW TRAP
948        {
949          cpu.FFV_faults &= ~2u;
950 # if defined(THREADZ) || defined(LOCKLESS)
951          unlock_scu ();
952 # endif
953          do_FFV_fault (2, "CU HIST OVF TRAP");
954        }
955      if (cpu.FFV_faults & 4u)  // FFV + 6 ADR TRAP
956        {
957          cpu.FFV_faults &= ~4u;
958 # if defined(THREADZ) || defined(LOCKLESS)
959          unlock_scu ();
960 # endif
961          do_FFV_fault (3, "ADR TRAP");
962        }
963 #endif
964 #if defined(THREADZ) || defined(LOCKLESS)
965      unlock_scu ();
966 #endif
967      doFault (FAULT_TRB, (_fault_subtype) {.bits=cpu.g7Faults}, "Dazed and confused in doG7Fault");
968   }
969 
advanceG7Faults(void)970 void advanceG7Faults (void)
971   {
972 #if defined(THREADZ) || defined(LOCKLESS)
973     lock_scu ();
974 #endif
975     cpu.g7Faults |= cpu.g7FaultsPreset;
976     cpu.g7FaultsPreset = 0;
977     //memcpy (cpu.g7SubFaults, cpu.g7SubFaultsPreset, sizeof (cpu.g7SubFaults));
978 #ifdef L68
979     cpu.FFV_faults |= cpu.FFV_faults_preset;
980     cpu.FFV_faults_preset = 0;
981 #endif
982 #if defined(THREADZ) || defined(LOCKLESS)
983     unlock_scu ();
984 #endif
985   }
986 
987