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]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
1060 {
1061 cpu . g7Faults &= ~(1u << FAULT_TRO);
1062 }
1063
1064 void doG7Fault (cpu_state_t * cpup, bool allowTR)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 }