root/src/dps8/dps8_scu.c

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

DEFINITIONS

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

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

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