root/src/dps8/dps8_cpu.h

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

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. SET_PR_BITNO
  2. SET_AR_CHAR_BITNO
  3. trackport
  4. core_read
  5. core_write
  6. core_write_zone
  7. core_read2
  8. core_write2
  9. core_readN
  10. core_writeN

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: 72d91a53-f62d-11ec-a98f-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2007-2013 Michael Mondy
   9  * Copyright (c) 2012-2016 Harry Reed
  10  * Copyright (c) 2013-2022 Charles Anthony
  11  * Copyright (c) 2015-2021 Eric Swenson
  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 
  20 #if !defined(__STDC_WANT_IEC_60559_BFP_EXT__)
  21 # define __STDC_WANT_IEC_60559_BFP_EXT__ 1
  22 #endif /* if !defined(__STDC_WANT_IEC_60559_BFP_EXT__) */
  23 
  24 #include <sys/types.h>
  25 
  26 #if defined(__APPLE__)
  27 # undef SCHED_NEVER_YIELD
  28 # define SCHED_NEVER_YIELD 1
  29 # include <mach/thread_policy.h>
  30 # include <mach/task_info.h>
  31 # include <sys/types.h>
  32 # include <sys/sysctl.h>
  33 # include <mach/thread_policy.h>
  34 # include <mach/thread_act.h>
  35 #endif /* if defined(__APPLE__) */
  36 
  37 #include "../simh/sim_timer.h"
  38 #include "hdbg.h"
  39 
  40 extern unsigned int nprocs;
  41 extern unsigned int ncores;
  42 extern bool running_perf_test;
  43 
  44 #define N_CPU_UNITS 1 // Default
  45 
  46 // JMP_ENTRY must be 0, which is the return value of the setjmp initial entry
  47 #define JMP_ENTRY             0
  48 #define JMP_REENTRY           1
  49 #define JMP_STOP              2
  50 #define JMP_SYNC_FAULT_RETURN 3
  51 #define JMP_REFETCH           4
  52 #define JMP_RESTART           5
  53 #define JMP_FORCE_RESTART     6
  54 
  55 // The CPU supports 3 addressing modes
  56 // [CAC] I tell a lie: 4 modes...
  57 // [CAC] I tell another lie: 5 modes...
  58 
  59 typedef enum
  60   {
  61     ABSOLUTE_mode,
  62     APPEND_mode,
  63   } addr_modes_e;
  64 
  65 // The control unit of the CPU is always in one of several states. We
  66 // don't currently use all of the states used in the physical CPU.
  67 // The FAULT_EXEC cycle did not exist in the physical hardware.
  68 
  69 typedef enum
  70   {
  71     FAULT_cycle,
  72     EXEC_cycle,
  73     FAULT_EXEC_cycle,
  74     INTERRUPT_cycle,
  75     INTERRUPT_EXEC_cycle,
  76     FETCH_cycle,
  77     PSEUDO_FETCH_cycle,
  78     SYNC_FAULT_RTN_cycle,
  79   } cycles_e;
  80 
  81 struct tpr_s
  82   {
  83     word3   TRR; // The current effective ring number
  84     word15  TSR; // The current effective segment number
  85     word6   TBR; // The current bit offset as calculated from ITS and ITP
  86                  // pointer pairs.
  87     word18  CA;  // The current computed address relative to the origin of the
  88                  // segment whose segment number is in TPR.TSR
  89   };
  90 
  91 struct ppr_s
  92   {
  93     word3   PRR; // The number of the ring in which the process is executing.
  94                  // It is set to the effective ring number of the procedure
  95                  // segment when control is transferred to the procedure.
  96     word15  PSR; // The segment number of the procedure being executed.
  97     word1   P;   // A flag controlling execution of privileged instructions.
  98                  // Its value is 1 (permitting execution of privileged
  99                  // instructions) if PPR.PRR is 0 and the privileged bit in
 100                  // the segment descriptor word (SDW.P) for the procedure is
 101                  // 1; otherwise, its value is 0.
 102     word18  IC;  // The word offset from the origin of the procedure segment
 103                  //  to the current instruction. (same as PPR.IC)
 104   };
 105 
 106 /////
 107 // The terms "pointer register" and "address register" both apply to the same
 108 // physical hardware. The distinction arises from the manner in which the
 109 // register is used and in the interpretation of the register contents.
 110 // "Pointer register" refers to the register as used by the appending unit and
 111 // "address register" refers to the register as used by the decimal unit.
 112 //
 113 // The three forms are compatible and may be freely intermixed. For example,
 114 // PRn may be loaded in pointer register form with the Effective Pointer to
 115 // Pointer Register n (eppn) instruction, then modified in pointer register
 116 // form with the Effective Address to Word/Bit Number of Pointer Register n
 117 // (eawpn) instruction, then further modified in address register form
 118 // (assuming character size k) with the Add k-Bit Displacement to Address
 119 // Register (akbd) instruction, and finally invoked in operand descriptor form
 120 // by the use of MF.AR in an EIS multiword instruction .
 121 //
 122 // The reader's attention is directed to the presence of two bit number
 123 // registers, PRn.BITNO and ARn.BITNO. Because the Multics processor was
 124 // implemented as an enhancement to an existing design, certain apparent
 125 // anomalies appear. One of these is the difference in the handling of
 126 // unaligned data items by the appending unit and decimal unit. The decimal
 127 // unit handles all unaligned data items with a 9-bit byte number and bit
 128 // offset within the byte. Conversion from the description given in the EIS
 129 // operand descriptor is done automatically by the hardware. The appending unit
 130 // maintains compatibility with the earlier generation Multics processor by
 131 // handling all unaligned data items with a bit offset from the prior word
 132 // boundary; again with any necessary conversion done automatically by the
 133 // hardware. Thus, a pointer register, PRn, may be loaded from an ITS pointer
 134 // pair having a pure bit offset and modified by one of the EIS address
 135 // register instructions (a4bd, s9bd, etc.) using character displacement
 136 // counts. The automatic conversion performed ensures that the pointer
 137 // register, PRi, and its matching address register, ARi, both describe the
 138 // same physical bit in main memory.
 139 //
 140 // N.B. Subtle differences between the interpretation of PR/AR. Need to take
 141 // this into account.
 142 //
 143 //     * For Pointer Registers:
 144 //       - PRn.WORDNO The offset in words from the base or origin of the
 145 //                    segment to the data item.
 146 //       - PRn.BITNO  The number of the bit within PRn.WORDNO that is the
 147 //                    first bit of the data item. Data items aligned on word
 148 //                    boundaries always have the value 0. Unaligned data items
 149 //                    may have any value in the range [1,35].
 150 //
 151 //     * For Address Registers:
 152 //       - ARn.WORDNO The offset in words relative to the current addressing
 153 //                    base referent (segment origin, BAR.BASE, or absolute 0
 154 //                    depending on addressing mode) to the word containing the
 155 //                    next data item element.
 156 //       - ARn.CHAR   The number of the 9-bit byte within ARn.WORDNO
 157 //                    containing the first bit of the next data item element.
 158 //       - ARn.BITNO  The number of the bit within ARn.CHAR that is the
 159 //                    first bit of the next data item element.
 160 /////
 161 
 162 struct par_s
 163   {
 164     word15  SNR;      // The segment number of the segment containing the data
 165                       // item described by the pointer register.
 166     word3   RNR;      // The final effective ring number value calculated during
 167                       // execution of the instruction that last loaded the PR.
 168 
 169     word6  PR_BITNO;  // The number of the bit within PRn.WORDNO that is the
 170                       // first bit of the data item. Data items aligned on word
 171                       // boundaries always have the value 0. Unaligned data
 172                       //  items may have any value in the range [1,35].
 173     word2   AR_CHAR;
 174     word4   AR_BITNO;
 175 
 176     word18  WORDNO;   // The offset in words from the base or origin of the
 177                       // segment to the data item.
 178   };
 179 
 180 // N.B. remember there are subtle differences between AR/PR.BITNO
 181 
 182 #define AR    PAR
 183 #define PR    PAR
 184 
 185 struct bar_s
 186   {
 187     word9 BASE;     // Contains the 9 high-order bits of an 18-bit address
 188                     // relocation constant. The low-order bits are generated
 189                     // as zeros.
 190     word9 BOUND;    // Contains the 9 high-order bits of the unrelocated
 191                     // address limit. The low- order bits are generated as
 192                     // zeros. An attempt to access main memory beyond this
 193                     // limit causes a store fault, out of bounds. A value of
 194                     // 0 is truly 0, indicating a null memory range.
 195   };
 196 
 197 struct dsbr_s
 198   {
 199     word24  ADDR;   // If DSBR.U = 1, the 24-bit absolute main memory address
 200                     //  of the origin of the current descriptor segment;
 201                     //  otherwise, the 24-bit absolute main memory address of
 202                     //  the page table for the current descriptor segment.
 203     word14  BND;    // The 14 most significant bits of the highest Y-block16
 204                     //  address of the descriptor segment that can be
 205                     //  addressed without causing an access violation, out of
 206                     //  segment bounds, fault.
 207     word1   U;      // A flag specifying whether the descriptor segment is
 208                     // unpaged (U = 1) or paged (U = 0).
 209     word12  STACK;  // The upper 12 bits of the 15-bit stack base segment
 210                     // number. It is used only during the execution of the
 211                     // call6 instruction. (See Section 8 for a discussion
 212                     //  of generation of the stack segment number.)
 213   };
 214 
 215 // The segment descriptor word (SDW) pair contains information that controls
 216 // the access to a segment. The SDW for segment n is located at offset 2n in
 217 // the descriptor segment whose description is currently loaded into the
 218 // descriptor segment base register (DSBR).
 219 
 220 struct sdw_s
 221   {
 222     word24  ADDR;    // The 24-bit absolute main memory address of the page
 223                      //  table for the target segment if SDWAM.U = 0;
 224                      //  otherwise, the 24-bit absolute main memory address
 225                      //  of the origin of the target segment.
 226     word3   R1;      // Upper limit of read/write ring bracket
 227     word3   R2;      // Upper limit of read/execute ring bracket
 228     word3   R3;      // Upper limit of call ring bracket
 229     word14  BOUND;   // The 14 high-order bits of the last Y-block16 address
 230                      //  within the segment that can be referenced without an
 231                      //  access violation, out of segment bound, fault.
 232     word1   R;       // Read permission bit. If this bit is set ON, read
 233                      //  access requests are allowed.
 234     word1   E;       // Execute permission bit. If this bit is set ON, the SDW
 235                      //  may be loaded into the procedure pointer register
 236                      //  (PPR) and instructions fetched from the segment for
 237                      //  execution.
 238     word1   W;       // Write permission bit. If this bit is set ON, write
 239                      //  access requests are allowed.
 240     word1   P;       // Privileged flag bit. If this bit is set ON, privileged
 241                      //  instructions from the segment may be executed if
 242                      //  PPR.PRR is 0.
 243     word1   U;       // Unpaged flag bit. If this bit is set ON, the segment
 244                      //  is unpaged and SDWAM.ADDR is the 24-bit absolute
 245                      //  main memory address of the origin of the segment. If
 246                      //  this bit is set OFF, the segment is paged andis
 247                      //  SDWAM.ADDR the 24-bit absolute main memory address of
 248                      //  the page table for the segment.
 249     word1   G;       // Gate control bit. If this bit is set OFF, calls and
 250                      //  transfers into the segment must be to an offset no
 251                      //  greater than the value of SDWAM.CL as described
 252                      //  below.
 253     word1   C;       // Cache control bit. If this bit is set ON, data and/or
 254                      //  instructions from the segment may be placed in the
 255                      //  cache memory.
 256     word14  EB;      // Call limiter (entry bound) value. If SDWAM.G is set
 257                      //  OFF, transfers of control into the segment must be to
 258                      //  segment addresses no greater than this value.
 259     word15  POINTER; // The effective segment number used to fetch this SDW
 260                      //  from main memory.
 261     word1   DF;      // Directed fault flag (called F in AL39).
 262                      //  * 0 = page not in main memory; execute directed fault
 263                      //        FC
 264                      //  * 1 = page is in main memory
 265     word2   FC;      // Directed fault number for page fault.
 266     word1   FE;      // Full/empty bit. If this bit is set ON, the SDW in the
 267                      //  register is valid. If this bit is set OFF, a hit is
 268                      //  not possible. All SDWAM.F bits are set OFF by the
 269                      //  instructions that clear the SDWAM.
 270     // L68: word4
 271     // DPS8M: word6
 272     word6   USE;
 273                      // Usage count for the register. The SDWAM.USE field is
 274                      //  used to maintain a strict FIFO queue order among the
 275                      //  SDWs. When an SDW is matched, its USE value is set to
 276                      //  15 (newest) on the DPS/L68 and to 63 on the DPS 8M,
 277                      //  and the queue is reordered. SDWs newly fetched from
 278                      //  main memory replace the SDW with USE value 0 (oldest)
 279                      //  and the queue is reordered.
 280     bool    loaded;
 281                      // DPS8M AM register written since initialization;
 282                      //  its parity bit stays valid when F is cleared
 283   };
 284 
 285 typedef struct sdw_s sdw_s;
 286 typedef struct sdw_s sdw0_s;
 287 
 288 
 289 
 290 
 291 
 292 
 293 
 294 
 295 
 296 
 297 
 298 
 299 
 300 
 301 
 302 
 303 
 304 
 305 
 306 
 307 
 308 
 309 
 310 
 311 
 312 
 313 
 314 
 315 
 316 
 317 
 318 
 319 
 320 
 321 
 322 
 323 
 324 
 325 
 326 
 327 
 328 
 329 
 330 
 331 
 332 
 333 
 334 
 335 
 336 
 337 
 338 
 339 
 340 
 341 
 342 // PTW as used by APU
 343 
 344 struct ptw_s
 345  {
 346     word18  ADDR;    // The 18 high-order bits of the 24-bit absolute
 347                      //  main memory address of the page.
 348     word1   U;       // * 1 = page has been used (referenced)
 349     word1   M;       // Page modified flag bit. This bit is set ON whenever
 350                      //  the PTW is used for a store type instruction. When
 351                      //  the bit changes value from 0 to 1, a special
 352                      //  extra cycle is generated to write it back into the
 353                      //  PTW in the page table in main memory.
 354     word1   DF;      // Directed fault flag
 355                      // * 0 = page not in main memory; execute directed fault FC
 356                      // * 1 = page is in main memory
 357     word2   FC;      // Directed fault number for page fault.
 358     word15  POINTER; // The effective segment number used to fetch this PTW
 359                      //  from main memory.
 360     word12  PAGENO;  // The 12 high-order bits of the 18-bit computed
 361                      //  address (TPR.CA) used to fetch this PTW from main
 362                      //  memory.
 363     word1   FE;      // Full/empty bit. If this bit is set ON, the PTW in
 364                      //  the register is valid. If this bit is set OFF, a
 365                      //  hit is not possible. All PTWAM.F bits are set OFF
 366                      //  by the instructions that clear the PTWAM.
 367     // DPS8M: word6
 368     // L68: word4
 369     word6   USE;
 370                      // Usage count for the register. The PTWAM.USE field
 371                      //  is used to maintain a strict FIFO queue order
 372                      //  among the PTWs. When an PTW is matched its USE
 373                      // value is set to 15 (newest) on the DPS/L68 and to
 374                      //  63 on the DPS 8M, and the queue is reordered.
 375                      //  PTWs newly fetched from main memory replace the
 376                      //  PTW with USE value 0 (oldest) and the queue is
 377                      //  reordered.
 378     bool    loaded;
 379                      // DPS8M AM register written since initialization;
 380                      //  its parity bit stays valid when F is cleared
 381   };
 382 
 383 typedef struct ptw_s ptw_s;
 384 typedef struct ptw_s ptw0_s;
 385 
 386 
 387 
 388 
 389 
 390 
 391 
 392 
 393 
 394 
 395 
 396 
 397 
 398 
 399 
 400 
 401 
 402 
 403 
 404 
 405 //
 406 // Cache Mode Register
 407 //
 408 
 409 struct cache_mode_register_s
 410   {
 411     word15   cache_dir_address;
 412     word1    par_bit;
 413     word1    lev_ful;
 414     word1    csh1_on; // 1: The lower half of the cache memory is active and
 415                       // enabled as per the state of inst_on
 416     word1    csh2_on; // 1: The upper half of the cache memory is active and
 417                       // enabled as per the state of inst_on
 418     // L68 only
 419     word1    opnd_on; // 1: The cache memory (if active) is used for operands.
 420 
 421     word1    inst_on; // 1: The cache memory (if active) is used for
 422                       //  instructions.
 423     // When the cache-to-register mode flag (bit 59 of the cache mode register)
 424     // is set ON, the processor is forced to fetch the operands of all
 425     // double-precision operations unit load operations from the cache memory.
 426     // Y0,12 are ignored, Y15,21 select a column, and Y13,14 select a level.
 427     // All other operations (e.g., instruction fetches, single-precision
 428     // operands, etc.) are treated normally.
 429     word1    csh_reg;
 430     word1    str_asd;
 431     word1    col_ful;
 432     word2    rro_AB;
 433     word1    bypass_cache; // DPS8M only
 434     word2    luf;          // LUF value
 435                            // 0   1   2   3
 436                            // Lockup time
 437                            // 2ms 4ms 8ms 16ms
 438                            // The lockup timer is set to 16ms when the
 439                            // processor is initialized.
 440   };
 441 
 442 typedef struct cache_mode_register_s cache_mode_register_s;
 443 
 444 typedef struct mode_register_s
 445   {
 446     word36 r;
 447     // L68 only
 448                     //  8M      L68
 449     word15 FFV;     //  0       FFV     0 - 14
 450     word1 OC_TRAP;  //  0       a           16
 451     word1 ADR_TRAP; //  0       b           17
 452     word9 OPCODE;   //  0       OPCODE 18 - 26
 453     word1 OPCODEX;  //  0       OPCODE      27
 454 
 455  // word1 cuolin;   //  a       c           18 control unit overlap inhibit
 456  // word1 solin;    //  b       d           19 store overlap inhibit
 457     word1 sdpap;    //  c       e           20 store incorrect data parity
 458     word1 separ;    //  d       f           21 store incorrect ZAC
 459  // word2 tm;       //  e       g      22 - 23 timing margins
 460  // word2 vm;       //  f       h      24 - 25 voltage margins
 461                     //  0       0           26 history register overflow trap
 462                     //  0       0           27 strobe HR on opcode match
 463     word1 hrhlt;    //  g       i           28 history register overflow trap
 464 
 465     // DPS8M only
 466     word1 hrxfr;    //  h       j           29 strobe HR on transfer made
 467     // L68 only
 468                     //  h       j           29 strobe HR on opcode match
 469     word1 ihr;      //  i       k           30 Enable HR
 470     word1 ihrrs;    //  j                   31 HR reset options
 471                     //          l           31 HR lock control
 472                     //  k                   32 margin control
 473                     //          m           32 test mode indicator
 474     // DPS8M only
 475     word1 hexfp;    //  l       0           33 hex mode
 476                     //  0       0           34
 477      word1 emr;     //  m       n           35 enable MR
 478   } mode_register_s;
 479 
 480 extern DEVICE cpu_dev;
 481 
 482 // address of an EIS operand
 483 typedef struct EISaddr_s
 484   {
 485 #if !defined(EIS_PTR)
 486     word18  address;    // 18-bit virtual address
 487 #endif /* if !defined(EIS_PTR) */
 488 
 489     word36  data;
 490     word1    bit;
 491     eRW     mode;
 492 
 493     int     last_bit_posn;  // track for caching tests
 494 
 495     // for type of data being address by this object
 496 
 497     // eisDataType _type;   // type of data - alphanumeric/numeric
 498 
 499 #if !defined(EIS_PTR3)
 500     int     TA;    // type of Alphanumeric chars in src
 501 #endif /* if !defined(EIS_PTR3) */
 502     int     TN;    // type of Numeric chars in src
 503     int     cPos;
 504     int     bPos;
 505 
 506 #if !defined(EIS_PTR4)
 507     // for when using AR/PR register addressing
 508     word15  SNR;                // The segment number of the segment containing the
 509                                 //  data item described by the pointer register.
 510     word3   RNR;                // The effective ring number value calculated during
 511                                 //  execution of the instruction that last loaded.
 512     MemoryAccessType    mat;    // Memory access type for operation.
 513 #endif /* if !defined(EIS_PTR4) */
 514 
 515     // Cache
 516 
 517     // There is a cache for each operand, but they do not cross check;
 518     // this means that if one of them has a cached dirty word, the
 519     // others will not check for a hit, and will use the old value.
 520     // AL39 warns that overlapping operands can cause unexpected behavior
 521     // due to caching issues, so the this behavior is closer to the actual
 522     // h/w then to the theoretical need for cache consistency.
 523 
 524     // We don't need to cache mat or TPR because they will be constant
 525     // across an instruction.
 526 
 527     bool cacheValid;
 528     bool cacheDirty;
 529 #define paragraphSz 8
 530 #define paragraphMask 077777770
 531 #define paragraphOffsetMask 07
 532     word36 cachedParagraph [paragraphSz];
 533     bool wordDirty [paragraphSz];
 534     word18 cachedAddr;
 535 
 536   } EISaddr;
 537 
 538 typedef struct EISstruct_s
 539   {
 540     word36  op [3];         // raw operand descriptors
 541 #define OP1 op [0]          // 1st descriptor (2nd ins word)
 542 #define OP2 op [1]          // 2nd descriptor (3rd ins word)
 543 #define OP3 op [2]          // 3rd descriptor (4th ins word)
 544 
 545     bool     P;             // 4-bit data sign character control
 546 
 547     uint    MF [3];
 548 #define MF1 MF [0]          // Modification field for operand descriptor 1
 549 #define MF2 MF [1]          // Modification field for operand descriptor 2
 550 #define MF3 MF [2]          // Modification field for operand descriptor 3
 551 
 552     uint    CN [3];
 553 #define CN1 CN [0]
 554 #define CN2 CN [1]
 555 #define CN3 CN [2]
 556 
 557     uint    WN [3];
 558 #define WN1 WN [0]
 559 #define WN2 WN [1]
 560 #define WN3 CN [2]
 561 
 562    uint     C [3];
 563 #define C1  C [0]
 564 #define C2  C [1]
 565 #define C3  C [2]
 566 
 567    uint     B [3];
 568 #define B1  B [0]
 569 #define B2  B [1]
 570 #define B3  B [2]
 571 
 572    uint     N [3];
 573 #define N1  N [0]
 574 #define N2  N [1]
 575 #define N3  N [2]
 576 
 577     uint    TN [3];         // type numeric
 578 #define TN1 TN [0]
 579 #define TN2 TN [1]
 580 #define TN3 TN [2]
 581 
 582 #if defined(EIS_PTR3)
 583 # define TA1 cpu.du.TAk[0]
 584 # define TA2 cpu.du.TAk[1]
 585 # define TA3 cpu.du.TAk[2]
 586 #else
 587 
 588     uint     TA [3];        // type alphanumeric
 589 # define TA1 TA [0]
 590 # define TA2 TA [1]
 591 # define TA3 TA [2]
 592 #endif /* if defined(EIS_PTR3) */
 593 
 594    uint     S [3];          // Sign and decimal type of number
 595 #define S1  S [0]
 596 #define S2  S [1]
 597 #define S3  S [2]
 598 
 599     int     SF [3];         // scale factor
 600 #define SF1 SF [0]
 601 #define SF2 SF [1]
 602 #define SF3 SF [2]
 603 
 604     word18 _flags;          // flags set during operation
 605     word18 _faults;         // faults generated by instruction
 606 
 607     word72s x;              // a signed, 128-bit integers for playing with ...
 608 
 609     // Stuff for Micro-operations and Edit instructions...
 610 
 611     word9   editInsertionTable [8];     // 8 9-bit chars
 612 
 613     int     mopIF;          // current micro-operation IF field
 614     struct MOP_struct_s *m;          // pointer to current MOP struct
 615 
 616     word9   inBuffer [64];  // decimal unit input buffer
 617     word9   *in;            // pointer to current read position in inBuffer
 618     uint    inBufferCnt;    // number of characters in inBuffer
 619     word9   outBuffer [64]; // output buffer
 620     word9   *out;           // pointer to current write position in outBuffer;
 621 
 622     int     exponent;       // For decimal floating-point (evil)
 623     int     sign;           // For signed decimal (1, -1)
 624 
 625 #if defined(EIS_PTR2)
 626 # define KMOP 1
 627 #else
 628     EISaddr *mopAddress;    // mopAddress, pointer to addr [0], [1], or [2]
 629 #endif /* if defined(EIS_PTR2) */
 630 
 631     int     mopTally;       // number of micro-ops
 632     int     mopPos;         // current mop char posn
 633 
 634     // Edit Flags
 635     // The processor provides the following four edit flags for use by the
 636     // micro operations.
 637 
 638     bool    mopES;          // End Suppression flag; initially OFF, set ON by
 639                             //  a micro operation when zero-suppression ends.
 640     bool    mopSN;          // Sign flag; initially set OFF if the sending
 641                             //  string has an alphanumeric descriptor or an
 642                             //  unsigned numeric descriptor. If the sending
 643                             //  string has a signed numeric descriptor, the
 644                             //  sign is initially read from the sending string
 645                             //  from the digit position defined by the sign
 646                             //  and the decimal type field (S); SN is set
 647                             //  OFF if positive, ON if negative. If all
 648                             //  digits are zero, the data is assumed positive
 649                             //  and the SN flag is set OFF, even when the
 650                             //  sign is negative.
 651     bool    mopZ;           // Zero flag; initially set ON. It is set OFF
 652                             //  whenever a sending string character that is not
 653                             //  decimal zero is moved into the receiving string.
 654     bool    mopBZ;          // Blank-when-zero flag; initially set OFF and
 655                             //  set ON by either the ENF or SES micro
 656                             //  operation. If, at the completion of a move
 657                             //  (L1 exhausted), both the Z and BZ flags are
 658                             //  ON, the receiving string is filled with
 659                             //  character 1 of the edit insertion table.
 660 
 661     EISaddr addr [3];
 662 
 663 #define ADDR1       addr [0]
 664     int     srcTally;       // number of chars in src (max 63)
 665     int     srcTA;          // type of Alphanumeric chars in src
 666     int     srcSZ;          // size of chars in src (4-, 6-, or 9-bits)
 667 
 668 #define ADDR2       addr [1]
 669 
 670 #define ADDR3       addr [2]
 671     int     dstTally;       // number of chars in dst (max 63)
 672     int     dstSZ;          // size of chars in dst (4-, 6-, or 9-bits)
 673 
 674     bool    mvne;           // for MSES micro-op. True when mvne, false when mve
 675   } EISstruct;
 676 
 677 // Instruction decode structure. Used to represent instruction information
 678 
 679 typedef struct DCDstruct_s
 680   {
 681     struct opcode_s * info; // opcode_s *
 682     uint32 opcode;          // opcode
 683     bool   opcodeX;         // opcode extension
 684     uint32 opcode10;        // opcode | (opcodeX ? 01000 : 0)
 685     word18 address;         // bits 0-17 of instruction
 686     word1  b29;             // bit-29 - address via pointer register. Usually.
 687     bool   i;               // interrupt inhibit bit.
 688     word6  tag;             // instruction tag
 689 
 690     bool stiTally;          // for sti instruction
 691     bool restart;           // instruction is to be restarted
 692   } DCDstruct;
 693 
 694 // Emulator-only interrupt and fault info
 695 
 696 typedef struct
 697   {
 698     volAtomic int fault [N_FAULT_GROUPS];
 699                             // only one fault in groups 1..6 can be pending
 700     volAtomic bool XIP [N_SCU_UNITS_MAX];
 701   } events_t;
 702 
 703 // Physical Switches
 704 
 705 enum procModeSettings { procModeGCOS = 1, procModeMultics = 0 };
 706 
 707 // Switches on the Processor's maintenance and configuration panels
 708 typedef struct
 709   {
 710     uint FLT_BASE; // normally 7 MSB of 12bit fault base addr
 711     uint cpu_num;  // zero for CPU 'A', one for 'B' etc.
 712     word36 data_switches;
 713     word18 addr_switches;
 714     uint assignment [N_CPU_PORTS];
 715     uint interlace [N_CPU_PORTS];    // 0/2/4
 716     uint enable [N_CPU_PORTS];
 717     uint init_enable [N_CPU_PORTS];
 718     uint store_size [N_CPU_PORTS];   // 0-7 encoding 32K-4M
 719     enum procModeSettings procMode;  // 1 bit  Read by rsw instruction; format unknown
 720 
 721     bool enable_cache;   // Enable 8K cache
 722     bool sdwam_enable;   // Enable Segment Descriptor WAM
 723     bool ptwam_enable;   // Enable Page Table WAM
 724 
 725     // CPU serial number; not strictly a switch; on DPS8/M, burned into the CPU PROM
 726     uint serno;
 727   } switches_t;
 728 
 729 // Optional H/W
 730 typedef struct {
 731   uint proc_speed; // 4 bits Read by rsw instruction; format unknown
 732   bool hex_mode_installed;
 733   bool prom_installed;
 734   bool cache_installed;
 735   bool clock_slave_installed;
 736 } optionsType;
 737 
 738 // Hardware tweaks
 739 typedef struct {
 740     uint report_faults;   // If set, faults are reported and ignored
 741     uint tro_enable;      // If set, Timer runout faults are generated.
 742     uint drl_fatal;       // If set, DRL instructions halt the CPU
 743     bool useMap;          // If set, consult memory configuration switches to translate memory
 744                           //          addresses to SCU memory banks
 745     uint dis_enable;      // If non-zero, DIS instruction works
 746     uint halt_on_unimp;   // If non-zero, halt CPU on unimplemented instruction instead of faulting
 747     bool isolts_mode;     // If true, CPU is configured to run ISOLTS.
 748     bool tandd_mode;      // If true, CPU runs the T&D tape: T&D-only
 749                           // behaviour; switches come from the ini.
 750     uint enable_wam;      // If zero, the simulated cache is ignored and always returns "miss";
 751                           //           turning it on incurs a large performance hit.
 752     bool enable_emcall;   // If set, the instruction set is extended with simulator debugging instructions
 753     bool nodis;           // If true, start CPU in FETCH cycle; else start in DIS instruction
 754     bool l68_mode;        // False: DPS8/M; True: 6180
 755 } tweaksType;
 756 
 757 enum ou_cycle_e
 758   {
 759     ou_GIN = 0400,
 760     ou_GOS = 0200,
 761     ou_GD1 = 0100,
 762     ou_GD2 = 0040,
 763     ou_GOE = 0020,
 764     ou_GOA = 0010,
 765     ou_GOM = 0004,
 766     ou_GON = 0002,
 767     ou_GOF = 0001
 768   };
 769 
 770 typedef struct
 771   {
 772     // Operations Unit/Address Modification
 773     bool   directOperandFlag;
 774     word36 directOperand;
 775     word6  characterOperandSize; // just the left most bit
 776     word3  characterOperandOffset;
 777     word18 character_address;
 778     word36 character_data;
 779     bool crflag;
 780 
 781     // L68 only
 782     word2 eac;
 783     word1 RB1_FULL;
 784     word1 RP_FULL;
 785     word1 RS_FULL;
 786     word9 cycle;
 787     word1 STR_OP;
 788     word9 RS;      // opcode, for the OU history register
 789     // End L68 only
 790 
 791 #if defined(PANEL68)
 792     word4 opsz;
 793     word10 reguse;
 794 #endif /* if defined(PANEL68) */
 795   } ou_unit_data_t;
 796 
 797 // APU history operation parameter
 798 
 799 enum APUH_e
 800   {
 801     APUH_FDSPTW = 1llu << (35 - 17),
 802     APUH_MDSPTW = 1llu << (35 - 18),
 803     APUH_FSDWP  = 1llu << (35 - 19),
 804     APUH_FPTW   = 1llu << (35 - 20),
 805     APUH_FPTW2  = 1llu << (35 - 21),
 806     APUH_MPTW   = 1llu << (35 - 22),
 807     APUH_FANP   = 1llu << (35 - 23),
 808     APUH_FAP    = 1llu << (35 - 24)
 809   };
 810 
 811 enum {
 812 //   AL39 pg 64 APU hist.
 813         apu_FLT = 1ll << (33 -  0), //  0   l FLT Access violation or directed
 814                                     //            fault on this cycle
 815                                     //  1-2 a BSY    Data source for ESN
 816     apu_ESN_PSR = 0,                //                  00 PPR.PSR
 817     apu_ESN_SNR = 1ll << (33 -  1), //                  01 PRn.SNR
 818     apu_ESN_TSR = 1ll << (33 -  2), //                  10 TPR.TSR
 819                                     //                  11 not used
 820                                     //  3     PRAP
 821        apu_HOLD = 1ll << (33 -  4), //  4     HOLD  An access violation or
 822                                     //              directed fault is waiting
 823                                     //  5     FRIW
 824                                     //  6     XSF
 825                                     //  7     STF
 826        apu_TP_P = 1ll << (33 -  8), //  8     TP P    Guessing PPR.p set from
 827                                     //                SDW.P
 828        apu_PP_P = 1ll << (33 -  9), //  9     PP P    PPR.P?
 829                                     // 10     ?
 830                                     // 11     S-ON   Segment on?
 831                                     // 12     ZMAS
 832                                     // 13     SDMF   Seg. Descr. Modify?
 833                                     // 14     SFND
 834                                     // 15     ?
 835                                     // 16     P-ON   Page on?
 836                                     // 17     ZMAP
 837                                     // 18     PTMF
 838                                     // 19     PFND
 839       apu_FDPT  = 1ll << (33 - 20), // 20   b FDPT   Fetch descriptor segment PTW
 840       apu_MDPT  = 1ll << (33 - 21), // 21   c MDPT   Modify descriptor segment PTW
 841       apu_FSDP  = 1ll << (33 - 22), // 22   d FSDP   Fetch SDW paged descr. seg.
 842       apu_FSDN  = 1ll << (33 - 23), // 23     FSDN   Fetch SDW non-paged
 843       apu_FPTW  = 1ll << (33 - 24), // 24   e FPTW   Fetch PTW
 844       apu_MPTW  = 1ll << (33 - 25), // 25   g MPTW   Modify PTW
 845       apu_FPTW2 = 1ll << (33 - 26), // 26   f FPT2   // Fetch prepage
 846       apu_FAP   = 1ll << (33 - 27), // 27   i FAP    Final address fetch from
 847                                     //               paged seg.
 848       apu_FANP  = 1ll << (33 - 28), // 28   h FANP   Final address fetch from
 849                                     //               non-paged segment
 850                                     // 29     FAAB   Final address absolute?
 851       apu_FA    = 1ll << (33 - 30), // 30     FA     Final address?
 852                                     // 31     EAAU
 853       apu_PIAU  = 1ll << (33 - 32)  // 32     PIAU   Instruction fetch?
 854                                     // 33     TGAU
 855   };
 856 
 857 typedef struct
 858   {
 859     processor_cycle_type lastCycle;
 860 #if defined(PANEL68)
 861     word34 state;
 862 #endif /* if defined(PANEL68) */
 863   } apu_unit_data_t;
 864 
 865 typedef struct
 866   {
 867     // NB: Some of the data normally stored here is represented
 868     // elsewhere -- e.g.,the PPR is a variable outside of this
 869     // struct.   Other data is live and only stored here.
 870 
 871     // This is a collection of flags and registers from the
 872     // appending unit and the control unit.  The scu and rcu
 873     // instructions store and load these values to an 8 word
 874     // memory block.
 875     //
 876     // The CU data may only be valid for use with the scu and
 877     // rcu instructions.
 878     //
 879     // Comments indicate format as stored in 8 words by the scu
 880     // instruction.
 881 
 882     // NOTE: PPR (procedure pointer register) is a combination of registers:
 883     //   From the Appending Unit
 884     //     PRR bits [0..2] of word 0
 885     //     PSR bits [3..17] of word 0
 886     //     P   bit 18 of word 0
 887     //   From the Control Unit
 888     //     IC  bits [0..17] of word 4
 889 
 890     /* word 0 */
 891                    // 0-2   PRR is stored in PPR
 892                    // 3-17  PSR is stored in PPR
 893                    // 18    P   is stored in PPR
 894     word1 XSF;     // 19    XSF External segment flag
 895     word1 SDWAMM;  // 20    SDWAMM Match on SDWAM
 896     word1 SD_ON;   // 21    SDWAM enabled
 897     word1 PTWAMM;  // 22    PTWAMM Match on PTWAM
 898     word1 PT_ON;   // 23    PTWAM enabled
 899 
 900 
 901 
 902 
 903 
 904 
 905 
 906 
 907 
 908 
 909 
 910 
 911 
 912     word12 APUCycleBits;
 913 
 914 
 915     /* word 1 */
 916                    //                 AVF Access Violation Fault
 917                    //                 SF  Store Fault
 918                    //                 IPF Illegal Procedure Fault
 919                    //
 920     word1 IRO_ISN; //  0    IRO       AVF Illegal Ring Order
 921                    //       ISN       SF  Illegal segment number
 922     word1 OEB_IOC; //  1    ORB       AVF Out of execute bracket [sic] should
 923                    //                     be OEB?
 924                    //       IOC       IPF Illegal op code
 925     word1 EOFF_IAIM;
 926                    //  2    E-OFF     AVF Execute bit is off
 927                    //       IA+IM     IPF Illegal address of modifier
 928     word1 ORB_ISP; //  3    ORB       AVF Out of read bracket
 929                    //       ISP       IPF Illegal slave procedure
 930     word1 ROFF_IPR;//  4    R-OFF     AVF Read bit is off
 931                    //       IPR       IPF Illegal EIS digit
 932     word1 OWB_NEA; //  5    OWB       AVF Out of write bracket
 933                    //       NEA       SF  Nonexistent address
 934     word1 WOFF_OOB;//  6    W-OFF     AVF Write bit is off
 935                    //       OOB       SF  Out of bounds (BAR mode)
 936     word1 NO_GA;   //  7    NO GA     AVF Not a gate
 937     word1 OCB;     //  8    OCB       AVF Out of call bracket
 938     word1 OCALL;   //  9    OCALL     AVF Outward call
 939     word1 BOC;     // 10    BOC       AVF Bad outward call
 940 // PTWAM error is DPS8M only
 941     word1 PTWAM_ER;// 11    PTWAM_ER  AVF PTWAM error // inward return
 942     word1 CRT;     // 12    CRT       AVF Cross ring transfer
 943     word1 RALR;    // 13    RALR      AVF Ring alarm
 944 // On DPS8M a SDWAM error, on DP8/L68 a WAM error
 945     word1 SDWAM_ER;// 14    SWWAM_ER  AVF SDWAM error
 946     word1 OOSB;    // 15    OOSB      AVF Out of segment bounds
 947     word1 PARU;    // 16    PARU      Parity fault - processor parity upper
 948     word1 PARL;    // 17    PARL      Parity fault - processor parity lower
 949     word1 ONC1;    // 18    ONC1      Operation not complete fault error #1
 950     word1 ONC2;    // 19    ONC2      Operation not complete fault error #2
 951     word4 IA;      // 20-23 IA        System control illegal action lines
 952     word3 IACHN;   // 24-26 IACHN     Illegal action processor port
 953     word3 CNCHN;   // 27-29 CNCHN     Connect fault - connect processor port
 954     word5 FI_ADDR; // 30-34 F/I ADDR  Modulo 2 fault/interrupt vector address
 955     word1 FLT_INT; // 35    F/I       0 = interrupt; 1 = fault
 956 
 957     /* word 2 */
 958                    //  0- 2 TRR
 959                    //  3-17 TSR
 960                    // 18-21 PTW
 961                    //                  18  PTWAM levels A, B enabled
 962                    //                  19  PTWAM levels C, D enabled
 963                    //                  20  PTWAM levels A, B match
 964                    //                  21  PTWAM levels C, D match
 965                    // 22-25 SDW
 966                    //                  22  SDWAM levels A, B enabled
 967                    //                  23  SDWAM levels C, D enabled
 968                    //                  24  SDWAM levels A, B match
 969                    //                  25  SDWAM levels C, D match
 970                    // 26             0
 971                    // 27-29 CPU      CPU Number
 972     word6 delta;   // 30-35 DELTA    addr increment for repeats
 973 
 974     /* word 3 */
 975                    //  0-17          0
 976                    // 18-21 TSNA     Pointer register number for non-EIS
 977                    //                operands or EIS Operand #1
 978                    //                  18-20 PRNO Pointer register number
 979                    //                  21       PRNO is valid
 980                    // 22-25 TSNB     Pointer register number for EIS operand #2
 981                    //                  22-24 PRNO Pointer register number
 982                    //                  25       PRNO is valid
 983                    // 26-29 TSNC     Pointer register number for EIS operand #2
 984                    //                  26-28 PRNO Pointer register number
 985                    //                  29       PRNO is valid
 986     word3 TSN_PRNO [3];
 987     word1 TSN_VALID [3];
 988 
 989                    // 30-35 TEMP BIT Current bit offset (TPR.TBR)
 990 
 991     /* word 4 */
 992                    //  0-17 PPR.IC
 993     word18 IR;     // 18-35 Indicator register
 994                    //    18 ZER0
 995                    //    19 NEG
 996                    //    20 CARY
 997                    //    21 OVFL
 998                    //    22 EOVF
 999                    //    23 EUFL
1000                    //    24 OFLM
1001                    //    25 TRO
1002                    //    26 PAR
1003                    //    27 PARM
1004                    //    28 -BM
1005                    //    29 TRU
1006                    //    30 MIF
1007                    //    31 ABS
1008                    //    32 HEX [sic] Figure 3-32 is wrong.
1009                    // 33-35 0
1010 
1011     /* word 5 */
1012 
1013                    //  0-17 COMPUTED ADDRESS (TPR.CA)
1014     word1 repeat_first;
1015                    // 18    RF  First cycle of all repeat instructions
1016     word1 rpt;     // 19    RPT Execute an Repeat (rpt) instruction
1017     word1 rd;      // 20    RD  Execute an Repeat Double (rpd) instruction
1018     word1 rl;      // 21    RL  Execute a Repeat Link (rpl) instruction
1019     word1 pot;     // 22    POT Prepare operand tally
1020                    // 23    PON Prepare operand no tally
1021     //xde xdo
1022     // 0   0   no execute           -> 0 0
1023     // 1   0   execute XEC          -> 0 0
1024     // 1   1   execute even of XED  -> 0 1
1025     // 0   1   execute odd of XED   -> 0 0
1026     word1 xde;     // 24    XDE Execute instruction from Execute Double even
1027                    //       pair
1028     word1 xdo;     // 25    XDO Execute instruction from Execute Double odd pair
1029     word1 itp;     // 26    ITP Execute ITP indirect cycle
1030     word1 rfi;     // 27    RFI Restart this instruction
1031     word1 its;     // 28    ITS Execute ITS indirect cycle
1032     word1 FIF;     // 29    FIF Fault occurred during instruction fetch
1033     word6 CT_HOLD; // 30-35 CT HOLD contents of the "remember modifier" register
1034 
1035     /* word 6 */
1036     word36 IWB;
1037 
1038     /* word 7 */
1039     word36 IRODD; /* Instr holding register; odd word of last pair fetched */
1040  } ctl_unit_data_t;
1041 
1042 #define USE_IRODD (cpu.cu.rd && ((cpu. PPR.IC & 1) != 0))
1043 #define IWB_IRODD (USE_IRODD ? cpu.cu.IRODD : cpu.cu.IWB)
1044 
1045 // L68 only
1046 enum du_cycle1_e
1047   {
1048     //  0 -FPOL Prepare operand length
1049     du1_nFPOL        = 0400000000000ull,
1050     //  1 -FPOP Prepare operand pointer
1051     du1_nFPOP        = 0200000000000ull,
1052     //  2 -NEED-DESC Need descriptor
1053     du1_nNEED_DESC   = 0100000000000ull,
1054     //  3 -SEL-ADR Select address register
1055     du1_nSEL_DIR     = 0040000000000ull,
1056     //  4 -DLEN=DIRECT Length equals direct
1057     du1_nDLEN_DIRECT = 0020000000000ull,
1058     //  5 -DFRST Descriptor processed for first time
1059     du1_nDFRST       = 0010000000000ull,
1060     //  6 -FEXR Extended register modification
1061     du1_nFEXR        = 0004000000000ull,
1062     //  7 -DLAST-FRST Last cycle of DFRST
1063     du1_nLAST_DFRST  = 0002000000000ull,
1064     //  8 -DDU-LDEA Decimal unit load  (lpl?)
1065     du1_nDDU_LDEA    = 0001000000000ull,
1066     //  9 -DDU-STAE Decimal unit store (spl?)
1067     du1_nDDU_STEA    = 0000400000000ull,
1068     // 10 -DREDO Redo operation without pointer and length update
1069     du1_nDREDO       = 0000200000000ull,
1070     // 11 -DLVL<WD-SZ Load with count less than word size
1071     du1_nDLVL_WD_SZ  = 0000100000000ull,
1072     // 12 -EXH Exhaust
1073     du1_nEXH         = 0000040000000ull,
1074     // 13 DEND-SEQ End of sequence
1075     du1_DEND_SEQ     = 0000020000000ull,
1076     // 14 -DEND End of instruction
1077     du1_nEND         = 0000010000000ull,
1078     // 15 -DU=RD+WRT Decimal unit write-back
1079     du1_nDU_RD_WRT   = 0000004000000ull,
1080     // 16 -PTRA00 PR address bit 0
1081     du1_nPTRA00      = 0000002000000ull,
1082     // 17 -PTRA01 PR address bit 1
1083     du1_nPTRA01      = 0000001000000ull,
1084     // 18 FA/Il Descriptor l active
1085     du1_FA_I1        = 0000000400000ull,
1086     // 19 FA/I2 Descriptor 2 active
1087     du1_FA_I2        = 0000000200000ull,
1088     // 20 FA/I3 Descriptor 3 active
1089     du1_FA_I3        = 0000000100000ull,
1090     // 21 -WRD Word operation
1091     du1_nWRD         = 0000000040000ull,
1092     // 22 -NINE 9-bit character operation
1093     du1_nNINE        = 0000000020000ull,
1094     // 23 -SIX 6-bit character operation
1095     du1_nSIX         = 0000000010000ull,
1096     // 24 -FOUR 4-bit character operation
1097     du1_nFOUR        = 0000000004000ull,
1098     // 25 -BIT Bit operation
1099     du1_nBIT         = 0000000002000ull,
1100     // 26 Unused
1101     //               = 0000000001000ull,
1102     // 27 Unused
1103     //               = 0000000000400ull,
1104     // 28 Unused
1105     //               = 0000000000200ull,
1106     // 29 Unused
1107     //               = 0000000000100ull,
1108     // 30 FSAMPL Sample for mid-instruction interrupt
1109     du1_FSAMPL       = 0000000000040ull,
1110     // 31 -DFRST-CT Specified first count of a sequence
1111     du1_nDFRST_CT    = 0000000000020ull,
1112     // 32 -ADJ-LENGTH Adjust length
1113     du1_nADJ_LENTGH  = 0000000000010ull,
1114     // 33 -INTRPTD Mid-instruction interrupt
1115     du1_nINTRPTD     = 0000000000004ull,
1116     // 34 -INHIB Inhibit STC1 (force "STC0")
1117     du1_nINHIB       = 0000000000002ull,
1118     // 35 Unused
1119     //               = 0000000000001ull,
1120   };
1121 
1122 // L68 only
1123 enum du_cycle2_e
1124   {
1125     // 36 DUD Decimal unit idle
1126     du2_DUD          = 0400000000000ull,
1127     // 37 -GDLDA Descriptor load gate A
1128     du2_nGDLDA       = 0200000000000ull,
1129     // 38 -GDLDB Descriptor load gate B
1130     du2_nGDLDB       = 0100000000000ull,
1131     // 39 -GDLDC Descriptor load gate C
1132     du2_nGDLDC       = 0040000000000ull,
1133     // 40 NLD1 Prepare alignment count for first numeric operand load
1134     du2_NLD1         = 0020000000000ull,
1135     // 41 GLDP1 Numeric operand one load gate
1136     du2_GLDP1        = 0010000000000ull,
1137     // 42 NLD2 Prepare alignment count for second numeric operand load
1138     du2_NLD2         = 0004000000000ull,
1139     // 43 GLDP2 Numeric operand two load gate
1140     du2_GLDP2        = 0002000000000ull,
1141     // 44 ANLD1 Alphanumeric operand one load gate
1142     du2_ANLD1        = 0001000000000ull,
1143     // 45 ANLD2 Alphanumeric operand two load gate
1144     du2_ANLD2        = 0000400000000ull,
1145     // 46 LDWRT1 Load rewrite register one gate (XXX Guess indirect desc. MFkID)
1146     du2_LDWRT1       = 0000200000000ull,
1147     // 47 LDWRT2 Load rewrite register two gate (XXX Guess indirect desc. MFkID)
1148     du2_LDWRT2       = 0000100000000ull,
1149     // 50 -DATA-AVLDU Decimal unit data available
1150     du2_nDATA_AVLDU  = 0000040000000ull,
1151     // 49 WRT1 Rewrite register one loaded
1152     du2_WRT1         = 0000020000000ull,
1153     // 50 GSTR Numeric store gate
1154     du2_GSTR         = 0000010000000ull,
1155     // 51 ANSTR Alphanumeric store gate
1156     du2_ANSTR        = 0000004000000ull,
1157     // 52 FSTR-OP-AV Operand available to be stored
1158     du2_FSTR_OP_AV   = 0000002000000ull,
1159     // 53 -FEND-SEQ End sequence flag
1160     du2_nFEND_SEQ    = 0000001000000ull,
1161     // 54 -FLEN<128 Length less than 128
1162     du2_nFLEN_128    = 0000000400000ull,
1163     // 55 FGCH Character operation gate
1164     du2_FGCH         = 0000000200000ull,
1165     // 56 FANPK Alphanumeric packing cycle gate
1166     du2_FANPK        = 0000000100000ull,
1167     // 57 FEXMOP Execute MOP gate
1168     du2_FEXOP        = 0000000040000ull,
1169     // 58 FBLNK Blanking gate
1170     du2_FBLNK        = 0000000020000ull,
1171     // 59 Unused
1172     //               = 0000000010000ull,
1173     // 60 DGBD Binary to decimal execution gate
1174     du2_DGBD         = 0000000004000ull,
1175     // 61 DGDB Decimal to binary execution gate
1176     du2_DGDB         = 0000000002000ull,
1177     // 62 DGSP Shift procedure gate
1178     du2_DGSP         = 0000000001000ull,
1179     // 63 FFLTG Floating result flag
1180     du2_FFLTG        = 0000000000400ull,
1181     // 64 FRND Rounding flag
1182     du2_FRND         = 0000000000200ull,
1183     // 65 DADD-GATE Add/subtract execute gate
1184     du2_DADD_GATE    = 0000000000100ull,
1185     // 66 DMP+DV-GATE Multiply/divide execution gate
1186     du2_DMP_DV_GATE  = 0000000000040ull,
1187     // 67 DXPN-GATE Exponent network execution gate
1188     du2_DXPN_GATE    = 0000000000020ull,
1189     // 68 Unused
1190     //               = 0000000000010ull,
1191     // 69 Unused
1192     //               = 0000000000004ull,
1193     // 70 Unused
1194     //               = 0000000000002ull,
1195     // 71 Unused
1196     //               = 0000000000001ull,
1197   };
1198 
1199 // L68 only
1200 #define DU_CYCLE_GDLDA {   clrmask (& cpu.du.cycle2, du2_nGDLDA);              \
1201                            setmask (& cpu.du.cycle2, du2_nGDLDB | du2_nGDLDC); }
1202 #define DU_CYCLE_GDLDB {   clrmask (& cpu.du.cycle2, du2_nGDLDB);              \
1203                            setmask (& cpu.du.cycle2, du2_nGDLDA | du2_nGDLDC); }
1204 #define DU_CYCLE_GDLDC {   clrmask (& cpu.du.cycle2, du2_nGDLDC);              \
1205                            setmask (& cpu.du.cycle2, du2_nGDLDA | du2_nGDLDB); }
1206 #define DU_CYCLE_FA_I1     setmask (& cpu.du.cycle1, du1_FA_I1)
1207 #define DU_CYCLE_FA_I2     setmask (& cpu.du.cycle1, du1_FA_I2)
1208 #define DU_CYCLE_FA_I3     setmask (& cpu.du.cycle1, du1_FA_I3)
1209 #define DU_CYCLE_ANLD1     setmask (& cpu.du.cycle2, du2_ANLD1)
1210 #define DU_CYCLE_ANLD2     setmask (& cpu.du.cycle2, du2_ANLD2)
1211 #define DU_CYCLE_NLD1      setmask (& cpu.du.cycle2, du2_NLD1)
1212 #define DU_CYCLE_NLD2      setmask (& cpu.du.cycle2, du2_NLD2)
1213 #define DU_CYCLE_FRND      setmask (& cpu.du.cycle2, du2_FRND)
1214 #define DU_CYCLE_DGBD      setmask (& cpu.du.cycle2, du2_DGBD)
1215 #define DU_CYCLE_DGDB      setmask (& cpu.du.cycle2, du2_DGDB)
1216 #define DU_CYCLE_DDU_LDEA  clrmask (& cpu.du.cycle1, du1_nDDU_LDEA)
1217 #define DU_CYCLE_DDU_STEA  clrmask (& cpu.du.cycle1, du1_nDDU_STEA)
1218 #define DU_CYCLE_END       clrmask (& cpu.du.cycle1, du1_nEND)
1219 #define DU_CYCLE_LDWRT1    setmask (& cpu.du.cycle2, du2_LDWRT1)
1220 #define DU_CYCLE_LDWRT2    setmask (& cpu.du.cycle2, du2_LDWRT2)
1221 #define DU_CYCLE_FEXOP     setmask (& cpu.du.cycle2, du2_FEXOP)
1222 #define DU_CYCLE_ANSTR     setmask (& cpu.du.cycle2, du2_ANSTR)
1223 #define DU_CYCLE_GSTR      setmask (& cpu.du.cycle2, du2_GSTR)
1224 #define DU_CYCLE_FLEN_128  clrmask (& cpu.du.cycle2, du2_nFLEN_128)
1225 #define DU_CYCLE_FDUD  { cpu.du.cycle1 = \
1226                       du1_nFPOL        | \
1227                       du1_nFPOP        | \
1228                       du1_nNEED_DESC   | \
1229                       du1_nSEL_DIR     | \
1230                       du1_nDLEN_DIRECT | \
1231                       du1_nDFRST       | \
1232                       du1_nFEXR        | \
1233                       du1_nLAST_DFRST  | \
1234                       du1_nDDU_LDEA    | \
1235                       du1_nDDU_STEA    | \
1236                       du1_nDREDO       | \
1237                       du1_nDLVL_WD_SZ  | \
1238                       du1_nEXH         | \
1239                       du1_nEND         | \
1240                       du1_nDU_RD_WRT   | \
1241                       du1_nWRD         | \
1242                       du1_nNINE        | \
1243                       du1_nSIX         | \
1244                       du1_nFOUR        | \
1245                       du1_nBIT         | \
1246                       du1_nINTRPTD     | \
1247                       du1_nINHIB;        \
1248                     cpu.du.cycle2 =      \
1249                       du2_DUD          | \
1250                       du2_nGDLDA       | \
1251                       du2_nGDLDB       | \
1252                       du2_nGDLDC       | \
1253                       du2_nDATA_AVLDU  | \
1254                       du2_nFEND_SEQ    | \
1255                       du2_nFLEN_128;     \
1256                   }
1257 #define DU_CYCLE_nDUD clrmask (& cpu.du.cycle2, du2_DUD)
1258 
1259 #if defined(PANEL68)
1260 // Control points
1261 # define CPT(R,C) cpu.cpt[R][C]=1
1262 # define CPTUR(C) cpu.cpt[cpt5L][C]=1
1263 #else
1264 # define CPT(R,C)
1265 # define CPTUR(C)
1266 #endif /* if defined(PANEL68) */
1267 
1268 
1269 
1270 
1271 
1272 
1273 
1274 
1275 
1276 
1277 
1278 
1279 
1280 
1281 
1282 
1283 
1284 
1285 
1286 
1287 
1288 
1289 
1290 
1291 
1292 
1293 
1294 
1295 
1296 
1297 
1298 
1299 
1300 
1301 
1302 
1303 
1304 
1305 
1306 
1307 
1308 
1309 
1310 
1311 
1312 
1313 
1314 
1315 
1316 
1317 
1318 
1319 
1320 
1321 
1322 
1323 
1324 
1325 
1326 
1327 
1328 
1329 
1330 
1331 
1332 
1333 
1334 
1335 
1336 
1337 
1338 
1339 
1340 
1341 
1342 
1343 
1344 
1345 
1346 
1347 
1348 
1349 
1350 
1351 
1352 
1353 
1354 
1355 
1356 
1357 
1358 
1359 typedef struct du_unit_data_t
1360   {
1361     // Word 0
1362 
1363                       //  0- 8  9   Zeros
1364     word1 Z;          //     9  1   Z       All bit-string instruction results
1365                       //                      are zero
1366     word1 NOP;        //    10  1   0       Negative overpunch found in 6-4
1367                       //                      expanded move
1368     word24 CHTALLY;   // 12-35 24   CHTALLY The number of characters examined
1369                       //                      by the scm, scmr, scd,
1370                       //                      scdr, tct, or tctr instructions
1371                       //                      (up to the interrupt or match)
1372 
1373     // Word 1
1374 
1375                       //  0-35 26   Zeros
1376 
1377     // Word 2
1378 
1379     // word24 D1_PTR; //  0-23 24   D1 PTR  Address of the last double-word
1380                       //                      accessed by operand descriptor 1;
1381                       //                      bits 17-23 (bit-address) valid
1382                       //                      only for initial access
1383                       //    24  1   Zero
1384     // word2 TA1;     // 25-26  2   TA1     Alphanumeric type of operand
1385                       //                      descriptor 1
1386                       // 27-29  3   Zeroes
1387                       //    30  1   I       Decimal unit interrupted flag; a
1388                       //                      copy of the mid-instruction
1389                       //                      interrupt fault indicator
1390     // word1 F1;      //    31  1   F1      First time; data in operand
1391                       //                      descriptor 1 is valid
1392     // word1 A1;      //    32  1   A1      Operand descriptor 1 is active
1393                       // 33-35  3   Zeroes
1394 
1395     // Word 3
1396 
1397     word10 LEVEL1;    //  0- 9 10   LEVEL 1 Difference in the count of
1398                       //                      characters loaded into the and
1399                       //                      processor characters not acted
1400                       //                      upon
1401     // word24 D1_RES; // 12-35 24   D1 RES  Count of characters remaining in
1402                       //                      operand descriptor 1
1403 
1404     // Word 4
1405 
1406     // word24 D2_PTR; //  0-23 24   D2 PTR  Address of the last double-word
1407                       //                      accessed by operand descriptor 2;
1408                       //                      bits 17-23 (bit-address) valid
1409                       //                      only for initial access
1410                       //    24  1   Zero
1411     // word2 TA2;     // 25-26  2   TA2     Alphanumeric type of operand
1412                       //                      descriptor 2
1413                       // 27-29  3   Zeroes
1414     word1 R;          //    30  1   R       Last cycle performed must be
1415                       //                    repeated
1416     // word1 F2;      //    31  1   F2      First time; data in operand
1417                       //                      descriptor 2 is valid
1418     // word1 A2;      //    32  1   A2      Operand descriptor 2 is active
1419                       // 33-35  3   Zeroes
1420 
1421     // Word 5
1422 
1423     word10 LEVEL2;    //  0- 9 10   LEVEL 2 Same as LEVEL 1, but used mainly
1424                       //                      for OP 2 information
1425     // word24 D2_RES; // 12-35 24   D2 RES  Count of characters remaining in
1426                       //                      operand descriptor 2
1427 
1428     // Word 6
1429 
1430     // word24 D3_PTR; //  0-23 24   D3 PTR  Address of the last double-word
1431                       //                      accessed by operand descriptor 3;
1432                       //                      bits 17-23 (bit-address) valid
1433                       //                      only for initial access
1434                       //    24  1   Zero
1435     // word2 TA3;     // 25-26  2   TA3     Alphanumeric type of operand
1436                       //                      descriptor 3
1437                       // 27-29  3   Zeroes
1438                       //    30  1   R       Last cycle performed must be
1439                       //                      repeated
1440                       //                    [XXX: what is the difference between
1441                       //                      this and word4.R]
1442     // word1 F3;      //    31  1   F3      First time; data in operand
1443                       //                      descriptor 3 is valid
1444     // word1 A3;      //    32  1   A3      Operand descriptor 3 is active
1445     word3 JMP;        // 33-35  3   JMP     Descriptor count; number of words
1446                       //                      to skip to find the next
1447                       //                      instruction following this
1448                       //                      multiword instruction
1449 
1450     // Word 7
1451 
1452                       //  0-12 12   Zeroes
1453     // word24 D3_RES; // 12-35 24   D3 RES  Count of characters remaining in
1454                       //                      operand descriptor 3
1455 
1456     // Fields from above reorganized for generality
1457     word2 TAk [3];
1458 
1459 // D_PTR is a word24 divided into a 18 bit address, and a 6-bit bitno/char
1460 // field
1461 
1462     word18 Dk_PTR_W [3];
1463 #define D1_PTR_W Dk_PTR_W [0]
1464 #define D2_PTR_W Dk_PTR_W [1]
1465 #define D3_PTR_W Dk_PTR_W [2]
1466 
1467     word6 Dk_PTR_B [3];
1468 #define D1_PTR_B Dk_PTR_B [0]
1469 #define D2_PTR_B Dk_PTR_B [1]
1470 #define D3_PTR_B Dk_PTR_B [2]
1471 
1472     word24 Dk_RES [3];
1473 #define D_RES Dk_RES
1474 #define D1_RES Dk_RES [0]
1475 #define D2_RES Dk_RES [1]
1476 #define D3_RES Dk_RES [2]
1477 
1478     word1 Fk [3];
1479 //#define F Fk
1480 #define F1 Fk [0]
1481 #define F2 Fk [0]
1482 #define F3 Fk [0]
1483 
1484     word1 Ak [3];
1485 
1486     // Working storage for EIS instruction processing.
1487 
1488     // These values must be restored on instruction restart
1489     word7 MF [3]; // Modifier fields for each instruction.
1490 
1491     // Image of LPL/SPL for ISOLTS compliance
1492     word36 image [8];
1493 
1494 #if defined(PANEL68)
1495     word37 cycle1;
1496     word37 cycle2;
1497     word1 POL; // Prepare operand length
1498     word1 POP; // Prepare operand pointer
1499 #endif /* if defined(PANEL68) */
1500   } du_unit_data_t;
1501 
1502 #if defined(PANEL68)
1503 // prepare_state bits
1504 enum
1505   {
1506     ps_PIA = 0200,
1507     ps_POA = 0100,
1508     ps_RIW = 0040,
1509     ps_SIW = 0020,
1510     ps_POT = 0010,
1511     ps_PON = 0004,
1512     ps_RAW = 0002,
1513     ps_SAW = 0001
1514   };
1515 #endif /* if defined(PANEL68) */
1516 
1517 // History registers
1518 
1519 // CU History register flag2 field bit
1520 
1521 enum
1522   {
1523     CUH_XINT = 0100,
1524     CUH_IFT  =  040,
1525     CUH_CRD  =  020,
1526     CUH_MRD  =  010,
1527     CUH_MSTO =   04,
1528     CUH_PIB  =   02
1529 };
1530 
1531 #define N_DPS8M_WAM_ENTRIES 64
1532 #define N_DPS8M_WAM_MASK   077
1533 #define N_L68_WAM_ENTRIES   16
1534 #define N_L68_WAM_MASK     017
1535 #define N_NAX_WAM_ENTRIES   64
1536 #define N_MODEL_WAM_ENTRIES (cpu.tweaks.l68_mode ? N_L68_WAM_ENTRIES : N_DPS8M_WAM_ENTRIES)
1537 
1538 #include "ucache.h"
1539 
1540 typedef struct coreLockState_s {
1541     uint64_t lockCnt;
1542     uint64_t lockImmediate;
1543     uint64_t lockWait;
1544     uint64_t lockWaitMax;
1545 #if !defined(SCHED_NEVER_YIELD)
1546     uint64_t lockYield;
1547 #endif /* if !defined(SCHED_NEVER_YIELD) */
1548     word24 locked_addr;
1549 } coreLockState_t;
1550 
1551 typedef struct cpu_state_s
1552   {
1553 
1554 #if defined(THREADZ) || defined(LOCKLESS)
1555     // Set when sim_instr starts fetching and executing; used to improve
1556     // thread creation lag time issues.
1557     volAtomic bool executing;
1558     volAtomic bool forceRestart;
1559     // CPU is running Multics: it has been booted or added, and not deleted,
1560     //  and not an ISOLTS test cpu.
1561     // ISOLTS test CPUs can be master, but never slave.
1562     volAtomic bool inMultics;
1563     bool syncClockModeMaster; // It set, this CPU is the master
1564     volAtomic long int workAllocation; // If in sync clock mode, this is
1565                                            // the amount of work we have
1566                                            // been allocated
1567     // How many cycles has the master held the clock
1568     int masterCycleCnt;
1569     //volatile atomic_bool rcfDelete;  // Set if the CPU was halted by a RCF DELETE
1570     bool syncClockModeCache; // Thread copy of syncClockMode
1571     int syncClockModePoll; // Poll syncClockMode
1572     volAtomic atomic_bool isSlave;
1573     bool becomeSlave;
1574 #endif
1575 
1576     EISstruct currentEISinstruction;
1577 
1578     uCache_t uCache;
1579 
1580     unsigned long long cycleCnt;
1581     unsigned long long instrCnt;
1582     unsigned long long instrCntT0;
1583     unsigned long long instrCntT1;
1584 
1585     coreLockState_t coreLockState;
1586 
1587     // From the control unit history register:
1588     _fault_subtype subFault; // saved by doFault
1589 
1590     word36   rA;     // accumulator
1591     word36   rQ;     // quotient
1592 
1593     fault_acv_subtype_  acvFaults;   // pending ACV faults
1594 
1595     sdw_s * SDW; // working SDW
1596 
1597     // Zone mask
1598     word36 zone;
1599 
1600     ptw_s * PTW;
1601 
1602     word36 CY;              // C(Y) operand data from memory
1603 
1604     uint64 lufCounter;
1605     // T&D mode: lockup time counted in TR decrements (2 ms = 1024), the
1606     // TR decrements so far (T&D calendar clock base), and the transfer
1607     // a lockup is taken on (PM776 08I).
1608     uint64 lufTicks;
1609     uint64 tanddTRTicks;
1610     word18 lufExecIC;   // IC of the instruction being executed
1611     word18 lufXferIC;   // IC of the last transfer (CONT_TRA)
1612     bool lufAfterXfer;  // the PSEUDO_FETCH follows that transfer
1613     bool lufRFI;        // T&D: doFault sets RFI in the SCU data
1614     bool tanddFetchFault; // T&D: g7 fault at a fetch; keep the fetch's APU status
1615     word24 l68PairAddr;   // L68: absolute address of the last instruction pair fetched
1616     bool l68PairValid;
1617     bool l68OddFault;     // L68: fault in an odd instruction; SCU word 7 = next pair's odd word
1618     volatile bool execSwitchesReq; // EXECUTE DATA SWITCHES pressed
1619     bool execSwitches;    // the fault cycle executes the data switches
1620     bool g7FetchFault;    // g7 fault taken between instructions: a non-transferring
1621                           // fault pair resumes at the IC
1622     bool tanddFetchIntr;  // T&D: interrupt at a fetch; patch the SCU data
1623     word36 tanddIRODD;    // T&D: IRODD before that fetch
1624     word6 lastTag;        // tag of the last instruction completed
1625     bool rptXnSaved;      // first repetition changed Xn; restore it on a fault
1626     uint rptXn;
1627     word18 rptXnOld;
1628     uint rptUndo[2];      // 1+Xn advanced for the next even/odd repeated instruction
1629     bool xsfScu;          // XSF for the SCU data: TSR loaded by this instruction's
1630                           //  address preparation (not cu.XSF, "went appending")
1631     bool scuRFI;          // doFault: RFI in the safe-stored SCU data only (not cu.rfi,
1632                           //  which would make the fault pair a restart)
1633     bool tanddFetched;  // T&D: FETCH_cycle fetched before sampling
1634     word3 neaPort;      // T&D: CPU port of the last NEA/parity illegal action (IACHN)
1635     bool neaNoPort;     // T&D: no enabled CPU port holds that address
1636     bool scLockedOut;   // T&D: a locked read hit bad parity; next access waits
1637     uint tanddEISstart; // T&D: CHTALLY when this execution of an interruptible EIS began
1638 
1639     _fault_subtype dlySubFltNum;
1640 
1641     const char * dlyCtx;
1642 
1643     word36 faultRegister [2];
1644 
1645     word36 itxPair [2];
1646 
1647 //#if defined(THREADZ) || defined(LOCKLESS)
1648 //    struct timespec rTRTime; // time when rTR was set
1649 //#endif
1650 
1651     mode_register_s MR;
1652     // Changes to the mode register history bits do not take affect until
1653     // the next instruction (ISOLTS 700 2a). Cache the values here so
1654     // that post register updates can see the old values.
1655     mode_register_s MR_cache;
1656 
1657     DCDstruct currentInstruction;
1658 
1659     ou_unit_data_t ou;
1660 
1661     word36 Ypair[2];        //  2-words
1662     word36 Yblock8[8];      //  8-words
1663     word36 Yblock16[16];    // 16-words
1664     word36 Yblock32[32];    // 32-words
1665 
1666     word36 scu_data[8];     // For SCU instruction
1667 
1668     ctl_unit_data_t cu;
1669     du_unit_data_t du;
1670 
1671     switches_t switches;
1672     optionsType options;
1673     tweaksType tweaks;
1674     switches_t isolts_switches_save;
1675 
1676     jmp_buf jmpMain; // This is the entry to the CPU state machine
1677 
1678     unsigned long      faultCnt [N_FAULTS];
1679 
1680     word36 history [N_HIST_SETS] [N_MAX_HIST_SIZE] [2];
1681 
1682     cycles_e cycle;
1683 
1684     _fault faultNumber;      // fault number saved by doFault
1685 
1686     apu_unit_data_t apu;
1687 
1688     word27   rTR;    // timer [map: TR, 9 0's]
1689 #if defined(THREADZ) || defined(LOCKLESS)
1690     uint     rTRsample;
1691 #endif
1692     word24   rY;     // address operand
1693 
1694     word18  lnk;     // rpl link value
1695 
1696     volAtomic uint g7FaultsPreset;
1697     uint g7Faults;
1698 
1699     word24 iefpFinalAddress;
1700 
1701     // ISOLTS fine grain TR estimation
1702     uint rTRlsb;
1703     uint shadowTR;
1704     uint TR0; // The value that the TR was set to.
1705 
1706     // Arguments for delayed overflow fault
1707     _fault dlyFltNum;
1708 
1709     word18 last_write;
1710 
1711 #if defined(LOCKLESS)
1712     word24 char_word_address;
1713 #endif /* if defined(LOCKLESS) */
1714 
1715     word24 rmw_address;
1716 
1717     uint restart_address;
1718 
1719     struct
1720       {
1721         word15 PSR;
1722         word3  PRR;
1723         word18 IC;
1724       } cu_data;            // For STCD instruction
1725     uint rTRticks;
1726 
1727     struct tpr_s TPR;     // Temporary Pointer Register
1728     struct ppr_s PPR;     // Procedure Pointer Register
1729     struct dsbr_s DSBR;   // Descriptor Segment Base Register
1730     ptw0_s PTW0; // a PTW not in PTWAM (PTWx1)
1731 
1732     uint history_cyclic [N_HIST_SETS]; // 0..63
1733 
1734     sdw_s SDW0;  // a SDW not in SDWAM
1735     sdw_s _s;
1736 
1737     word18   rX [8]; // index
1738 
1739     // Number of banks in each SCU
1740     uint sc_num_banks [N_SCU_UNITS_MAX];
1741 
1742     // Caching some cabling data for interrupt handling.
1743     // When a CPU calls get_highest_intr(), it needs to know
1744     // what port on the SCU it is attached to. Because of port
1745     // expanders several CPUs can be attached to an SCU port,
1746     // mapping from the CPU to the SCU is easier to query
1747     uint scu_port[N_SCU_UNITS_MAX];
1748 
1749     // L68 FFV faults
1750 
1751      uint FFV_faults_preset;
1752      uint FFV_faults;
1753      uint FFV_fault_number;
1754 
1755 #if defined(AFFINITY)
1756     uint affinity;
1757 #endif /* if defined(AFFINITY) */
1758 
1759     events_t events;
1760 
1761     word24 pad[16];
1762 
1763     struct par_s PAR [8]; // pointer/address registers
1764 
1765     ptw_s PTWAM [N_NAX_WAM_ENTRIES];
1766 
1767     // Map memory address through memory configuration switches
1768     // Minimum allocation chunk is 64K (SCBANK_SZ)
1769     // addr / SCBANK_SZ => bank_number
1770     // scbank_map[bank_number] is address of the bank in M. -1 is unmapped.
1771     int sc_addr_map [N_SCBANKS];
1772     // T&D: SCU internal interlace (config register INT): lower store size
1773     // in words for each CPU port whose SCU interlaces stores A and B,
1774     // else 0; and its port window base.
1775     uint sc_ilv_lower_wds [N_SCU_PORTS];
1776     uint sc_ilv_base [N_SCU_PORTS];
1777     bool sc_interlace;
1778     bool sc_ilv_single [N_SCU_PORTS]; // interlaced with only one store present
1779     // The SCU number holding each bank
1780     int sc_scu_map [N_SCBANKS];
1781 
1782     sdw_s SDWAM [N_NAX_WAM_ENTRIES]; // Segment Descriptor Word Associative Memory
1783 
1784     // Address Modification tally
1785     word12 AM_tally;
1786 
1787     struct bar_s BAR;     // Base Address Register
1788 
1789     cache_mode_register_s CMR;
1790 
1791     // The following are all from the control unit history register:
1792 
1793     bool interrupt_flag;     // an interrupt is pending in this cycle
1794     bool g7_flag;            // a g7 fault is pending in this cycle;
1795 
1796     bool wasXfer;      // The previous instruction was a transfer
1797 
1798     bool wasInhibited; // One or both of the previous instruction
1799                        // pair was interrupt inhibited.
1800 
1801     bool isExec;  // The instruction being executed is the target of
1802                   // an XEC or XED instruction
1803     bool isXED;   // The instruction being executed is the target of an
1804                   // XEC instruction
1805 
1806     word8    rE;       // exponent [map: rE, 28 0's]
1807 
1808     word6    rTAG;     // instruction tag
1809     word3    rRALR;    // ring alarm [3b] [map: 33 0's, RALR]
1810     word3    RSDWH_R1; // Track the ring number of the last SDW
1811 
1812     // L68: word4
1813     // DPS8M: word6
1814     word6 SDWAMR;
1815 
1816     // Zone mask
1817     bool useZone;
1818 
1819     // L68: word4
1820     // DPS8M: word6
1821     word6 PTWAMR;
1822 
1823     // G7 faults
1824     bool bTroubleFaultCycle;
1825 
1826     bool lufOccurred;
1827     bool secret_addressing_mode;
1828     // Used by LCPR to prevent the LCPR instruction from being recorded
1829     // in the CU.
1830     bool skip_cu_hist;
1831     bool adr_trap_lock;  // L68 ADR TRAP matched: lock the HR after this instruction
1832 
1833     // If the instruction wants overflow thrown after operand write
1834     bool dlyFlt;
1835 
1836     bool restart;
1837 
1838     // L68 FFV faults
1839     bool is_FFV;
1840 
1841 #if defined(AFFINITY)
1842     bool set_affinity;
1843 #endif /* if defined(AFFINITY) */
1844 
1845 #if defined(SPEED)
1846 # define SC_MAP_ADDR(addr,real_addr)                           \
1847    if (cpu.tweaks.useMap)                                      \
1848       {                                                        \
1849         word24 maddr = cpu.sc_interlace ?                      \
1850                          sc_interlace_addr (cpup, addr) : addr;\
1851         uint pgnum = maddr / SCBANK_SZ;                        \
1852         uint os = maddr % SCBANK_SZ;                           \
1853         int base = cpu.sc_addr_map[pgnum];                     \
1854         if (base < 0)                                          \
1855           {                                                    \
1856             if (cpu.tweaks.tandd_mode)                         \
1857               tandd_set_nea_port (cpup, addr);                 \
1858             doFault (FAULT_STR, fst_str_nea,  __func__);       \
1859           }                                                    \
1860         real_addr = (uint) base + os;                          \
1861       }                                                        \
1862     else                                                       \
1863       real_addr = addr;
1864 #else
1865 # define SC_MAP_ADDR(addr,real_addr)                           \
1866    if (cpu.tweaks.useMap)                                      \
1867       {                                                        \
1868         word24 maddr = cpu.sc_interlace ?                      \
1869                          sc_interlace_addr (cpup, addr) : addr;\
1870         uint pgnum = maddr / SCBANK_SZ;                        \
1871         uint os = maddr % SCBANK_SZ;                           \
1872         int base = cpu.sc_addr_map[pgnum];                     \
1873         if (base < 0)                                          \
1874           {                                                    \
1875             if (cpu.tweaks.tandd_mode)                         \
1876               tandd_set_nea_port (cpup, addr);                 \
1877             doFault (FAULT_STR, fst_str_nea,  __func__);       \
1878           }                                                    \
1879         real_addr = (uint) base + os;                          \
1880       }                                                        \
1881     else                                                       \
1882       {                                                        \
1883         nem_check (addr, __func__);                            \
1884         real_addr = addr;                                      \
1885       }
1886 #endif /* if defined(SPEED) */
1887 
1888 #if defined(PANEL68)
1889     // Intermediate data collection for APU SCROLL
1890     word18 lastPTWOffset;
1891 // The L68 APU SCROLL 4U has an entry "ACSD"; I am interpreting it as
1892 //   on: lastPTRAddr was a DSPTW
1893 //  off: lastPTRAddr was a PTW
1894     bool lastPTWIsDS;
1895     word18 APUDataBusOffset;
1896     word24 APUDataBusAddr;
1897     word24 APUMemAddr;
1898     word1 panel4_red_ready_light_state;
1899     word1 panel7_enabled_light_state;
1900 // The state of the panel switches
1901     volAtomic word15 APU_panel_segno_sw;
1902     volAtomic word1  APU_panel_enable_match_ptw_sw;  // lock
1903     volAtomic word1  APU_panel_enable_match_sdw_sw;  // lock
1904     volAtomic word1  APU_panel_scroll_select_ul_sw;
1905     volAtomic word4  APU_panel_scroll_select_n_sw;
1906     volAtomic word4  APU_panel_scroll_wheel_sw;
1907     //volAtomic word18 APU_panel_addr_sw;
1908     volAtomic word18 APU_panel_enter_sw;
1909     volAtomic word18 APU_panel_display_sw;
1910     volAtomic word4  CP_panel_wheel_sw;
1911     volAtomic word4  DATA_panel_ds_sw;
1912     volAtomic word4  DATA_panel_d1_sw;
1913     volAtomic word4  DATA_panel_d2_sw;
1914     volAtomic word4  DATA_panel_d3_sw;
1915     volAtomic word4  DATA_panel_d4_sw;
1916     volAtomic word4  DATA_panel_d5_sw;
1917     volAtomic word4  DATA_panel_d6_sw;
1918     volAtomic word4  DATA_panel_d7_sw;
1919     volAtomic word4  DATA_panel_wheel_sw;
1920     volAtomic word4  DATA_panel_addr_stop_sw;
1921     volAtomic word1  DATA_panel_enable_sw;
1922     volAtomic word1  DATA_panel_validate_sw;
1923     volAtomic word1  DATA_panel_auto_fast_sw;  // lock
1924     volAtomic word1  DATA_panel_auto_slow_sw;  // lock
1925     volAtomic word4  DATA_panel_cycle_sw;      // lock
1926     volAtomic word1  DATA_panel_step_sw;       // lock
1927     volAtomic word1  DATA_panel_s_trig_sw;
1928     volAtomic word1  DATA_panel_execute_sw;    // lock
1929     volAtomic word1  DATA_panel_scope_sw;
1930     volAtomic word1  DATA_panel_init_sw;       // lock
1931     volAtomic word1  DATA_panel_exec_sw;       // lock
1932     volAtomic word4  DATA_panel_hr_sel_sw;
1933     volAtomic word4  DATA_panel_trackers_sw;
1934     volAtomic bool panelInitialize;
1935 
1936     // Intermediate data collection for DATA SCROLL
1937     bool portBusy;
1938     word2 portSelect;
1939     word36 portAddr [N_CPU_PORTS];
1940     word36 portData [N_CPU_PORTS];
1941     // Intermediate data collection for CU
1942     word36 IWRAddr;
1943     word7 dataMode; // 0100  9 bit
1944                     // 0040  6 bit
1945                     // 0020  4 bit
1946                     // 0010  1 bit
1947                     // 0004  36 bit
1948                     // 0002  alphanumeric
1949                     // 0001  numeric
1950     word8 prepare_state;
1951     bool DACVpDF;
1952     bool AR_F_E;
1953     bool INS_FETCH;
1954     // Control Points data acquisition
1955     word1 cpt [28] [36];
1956 #endif /* if defined(PANEL68) */
1957 #if defined(THREADZ) || defined(LOCKLESS)
1958     pthread_t thread_id;
1959 #endif
1960 #define cpt1U   0  // Instruction processing tracking
1961 #define cpt1L   1  // Instruction processing tracking
1962 #define cpt2U   2  // Instruction execution tracking
1963 #define cpt2L   3  // Instruction execution tracking
1964 #define cpt3U   4  // Register usage
1965 #define cpt3L   5  // Register usage
1966 #define cpt4U   6
1967 #define cpt4L   7
1968 #define cpt5U   8
1969 #define cpt5L   9
1970 #define cpt6U  10
1971 #define cpt6L  11
1972 #define cpt7U  12
1973 #define cpt7L  13
1974 #define cpt8U  14
1975 #define cpt8L  15
1976 #define cpt9U  16
1977 #define cpt9L  17
1978 #define cpt10U 18
1979 #define cpt10L 19
1980 #define cpt11U 20
1981 #define cpt11L 21
1982 #define cpt12U 22
1983 #define cpt12L 23
1984 #define cpt13U 24
1985 #define cpt13L 25
1986 #define cpt14U 26
1987 #define cpt14L 27
1988 
1989 #define cptUseE     0
1990 #define cptUseBAR   1
1991 #define cptUseTR    2
1992 #define cptUseRALR  3
1993 #define cptUsePRn   4  // 4 - 11
1994 #define cptUseDSBR 12
1995 #define cptUseFR   13
1996 #define cptUseMR   14
1997 #define cptUseCMR  15
1998 #define cptUseIR   16
1999   } cpu_state_t;
2000 
2001 typedef struct MOP_struct_s
2002   {
2003     char * mopName;     // name of microoperation
2004     int (* f) (cpu_state_t *);   // pointer to mop() [returns character to be stored]
2005   } MOP_struct;
2006 
2007 #if defined(M_SHARED)
2008 extern cpu_state_t * cpus;
2009 #else
2010 extern cpu_state_t cpus [N_CPU_UNITS_MAX];
2011 #endif /* if defined(M_SHARED) */
2012 
2013 #if defined(THREADZ) || defined(LOCKLESS)
2014 extern __thread cpu_state_t * restrict _cpup;
2015 #else
2016 extern cpu_state_t * restrict _cpup;
2017 #endif /* if defined(THREADZ) || defined(LOCKLESS) */
2018 
2019 #define cpu (* cpup)
2020 
2021 #define N_STALL_POINTS 16
2022 struct stall_point_s
2023   {
2024     word15 segno;
2025     word18 offset;
2026     useconds_t time;
2027   };
2028 extern struct stall_point_s stall_points [N_STALL_POINTS];
2029 extern bool stall_point_active;
2030 
2031 uint set_cpu_idx (uint cpuNum);
2032 #if defined(THREADZ) || defined(LOCKLESS)
2033 extern __thread uint current_running_cpu_idx;
2034 extern bool bce_dis_called;
2035 #else
2036 # define current_running_cpu_idx 0
2037 #endif /* if defined(THREADZ) || defined(LOCKLESS) */
2038 
2039 // Support code to access ARn.BITNO, ARn.CHAR, PRn.BITNO
2040 
2041 #define GET_PR_BITNO(n) (cpu.PAR[n].PR_BITNO)
2042 #define GET_AR_BITNO(n) (cpu.PAR[n].AR_BITNO)
2043 #define GET_AR_CHAR(n)  (cpu.PAR[n].AR_CHAR)
2044 static inline void SET_PR_BITNO (cpu_state_t * restrict cpup, uint n, word6 b)
     /* [previous][next][first][last][top][bottom][index][help] */
