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