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