root/src/dps8/dps8_scu.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. scu_set_state
  2. scu_show_nunits
  3. scu_set_nunits
  4. scu_show_state
  5. scu_show_config
  6. scu_set_config
  7. dump_intr_regs
  8. scu_unit_reset
  9. scu_reset
  10. scu_update_not_ready
  11. scuStoreNotReady
  12. scuStoreParityIA
  13. scuReadParityIA
  14. scuCommandParityIA
  15. set_SCU_clock
  16. pcells
  17. deliver_interrupts
  18. scu_smic
  19. scu_sscr
  20. scu_rscr
  21. scu_cioc
  22. scu_set_interrupt
  23. scu_get_highest_intr
  24. scu_reset_unit
  25. scu_init
  26. scu_rmcm
  27. scu_smcm

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

/* [previous][next][first][last][top][bottom][index][help] */