root/src/dps8/dps8_scu.c

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

DEFINITIONS

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

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