1 /*
2 * vim: filetype=c:tabstop=4:ai:expandtab
3 * SPDX-License-Identifier: ICU
4 * SPDX-License-Identifier: Multics
5 * scspell-id: d49ab489-f62e-11ec-9ac1-80ee73e9b8e7
6 *
7 * ---------------------------------------------------------------------------
8 *
9 * Copyright (c) 2007-2013 Michael Mondy
10 * Copyright (c) 2012-2016 Harry Reed
11 * Copyright (c) 2013-2022 Charles Anthony
12 * Copyright (c) 2021-2025 The DPS8M Development Team
13 *
14 * This software is made available under the terms of the ICU License.
15 * See the LICENSE.md file at the top-level directory of this distribution.
16 *
17 * ---------------------------------------------------------------------------
18 *
19 * This source file may contain code comments that adapt, include, and/or
20 * incorporate Multics program code and/or documentation distributed under
21 * the Multics License. In the event of any discrepancy between code
22 * comments herein and the original Multics materials, the original Multics
23 * materials should be considered authoritative unless otherwise noted.
24 * For more details and historical background, see the LICENSE.md file at
25 * the top-level directory of this distribution.
26 *
27 * ---------------------------------------------------------------------------
28 */
29
30 //-V536
31
32 /*
33 * scu.c -- System Controller
34 *
35 * See AN70, section 8 and GB61.
36 *
37 * There were a few variations of SCs and SCUs:
38 * SCU -- Series 60 Level 66 Controller
39 * SC -- Level 68 System Controller
40 * 4MW SCU -- A later version of the Level 68 SC
41 *
42 * SCUs control access to memory.
43 * Each SCU owns a certain range of absolute memory.
44 * This emulator allows the CPU to access memory directly however.
45 * SCUs contain clocks.
46 * SCUS also contain facilities which allow CPUS and IOMs to communicate.
47 * CPUs or IOMS request access to memory via the SCU.
48 * CPUs use the CIOC instr to talk to IOMs and other CPUs via a SCU.
49 * IOMs use interrupts to ask a SCU to signal a CPU.
50 * Other Interesting instructions:
51 * read system controller reg and set system controller reg (RSCR & SSCR)
52 *
53 */
54
55 /*
56 * Physical Details & Interconnection -- AN70, section 8.
57 *
58 * SCUs have 8 ports.
59 * Active modules (CPUs and IOMs) have up to four of their ports
60 * connected to SCU ports.
61 *
62 * The 4MW SCU has eight on/off switches to enable or disable
63 * the ports. However, the associated registers allow for
64 * values of enabled, disabled, and program control.
65 *
66 * SCUs have stores (memory banks).
67 *
68 * SCUs have four sets of registers controlling interrupts. Only two
69 * of these sets, designated "A" and "B" are used. Each set has:
70 * Execute interrupt mask register -- 32 bits; enables/disables
71 * the corresponding execute interrupt cell
72 * Interrupt mask assignment register -- 9 bits total
73 * two parts: assigned bit, set of assigned ports (8 bits)
74 * In Multics, only one CPU will be assigned in either mask
75 * and no CPU appears in both. Earlier hardware versions had
76 * four 10-position rotary switches. Later hardware versions had
77 * two 9-position (0..7 and off) rotary switches.
78 *
79 * Config panel -- Level 68 6000 SCU
80 * -- from AM81
81 * store A and store B
82 * 3 position rotary switch: on line, maint, off line
83 * size: 32K, 64K, 128K, 256K
84 * exec interrupt mask assignment
85 * four 10-position rotary switches (A through D): off, 0 .. 7, M
86 * One switch for each program interrupt register
87 * Assign mask registers to system ports
88 * Normally assign one mask reg to each CPU
89 *
90 * AM81:
91 * " The EXECUTE INTERRUPT MASK ASSIGNMENT (EIMA) rotary switches
92 * determine where interrupts sent to memory are directed. The four EIMA
93 * rotary switches, one for each program interrupt register, are used to
94 * assign mask registers to system ports. The normal settings assign one
95 * mask register to each CPU configured.
96 *
97 * Each switch assigns mask registers as follows:
98 *
99 * Position
100 * OFF Unassigned
101 * 0 Assigned to port 0
102 * ...
103 * 7 Assigned to port 7
104 * M Assigned to maintenance panel
105 *
106 * Assignment of a mask register to a system port designates the
107 * port as a control port, and that port receives interrupt present
108 * signals. Up to four system ports can be designated as control
109 * ports. The normal settings assign one mask register to each CPU
110 * configured."
111 *
112 *
113 *
114 * Config panel -- Level 68 System Controller UNIT (4MW SCU)
115 * -- from AM81
116 * Store A, A1, B, B1 (online/offline)
117 * LWR Store Size
118 * PORT ENABLE
119 * Eight on/off switches
120 * Should be on for each port connected to a configured CPU
121 * mask/port assignment
122 * Two rotary switches (A & B); set to (off, 0..7)
123 * See EXEC INTERRUPT on the 6000 SCU
124 * When booting, one should be set to the port connected to
125 * the bootload CPU. The other should be off.
126 *
127 * If memory port B of CPU C goes to SCU D, then memory port B of all
128 * other CPUs *and* IOMs must go to SCU D. -- AN70, 8-4.
129 *
130 * The base address of the SCU is the actual memory size * the port
131 * assignment. -- AN70, 8-6.
132 *
133 * 43A239854 6000B Eng. Prod. Spec, 3.2.7 Interrupt Multiplex Word:
134 * "The IOM has the ability to set any of the 32 program interrupt
135 * cells located in the system controller containing the base address
136 * of the IOM. It should be noted that for any given IOM identity
137 * switch setting, the IOM can set only 8 of these program interrupt
138 * cells."
139 *
140 */
141
142 /*
143 * === Initialization and Booting -- Part 1 -- Operator's view
144 *
145 * Booting Instructions (GB61)
146 * First boot the BCE OS (Bootload command Environment). See below.
147 * A config deck is used
148 * Bootload SCU is the one with a base addr of zero.
149 * BCE is on a BCE/Multics System tape
150 * Booted from tape into the system via bootload console
151
152 */
153
154 /*
155 * 58009906 (DPS8)
156 * When CPU needs to address the SCU (for a write/read data cycle,
157 * for example), the ETMCM board int the CU of the CPU issues a $INT
158 * to the SCU. This signal is sent ... to the SCAMX active port
159 * control board in the SCU
160 */
161
162 // How? If one of the 32 interrupt cells is set in one of the SCs,
163 // our processor will have the interrupt present (XIP) line active.
164 // Perhaps faults are flagged in the same way via the SXC system
165 // controller command.
166
167 // TEMPORARY
168 // Each SCU owns a certain range of absolute memory.
169 // CPUs use the cioc instr to talk to IOMs and other CPUs via a SCU.
170 // IOMs use interrupts to ask a SCU to signal a CPU.
171 // read system controller reg and set system controller reg (rscr & sscr)
172 // Bootload SCU is the one with a base addr of zero.
173 // 58009906
174 // When CPU needs to address the SCU (for a write/read data cycle,
175 // for example), the ETMCM board int the CU of the CPU issues a $INT
176 // to the SCU. This signal is sent ... to the SCAMX active port
177 // control board in the
178 // -----------------------
179 // How? If one of the 32 interrupt cells is set in one of the SCs,
180 // our processor will have the interrupt present (XIP) line active.
181 // Perhaps faults are flagged in the same way via the SXC system
182 // controller command.
183
184 /*
185 * *** More (new) notes ***
186 *
187 * instr rmcm -- read mem controller mask register
188 * ... for the selected controller, if the processor has a mask register
189 * assigned ..
190 * instr smcm -- set mem controller mask register
191 * ... for the selected controller, if the processor has a mask register
192 * assigned, set it to C(AQ)
193 * instr smic
194 * turn on interrupt cells (any of 0..31)
195 * instr cioc -- connect i/o channel, pg 173
196 * SC addressed by Y sends a connect signal to the port specified
197 * by C(Y)33,35
198 * instr rscr & sscr -- Read/Store System Controller Register, pg 170
199 *
200 * 32 interrupt cells ... XIP
201 * mask info
202 * 8 mask registers
203 * 58009906
204 * =============
205 *
206 * AM81
207 * Every active device (CPU, IOM) must be able to access all SCUs
208 * Every SCU must have the same active device on the same SCU, so
209 * all SCUs must have the same PORT ENABLE settings
210 * Every active device must have the same SCU on the same port,
211 * so all active devices will have the same config panel settings.
212 * Ports must correspond -- port A on every CPU and IOM must either
213 * be connected to the same SCU or not connected to any SCU.
214 * IOMs should be on lower-numbered SCU ports than CPUs.
215 * Multics can have 16MW words of memory.
216 * CPUs have 8 ports, a..h.
217 * SCUs have 8 ports, 0..7.
218 *
219 *
220 * Level 68 6000 SCU Configuration Panel
221 * system control and monitor (cont&mon/mon/off)
222 * system boot control (on/off)
223 * alarm (disable/normal)
224 * maintenance panel mode (test/normal)
225 * store a
226 * mode (offline/maint/online)
227 * size (32k, 64k, 128k, 256k)
228 * store b
229 * mode (offline/maint/online)
230 * size (32k, 64k, 128k, 256k)
231 * execute interrupt mask assignment
232 * (A through D; off/0/1/2/3/4/5/6/7/m)
233 * [CAC] I interpret this as CPU [A..D] is connected to my port [0..7]
234 * address control
235 * lower store (a/b)
236 * offset (off, 16k, 32k, 64k)
237 * interlace (on/off)
238 * cycle port priority (on/off)
239 * port control (8 toggles) (enabled/prog cont/disable)
240 *
241 * The EXECUTE INTERRUPT MASK ASSIGNMENT (EIMA) rotary switches
242 * determine where interrupts sent to memory are directed. The four EIMA
243 * rotary switches, one for each program interrupt register, are used to
244 * assign mask registers to system ports. The normal settings assign one
245 * mask register to each CPU configured.
246 *
247 * Assignment of a mask register to a system port designates the port as a
248 * control port, and that port receives interrupt present signals. Up to four
249 * system ports can be designated as control ports. The normal settings
250 * assign one mask register to each cpu configured.
251 *
252 *
253 *
254 * Configuration rules for Multics:
255 *
256 * 1. Each CPU in the system must be connected to each SCU in the system
257 *
258 * 2. Each IOM in the system must be connected to each SCU in the system
259 *
260 * 3. Each SCU in the system must be connected to every CPU and IOM in the
261 * system.
262 *
263 * 4. Corresponding ports on all CPUs and IOMs must be connected to the same
264 * SCU. For example, port A on every CPU and IOM must be connected to the
265 * same SCU or not connected to any SCU.
266 *
267 * 5. Corresponding ports on all SCUs must be connected to the same active
268 * device (CPU or IOM). For example, if port 0 on any SCU is connected to
269 * IOM A, then port 0 on all SCUs must be connected to IOM A.
270 *
271 * 6. IOMs should be connected to lower-number SCU ports the CPUs.
272 *
273 * These rules are illustrated in Figure 3-5, where the port numbers for a
274 * small Multics system of 2 CPUS, 3 SCUs and 2 IOMs have been indicated
275 *
276 *
277 *
278 *
279 * ----------------- -----------------
280 * | | | |
281 * | CPU A | | CPU B |
282 * | | | |
283 * ----------------- -----------------
284 * | A | B | C | D | | A | B | C | D |
285 * ----------------- -----------------
286 * | | | | | |
287 * | | | | | -----------------
288 * | | | | | |
289 * | | -------------------------------)---)---------------- |
290 * | | | | | |
291 * -------------------- ----------------- | | | |
292 * | | | | | |
293 * | -----------------------------------)------------------- | | |
294 * | | | | | |
295 * | | | -------------------- | |
296 * | | | | | |
297 * ----------------- ----------------- -----------------
298 * | 7 | 6 | 5 | 4 | | 7 | 6 | 5 | 4 | | 7 | 6 | 5 | 4 |
299 * ----------------- ----------------- -----------------
300 * | | | | | |
301 * | SCU C | | SCU B | | SCU A |
302 * | | | | | |
303 * ----------------- ----------------- -----------------
304 * | 3 | 2 | 1 | 0 | | 3 | 2 | 1 | 0 | | 3 | 2 | 1 | 0 |
305 * ----------------- ----------------- -----------------
306 * | | | | | |
307 * | | | ----------- | |
308 * | | | | | |
309 * | -----------------------------------)--------- | | |
310 * | | | | | |
311 * ---------- -------------------------- | | | |
312 * | | | | | |
313 * | | ------------------------------)----)------------------------- |
314 * | | | | | |
315 * | | | | | ---------------------------
316 * | | | | | |
317 * ----------------- -----------------
318 * | A | B | C | D | | A | B | C | D |
319 * ----------------- -----------------
320 * | | | |
321 * | IOM A | | IOM B |
322 * | | | |
323 * ----------------- -----------------
324 *
325 *
326 *
327 *"During bootload, Multics requires a contiguous section of memory beginning at
328 * absolute address 0 and sufficiently large to contain all routines and data
329 * structures used during the first phase of Multics initialization (i.e.
330 * collection 1).
331 * The size of the section required varies among Multics release, and it also
332 * depends on the size of the SST segment, which is dependent on the parameters
333 * specified by the site on the SST config card. ... However
334 * 512 KW is adequate for all circumstances. There can be no "holes" in memory
335 * within this region. Beyond this region, "holes" can exist in memory."
336 *
337 *
338 */
339
340 /*
341 * From AN70-1 May84, pg 86 (8-6)
342 *
343 * RSCR SC_CFG bits 9-11 lower store size
344 *
345 * A DPS-8 SCU may have up to four store units attached to it. If this
346 * is the case, two store units form a pair of units. The size of a
347 * pair of units (or a single unit) is 32K * 2 ** (lower store size)
348 * above.
349 */
350
351 /*
352 * From AN70-1 May84, pg 86 (8-6)
353 *
354 * SCU ADDRESSING
355 *
356 * There are three ways in which an SCU is addressed. In the
357 * normal mode of operation (memory reading and writing), an active
358 * unit (IOM or CPU) translates an absolute address into a memory
359 * port (on it) and a relative memory address within the memory
360 * described by the memory port. The active module sends the
361 * address to the SCU on the proper memory port. If the active
362 * module is enabled by the port enable mask in the referenced SCU,
363 * the SCU will take the address given to it and provide the
364 * necessary memory access.
365 *
366 * The other two ways pertain to reading/setting control
367 * registers in the SCU itself. For each of these, it is still
368 * necessary to specify somehow the memory port on the CPU whose SCU
369 * registers are desired. For the RMCM, SMCM and SMIC instructions,
370 * this consists of providing a virtual address to the processor for
371 * which bits 1 and 2 are the memory port desired.
372 *
373 * The rscr and sscr instructions, though key off the final
374 * absolute address to determine the SCI (or SCU store unit)
375 * desired. Thus, software needs a way to translate a memory port
376 * number into an absolute address to reach the SCU. This is done
377 * with the paged segment scas, generated by int_scas (and
378 * init_scu). scas has a page corresponding to each SCU and to each
379 * store unit in each SCU. pmut$rscr and pmut$sscr use the memory
380 * port number desired to generate a virtual address into scas whose
381 * absolute address (courtesy of the ptws for sca) just happen to
382 * describe memory within that SCU.
383 *
384 * The cioc instruction (discussed below) also depends on the
385 * final absolute address of the target operand to identify the SCU
386 * to perform the operation. In the case of the cioc instruction,
387 * though, the has no particular impact in Multics software. All
388 * target operands for the cioc instruction when referencing IOMs
389 * are in the low order SCU. When referencing CPUS, the SCU
390 * performing the connecting has no real bearing.
391 *
392 * Inter-module communication
393 *
394 * As mentioned earlier, communication between active modules
395 * (CPUs and IOMs can only be performed through SCUs.
396 *
397 * CPUs communicate to IOMs and other CPUs via the cioc
398 * (connect i/o channel) instruction. The operand of the instruction
399 * is a word in memory. The SCU containing this operand is the SCU
400 * that performs the connect function. The word fetched from memory
401 * contains in its low order bits the identity of a port on the SCU
402 * to which this connection is to be sent. This only succeeds if the
403 * target port is enabled (port enable mask) on the SCU. When the
404 * target of the connection is an IOM; this generates a connect strobe
405 * to the IOM. The IOM examines its mailbox in memory to determine
406 * its course of action. When the target of the connect is another
407 * CPU, this generates a connect fault in the target processor. The
408 * target processor determines what course to follow on the basis
409 * of information in memory analyzed by software. When a connect is
410 * sent to a process (including the processor issuing the connect),
411 * the connect is deferred until the processor stops
412 * executing inhibited code (instructions with the inhibit bit set).
413 *
414 * Signals sent from an IOM to a CPU are much more involved.
415 * The basic flow is as follows. The IOM determines an interrupt
416 * number. (The interrupt number is a five bit value, from 0 to 31.
417 * The high order bits are the interrupt level.
418 *
419 * 0 - system fault
420 * 1 - terminate
421 * 2 - marker
422 * 3 - special
423 *
424 * The low order three bits determines the IOM and IOM channel
425 * group.
426 *
427 * 0 - IOM 0 channels 32-63
428 * 1 - IOM 1 channels 32-63
429 * 2 - IOM 2 channels 32-63
430 * 3 - IOM 3 channels 32-63
431 * 4 - IOM 0 channels 0-31
432 * 5 - IOM 1 channels 0-31
433 * 6 - IOM 2 channels 0-31
434 * 7 - IOM 3 channels 0-31
435 *
436 * It also takes the channel number in the group (0-31 meaning
437 * either channels 0-31 to 32-63) and sets the <channel number>th
438 * bit in the <interrupt number>th memory location in the interrupt
439 * mask word (IMW) array in memory. It then generates a word with
440 * the <interrupt number>th bit set and sends this to the bootload
441 * SCU with the SC (set execute cells) SCU command. This sets the
442 * execute interrupt cell register in the SCU and sends an XIP
443 * (execute interrupt present) signal to various processors
444 * connected to the SCU. (The details of this are covered in the
445 * next section.) One of the processors (the first to get to it)
446 * sends an XEC (execute interrupt cells) SCU command to the SCU who
447 * generated the XIP signal. The SCU provides the interrupt number
448 * to the processor, who uses it to determine the address of a fault
449 * pair in memory for the "fault" caused by this interrupt. The
450 * processing of the XEC command acts upon the highest priority
451 * (lowest number) bit in the execute interrupt cell register, and
452 * also resets this bit in the register.
453 *
454 * Interrupts Masks and Assignment
455 *
456 * The mechanism for determining which processors are candidates
457 * for receiving an interrupt from an IOM is an involved
458 * topic. First of all, a processor will not be interrupted as long
459 * as it is executing inhibited instructions (instructions with the
460 * inhibit bit set). Beyond this, though, lies the question of
461 * interrupt masks and mask assignment.
462 *
463 * Internal to the SCU are two sets of registers (A and B),
464 * each set consisting of the execute interrupt mask register and
465 * the interrupt mask assignment register. Each execute interrupt
466 * mask register is 32 bits long, with each bit enabling the
467 * corresponding bit in the execute interrupt cell register. Each
468 * interrupt mask assignment register has two parts, an assigned bit
469 * and a set of ports to which it is assigned (8 bits). When a bit
470 * is set in the execute interrupt sells register, the SCU ANDs this
471 * bit with the corresponding bit in each of the execute interrupt
472 * mask registers. If the corresponding bit of execute interrupt
473 * mask register A, for example, is on, the SCU then looks at the A
474 * interrupt mask assignment register. If this register is not
475 * assigned (enable), no further action takes place in regards to
476 * the A registers. (The B registers are still considered) (in
477 * parallel, by the way).) If the register is assigned (enabled)
478 * then interrupts will be send to all ports (processors) whose
479 * corresponding bit is set in the interrupt mask assignment
480 * register. This, only certain interrupts are allowed to be
481 * signalled at any given time (base on the contents of the execute
482 * interrupt mask registers) and only certain processors will
483 * receive these interrupts (as controlled by the interrupt mask
484 * assignment registers).
485 *
486 * In Multics, only one processor is listed in each of the two
487 * interrupt mask assignment registers, and no processor appears in
488 * both. Thus there is a one for one correspondence between
489 * interrupt masks that are assigned (interrupt mask registers whose
490 * assigned (enabled) bit is on) and processors who have an
491 * interrupt mask (SCU port number appears in an interrupt mask
492 * register). So, at any one time only two processors
493 * are eligible to receive interrupts. Other processors need not
494 * worry about masking interrupts.
495 *
496 * The contents of the interrupt mask registers may be
497 * obtained with the SCU configuration information with the rscr
498 * instruction and set with the sscr instruction.
499 *
500 * bits meaning
501 *
502 * 00-07 ports assigned to mask A (interrupt mask assignment A)
503 * 08-08 mask A is unassigned (disabled)
504 * 36-43 ports assigned to mask B (interrupt mask assignment B)
505 * 44-44 mask B is unassigned (disabled)
506 *
507 * The contents of a execute interrupt mask register are
508 * obtained with the rmcm or the rscr instruction and set with the
509 * smcm or the sscr instruction. The rmcm and smcm instruction only
510 * work if the processor making the request has a mask register
511 * assigned to it. If not, rmcm returns zero (no interrupt are
512 * enabled to it) and a smcm is ignored (actually the port mask
513 * setting is still done). The rscr and sscr instructions allow the
514 * examining/setting of the execute interrupt mask register for any
515 * port on a SCU; these have the same effect as smcm and rmcm if the
516 * SCU port being referenced does not have a mask assigned to it.
517 * The format of the data returned by these instructions is as
518 * follows.
519 *
520 * bits meaning
521 * 00-15 execute interrupt mask register 00-15
522 * 32-35 SCU port mask 0-3
523 * 36-51 execute interrupt mask register 16-31
524 * 68-71 SCU port mask 4-7
525 *
526 */
527
528 // SCU numbering:
529 //
530 // AM81-04, pg 49: "... the ports are listed in order of increasing base
531 // address, which corresponds to the order of mem config cards."
532 // pg 97: "mem port size state ... port as a value (a through h) that
533 // corresponds to the number of the active module port to which the
534 // system controller is connected.
535 //
536 // From this, I conclude;
537 // The SCU connected to port A (0) is SCUA, 1 B, 2 C, etc.
538 // SCUA starts at address 0, and the SCUs are sorted by increasing addresses.
539 //
540
541 // ============================================================================
542
543 #include <sys/time.h>
544 #include "dps8.h"
545 #include "dps8_sys.h"
546 #include "dps8_iom.h"
547 #include "dps8_cable.h"
548 #include "dps8_cpu.h"
549 #include "dps8_faults.h"
550 #include "dps8_scu.h"
551 #include "dps8_utils.h"
552 #if defined(THREADZ) || defined(LOCKLESS)
553 # include "threadz.h"
554 #endif
555
556 #define DBG_CTR 1
557
558 scu_t scu [N_SCU_UNITS_MAX];
559
560 #define N_SCU_UNITS 1 // Default
561
562 static UNIT scu_unit [N_SCU_UNITS_MAX] = {
563 #if defined(NO_C_ELLIPSIS)
564 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
565 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
566 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
567 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
568 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
569 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
570 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
571 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
572 #else
573 [0 ... N_SCU_UNITS_MAX-1] = {
574 UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
575 }
576 #endif
577 };
578
579 #define UNIT_NUM(uptr) ((uptr) - scu_unit)
580
581 // Hardware configuration switches
582
583 // sscr and other instructions override these settings
584
585 static struct config_switches
586 {
587 uint mode; // program or manual
588 uint port_enable [N_SCU_PORTS]; // enable/disable
589 uint mask_enable [N_ASSIGNMENTS]; // enable/disable
590 uint mask_assignment [N_ASSIGNMENTS]; // assigned port number
591 uint lower_store_size; // In K words, power of 2; 32 - 4096
592 uint cyclic; // 7 bits
593 uint nea; // 8 bits
594 uint onl; // 4 bits
595 uint interlace; // 1 bit
596 uint lwr; // 1 bit
597 } config_switches [N_SCU_UNITS_MAX];
598
599 enum { MODE_MANUAL = 0, MODE_PROGRAM = 1 };
600
601 unsigned int gtod_warned = 0;
602
603 // ============================================================================
604
605 static t_stat scu_set_state (UNUSED UNIT * uptr, UNUSED int32 value,
/* ![[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)
*/
606 const char * cptr, UNUSED void * desc)
607 {
608 sim_printf("Cannot modify STATE; try SET SCUn CONFIG%s%s.\r\n",
609 cptr ? "=" : "", cptr ? cptr : "");
610 return SCPE_ARG;
611 }
612
613 static t_stat scu_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
/* ![[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)
*/
614 UNUSED int val, const UNUSED void * desc)
615 {
616 sim_printf("Number of SCU units in system is %d\r\n", scu_dev.numunits);
617 return SCPE_OK;
618 }
619
620 static t_stat scu_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
/* ![[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)
*/
621 const char * cptr, UNUSED void * desc)
622 {
623 if (! cptr)
624 return SCPE_ARG;
625 int n = atoi (cptr);
626 if (n < 1 || n > N_SCU_UNITS_MAX)
627 return SCPE_ARG;
628 scu_dev.numunits = (uint) n;
629 return SCPE_OK;
630 }
631
632 static t_stat scu_show_state (UNUSED FILE * st, UNIT *uptr, UNUSED int val,
/* ![[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)
*/
633 UNUSED const void * desc)
634 {
635 #if defined(TESTING)
636 cpu_state_t * cpup = _cpup;
637 #endif
638 long scu_unit_idx = UNIT_NUM (uptr);
639 if (scu_unit_idx < 0 || scu_unit_idx >= (int) scu_dev.numunits)
640 {
641 sim_debug (DBG_ERR, & scu_dev,
642 "scu_show_state: Invalid unit number %ld\r\n",
643 (long) scu_unit_idx);
644 sim_printf ("error: Invalid unit number %ld\r\n", (long) scu_unit_idx);
645 return SCPE_ARG;
646 }
647
648 sim_printf ("SCU unit number %ld\r\n", (long) scu_unit_idx);
649 scu_t * scup = scu + scu_unit_idx;
650 sim_printf (" Mode %s\r\n",
651 config_switches[scu_unit_idx].mode ? "PROGRAM" : "MANUAL");
652
653 for (int i = 0; i < N_SCU_PORTS; i ++)
654 {
655 struct ports * pp = scup -> ports + i;
656
657 sim_printf (" Port %d %s dev_idx %d dev_port %d type %s\r\n",
658 i, scup->port_enable[i] ? "ENABLE " : "DISABLE",
659 pp->dev_idx, pp->dev_port[XXX_TEMP_SCU_SUBPORT],
660 pp->type == ADEV_NONE ? "NONE" :
661 pp->type == ADEV_CPU ? "CPU" :
662 pp->type == ADEV_IOM ? "IOM" :
663 "<enum broken>");
664 }
665 for (int i = 0; i < N_ASSIGNMENTS; i ++)
666 {
667 //struct interrupts * ip = scup -> interrupts + i;
668
669 sim_printf (" Cell %c\r\n", 'A' + i);
670 sim_printf (" exec_intr_mask %012o\r\n",
671 scup -> exec_intr_mask [i]);
672 sim_printf (" mask_enable %s\r\n",
673 scup -> mask_enable [i] ? "ENABLE" : "DISABLE");
674 sim_printf (" mask_assignment %d\r\n",
675 scup -> mask_assignment [i]);
676 sim_printf (" cells ");
677 for (int j = 0; j < N_CELL_INTERRUPTS; j ++)
678 sim_printf("%d", scup -> cells [j]);
679 sim_printf ("\r\n");
680 }
681 sim_printf("Lower store size: 0%o\r\n", scup -> lower_store_size);
682 sim_printf("Cyclic: %03o\r\n", scup -> cyclic);
683 sim_printf("NEA: %03o\r\n", scup -> nea);
684 sim_printf("Online: %02o\r\n", scup -> onl);
685 sim_printf("Interlace: %o\r\n", scup -> interlace);
686 sim_printf("Lower: %o\r\n", scup -> lwr);
687 sim_printf("ID: %o\r\n", scup -> id);
688 sim_printf("mode_reg: %06o\r\n", scup -> mode_reg);
689 sim_printf("Elapsed days: %d\r\n", scup -> elapsed_days);
690 sim_printf("Steady clock: %d\r\n", scup -> steady_clock);
691 sim_printf("Bullet time: %d\r\n", scup -> bullet_time);
692 sim_printf("Clock delta: %lld\r\n", (long long)scup -> clock_delta);
693 return SCPE_OK;
694 }
695
696 static t_stat scu_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
/* ![[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)
*/
697 UNUSED int val, UNUSED const void * desc)
698 {
699 #if defined(TESTING)
700 cpu_state_t * cpup = _cpup;
701 #endif
702 static const char * map [N_SCU_PORTS] =
703 {
704 "0", "1", "2", "3", "4", "5", "6", "7"
705 };
706 long scu_unit_idx = UNIT_NUM (uptr);
707 if (scu_unit_idx < 0 || scu_unit_idx >= (int) scu_dev.numunits)
708 {
709 sim_debug (DBG_ERR, & scu_dev,
710 "scu_show_config: Invalid unit number %ld\r\n",
711 (long) scu_unit_idx);
712 sim_printf ("error: Invalid unit number %ld\r\n", (long) scu_unit_idx);
713 return SCPE_ARG;
714 }
715
716 sim_printf ("SCU unit number %ld\r\n", (long) scu_unit_idx);
717
718 struct config_switches * sw = config_switches + scu_unit_idx;
719
720 const char * mode = "<out of range>";
721 switch (sw -> mode)
722 {
723 case MODE_PROGRAM:
724 mode = "Program";
725 break;
726 case MODE_MANUAL:
727 mode = "Manual";
728 break;
729 }
730
731 sim_printf ("Mode: %s\r\n", mode);
732 sim_printf ("Port Enable: ");
733 for (int i = 0; i < N_SCU_PORTS; i ++)
734 sim_printf (" %3o", sw -> port_enable [i]);
735 sim_printf ("\r\n");
736 for (int i = 0; i < N_ASSIGNMENTS; i ++)
737 {
738 sim_printf ("Mask %c: %s\r\n",
739 'A' + i,
740 sw->mask_enable[i] ? (map[sw->mask_assignment[i]]) : "Off");
741 }
742 sim_printf ("Lower Store Size: %o\r\n", sw -> lower_store_size);
743 sim_printf ("Cyclic: %03o\r\n", sw -> cyclic);
744 sim_printf ("Non-existent address: %03o\r\n", sw -> nea);
745
746 return SCPE_OK;
747 }
748
749 //
750 // set scu0 config=<blah> [;<blah>]
751 //
752 // blah =
753 // mode= manual | program
754 // mask[A|B] = off | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
755 // portN = enable | disable
756 // lwrstoresize = 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096
757 // cyclic = n
758 // nea = n
759 //
760 // o nea is not implemented; will read as "nea off"
761 // o Multics sets cyclic priority explicitly; config
762 // switches are ignored.
763 // o STORE A, A1, B, B1 ONLINE/OFFLINE not implemented;
764 // will always read online.
765 // o store size if not enforced; a full memory complement
766 // is provided.
767 // o interlace not implemented; will read as 'off'
768 // o LOWER STORE A/B not implemented.
769 // o MASK is 'MASK/PORT ASSIGNMENT' analogous to the
770 // 'EXECUTE INTERRUPT MASK ASSIGNMENT of a 6000 SCU
771
772 static config_value_list_t cfg_mode_list [] =
773 {
774 { "manual", 0 },
775 { "program", 1 },
776 { NULL, 0 }
777 };
778
779 static config_value_list_t cfg_mask_list [] =
780 {
781 { "off", -1 },
782 { NULL, 0 }
783 };
784
785 static config_value_list_t cfg_able_list [] =
786 {
787 { "disable", 0 },
788 { "enable", 1 },
789 { NULL, 0 }
790 };
791
792 static config_value_list_t cfg_size_list [] =
793 {
794 { "32", 0 },
795 { "64", 1 },
796 { "128", 2 },
797 { "256", 3 },
798 { "512", 4 },
799 { "1024", 5 },
800 { "2048", 6 },
801 { "4096", 7 },
802 { "32K", 0 },
803 { "64K", 1 },
804 { "128K", 2 },
805 { "256K", 3 },
806 { "512K", 4 },
807 { "1024K", 5 },
808 { "2048K", 6 },
809 { "4096K", 7 },
810 { "1M", 5 },
811 { "2M", 6 },
812 { "4M", 7 },
813 { NULL, 0 }
814 };
815
816 static config_value_list_t cfg_on_off [] =
817 {
818 { "off", 0 },
819 { "on", 1 },
820 { "disable", 0 },
821 { "enable", 1 },
822 { NULL, 0 }
823 };
824
825 static config_list_t scu_config_list [] =
826 {
827 /* 0 */ { "mode", 1, 0, cfg_mode_list },
828 /* 1 */ { "maska", 0, N_SCU_PORTS - 1, cfg_mask_list },
829 /* 2 */ { "maskb", 0, N_SCU_PORTS - 1, cfg_mask_list },
830 /* 3 */ { "port0", 1, 0, cfg_able_list },
831 /* 4 */ { "port1", 1, 0, cfg_able_list },
832 /* 5 */ { "port2", 1, 0, cfg_able_list },
833 /* 6 */ { "port3", 1, 0, cfg_able_list },
834 /* 7 */ { "port4", 1, 0, cfg_able_list },
835 /* 8 */ { "port5", 1, 0, cfg_able_list },
836 /* 9 */ { "port6", 1, 0, cfg_able_list },
837 /* 10 */ { "port7", 1, 0, cfg_able_list },
838 /* 11 */ { "lwrstoresize", 0, 7, cfg_size_list },
839 /* 12 */ { "cyclic", 0, 0177, NULL },
840 /* 13 */ { "nea", 0, 0377, NULL },
841 // mask: 8 a_online, 4 a1_online, 2 b_online, 1, b1_online
842 /* 14 */ { "onl", 0, 017, NULL },
843 /* 15 */ { "int", 0, 1, NULL },
844 /* 16 */ { "lwr", 0, 1, NULL },
845
846 // Hacks
847
848 /* 17 */ { "elapsed_days", 0, 20000, NULL },
849 /* 18 */ { "steady_clock", 0, 1, cfg_on_off },
850 /* 19 */ { "bullet_time", 0, 1, cfg_on_off },
851 /* 20 */ { "clock_delta", -2147483648, 2147483647, NULL },
852 { NULL, 0, 0, NULL }
853 };
854
855 static t_stat scu_set_config (UNIT * uptr, UNUSED int32 value,
/* ![[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)
*/
856 const char * cptr, UNUSED void * desc)
857 {
858 #if defined(TESTING)
859 cpu_state_t * cpup = _cpup;
860 #endif
861 long scu_unit_idx = UNIT_NUM (uptr);
862 if (scu_unit_idx < 0 || scu_unit_idx >= (int) scu_dev.numunits)
863 {
864 sim_debug (DBG_ERR, & scu_dev,
865 "scu_set_config: Invalid unit number %ld\r\n", (long) scu_unit_idx);
866 sim_printf ("error: scu_set_config: Invalid unit number %ld\r\n",
867 (long) scu_unit_idx);
868 return SCPE_ARG;
869 }
870
871 struct config_switches * sw = config_switches + scu_unit_idx;
872
873 config_state_t cfg_state = { NULL, NULL };
874
875 for (;;)
876 {
877 int64_t v;
878 int rc = cfg_parse ("scu_set_config", cptr, scu_config_list,
879 & cfg_state, & v);
880 if (rc == -1) // done
881 break;
882
883 if (rc == -2) // error
884 {
885 cfg_parse_done (& cfg_state);
886 return SCPE_ARG;
887 }
888
889 const char * p = scu_config_list [rc].name;
890 if (strcmp (p, "mode") == 0)
891 sw -> mode = (uint) v;
892 else if (strcmp (p, "maska") == 0)
893 {
894 if (v == -1)
895 sw -> mask_enable [0] = false;
896 else
897 {
898 sw -> mask_enable [0] = true;
899 sw -> mask_assignment [0] = (uint) v;
900 }
901 }
902 else if (strcmp (p, "maskb") == 0)
903 {
904 if (v == -1)
905 sw -> mask_enable [1] = false;
906 else
907 {
908 sw -> mask_enable [1] = true;
909 sw -> mask_assignment [1] = (uint) v;
910 }
911 }
912 else if (strcmp (p, "port0") == 0)
913 sw -> port_enable [0] = (uint) v;
914 else if (strcmp (p, "port1") == 0)
915 sw -> port_enable [1] = (uint) v;
916 else if (strcmp (p, "port2") == 0)
917 sw -> port_enable [2] = (uint) v;
918 else if (strcmp (p, "port3") == 0)
919 sw -> port_enable [3] = (uint) v;
920 else if (strcmp (p, "port4") == 0)
921 sw -> port_enable [4] = (uint) v;
922 else if (strcmp (p, "port5") == 0)
923 sw -> port_enable [5] = (uint) v;
924 else if (strcmp (p, "port6") == 0)
925 sw -> port_enable [6] = (uint) v;
926 else if (strcmp (p, "port7") == 0)
927 sw -> port_enable [7] = (uint) v;
928 else if (strcmp (p, "lwrstoresize") == 0)
929 sw -> lower_store_size = (uint) v;
930 else if (strcmp (p, "cyclic") == 0)
931 sw -> cyclic = (uint) v;
932 else if (strcmp (p, "nea") == 0)
933 sw -> nea = (uint) v;
934 else if (strcmp (p, "onl") == 0)
935 sw -> onl = (uint) v;
936 else if (strcmp (p, "int") == 0)
937 sw -> interlace = (uint) v;
938 else if (strcmp (p, "lwr") == 0)
939 sw -> lwr = (uint) v;
940 else if (strcmp (p, "elapsed_days") == 0)
941 scu [scu_unit_idx].elapsed_days = (uint) v;
942 else if (strcmp (p, "steady_clock") == 0)
943 scu [scu_unit_idx].steady_clock = (uint) v;
944 else if (strcmp (p, "bullet_time") == 0)
945 scu [scu_unit_idx].bullet_time = (uint) v;
946 else if (strcmp (p, "clock_delta") == 0)
947 scu [scu_unit_idx].clock_delta = (int64_t) v;
948 else
949 {
950 sim_printf ("error: scu_set_config: invalid cfg_parse rc <%d>\r\n",
951 rc);
952 cfg_parse_done (& cfg_state);
953 return SCPE_ARG;
954 }
955 } // process statements
956 cfg_parse_done (& cfg_state);
957 return SCPE_OK;
958 }
959
960 static MTAB scu_mod [] =
961 {
962 {
963 MTAB_XTD | MTAB_VUN | \
964 MTAB_NMO | MTAB_VALR, /* Mask */
965 0, /* Match */
966 (char *) "CONFIG", /* Print string */
967 (char *) "CONFIG", /* Match string */
968 scu_set_config, /* Validation routine */
969 scu_show_config, /* Display routine */
970 NULL, /* Value descriptor */
971 NULL /* Help */
972 },
973 {
974 MTAB_XTD | MTAB_VDV | \
975 MTAB_NMO | MTAB_VALR, /* Mask */
976 0, /* Match */
977 (char *) "NUNITS", /* Print string */
978 (char *) "NUNITS", /* Match string */
979 scu_set_nunits, /* Validation routine */
980 scu_show_nunits, /* Display routine */
981 (char *) "Number of SCU units in the system", /* Value descriptor */
982 NULL /* Help */
983 },
984 {
985 MTAB_XTD | MTAB_VUN | \
986 MTAB_NMO | MTAB_VALR, /* Mask */
987 0, /* Match */
988 (char *) "STATE", /* Print string */
989 (char *) "STATE", /* Match string */
990 scu_set_state, /* Validation routine */
991 scu_show_state, /* Display routine */
992 (char *) "SCU unit internal state", /* Value descriptor */
993 NULL /* Help */
994 },
995 {
996 MTAB_XTD | MTAB_VUN | \
997 MTAB_NMO | MTAB_VALR, /* Mask */
998 0, /* Match */
999 (char *) "RESET", /* Print string */
1000 (char *) "RESET", /* Match string */
1001 scu_reset_unit, /* Validation routine */
1002 NULL, /* Display routine */
1003 (char *) "reset SCU unit", /* Value descriptor */
1004 NULL /* Help */
1005 },
1006 {
1007 0, 0, NULL, NULL, NULL, NULL, NULL, NULL
1008 }
1009 };
1010
1011 //static t_stat scu_reset (DEVICE *dptr);
1012
1013 static DEBTAB scu_dt [] =
1014 {
1015 { (char *) "TRACE", DBG_TRACE, NULL },
1016 { (char *) "NOTIFY", DBG_NOTIFY, NULL },
1017 { (char *) "INFO", DBG_INFO, NULL },
1018 { (char *) "ERR", DBG_ERR, NULL },
1019 { (char *) "WARN", DBG_WARN, NULL },
1020 { (char *) "DEBUG", DBG_DEBUG, NULL },
1021 { (char *) "INTR", DBG_INTR, NULL }, // Don't move as it messes up DBG messages
1022 { (char *) "ALL", DBG_ALL, NULL },
1023 { NULL, 0, NULL }
1024 };
1025
1026 DEVICE scu_dev =
1027 {
1028 (char *) "SCU", /* Name */
1029 scu_unit, /* Units */
1030 NULL, /* Registers */
1031 scu_mod, /* Modifiers */
1032 N_SCU_UNITS, /* #Units */
1033 10, /* Address radix */
1034 8, /* Address width */
1035 1, /* Address increment */
1036 8, /* Data radix */
1037 8, /* Data width */
1038 NULL, /* Examine routine */
1039 NULL, /* Deposit routine */
1040 & scu_reset, /* Reset routine */
1041 NULL, /* Boot routine */
1042 NULL, /* Attach routine */
1043 NULL, /* Detach routine */
1044 NULL, /* Context */
1045 DEV_DEBUG, /* Flags */
1046 0, /* Debug control flags */
1047 scu_dt, /* Debug flag names */
1048 NULL, /* Memory size change */
1049 NULL, /* Logical name */
1050 NULL, /* Help */
1051 NULL, /* Attach_help */
1052 NULL, /* Help_ctx */
1053 NULL, /* Description */
1054 NULL /* End */
1055 };
1056
1057 static void dump_intr_regs (char * ctx, uint scu_unit_idx)
/* ![[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)
*/
1058 {
1059 #if defined(TESTING)
1060 scu_t * up = scu + scu_unit_idx;
1061 cpu_state_t * cpup = _cpup;
1062
1063 sim_debug (DBG_DEBUG, & scu_dev,
1064 "%s A: mask %011o enable %o assignment %o\r\n",
1065 ctx, up -> exec_intr_mask [0], up -> mask_enable [0],
1066 up -> mask_assignment [0]);
1067 sim_debug (DBG_DEBUG, & scu_dev,
1068 "%s B: mask %011o enable %o assignment %o\r\n",
1069 ctx, up -> exec_intr_mask [1], up -> mask_enable [1],
1070 up -> mask_assignment [1]);
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 #endif
1119 }
1120
1121 void scu_unit_reset (int scu_unit_idx)
/* ![[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)
*/
1122 {
1123 scu_t * up = scu + scu_unit_idx;
1124 struct config_switches * sw = config_switches + scu_unit_idx;
1125
1126 for (int i = 0; i < N_SCU_PORTS; i ++)
1127 {
1128 up -> port_enable [i] = sw -> port_enable [i];
1129 }
1130
1131 for (int i = 0; i < N_ASSIGNMENTS; i ++)
1132 {
1133 up -> mask_enable [i] = sw -> mask_enable [i];
1134 up -> mask_assignment [i] = sw -> mask_assignment [i];
1135 up -> mask_field [i] = sw -> mask_enable [i] ?
1136 ((2u << (N_SCU_PORTS - 1 - sw -> mask_assignment [i])) & 0777) : 0001;
1137 }
1138 up -> lower_store_size = sw -> lower_store_size;
1139 up -> cyclic = sw -> cyclic;
1140 up -> nea = sw -> nea;
1141 up -> onl = sw -> onl;
1142 up -> interlace = sw -> interlace;
1143 up -> lwr = sw -> lwr;
1144
1145 // This is to allow the CPU reset to update the memory map. IAC clears the
1146 // attached SCUs; they clear the attached IOMs.
1147
1148 for (uint port_num = 0; port_num < N_SCU_PORTS; port_num ++)
1149 {
1150 struct ports * portp = & scu [scu_unit_idx].ports [port_num];
1151 if (portp->type != ADEV_IOM)
1152 continue;
1153 //if (! scu [scu_unit_idx].port_enable [scu_port_num])
1154 //continue;
1155 iom_unit_reset_idx ((uint) portp->dev_idx);
1156 }
1157
1158 // CAC - These settings were reversed engineer from the code instead
1159 // of from the documentation. In case of issues, try fixing these, not the
1160 // code.
1161
1162 for (int i = 0; i < N_ASSIGNMENTS; i ++)
1163 {
1164 // XXX Hack for t4d
1165 up -> exec_intr_mask [i] = 037777777777;
1166 }
1167 }
1168
1169 t_stat scu_reset (UNUSED DEVICE * dptr)
/* ![[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)
*/
1170 {
1171 // On reset, instantiate the config switch settings
1172
1173 for (int scu_unit_idx = 0; scu_unit_idx < N_SCU_UNITS_MAX; scu_unit_idx ++)
1174 scu_unit_reset (scu_unit_idx);
1175 return SCPE_OK;
1176 }
1177
1178 // ============================================================================
1179
1180 #if defined(THREADZ) || defined(LOCKLESS)
1181 static pthread_mutex_t clock_lock = PTHREAD_MUTEX_INITIALIZER;
1182 #endif
1183
1184 // The SCU clock is 52 bits long; fits in t_uint64
1185 // T&D: SC mode register (scr.incl.pl1 scr_mr, Q bits 18-35 here):
1186 // Q18-27 strobe margins TS/G0/ANSWER/DA/EOC, 2 bits each, 10 = inhibit
1187 // strobe: the store unit is not ready (SM784 07, 08)
1188 // Q30 parity_override, Q31 parity_disable, Q32 store_IA_disable
1189 uint scuGoInhibitMask = 0;
1190
1191 static void scu_update_not_ready (uint scu_unit_idx)
/* ![[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)
*/
1192 {
1193 bool inhibit = false;
1194 for (int f = 0; f < 5; f ++)
1195 if (((scu [scu_unit_idx].mode_reg >> (16 - 2 * f)) & 3) == 2)
1196 inhibit = true;
1197 if (inhibit)
1198 scuGoInhibitMask |= 1u << scu_unit_idx;
1199 else
1200 scuGoInhibitMask &= ~(1u << scu_unit_idx);
1201 }
1202
1203 // A store to an SCU whose mode register inhibits a strobe: store unit not
1204 // ready. One shot (inferred): the fault's own SCU store goes to the same
1205 // memory before the test restores the mode register.
1206 bool scuStoreNotReady (cpu_state_t * cpup, word24 addr)
/* ![[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)
*/
1207 {
1208 int scu_unit_idx = tandd_scu_for_addr (cpup, addr);
1209 if (scu_unit_idx < 0 || ! (scuGoInhibitMask & (1u << scu_unit_idx)))
1210 return false;
1211 scuGoInhibitMask &= ~(1u << scu_unit_idx);
1212 return true;
1213 }
1214
1215 // A store sent with incorrect data (sdpap) or ZAC (separ) parity:
1216 // parity checking on: SC detects it, no store, IA 15 data / 14 ZAC
1217 // parity_disable: passed to the store unit, which detects it:
1218 // IA 17 data / 16 ZAC (also with parity_override,
1219 // SM782 11); the data is stored, with its bad
1220 // parity kept, only with parity_override too
1221 // (SM782 11; without it SM929 05 expects the word
1222 // unaltered); a bad ZAC never (SM783 11)
1223 // store_IA_disable: the store unit's IA (17/16) not indicated
1224 uint scuStoreParityIA (cpu_state_t * cpup, word24 addr, bool zac, bool * doStore, bool * keepBadParity)
/* ![[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)
*/
1225 {
1226 int scu_unit_idx = tandd_scu_for_addr (cpup, addr);
1227 word18 mr = scu_unit_idx < 0 ? 0 : scu [scu_unit_idx].mode_reg;
1228 bool parityOverride = (mr & 0000040) != 0;
1229 bool parityDisable = (mr & 0000020) != 0;
1230 bool storeIADisable = (mr & 0000010) != 0;
1231 uint ia;
1232 * keepBadParity = parityDisable && parityOverride;
1233 if (! parityDisable)
1234 {
1235 * doStore = false;
1236 ia = zac ? 014 : 015;
1237 }
1238 else
1239 {
1240 * doStore = ! zac && parityOverride;
1241 ia = storeIADisable ? 0 : (zac ? 016 : 017);
1242 }
1243 return ia;
1244 }
1245
1246 // Reading a word kept with incorrect parity: the store unit reports it
1247 // (06) unless store_IA_disable; the SC detects it (05) unless
1248 // parity_disable; both 07 (SM782 11: 07, 13: 06, 15: 05).
1249 uint scuReadParityIA (cpu_state_t * cpup, word24 addr)
/* ![[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)
*/
1250 {
1251 int scu_unit_idx = tandd_scu_for_addr (cpup, addr);
1252 word18 mr = scu_unit_idx < 0 ? 0 : scu [scu_unit_idx].mode_reg;
1253 bool suReports = (mr & 0000010) == 0;
1254 bool scDetects = (mr & 0000020) == 0;
1255 return suReports && scDetects ? 007 : suReports ? 006 : scDetects ? 005 : 0;
1256 }
1257
1258 // A command (smic, sscr, smcm) with incorrect ZAC/data parity: refused
1259 // with IA 14/15 unless parity_disable (then done, no IA).
1260 uint scuCommandParityIA (uint scu_unit_idx, bool zac)
/* ![[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)
*/
1261 {
1262 word18 mr = scu_unit_idx < N_SCU_UNITS_MAX ? scu [scu_unit_idx].mode_reg : 0;
1263 return (mr & 0000020) ? 0 : (zac ? 014 : 015);
1264 }
1265
1266 static uint64 set_SCU_clock (cpu_state_t * cpup, uint scu_unit_idx)
/* ![[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)
*/
1267 {
1268 #if defined(THREADZ) || defined(LOCKLESS)
1269 pthread_mutex_lock (& clock_lock);
1270 #endif
1271
1272 // The emulator supports two clock models: steady and real
1273 // In steady mode the time of day is coupled to the instruction clock,
1274 // allowing reproducible behavior. In real, the clock is
1275 // coupled to the actual time-of-day.
1276
1277 // T&D: the TR counts down with execution, so the calendar clock
1278 // advances with it: real time at the first read + TR counts * 125/64 us
1279 // (512 kHz). SM784 13: the clock and the TR agree within 100 counts.
1280 // Only on a T&D machine (tandd_io): under ISOLTS only the CPU under
1281 // test has tandd_mode, and its TR-based reads ran the shared clock
1282 // hours ahead of real time; Multics' reads then got last_time + 1, so
1283 // its clock stood still and its timers (ISOLTS's waits) never expired.
1284 if (cpu.tweaks.tandd_mode && tandd_io_mode ())
1285 {
1286 static uint64 tandd_base = 0;
1287 if (tandd_base == 0)
1288 {
1289 struct timespec ts;
1290 clock_gettime (CLOCK_REALTIME, & ts);
1291 tandd_base = 2177452800000000LL +
1292 (uint64) ts.tv_sec * 1000000u +
1293 (uint64) ts.tv_nsec / 1000u;
1294 }
1295 uint64 Multics_usecs = tandd_base + (cpu.tanddTRTicks * 125u) / 64u;
1296 Multics_usecs += (uint64) scu [scu_unit_idx].user_correction;
1297 if (scu [scu_unit_idx].last_time >= Multics_usecs)
1298 Multics_usecs = scu [scu_unit_idx].last_time + 1;
1299 scu [scu_unit_idx].last_time = Multics_usecs;
1300 goto done;
1301 }
1302
1303 if (scu [0].steady_clock)
1304 {
1305 // The is a bit of code that is waiting for 5000 ms; this
1306 // fools into going faster
1307 #if defined(NEED_128)
1308 uint128 big = construct_128 (0, cpu.instrCnt);
1309 // Sync up the clock and the TR; see wiki page "CAC 08-Oct-2014"
1310 //big *= 4u;
1311 big = lshift_128 (big, 2);
1312 if (scu [0].bullet_time)
1313 big = multiply_128 (big, construct_128 (0, 10000u));
1314
1315 //big += scu [0].elapsed_days * 1000000llu * 60llu * 60llu * 24llu;
1316 uint128 days = construct_128 (0, scu[0].elapsed_days);
1317 days = multiply_128 (days, construct_128 (0, 1000000));
1318 days = multiply_128 (days, construct_128 (0, 60 * 60 * 24));
1319 big = add_128 (big, days);
1320 #else
1321 __uint128_t big = cpu.instrCnt;
1322 // Sync up the clock and the TR; see wiki page "CAC 08-Oct-2014"
1323 big *= 4u;
1324 //big /= 100u;
1325 if (scu [0].bullet_time)
1326 big *= 10000;
1327
1328 big += scu [0].elapsed_days * 1000000llu * 60llu * 60llu * 24llu;
1329 #endif
1330
1331 // Boot time
1332
1333 // load_fnp is complaining that FNP core image is more than 5 years old; try
1334 // moving the 'boot time' back to MR12.3 release date. (12/89 according to
1335 // https://www.multicians.org/chrono.html
1336
1337 // date -d "1990-01-01 00:00:00 -9" +%s
1338 // 631184400
1339 // For debugging MR12.3 and earlier with steady_clock, uncomment --
1340 // uint64 UNIX_secs = 631184400;
1341
1342 // Otherwise, we'll use the current time as the steady_clock starting point --
1343 uint64 UNIX_secs = (uint64)time(NULL);
1344
1345 #if defined(NEED_128)
1346 uint64 UNIX_usecs = UNIX_secs * 1000000llu + big.l;
1347 #else
1348 uint64 UNIX_usecs = UNIX_secs * 1000000llu + (uint64) big;
1349 #endif
1350 // now determine uSecs since Jan 1, 1901 ...
1351 uint64 Multics_usecs = 2177452800000000llu + UNIX_usecs;
1352
1353 // The casting to uint show be okay; both are 64 bit, so if
1354 // user_correction is <0, it will come out in the wash ok.
1355 Multics_usecs += (uint64) scu [scu_unit_idx].user_correction;
1356
1357 // The get calendar clock function is guaranteed to return
1358 // different values on successive calls.
1359
1360 if (scu [scu_unit_idx].last_time >= Multics_usecs)
1361 {
1362 sim_debug (DBG_TRACE, & scu_dev, "finagle clock\r\n");
1363 Multics_usecs = scu [scu_unit_idx].last_time + 1;
1364 }
1365 scu [scu_unit_idx].last_time = Multics_usecs;
1366 goto done;
1367 }
1368
1369 // The calendar clock consists of a 52-bit register which counts
1370 // microseconds and is readable as a double-precision integer by a
1371 // single instruction from any central processor. This rate is in
1372 // the same order of magnitude as the instruction processing rate of
1373 // the GE-645, so that timing of 10-instruction subroutines is
1374 // meaningful. The register is wide enough that overflow requires
1375 // several tens of years; thus it serves as a calendar containing
1376 // the number of microseconds since 0000 GMT, January 1, 1901
1377 /// Secs from Jan 1, 1901 to Jan 1, 1970 - 2 177 452 800 Seconds
1378 /// uSecs from Jan 1, 1901 to Jan 1, 1970 - 2 177 452 800 000 000 uSeconds
1379
1380 struct timeval now;
1381 gettimeofday(& now, NULL);
1382
1383 if (scu [scu_unit_idx].clock_delta) // Apply clock_delta correction.
1384 now.tv_sec += scu [scu_unit_idx].clock_delta;
1385
1386 uint64 UNIX_secs = (uint64) now.tv_sec;
1387 uint64 UNIX_usecs = UNIX_secs * 1000000LL + (uint64) now.tv_usec;
1388
1389 static uint64 last_UNIX_usecs = 0;
1390 if ( (!sim_quiet) && (UNIX_usecs < last_UNIX_usecs))
1391 {
1392 if (gtod_warned < 11)
1393 {
1394 sim_warn ("\rHost clock went backwards %llu uS!\r\n",
1395 (unsigned long long)(last_UNIX_usecs - UNIX_usecs));
1396 gtod_warned++;
1397 }
1398 else if (gtod_warned == 11)
1399 {
1400 sim_warn ("\rHost clock went backwards %llu uS! Suppressing further warnings.\r\n",
1401 (unsigned long long)(last_UNIX_usecs - UNIX_usecs));
1402 gtod_warned++;
1403 }
1404 }
1405 last_UNIX_usecs = UNIX_usecs;
1406
1407 // now determine uSecs since Jan 1, 1901 ...
1408 uint64 Multics_usecs = 2177452800000000LL + UNIX_usecs;
1409
1410 // The casting to uint show be okay; both are 64 bit, so if
1411 // user_correction is <0, it will come out in the wash ok.
1412 Multics_usecs += (uint64) scu [scu_unit_idx].user_correction;
1413
1414 if (scu [scu_unit_idx].last_time >= Multics_usecs)
1415 Multics_usecs = scu [scu_unit_idx].last_time + 1;
1416 scu [scu_unit_idx].last_time = Multics_usecs;
1417
1418 done:
1419 #if defined(THREADZ) || defined(LOCKLESS)
1420 pthread_mutex_unlock (& clock_lock);
1421 #endif
1422
1423 return scu [scu_unit_idx].last_time;
1424 }
1425
1426 //static char pcellb [N_CELL_INTERRUPTS + 1];
1427 static char * pcells (uint scu_unit_idx, char * buf)
/* ![[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)
*/
1428 {
1429 for (uint i = 0; i < N_CELL_INTERRUPTS; i ++)
1430 {
1431 if (scu [scu_unit_idx].cells [i])
1432 buf [i] = '1';
1433 else
1434 buf [i] = '0';
1435 }
1436 buf [N_CELL_INTERRUPTS] = '\0';
1437 return buf;
1438 }
1439
1440 // Either an interrupt has arrived on a port, or a mask register has
1441 // been updated. Bring the CPU up date on the interrupts.
1442
1443 // threadz notes:
1444 //
1445 // deliver_interrupts is called either from a CPU instruction or from
1446 // IOM set_general_interrupt on the IOM thread.
1447 //
1448 // potential race conditions:
1449 // CPU variables: XIP
1450 // SCU variables: cells, mask_enable, exec_intr_mask, mask assignment
1451
1452 // Always called with SCU lock set
1453
1454 static void deliver_interrupts (cpu_state_t * cpup, uint scu_unit_idx)
/* ![[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)
*/
1455 {
1456 #if defined(TESTING)
1457 {
1458 cpu_state_t * cpup = _cpup;
1459 sim_debug (DBG_DEBUG, & scu_dev, "deliver_interrupts %o\r\n", scu_unit_idx);
1460 }
1461 #endif
1462 #if defined(THREADZ) || defined(LOCKLESS)
1463 atomic_thread_fence (memory_order_seq_cst);
1464 #endif /* defined(THREADZ) || defined(LOCKLESS) */
1465 for (uint cpun = 0; cpun < cpu_dev.numunits; cpun ++)
1466 {
1467 cpus[cpun].events.XIP[scu_unit_idx] = false;
1468 }
1469
1470 // If the CIOC generates marker and terminate interrupts, they will be posted simultaneously.
1471 // Since the interrupts are recognized by priority and terminate has a higher priority then
1472 // marker, if will be delivered first. The following code will deliver marker before terminate.
1473
1474 #if defined(REORDER)
1475 for (uint jnum = 0; jnum < N_CELL_INTERRUPTS; jnum ++)
1476 {
1477 static const uint reorder[N_CELL_INTERRUPTS] = {
1478 0, 1, 2, 3, 4, 5, 6, 7,
1479 16, 17, 18, 29, 20, 21, 22, 23,
1480 8, 9, 10, 11, 12, 13, 14, 15,
1481 25, 25, 26, 27, 28, 29, 30, 31 };
1482 uint inum = reorder[jnum];
1483 if (! scu [scu_unit_idx].cells [inum])
1484 continue; //
1485 sim_debug (DBG_DEBUG, & scu_dev, "trying to deliver %d\r\n", inum);
1486 sim_debug (DBG_INTR, & scu_dev,
1487 "scu %u trying to deliver %d\r\n", scu_unit_idx, inum);
1488
1489 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++) // A, B
1490 {
1491 //sim_debug (DBG_DEBUG, & scu_dev,
1492 // "trying inum %u pima %u enable %u\r\n"
1493 // , inum, pima, scu [scu_unit_idx].mask_enable [pima]);
1494 if (scu [scu_unit_idx].mask_enable [pima] == 0)
1495 continue;
1496 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
1497 uint port = scu [scu_unit_idx].mask_assignment [pima];
1498 if (port >= N_SCU_PORTS) // mask assigned to no port
1499 continue;
1500 //sim_debug (DBG_DEBUG, & scu_dev,
1501 // "mask %u port %u type %u cells %o\r\n",
1502 // mask, port, scu [scu_unit_idx].ports [port].type,
1503 // scu [scu_unit_idx].cells [inum]);
1504 if (scu [scu_unit_idx].ports [port].type != ADEV_CPU)
1505 continue;
1506 if ((mask & (1u << (31 - inum))) != 0)
1507 {
1508 uint sn = 0;
1509 if (scu[scu_unit_idx].ports[port].is_exp)
1510 {
1511 sn = (uint) scu[scu_unit_idx].ports[port].xipmaskval;
1512 if (sn >= N_SCU_SUBPORTS)
1513 {
1514 sim_warn ("XIP mask not set; defaulting to subport 0\r\n");
1515 sn = 0;
1516 }
1517 }
1518 if (! cables->scu_to_cpu[scu_unit_idx][port][sn].in_use)
1519 {
1520 sim_warn ("bad scu_unit_idx %u\r\n", scu_unit_idx);
1521 continue;
1522 }
1523 uint cpu_unit_udx = cables->scu_to_cpu[scu_unit_idx][port][sn].cpu_unit_idx;
1524 # if defined(THREADZ) || defined(LOCKLESS)
1525 // Need to do this before setting XIP to avoid race condition
1526 // We are about to interrupt a CPU; this is done to either
1527 // Multics signalling, such has CAM cache clear
1528 // Adding a new CPU
1529 // Reading a deleted CPU
1530 // Starting an ISOLTS CPU
1531 // If it is a Multics signal, the target CPU will be marked as 'inMultics';
1532 // For the other cases, 'inMultics ' will not be set.
1533 // cpup != NULL means that this interrupt was generated by a CPU, rather
1534 // than an IOM; we need this to set the calling thread into slave mode.
1535 if ((! sys.sys_opts.nosync) && cpup && (! cpus[cpu_unit_udx].inMultics)) {
1536 // The interrupt is to start or restart a CPU.
1537 # ifdef SYNCTEST
1538 sim_printf ("CPU %c becomes clock master\r\n", 'A' + cpu_unit_udx);
1539 # endif
1540 becomeClockMaster (cpu_unit_udx);
1541 // Set this so that the calling thread will join the queue immediately.
1542 cpu.syncClockModePoll = 0;
1543 cpu.syncClockModeCache = true;
1544 __asm volatile ("");
1545 atomic_thread_fence (memory_order_seq_cst);
1546 }
1547 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1548 disDiagInterruptSet ((uint) cpu_unit_udx);
1549 # if defined(TESTING)
1550 HDBGIntrSet (inum, cpu_unit_udx, scu_unit_idx, __func__);
1551 # endif
1552 createCPUThread((uint) cpu_unit_udx);
1553 # if !defined(NO_TIMEWAIT)
1554 wakeCPU ((uint) cpu_unit_udx);
1555 # endif
1556 sim_debug (DBG_DEBUG, & scu_dev,
1557 "interrupt set for CPU %d SCU %d\r\n",
1558 cpu_unit_udx, scu_unit_idx);
1559 # else // ! THREADZ
1560 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1561 sim_debug (DBG_DEBUG, & scu_dev, "interrupt set for CPU %d SCU %d\r\n", cpu_unit_udx, scu_unit_idx);
1562 sim_debug (DBG_INTR, & scu_dev,
1563 "XIP set for SCU %d\r\n", scu_unit_idx);
1564 # endif // ! THREADZ
1565 }
1566 }
1567 }
1568 #else // !REORDER
1569 for (uint inum = 0; inum < N_CELL_INTERRUPTS; inum ++)
1570 {
1571 if (! scu [scu_unit_idx].cells [inum])
1572 continue; //
1573 sim_debug (DBG_DEBUG, & scu_dev, "trying to deliver %d\r\n", inum);
1574 sim_debug (DBG_INTR, & scu_dev,
1575 "scu %u trying to deliver %d\r\n", scu_unit_idx, inum);
1576
1577 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++) // A, B
1578 {
1579 //sim_debug (DBG_DEBUG, & scu_dev,
1580 // "trying inum %u pima %u enable %u\r\n"
1581 // , inum, pima, scu [scu_unit_idx].mask_enable [pima]);
1582 if (scu [scu_unit_idx].mask_enable [pima] == 0)
1583 continue;
1584 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
1585 uint port = scu [scu_unit_idx].mask_assignment [pima];
1586 if (port >= N_SCU_PORTS) // mask assigned to no port
1587 continue;
1588 //sim_debug (DBG_DEBUG, & scu_dev,
1589 // "mask %u port %u type %u cells %o\r\n",
1590 // mask, port, scu [scu_unit_idx].ports [port].type,
1591 // scu [scu_unit_idx].cells [inum]);
1592 if (scu [scu_unit_idx].ports [port].type != ADEV_CPU)
1593 continue;
1594 if ((mask & (1u << (31 - inum))) != 0)
1595 {
1596 uint sn = 0;
1597 if (scu[scu_unit_idx].ports[port].is_exp)
1598 {
1599 sn = (uint) scu[scu_unit_idx].ports[port].xipmaskval;
1600 if (sn >= N_SCU_SUBPORTS)
1601 {
1602 sim_warn ("XIP mask not set; defaulting to subport 0\r\n");
1603 sn = 0;
1604 }
1605 }
1606 if (! cables->scu_to_cpu[scu_unit_idx][port][sn].in_use)
1607 {
1608 sim_warn ("bad scu_unit_idx %u\r\n", scu_unit_idx);
1609 continue;
1610 }
1611 uint cpu_unit_udx = cables->scu_to_cpu[scu_unit_idx][port][sn].cpu_unit_idx;
1612 # if defined(THREADZ) || defined(LOCKLESS)
1613 // Need to do this before setting XIP to avoid race condition
1614 // We are about to interrupt a CPU; this is done to either
1615 // Multics signalling, such has CAM cache clear
1616 // Adding a new CPU
1617 // Reading a deleted CPU
1618 // Starting an ISOLTS CPU
1619 // If it is a Multics signal, the target CPU will be marked as 'inMultics';
1620 // For the other cases, 'inMultics ' will not be set.
1621 // cpup != NULL means that this interrupt was generated by a CPU, rather
1622 // than an IOM; we need this to set the calling thread into slave mode.
1623 if ((! sys_opts.nosync) && cpup && (! cpus[cpu_unit_udx].inMultics)) {
1624 // The interrupt is to start or restart a CPU.
1625 # ifdef SYNCTEST
1626 sim_printf ("CPU %c becomes clock master\r\n", 'A' + cpu_unit_udx);
1627 # endif
1628 becomeClockMaster (cpu_unit_udx);
1629 }
1630 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1631 disDiagInterruptSet ((uint) cpu_unit_udx);
1632 # if defined(TESTING)
1633 HDBGIntrSet (inum, cpu_unit_udx, scu_unit_idx, __func__);
1634 # endif
1635 # ifdef SYNCTEST
1636 if (cpus[cpu_unit_udx].rcfDelete) sim_printf ("Poking CPU %c in rcfDelete\r\n", 'A' + cpu_unit_udx);
1637 # endif
1638 createCPUThread((uint) cpu_unit_udx);
1639 # if !defined(NO_TIMEWAIT)
1640 wakeCPU ((uint) cpu_unit_udx);
1641 # endif
1642 sim_debug (DBG_DEBUG, & scu_dev,
1643 "interrupt set for CPU %d SCU %d\r\n",
1644 cpu_unit_udx, scu_unit_idx);
1645 # else // ! THREADZ
1646 cpus[cpu_unit_udx].events.XIP[scu_unit_idx] = true;
1647 sim_debug (DBG_DEBUG, & scu_dev, "interrupt set for CPU %d SCU %d\r\n", cpu_unit_udx, scu_unit_idx);
1648 sim_debug (DBG_INTR, & scu_dev,
1649 "XIP set for SCU %d\r\n", scu_unit_idx);
1650 # endif // ! THREADZ
1651 }
1652 }
1653 }
1654 #endif // REORDER
1655 }
1656
1657 t_stat scu_smic (cpu_state_t * cpup, uint scu_unit_idx, uint UNUSED cpu_unit_udx,
/* ![[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)
*/
1658 uint UNUSED cpu_port_num, word36 rega)
1659 {
1660 #if defined(THREADZ) || defined(LOCKLESS)
1661 lock_scu ();
1662 #endif
1663 // smic can set cells but not reset them...
1664
1665 if (getbits36_1 (rega, 35))
1666 {
1667 for (uint i = 0; i < 16; i ++)
1668 {
1669 if (getbits36_1 (rega, i))
1670 scu [scu_unit_idx].cells [i + 16] = 1;
1671 }
1672 char pcellb [N_CELL_INTERRUPTS + 1];
1673 sim_debug (DBG_TRACE, & scu_dev,
1674 "SMIC low: Unit %u Cells: %s\r\n",
1675 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1676 }
1677 else
1678 {
1679 for (uint i = 0; i < 16; i ++)
1680 {
1681 if (getbits36_1 (rega, i))
1682 scu [scu_unit_idx].cells [i] = 1;
1683 }
1684 char pcellb [N_CELL_INTERRUPTS + 1];
1685 sim_debug (DBG_TRACE, & scu_dev,
1686 "SMIC high: Unit %d Cells: %s\r\n",
1687 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1688 }
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714 dump_intr_regs ("smic", scu_unit_idx);
1715 deliver_interrupts (cpup, scu_unit_idx);
1716 #if defined(THREADZ) || defined(LOCKLESS)
1717 unlock_scu ();
1718 #endif
1719 return SCPE_OK;
1720 }
1721
1722 // system controller and the function to be performed as follows:
1723 //
1724 // Effective Function
1725 // Address
1726 // y0000x C(system controller mode register) -> C(AQ)
1727 // y0001x C(system controller configuration switches) -> C(AQ)
1728 // y0002x C(mask register assigned to port 0) -> C(AQ)
1729 // y0012x C(mask register assigned to port 1) -> C(AQ)
1730 // y0022x C(mask register assigned to port 2) -> C(AQ)
1731 // y0032x C(mask register assigned to port 3) -> C(AQ)
1732 // y0042x C(mask register assigned to port 4) -> C(AQ)
1733 // y0052x C(mask register assigned to port 5) -> C(AQ)
1734 // y0062x C(mask register assigned to port 6) -> C(AQ)
1735 // y0072x C(mask register assigned to port 7) -> C(AQ)
1736 // y0003x C(interrupt cells) -> C(AQ)
1737 //
1738 // y0004x
1739 // or C(calendar clock) -> C(AQ)
1740 // y0005x
1741 //
1742 // y0006x
1743 // or C(store unit mode register) -> C(AQ)
1744 // y0007x
1745 //
1746 // where: y = value of C(TPR.CA)0,2 (C(TPR.CA)1,2 for the DPS 8M
1747 // processor) used to select the system controller
1748 // x = any octal digit
1749 //
1750
1751 t_stat scu_sscr (cpu_state_t * cpup, uint scu_unit_idx, UNUSED uint cpu_unit_udx,
/* ![[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)
*/
1752 UNUSED uint cpu_port_num, word18 addr,
1753 word36 rega, word36 regq)
1754 {
1755 sim_debug (DBG_DEBUG, & scu_dev, "sscr SCU unit %o\r\n", scu_unit_idx);
1756
1757 // Only valid for a 4MW SCU
1758
1759 if (scu_unit_idx >= scu_dev.numunits)
1760 {
1761 // XXX should this be a store fault?
1762 sim_warn ("%s: scu_unit_idx out of range %d\r\n",
1763 __func__, scu_unit_idx);
1764 return SCPE_OK;
1765 }
1766
1767 // BCE uses clever addressing schemes to select SCUs; it appears we need
1768 // to be more selecting in picking out the function bits;
1769 //uint function = (addr >> 3) & 07777;
1770 uint function = (addr >> 3) & 07;
1771
1772 // See scs.incl.pl1
1773
1774 if (config_switches [scu_unit_idx].mode != MODE_PROGRAM)
1775 {
1776 sim_warn ("%s: SCU mode is 'MANUAL', not 'PROGRAM' -- sscr "
1777 "not allowed to set switches.\r\n",
1778 __func__);
1779 // XXX [CAC] Setting an unassigned register generates a STORE FAULT;
1780 // this probably should as well
1781 return SCPE_OK;
1782 }
1783
1784 // Not used by 4MW
1785
1786 switch (function)
1787 {
1788 case 00000: // Set system controller mode register
1789 {
1790 #if defined(THREADZ) || defined(LOCKLESS)
1791 lock_scu ();
1792 #endif
1793 // The ID (Q 14-17) is the SC model, read only (SM784 decides
1794 // which tests apply from it)
1795 scu [scu_unit_idx].mode_reg = getbits36_18 (regq, 54 - 36);
1796 scu_update_not_ready (scu_unit_idx);
1797 #if defined(THREADZ) || defined(LOCKLESS)
1798 unlock_scu ();
1799 #endif
1800 }
1801 break;
1802
1803 case 00001: // Set system controller configuration register
1804 // (4MW SCU only)
1805 {
1806 sim_debug (DBG_DEBUG, & scu_dev,
1807 "sscr 1 %d A: %012"PRIo64" Q: %012"PRIo64"\r\n",
1808 scu_unit_idx, rega, regq);
1809 #if defined(THREADZ) || defined(LOCKLESS)
1810 lock_scu ();
1811 #endif
1812 scu_t * up = scu + scu_unit_idx;
1813 for (int maskab = 0; maskab < 2; maskab ++)
1814 {
1815 word9 mask = ((maskab ? regq : rega) >> 27) & 0777;
1816 up -> mask_field [maskab] = mask;
1817 if (mask & 01)
1818 {
1819 up -> mask_enable [maskab] = 0;
1820 sim_debug (DBG_DEBUG, & scu_dev,
1821 "sscr %u mask disable %d\r\n",
1822 scu_unit_idx, maskab);
1823 }
1824 else
1825 {
1826 up -> mask_enable [maskab] = 1;
1827 sim_debug (DBG_DEBUG, & scu_dev,
1828 "sscr %u mask enable %d\r\n",
1829 scu_unit_idx, maskab);
1830 // Enabled with no port bit set: assigned to no port
1831 // (N_SCU_PORTS); it was left at the old port (SM781 10A).
1832 up -> mask_assignment [maskab] = N_SCU_PORTS;
1833 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
1834 {
1835 if ((2 << (N_SCU_PORTS - 1 - pn)) & mask)
1836 {
1837 up -> mask_assignment [maskab] = (uint) pn;
1838 break;
1839 }
1840 }
1841
1842 }
1843 sim_debug (DBG_INTR, & scu_dev,
1844 "SCU%u SSCR1 mask %c enable set to %u assigned to "
1845 "port %u\r\n",
1846 scu_unit_idx, 'a' + maskab, up->mask_enable[maskab],
1847 up->mask_assignment[maskab]);
1848 }
1849 // AN87-00A, pg 2-5, 2-6 specify which fields are and are not
1850 // settable.
1851
1852 //if (up -> lower_store_size != ((rega >> 24) & 07))
1853 //sim_printf ("??? The CPU tried to change the SCU store size\r\n");
1854 up -> lower_store_size = (rega >> 24) & 07;
1855 up -> cyclic = (regq >> 8) & 0177;
1856 up -> nea = (rega >> 6) & 0377;
1857 up -> onl = (rega >> 20) & 017;
1858 up -> interlace = (rega >> 5) & 1;
1859 up -> lwr = (rega >> 4) & 1;
1860 up -> port_enable [0] = (rega >> 3) & 01;
1861 up -> port_enable [1] = (rega >> 2) & 01;
1862 up -> port_enable [2] = (rega >> 1) & 01;
1863 up -> port_enable [3] = (rega >> 0) & 01;
1864 up -> port_enable [4] = (regq >> 3) & 01;
1865 up -> port_enable [5] = (regq >> 2) & 01;
1866 up -> port_enable [6] = (regq >> 1) & 01;
1867 up -> port_enable [7] = (regq >> 0) & 01;
1868
1869 #if defined(THREADZ) || defined(LOCKLESS)
1870 unlock_scu ();
1871 #endif
1872 // XXX A, A1, B, B1, INT, LWR not implemented (AG87-00A pgs 2-5,
1873 // 2-6), except in T&D mode, where the memory map follows them.
1874 if (cpup && cpu.tweaks.tandd_mode)
1875 setup_scbank_map (cpup);
1876 break;
1877 }
1878
1879 case 00002: // Set mask register port 0
1880 //case 00012: // Set mask register port 1
1881 //case 00022: // Set mask register port 2
1882 //case 00032: // Set mask register port 3
1883 //case 00042: // Set mask register port 4
1884 //case 00052: // Set mask register port 5
1885 //case 00062: // Set mask register port 6
1886 //case 00072: // Set mask register port 7
1887 {
1888 #if defined(THREADZ) || defined(LOCKLESS)
1889 lock_scu ();
1890 #endif
1891 uint port_num = (addr >> 6) & 07;
1892 sim_debug (DBG_DEBUG, & scu_dev, "Set mask register port %d to "
1893 "%012"PRIo64",%012"PRIo64"\r\n",
1894 port_num, rega, regq);
1895
1896 // Find mask reg assigned to specified port
1897 int mask_num = -1;
1898 uint n_masks_found = 0;
1899 for (int p = 0; p < N_ASSIGNMENTS; p ++)
1900 {
1901 //if (scup -> interrupts [p].mask_assign.unassigned)
1902 if (scu [scu_unit_idx].mask_enable [p] == 0)
1903 continue;
1904 //if (scup -> interrupts [p].mask_assign.port == port_num)
1905 if (scu [scu_unit_idx ].mask_assignment [p] == port_num)
1906 {
1907 if (n_masks_found == 0)
1908 mask_num = p;
1909 n_masks_found ++;
1910 }
1911 }
1912
1913 if (! n_masks_found)
1914 {
1915 // According to bootload_tape_label.alm, this condition is OK
1916 sim_debug (DBG_WARN, & scu_dev,
1917 "%s: No masks assigned to cpu on port %d\r\n",
1918 __func__, port_num);
1919 #if defined(THREADZ) || defined(LOCKLESS)
1920 unlock_scu ();
1921 #endif
1922 return SCPE_OK;
1923 }
1924
1925 if (n_masks_found > 1)
1926 {
1927 // Not legal for Multics
1928 sim_debug (DBG_WARN, & scu_dev,
1929 "%s: Multiple masks assigned to cpu on port %d\r\n",
1930 __func__, port_num);
1931 }
1932
1933 // See AN87
1934 //scup -> interrupts[mask_num].exec_intr_mask = 0;
1935 scu [scu_unit_idx].exec_intr_mask [mask_num] = 0;
1936 scu [scu_unit_idx].exec_intr_mask [mask_num] |=
1937 ((word32) getbits36_16(rega, 0) << 16);
1938 scu [scu_unit_idx].exec_intr_mask [mask_num] |=
1939 getbits36_16(regq, 0);
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949 sim_debug (DBG_TRACE, & scu_dev,
1950 "SSCR Set mask unit %u port %u mask_num %u "
1951 "mask 0x%08x\r\n",
1952 scu_unit_idx, port_num, mask_num,
1953 scu [scu_unit_idx].exec_intr_mask [mask_num]);
1954 dump_intr_regs ("sscr set mask", scu_unit_idx);
1955 scu [scu_unit_idx].mask_enable [mask_num] = 1;
1956 sim_debug (DBG_INTR, & scu_dev,
1957 "SCU%u SSCR2 exec_intr mask %c set to 0x%08x"
1958 " and enabled.\r\n",
1959 scu_unit_idx, 'a' + mask_num,
1960 scu[scu_unit_idx].exec_intr_mask[mask_num]);
1961
1962 deliver_interrupts (cpup, scu_unit_idx);
1963 #if defined(THREADZ) || defined(LOCKLESS)
1964 unlock_scu ();
1965 #endif
1966 }
1967 break;
1968
1969 case 00003: // Set interrupt cells
1970 {
1971 #if defined(THREADZ) || defined(LOCKLESS)
1972 lock_scu ();
1973 #endif
1974 for (uint i = 0; i < 16; i ++)
1975 {
1976 scu [scu_unit_idx].cells [i] =
1977 getbits36_1 (rega, i) ? 1 : 0;
1978 scu [scu_unit_idx].cells [i + 16] =
1979 getbits36_1 (regq, i) ? 1 : 0;
1980 }
1981 char pcellb [N_CELL_INTERRUPTS + 1];
1982 sim_debug (DBG_TRACE, & scu_dev,
1983 "SSCR Set int. cells: Unit %u Cells: %s\r\n",
1984 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1985 sim_debug (DBG_INTR, & scu_dev,
1986 "SCU%u SSCR3 Set int. cells %s\r\n",
1987 scu_unit_idx, pcells (scu_unit_idx, pcellb));
1988 dump_intr_regs ("sscr set interrupt cells", scu_unit_idx);
1989 deliver_interrupts (NULL, scu_unit_idx);
1990 #if defined(THREADZ) || defined(LOCKLESS)
1991 unlock_scu ();
1992 #endif
1993 }
1994 break;
1995
1996 case 00004: // Set calendar clock (4MW SCU only)
1997 case 00005:
1998 {
1999 // AQ: 20-35 clock bits 0-15, 36-71 clock bits 16-51
2000 word16 b0_15 = (word16) getbits36_16 (cpu.rA, 20);
2001 word36 b16_51 = cpu.rQ;
2002 uint64 new_clk = (((uint64) b0_15) << 36) | b16_51;
2003 #if defined(THREADZ) || defined(LOCKLESS)
2004 lock_scu ();
2005 #endif
2006 // set_SCU_clock already includes the current correction, so
2007 // add the difference; reads start from the new value, even an
2008 // earlier one (SM784 14 loads 0, then all ones).
2009 scu [scu_unit_idx].user_correction +=
2010 (int64) (new_clk - set_SCU_clock (cpup, scu_unit_idx));
2011 scu [scu_unit_idx].last_time = new_clk;
2012 #if defined(THREADZ) || defined(LOCKLESS)
2013 unlock_scu ();
2014 #endif
2015 //sim_printf ("sscr %o\r\n", function);
2016 }
2017 break;
2018
2019 case 00006: // Set unit mode register
2020 case 00007:
2021 // XXX See notes in AL39 sscr re: store unit selection
2022 //sim_printf ("sscr %o\r\n", function);
2023 // Not emulated; the T&D pages set it routinely (SM783), so don't
2024 // write the warning onto the T&D console
2025 if (! tandd_io_mode ())
2026 sim_warn ("sscr set unit mode register\r\n");
2027 //return STOP_UNIMP;
2028 return SCPE_OK;
2029
2030 default:
2031 sim_warn ("sscr unhandled code\r\n");
2032 //return STOP_UNIMP;
2033 return SCPE_OK;
2034 //sim_printf ("sscr %o\r\n", function);
2035 }
2036 return SCPE_OK;
2037 }
2038
2039 t_stat scu_rscr (cpu_state_t * cpup, uint scu_unit_idx, uint cpu_unit_udx, word18 addr,
/* ![[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)
*/
2040 word36 * rega, word36 * regq)
2041 {
2042 // Only valid for a 4MW SCU
2043
2044 if (scu_unit_idx >= scu_dev.numunits)
2045 {
2046 sim_warn ("%s: scu_unit_idx out of range %d\r\n",
2047 __func__, scu_unit_idx);
2048 return SCPE_OK;
2049 }
2050
2051 // BCE uses clever addressing schemes to select SCUs; it appears we need
2052 // to be more selecting in picking out the function bits;
2053 //uint function = (addr >> 3) & 07777;
2054 uint function = (addr >> 3) & 07;
2055
2056 //sim_printf ("rscr %o\r\n", function);
2057
2058 // See scs.incl.pl1
2059
2060 switch (function)
2061 {
2062 case 00000: // Read system controller mode register
2063 {
2064 // AN-87
2065 // 0..0 -> A
2066 // 0..0 -> Q 36-49 (0-13)
2067 // ID -> Q 50-53 (14-17)
2068 // MODE REG -> Q 54-71 (18-35)
2069 //
2070 // ID: 0000 8034, 8035
2071 // 0001 Level 68 SC
2072 // 0010 Level 66 SCU
2073 // CAC: According to scr.incl.pl1. 0010 is a 4MW SCU
2074 // MODE REG: these fields are only used by T&D
2075 * rega = 0;
2076 //* regq = 0000002000000; // ID = 0010
2077 * regq = 0;
2078 #if defined(THREADZ) || defined(LOCKLESS)
2079 lock_scu ();
2080 #endif
2081 putbits36_4 (regq, 50 - 36, scu [scu_unit_idx].id);
2082 putbits36_18 (regq, 54 - 36, scu [scu_unit_idx].mode_reg);
2083 #if defined(THREADZ) || defined(LOCKLESS)
2084 unlock_scu ();
2085 #endif
2086 break;
2087 }
2088
2089 case 00001: // Read system controller configuration register
2090 {
2091 // AN-87, scr.incl.pl1
2092 //
2093 // SCU:
2094 // reg A:
2095 // MASK A | SIZE | A | A1 | B | B1 | PORT | 0 | MOD | NEA |
2096 // INT | LWR | PMR 0-3
2097 // reg Q:
2098 // MASK B | not used | CYCLIC PRIOR | not used | PMR 4-7
2099 //
2100 // MASK A/B (9 bits): EIMA switch setting for mask A/B. The
2101 // assigned port corresponds to the but position within the
2102 // field. A bit in position 9 indicates that the mask is
2103 // not assigned.
2104 // From scr.incl.pl1:
2105 // 400 => assigned to port 0
2106 // .
2107 // .
2108 // 002 => assigned to port 7
2109 // 001 => mask off */
2110
2111 //
2112 // SIZE (3 bits): Size of lower store
2113 // 000 = 32K ... 111 = 4M
2114 //
2115 // A A1 B B1 (1 bit): store unit A/A1/B/B1 online
2116 //
2117 // PORT (4 bits): Port number of the SCU port through which
2118 // the RSCR instruction was received
2119 //
2120 //struct config_switches * sw = config_switches + scu_unit_idx;
2121 sim_debug (DBG_DEBUG, & scu_dev, "rscr 1 %d\r\n", scu_unit_idx);
2122 #if defined(THREADZ) || defined(LOCKLESS)
2123 lock_scu ();
2124 #endif
2125 scu_t * up = scu + scu_unit_idx;
2126 word9 maskab [2];
2127 for (int i = 0; i < 2; i ++)
2128 {
2129 maskab [i] = (word9) (up -> mask_field [i] & 0777);
2130 }
2131
2132 int scu_port_num = -1; // The port that the rscr instruction was
2133 // received on
2134
2135 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2136 {
2137 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2138 {
2139 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2140 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2141 cpu_unit_udx)
2142 {
2143 scu_port_num = pn;
2144 goto gotit;
2145 }
2146 }
2147 }
2148 gotit:;
2149 if (scu_port_num < 0)
2150 {
2151 #if defined(THREADZ) || defined(LOCKLESS)
2152 unlock_scu ();
2153 #endif
2154 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2155 "scu_unit_no %d, cpu_unit_udx %d\r\n",
2156 __func__, scu_unit_idx, cpu_unit_udx);
2157 return SCPE_OK;
2158 }
2159
2160 // AN87, pg 2-5
2161 word36 a, q;
2162
2163 a = 0;
2164 // (data, starting bit position, number of bits, value)
2165 putbits36_9 (& a, 0, maskab [0]);
2166 putbits36_3 (& a, 9, (word3) up -> lower_store_size);
2167 putbits36_4 (& a, 12, (word4) up -> onl); // A, A1, B, B1 online
2168 putbits36_4 (& a, 16, (word4) scu_port_num);
2169 putbits36_1 (& a, 21, (word1) config_switches[scu_unit_idx].mode);
2170 putbits36_8 (& a, 22, (word8) up -> nea);
2171 putbits36_1 (& a, 30, (word1) up -> interlace);
2172 putbits36_1 (& a, 31, (word1) up -> lwr);
2173 // XXX INT, LWR not implemented. (AG87-00A pgs 2-5. 2-6)
2174 // interlace <- 0
2175 // lower <- 0
2176 // Looking at scr_util.list, I *think* the port order
2177 // 0,1,2,3.
2178 putbits36_1 (& a, 32, (word1) up -> port_enable [0]);
2179 putbits36_1 (& a, 33, (word1) up -> port_enable [1]);
2180 putbits36_1 (& a, 34, (word1) up -> port_enable [2]);
2181 putbits36_1 (& a, 35, (word1) up -> port_enable [3]);
2182 * rega = a;
2183
2184 q = 0;
2185 putbits36_9 (& q, 0, maskab [1]);
2186 // cyclic prior <- 0
2187 putbits36_7 (& q, 57-36, (word7) up -> cyclic & MASK7);
2188 // Looking at scr_util.list, I *think* the port order
2189 // 0,1,2,3.
2190 putbits36_1 (& q, 32, (word1) up -> port_enable [4]);
2191 putbits36_1 (& q, 33, (word1) up -> port_enable [5]);
2192 putbits36_1 (& q, 34, (word1) up -> port_enable [6]);
2193 putbits36_1 (& q, 35, (word1) up -> port_enable [7]);
2194 * regq = q;
2195
2196 #if defined(THREADZ) || defined(LOCKLESS)
2197 unlock_scu ();
2198 #endif
2199 sim_debug (DBG_DEBUG, & scu_dev,
2200 "rscr 1 %d A: %012"PRIo64" Q: %012"PRIo64"\r\n",
2201 scu_unit_idx, * rega, * regq);
2202 break;
2203 }
2204
2205 case 00002: // mask register
2206 {
2207 uint port_num = (addr >> 6) & MASK3;
2208 #if defined(THREADZ) || defined(LOCKLESS)
2209 lock_scu ();
2210 #endif
2211 scu_t * up = scu + scu_unit_idx;
2212 uint mask_contents = 0;
2213 if (up -> mask_assignment [0] == port_num)
2214 {
2215 mask_contents = up -> exec_intr_mask [0];
2216 }
2217 else if (up -> mask_assignment [1] == port_num)
2218 {
2219 mask_contents = up -> exec_intr_mask [1];
2220 }
2221 mask_contents &= MASK32;
2222
2223 * rega = 0;
2224 putbits36 (rega, 0, 16, (mask_contents >> 16) & MASK16);
2225 putbits36 (rega, 32, 1, up -> port_enable [0]);
2226 putbits36 (rega, 33, 1, up -> port_enable [1]);
2227 putbits36 (rega, 34, 1, up -> port_enable [2]);
2228 putbits36 (rega, 35, 1, up -> port_enable [3]);
2229
2230 * regq = 0;
2231 putbits36 (regq, 0, 16, (mask_contents >> 0) & MASK16);
2232 putbits36 (regq, 32, 1, up -> port_enable [4]);
2233 putbits36 (regq, 33, 1, up -> port_enable [5]);
2234 putbits36 (regq, 34, 1, up -> port_enable [6]);
2235 putbits36 (regq, 35, 1, up -> port_enable [7]);
2236
2237 #if defined(THREADZ) || defined(LOCKLESS)
2238 unlock_scu ();
2239 #endif
2240 sim_debug (DBG_TRACE, & scu_dev,
2241 "RSCR mask unit %u port %u assigns %u %u mask 0x%08x\r\n",
2242 scu_unit_idx, port_num, up -> mask_assignment [0],
2243 up -> mask_assignment [1],
2244 mask_contents);
2245 }
2246 break;
2247
2248 case 00003: // Interrupt cells
2249 {
2250 #if defined(THREADZ) || defined(LOCKLESS)
2251 lock_scu ();
2252 #endif
2253 scu_t * up = scu + scu_unit_idx;
2254 // * rega = up -> exec_intr_mask [0];
2255 // * regq = up -> exec_intr_mask [1];
2256 // Only the cell bits are loaded; the rest of AQ is zero (the
2257 // old A/Q bits 16-35 leaked through; SM781 05A, as dps8m4).
2258 * rega = 0;
2259 * regq = 0;
2260 for (uint i = 0; i < N_CELL_INTERRUPTS; i ++)
2261 {
2262 word1 cell = up -> cells [i] ? 1 : 0;
2263 if (i < 16)
2264 putbits36_1 (rega, i, cell);
2265 else
2266 putbits36_1 (regq, i - 16, cell);
2267 }
2268 #if defined(THREADZ) || defined(LOCKLESS)
2269 unlock_scu ();
2270 #endif
2271 }
2272 break;
2273
2274 case 00004: // Get calendar clock (4MW SCU only)
2275 case 00005:
2276 {
2277 uint64 clk = set_SCU_clock (cpup, scu_unit_idx) & ((1llu << 52) - 1); // 52 bits
2278 cpu.rQ = clk & 0777777777777; // lower 36-bits of clock
2279 cpu.rA = (clk >> 36) & 0177777; // upper 16-bits of clock
2280 #if defined(TESTING)
2281 HDBGRegAW ("rscr get clock");
2282 HDBGRegQW ("rscr get clock");
2283 #endif
2284 }
2285 break;
2286
2287 case 00006: // SU Mode register
2288 case 00007: // SU Mode register
2289 {
2290 //sim_printf ("rscr SU Mode Register%o\r\n", function);
2291
2292 // Completely undocumented...
2293 // scr.incl.alm
2294 //" Structure scr_su
2295 //"
2296 // equ scr_su_size,2
2297 //
2298 //
2299 // equ scr_su.ZAC_line_word,1
2300 // equ scr_su.ZAC_line_shift,30
2301 // bool scr_su.ZAC_line_mask,000077
2302 // equ scr_su.syndrome_word,1
2303 // equ scr_su.syndrome_shift,22
2304 // bool scr_su.syndrome_mask,000377
2305 // equ scr_su.identification_word,1
2306 // equ scr_su.identification_shift,18
2307 // bool scr_su.identification_mask,000017
2308 // equ scr_su.EDAC_disabled_word,1
2309 // bool scr_su.EDAC_disabled,400000 " DL
2310 // equ scr_su.MINUS_5_VOLT_margin_word,1
2311 //" equ scr_su.MINUS_5_VOLT_margin_shift,11
2312 // bool scr_su.MINUS_5_VOLT_margin_mask,000003
2313 // equ scr_su.PLUS_5_VOLT_margin_word,1
2314 // equ scr_su.PLUS_5_VOLT_margin_shift,9
2315 // bool scr_su.PLUS_5_VOLT_margin_mask,000003
2316 // equ scr_su.spare_margin_word,1
2317 // equ scr_su.spare_margin_shift,7
2318 // bool scr_su.spare_margin_mask,000003
2319 // equ scr_su.PLUS_19_VOLT_margin_word,1
2320 //" equ scr_su.PLUS_19_VOLT_margin_shift,5
2321 // bool scr_su.PLUS_19_VOLT_margin_mask,000003
2322 // equ scr_su.SENSE_strobe_margin_word,1
2323 //" equ scr_su.SENSE_strobe_margin_shift,2
2324 // bool scr_su.SENSE_strobe_margin_mask,000003
2325 //" equ scr_su.maint_functions_enabled_word,1
2326 // bool scr_su.maint_functions_enabled,000001 " DL
2327
2328 // 1 1 1 2 2 2 2 3 3 3 3
2329 // 0 6 4 8 9 3 5 7 9 1 2 4 5
2330 // ------------------------------------------------------------------------------
2331 // | ZAC | synd | id | EDAC | 0 | -5 | +5 | spare | +19 | 0 | sense | 0 | maint |
2332 // ------------------------------------------------------------------------------
2333 // 6 8 4 1 4 2 2 2 2 1 2 1 1
2334
2335 // Okay, it looks safe to return 0.
2336
2337 * rega = 0;
2338 * regq = 0;
2339 }
2340 break;
2341
2342 default:
2343 sim_warn ("rscr %o\r\n", function);
2344 return SCPE_OK;
2345 }
2346 return SCPE_OK;
2347 }
2348
2349
2350
2351
2352
2353 int scu_cioc (uint cpu_unit_udx, uint scu_unit_idx, uint scu_port_num,
/* ![[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)
*/
2354 uint expander_command, uint sub_mask)
2355 {
2356
2357
2358
2359 #if defined(TESTING)
2360 cpu_state_t * cpup = _cpup;
2361 sim_debug (DBG_DEBUG, & scu_dev,
2362 "scu_cioc: Connect from %o sent to "
2363 "unit %o port %o exp %o mask %03o\r\n",
2364 cpu_unit_udx, scu_unit_idx, scu_port_num,
2365 expander_command, sub_mask);
2366 #endif
2367 #if defined(THREADZ) || defined(LOCKLESS)
2368 lock_scu ();
2369 #endif
2370 struct ports * portp = & scu [scu_unit_idx].ports [scu_port_num];
2371
2372 int rc = 0;
2373 if (! scu [scu_unit_idx].port_enable [scu_port_num])
2374 {
2375 sim_debug (DBG_ERR, & scu_dev,
2376 "scu_cioc: Connect sent to disabled port; dropping\r\n");
2377 sim_debug (DBG_ERR, & scu_dev,
2378 "scu_cioc: scu_unit_idx %u scu_port_num %u\r\n",
2379 scu_unit_idx, scu_port_num);
2380 rc = 1;
2381 goto done;
2382 }
2383
2384 if (expander_command == 1) // "set subport enables"
2385 {
2386 for (uint i = 0; i < N_SCU_SUBPORTS; i++)
2387 {
2388 portp->subport_enables [i] = !! (sub_mask & (0200u >> i));
2389 }
2390 goto done;
2391 }
2392
2393 if (expander_command == 2) // "set xipmask"
2394 {
2395 int cnt = 0;
2396 int val = -1;
2397 for (uint i = 0; i < N_SCU_SUBPORTS; i++)
2398 {
2399 portp->xipmask [i] = !! (sub_mask & (0200u >> i));
2400 if (portp->xipmask [i])
2401 {
2402 val = (int) i;
2403 cnt ++;
2404 }
2405 }
2406 if (cnt > 1)
2407 {
2408 sim_warn ("xip mask cnt > 1\r\n");
2409 val = -1;
2410 }
2411 portp->xipmaskval = val;
2412 goto done;
2413 }
2414
2415 if (portp -> type == ADEV_IOM)
2416 {
2417 int iom_unit_idx = portp->dev_idx;
2418 #if defined(THREADZ) || defined(LOCKLESS)
2419 unlock_scu ();
2420 # if !defined(IO_ASYNC_PAYLOAD_CHAN) && !defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
2421 lock_iom ();
2422 lock_libuv ();
2423 # endif
2424 iom_interrupt (scu_unit_idx, (uint) iom_unit_idx);
2425 # if !defined(IO_ASYNC_PAYLOAD_CHAN) && !defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
2426 unlock_libuv ();
2427 unlock_iom ();
2428 # endif
2429 return 0;
2430 #else // ! THREADZ
2431 if (sys_opts.iom_times.connect <= 0)
2432 {
2433 iom_interrupt (scu_unit_idx, (uint) iom_unit_idx);
2434 goto done;
2435 }
2436 else
2437 {
2438 //sim_printf ("scu_cioc: Queuing an IOM in %d cycles "
2439 //"(for the connect channel) %u %d\r\n",
2440 //sys_opts.iom_times.connect, scu_unit_idx, iom_unit_idx);
2441 sim_debug (DBG_INFO, & scu_dev,
2442 "scu_cioc: Queuing an IOM in %d cycles "
2443 "(for the connect channel)\r\n",
2444 sys_opts.iom_times.connect);
2445 // Stash the iom_interrupt call parameters
2446 iom_dev.units[iom_unit_idx].u3 = (int32) scu_unit_idx;
2447 iom_dev.units[iom_unit_idx].u4 = (int32) iom_unit_idx;
2448 int rc;
2449 if ((rc = sim_activate (& iom_dev.units [iom_unit_idx],
2450 sys_opts.iom_times.connect)) != SCPE_OK)
2451 {
2452 sim_warn ("sim_activate failed (%d)\r\n", rc);
2453 goto done;
2454 }
2455 goto done;
2456 }
2457 #endif // ! THREADZ
2458 }
2459 else if (portp -> type == ADEV_CPU)
2460 {
2461
2462 // by subport_enables
2463 if (portp->is_exp)
2464 {
2465 for (uint sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2466 {
2467 if (portp->subport_enables[sn])
2468 {
2469 if (! cables->
2470 scu_to_cpu[scu_unit_idx][scu_port_num][sn].in_use)
2471 {
2472 sim_warn ("Can't find CPU to interrupt\r\n");
2473 continue;
2474 }
2475 uint cpu_unit_udx = cables->
2476 scu_to_cpu[scu_unit_idx][scu_port_num][sn].cpu_unit_idx;
2477 setG7fault ((uint) cpu_unit_udx, FAULT_CON);
2478 }
2479 }
2480 }
2481 else
2482 {
2483 if (! cables->scu_to_cpu[scu_unit_idx][scu_port_num][0].in_use)
2484 {
2485 sim_warn ("Can't find CPU to interrupt\r\n");
2486 rc = 1;
2487 goto done;
2488 }
2489 uint cpu_unit_udx =
2490 cables->scu_to_cpu[scu_unit_idx][scu_port_num][0].cpu_unit_idx;
2491 setG7fault ((uint) cpu_unit_udx, FAULT_CON);
2492 }
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515 goto done;
2516 }
2517 else
2518 {
2519 sim_debug (DBG_ERR, & scu_dev,
2520 "scu_cioc: Connect sent to not-an-IOM or CPU; dropping\r\n");
2521 rc = 1;
2522 goto done;
2523 }
2524 done:
2525 #if defined(THREADZ) || defined(LOCKLESS)
2526 unlock_scu ();
2527 #endif
2528 return rc;
2529 }
2530
2531 // =============================================================================
2532
2533 // The SXC (set execute cells) SCU command.
2534
2535 // From AN70:
2536 // It then generates a word with
2537 // the <interrupt number>th bit set and sends this to the bootload
2538 // SCU with the SC (set execute cells) SCU command.
2539 //
2540
2541 int scu_set_interrupt (uint scu_unit_idx, uint inum)
/* ![[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)
*/
2542 {
2543 #if defined(TESTING)
2544 cpu_state_t * cpup = _cpup;
2545 #endif
2546 const char* moi = "SCU::interrupt";
2547
2548 if (inum >= N_CELL_INTERRUPTS)
2549 {
2550 sim_debug (DBG_WARN, & scu_dev,
2551 "%s: Bad interrupt number %d\r\n", moi, inum);
2552 return 1;
2553 }
2554
2555 #if defined(THREADZ) || defined(LOCKLESS)
2556 lock_scu ();
2557 #endif
2558 scu [scu_unit_idx].cells [inum] = 1;
2559 dump_intr_regs ("scu_set_interrupt", scu_unit_idx);
2560 deliver_interrupts (NULL, scu_unit_idx);
2561 #if defined(THREADZ) || defined(LOCKLESS)
2562 unlock_scu ();
2563 #endif
2564 return 0;
2565 }
2566
2567 // Scan a SCU for interrupts from highest to lowest. If an interrupt is
2568 // present, clear it, update the interrupt state bits and return the fault
2569 // pair address for the interrupt (2 * interrupt number). If no interrupt
2570 // is present, return 1.
2571 //
2572
2573 uint scu_get_highest_intr (uint scu_unit_idx)
/* ![[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)
*/
2574 {
2575 #if defined(TESTING)
2576 cpu_state_t * cpup = _cpup;
2577 #endif
2578 #if defined(THREADZ) || defined(LOCKLESS)
2579 lock_scu ();
2580 #endif
2581 // lower numbered cells have higher priority
2582 for (int inum = 0; inum < N_CELL_INTERRUPTS; inum ++)
2583 {
2584 for (uint pima = 0; pima < N_ASSIGNMENTS; pima ++) // A, B
2585 {
2586 if (scu [scu_unit_idx].mask_enable [pima] == 0)
2587 continue;
2588 uint mask = scu [scu_unit_idx].exec_intr_mask [pima];
2589 uint port = scu [scu_unit_idx].mask_assignment [pima];
2590 if (port >= N_SCU_PORTS) // mask assigned to no port
2591 continue;
2592 // if (scu [scu_unit_idx].ports [port].type != ADEV_CPU ||
2593 // scu [scu_unit_idx].ports [port].dev_idx != current_running_cpu_idx)
2594 if (scu[scu_unit_idx].ports[port].type != ADEV_CPU ||
2595 cpus[current_running_cpu_idx].scu_port[scu_unit_idx] != port)
2596 continue;
2597 if (scu [scu_unit_idx].cells [inum] &&
2598 (mask & (1u << (31 - inum))) != 0)
2599 {
2600 sim_debug (DBG_TRACE, & scu_dev,
2601 "scu_get_highest_intr inum %d pima %u mask 0%011o port %u cells 0%011o\r\n",
2602 inum, pima, mask, port, scu [scu_unit_idx].cells [inum]);
2603 scu [scu_unit_idx].cells [inum] = false;
2604 dump_intr_regs ("scu_get_highest_intr", scu_unit_idx);
2605 deliver_interrupts (NULL, scu_unit_idx);
2606 #if defined(THREADZ) || defined(LOCKLESS)
2607 unlock_scu ();
2608 #endif
2609 return (uint) inum * 2;
2610 }
2611 }
2612 }
2613 #if defined(THREADZ) || defined(LOCKLESS)
2614 unlock_scu ();
2615 #endif
2616 return 1;
2617 }
2618
2619 t_stat scu_reset_unit (UNIT * uptr, UNUSED int32 value,
/* ![[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)
*/
2620 UNUSED const char * cptr,
2621 UNUSED void * desc)
2622 {
2623 uint scu_unit_idx = (uint) (uptr - scu_unit);
2624 scu_unit_reset ((int) scu_unit_idx);
2625 return SCPE_OK;
2626 }
2627
2628 void scu_init (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)
*/
2629 {
2630 // One time only initializations
2631
2632 for (int u = 0; u < N_SCU_UNITS_MAX; u ++)
2633 {
2634 for (int p = 0; p < N_SCU_PORTS; p ++)
2635 {
2636 for (int s = 0; s < N_SCU_SUBPORTS; s ++)
2637 {
2638 scu[u].ports[p].dev_port[s] = -1;
2639 scu[u].ports[p].subport_enables[s] = false;
2640 scu[u].ports[p].xipmask[s] = false;
2641 // Invalid value for detecting uninitialized XIP mask.
2642 scu[u].ports[p].xipmaskval = N_SCU_SUBPORTS;
2643 }
2644 scu[u].ports[p].type = ADEV_NONE;
2645 scu[u].ports[p].is_exp = false;
2646 }
2647
2648 // ID: 0000 8034, 8035
2649 // 0001 Level 68 SC
2650 // 0010 Level 66 SCU
2651 scu [u].id = 02l; // 0b0010
2652 scu [u].mode_reg = 0; // used by T&D
2653 scu [u].elapsed_days = 0;
2654 }
2655
2656 }
2657
2658 t_stat scu_rmcm (uint scu_unit_idx, uint cpu_unit_udx, word36 * rega,
/* ![[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)
*/
2659 word36 * regq)
2660 {
2661 #if defined(TESTING)
2662 cpu_state_t * cpup = _cpup;
2663 #endif
2664 scu_t * up = scu + scu_unit_idx;
2665
2666 // Assume no mask register assigned
2667 * rega = 0;
2668 * regq = 0;
2669
2670 // Which port is cpu_unit_udx connected to? (i.e. which port did the
2671 // command come in on?
2672 int scu_port_num = -1; // The port that the rscr instruction was
2673 // received on
2674
2675 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2676 {
2677 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2678 {
2679 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2680 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2681 cpu_unit_udx)
2682 {
2683 scu_port_num = pn;
2684 goto gotit;
2685 }
2686 }
2687 }
2688
2689 gotit:;
2690
2691 //sim_printf ("rmcm scu_port_num %d\r\n", scu_port_num);
2692
2693 if (scu_port_num < 0)
2694 {
2695 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2696 "scu_unit_no %d, cpu_unit_udx %d\r\n",
2697 __func__, scu_unit_idx, cpu_unit_udx);
2698 sim_debug (DBG_ERR, & scu_dev,
2699 "%s: can't find cpu port in the snarl of cables; "
2700 "scu_unit_no %d, cpu_unit_udx %d\r\n",
2701 __func__, scu_unit_idx, cpu_unit_udx);
2702 // Non 4MWs do a store fault
2703 return SCPE_OK;
2704 }
2705
2706 // A reg:
2707 // 0 15 16 31 32 35
2708 // IER 0-15 00000000 PER 0-3
2709 // Q reg:
2710 // 0 15 16 31 32 35
2711 // IER 16-32 00000000 PER 4-7
2712
2713 sim_debug (DBG_TRACE, & scu_dev, "rmcm selected scu port %u\r\n",
2714 scu_port_num);
2715 #if defined(THREADZ) || defined(LOCKLESS)
2716 lock_scu ();
2717 #endif
2718 uint mask_contents = 0;
2719 if (up -> mask_assignment [0] == (uint) scu_port_num)
2720 {
2721 mask_contents = up -> exec_intr_mask [0];
2722 sim_debug (DBG_TRACE, & scu_dev, "rmcm got mask %011o from pima A\r\n",
2723 mask_contents);
2724 }
2725 else if (up -> mask_assignment [1] == (uint) scu_port_num)
2726 {
2727 mask_contents = up -> exec_intr_mask [1];
2728 sim_debug (DBG_TRACE, & scu_dev, "rmcm got mask %011o from pima B\r\n",
2729 mask_contents);
2730 }
2731 mask_contents &= MASK32;
2732
2733 * rega = 0; //-V1048
2734 putbits36_16 (rega, 0, (mask_contents >> 16) & MASK16);
2735 putbits36_1 (rega, 32, (word1) up -> port_enable [0]);
2736 putbits36_1 (rega, 33, (word1) up -> port_enable [1]);
2737 putbits36_1 (rega, 34, (word1) up -> port_enable [2]);
2738 putbits36_1 (rega, 35, (word1) up -> port_enable [3]);
2739
2740 * regq = 0; //-V1048
2741 putbits36_16 (regq, 0, (mask_contents >> 0) & MASK16);
2742 putbits36_1 (regq, 32, (word1) up -> port_enable [4]);
2743 putbits36_1 (regq, 33, (word1) up -> port_enable [5]);
2744 putbits36_1 (regq, 34, (word1) up -> port_enable [6]);
2745 putbits36_1 (regq, 35, (word1) up -> port_enable [7]);
2746
2747 #if defined(THREADZ) || defined(LOCKLESS)
2748 unlock_scu ();
2749 #endif
2750 sim_debug (DBG_TRACE, & scu_dev,
2751 "RMCM returns %012"PRIo64" %012"PRIo64"\r\n",
2752 * rega, * regq);
2753 dump_intr_regs ("rmcm", scu_unit_idx);
2754 return SCPE_OK;
2755 }
2756
2757 t_stat scu_smcm (uint scu_unit_idx, uint cpu_unit_udx, word36 rega, word36 regq)
/* ![[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)
*/
2758 {
2759 #if defined(TESTING)
2760 cpu_state_t * cpup = _cpup;
2761 #endif
2762 sim_debug (DBG_TRACE, & scu_dev,
2763 "SMCM SCU unit %d CPU unit %d A %012"PRIo64" Q %012"PRIo64"\r\n",
2764 scu_unit_idx, cpu_unit_udx, rega, regq);
2765
2766 scu_t * up = scu + scu_unit_idx;
2767
2768 // Which port is cpu_unit_udx connected to? (i.e. which port did the
2769 // command come in on?
2770 int scu_port_num = -1; // The port that the rscr instruction was
2771 // received on
2772
2773 for (int pn = 0; pn < N_SCU_PORTS; pn ++)
2774 {
2775 for (int sn = 0; sn < N_SCU_SUBPORTS; sn ++)
2776 {
2777 if (cables->scu_to_cpu[scu_unit_idx][pn][sn].in_use &&
2778 cables->scu_to_cpu[scu_unit_idx][pn][sn].cpu_unit_idx ==
2779 cpu_unit_udx)
2780 {
2781 scu_port_num = pn;
2782 goto gotit;
2783 }
2784 }
2785 }
2786 gotit:;
2787
2788 //sim_printf ("rmcm scu_port_num %d\r\n", scu_port_num);
2789
2790 if (scu_port_num < 0)
2791 {
2792 sim_warn ("%s: can't find cpu port in the snarl of cables; "
2793 "scu_unit_no %d, cpu_unit_udx %d\r\n",
2794 __func__, scu_unit_idx, cpu_unit_udx);
2795 return SCPE_OK;
2796 }
2797
2798 sim_debug (DBG_TRACE, & scu_dev, "SMCM SCU port num %d\r\n", scu_port_num);
2799
2800 // A reg:
2801 // 0 15 16 31 32 35
2802 // IER 0-15 00000000 PER 0-3
2803 // Q reg:
2804 // 0 15 16 31 32 35
2805 // IER 16-32 00000000 PER 4-7
2806
2807 uint imask =
2808 ((uint) getbits36_16(rega, 0) << 16) |
2809 ((uint) getbits36_16(regq, 0) << 0);
2810 #if defined(THREADZ) || defined(LOCKLESS)
2811 lock_scu ();
2812 #endif
2813 if (up -> mask_assignment [0] == (uint) scu_port_num)
2814 {
2815 up -> exec_intr_mask [0] = imask;
2816 sim_debug (DBG_TRACE, & scu_dev, "SMCM intr mask 0 set to %011o\r\n",
2817 imask);
2818 }
2819 else if (up -> mask_assignment [1] == (uint) scu_port_num)
2820 {
2821 up -> exec_intr_mask [1] = imask;
2822 sim_debug (DBG_TRACE, & scu_dev, "SMCM intr mask 1 set to %011o\r\n",
2823 imask);
2824 }
2825
2826 scu [scu_unit_idx].port_enable [0] = (uint) getbits36_1 (rega, 32);
2827 scu [scu_unit_idx].port_enable [1] = (uint) getbits36_1 (rega, 33);
2828 scu [scu_unit_idx].port_enable [2] = (uint) getbits36_1 (rega, 34);
2829 scu [scu_unit_idx].port_enable [3] = (uint) getbits36_1 (rega, 35);
2830 scu [scu_unit_idx].port_enable [4] = (uint) getbits36_1 (regq, 32);
2831 scu [scu_unit_idx].port_enable [5] = (uint) getbits36_1 (regq, 33);
2832 scu [scu_unit_idx].port_enable [6] = (uint) getbits36_1 (regq, 34);
2833 scu [scu_unit_idx].port_enable [7] = (uint) getbits36_1 (regq, 35);
2834
2835 dump_intr_regs ("smcm", scu_unit_idx);
2836 deliver_interrupts (NULL, scu_unit_idx);
2837 #if defined(THREADZ) || defined(LOCKLESS)
2838 unlock_scu ();
2839 #endif
2840
2841 return SCPE_OK;
2842 }