2045   {
2046      // Keep PR_BITNO = 9 * AR_CHAR + AR_BITNO, as LAREG/LARn set it, for
2047      // bit offsets past 35 too (LAREG with CHAR 3, BITNO 9-15 gives 36-42),
2048      // so that saving and restoring the registers (SPRI/SAREG, LPRI/LAREG)
2049      // gives back the same state. PS955 checks this: EAWP2 with PR7 from
2050      // LAREG (36), LPRPn with C(Y)0,5 = 43-47 (BITNO wraps in 4 bits).
2051      if (b < 36) {
2052        cpu.PAR[n].PR_BITNO = b;
2053        cpu.PAR[n].AR_BITNO = (b % 9) & MASK4;
2054        cpu.PAR[n].AR_CHAR = (b / 9) & MASK2;
2055      } else {
2056        cpu.PAR[n].AR_BITNO = (b - 27) & MASK4;
2057        cpu.PAR[n].AR_CHAR = 3;
2058        cpu.PAR[n].PR_BITNO = 27 + cpu.PAR[n].AR_BITNO;
2059      }
2060   }
2061 #define SET_PR_BITNO(n, b) SET_PR_BITNO(cpup, n, b)
2062 static inline void SET_AR_CHAR_BITNO (cpu_state_t * restrict cpup, uint n, word2 c, word4 b)
     /* [previous][next][first][last][top][bottom][index][help] */
