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