2063   {
2064      cpu.PAR[n].PR_BITNO = c * 9 + b;
2065      cpu.PAR[n].AR_BITNO = b & MASK4;
2066      cpu.PAR[n].AR_CHAR = c & MASK2;
2067   }
2068 #define SET_AR_CHAR_BITNO(n, c, b) SET_AR_CHAR_BITNO(cpup, n, c, b)
2069 
2070 bool sample_interrupts (cpu_state_t * cpup);
2071 t_stat simh_hooks (cpu_state_t * cpup);
2072 int operand_size (cpu_state_t * cpup);
2073 //void read_operand (word18 addr, processor_cycle_type cyctyp);
2074 void readOperandRead (cpu_state_t * cpup, word18 addr);
2075 void readOperandRMW (cpu_state_t * cpup, word18 addr);
2076 t_stat write_operand (cpu_state_t * cpup, word18 addr, processor_cycle_type acctyp);
2077 
2078 #if defined(PANEL68)
2079 static inline void trackport (word24 a, word36 d)
     /* [previous][next][first][last][top][bottom][index][help] */
2080   {
2081     cpu_state_t * cpup = _cpup;
2082     // Simplifying assumption: 4 * 4MW SCUs
2083     word2 port = (a >> 22) & MASK2;
2084     cpu.portSelect = port;
2085     cpu.portAddr [port] = a;
2086     cpu.portData [port] = d;
2087     cpu.portBusy = false;
2088   }
2089 #endif /* if defined(PANEL68) */
2090 
2091 #if defined(SPEED) && defined(INLINE_CORE)
2092 # error INLINE_CORE has known issues.
2093 // Ugh. Circular dependencies XXX
2094 NO_RETURN void doFault (_fault faultNumber, _fault_subtype faultSubtype,
2095               const char * faultMsg);
2096 extern const _fault_subtype fst_str_nea;
2097 
2098 static inline int core_read (word24 addr, word36 *data, \
     /* [previous][next][first][last][top][bottom][index][help] */
2099   UNUSED const char * ctx)
2100   {
2101     PNL (cpu.portBusy = true;)
2102     SC_MAP_ADDR (addr, addr);
2103     * data = M[addr] & DMASK;
2104     DO_WORK_MEM;
2105     PNL (trackport (addr, * data);)
2106     return 0;
2107   }
2108 
2109 static inline int core_write (word24 addr, word36 data, \
     /* [previous][next][first][last][top][bottom][index][help] */
2110   UNUSED const char * ctx)
2111   {
2112     PNL (cpu.portBusy = true;)
2113     SC_MAP_ADDR (addr, addr);
2114     if (cpu.tweaks.isolts_mode)
2115       {
2116         if (cpu.MR.sdpap)
2117           {
2118             sim_warn ("failing to implement sdpap\r\n");
2119             cpu.MR.sdpap = 0;
2120           }
2121         if (cpu.MR.separ)
2122           {
2123             sim_warn ("failing to implement separ\r\n");
2124             cpu.MR.separ = 0;
2125           }
2126      }
2127     M[addr] = data & DMASK;
2128     DO_WORK_MEM;
2129     PNL (trackport (addr, data);)
2130     return 0;
2131   }
2132 
2133 static inline int core_write_zone (word24 addr, word36 data, \
     /* [previous][next][first][last][top][bottom][index][help] */
2134   UNUSED const char * ctx)
2135   {
2136     PNL (cpu.portBusy = true;)
2137     SC_MAP_ADDR (addr, addr);
2138     if (cpu.tweaks.isolts_mode)
2139       {
2140         if (cpu.MR.sdpap)
2141           {
2142             sim_warn ("failing to implement sdpap\r\n");
2143             cpu.MR.sdpap = 0;
2144           }
2145         if (cpu.MR.separ)
2146           {
2147             sim_warn ("failing to implement separ\r\n");
2148             cpu.MR.separ = 0;
2149           }
2150       }
2151     M[addr] = (M[addr] & ~cpu.zone) | (data & cpu.zone);
2152     cpu.useZone = false; // Safety
2153     DO_WORK_MEM;
2154     PNL (trackport (addr, data);)
2155     return 0;
2156   }
2157 
2158 static inline int core_read2 (word24 addr, word36 *even, word36 *odd,
     /* [previous][next][first][last][top][bottom][index][help] */
2159                               UNUSED const char * ctx)
2160   {
2161     PNL (cpu.portBusy = true;)
2162     SC_MAP_ADDR (addr, addr);
2163     *even = M[addr++] & DMASK;
2164     *odd = M[addr] & DMASK;
2165     DO_WORK_MEM;
2166     PNL (trackport (addr - 1, * even);)
2167     return 0;
2168   }
2169 
2170 static inline int core_write2 (word24 addr, word36 even, word36 odd,
     /* [previous][next][first][last][top][bottom][index][help] */
2171                                UNUSED const char * ctx)
2172   {
2173     PNL (cpu.portBusy = true;)
2174     SC_MAP_ADDR (addr, addr);
2175     if (cpu.tweaks.isolts_mode)
2176       {
2177         if (cpu.MR.sdpap)
2178           {
2179             sim_warn ("failing to implement sdpap\r\n");
2180             cpu.MR.sdpap = 0;
2181           }
2182         if (cpu.MR.separ)
2183           {
2184             sim_warn ("failing to implement separ\r\n");
2185             cpu.MR.separ = 0;
2186           }
2187       }
2188     M[addr++] = even;
2189     M[addr] = odd;
2190     PNL (trackport (addr - 1, even);)
2191     DO_WORK_MEM;
2192     return 0;
2193   }
2194 #else
2195 int core_read (cpu_state_t * cpup, word24 addr, word36 *data, const char * ctx);
2196 int core_write (cpu_state_t * cpup, word24 addr, word36 data, const char * ctx);
2197 int core_write_zone (cpu_state_t * cpup, word24 addr, word36 data, const char * ctx);
2198 int core_read2 (cpu_state_t * cpup, word24 addr, word36 *even, word36 *odd, const char * ctx);
2199 int core_write2 (cpu_state_t * cpup, word24 addr, word36 even, word36 odd, const char * ctx);
2200 #endif /* if defined(SPEED) && defined(INLINE_CORE) */
2201 
2202 #if defined(LOCKLESS)
2203 
2204 /*
2205  * Atomic operations to use defined as follows:
2206  *
2207  *  AIX_ATOMICS  -  IBM AIX atomics
2208  *  BSD_ATOMICS  -  FreeBSD atomics
2209  *  GNU_ATOMICS  -  GNU atomics
2210  * SYNC_ATOMICS  -  GNU sync-style atomics
2211  *
2212  * The following are reserved and not yet implemented:
2213  *
2214  *  ISO_ATOMICS  -  ISO/IEC 9899:2011 (C11) atomics
2215  *   NT_ATOMICS  -  Microsoft Windows NT atomics
2216  *
2217  * For further details, see:
2218  *
2219  * AIX_ATOMICS:
2220  *  https://www.ibm.com/docs/en/aix/7.3?topic=services-atomic-operations
2221  *
2222  * BSD_ATOMICS:
2223  *  https://www.freebsd.org/cgi/man.cgi?query=atomic&sektion=9&format=html
2224  *  https://man.dragonflybsd.org/?command=atomic&section=9
2225  *
2226  * GNU_ATOMICS:
2227  *  https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
2228  *
2229  * SYNC_ATOMICS:
2230  *  https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
2231  *
2232  * ISO_ATOMICS:
2233  *  https://en.cppreference.com/w/c/atomic
2234  *
2235  * NT_ATOMICS:
2236  *  https://docs.microsoft.com/en-us/windows/win32/sync/synchronization-functions
2237  *  https://docs.microsoft.com/en-us/windows/win32/sync/interlocked-variable-access
2238  */
2239 
2240 // AIX_ATOMICS are SYNC_ATOMICS (for now)
2241 # if ( defined (AIX_ATOMICS) && \
2242    (! (defined (SYNC_ATOMICS))))
2243 #  define SYNC_ATOMICS 1
2244 # endif
2245 
2246 // FreeBSD atomics (default on for FreeBSD)
2247 # if (! defined (GNU_ATOMICS)) && (! defined (SYNC_ATOMICS)) && \
2248      (! defined (BSD_ATOMICS)) && (! defined (AIX_ATOMICS))
2249 #  if defined(__FreeBSD__) \
2250    || defined(__DragonFly__)
2251 #   undef BSD_ATOMICS
2252 #   define BSD_ATOMICS 1
2253 #  endif
2254 # endif
2255 
2256 // Otherwise, default to GNU_ATOMICS
2257 # if (! defined (GNU_ATOMICS)) && (! defined (BSD_ATOMICS)) && \
2258      (! defined (SYNC_ATOMICS)) && (! defined (AIX_ATOMICS))
2259 #  undef GNU_ATOMICS
2260 #  define GNU_ATOMICS 1
2261 # endif
2262 
2263 int core_read_lock (cpu_state_t * cpup, word24 addr, word36 *data, const char * ctx);
2264 int core_write_unlock (cpu_state_t * cpup, word24 addr, word36 data, const char * ctx);
2265 int core_unlock_all(cpu_state_t * cpup);
2266 
2267 # define DEADLOCK_DETECT   0x40000000U
2268 # define MEM_LOCKED_BIT    61
2269 # define MEM_LOCKED        (1LLU<<MEM_LOCKED_BIT)
2270 
2271 # if !defined(SCHED_NEVER_YIELD)
2272 #  undef SCHED_YIELD
2273 #  define SCHED_YIELD(lockStatePtr)                                      \
2274   do                                                                     \
2275     {                                                                    \
2276       if ((i & 0xff) == 0)                                               \
2277         {                                                                \
2278           sched_yield();                                                 \
2279           (lockStatePtr)->lockYield++;                                   \
2280         }                                                                \
2281     }                                                                    \
2282   while(0)
2283 # else
2284 #  undef SCHED_YIELD
2285 #  define SCHED_YIELD(lockStatePtr)                                      \
2286   do                                                                     \
2287     {                                                                    \
2288     }                                                                    \
2289   while(0)
2290 # endif /* if !defined(SCHED_NEVER_YIELD) */
2291 
2292 # if defined (BSD_ATOMICS)
2293 #  include <machine/atomic.h>
2294 
2295 #  define LOCK_CORE_WORD(addr,lockStatePtr)                              \
2296   do                                                                     \
2297     {                                                                    \
2298       unsigned int i = DEADLOCK_DETECT;                                  \
2299       while ( atomic_testandset_64((volatile uint64_t *)&M[addr],        \
2300             MEM_LOCKED_BIT) == 1 && i > 0)                               \
2301         {                                                                \
2302           i--;                                                           \
2303           SCHED_YIELD(lockStatePtr);                                     \
2304         }                                                                \
2305       if (i == 0)                                                        \
2306         {                                                                \
2307           sim_warn ("%s: locked %x addr %x deadlock\r\n", __func__,      \
2308               (lockStatePtr)->locked_addr, addr);                        \
2309         }                                                                \
2310       (lockStatePtr)->lockCnt++;                                         \
2311       if (i == DEADLOCK_DETECT)                                          \
2312         (lockStatePtr)->lockImmediate++;                                 \
2313       (lockStatePtr)->lockWait += (DEADLOCK_DETECT-i);                   \
2314       (lockStatePtr)->lockWaitMax = ((DEADLOCK_DETECT-i) >               \
2315           (lockStatePtr)->lockWaitMax) ?                                 \
2316               (DEADLOCK_DETECT-i) : (lockStatePtr)->lockWaitMax;         \
2317     }                                                                    \
2318   while (0)
2319 
2320 #  define LOAD_ACQ_CORE_WORD(res, addr)                                  \
2321   do                                                                     \
2322     {                                                                    \
2323       res = atomic_load_acq_64((volatile uint64_t *)&M[addr]);           \
2324     }                                                                    \
2325   while (0)
2326 
2327 #  define STORE_REL_CORE_WORD(addr, data)                                \
2328   do                                                                     \
2329     {                                                                    \
2330       atomic_store_rel_64((volatile uint64_t *)&M[addr], data & DMASK);  \
2331     }                                                                    \
2332   while (0)
2333 
2334 # endif // BSD_ATOMICS
2335 
2336 # if defined(GNU_ATOMICS)
2337 
2338 #  define LOCK_CORE_WORD(addr,lockStatePtr)                              \
2339   do                                                                     \
2340     {                                                                    \
2341       unsigned int i = DEADLOCK_DETECT;                                  \
2342       while ((__atomic_fetch_or((volatile uint64_t *)&M[addr],           \
2343         MEM_LOCKED, __ATOMIC_ACQ_REL) & MEM_LOCKED)                      \
2344                 && i > 0)                                                \
2345     {                                                                    \
2346       i--;                                                               \
2347       SCHED_YIELD(lockStatePtr);                                         \
2348     }                                                                    \
2349       if (i == 0)                                                        \
2350         {                                                                \
2351           sim_warn ("%s: locked %x addr %x deadlock\r\n",                \
2352             __func__, (lockStatePtr)->locked_addr, addr);                \
2353         }                                                                \
2354       (lockStatePtr)->lockCnt++;                                         \
2355       if (i == DEADLOCK_DETECT)                                          \
2356           (lockStatePtr)->lockImmediate++;                               \
2357       (lockStatePtr)->lockWait += (DEADLOCK_DETECT-i);                   \
2358       (lockStatePtr)->lockWaitMax = ((DEADLOCK_DETECT-i) >               \
2359           (lockStatePtr)->lockWaitMax) ? (DEADLOCK_DETECT-i) :           \
2360               (lockStatePtr)->lockWaitMax;                               \
2361     }                                                                    \
2362   while (0)
2363 
2364 #  define LOAD_ACQ_CORE_WORD(res, addr)                                  \
2365   do                                                                     \
2366     {                                                                    \
2367       res = __atomic_load_n((volatile uint64_t *)&M[addr],               \
2368           __ATOMIC_ACQUIRE);                                             \
2369     }                                                                    \
2370   while (0)
2371 
2372 #  define STORE_REL_CORE_WORD(addr, data)                                \
2373   do                                                                     \
2374     {                                                                    \
2375       __atomic_store_n((volatile uint64_t *)&M[addr], data &             \
2376           DMASK, __ATOMIC_RELEASE);                                      \
2377     }                                                                    \
2378   while (0)
2379 
2380 # endif // GNU_ATOMICS
2381 
2382 # if defined(SYNC_ATOMICS)
2383 #  if defined(MEMORY_ACCESS_NOT_STRONGLY_ORDERED)
2384 #   define MEM_BARRIER()   do { __sync_synchronize(); } while (0)
2385 #  else
2386 #   define MEM_BARRIER()   do {} while (0)
2387 #  endif
2388 
2389 #  define LOCK_CORE_WORD(addr,lockStatePtr)                              \
2390      do                                                                  \
2391        {                                                                 \
2392          unsigned int i = DEADLOCK_DETECT;                               \
2393          while ((__sync_fetch_and_or((volatile uint64_t *)&M[addr],      \
2394              MEM_LOCKED) & MEM_LOCKED) && i > 0)                         \
2395            {                                                             \
2396             i--;                                                         \
2397             SCHED_YIELD(lockStatePtr);                                   \
2398            }                                                             \
2399          if (i == 0)                                                     \
2400            {                                                             \
2401             sim_warn ("%s: locked %x addr %x deadlock\r\n", __func__,    \
2402                 (lockStatePtr)->locked_addr, addr);                      \
2403             }                                                            \
2404          (lockStatePtr)->lockCnt++;                                      \
2405          if (i == DEADLOCK_DETECT)                                       \
2406            (lockStatePtr)->lockImmediate++;                              \
2407          (lockStatePtr)->lockWait += (DEADLOCK_DETECT-i);                \
2408          (lockStatePtr)->lockWaitMax = ((DEADLOCK_DETECT-i) >            \
2409              (lockStatePtr)->lockWaitMax) ?                              \
2410                  (DEADLOCK_DETECT-i) : (lockStatePtr)->lockWaitMax;      \
2411        }                                                                 \
2412      while (0)
2413 
2414 #  define LOAD_ACQ_CORE_WORD(res, addr)                                  \
2415      do                                                                  \
2416        {                                                                 \
2417          res = M[addr];                                                  \
2418          MEM_BARRIER();                                                  \
2419        }                                                                 \
2420      while (0)
2421 
2422 #  define STORE_REL_CORE_WORD(addr, data)                                \
2423   do                                                                     \
2424     {                                                                    \
2425       MEM_BARRIER();                                                     \
2426       M[addr] = data & DMASK;                                            \
2427     }                                                                    \
2428   while (0)
2429 
2430 # endif  // SYNC_ATOMICS
2431 #endif  // LOCKLESS
2432 
2433 static inline void core_readN (cpu_state_t * cpup, word24 addr, word36 * data, uint n,
     /* [previous][next][first][last][top][bottom][index][help] */
2434                                UNUSED const char * ctx)
2435   {
2436     for (uint i = 0; i < n; i ++)
2437       {
2438         core_read (cpup, addr + i, data + i, ctx);
2439         //HDBGMRead (addr + i, * (data + i), __func__);
2440       }
2441   }
2442 
2443 static inline void core_writeN (cpu_state_t * cpup, word24 addr, word36 * data, uint n,
     /* [previous][next][first][last][top][bottom][index][help] */
2444                                 UNUSED const char * ctx)
2445   {
2446     for (uint i = 0; i < n; i ++)
2447       {
2448         core_write (cpup, addr + i, data [i], ctx);
2449         //HDBGMWrite (addr + i, * (data + i), __func__);
2450       }
2451   }
2452 
2453 int is_priv_mode (cpu_state_t * cpup);
2454 //void set_went_appending (void);
2455 //void clr_went_appending (void);
2456 //bool get_went_appending (void);
2457 bool get_bar_mode (cpu_state_t * cpup);
2458 addr_modes_e get_addr_mode (cpu_state_t * cpup);
2459 void set_addr_mode (cpu_state_t * cpup, addr_modes_e mode);
2460 void decode_instruction (cpu_state_t * cpup, word36 inst, DCDstruct * p);
2461 #if !defined(SPEED)
2462 t_stat set_mem_watch (int32 arg, const char * buf);
2463 #endif /* if !defined(SPEED) */
2464 char *str_SDW0 (char * buf, sdw_s *SDW);
2465 int lookup_cpu_mem_map (cpu_state_t * cpup, word24 addr);
2466 bool tandd_mode_any (void);
2467 void cpu_init (void);
2468 void cpu_stop_poll_timer (void);
2469 void setup_scbank_map (cpu_state_t * cpup);
2470 void tandd_set_nea_port (cpu_state_t * cpup, word24 addr);
2471 // T&D parity, store not ready and lock out (SM782-SM784)
2472 int tandd_scu_for_addr (cpu_state_t * cpup, word24 addr);
2473 bool sdpap_store (cpu_state_t * cpup, word24 addr, word36 * data, uint nWords);
2474 bool sc_command_parity (cpu_state_t * cpup, uint scuUnitIdx, uint cpuPortNum);
2475 extern uint nBadParity;
2476 void bad_parity_read (cpu_state_t * cpup, word24 addr);
2477 void bad_parity_clear (word24 addr);
2478 void bad_parity_mark (word24 addr);
2479 bool bad_parity_marked (word24 addr);
2480 void sc_lockout_wait (cpu_state_t * cpup);
2481 uint scuStoreParityIA (cpu_state_t * cpup, word24 addr, bool zac, bool * doStore, bool * keepBadParity);
2482 uint scuReadParityIA (cpu_state_t * cpup, word24 addr);
2483 uint scuCommandParityIA (uint scuUnitIdx, bool zac);
2484 extern uint scuGoInhibitMask;
2485 bool scuStoreNotReady (cpu_state_t * cpup, word24 addr);
2486 #define BAD_PARITY_READ(a)  do { if (nBadParity) bad_parity_read (cpup, (a)); } while (0)
2487 #define BAD_PARITY_WRITE(a) do { if (nBadParity) bad_parity_clear ((a)); } while (0)
2488 #define SC_LOCKOUT_WAIT()   do { if (cpu.scLockedOut) sc_lockout_wait (cpup); } while (0)
2489 word24 sc_interlace_addr (cpu_state_t * cpup, word24 addr);
2490 void add_dps8m_CU_history (cpu_state_t * cpup);
2491 void add_dps8m_DUOU_history (word36 flags, word18 ICT, word9 RS_REG, word9 flags2);
2492 void add_dps8m_APU_history (word15 ESN, word21 flags, word24 RMA, word3 RTRR, word9 flags2);
2493 void add_dps8m_EAPU_history (word18 ZCA, word18 opcode);
2494 void add_l68_CU_history (cpu_state_t * cpup);
2495 void add_l68_CU_fetch_history (cpu_state_t * cpup);
2496 void press_execute_switches (uint cpuNo);
2497 void add_l68_OU_history (cpu_state_t * cpup);
2498 void add_l68_DU_history (cpu_state_t * cpup);
2499 void add_l68_APU_history (cpu_state_t * cpup, enum APUH_e op);
2500 void add_history_force (cpu_state_t * cpup, uint hset, word36 w0, word36 w1);
2501 word18 get_BAR_address(cpu_state_t * cpup, word18 addr);
2502 #if defined(THREADZ) || defined(LOCKLESS)
2503 t_stat threadz_sim_instr (void);
2504 void * cpu_thread_main (void * arg);
2505 void perfTest (char * testName);
2506 #endif
2507 void cpu_reset_unit_idx (UNUSED uint cpun, bool clear_mem);
2508 void setupPROM (uint cpuNo, unsigned char * PROM);
2509 void cpuStats (uint cpuNo);
2510 #if defined(THREADZ) || defined(LOCKLESS)
2511 void becomeClockMaster (uint cpuNum);
2512 void giveupClockMaster (cpu_state_t * cpup);
2513 #endif
2514 char * cycle_str (cycles_e cycle);

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