root/src/dps8/dps8_cpu.c

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

DEFINITIONS

This source file includes following definitions.
  1. cpu_show_config
  2. cpu_set_config
  3. cpu_show_nunits
  4. cpu_set_nunits
  5. cpu_show_kips
  6. cpu_set_kips
  7. cpu_show_stall
  8. cpu_set_stall
  9. setCPUConfigL68
  10. setCPUConfigDPS8M
  11. cycle_str
  12. set_cpu_cycle
  13. set_cpu_idx
  14. cpu_reset_unit_idx
  15. simh_cpu_reset_and_clear_unit
  16. simh_cpu_reset_unit
  17. str_SDW0
  18. cpu_boot
  19. scu_phys_bank
  20. setup_scbank_map_tandd
  21. sc_port_for_addr
  22. tandd_scu_for_addr
  23. consume_parity_bits
  24. ia_priority
  25. sdpap_store
  26. sc_command_parity
  27. bad_parity_mark
  28. bad_parity_clear
  29. bad_parity_marked
  30. bad_parity_read
  31. sc_lockout_wait
  32. sc_fine_map
  33. tandd_set_nea_port
  34. setup_scbank_map
  35. tandd_io_mode
  36. lookup_cpu_mem_map
  37. get_serial_number
  38. do_stats
  39. ev_poll_cb
  40. cpu_init
  41. cpu_stop_poll_timer
  42. cpu_reset
  43. sim_cpu_reset
  44. cpu_ex
  45. cpu_dep
  46. get_highest_intr
  47. disDiagEnabled
  48. disDiagEnter
  49. disDiagInterruptSet
  50. disDiagWake
  51. sample_interrupts
  52. simh_hooks
  53. panel_process_event
  54. sim_instr
  55. cpu_thread_main
  56. do_LUF_fault
  57. set_temporary_absolute_mode
  58. clear_temporary_absolute_mode
  59. becomeClockMaster
  60. giveupClockMaster
  61. threadz_sim_instr
  62. operand_size
  63. readOperandRead
  64. readOperandRMW
  65. write_operand
  66. set_mem_watch
  67. nem_check
  68. core_read
  69. core_read_lock
  70. core_write
  71. core_write_unlock
  72. core_unlock_all
  73. core_write_zone
  74. core_read2
  75. core_write2
  76. decode_instruction
  77. is_priv_mode
  78. get_bar_mode
  79. get_addr_mode
  80. set_addr_mode
  81. get_BAR_address
  82. add_history
  83. add_history_force
  84. add_dps8m_CU_history
  85. add_dps8m_DU_OU_history
  86. add_dps8m_APU_history
  87. add_dps8m_EAPU_history
  88. add_l68_CU_history_entry
  89. add_l68_CU_history
  90. add_l68_CU_fetch_history
  91. add_l68_DU_history
  92. add_l68_OU_history
  93. add_l68_APU_history
  94. get_dbg_verb
  95. dps8_sim_debug
  96. setupPROM
  97. cpuStats
  98. perfTest

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * SPDX-License-Identifier: Multics
   5  * scspell-id: 6e07fe19-f62d-11ec-86f2-80ee73e9b8e7
   6  *
   7  * ---------------------------------------------------------------------------
   8  *
   9  * Copyright (c) 2007-2013 Michael Mondy
  10  * Copyright (c) 2012-2016 Harry Reed
  11  * Copyright (c) 2013-2023 Charles Anthony
  12  * Copyright (c) 2017 Michal Tomek
  13  * Copyright (c) 2026 Eric Swenson
  14  * Copyright (c) 2021-2026 Jeffrey H. Johnson
  15  * Copyright (c) 2021-2026 The DPS8M Development Team
  16  *
  17  * This software is made available under the terms of the ICU License.
  18  * See the LICENSE.md file at the top-level directory of this distribution.
  19  *
  20  * ---------------------------------------------------------------------------
  21  *
  22  * This source file may contain code comments that adapt, include, and/or
  23  * incorporate Multics program code and/or documentation distributed under
  24  * the Multics License.  In the event of any discrepancy between code
  25  * comments herein and the original Multics materials, the original Multics
  26  * materials should be considered authoritative unless otherwise noted.
  27  * For more details and historical background, see the LICENSE.md file at
  28  * the top-level directory of this distribution.
  29  *
  30  * ---------------------------------------------------------------------------
  31  */
  32 
  33 #include <stdio.h>
  34 #include <unistd.h>
  35 #include <ctype.h>
  36 
  37 #if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32)
  38 # include <sys/mman.h>
  39 #endif
  40 
  41 #include "dps8.h"
  42 #include "dps8_sys.h"
  43 #include "dps8_iom.h"
  44 #include "dps8_cable.h"
  45 #include "dps8_cpu.h"
  46 #include "dps8_rt.h"
  47 #include "dps8_priv.h"
  48 #include "dps8_addrmods.h"
  49 #include "dps8_faults.h"
  50 #include "dps8_scu.h"
  51 #include "dps8_append.h"
  52 #include "dps8_ins.h"
  53 #include "dps8_state.h"
  54 #include "dps8_math.h"
  55 #include "dps8_iefp.h"
  56 #include "dps8_console.h"
  57 #include "dps8_fnp2.h"
  58 #include "dps8_socket_dev.h"
  59 #include "dps8_crdrdr.h"
  60 #include "dps8_absi.h"
  61 #include "dps8_mgp.h"
  62 #include "dps8_net.h"
  63 #include "dps8_utils.h"
  64 #include "dps8_memalign.h"
  65 
  66 #if defined(M_SHARED)
  67 # include "shm.h"
  68 #endif
  69 
  70 #include "dps8_opcodetable.h"
  71 #include "../simh/sim_defs.h"
  72 #include "../simh/sim_os_mem.h"
  73 
  74 #if defined(THREADZ) || defined(LOCKLESS)
  75 # include "threadz.h"
  76 __thread uint current_running_cpu_idx;
  77 #endif
  78 
  79 #include "ver.h"
  80 
  81 #if defined(_AIX) && !defined(__PASE__)
  82 # include <pthread.h>
  83 # include <sys/resource.h>
  84 #endif
  85 
  86 #if defined(NO_LOCALE)
  87 # define xstrerror_l strerror
  88 #endif
  89 
  90 #define DBG_CTR cpu.cycleCnt
  91 
  92 #define ASSUME0 0
  93 
  94 #define FREE(p) do  \
  95   {                 \
  96     free((p));      \
  97     (p) = NULL;     \
  98   } while(0)
  99 
 100 // CPU data structures
 101 
 102 static UNIT cpu_unit [N_CPU_UNITS_MAX] = {
 103 #if defined(NO_C_ELLIPSIS)
 104   { UDATA (NULL, UNIT_FIX|UNIT_BINK, MEMSIZE), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 105   { UDATA (NULL, UNIT_FIX|UNIT_BINK, MEMSIZE), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 106   { UDATA (NULL, UNIT_FIX|UNIT_BINK, MEMSIZE), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 107   { UDATA (NULL, UNIT_FIX|UNIT_BINK, MEMSIZE), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 108   { UDATA (NULL, UNIT_FIX|UNIT_BINK, MEMSIZE), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 109   { UDATA (NULL, UNIT_FIX|UNIT_BINK, MEMSIZE), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 110   { UDATA (NULL, UNIT_FIX|UNIT_BINK, MEMSIZE), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
 111   { UDATA (NULL, UNIT_FIX|UNIT_BINK, MEMSIZE), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
 112 #else
 113   [0 ... N_CPU_UNITS_MAX - 1] = {
 114     UDATA (NULL, UNIT_FIX|UNIT_BINK, MEMSIZE), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
 115   }
 116 #endif
 117 };
 118 
 119 #define UNIT_IDX(uptr) ((uptr) - cpu_unit)
 120 
 121 // Assume CPU clock ~ 1MIPS. lockup time is 32 ms
 122 #define LOCKUP_KIPS 1000
 123 static uint64 kips = LOCKUP_KIPS;
 124 // Lockup limit n (0-3 = CMR.luf 2/4/8/16 ms, 4 = 32 ms privileged). In T&D
 125 // mode the lockup is timed in TR decrements (512 kHz: 2 ms = 1024 counts),
 126 // so the TR a page reads after a lockup agrees with it (PM776 08A-08H).
 127 #define LUF_OVER(n) (cpu.tweaks.tandd_mode ? \
 128     cpu.lufTicks >= (1024u << (n)) : \
 129     cpu.lufCounter > luf_limits[n])
 130 
 131 static uint64 luf_limits[] =
 132   {
 133      2000*LOCKUP_KIPS/1000,
 134      4000*LOCKUP_KIPS/1000,
 135      8000*LOCKUP_KIPS/1000,
 136     16000*LOCKUP_KIPS/1000,
 137     32000*LOCKUP_KIPS/1000
 138   };
 139 
 140 struct stall_point_s stall_points [N_STALL_POINTS];
 141 bool stall_point_active = false;
 142 
 143 #if defined(PANEL68)
 144 static void panel_process_event (void);
 145 #endif /* if defined(PANEL68) */
 146 
 147 static t_stat simh_cpu_reset_and_clear_unit (UNIT * uptr,
 148                                              UNUSED int32 value,
 149                                              UNUSED const char * cptr,
 150                                              UNUSED void * desc);
 151 char * cycle_str (cycles_e cycle);
 152 
 153 static t_stat cpu_show_config (UNUSED FILE * st, UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 154                                UNUSED int val, UNUSED const void * desc)
 155   {
 156     long cpu_unit_idx = UNIT_IDX (uptr);
 157     if (cpu_unit_idx < 0 || cpu_unit_idx >= N_CPU_UNITS_MAX)
 158       {
 159         sim_warn ("error: Invalid unit number %ld\r\n", (long) cpu_unit_idx);
 160         return SCPE_ARG;
 161       }
 162 
 163 #define PFC_INT8 "%c%c%c%c%c%c%c%c"
 164 
 165 #define PBI_8(i)                     \
 166     ( ((i) & 0x80ll) ? '1' : '0' ),  \
 167     ( ((i) & 0x40ll) ? '1' : '0' ),  \
 168     ( ((i) & 0x20ll) ? '1' : '0' ),  \
 169     ( ((i) & 0x10ll) ? '1' : '0' ),  \
 170     ( ((i) & 0x08ll) ? '1' : '0' ),  \
 171     ( ((i) & 0x04ll) ? '1' : '0' ),  \
 172     ( ((i) & 0x02ll) ? '1' : '0' ),  \
 173     ( ((i) & 0x01ll) ? '1' : '0' )
 174 
 175 #define PFC_INT16 PFC_INT8  PFC_INT8
 176 #define PFC_INT32 PFC_INT16 PFC_INT16
 177 #define PFC_INT64 PFC_INT32 PFC_INT32
 178 
 179 #define PBI_16(i) PBI_8((i)  >>  8), PBI_8(i)
 180 #define PBI_32(i) PBI_16((i) >> 16), PBI_16(i)
 181 #define PBI_64(i) PBI_32((i) >> 32), PBI_32(i)
 182 
 183     char dsbin[66], adbin[34];
 184 
 185     sim_msg ("CPU unit number %ld\r\n", (long) cpu_unit_idx);
 186 
 187     sim_msg ("Fault base:                   %03o(8)\r\n",
 188                 cpus[cpu_unit_idx].switches.FLT_BASE);
 189     sim_msg ("CPU number:                   %01o(8)\r\n",
 190                 cpus[cpu_unit_idx].switches.cpu_num);
 191     sim_msg ("Data switches:                %012llo(8)\r\n",
 192                 (unsigned long long)cpus[cpu_unit_idx].switches.data_switches);
 193     (void)snprintf (dsbin, 65, PFC_INT64,
 194                     PBI_64((unsigned long long)cpus[cpu_unit_idx].switches.data_switches));
 195     sim_msg ("                              %36s(2)\r\n",
 196                 dsbin + strlen(dsbin) - 36);
 197     sim_msg ("Address switches:             %06o(8)\r\n",
 198                 cpus[cpu_unit_idx].switches.addr_switches);
 199     (void)snprintf (adbin, 33, PFC_INT32,
 200                     PBI_32(cpus[cpu_unit_idx].switches.addr_switches));
 201     sim_msg ("                              %18s(2)\r\n",
 202                 adbin + strlen(adbin) - 18);
 203     for (int i = 0; i < (cpus[cpu_unit_idx].tweaks.l68_mode ? N_L68_CPU_PORTS : N_DPS8M_CPU_PORTS); i ++)
 204       {
 205         sim_msg ("Port%c enable:                 %01o(8)\r\n",
 206                     'A' + i, cpus[cpu_unit_idx].switches.enable [i]);
 207         sim_msg ("Port%c init enable:            %01o(8)\r\n",
 208                     'A' + i, cpus[cpu_unit_idx].switches.init_enable [i]);
 209         sim_msg ("Port%c assignment:             %01o(8)\r\n",
 210                     'A' + i, cpus[cpu_unit_idx].switches.assignment [i]);
 211         sim_msg ("Port%c interlace:              %01o(8)\r\n",
 212                     'A' + i, cpus[cpu_unit_idx].switches.interlace [i]);
 213         sim_msg ("Port%c store size:             %01o(8)\r\n",
 214                     'A' + i, cpus[cpu_unit_idx].switches.store_size [i]);
 215       }
 216     sim_msg ("Processor mode:               %s [%o]\r\n",
 217                 cpus[cpu_unit_idx].switches.procMode == \
 218                     procModeMultics ? "Multics" : cpus[cpu_unit_idx].switches.procMode == procModeGCOS ? "GCOS" : "???",
 219                 cpus[cpu_unit_idx].switches.procMode);
 220     sim_msg ("8K Cache:                     %s\r\n",
 221                 cpus[cpu_unit_idx].switches.enable_cache ? "Enabled" : "Disabled");
 222     sim_msg ("SDWAM:                        %s\r\n",
 223                 cpus[cpu_unit_idx].switches.sdwam_enable ? "Enabled" : "Disabled");
 224     sim_msg ("PTWAM:                        %s\r\n",
 225                 cpus[cpu_unit_idx].switches.ptwam_enable ? "Enabled" : "Disabled");
 226 
 227     sim_msg ("Processor speed:              %02o(8)\r\n",
 228                 cpus[cpu_unit_idx].options.proc_speed);
 229     sim_msg ("DIS enable:                   %01o(8)\r\n",
 230                 cpus[cpu_unit_idx].tweaks.dis_enable);
 231     sim_msg ("Steady clock:                 %01o(8)\r\n",
 232                 scu [0].steady_clock);
 233     sim_msg ("Halt on unimplemented:        %01o(8)\r\n",
 234                 cpus[cpu_unit_idx].tweaks.halt_on_unimp);
 235     sim_msg ("Enable simulated SDWAM/PTWAM: %01o(8)\r\n",
 236                 cpus[cpu_unit_idx].tweaks.enable_wam);
 237     sim_msg ("Report faults:                %01o(8)\r\n",
 238                 cpus[cpu_unit_idx].tweaks.report_faults);
 239     sim_msg ("TRO faults enabled:           %01o(8)\r\n",
 240                 cpus[cpu_unit_idx].tweaks.tro_enable);
 241     sim_msg ("drl fatal enabled:            %01o(8)\r\n",
 242                 cpus[cpu_unit_idx].tweaks.drl_fatal);
 243     sim_msg ("useMap:                       %d\r\n",
 244                 cpus[cpu_unit_idx].tweaks.useMap);
 245     sim_msg ("PROM installed:               %01o(8)\r\n",
 246                 cpus[cpu_unit_idx].options.prom_installed);
 247     sim_msg ("Hex mode installed:           %01o(8)\r\n",
 248                 cpus[cpu_unit_idx].options.hex_mode_installed);
 249     sim_msg ("8K cache installed:           %01o(8)\r\n",
 250                 cpus[cpu_unit_idx].options.cache_installed);
 251     sim_msg ("Clock slave installed:        %01o(8)\r\n",
 252                 cpus[cpu_unit_idx].options.clock_slave_installed);
 253 #if defined(AFFINITY)
 254     if (cpus[cpu_unit_idx].set_affinity)
 255       sim_msg ("CPU affinity:                 %d\r\n", cpus[cpu_unit_idx].affinity);
 256     else
 257       sim_msg ("CPU affinity:                 not set\r\n");
 258 #endif
 259     sim_msg ("ISOLTS mode:                  %01o(8)\r\n", cpus[cpu_unit_idx].tweaks.isolts_mode);
 260     sim_msg ("T&D mode:                     %01o(8)\r\n", cpus[cpu_unit_idx].tweaks.tandd_mode);
 261     sim_msg ("NODIS mode:                   %01o(8)\r\n", cpus[cpu_unit_idx].tweaks.nodis);
 262     sim_msg ("6180 mode:                    %01o(8) [%s]\r\n",
 263              cpus[cpu_unit_idx].tweaks.l68_mode, cpus[cpu_unit_idx].tweaks.l68_mode ? "6180" : "DPS8/M");
 264     return SCPE_OK;
 265   }
 266 
 267 //
 268 // set cpu0 config=<blah> [;<blah>]
 269 //
 270 //    blah =
 271 //           faultbase = n
 272 //           num = n
 273 //           data = n
 274 //           portenable = n
 275 //           portconfig = n
 276 //           portinterlace = n
 277 //           mode = n
 278 //           speed = n
 279 //    Hacks:
 280 //           dis_enable = n
 281 //           steadyclock = on|off
 282 //           halt_on_unimplemented = n
 283 //           enable_wam = n
 284 //           report_faults = n
 285 //               n = 0 don't
 286 //               n = 1 report
 287 //               n = 2 report overflow
 288 //           tro_enable = n
 289 //           drl_fatal
 290 
 291 static config_value_list_t cfg_multics_fault_base [] =
 292   {
 293     { "multics", 2 },
 294     { NULL,      0 }
 295   };
 296 
 297 static config_value_list_t cfg_on_off [] =
 298   {
 299     { "off",     0 },
 300     { "on",      1 },
 301     { "disable", 0 },
 302     { "enable",  1 },
 303     { NULL,      0 }
 304   };
 305 
 306 static config_value_list_t cfg_l68_mode [] = {
 307   { "dps8/m", 0 },
 308   { "dps8m",  0 },
 309   { "dps8",   0 },
 310   { "l68",    1 },
 311   { "l6180",  1 },
 312   { "6180",   1 },
 313 };
 314 
 315 static config_value_list_t cfg_cpu_mode [] =
 316   {
 317     { "gcos",    0 },
 318     { "multics", 1 },
 319     { NULL,      0 }
 320   };
 321 
 322 static config_value_list_t cfg_port_letter [] =
 323   {
 324     { "a",  0 },
 325     { "b",  1 },
 326     { "c",  2 },
 327     { "d",  3 },
 328     { "e",  4 },
 329     { "f",  5 },
 330     { "g",  6 },
 331     { "h",  7 },
 332     { NULL, 0 }
 333   };
 334 
 335 static config_value_list_t cfg_interlace [] =
 336   {
 337     { "off", 0 },
 338     { "2",   2 },
 339     { "4",   4 },
 340     { NULL,  0 }
 341   };
 342 
 343 #if defined(AFFINITY)
 344 static config_value_list_t cfg_affinity [] =
 345   {
 346     { "off", -1 },
 347     { NULL,  0  }
 348   };
 349 #endif
 350 
 351 static config_value_list_t cfg_size_list [] =
 352   {
 353 
 354 
 355 
 356 
 357 
 358 
 359 
 360 
 361 
 362 
 363 
 364 
 365 
 366 
 367 
 368 
 369 
 370 
 371 
 372 
 373 
 374 
 375 
 376 
 377 
 378 
 379 
 380 
 381 
 382 
 383 
 384 
 385 
 386 
 387 
 388 
 389 
 390 
 391 
 392 
 393 
 394 
 395 
 396 
 397 
 398 
 399 
 400 
 401 
 402 
 403 
 404 
 405 
 406 
 407 
 408 
 409 
 410 
 411 
 412 
 413 
 414 
 415     { "32",     8 },    //   32768
 416     { "32K",    8 },    //   32768
 417     { "64",     9 },    //   65536
 418     { "64K",    9 },    //   65536
 419     { "128",   10 },    //  131072
 420     { "128K",  10 },    //  131072
 421     { "256",   11 },    //  262144
 422     { "256K",  11 },    //  262144
 423     { "512",   12 },    //  524288
 424     { "512K",  12 },    //  524288
 425     { "1024",  13 },    // 1048576
 426     { "1024K", 13 },    // 1048576
 427     { "1M",    13 },
 428     { "2048",  14 },    // 2097152
 429     { "2048K", 14 },    // 2097152
 430     { "2M",    14 },
 431     { "4096",  15 },    // 4194304
 432     { "4096K", 15 },    // 4194304
 433     { "4M",    15 },
 434     { NULL,    0  }
 435   };
 436 
 437 static config_list_t cpu_config_list [] =
 438   {
 439     { "faultbase",             0,  0177,            cfg_multics_fault_base },
 440     { "num",                   0,  07,              NULL                   },
 441     { "data",                  0,  0777777777777,   NULL                   },
 442     { "stopnum",               0,  999999,          NULL                   },
 443     { "mode",                  0,  01,              cfg_cpu_mode           },
 444     { "speed",                 0,  017,             NULL                   },  // XXX use keywords
 445     { "port",                  0,  N_CPU_PORTS - 1, cfg_port_letter        },
 446     { "assignment",            0,  7,               NULL                   },
 447     { "interlace",             0,  1,               cfg_interlace          },
 448     { "enable",                0,  1,               cfg_on_off             },
 449     { "init_enable",           0,  1,               cfg_on_off             },
 450     { "store_size",            0,  7,               cfg_size_list          },
 451     { "enable_cache",          0,  1,               cfg_on_off             },
 452     { "sdwam",                 0,  1,               cfg_on_off             },
 453     { "ptwam",                 0,  1,               cfg_on_off             },
 454 
 455     // Hacks
 456     { "dis_enable",            0,  1,               cfg_on_off             },
 457     // steady_clock was moved to SCU; keep here for script compatibility
 458     { "steady_clock",          0,  1,               cfg_on_off             },
 459     { "halt_on_unimplemented", 0,  1,               cfg_on_off             },
 460     { "enable_wam",            0,  1,               cfg_on_off             },
 461     { "report_faults",         0,  1,               cfg_on_off             },
 462     { "tro_enable",            0,  1,               cfg_on_off             },
 463     { "drl_fatal",             0,  1,               cfg_on_off             },
 464     { "useMap",                0,  1,               cfg_on_off             },
 465     { "address",               0,  0777777,         NULL                   },
 466     { "prom_installed",        0,  1,               cfg_on_off             },
 467     { "hex_mode_installed",    0,  1,               cfg_on_off             },
 468     { "cache_installed",       0,  1,               cfg_on_off             },
 469     { "clock_slave_installed", 0,  1,               cfg_on_off             },
 470     { "enable_emcall",         0,  1,               cfg_on_off             },
 471 
 472     // Tuning
 473 #if defined(AFFINITY)
 474     { "affinity",              -1, 32767,           cfg_affinity           },
 475 #endif
 476     { "isolts_mode",           0,  1,               cfg_on_off             },
 477     { "tandd_mode",            0,  1,               cfg_on_off             },
 478     { "nodis",                 0,  1,               cfg_on_off             },
 479     { "l68_mode",              0,  1,               cfg_l68_mode           },
 480     { NULL,                    0,  0,               NULL                   }
 481   };
 482 
 483 static t_stat cpu_set_config (UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
 484                               const char * cptr, UNUSED void * desc)
 485   {
 486     long cpu_unit_idx = UNIT_IDX (uptr);
 487     if (cpu_unit_idx < 0 || cpu_unit_idx >= N_CPU_UNITS_MAX)
 488       {
 489         sim_warn ("error: cpu_set_config: Invalid unit number %ld\r\n",
 490                     (long) cpu_unit_idx);
 491         return SCPE_ARG;
 492       }
 493 
 494     static int port_num = 0;
 495 
 496     config_state_t cfg_state = { NULL, NULL };
 497 
 498     for (;;)
 499       {
 500         int64_t v;
 501         int rc = cfg_parse (__func__, cptr, cpu_config_list,
 502                            & cfg_state, & v);
 503         if (rc == -1) // done
 504           {
 505             break;
 506           }
 507         if (rc == -2) // error
 508           {
 509             cfg_parse_done (& cfg_state);
 510             return SCPE_ARG;
 511           }
 512 
 513         const char * p = cpu_config_list [rc] . name;
 514         if (strcmp (p, "faultbase") == 0)
 515           cpus[cpu_unit_idx].switches.FLT_BASE = (uint) v;
 516         else if (strcmp (p, "num") == 0)
 517           cpus[cpu_unit_idx].switches.cpu_num = (uint) v;
 518         else if (strcmp (p, "data") == 0)
 519           cpus[cpu_unit_idx].switches.data_switches = (word36) v;
 520         else if (strcmp (p, "stopnum") == 0)
 521           {
 522             // set up for check stop
 523             // convert stopnum to bcd
 524             int64_t d1 = (v / 1000) % 10;
 525             int64_t d2 = (v /  100) % 10;
 526             int64_t d3 = (v /   10) % 10;
 527             int64_t d4 = (v /    1) % 10;
 528             word36 d = 0123000000000;
 529             putbits36_6 (& d,  9, (word4) d1);
 530             putbits36_6 (& d, 15, (word4) d2);
 531             putbits36_6 (& d, 21, (word4) d3);
 532             putbits36_6 (& d, 27, (word4) d4);
 533             cpus[cpu_unit_idx].switches.data_switches = d;
 534           }
 535         else if (strcmp (p, "address") == 0)
 536           cpus[cpu_unit_idx].switches.addr_switches = (word18) v;
 537         else if (strcmp (p, "mode") == 0)
 538           cpus[cpu_unit_idx].switches.procMode = v ? procModeMultics : procModeGCOS;
 539         else if (strcmp (p, "speed") == 0)
 540           cpus[cpu_unit_idx].options.proc_speed = (uint) v;
 541         else if (strcmp (p, "port") == 0) {
 542           if ((! cpus[cpu_unit_idx].tweaks.l68_mode) && (int) v > 3) {
 543             cfg_parse_done (& cfg_state);
 544             return SCPE_ARG;
 545           }
 546           port_num = (int) v;
 547         }
 548         else if (strcmp (p, "assignment") == 0)
 549           cpus[cpu_unit_idx].switches.assignment [port_num] = (uint) v;
 550         else if (strcmp (p, "interlace") == 0)
 551           cpus[cpu_unit_idx].switches.interlace [port_num] = (uint) v;
 552         else if (strcmp (p, "enable") == 0)
 553           cpus[cpu_unit_idx].switches.enable [port_num] = (uint) v;
 554         else if (strcmp (p, "init_enable") == 0)
 555           cpus[cpu_unit_idx].switches.init_enable [port_num] = (uint) v;
 556         else if (strcmp (p, "store_size") == 0) {
 557           if (v > 7) {
 558             if (cpus[cpu_unit_idx].tweaks.l68_mode) {
 559               switch (v) {
 560                 case  8:  v = 0;   break; // 32K
 561                 case  9:  v = 1;   break; // 64K
 562                 case 10:  v = 3;   break; // 128K
 563                 case 11:  v = 7;   break; // 256K
 564                 case 12:  v = 4;   break; // 512K
 565                 case 13:  v = 5;   break; // 1024K
 566                 case 14:  v = 6;   break; // 2048K
 567                 case 15:  v = 2;   break; // 4096K
 568               }
 569             } else {
 570               switch (v) {
 571                 case  8:  v = 0;   break; // 32K
 572                 case  9:  v = 1;   break; // 64K
 573                 case 10:  v = 2;   break; // 128K
 574                 case 11:  v = 3;   break; // 256K
 575                 case 12:  v = 4;   break; // 512K
 576                 case 13:  v = 5;   break; // 1024K
 577                 case 14:  v = 6;   break; // 2048K
 578                 case 15:  v = 7;   break; // 4096K
 579               }
 580             }
 581           }
 582           cpus[cpu_unit_idx].switches.store_size [port_num] = (uint) v;
 583         }
 584         else if (strcmp (p, "enable_cache") == 0)
 585           cpus[cpu_unit_idx].switches.enable_cache = (uint) v ? true : false;
 586         else if (strcmp (p, "sdwam") == 0)
 587           cpus[cpu_unit_idx].switches.sdwam_enable = (uint) v ? true : false;
 588         else if (strcmp (p, "ptwam") == 0)
 589           cpus[cpu_unit_idx].switches.ptwam_enable = (uint) v ? true : false;
 590         else if (strcmp (p, "dis_enable") == 0)
 591           cpus[cpu_unit_idx].tweaks.dis_enable = (uint) v;
 592         else if (strcmp (p, "steady_clock") == 0)
 593           scu [0].steady_clock = (uint) v;
 594         else if (strcmp (p, "halt_on_unimplemented") == 0)
 595           cpus[cpu_unit_idx].tweaks.halt_on_unimp = (uint) v;
 596         else if (strcmp (p, "enable_wam") == 0)
 597           cpus[cpu_unit_idx].tweaks.enable_wam = (uint) v;
 598         else if (strcmp (p, "report_faults") == 0)
 599           cpus[cpu_unit_idx].tweaks.report_faults = (uint) v;
 600         else if (strcmp (p, "tro_enable") == 0)
 601           cpus[cpu_unit_idx].tweaks.tro_enable = (uint) v;
 602         else if (strcmp (p, "drl_fatal") == 0)
 603           cpus[cpu_unit_idx].tweaks.drl_fatal = (uint) v;
 604         else if (strcmp (p, "useMap") == 0)
 605           cpus[cpu_unit_idx].tweaks.useMap = v;
 606         else if (strcmp (p, "prom_installed") == 0)
 607           cpus[cpu_unit_idx].options.prom_installed = v;
 608         else if (strcmp (p, "hex_mode_installed") == 0)
 609           cpus[cpu_unit_idx].options.hex_mode_installed = v;
 610         else if (strcmp (p, "cache_installed") == 0)
 611           cpus[cpu_unit_idx].options.cache_installed = v;
 612         else if (strcmp (p, "clock_slave_installed") == 0)
 613           cpus[cpu_unit_idx].options.clock_slave_installed = v;
 614         else if (strcmp (p, "enable_emcall") == 0)
 615           cpus[cpu_unit_idx].tweaks.enable_emcall = v;
 616 #if defined(AFFINITY)
 617         else if (strcmp (p, "affinity") == 0)
 618           if (v < 0)
 619             {
 620               cpus[cpu_unit_idx].set_affinity = false;
 621             }
 622           else
 623             {
 624               cpus[cpu_unit_idx].set_affinity = true;
 625               cpus[cpu_unit_idx].affinity = (uint) v;
 626             }
 627 #endif
 628         else if (strcmp (p, "tandd_mode") == 0)
 629           cpus[cpu_unit_idx].tweaks.tandd_mode = v ? true : false;
 630         else if (strcmp (p, "isolts_mode") == 0)
 631           {
 632             bool was = cpus[cpu_unit_idx].tweaks.isolts_mode;
 633             cpus[cpu_unit_idx].tweaks.isolts_mode = v;
 634             if (v && ! was) {
 635               uint store_sz;
 636               if (cpus[cpu_unit_idx].tweaks.l68_mode) // L68
 637                 store_sz = 3;
 638               else // DPS8M
 639                 store_sz = 2;
 640               cpus[cpu_unit_idx].isolts_switches_save     = cpus[cpu_unit_idx].switches;
 641 
 642               cpus[cpu_unit_idx].switches.data_switches   = 00000030714000;
 643               cpus[cpu_unit_idx].switches.addr_switches   = 0100150;
 644               cpus[cpu_unit_idx].tweaks.useMap            = true;
 645               cpus[cpu_unit_idx].tweaks.enable_wam        = true;
 646               cpus[cpu_unit_idx].switches.assignment  [0] = 0;
 647               cpus[cpu_unit_idx].switches.interlace   [0] = false;
 648               cpus[cpu_unit_idx].switches.enable      [0] = false;
 649               cpus[cpu_unit_idx].switches.init_enable [0] = false;
 650               cpus[cpu_unit_idx].switches.store_size  [0] = store_sz;
 651 
 652               cpus[cpu_unit_idx].switches.assignment  [1] = 0;
 653               cpus[cpu_unit_idx].switches.interlace   [1] = false;
 654               cpus[cpu_unit_idx].switches.enable      [1] = true;
 655               cpus[cpu_unit_idx].switches.init_enable [1] = false;
 656               cpus[cpu_unit_idx].switches.store_size  [1] = store_sz;
 657 
 658               cpus[cpu_unit_idx].switches.assignment  [2] = 0;
 659               cpus[cpu_unit_idx].switches.interlace   [2] = false;
 660               cpus[cpu_unit_idx].switches.enable      [2] = false;
 661               cpus[cpu_unit_idx].switches.init_enable [2] = false;
 662               cpus[cpu_unit_idx].switches.store_size  [2] = store_sz;
 663 
 664               cpus[cpu_unit_idx].switches.assignment  [3] = 0;
 665               cpus[cpu_unit_idx].switches.interlace   [3] = false;
 666               cpus[cpu_unit_idx].switches.enable      [3] = false;
 667               cpus[cpu_unit_idx].switches.init_enable [3] = false;
 668               cpus[cpu_unit_idx].switches.store_size  [3] = store_sz;
 669 
 670               if (cpus[cpu_unit_idx].tweaks.l68_mode) { // L68
 671                 cpus[cpu_unit_idx].switches.assignment  [4] = 0;
 672                 cpus[cpu_unit_idx].switches.interlace   [4] = false;
 673                 cpus[cpu_unit_idx].switches.enable      [4] = false;
 674                 cpus[cpu_unit_idx].switches.init_enable [4] = false;
 675                 cpus[cpu_unit_idx].switches.store_size  [4] = 3;
 676 
 677                 cpus[cpu_unit_idx].switches.assignment  [5] = 0;
 678                 cpus[cpu_unit_idx].switches.interlace   [5] = false;
 679                 cpus[cpu_unit_idx].switches.enable      [5] = false;
 680                 cpus[cpu_unit_idx].switches.init_enable [5] = false;
 681                 cpus[cpu_unit_idx].switches.store_size  [5] = 3;
 682 
 683                 cpus[cpu_unit_idx].switches.assignment  [6] = 0;
 684                 cpus[cpu_unit_idx].switches.interlace   [6] = false;
 685                 cpus[cpu_unit_idx].switches.enable      [6] = false;
 686                 cpus[cpu_unit_idx].switches.init_enable [6] = false;
 687                 cpus[cpu_unit_idx].switches.store_size  [6] = 3;
 688 
 689                 cpus[cpu_unit_idx].switches.assignment  [7] = 0;
 690                 cpus[cpu_unit_idx].switches.interlace   [7] = false;
 691                 cpus[cpu_unit_idx].switches.enable      [7] = false;
 692                 cpus[cpu_unit_idx].switches.init_enable [7] = false;
 693                 cpus[cpu_unit_idx].switches.store_size  [7] = 3;
 694               }
 695               cpus[cpu_unit_idx].switches.enable      [1] = true; //-V1048
 696 
 697 #if defined(THREADZ) || defined(LOCKLESS)
 698               if (cpus[cpu_unit_idx].executing) {
 699                 cpus[cpu_unit_idx].forceRestart = true;
 700                 wakeCPU (cpu_unit_idx);
 701               } else {
 702                 cpu_reset_unit_idx ((uint) cpu_unit_idx, false);
 703                 //simh_cpu_reset_and_clear_unit (cpuUnits + cpu_unit_idx, 0, NULL, NULL);
 704               }
 705 #else /* defined(THREADZ) || defined(LOCKLESS) */
 706               cpu_reset_unit_idx ((uint) cpu_unit_idx, false);
 707               simh_cpu_reset_and_clear_unit (cpu_unit + cpu_unit_idx, 0, NULL, NULL);
 708 #endif /* defined(THREADZ) || defined(LOCKLESS) */
 709 
 710             } else if (was && !v) {
 711               cpus[cpu_unit_idx].switches = cpus[cpu_unit_idx].isolts_switches_save;
 712 
 713 #if defined(THREADZ) || defined(LOCKLESS)
 714               if (cpus[cpu_unit_idx].executing) {
 715                 cpus[cpu_unit_idx].forceRestart = true;
 716                 wakeCPU (cpu_unit_idx);
 717               } else {
 718                 cpu_reset_unit_idx ((uint) cpu_unit_idx, false);
 719                 //simh_cpu_reset_and_clear_unit (cpuUnits + cpu_unit_idx, 0, NULL, NULL);
 720               }
 721 #else /* defined(THREADZ) || defined(LOCKLESS) */
 722             cpu_reset_unit_idx ((uint) cpu_unit_idx, false);
 723             simh_cpu_reset_and_clear_unit (cpu_unit + cpu_unit_idx, 0, NULL, NULL);
 724 #endif /* defined(THREADZ) || defined(LOCKLESS) */
 725 
 726             }
 727           }
 728         else if (strcmp (p, "nodis") == 0)
 729           cpus[cpu_unit_idx].tweaks.nodis = v;
 730         else if (strcmp (p, "l68_mode") == 0)
 731           cpus[cpu_unit_idx].tweaks.l68_mode = v;
 732         else
 733           {
 734             sim_warn ("error: cpu_set_config: Invalid cfg_parse rc <%ld>\r\n",
 735                         (long) rc);
 736             cfg_parse_done (& cfg_state);
 737             return SCPE_ARG;
 738           }
 739       } // process statements
 740     cfg_parse_done (& cfg_state);
 741 
 742     return SCPE_OK;
 743   }
 744 
 745 static t_stat cpu_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 746                                UNUSED int val, UNUSED const void * desc)
 747   {
 748     sim_msg ("Number of CPUs in system is %d\r\n", cpu_dev.numunits);
 749     return SCPE_OK;
 750   }
 751 
 752 static t_stat cpu_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
 753                               const char * cptr, UNUSED void * desc)
 754   {
 755     if (! cptr)
 756       return SCPE_ARG;
 757     int n = atoi (cptr);
 758     if (n < 1 || n > N_CPU_UNITS_MAX)
 759       return SCPE_ARG;
 760     cpu_dev.numunits = (uint32) n;
 761     return SCPE_OK;
 762   }
 763 
 764 static t_stat cpu_show_kips (UNUSED FILE * st, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 765                              UNUSED int val, UNUSED const void * desc)
 766   {
 767     sim_msg ("CPU KIPS %lu\r\n", (unsigned long)kips);
 768     return SCPE_OK;
 769   }
 770 
 771 static t_stat cpu_set_kips (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
 772                             const char * cptr, UNUSED void * desc)
 773   {
 774     if (! cptr)
 775       return SCPE_ARG;
 776     long n = atol (cptr);
 777     if (n < 1 || n > 4000000)
 778       return SCPE_ARG;
 779     kips = (uint64) n;
 780     luf_limits[0] =  2000*kips/1000;
 781     luf_limits[1] =  4000*kips/1000;
 782     luf_limits[2] =  8000*kips/1000;
 783     luf_limits[3] = 16000*kips/1000;
 784     luf_limits[4] = 32000*kips/1000;
 785     return SCPE_OK;
 786   }
 787 
 788 static t_stat cpu_show_stall (UNUSED FILE * st, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 789                              UNUSED int val, UNUSED const void * desc)
 790   {
 791     if (! stall_point_active)
 792       {
 793         sim_printf ("No stall points\r\n");
 794         return SCPE_OK;
 795       }
 796 
 797     sim_printf ("Stall points\r\n");
 798     for (int i = 0; i < N_STALL_POINTS; i ++)
 799       if (stall_points[i].segno || stall_points[i].offset)
 800         {
 801 #if defined(WIN_STDIO)
 802           sim_printf ("%2ld %05o:%06o %10lu\r\n",
 803 #else
 804           sim_printf ("%2ld %05o:%06o %'10lu\r\n",
 805 #endif
 806                  (long)i, stall_points[i].segno, stall_points[i].offset,
 807                  (unsigned long)stall_points[i].time);
 808         }
 809     return SCPE_OK;
 810   }
 811 
 812 // set cpu stall=n=s:o=t
 813 //   n stall point number
 814 //   s segment number (octal)
 815 //   o offset (octal)
 816 //   t time in microseconds (decimal)
 817 
 818 static t_stat cpu_set_stall (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
 819                              const char * cptr, UNUSED void * desc)
 820   {
 821     if (! cptr)
 822       return SCPE_ARG;
 823 
 824     long n, s, o, t;
 825 
 826     char * end;
 827     n = strtol (cptr, & end, 0);
 828     if (* end != '=')
 829       return SCPE_ARG;
 830     if (n < 0 || n >= N_STALL_POINTS)
 831       return SCPE_ARG;
 832 
 833     s = strtol (end + 1, & end, 8);
 834     if (* end != ':')
 835       return SCPE_ARG;
 836     if (s < 0 || s > MASK15)
 837       return SCPE_ARG;
 838 
 839     o = strtol (end + 1, & end, 8);
 840     if (* end != '=')
 841       return SCPE_ARG;
 842     if (o < 0 || o > MASK18)
 843       return SCPE_ARG;
 844 
 845     t = strtol (end + 1, & end, 0);
 846     if (* end != 0)
 847       return SCPE_ARG;
 848     if (t < 0 || t > 30000000)
 849       return SCPE_ARG;
 850 
 851     stall_points[n].segno  = (word15) s;
 852     stall_points[n].offset = (word18) o;
 853     stall_points[n].time   = (unsigned int) t;
 854     stall_point_active     = false;
 855 
 856     for (int i = 0; i < N_STALL_POINTS; i ++)
 857       if (stall_points[n].segno && stall_points[n].offset)
 858         stall_point_active = true;
 859 
 860     return SCPE_OK;
 861   }
 862 
 863 static t_stat setCPUConfigL68 (UNIT * uptr, UNUSED int32 value, UNUSED const char * cptr, UNUSED void * desc) {
     /* [previous][next][first][last][top][bottom][index][help] */
 864   long cpuUnitIdx = UNIT_IDX (uptr);
 865   if (cpuUnitIdx < 0 || cpuUnitIdx >= N_CPU_UNITS_MAX)
 866     return SCPE_ARG;
 867   cpu_state_t * cpun = cpus + cpuUnitIdx;
 868 
 869   cpun->tweaks.l68_mode = 1;
 870   cpun->options.hex_mode_installed = 0;
 871   for (uint port_num = 0; port_num < N_DPS8M_CPU_PORTS; port_num ++) {
 872     cpun->switches.assignment[port_num] = port_num;
 873     cpun->switches.interlace[port_num] = 0;
 874     cpun->switches.store_size[port_num] = 2;
 875     cpun->switches.enable[port_num] = 1;
 876     cpun->switches.init_enable[port_num] = 1;
 877   }
 878   for (uint port_num = N_DPS8M_CPU_PORTS; port_num < N_L68_CPU_PORTS; port_num ++) {
 879     cpun->switches.assignment[port_num] = 0;
 880     cpun->switches.interlace[port_num] = 0;
 881     cpun->switches.store_size[port_num] = 0;
 882     cpun->switches.enable[port_num] = 0;
 883     cpun->switches.init_enable[port_num] = 0;
 884   }
 885   return SCPE_OK;
 886 }
 887 
 888 static t_stat setCPUConfigDPS8M (UNIT * uptr, UNUSED int32 value, UNUSED const char * cptr, UNUSED void * desc) {
     /* [previous][next][first][last][top][bottom][index][help] */
 889   long cpuUnitIdx = UNIT_IDX (uptr);
 890   if (cpuUnitIdx < 0 || cpuUnitIdx >= N_CPU_UNITS_MAX)
 891     return SCPE_ARG;
 892   cpu_state_t * cpun = cpus + cpuUnitIdx;
 893 
 894   cpun->tweaks.l68_mode = 0;
 895   cpun->options.hex_mode_installed = 0;
 896   for (uint port_num = 0; port_num < N_DPS8M_CPU_PORTS; port_num ++) {
 897     cpun->switches.assignment[port_num] = port_num;
 898     cpun->switches.interlace[port_num] = 0;
 899     cpun->switches.store_size[port_num] = 7;
 900     cpun->switches.enable[port_num] = 1;
 901     cpun->switches.init_enable[port_num] = 1;
 902   }
 903   for (uint port_num = N_DPS8M_CPU_PORTS; port_num < N_L68_CPU_PORTS; port_num ++) {
 904     cpun->switches.assignment[port_num] = 0;
 905     cpun->switches.interlace[port_num] = 0;
 906     cpun->switches.store_size[port_num] = 0;
 907     cpun->switches.enable[port_num] = 0;
 908     cpun->switches.init_enable[port_num] = 0;
 909   }
 910   return SCPE_OK;
 911 }
 912 
 913 char * cycle_str (cycles_e cycle)
     /* [previous][next][first][last][top][bottom][index][help] */
 914   {
 915     switch (cycle)
 916       {
 917         //case ABORT_cycle:
 918           //return "ABORT_cycle";
 919         case FAULT_cycle:
 920           return "FAULT_cycle";
 921         case EXEC_cycle:
 922           return "EXEC_cycle";
 923         case FAULT_EXEC_cycle:
 924           return "FAULT_EXEC_cycle";
 925         case INTERRUPT_cycle:
 926           return "INTERRUPT_cycle";
 927         case INTERRUPT_EXEC_cycle:
 928           return "INTERRUPT_EXEC_cycle";
 929         case FETCH_cycle:
 930           return "FETCH_cycle";
 931         case PSEUDO_FETCH_cycle:
 932           return "PSEUDO_FETCH_cycle";
 933         case SYNC_FAULT_RTN_cycle:
 934           return "SYNC_FAULT_RTN_cycle";
 935         default:
 936           return "unknown cycle";
 937       }
 938   }
 939 
 940 static void set_cpu_cycle (cpu_state_t * cpup, cycles_e cycle)
     /* [previous][next][first][last][top][bottom][index][help] */
 941   {
 942     sim_debug (DBG_CYCLE, & cpu_dev, "Setting cycle to %s\r\n",
 943                cycle_str (cycle));
 944     cpu.cycle = cycle;
 945   }
 946 
 947 // DPS8M Memory of 36 bit words is implemented as an array of 64 bit words.
 948 // Put state information into the unused high order bits.
 949 #define MEM_UNINITIALIZED (1LLU<<62)
 950 
 951 uint set_cpu_idx (UNUSED uint cpu_idx)
     /* [previous][next][first][last][top][bottom][index][help] */
 952   {
 953     uint prev = current_running_cpu_idx;
 954 #if defined(THREADZ) || defined(LOCKLESS)
 955     current_running_cpu_idx = cpu_idx;
 956 #endif
 957     _cpup = & cpus [current_running_cpu_idx];
 958     return prev;
 959   }
 960 
 961 void cpu_reset_unit_idx (UNUSED uint cpun, bool clear_mem)
     /* [previous][next][first][last][top][bottom][index][help] */
 962   {
 963     uint save = set_cpu_idx (cpun);
 964     cpu_state_t * cpup = _cpup;
 965     if (clear_mem)
 966       {
 967         for (uint i = 0; i < MEMSIZE; i ++)
 968           {
 969             // Clear lock bits and data field; set uninitialized
 970 #if defined(LOCKLESS)
 971             M[i] = (M[i] & ~(MASK36 | MEM_LOCKED)) | MEM_UNINITIALIZED;
 972 #else
 973             M[i] = (M[i] & ~(MASK36)) | MEM_UNINITIALIZED;
 974 #endif
 975           }
 976       }
 977     cpu.rA = 0;
 978     cpu.rQ = 0;
 979 
 980     cpu.PPR.IC   = 0;
 981     cpu.PPR.PRR  = 0;
 982     cpu.PPR.PSR  = 0;
 983     cpu.PPR.P    = 1;
 984     cpu.RSDWH_R1 = 0;
 985     cpu.rTR      = MASK27;
 986 
 987     if (cpu.tweaks.isolts_mode)
 988       {
 989         cpu.shadowTR = 0;
 990         cpu.rTRlsb   = 0;
 991       }
 992     cpu.rTRticks = 0;
 993 
 994     set_addr_mode (cpup, ABSOLUTE_mode);
 995     SET_I_NBAR;
 996 
 997     cpu.CMR.luf  = 3;    // default of 16 mS
 998     cpu.cu.SD_ON = cpu.switches.sdwam_enable ? 1 : 0;
 999     cpu.cu.PT_ON = cpu.switches.ptwam_enable ? 1 : 0;
1000 
1001     if (cpu.tweaks.nodis) {
1002       set_cpu_cycle (cpup, FETCH_cycle);
1003     } else {
1004       set_cpu_cycle (cpup, EXEC_cycle);
1005       cpu.cu.IWB = 0000000616200; //-V536  // Stuff DIS w/interrupt inhibit  in instruction buffer
1006     }
1007 #if defined(PERF_STRIP)
1008     set_cpu_cycle (cpup, FETCH_cycle);
1009 #endif
1010     cpu.wasXfer        = false;
1011     cpu.wasInhibited   = false;
1012 
1013     cpu.interrupt_flag = false;
1014     cpu.g7_flag        = false;
1015 
1016     cpu.faultRegister [0] = 0;
1017     cpu.faultRegister [1] = 0;
1018 
1019 #if defined(RAPRx)
1020     cpu.apu.lastCycle = UNKNOWN_CYCLE;
1021 #endif
1022 
1023     (void)memset (& cpu.PPR, 0, sizeof (struct ppr_s));
1024 
1025     setup_scbank_map (cpup);
1026 
1027     tidy_cu (cpup);
1028     set_cpu_idx (save);
1029   }
1030 
1031 static t_stat simh_cpu_reset_and_clear_unit (UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
1032                                              UNUSED int32 value,
1033                                              UNUSED const char * cptr,
1034                                              UNUSED void * desc)
1035   {
1036     long cpu_unit_idx = UNIT_IDX (uptr);
1037     cpu_state_t * cpun = cpus + cpu_unit_idx;
1038     if (cpun->tweaks.isolts_mode)
1039       {
1040         // Currently isolts_mode requires useMap, so this is redundant
1041         if (cpun->tweaks.useMap)
1042           {
1043             for (uint pgnum = 0; pgnum < N_SCBANKS; pgnum ++)
1044               {
1045                 int base = cpun->sc_addr_map [pgnum];
1046                 if (base < 0)
1047                   continue;
1048                 for (uint addr = 0; addr < SCBANK_SZ; addr ++)
1049                   M [addr + (uint) base] = MEM_UNINITIALIZED;
1050               }
1051           }
1052       }
1053     // Crashes console?
1054     cpu_reset_unit_idx ((uint) cpu_unit_idx, false);
1055     return SCPE_OK;
1056   }
1057 
1058 static t_stat simh_cpu_reset_unit (UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
1059                                    UNUSED int32 value,
1060                                    UNUSED const char * cptr,
1061                                    UNUSED void * desc)
1062   {
1063     long cpu_unit_idx = UNIT_IDX (uptr);
1064     cpu_reset_unit_idx ((uint) cpu_unit_idx, false); // no clear memory
1065     return SCPE_OK;
1066   }
1067 
1068 #if !defined(PERF_STRIP)
1069 static uv_loop_t * ev_poll_loop;
1070 static uv_timer_t ev_poll_handle;
1071 #endif /* if !defined(PERF_STRIP) */
1072 
1073 static MTAB cpu_mod[] =
1074   {
1075     {
1076       MTAB_unit_value,                /* Mask               */
1077       0,                              /* Match              */
1078       "CONFIG",                       /* Print string       */
1079       "CONFIG",                       /* Match string       */
1080       cpu_set_config,                 /* Validation routine */
1081       cpu_show_config,                /* Display routine    */
1082       NULL,                           /* Value descriptor   */
1083       NULL                            /* Help               */
1084     },
1085 
1086 // RESET (INITIALIZE) -- reset CPU
1087 
1088     {
1089       MTAB_unit_value,                /* Mask               */
1090       0,                              /* Match              */
1091       "RESET",                        /* Print string       */
1092       "RESET",                        /* Match string       */
1093       simh_cpu_reset_unit,            /* Validation routine */
1094       NULL,                           /* Display routine    */
1095       NULL,                           /* Value descriptor   */
1096       NULL                            /* Help               */
1097     },
1098 
1099     {
1100       MTAB_unit_value,                /* Mask               */
1101       0,                              /* Match              */
1102       "INITIALIZE",                   /* Print string       */
1103       "INITIALIZE",                   /* Match string       */
1104       simh_cpu_reset_unit,            /* Validation routine */
1105       NULL,                           /* Display routine    */
1106       NULL,                           /* Value descriptor   */
1107       NULL                            /* Help               */
1108     },
1109 
1110 // INITAILIZEANDCLEAR (IAC) -- reset CPU, clear Memory
1111 
1112     {
1113       MTAB_unit_value,                /* Mask               */
1114       0,                              /* Match              */
1115       "INITIALIZEANDCLEAR",           /* Print string       */
1116       "INITIALIZEANDCLEAR",           /* Match string       */
1117       simh_cpu_reset_and_clear_unit,  /* Validation routine */
1118       NULL,                           /* Display routine    */
1119       NULL,                           /* Value descriptor   */
1120       NULL                            /* Help               */
1121     },
1122 
1123     {
1124       MTAB_unit_value,                /* Mask               */
1125       0,                              /* Match              */
1126       "IAC",                          /* Print string       */
1127       "IAC",                          /* Match string       */
1128       simh_cpu_reset_and_clear_unit,  /* Validation routine */
1129       NULL,                           /* Display routine    */
1130       NULL,                           /* Value descriptor   */
1131       NULL                            /* Help               */
1132     },
1133 
1134     {
1135       MTAB_dev_value,                 /* Mask               */
1136       0,                              /* Match              */
1137       "NUNITS",                       /* Print string       */
1138       "NUNITS",                       /* Match string       */
1139       cpu_set_nunits,                 /* Validation routine */
1140       cpu_show_nunits,                /* Display routine    */
1141       NULL,                           /* Value descriptor   */
1142       NULL                            /* Help               */
1143     },
1144 
1145     {
1146       MTAB_dev_value,                 /* Mask               */
1147       0,                              /* Match              */
1148       "KIPS",                         /* Print string       */
1149       "KIPS",                         /* Match string       */
1150       cpu_set_kips,                   /* Validation routine */
1151       cpu_show_kips,                  /* Display routine    */
1152       NULL,                           /* Value descriptor   */
1153       NULL                            /* Help               */
1154     },
1155 
1156     {
1157       MTAB_dev_value,                 /* Mask               */
1158       0,                              /* Match              */
1159       "STALL",                        /* Print string       */
1160       "STALL",                        /* Match string       */
1161       cpu_set_stall,                  /* Validation routine */
1162       cpu_show_stall,                 /* Display routine    */
1163       NULL,                           /* Value descriptor   */
1164       NULL                            /* Help               */
1165     },
1166 
1167     {
1168       MTAB_unit_value,                /* Mask               */
1169       0,                              /* Match              */
1170       "DPS8M",                        /* Print string       */
1171       "DPS8M",                        /* Match string       */
1172       setCPUConfigDPS8M,              /* Validation routine */
1173       NULL,                           /* Display routine    */
1174       NULL,                           /* Value descriptor   */
1175       NULL                            /* Help               */
1176     },
1177 
1178     {
1179       MTAB_unit_value,                /* Mask               */
1180       0,                              /* Match              */
1181       "L68",                          /* Print string       */
1182       "L68",                          /* Match string       */
1183       setCPUConfigL68,                /* Validation routine */
1184       NULL,                           /* Display routine    */
1185       NULL,                           /* Value descriptor   */
1186       NULL                            /* Help               */
1187     },
1188 
1189     { 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }
1190   };
1191 
1192 static DEBTAB cpu_dt[] =
1193   {
1194     { "TRACE",       DBG_TRACE,       NULL },
1195     { "TRACEEXT",    DBG_TRACEEXT,    NULL },
1196     { "MESSAGES",    DBG_MSG,         NULL },
1197 
1198     { "REGDUMPAQI",  DBG_REGDUMPAQI,  NULL },
1199     { "REGDUMPIDX",  DBG_REGDUMPIDX,  NULL },
1200     { "REGDUMPPR",   DBG_REGDUMPPR,   NULL },
1201     { "REGDUMPPPR",  DBG_REGDUMPPPR,  NULL },
1202     { "REGDUMPDSBR", DBG_REGDUMPDSBR, NULL },
1203     { "REGDUMPFLT",  DBG_REGDUMPFLT,  NULL }, // Don't move as it messes up DBG message
1204     { "REGDUMP",     DBG_REGDUMP,     NULL },
1205 
1206     { "ADDRMOD",     DBG_ADDRMOD,     NULL },
1207     { "APPENDING",   DBG_APPENDING,   NULL },
1208 
1209     { "NOTIFY",      DBG_NOTIFY,      NULL },
1210     { "INFO",        DBG_INFO,        NULL },
1211     { "ERR",         DBG_ERR,         NULL },
1212     { "WARN",        DBG_WARN,        NULL },
1213     { "DEBUG",       DBG_DEBUG,       NULL }, // Don't move as it messes up DBG message
1214     { "ALL",         DBG_ALL,         NULL },
1215 
1216     { "FAULT",       DBG_FAULT,       NULL },
1217     { "INTR",        DBG_INTR,        NULL },
1218     { "CORE",        DBG_CORE,        NULL },
1219     { "CYCLE",       DBG_CYCLE,       NULL },
1220     { "CAC",         DBG_CAC,         NULL },
1221     { "FINAL",       DBG_FINAL,       NULL },
1222     { "AVC",         DBG_AVC,         NULL },
1223     { NULL,          0,               NULL }
1224   };
1225 
1226 // This is part of the scp interface
1227 const char *sim_stop_messages[] =
1228   {
1229     "Unknown error",           // SCPE_OK
1230     "Simulation stop",         // STOP_STOP
1231     "Breakpoint",              // STOP_BKPT
1232   };
1233 
1234 /* End of scp interface */
1235 
1236 /* Processor configuration switches
1237  *
1238  * From AM81-04 Multics System Maintenance Procedures
1239  *
1240  * "A Level 68 IOM system may contain a maximum of 7 CPUs, 4 IOMs, 8 SCUs,
1241  * and 16MW of memory ...
1242  * [CAC]: ... but AN87 says Multics only supports two IOMs
1243  *
1244  * ASSIGNMENT: 3 toggle switches determine the base address of the SCU
1245  * connected to the port. The base address (in KW) is the product of this
1246  * number and the value defined by the STORE SIZE patch plug for the port.
1247  *
1248  * ADDRESS RANGE: toggle FULL/HALF. Determines the size of the SCU as full or
1249  * half of the STORE SIZE patch.
1250  *
1251  * PORT ENABLE: (4? toggles)
1252  *
1253  * INITIALIZE ENABLE: (4? toggles) These switches enable the receipt of an
1254  * initialize signal from the SCU connected to the ports. This signal is used
1255  * during the first part of bootload to set all CPUs to a known (idle) state.
1256  * The switch for each port connected to an SCU should be ON, otherwise off.
1257  *
1258  * INTERLACE: ... All INTERLACE switches should be OFF for Multics operation.
1259  *
1260  */
1261 
1262 #if !defined(SPEED)
1263 static bool watch_bits [MEMSIZE];
1264 #endif /* if !defined(SPEED) */
1265 
1266 char * str_SDW0 (char * buf, sdw0_s * SDW)
     /* [previous][next][first][last][top][bottom][index][help] */
1267   {
1268     (void)sprintf (buf, "ADDR=%06o R1=%o R2=%o R3=%o F=%o FC=%o BOUND=%o R=%o "
1269                         "E=%o W=%o P=%o U=%o G=%o C=%o EB=%o",
1270                    SDW->ADDR, SDW->R1,    SDW->R2, SDW->R3, SDW->DF,
1271                    SDW->FC,   SDW->BOUND, SDW->R,  SDW->E,  SDW->W,
1272                    SDW->P,    SDW->U,     SDW->G,  SDW->C,  SDW->EB);
1273     return buf;
1274   }
1275 
1276 static t_stat cpu_boot (UNUSED int32 cpu_unit_idx, UNUSED DEVICE * dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1277   {
1278     sim_warn ("Try 'BOOT IOMn'\r\n");
1279     return SCPE_ARG;
1280   }
1281 
1282 // The original h/w had one to four (DPS8/M) or eight (Level 68) SCUs;
1283 // each SCU held memory.
1284 // Memory accesses were sent to the SCU that held the region of memory
1285 // being addressed.
1286 //
1287 // eg, SCU 0 has 1 MW of memory and SCU 1 has 2 MW
1288 // Address
1289 //      0M +------------------+
1290 //         |                  |  SCU 0
1291 //      1M +------------------+
1292 //         |                  |  SCU 1
1293 //         |                  |
1294 //      3M +------------------+
1295 //
1296 // So SCU 0 has the first MW of addresses, and SCU1 has the second and third
1297 // MWs.
1298 //
1299 // The simulator has a single 16MW array of memory. This code walks the SCUs
1300 // allocates memory regions out of that array to the SCUs based on their
1301 // individual configurations. The 16MW is divided into 4 zones, one for each
1302 // SCU. (SCU0 uses the first 4MW, SCU1 the second 4MW, etc.
1303 //
1304 #define ZONE_SZ (MEM_SIZE_MAX / 4)
1305 //
1306 // The minimum SCU memory size increment is 64KW, which I will refer to as
1307 // a 'bank'. To map a CPU address to the simulated array, the CPU address is
1308 // divided into a bank number and an offset into that bank
1309 //
1310 //    bank_num    = addr / SCBANK_SZ
1311 //    bank_offset = addr % SCBANK_SZ
1312 //
1313 // sc_addr_map[] maps bank numbers to offset in the simulated memory array
1314 //
1315 //    real_addr = sc_addr_map[bank_num] + bank_offset
1316 //
1317 
1318 // T&D mode: map each CPU port's addresses through its SCU's configuration
1319 // register (lower store size, stores A/A1/B/B1 online, LWR, NEA), as the
1320 // T&D SCU tests (SM781 13A, 17A) and dps8m4 do. Memory stays in the
1321 // port's zone of M. Limited to the port's window (port assignment and
1322 // store size switches).
1323 
1324 // T&D: where SCU bank scu_bank (of the SCU's 4M address space; offset:
1325 // the store A/B swap for LWR) is kept in the CPU port's zone of M:
1326 // relative to the port window's first SCU bank, mod 4M, so that without
1327 // LWR the window is kept from the start of the zone, as in
1328 // setup_scbank_map.
1329 static int scu_phys_bank (uint scu_bank, int offset, uint scu_base_bks)
     /* [previous][next][first][last][top][bottom][index][help] */
1330   {
1331     int n_bks = (int) ((4u << 20) / SCBANK_SZ);
1332     int b = ((int) scu_bank + offset - (int) scu_base_bks) % n_bks;
1333     return b < 0 ? b + n_bks : b;
1334   }
1335 
1336 static void setup_scbank_map_tandd (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1337   {
1338     for (uint pg = 0; pg < N_SCBANKS; pg ++)
1339       {
1340         cpu.sc_addr_map [pg] = -1;
1341         cpu.sc_scu_map  [pg] = -1;
1342       }
1343     for (uint u = 0; u < N_SCU_UNITS_MAX; u ++)
1344       cpu.sc_num_banks[u] = 0;
1345     for (uint p = 0; p < N_SCU_PORTS; p ++)
1346       cpu.sc_fine_port[p] = false;
1347     cpu.sc_fine = false;
1348 
1349     uint dps8m_store_table [8] =
1350       { 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304 };
1351     uint l68_store_table [8] =
1352       { 32768, 65536, 4194304, 131072, 524288, 1048576, 2097152, 262144 };
1353 
1354     int n_ports = cpu.tweaks.l68_mode ? N_L68_CPU_PORTS : N_DPS8M_CPU_PORTS;
1355     for (int port_num = 0; port_num < n_ports; port_num ++)
1356       {
1357         if (! cpu.switches.enable [port_num])
1358           continue;
1359         if (! cables->cpu_to_scu[current_running_cpu_idx][port_num].in_use)
1360           continue;
1361 
1362         uint store_size = cpu.switches.store_size [port_num];
1363         // ISOLTS on an L68: size code 3 means 64K (the "cpu test"
1364         // free-edge connector), as in setup_scbank_map's
1365         // l68_isolts_store_table; configure_test_cpu checks that an LDA
1366         // at 64K takes a store fault.
1367         uint sz_wds = cpu.tweaks.l68_mode ?
1368                         (cpu.tweaks.isolts_mode && store_size == 3 ?
1369                            65536 : l68_store_table [store_size]) :
1370                         dps8m_store_table [store_size];
1371         uint base_addr_bks = (sz_wds * cpu.switches.assignment[port_num]) / SCBANK_SZ;
1372         uint port_banks    = sz_wds / SCBANK_SZ;
1373 
1374         uint scu_unit_idx = cables->cpu_to_scu[current_running_cpu_idx][port_num].scu_unit_idx;
1375         scu_t * up = scu + scu_unit_idx;
1376 
1377         // Store units. The lower store is A (B with LWR) and A1 (B1): A1
1378         // (B1) is its upper half (WSCU66LA 3.2.3: the second unit of a
1379         // pair is selected by the address bit just below the pair-size
1380         // boundary; the smallest pair is 64K, two 32K units). A 32K store
1381         // is one unit, A (B). The upper store, if present, is as big as
1382         // the lower one.
1383         uint lower_wds = (1u << up->lower_store_size) * 32768u;
1384         uint half_wds  = lower_wds >= 65536u ? lower_wds / 2 : lower_wds;
1385         bool a_on  = (up->onl >> 3) & 1;
1386         bool a1_on = (up->onl >> 2) & 1;
1387         bool b_on  = (up->onl >> 1) & 1;
1388         bool b1_on = (up->onl >> 0) & 1;
1389         // sub_enable [slot * 2 + half]: slot 0 = lower store, 1 = upper
1390         bool sub_enable[4];
1391         if (up->lwr)   // store B is lower
1392           {
1393             sub_enable[0] = b_on; sub_enable[1] = b1_on;
1394             sub_enable[2] = a_on; sub_enable[3] = a1_on;
1395           }
1396         else
1397           {
1398             sub_enable[0] = a_on; sub_enable[1] = a1_on;
1399             sub_enable[2] = b_on; sub_enable[3] = b1_on;
1400           }
1401         // The upper store is present when its first unit (B, or A with
1402         // LWR) is online; its second unit (B1/A1) is not used without it
1403         // (taken as a hardware rule: B1 is not online while B is offline).
1404         uint upper_wds = (up->lwr ? a_on : b_on) ? lower_wds : 0;
1405         // NEA (bit 0200 enables; 7 bits, 1 = 32K): addresses within the
1406         // SCU at or above it don't exist (AN70).
1407         bool nea_enabled = (up->nea >> 7) & 1;
1408         uint nea_wds     = nea_enabled ? (up->nea & 0177u) << 15 : (4u << 20);
1409 
1410         // The SCU decodes the address it receives, the absolute address
1411         // mod 4M (a 4MW SCU), not the offset from the CPU port's base:
1412         // Multics' scr_util computes the upper store size as
1413         // NEA - mod (base, 4M) - lower store size. The two differ only
1414         // when a port's base is not a multiple of 4M, i.e. on an L68 with
1415         // port size switches below 4M. SM781 13A on such an L68 (256K
1416         // ports) sets SC 1's NEA to its port base + 32K and expects a store
1417         // fault at that address. Stores A/A1/B/B1, NEA and the word kept
1418         // are all chosen by this SCU address.
1419         uint base_wds     = sz_wds * cpu.switches.assignment[port_num];
1420         uint scu_base_wds = base_wds % (4u << 20);
1421 
1422         // Where each store unit is kept in the port's zone of M: its home
1423         // SCU address, store A at 0 and store B at the lower store size
1424         // (stride, below), whatever LWR says, so that LWR moves A and B
1425         // without moving their contents. Kept relative to the port
1426         // window's first SCU address, mod 4M, so that without LWR the
1427         // window is kept from the start of the zone, as setup_scbank_map
1428         // does (ISOLTS: Multics' CPU and the CPU under test share memory).
1429         // Interlaced, the SCU address is below 4M and its 2 bit selects
1430         // the store, so a store's local word address is below
1431         // min (lower store size, 2M), and store B is kept at that stride:
1432         // the same place as without interlace when the lower store is 2M
1433         // or less; with a 4M lower store, A's reachable words are its
1434         // first 2M and B's go in the second 2M (the zone has room for
1435         // 4M, not the 8M of two 4M stores).
1436         uint stride_wds = lower_wds;
1437         if (up->interlace && stride_wds > (2u << 20))
1438           stride_wds = 2u << 20;
1439 
1440         // Mapped word by word if the bank map (64K banks) can't express
1441         // the configuration.
1442         bool fine = up->interlace ||
1443                     lower_wds < 2 * SCBANK_SZ ||   // A/A1 not on a bank boundary
1444                     nea_wds % SCBANK_SZ != 0 ||
1445                     sz_wds % SCBANK_SZ != 0 ||
1446                     base_wds % SCBANK_SZ != 0;
1447 
1448         cpu.sc_num_banks[port_num] = (lower_wds + upper_wds) / SCBANK_SZ;
1449         if (cpu.sc_num_banks[port_num] > port_banks)
1450           cpu.sc_num_banks[port_num] = port_banks;
1451 
1452         if (fine)
1453           {
1454             cpu.sc_fine_port[port_num]      = true;
1455             cpu.sc_fine_interlace[port_num] = up->interlace != 0;
1456             cpu.sc_fine_base[port_num]      = base_wds;
1457             cpu.sc_fine_window[port_num]    = sz_wds;
1458             cpu.sc_fine_scu_base[port_num]  = scu_base_wds;
1459             cpu.sc_fine_lower_wds[port_num] = lower_wds;
1460             cpu.sc_fine_upper_wds[port_num] = upper_wds;
1461             cpu.sc_fine_nea_wds[port_num]   = nea_wds;
1462             cpu.sc_fine = true;
1463             for (uint slot = 0; slot < 2; slot ++)
1464               for (uint unit = 0; unit < SC_FINE_UNITS; unit ++)
1465                 {
1466                   cpu.sc_fine_phys[port_num][slot][unit] = -1;
1467                   uint local_wd = unit * SC_FINE_UNIT;
1468                   if (local_wd >= (slot ? upper_wds : lower_wds))
1469                     continue;
1470                   if (! sub_enable[slot * 2 + (local_wd >= half_wds ? 1 : 0)])
1471                     continue;
1472                   uint home_store = up->lwr ? 1 - slot : slot;  // 0 = A, 1 = B
1473                   uint home = home_store * stride_wds + local_wd;
1474                   uint rel  = (home + (4u << 20) - scu_base_wds) % (4u << 20);
1475                   cpu.sc_fine_phys[port_num][slot][unit] =
1476                     (int) port_num * (int) ZONE_SZ + (int) rel;
1477                 }
1478             // sc_addr_map and sc_scu_map stay -1 for the window: a 64K
1479             // bank can't describe a 32K window. sc_fine_map maps every
1480             // address of the window, and sc_port_for_addr finds its port.
1481             continue;
1482           }
1483 
1484         // By bank: every unit, the NEA boundary and the window are whole
1485         // banks here.
1486         uint scu_base_bks = scu_base_wds / SCBANK_SZ;
1487         for (uint n_bank = 0; n_bank < port_banks; n_bank ++)
1488           {
1489             uint scu_wd = scu_base_wds + n_bank * SCBANK_SZ;
1490             if (scu_wd >= lower_wds + upper_wds || scu_wd >= nea_wds)
1491               continue;
1492             uint slot = scu_wd >= lower_wds ? 1 : 0;
1493             uint local_wd = scu_wd - slot * lower_wds;
1494             if (! sub_enable[slot * 2 + (local_wd >= half_wds ? 1 : 0)])
1495               continue;
1496             uint addr_bks = base_addr_bks + n_bank;
1497             if (addr_bks >= N_SCBANKS)
1498               continue;
1499             if (cpu.sc_addr_map [addr_bks] != -1)
1500               continue;
1501             uint home_store = up->lwr ? 1 - slot : slot;
1502             uint home_bks = (home_store * stride_wds + local_wd) / SCBANK_SZ;
1503             int phys_bank = scu_phys_bank (home_bks, 0, scu_base_bks);
1504             cpu.sc_addr_map[addr_bks] = (int) port_num * (int) ZONE_SZ + phys_bank * (int) SCBANK_SZ;
1505             cpu.sc_scu_map[addr_bks]  = port_num;
1506           }
1507       }
1508   }
1509 
1510 // The CPU port whose memory holds absolute address addr, or -1: a port
1511 // mapped word by word (sc_fine_port, T&D) if addr is in its window, else
1512 // the bank map's port. The port of a word-mapped window is returned for
1513 // every address of the window, as the SCU is there even where a store
1514 // unit is offline or beyond NEA (sc_fine_map decides those).
1515 int sc_port_for_addr (cpu_state_t * cpup, word24 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
1516   {
1517     if (cpu.sc_fine)
1518       for (uint port_num = 0; port_num < N_SCU_PORTS; port_num ++)
1519         {
1520           if (! cpu.sc_fine_port[port_num])
1521             continue;
1522           uint base = cpu.sc_fine_base[port_num];
1523           if (addr >= base && addr - base < cpu.sc_fine_window[port_num])
1524             return (int) port_num;
1525         }
1526     uint pg = addr / SCBANK_SZ;
1527     if (pg >= N_SCBANKS)
1528       return -1;
1529     return cpu.sc_scu_map[pg];
1530   }
1531 
1532 // T&D: the SCU holding absolute address addr (via the CPU port that the
1533 // bank map assigns it to), or -1.
1534 int tandd_scu_for_addr (cpu_state_t * cpup, word24 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
1535   {
1536     int port = sc_port_for_addr (cpup, addr);
1537     if (port < 0)
1538       return -1;
1539     return (int) cables->cpu_to_scu[current_running_cpu_idx][port].scu_unit_idx;
1540   }
1541 
1542 // The mode register's sdpap (data) and separ (ZAC) bits are for the next
1543 // store instruction, which consumes both (AL39: the processor resets bit
1544 // 20/21; SM784 08 sets both). True if separ was set: ZAC has the higher
1545 // illegal action priority (2, data parity 6).
1546 static bool consume_parity_bits (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1547   {
1548     bool zac = cpu.MR.separ;
1549     cpu.MR.separ = 0;
1550     cpu.MR.sdpap = 0;
1551     putbits36_1 (& cpu.MR.r, 20, 0);
1552     putbits36_1 (& cpu.MR.r, 21, 0);
1553     return zac;
1554   }
1555 
1556 // AL39 table 3-2 priority of a system controller illegal action code
1557 // (lower is reported first).
1558 static int ia_priority (uint ia)
     /* [previous][next][first][last][top][bottom][index][help] */
1559   {
1560     static const int prio [16] = { 99, 99, 5, 1, 99, 12, 11, 10, 4, 13, 3, 7, 2, 6, 8, 9 };
1561     return prio [ia & 017];
1562   }
1563 
1564 // T&D: a store instruction with sdpap/separ pending or to a store unit
1565 // that is not ready. The system controller's mode register decides
1566 // whether it is stored and which illegal action is signalled; an illegal
1567 // action gives a parity fault (store fault for not ready) unless the
1568 // parity mask is on (SM782-SM784). Called by every store path; true if it
1569 // did (or suppressed) the store.
1570 bool sdpap_store (cpu_state_t * cpup, word24 addr, word36 * data, uint nWords)
     /* [previous][next][first][last][top][bottom][index][help] */
1571   {
1572     if (! cpu.tweaks.tandd_mode)
1573       return false;
1574     bool notReady = scuGoInhibitMask && scuStoreNotReady (cpup, addr);
1575     bool parity = cpu.MR.separ || cpu.MR.sdpap;
1576     if (! (notReady || parity))
1577       return false;
1578     bool zac = false, doStore = ! notReady, keepBadParity = false;
1579     uint ia = 0;
1580     if (parity)
1581       {
1582         // separ applies to every memory cycle of the next store
1583         zac = consume_parity_bits (cpup);
1584         bool parityStore;
1585         ia = scuStoreParityIA (cpup, addr, zac, & parityStore, & keepBadParity);
1586         doStore = doStore && parityStore;
1587       }
1588     // Both: the SC reports the higher priority one (SM784 08)
1589     if (notReady && (! ia || ia_priority (013) < ia_priority (ia))) //-V536
1590       {
1591         tandd_set_nea_port (cpup, addr);
1592         doFault (FAULT_STR, (_fault_subtype) {.fault_str_subtype=flt_str_nrdy}, "store unit not ready");
1593       }
1594     if (doStore)
1595       {
1596         if (cpu.useZone)
1597           core_write_zone (cpup, addr, * data, "PARITY_STORE");
1598         else
1599           core_writeN (cpup, addr, data, nWords, "PARITY_STORE");
1600         if (keepBadParity && ! zac)
1601           for (uint i = 0; i < nWords; i ++)
1602             bad_parity_mark (addr + i);
1603       }
1604     if (ia)
1605       {
1606         tandd_set_nea_port (cpup, addr);
1607         SETF (cpu.cu.IR, I_PERR);
1608         if (! TST_I_PMASK)   // the parity mask inhibits the fault
1609           doFault (FAULT_PAR, (_fault_subtype) {.bits=ia}, zac ? "separ" : "sdpap");
1610       }
1611     return true;
1612   }
1613 
1614 // T&D: a system controller command (smic, sscr, smcm) sent with
1615 // sdpap/separ pending: refused with IA 14 (ZAC) / 15 (data) unless the SC
1616 // mode register has parity_disable (SM783 ZAC-PARITY). True if the command
1617 // must not be done.
1618 bool sc_command_parity (cpu_state_t * cpup, uint scuUnitIdx, uint cpuPortNum)
     /* [previous][next][first][last][top][bottom][index][help] */
1619   {
1620     if (! cpu.tweaks.tandd_mode || ! (cpu.MR.separ || cpu.MR.sdpap))
1621       return false;
1622     bool zac = consume_parity_bits (cpup);
1623     uint ia = scuCommandParityIA (scuUnitIdx, zac);
1624     if (! ia)
1625       return false;
1626     cpu.neaPort = (word3) cpuPortNum;
1627     SETF (cpu.cu.IR, I_PERR);
1628     if (! TST_I_PMASK)
1629       doFault (FAULT_PAR, (_fault_subtype) {.bits=ia}, zac ? "separ command" : "sdpap command");
1630     return true;
1631   }
1632 
1633 // T&D: words stored with incorrect parity kept by the store unit (SC mode
1634 // register parity_disable + parity_override). Reading one faults; a normal
1635 // store clears it.
1636 #define N_BAD_PARITY 16
1637 uint nBadParity = 0;
1638 static word24 badParity[N_BAD_PARITY];
1639 
1640 void bad_parity_mark (word24 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
1641   {
1642     for (uint i = 0; i < nBadParity; i ++)
1643       if (badParity[i] == addr)
1644         return;
1645     if (nBadParity < N_BAD_PARITY)
1646       badParity[nBadParity ++] = addr;
1647   }
1648 
1649 void bad_parity_clear (word24 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
1650   {
1651     for (uint i = 0; i < nBadParity; i ++)
1652       if (badParity[i] == addr)
1653         {
1654           badParity[i] = badParity[-- nBadParity];
1655           return;
1656         }
1657   }
1658 
1659 bool bad_parity_marked (word24 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
1660   {
1661     for (uint i = 0; i < nBadParity; i ++)
1662       if (badParity[i] == addr)
1663         return true;
1664     return false;
1665   }
1666 
1667 // A read at an even address faults if either word of the double word has
1668 // bad parity, with PARU/PARL for the even/odd word (subtype bits 0100,
1669 // 0200); a read at an odd address faults only if that word does, and then
1670 // sets both. Fits SM782 11/13 and SM783 02/03. The illegal action code
1671 // depends on the SC mode register (scuReadParityIA); the parity mask
1672 // inhibits the fault.
1673 void bad_parity_read (cpu_state_t * cpup, word24 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
1674   {
1675     if (! cpu.tweaks.tandd_mode)
1676       return;
1677     bool upper = bad_parity_marked (addr & ~1u);
1678     bool lower = bad_parity_marked (addr | 1u);
1679     if (addr & 1)
1680       {
1681         if (! lower)
1682           return;
1683         upper = true;
1684       }
1685     else if (! (upper || lower))
1686       return;
1687     word24 badAddr = (addr & 1) ? addr : (bad_parity_marked (addr) ? addr : (addr | 1u));
1688     uint ia = scuReadParityIA (cpup, badAddr);
1689     SETF (cpu.cu.IR, I_PERR);
1690     if (TST_I_PMASK)
1691       return;
1692     tandd_set_nea_port (cpup, badAddr);
1693     doFault (FAULT_PAR,
1694              (_fault_subtype) {.bits=(upper ? 0100u : 0u) | (lower ? 0200u : 0u) | ia},
1695              "bad parity read");
1696   }
1697 
1698 // T&D: a locked read (RMW) of a bad parity word leaves the SC locked; the
1699 // next operand access waits 16 TR counts (SM784 15 needs more than 7;
1700 // inferred length), charged to the TR and the T&D clock.
1701 void sc_lockout_wait (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1702   {
1703     if (cpu.cycle == FETCH_cycle)
1704       return;
1705     cpu.scLockedOut = false;
1706     cpu.rTR = (cpu.rTR - 16u) & MASK27;
1707     cpu.lufTicks += 16;
1708     cpu.tanddTRTicks += 16;
1709   }
1710 
1711 // T&D: map addr if it is in the window of a port that
1712 // setup_scbank_map_tandd maps word by word (sc_fine_port): set *realp to
1713 // where the word is kept in M, or take the store fault, and return true.
1714 // The SCU address (absolute address mod 4M) selects the store and the
1715 // word within it. Without interlace the lower store holds the SCU
1716 // addresses below its size and the upper store the next ones. With SCU
1717 // internal interlace the stores alternate double words: the 2 bit selects
1718 // the store, and the store word is the address with that bit removed.
1719 // (The double word granularity is inferred from SM781 17A, which probes
1720 // location 2; as dps8m4.)
1721 bool sc_fine_map (cpu_state_t * cpup, word24 addr, uint * realp)
     /* [previous][next][first][last][top][bottom][index][help] */
1722   {
1723     for (uint port_num = 0; port_num < N_SCU_PORTS; port_num ++)
1724       {
1725         if (! cpu.sc_fine_port[port_num])
1726           continue;
1727         uint base = cpu.sc_fine_base[port_num];
1728         if (addr < base || addr - base >= cpu.sc_fine_window[port_num])
1729           continue;
1730         uint scu   = cpu.sc_fine_scu_base[port_num] + (addr - base);
1731         uint lower = cpu.sc_fine_lower_wds[port_num];
1732         uint upper = cpu.sc_fine_upper_wds[port_num];
1733         uint store, word;
1734         bool present = true;
1735         if (cpu.sc_fine_interlace[port_num])
1736           {
1737             if (scu >= 2 * lower)
1738               present = false;
1739             store = (scu >> 1) & 1;
1740             word  = ((scu >> 2) << 1) | (scu & 1);
1741             // With only one store present the double words that would be
1742             // in the other store don't exist (SM781 17A: location 2 gives
1743             // a store fault), reported as store not ready (IA 13), not NEA.
1744             if (present && store && ! upper)
1745               {
1746                 tandd_set_nea_port (cpup, addr);
1747                 doFault (FAULT_STR, (_fault_subtype) {.fault_str_subtype=flt_str_nrdy},
1748                          "interlace: store not present");
1749               }
1750           }
1751         else
1752           {
1753             store = scu >= lower ? 1 : 0;
1754             word  = scu - store * lower;
1755             if (word >= (store ? upper : lower))
1756               present = false;
1757           }
1758         // NEA applies to the address the SCU receives, not to the word
1759         // within the selected store.
1760         int phys = -1;
1761         if (present && scu < cpu.sc_fine_nea_wds[port_num] && word < (4u << 20))
1762           phys = cpu.sc_fine_phys[port_num][store][word / SC_FINE_UNIT];
1763         if (phys < 0)
1764           {
1765             tandd_set_nea_port (cpup, addr);
1766             doFault (FAULT_STR, fst_str_nea, "nonexistent address");
1767           }
1768         * realp = (uint) phys + word % SC_FINE_UNIT;
1769         return true;
1770       }
1771     return false;
1772   }
1773 
1774 // T&D: the CPU port whose window (port assignment and store size
1775 // switches) holds addr; SCU word 1 IACHN of an NEA store fault.
1776 void tandd_set_nea_port (cpu_state_t * cpup, word24 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
1777   {
1778     uint dps8m_store_table [8] =
1779       { 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304 };
1780     uint l68_store_table [8] =
1781       { 32768, 65536, 4194304, 131072, 524288, 1048576, 2097152, 262144 };
1782     cpu.neaPort = 0;
1783     cpu.neaNoPort = true;
1784     int n_ports = cpu.tweaks.l68_mode ? N_L68_CPU_PORTS : N_DPS8M_CPU_PORTS;
1785     for (int port_num = 0; port_num < n_ports; port_num ++)
1786       {
1787         if (! cpu.switches.enable [port_num])
1788           continue;
1789         uint store_size = cpu.switches.store_size [port_num];
1790         // ISOLTS on an L68: size code 3 means 64K (the "cpu test"
1791         // free-edge connector), as in setup_scbank_map's
1792         // l68_isolts_store_table; configure_test_cpu checks that an LDA
1793         // at 64K takes a store fault.
1794         uint sz_wds = cpu.tweaks.l68_mode ?
1795                         (cpu.tweaks.isolts_mode && store_size == 3 ?
1796                            65536 : l68_store_table [store_size]) :
1797                         dps8m_store_table [store_size];
1798         uint base = sz_wds * cpu.switches.assignment[port_num];
1799         if (addr >= base && addr - base < sz_wds)
1800           {
1801             cpu.neaPort = (word3) port_num;
1802             cpu.neaNoPort = false;
1803             return;
1804           }
1805       }
1806   }
1807 
1808 void setup_scbank_map (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1809   {
1810     // The word-by-word map is T&D only, so the normal map must not leave
1811     // a previous T&D map's ports active (tandd_mode turned off, then a
1812     // CPU reset). setup_scbank_map_tandd sets them again.
1813     cpu.sc_fine = false;
1814     for (uint p = 0; p < N_SCU_PORTS; p ++)
1815       cpu.sc_fine_port[p] = false;
1816 
1817     if (cpu.tweaks.tandd_mode)
1818       {
1819         setup_scbank_map_tandd (cpup);
1820         return;
1821       }
1822 
1823     // Initialize to unmapped
1824     for (uint pg = 0; pg < N_SCBANKS; pg ++)
1825       {
1826         cpu.sc_addr_map [pg] = -1;
1827         cpu.sc_scu_map  [pg] = -1;
1828       }
1829     for (uint u = 0; u < N_SCU_UNITS_MAX; u ++)
1830       cpu.sc_num_banks[u] = 0;
1831 
1832     // For each port
1833     for (int port_num = 0; port_num < (cpu.tweaks.l68_mode ? N_L68_CPU_PORTS : N_DPS8M_CPU_PORTS); port_num ++)
1834       {
1835         // Ignore disabled ports
1836         if (! cpu.switches.enable [port_num])
1837           continue;
1838 
1839         // Ignore disconnected ports
1840         // This will happen during early initialization,
1841         // before any cables are run.
1842         if (! cables->cpu_to_scu[current_running_cpu_idx][port_num].in_use)
1843           {
1844             continue;
1845           }
1846 
1847         // Calculate the amount of memory in the SCU in words
1848         uint store_size = cpu.switches.store_size [port_num];
1849         uint dps8m_store_table [8] =
1850           { 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304 };
1851 // ISOLTS sez:
1852 // for DPS88:
1853 //   3. set store size switches to 2222.
1854 // for L68:
1855 //   3. remove the right free-edge connector on the 645pq wwb at slot ab28.
1856 //
1857 // During ISOLTS initialization, it requires that the memory switch be set to
1858 // '3' for all eight ports; this corresponds to '2' for the DPS8M (131072)
1859 // Then:
1860 // isolts: a "lda 65536" (64k) failed to produce a store fault
1861 //
1862 // So it seems that the memory size is expected to be 64K, not 128K as per
1863 // the switches; presumably step 3 causes this. Fake it by tweaking store table:
1864 //
1865         uint l68_store_table [8] =
1866           { 32768, 65536, 4194304, 131072, 524288, 1048576, 2097152, 262144 };
1867         uint l68_isolts_store_table [8] =
1868           { 32768, 65536, 4194304, 65536, 524288, 1048576, 2097152, 262144 };
1869 
1870         uint sz_wds =
1871           cpu.tweaks.l68_mode ?
1872             cpu.tweaks.isolts_mode ?
1873               l68_isolts_store_table [store_size] :
1874                 l68_store_table [store_size] :
1875           dps8m_store_table [store_size];
1876 
1877         // Calculate the base address that will be assigned to the SCU
1878         uint base_addr_wds = sz_wds * cpu.switches.assignment[port_num];
1879 
1880         // Now convert to SCBANK_SZ (number of banks)
1881         uint num_banks             = sz_wds / SCBANK_SZ;
1882         cpu.sc_num_banks[port_num] = num_banks;
1883         uint base_addr_bks         = base_addr_wds / SCBANK_SZ;
1884 
1885         // For each page handled by the SCU
1886         for (uint pg = 0; pg < num_banks; pg ++)
1887           {
1888             // What is the address of this bank?
1889             uint addr_bks = base_addr_bks + pg;
1890             // Past the end of memory?
1891             if (addr_bks < N_SCBANKS)
1892               {
1893                 // Has this address been already assigned?
1894                 if (cpu.sc_addr_map [addr_bks] != -1)
1895                   {
1896                     sim_warn ("scbank overlap addr_bks %d (%o) old port %d "
1897                                 "newport %d\r\n",
1898                                 addr_bks, addr_bks, cpu.sc_addr_map [addr_bks], port_num);
1899                   }
1900                 else
1901                   {
1902                     // Assign it
1903                     cpu.sc_addr_map[addr_bks] = (int)((int)port_num * (int)ZONE_SZ + (int)pg * (int)SCBANK_SZ);
1904                     cpu.sc_scu_map[addr_bks]  = port_num;
1905                   }
1906               }
1907             else
1908               {
1909                 sim_warn ("addr_bks too big port %d addr_bks %d (%o), "
1910                             "limit %d (%o)\r\n",
1911                             port_num, addr_bks, addr_bks, N_SCBANKS, N_SCBANKS);
1912               }
1913           }
1914 
1915       } // for port_num
1916 
1917     //for (uint pg = 0; pg < N_SCBANKS; pg ++)
1918      //sim_printf ("pg %o map: %08o\r\n", pg, cpu.sc_addr_map[pg]);
1919   } // sc_bank_map
1920 
1921 // True when the devices are to behave as the T&D tape expects (set sys
1922 // config=tandd_io=on); for device code, which has no CPU context. This is
1923 // separate from the CPUs' tandd_mode: ISOLTS needs tandd_mode on the CPU
1924 // under test while Multics goes on using the I/O system, so a CPU in T&D
1925 // mode must not change device behaviour (e.g. poll_mpc's EURC commands).
1926 
1927 bool tandd_io_mode (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1928   {
1929     return sys_opts.tandd_io;
1930   }
1931 
1932 int lookup_cpu_mem_map (cpu_state_t * cpup, word24 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
1933   {
1934     return sc_port_for_addr (cpup, addr);
1935   }
1936 
1937 //
1938 // serial.txt format
1939 //
1940 //      sn:  number[,number]
1941 //
1942 //  Additional numbers will be for multi-cpu systems.
1943 //  XXX: Other fields to be added.
1944 
1945 #if !defined(PERF_STRIP)
1946 static void get_serial_number (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1947   {
1948       bool havesn = false;
1949       FILE * fp = fopen ("./serial.txt", "r");
1950     while (fp && ! feof (fp))
1951       {
1952         char buffer [81] = "";
1953 # if !defined(__clang_analyzer__)
1954         char * checksn = fgets (buffer, sizeof (buffer), fp);
1955         (void)checksn;
1956 # endif
1957         uint cpun, sn;
1958         if (sscanf (buffer, "sn: %u", & sn) == 1)
1959           {
1960             if (cpu.switches.serno)
1961               sim_msg ("\r\nReplacing CPU serial number:\r\n");
1962             cpu.switches.serno = sn;
1963             if (!sim_quiet)
1964               {
1965                 sim_msg ("%s CPU serial number: %u\r\n", sim_name, cpu.switches.serno);
1966               }
1967             havesn = true;
1968           }
1969         else if (sscanf (buffer, "sn%u: %u", & cpun, & sn) == 2)
1970           {
1971             if (cpun < N_CPU_UNITS_MAX)
1972               {
1973                 if (cpus[cpun].switches.serno)
1974                   sim_msg ("\r\nReplacing CPU %u serial number:\r\n", cpun);
1975                 cpus[cpun].switches.serno = sn;
1976                 if (!sim_quiet)
1977                   {
1978                     sim_msg ("%s CPU %u serial number: %u\r\n",
1979                     sim_name, cpun, cpus[cpun].switches.serno);
1980                   }
1981                 havesn = true;
1982               }
1983           }
1984       }
1985     if (!havesn)
1986       {
1987         if (!sim_quiet)
1988           {
1989             sim_msg ("\r\nPlease register your system at https://dps8m.gitlab.io/register/\r\n");
1990             sim_msg ("or create the file 'serial.txt' containing the line 'sn: 0'.\r\n\r\n");
1991           }
1992       }
1993     if (fp)
1994       fclose (fp);
1995   }
1996 #endif /* if !defined(PERF_STRIP) */
1997 
1998 #if defined(STATS)
1999 static void do_stats (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2000   {
2001     static struct timespec stats_time;
2002     static bool first = true;
2003     if (first)
2004       {
2005         first = false;
2006         clock_gettime (CLOCK_BOOTTIME, & stats_time);
2007         sim_msg ("stats started\r\n");
2008       }
2009     else
2010       {
2011         struct timespec now, delta;
2012         clock_gettime (CLOCK_BOOTTIME, & now);
2013         timespec_diff (& stats_time, & now, & delta);
2014         stats_time = now;
2015         sim_msg ("stats %6ld.%02ld\r\n", delta.tv_sec,
2016                     delta.tv_nsec / 10000000);
2017 
2018         sim_msg ("Instruction counts\r\n");
2019         for (uint i = 0; i < 8; i ++)
2020           {
2021 # if defined(WIN_STDIO)
2022             sim_msg (" %9lld\r\n", (long long int) cpus[i].instrCnt);
2023 # else
2024             sim_msg (" %'9lld\r\n", (long long int) cpus[i].instrCnt);
2025 # endif /* if defined(WIN_STDIO) */
2026             cpus[i].instrCnt = 0;
2027           }
2028         sim_msg ("\r\n");
2029       }
2030   }
2031 #endif
2032 
2033 // The 100Hz timer has expired; poll I/O
2034 
2035 #if !defined(PERF_STRIP)
2036 static void ev_poll_cb (UNUSED uv_timer_t * handle)
     /* [previous][next][first][last][top][bottom][index][help] */
2037   {
2038     cpu_state_t * cpup = _cpup;
2039 
2040     // Call the one hertz stuff every 100 loops
2041     static uint oneHz = 0;
2042     if (oneHz ++ >= sys_opts.sys_slow_poll_interval) // ~ 1Hz
2043       {
2044         oneHz = 0;
2045         rdrProcessEvent ();
2046 # if defined(STATS)
2047         do_stats ();
2048 # endif
2049         cpu.instrCntT0 = cpu.instrCntT1;
2050         cpu.instrCntT1 = cpu.instrCnt;
2051       }
2052     fnpProcessEvent ();
2053 # if defined(WITH_SOCKET_DEV)
2054 #  if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
2055     sk_process_event ();
2056 #  endif /* if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) */
2057 # endif /* if defined(WITH_SOCKET_DEV) */
2058     consoleProcess ();
2059 # if defined(IO_ASYNC_PAYLOAD_CHAN)
2060     iomProcess ();
2061 # endif
2062 # if defined(WITH_ABSI_DEV)
2063 #  if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
2064     absi_process_event ();
2065 #  endif /* if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64) */
2066 # endif /* if defined(WITH_ABSI_DEV) */
2067 # if defined(WITH_MGP_DEV)
2068     mgp_process_event ();
2069 # endif /* if defined(WITH_MGP_DEV) */
2070 # if defined(WITH_NET_DEV)
2071     net_process_event ();
2072 # endif /* if defined(WITH_NET_DEV) */
2073     PNL (panel_process_event ());
2074   }
2075 #endif /* if !defined(PERF_STRIP) */
2076 
2077 // called once initialization
2078 
2079 void cpu_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2080   {
2081 // !!!! Do not use 'cpu' in this routine; usage of 'cpus' violates 'restrict'
2082 // !!!! attribute
2083 
2084     M = system_state->M;
2085 #if defined(M_SHARED)
2086     cpus = system_state->cpus;
2087 #endif /* if defined(M_SHARED) */
2088 
2089 #if !defined(SPEED)
2090     (void)memset (& watch_bits, 0, sizeof (watch_bits));
2091 #endif /* if !defined(SPEED) */
2092 
2093     set_cpu_idx (0);
2094 
2095     (void)memset (cpus, 0, sizeof (cpu_state_t) * N_CPU_UNITS_MAX);
2096 
2097 #if !defined(PERF_STRIP)
2098     get_serial_number (_cpup);
2099 
2100     ev_poll_loop = uv_default_loop ();
2101     uv_timer_init (ev_poll_loop, & ev_poll_handle);
2102     // 10 ms == 100Hz
2103     unsigned int poll_interval = sys_opts.sys_poll_interval;
2104     uv_timer_start (& ev_poll_handle, ev_poll_cb, poll_interval, poll_interval);
2105 #endif /* if !defined(PERF_STRIP) */
2106     // TODO: reset *all* other structures to zero
2107 
2108     cpu_state_t * cpup = _cpup;
2109 
2110     cpu.instrCnt = 0;
2111     cpu.cycleCnt = 0;
2112     for (int i = 0; i < N_FAULTS; i ++)
2113       cpu.faultCnt [i] = 0;
2114 
2115 #if defined(MATRIX)
2116     initializeTheMatrix ();
2117 #endif /* if defined(MATRIX) */
2118   }
2119 
2120 void cpu_stop_poll_timer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2121   {
2122 #if !defined(PERF_STRIP)
2123     if (ev_poll_loop && !uv_is_closing ((uv_handle_t *) & ev_poll_handle))
2124       {
2125         (void)uv_timer_stop (& ev_poll_handle);
2126         uv_close ((uv_handle_t *) & ev_poll_handle, NULL);
2127       }
2128 #endif /* if !defined(PERF_STRIP) */
2129   }
2130 
2131 static void cpu_reset (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2132   {
2133     for (uint i = 0; i < N_CPU_UNITS_MAX; i ++)
2134       {
2135         cpu_reset_unit_idx (i, true);
2136       }
2137 
2138     set_cpu_idx (0);
2139 
2140 #if defined(TESTING)
2141     cpu_state_t * cpup = _cpup;
2142     sim_debug (DBG_INFO, & cpu_dev, "CPU reset: Running\r\n");
2143 #endif
2144   }
2145 
2146 static t_stat sim_cpu_reset (UNUSED DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
2147   {
2148     //(void)memset (M, -1, MEMSIZE * sizeof (word36));
2149 
2150     // Fill DPS8M memory with zeros, plus a flag only visible to the emulator
2151     // marking the memory as uninitialized.
2152 
2153     cpu_reset ();
2154     return SCPE_OK;
2155   }
2156 
2157 /* Memory examine */
2158 //  t_stat examine_routine (t_val *eval_array, t_addr addr, UNIT *uptr, int32
2159 //  switches)
2160 //  Copy  sim_emax consecutive addresses for unit uptr, starting
2161 //  at addr, into eval_array. The switch variable has bit<n> set if the n'th
2162 //  letter was specified as a switch to the examine command.
2163 // Not true...
2164 
2165 static t_stat cpu_ex (t_value *vptr, t_addr addr, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
2166                       UNUSED int32 sw)
2167   {
2168     if (addr>= MEMSIZE)
2169         return SCPE_NXM;
2170     if (vptr != NULL)
2171       {
2172         *vptr = M[addr] & DMASK;
2173       }
2174     return SCPE_OK;
2175   }
2176 
2177 /* Memory deposit */
2178 
2179 static t_stat cpu_dep (t_value val, t_addr addr, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
2180                        UNUSED int32 sw)
2181   {
2182     if (addr >= MEMSIZE) return SCPE_NXM;
2183     M[addr] = val & DMASK;
2184     return SCPE_OK;
2185   }
2186 
2187 /*
2188  * register stuff ...
2189  */
2190 
2191 #if defined(M_SHARED)
2192 // scp has to have a statically allocated IC to refer to.
2193 static word18 dummy_IC;
2194 #endif
2195 
2196 static REG cpu_reg[] =
2197   {
2198     // IC must be the first; see sim_PC.
2199 #if defined(M_SHARED)
2200     { ORDATA (IC, dummy_IC,       VASIZE), 0, 0, 0 },
2201 #else
2202     { ORDATA (IC, cpus[0].PPR.IC, VASIZE), 0, 0, 0 },
2203 #endif
2204     { NULL, NULL, 0, 0, 0, 0,  NULL, NULL, 0, 0, 0 }
2205   };
2206 
2207 /*
2208  * scp interface
2209  */
2210 
2211 REG *sim_PC = & cpu_reg[0];
2212 
2213 /* CPU device descriptor */
2214 
2215 DEVICE cpu_dev =
2216   {
2217     "CPU",          // name
2218     cpu_unit,       // units
2219     cpu_reg,        // registers
2220     cpu_mod,        // modifiers
2221     N_CPU_UNITS,    // #units
2222     8,              // address radix
2223     PASIZE,         // address width
2224     1,              // addr increment
2225     8,              // data radix
2226     36,             // data width
2227     & cpu_ex,       // examine routine
2228     & cpu_dep,      // deposit routine
2229     & sim_cpu_reset,// reset routine
2230     & cpu_boot,     // boot routine
2231     NULL,           // attach routine
2232     NULL,           // detach routine
2233     NULL,           // context
2234     DEV_DEBUG,      // device flags
2235     0,              // debug control flags
2236     cpu_dt,         // debug flag names
2237     NULL,           // memory size change
2238     NULL,           // logical name
2239     NULL,           // help
2240     NULL,           // attach help
2241     NULL,           // help context
2242     NULL,           // description
2243     NULL
2244   };
2245 
2246 #if defined(M_SHARED)
2247 cpu_state_t * cpus = NULL;
2248 #else
2249 cpu_state_t cpus [N_CPU_UNITS_MAX];
2250 #endif
2251 #if defined(THREADZ) || defined(LOCKLESS)
2252 __thread cpu_state_t * restrict _cpup;
2253 #else
2254 cpu_state_t * restrict _cpup;
2255 #endif
2256 
2257 // Scan the SCUs; it one has an interrupt present, return the fault pair
2258 // address for the highest numbered interrupt on that SCU. If no interrupts
2259 // are found, return 1.
2260 
2261 // Called with SCU lock set
2262 
2263 static uint get_highest_intr (cpu_state_t *cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2264   {
2265     uint fp = 1;
2266     for (uint scu_unit_idx = 0; scu_unit_idx < N_SCU_UNITS_MAX; scu_unit_idx ++)
2267       {
2268         if (cpu.events.XIP [scu_unit_idx])
2269           {
2270             fp = scu_get_highest_intr (scu_unit_idx); // CALLED WITH SCU LOCK
2271             if (fp != 1)
2272               break;
2273           }
2274       }
2275     return fp;
2276   }
2277 
2278 // Diagnostic for slow DIS wakeups of a CPU not in Multics (the ISOLTS
2279 // test CPU): with DPS8_DIS_DIAG set in the environment, report every DIS
2280 // wait longer than 3 s, split into the time until an interrupt was set for
2281 // the CPU and the time from then until the CPU noticed it.
2282 static int disDiagOn = -1;
2283 static uint32 disDiagStart[N_CPU_UNITS_MAX];
2284 static uint32 disDiagXip[N_CPU_UNITS_MAX];
2285 
2286 static bool disDiagEnabled (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2287   {
2288     if (disDiagOn < 0)
2289       disDiagOn = getenv ("DPS8_DIS_DIAG") != NULL;
2290     return disDiagOn;
2291   }
2292 
2293 void disDiagEnter (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2294   {
2295     uint i = (uint) current_running_cpu_idx;
2296 #if defined(THREADZ) || defined(LOCKLESS)
2297     if (cpu.inMultics)
2298       return;
2299 #else
2300     (void) cpup;  // only inMultics (threaded builds) needs it
2301 #endif
2302     if (! disDiagEnabled () || i >= N_CPU_UNITS_MAX)
2303       return;
2304     if (disDiagStart[i] == 0)
2305       {
2306         disDiagStart[i] = sim_os_msec () | 1;
2307         disDiagXip[i] = 0;
2308       }
2309   }
2310 
2311 void disDiagInterruptSet (uint i)
     /* [previous][next][first][last][top][bottom][index][help] */
2312   {
2313     if (! disDiagEnabled () || i >= N_CPU_UNITS_MAX)
2314       return;
2315     if (disDiagStart[i] != 0 && disDiagXip[i] == 0)
2316       disDiagXip[i] = sim_os_msec () | 1;
2317   }
2318 
2319 void disDiagWake (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2320   {
2321     uint i = (uint) current_running_cpu_idx;
2322     if (! disDiagEnabled () || i >= N_CPU_UNITS_MAX || disDiagStart[i] == 0)
2323       return;
2324     uint32 now = sim_os_msec ();
2325     // (the "| 1" marking a set time can put it 1 ms after now)
2326     uint32 total = now > disDiagStart[i] ? now - disDiagStart[i] : 0;
2327     if (total > 3000)
2328       {
2329         if (disDiagXip[i])
2330           sim_printf ("DISDIAG CPU %c DIS at %06o: %u ms; interrupt set after %u ms, "
2331                       "noticed %u ms later\r\n", 'A' + i, cpu.PPR.IC, total,
2332                       disDiagXip[i] > disDiagStart[i] ? disDiagXip[i] - disDiagStart[i] : 0,
2333                       now > disDiagXip[i] ? now - disDiagXip[i] : 0);
2334         else
2335           sim_printf ("DISDIAG CPU %c DIS at %06o: %u ms; no interrupt seen being set\r\n",
2336                       'A' + i, cpu.PPR.IC, total);
2337       }
2338     disDiagStart[i] = 0;
2339     disDiagXip[i] = 0;
2340   }
2341 
2342 bool sample_interrupts (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2343   {
2344     cpu.lufCounter = 0;
2345     cpu.lufTicks   = 0;
2346     for (uint scu_unit_idx = 0; scu_unit_idx < N_SCU_UNITS_MAX; scu_unit_idx ++)
2347       {
2348         if (cpu.events.XIP [scu_unit_idx])
2349           {
2350             return true;
2351           }
2352       }
2353     return false;
2354   }
2355 
2356 t_stat simh_hooks (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2357   {
2358     int reason = 0;
2359 
2360     if (breakEnable && stop_cpu)
2361       return STOP_STOP;
2362 
2363     if (cpu.tweaks.isolts_mode == 0)
2364       {
2365         // check clock queue
2366         if (sim_interval <= 0)
2367           {
2368             reason = sim_process_event ();
2369             if ((! breakEnable) && reason == SCPE_STOP)
2370               reason = SCPE_OK;
2371             if (reason)
2372               return reason;
2373           }
2374       }
2375 
2376     sim_interval --;
2377 
2378 #if !defined(THREADZ) && !defined(LOCKLESS)
2379 // This is needed for BCE_TRAP in install scripts
2380     // sim_brk_test expects a 32 bit address; PPR.IC into the low 18, and
2381     // PPR.PSR into the high 12
2382     if (sim_brk_summ &&
2383         sim_brk_test ((cpu.PPR.IC & 0777777) |
2384                       ((((t_addr) cpu.PPR.PSR) & 037777) << 18),
2385                       SWMASK ('E')))  /* breakpoint? */
2386       return STOP_BKPT; /* stop simulation */
2387 # if !defined(SPEED)
2388     if (sim_deb_break && cpu.cycleCnt >= sim_deb_break)
2389       return STOP_BKPT; /* stop simulation */
2390 # endif /* if !defined(SPEED) */
2391 #endif /* if !defined(THREADZ) && !defined(LOCKLESS) */
2392 
2393     return reason;
2394   }
2395 
2396 #if defined(PANEL68)
2397 static void panel_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2398   {
2399     cpu_state_t * cpup = _cpup;
2400     // INITIALIZE pressed; treat at as a BOOT.
2401     if (cpu.panelInitialize && cpu.DATA_panel_s_trig_sw == 0)
2402       {
2403          // Wait for release
2404          while (cpu.panelInitialize)
2405            ;
2406          if (cpu.DATA_panel_init_sw)
2407            cpu_reset_unit_idx (ASSUME0, true); // INITIALIZE & CLEAR
2408          else
2409            cpu_reset_unit_idx (ASSUME0, false); // INITIALIZE
2410          // XXX Until a boot switch is wired up
2411          do_boot ();
2412       }
2413     // EXECUTE pressed; EXECUTE PB set, EXECUTE FAULT set
2414     if (cpu.DATA_panel_s_trig_sw == 0 &&
2415         cpu.DATA_panel_execute_sw &&  // EXECUTE button
2416         cpu.DATA_panel_scope_sw &&    // 'EXECUTE PB/SCOPE REPEAT' set to PB
2417         cpu.DATA_panel_exec_sw == 0)  // 'EXECUTE SWITCH/EXECUTE FAULT'
2418                                       //  set to FAULT
2419       {
2420         // Wait for release
2421         while (cpu.DATA_panel_execute_sw)
2422           ;
2423 
2424         if (cpu.DATA_panel_exec_sw) // EXECUTE SWITCH
2425           {
2426             cpu_reset_unit_idx (ASSUME0, false);
2427             cpu.cu.IWB = cpu.switches.data_switches;
2428             set_cpu_cycle (cpup, EXEC_cycle);
2429           }
2430          else // EXECUTE FAULT
2431           {
2432             setG7fault (current_running_cpu_idx, FAULT_EXF);
2433           }
2434       }
2435   }
2436 #endif
2437 
2438 #if defined(THREADZ) || defined(LOCKLESS)
2439 bool bce_dis_called = false;
2440 
2441 // The hypervisor CPU for the threadz model
2442 t_stat sim_instr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2443   {
2444     cpu_state_t * cpup = _cpup;
2445     t_stat reason = 0;
2446 
2447 
2448 
2449 
2450 
2451 
2452 
2453 
2454 
2455 
2456 
2457 
2458 
2459 
2460 
2461 
2462 
2463 
2464 
2465 
2466 
2467 
2468 
2469 
2470 
2471 
2472 
2473 
2474 
2475 
2476 
2477 
2478 
2479 
2480 
2481 
2482 
2483 
2484 
2485 
2486 
2487 
2488 
2489 
2490 
2491     if (cpuThreadz[0].run == false)
2492           createCPUThread (0);
2493     do
2494       {
2495         // Process deferred events and breakpoints
2496         reason = simh_hooks (cpup);
2497         if (reason)
2498           {
2499             break;
2500           }
2501 
2502 
2503 
2504 
2505 
2506 
2507 
2508 
2509 
2510 
2511 
2512 
2513 
2514 
2515 
2516 
2517 
2518 
2519 
2520 
2521 
2522 
2523 
2524 
2525 
2526 
2527 
2528         if (bce_dis_called) {
2529           //return STOP_STOP;
2530           reason = STOP_STOP;
2531           break;
2532         }
2533 
2534 # if !defined(PERF_STRIP)
2535 // Loop runs at 1000 Hz
2536 
2537 #  if defined(LOCKLESS)
2538         lock_iom();
2539 #  endif
2540         lock_libuv ();
2541         uv_run (ev_poll_loop, UV_RUN_NOWAIT);
2542         unlock_libuv ();
2543 #  if defined(LOCKLESS)
2544         unlock_iom();
2545 #  endif
2546         PNL (panel_process_event ());
2547 
2548         int con_unit_idx = check_attn_key ();
2549         if (con_unit_idx != -1)
2550           console_attn_idx (con_unit_idx);
2551 # endif
2552 
2553 # if defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
2554         struct timespec next_time;
2555         clock_gettime (CLOCK_REALTIME, & next_time);
2556         next_time.tv_nsec += 1000l * 1000l;
2557         if (next_time.tv_nsec >= 1000l * 1000l *1000l)
2558           {
2559             next_time.tv_nsec -= 1000l * 1000l *1000l;
2560             next_time.tv_sec  += (time_t) 1;
2561           }
2562         struct timespec new_time;
2563         do
2564           {
2565             pthread_mutex_lock (& iom_start_lock);
2566             pthread_cond_timedwait (& iomCond,
2567                                     & iom_start_lock,
2568                                     & next_time);
2569             pthread_mutex_unlock (& iom_start_lock);
2570             lock_iom();
2571             lock_libuv ();
2572 
2573             iomProcess ();
2574 
2575             unlock_libuv ();
2576             unlock_iom ();
2577 
2578             clock_gettime (CLOCK_REALTIME, & new_time);
2579           }
2580         while ((next_time.tv_sec == new_time.tv_sec) ? (next_time.tv_nsec > new_time.tv_nsec) : \
2581                                                        (next_time.tv_sec  > new_time.tv_sec));
2582 # else
2583         sim_usleep (1000); // 1000 us == 1 ms == 1/1000 sec.
2584 # endif
2585       }
2586     while (reason == 0); //-V654
2587 
2588     for (uint cpuNo = 0; cpuNo < N_CPU_UNITS_MAX; cpuNo ++) {
2589       cpuStats (cpuNo);
2590     }
2591 
2592 # if defined(TESTING)
2593     HDBGPrint ();
2594 # endif
2595     return reason;
2596   }
2597 #endif
2598 
2599 #if !defined(THREADZ) && !defined(LOCKLESS)
2600 static uint fast_queue_subsample = 0;
2601 #endif
2602 
2603 //
2604 // Okay, let's treat this as a state machine
2605 //
2606 //  INTERRUPT_cycle
2607 //     clear interrupt, load interrupt pair into instruction buffer
2608 //     set INTERRUPT_EXEC_cycle
2609 //  INTERRUPT_EXEC_cycle
2610 //     execute instruction in instruction buffer
2611 //     if (! transfer) set INTERUPT_EXEC2_cycle
2612 //     else set FETCH_cycle
2613 //  INTERRUPT_EXEC2_cycle
2614 //     execute odd instruction in instruction buffer
2615 //     set INTERUPT_EXEC2_cycle
2616 //
2617 //  FAULT_cycle
2618 //     fetch fault pair into instruction buffer
2619 //     set FAULT_EXEC_cycle
2620 //  FAULT_EXEC_cycle
2621 //     execute instructions in instruction buffer
2622 //     if (! transfer) set FAULT_EXE2_cycle
2623 //     else set FETCH_cycle
2624 //  FAULT_EXEC2_cycle
2625 //     execute odd instruction in instruction buffer
2626 //     set FETCH_cycle
2627 //
2628 //  FETCH_cycle
2629 //     fetch instruction into instruction buffer
2630 //     set EXEC_cycle
2631 //
2632 //  EXEC_cycle
2633 //     execute instruction in instruction buffer
2634 //     if (repeat conditions) keep cycling
2635 //     if (pair) set EXEC2_cycle
2636 //     else set FETCH_cycle
2637 //  EXEC2_cycle
2638 //     execute odd instruction in instruction buffer
2639 //
2640 //  XEC_cycle
2641 //     load instruction into instruction buffer
2642 //     set EXEC_cycle
2643 //
2644 //  XED_cycle
2645 //     load instruction pair into instruction buffer
2646 //     set EXEC_cycle
2647 //
2648 // other extant cycles:
2649 //  ABORT_cycle
2650 
2651 #if defined(THREADZ) || defined(LOCKLESS)
2652 void * cpu_thread_main (void * arg)
     /* [previous][next][first][last][top][bottom][index][help] */
2653   {
2654     int myid = * (int *) arg;
2655     set_cpu_idx ((uint) myid);
2656     unsigned char umyid = (unsigned char)toupper('a' + (int)myid);
2657     char thread_name[SIR_MAXPID] = {0};
2658     char temp_thread_name[SIR_MAXPID] = {0};
2659 
2660     _cpup->thread_id = pthread_self();
2661 
2662     if (realtime_ok) {
2663       set_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2664       check_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2665     } else {
2666 # if !defined(__QNX__)
2667       (void)sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
2668 # endif
2669     }
2670     _sir_snprintf_trunc(thread_name, SIR_MAXPID, "CPU %c", (unsigned int)umyid);
2671     if (!_sir_setthreadname(thread_name) || !_sir_getthreadname(temp_thread_name))
2672       (void)sir_info ("%s thread created (TID " SIR_TIDFORMAT ")",
2673         thread_name, PID_CAST _sir_gettid());
2674     else
2675       (void)sir_info ("Thread created (TID " SIR_TIDFORMAT ")",
2676         PID_CAST _sir_gettid());
2677 # if defined(TESTING) && defined(__APPLE__) && defined(__MACH__)
2678     (void)sir_info ("Mach thread ID: 0x%x", pthread_mach_thread_np(pthread_self()));
2679 # endif /* if defined(TESTING) && defined(__APPLE__) && defined(__MACH__) */
2680     bool warned = false;
2681     if (realtime_ok) {
2682       if (myid + 2 > nprocs) {
2683         (void)sir_warn ("Total number of supervisor and CPU threads (%lu) exceeds available host parallelism (%lu)!",
2684                         (unsigned long)(myid) + 2, (unsigned long)nprocs);
2685         warned = true;
2686       }
2687       if (!warned && nprocs >= 2 && ncores >= 1 && nprocs >= ncores && myid + 2 > ncores) {
2688         (void)sir_warn ("Total number of supervisor and CPU threads (%lu) exceeds physical host core count (%lu)!",
2689                         (unsigned long)(myid) + 2, (unsigned long)ncores);
2690       }
2691     } else {
2692       if (myid + 1 > nprocs) {
2693         (void)sir_warn ("Total number of CPU threads (%lu) exceeds available host parallelism (%lu)!",
2694                         (unsigned long)(myid) + 1, (unsigned long)nprocs);
2695         warned = true;
2696       }
2697       if (!warned && ncores >= 1 && nprocs >= ncores && myid + 1 > ncores) {
2698         (void)sir_warn ("Total number of CPU threads (%lu) exceeds physical host core count (%lu)!",
2699                         (unsigned long)(myid) + 1, (unsigned long)ncores);
2700       }
2701     }
2702     setSignals ();
2703     threadz_sim_instr ();
2704     return NULL;
2705   }
2706 #endif // THREADZ
2707 
2708 NO_RETURN
2709 static void do_LUF_fault (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2710   {
2711     // DPS8/M T&D/ISOLTS: a lockup that ends a loop is taken on the transfer
2712     // that closes it, which is restarted (RFI). PM776 08I (TRA * in master
2713     // mode) expects the fault at the TRA itself, which the PAS executive
2714     // only reports when RFI is on; 08A (SBA/TNZ *-1) gets the TNZ either
2715     // way. (Inferred from the page's expected values, from dps8m4.)
2716     if ((cpu.tweaks.tandd_mode || cpu.tweaks.isolts_mode) &&
2717         ! cpu.tweaks.l68_mode &&
2718         cpu.cycle == PSEUDO_FETCH_cycle && cpu.lufAfterXfer)
2719       {
2720         cpu.PPR.IC = cpu.lufXferIC;
2721         cpu.lufRFI = true;
2722       }
2723     CPT (cpt1U, 16); // LUF
2724     cpu.lufTicks    = 0;
2725     cpu.lufCounter  = 0;
2726     cpu.lufOccurred = false;
2727 // This is a hack to fix ISOLTS 776. ISOLTS checks that the TR has
2728 // decremented by the LUF timeout value. To implement this, we set
2729 // the TR to the expected value.
2730 
2731 // LUF  time
2732 //  0    2ms
2733 //  1    4ms
2734 //  2    8ms
2735 //  3   16ms
2736 // units
2737 // you have: 2ms
2738 // units
2739 // You have: 512000Hz
2740 // You want: 1/2ms
2741 //    * 1024
2742 //    / 0.0009765625
2743 //
2744 //  TR = 1024 << LUF
2745     // Not in T&D mode: there the TR counts with execution and the lockup is
2746     // timed by it (lufTicks), so the TR is already right (PM776, and PM785
2747     // 05A below, which this fudge gets wrong).
2748     if (cpu.tweaks.isolts_mode && ! cpu.tweaks.tandd_mode)
2749       cpu.shadowTR = (word27) cpu.TR0 - (1024u << (is_priv_mode (cpup) ? 4 : cpu.CMR.luf));
2750 
2751 // The logic fails for test 785:
2752 // set slave mode, LUF time 16ms.
2753 // loop for 15.9 ms.
2754 // set master mode.
2755 // loop for 15.9 ms. The LUF should be noticed, and lufOccurred set.
2756 // return to slave mode. The LUF should fire, with the timer register
2757 // being set for 31.1 ms.
2758 
2759 // XXX: Without accurate cycle timing or simply fudging the results,
2760 // I don't see how to fix this one.
2761 
2762     doFault (FAULT_LUF, fst_zero, "instruction cycle lockup");
2763   }
2764 
2765 #if !defined(THREADZ) && !defined(LOCKLESS)
2766 # define threadz_sim_instr sim_instr
2767 #endif
2768 
2769 /*
2770  * addr_modes_e get_addr_mode()
2771  *
2772  * Report what mode the CPU is in.
2773  * This is determined by examining a couple of IR flags.
2774  *
2775  * TODO: get_addr_mode() probably belongs in the CPU source file.
2776  *
2777  */
2778 
2779 static void set_temporary_absolute_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2780   {
2781     CPT (cpt1L, 20); // set temp. abs. mode
2782     cpu.secret_addressing_mode = true;
2783     cpu.cu.XSF = false;
2784 sim_debug (DBG_TRACEEXT, & cpu_dev, "set_temporary_absolute_mode bit 29 sets XSF to 0\r\n");
2785     //cpu.went_appending = false;
2786   }
2787 
2788 static bool clear_temporary_absolute_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2789   {
2790     CPT (cpt1L, 21); // clear temp. abs. mode
2791     cpu.secret_addressing_mode = false;
2792     return cpu.cu.XSF;
2793     //return cpu.went_appending;
2794   }
2795 
2796 #if defined(THREADZ) || defined(LOCKLESS)
2797 static const int workAllocationQuantum = 64;
2798 static const int syncClockModePollRate = 64;
2799 static const int masterCycleCntlimit = 2048;
2800 // A slave hands its work back only through the master, which doles out
2801 // allocations from its own sync poll in the EXEC cycle. A master that stops
2802 // reaching that poll (a fault loop, e.g. an ISOLTS CPU whose memory map
2803 // makes every read fault) would leave the slaves waiting forever, so the
2804 // slaves' waits are bounded. The limits are wall-clock milliseconds, well
2805 // above the master's own wait for its slaves (100000 x sim_usleep (1)).
2806 static const uint32 slaveWaitLimitMs = 10000;   // waiting for an allocation
2807 static const uint32 slaveStartLimitMs = 10;     // waiting for syncClockMode
2808 
2809 void becomeClockMaster (uint cpuNum) {
     /* [previous][next][first][last][top][bottom][index][help] */
2810   //HDBGNote (cpup, __func__, "entry%s.", "");
2811 # ifdef SYNCTEST
2812   sim_printf ("CPU%c %s entry\r\n", cpuNum + 'A', __func__);
2813   allocCount = 0;
2814 # endif
2815 
2816   //lockSync ();  // Only one CPU can manage the sync at a time; if more then one CPU is started
2817   // at once, the second will hang here until the first is finished. If this proves to be
2818   // a problem, then we need a mechanism for the second one to join the sync parade.
2819   if (syncClockMode) {
2820     // Someone else is already clock master; let them rule
2821     //sim_printf ("%s: someone else beat us here.\r\n", __func__);
2822     //HDBGNote (cpup, __func__, "someone else beat us here.%s", "");
2823     return;
2824   }
2825 
2826   syncClockModeMasterIdx = cpuNum;
2827   cpu_state_t * cpup = & cpus[cpuNum];
2828   cpu.syncClockModeMaster = true; // This CPU is the clock master
2829   cpu.masterCycleCnt = 0;
2830   cpu.syncClockModeCache = true;
2831   for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
2832     if (i != cpuNum) { // not the new master
2833       cpus[i].workAllocation = 0;
2834       __asm volatile ("");
2835       atomic_thread_fence (memory_order_seq_cst); //-V779
2836       if (cpus[i].inMultics && ! cpus[i].isSlave) { // it is up but not yet a slave
2837         cpus[i].syncClockModePoll = 0;
2838         __asm volatile ("");
2839         atomic_thread_fence (memory_order_seq_cst);
2840         cpus[i].becomeSlave = true;
2841         __asm volatile ("");
2842         atomic_thread_fence (memory_order_seq_cst);
2843       } // candidate
2844     } // not target CPU
2845   } // every CPU
2846 
2847   __asm volatile ("");
2848   atomic_thread_fence (memory_order_seq_cst);
2849   syncClockMode = true;
2850 
2851   __asm volatile ("");
2852   atomic_thread_fence (memory_order_seq_cst);
2853   //HDBGNote (cpup, __func__, "becomes clock master%s", "");
2854 } // becomeClockMaster
2855 
2856 void giveupClockMaster (cpu_state_t * cpup) {
     /* [previous][next][first][last][top][bottom][index][help] */
2857   //HDBGNote (cpup, __func__, "entry%s", "");
2858 # ifdef SYNCTEST
2859   //HDBGNote (cpup, __func__, "alloc count %d", allocCount);
2860   sim_printf ("CPU%c %s entry\r\n", cpu.cpuIdx + 'A', __func__);
2861   sim_printf ("CPU%c Alloc count %d\r\n", cpu.cpuIdx + 'A', allocCount);
2862 # endif
2863   __asm volatile ("");
2864   cpu.syncClockModeMaster = false; //-V779
2865   __asm volatile ("");
2866   syncClockMode = false; // Free the other processors
2867   __asm volatile ("");
2868   for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
2869     cpus[i].syncClockModeCache = false;
2870   }
2871   __asm volatile ("");
2872   atomic_thread_fence (memory_order_seq_cst);
2873   //unlockSync (); // And let someone else grab sync mode
2874 }
2875 #endif
2876 
2877 t_stat threadz_sim_instr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2878   {
2879     cpu_state_t * cpup = _cpup;
2880   //cpu.have_tst_lock = false;
2881 
2882 #if !defined(SCHED_NEVER_YIELD)
2883     unsigned long long lockYieldAll     = 0;
2884 #endif /* if !defined(SCHED_NEVER_YIELD) */
2885     unsigned long long lockWaitMaxAll   = 0;
2886     unsigned long long lockWaitAll      = 0;
2887     unsigned long long lockImmediateAll = 0;
2888     unsigned long long lockCntAll       = 0;
2889     unsigned long long instrCntAll      = 0;
2890     unsigned long long cycleCntAll      = 0;
2891 
2892     t_stat reason = 0;
2893 
2894 #if !defined(THREADZ) && !defined(LOCKLESS)
2895     set_cpu_idx (0);
2896 # if defined(M_SHARED)
2897 // scp needs to have the IC statically allocated, so a placeholder was
2898 // created.
2899 
2900     // Copy the placeholder so the IC can be set
2901     cpus [0].PPR.IC = dummy_IC;
2902 # endif
2903 
2904 #endif
2905 
2906     // This allows long jumping to the top of the state machine
2907     int val = setjmp (cpu.jmpMain);
2908 
2909     switch (val)
2910       {
2911         case JMP_ENTRY:
2912         case JMP_REENTRY:
2913             reason = 0;
2914             break;
2915         case JMP_SYNC_FAULT_RETURN:
2916             set_cpu_cycle (cpup, SYNC_FAULT_RTN_cycle);
2917             break;
2918         case JMP_STOP:
2919             reason = STOP_STOP;
2920             goto leave;
2921         case JMP_REFETCH:
2922 
2923             // Not necessarily so, but the only times
2924             // this path is taken is after an RCU returning
2925             // from an interrupt, which could only happen if
2926             // was xfer was false; or in a DIS cycle, in
2927             // which case we want it false so interrupts
2928             // can happen.
2929             cpu.wasXfer = false;
2930 
2931             set_cpu_cycle (cpup, FETCH_cycle);
2932             break;
2933         case JMP_RESTART:
2934             set_cpu_cycle (cpup, EXEC_cycle);
2935             break;
2936         case JMP_FORCE_RESTART:
2937           // The configuration has been changed on a CPU that
2938           // has been started and in DIS idle. DIS sees the
2939           // forceRestart flag and longjmps here.
2940           // cpu_reset_unit_idx will update the CPU state to
2941           // match the new configuration and set the
2942           // state to enter DIS.
2943           cpu_reset_unit_idx (current_running_cpu_idx, false);
2944 #if defined(THREADZ) || defined(LOCKLESS)
2945           // Were we a clock master?
2946           if (syncClockMode && syncClockModeMasterIdx == current_running_cpu_idx)
2947             giveupClockMaster (cpup);
2948 #endif
2949           break;
2950         default:
2951           sim_warn ("longjmp value of %d unhandled\r\n", val);
2952             goto leave;
2953       }
2954 
2955     // Main instruction fetch/decode loop
2956 
2957     DCDstruct * ci = & cpu.currentInstruction;
2958 
2959     if (cpu.restart)
2960       {
2961         set_cpu_cycle (cpup, FAULT_cycle);
2962       }
2963 
2964 #if defined(THREADZ) || defined(LOCKLESS)
2965     // These are used to signal createCPUThread that the "round
2966     // up the slaves" code above has run; they must be set
2967     // after that. This line will prevent the compiler from
2968     // hoisting them.
2969     __asm volatile ("");
2970     cpu.executing = true; //-V779
2971     if (cpu.tweaks.isolts_mode) {
2972       ;
2973     } else {
2974       cpu.inMultics = true;
2975     }
2976 #endif
2977 
2978     do
2979       {
2980 
2981         reason = 0;
2982 
2983 #if !defined(THREADZ) && !defined(LOCKLESS)
2984         // Process deferred events and breakpoints
2985         reason = simh_hooks (cpup);
2986         if (reason)
2987           {
2988             break;
2989           }
2990 
2991 // The event poll is consuming 40% of the CPU according to pprof.
2992 // We only want to process at 100Hz; yet we are testing at ~1MHz.
2993 // If we only test every 1000 cycles, we shouldn't miss by more then
2994 // 10%...
2995 
2996         //if ((! cpu.wasInhibited) && fast_queue_subsample ++ > 1024) // ~ 1KHz
2997         //static uint fastQueueSubsample = 0;
2998         if (fast_queue_subsample ++ > sys_opts.sys_poll_check_rate) // ~ 1KHz
2999           {
3000             fast_queue_subsample = 0;
3001 # if defined(CONSOLE_FIX)
3002 #  if defined(THREADZ) || defined(LOCKLESS)
3003             lock_libuv ();
3004 #  endif
3005 # endif
3006             uv_run (ev_poll_loop, UV_RUN_NOWAIT);
3007 # if defined(CONSOLE_FIX)
3008 #  if defined(THREADZ) || defined(LOCKLESS)
3009             unlock_libuv ();
3010 #  endif
3011 # endif
3012             PNL (panel_process_event ());
3013           }
3014 #endif // ! THREADZ
3015 
3016         cpu.cycleCnt ++;
3017 
3018 #if defined(THREADZ)
3019         // If we faulted somewhere with the memory lock set, clear it.
3020         unlock_mem_force ();
3021 
3022         // wait on run/switch
3023         cpuRunningWait ();
3024 #endif // THREADZ
3025 #if defined(LOCKLESS)
3026         core_unlock_all (cpup);
3027 #endif // LOCKLESS
3028 
3029 #if !defined(LOCKLESS)
3030         int con_unit_idx = check_attn_key ();
3031         if (con_unit_idx != -1)
3032           console_attn_idx (con_unit_idx);
3033 #endif
3034 
3035 #if !defined(THREADZ) && !defined(LOCKLESS)
3036         if (cpu.tweaks.isolts_mode)
3037           {
3038             if (cpu.cycle != FETCH_cycle)
3039               {
3040                 // Sync. the TR with the emulator clock.
3041                 cpu.rTRlsb ++;
3042                 if (cpu.rTRlsb >= 4)
3043                   {
3044                     cpu.rTRlsb   = 0;
3045                     cpu.shadowTR = (cpu.shadowTR - 1) & MASK27;
3046                     if (cpu.shadowTR == 0) // passing through 0...
3047                       {
3048                         if (cpu.tweaks.tro_enable)
3049                           setG7fault (current_running_cpu_idx, FAULT_TRO);
3050                       }
3051                   }
3052               }
3053           }
3054 #endif
3055 
3056 // Check for TR underflow. The TR is stored in a uint32_t, but is 27 bits wide.
3057 // The TR update code decrements the TR; if it passes through 0, the high bits
3058 // will be set.
3059 
3060 // If we assume a 1 MIPS reference platform, the TR would be decremented every
3061 // two instructions (1/2 MHz)
3062 
3063         if (cpu.tweaks.tandd_mode)
3064           {
3065             // T&D: the TR counts down with execution, one count per four
3066             // cycles, and the lockup timer and the T&D calendar clock
3067             // count with it (dps8m4 FAUX_TR). PM776/SM784 compare them.
3068             cpu.rTRticks = 0;
3069             if (++ cpu.rTRlsb >= 4)
3070               {
3071                 cpu.rTRlsb = 0;
3072                 cpu.rTR --;
3073                 cpu.lufTicks ++;
3074                 cpu.tanddTRTicks ++;
3075               }
3076           }
3077         else
3078           {
3079 
3080 
3081 
3082 
3083 
3084 # define TR_RATE 2
3085 
3086         //cpu.rTR      -= cpu.rTRticks / TR_RATE;
3087         // ubsan
3088         cpu.rTR = (word27) (((word27s) cpu.rTR) - (word27s) (cpu.rTRticks / TR_RATE));
3089         cpu.rTRticks %= TR_RATE;
3090 
3091 
3092           }
3093 
3094         if (cpu.rTR & ~MASK27)
3095           {
3096             cpu.rTR &= MASK27;
3097             if (cpu.tweaks.tro_enable) {
3098               setG7fault (current_running_cpu_idx, FAULT_TRO);
3099             }
3100           }
3101 
3102         sim_debug (DBG_CYCLE, & cpu_dev, "Cycle is %s\r\n",
3103                    cycle_str (cpu.cycle));
3104 
3105         switch (cpu.cycle)
3106           {
3107             case INTERRUPT_cycle:
3108               {
3109                 CPT (cpt1U, 0); // Interrupt cycle
3110                 // In the INTERRUPT CYCLE, the processor safe-stores
3111                 // the Control Unit Data (see Section 3) into
3112                 // program-invisible holding registers in preparation
3113                 // for a Store Control Unit (scu) instruction, enters
3114                 // temporary absolute mode, and forces the current
3115                 // ring of execution C(PPR.PRR) to
3116                 // 0. It then issues an XEC system controller command
3117                 // to the system controller on the highest priority
3118                 // port for which there is a bit set in the interrupt
3119                 // present register.
3120 
3121                 uint intr_pair_addr = get_highest_intr (cpup);
3122 #if defined(TESTING)
3123                 HDBGIntr (intr_pair_addr, "");
3124 #endif
3125                 cpu.cu.FI_ADDR = (word5) (intr_pair_addr / 2);
3126                 cu_safe_store (cpup);
3127                 // T&D: an interrupt recognized at a fetch: the previous odd
3128                 // instruction, XSF off, RFI and FIF on (PA865 03B)
3129                 if (cpu.tanddFetchIntr)
3130                   {
3131                     cpu.scu_data[7] = cpu.tanddIRODD;
3132                     putbits36_1 (& cpu.scu_data[0], 19, 0);
3133                     putbits36_1 (& cpu.scu_data[5], 27, 1);
3134                     putbits36_1 (& cpu.scu_data[5], 29, 1);
3135                   }
3136                 // XXX the whole interrupt cycle should be rewritten as an xed
3137                 // instruction pushed to IWB and executed
3138 
3139                 CPT (cpt1U, 1); // safe store complete
3140                 // Temporary absolute mode
3141                 set_temporary_absolute_mode (cpup);
3142 
3143                 // Set to ring 0
3144                 cpu.PPR.PRR = 0;
3145                 cpu.TPR.TRR = 0;
3146 
3147                 sim_debug (DBG_INTR, & cpu_dev, "intr_pair_addr %u flag %d\r\n",
3148                            intr_pair_addr, cpu.interrupt_flag);
3149 #if !defined(SPEED)
3150                 if_sim_debug (DBG_INTR, & cpu_dev)
3151                     traceInstruction (DBG_INTR);
3152 #endif /* if !defined(SPEED) */
3153                 // Check that an interrupt is actually pending
3154                 if (cpu.interrupt_flag)
3155                   {
3156                     CPT (cpt1U, 2); // interrupt pending
3157                     // clear interrupt, load interrupt pair into instruction
3158                     // buffer; set INTERRUPT_EXEC_cycle.
3159 
3160                     // In the h/w this is done later, but doing it now allows
3161                     // us to avoid clean up for no interrupt pending.
3162 
3163                     if (intr_pair_addr != 1) // no interrupts
3164                       {
3165                         CPT (cpt1U, 3); // interrupt identified
3166 
3167                         // get interrupt pair
3168                         core_read2 (cpup, intr_pair_addr,
3169                                     & cpu.cu.IWB, & cpu.cu.IRODD, __func__);
3170 #if defined(TESTING)
3171                         HDBGMRead (intr_pair_addr, cpu.cu.IWB, "intr even");
3172                         HDBGMRead (intr_pair_addr + 1, cpu.cu.IRODD, "intr odd");
3173 #endif
3174                         cpu.cu.xde = 1;
3175                         cpu.cu.xdo = 1;
3176                         cpu.isExec = true;
3177                         cpu.isXED  = true;
3178 
3179                         CPT (cpt1U, 4); // interrupt pair fetched
3180                         cpu.interrupt_flag = false;
3181                         cpu.tanddFetchIntr = false;
3182                         set_cpu_cycle (cpup, INTERRUPT_EXEC_cycle);
3183                         break;
3184                       } // int_pair != 1
3185                   } // interrupt_flag
3186 
3187                 // If we get here, there was no interrupt
3188 
3189                 CPT (cpt1U, 5); // interrupt pair spurious
3190                 cpu.interrupt_flag = false;
3191                 clear_temporary_absolute_mode (cpup);
3192                 // Restores addressing mode
3193                 cu_safe_restore (cpup);
3194                 if (cpu.tanddFetchIntr)   // undo the T&D SCU data patch
3195                   {
3196                     cpu.cu.rfi = 0;
3197                     cpu.cu.FIF = 0;
3198                     cpu.tanddFetchIntr = false;
3199                   }
3200                 // We can only get here if wasXfer was
3201                 // false, so we can assume it still is.
3202                 cpu.wasXfer = false;
3203 // The only place cycle is set to INTERRUPT_cycle in FETCH_cycle; therefore
3204 // we can safely assume that is the state that should be restored.
3205                 set_cpu_cycle (cpup, FETCH_cycle);
3206               }
3207               break;
3208 
3209             case FETCH_cycle:
3210 #if defined(PANEL68)
3211                 (void)memset (cpu.cpt, 0, sizeof (cpu.cpt));
3212 #endif
3213                 CPT (cpt1U, 13); // fetch cycle
3214 
3215                 // EXECUTE DATA SWITCHES (press_execute_switches): the
3216                 // switches' instruction runs like a fault pair, in
3217                 // temporary absolute mode, with the CU data safe-stored
3218                 if (UNLIKELY (cpu.execSwitchesReq))
3219                   {
3220                     cpu.execSwitchesReq = false;
3221                     cpu.execSwitches    = true;
3222                     cpu.faultNumber     = FAULT_EXF;
3223                     set_cpu_cycle (cpup, FAULT_cycle);
3224                     break;
3225                   }
3226 
3227                 PNL (L68_ (cpu.INS_FETCH = false;))
3228 
3229 // "If the interrupt inhibit bit is not set in the current instruction
3230 // word at the point of the next sequential instruction pair virtual
3231 // address formation, the processor samples the [group 7 and interrupts]."
3232 
3233 // Since XEx/RPx may overwrite IWB, we must remember
3234 // the inhibit bits (cpu.wasInhibited).
3235 
3236 // If the instruction pair virtual address being formed is the result of a
3237 // transfer of control condition or if the current instruction is
3238 // Execute (xec), Execute Double (xed), Repeat (rpt), Repeat Double (rpd),
3239 // or Repeat Link (rpl), the group 7 faults and interrupt present lines are
3240 // not sampled.
3241 
3242 // Group 7 Faults
3243 //
3244 // Shutdown
3245 //
3246 // An external power shutdown condition has been detected. DC POWER shutdown
3247 // will occur in approximately one millisecond.
3248 //
3249 // Timer Runout
3250 //
3251 // The timer register has decremented to or through the value zero. If the
3252 // processor is in privileged mode or absolute mode, recognition of this fault
3253 // is delayed until a return to normal mode or BAR mode. Counting in the timer
3254 // register continues.
3255 //
3256 // Connect
3257 //
3258 // A connect signal ($CON strobe) has been received from a system controller.
3259 // This event is to be distinguished from a Connect Input/Output Channel (cioc)
3260 // instruction encountered in the program sequence.
3261 
3262                 // check BAR bound and raise store fault if above
3263                 // pft 04d 10070, ISOLTS-776 06ad
3264                 if (get_bar_mode (cpup))
3265                     get_BAR_address (cpup, cpu.PPR.IC);
3266 
3267                 // T&D: fetch the next pair first and use its inhibit bit
3268                 // when deciding whether to sample ("the interrupt inhibit
3269                 // bit ... in the current instruction word at the point of
3270                 // the next sequential instruction pair virtual address
3271                 // formation"); dps8m4 FETCH_REWORK, SM781 07A. Multics and
3272                 // ISOLTS keep sampling before the fetch.
3273                 cpu.tanddFetched = false;
3274                 cpu.g7FetchFault = false;
3275                 word36 tanddIRODD = cpu.cu.IRODD;
3276                 if (cpu.tweaks.tandd_mode)
3277                   {
3278                     cpu.isExec           = false;
3279                     cpu.isXED            = false;
3280                     cpu.cu.XSF           = 0;
3281                     cpu.cu.TSN_VALID [0] = 0;
3282                     cpu.TPR.TSR          = cpu.PPR.PSR;
3283                     cpu.TPR.TRR          = cpu.PPR.PRR;
3284                     PNL (cpu.prepare_state = ps_PIA);
3285                     PNL (L68_ (cpu.INS_FETCH = true;))
3286                     fetchInstruction (cpup, cpu.PPR.IC);
3287                     cpu.tanddFetched = true;
3288                   }
3289 
3290                 // Don't check timer runout if privileged
3291                 // ISOLTS-776 04bcf, 785 02c
3292                 // (but do if in a DIS instruction with bit28 clear)
3293                 bool tmp_priv_mode = is_priv_mode (cpup);
3294                 bool is_dis        = cpu.tanddFetched ?
3295                                      (IWB_IRODD & 0000000777400) == 0000000616000 :
3296                                      (cpu.currentInstruction.opcode  == 0616 &&
3297                                       cpu.currentInstruction.opcodeX == 0);
3298                 bool noCheckTR     = tmp_priv_mode &&
3299                                      !(is_dis && GET_I (cpu.cu.IWB) == 0);
3300 
3301                 if (is_dis)
3302                   {
3303                     // take interrupts and g7 faults as long as
3304                     // last instruction is DIS (??)
3305                     cpu.interrupt_flag = sample_interrupts (cpup);
3306                     cpu.g7_flag =
3307                               noCheckTR ? bG7PendingNoTRO (cpup) : bG7Pending (cpup);
3308                   }
3309                 else if (! (cpu.cu.xde | cpu.cu.xdo |
3310                        cpu.cu.rpt | cpu.cu.rd | cpu.cu.rl))
3311                   {
3312                     if ((!cpu.wasInhibited) &&
3313                         ! (cpu.tanddFetched && GET_I (IWB_IRODD)) &&
3314                         (cpu.PPR.IC & 1) == 0 &&
3315                         (! cpu.wasXfer))
3316                       {
3317                         CPT (cpt1U, 14); // sampling interrupts
3318                         cpu.interrupt_flag = sample_interrupts (cpup);
3319                         cpu.g7_flag =
3320                           noCheckTR ? bG7PendingNoTRO (cpup) : bG7Pending (cpup);
3321                       }
3322                     cpu.wasInhibited = false;
3323                   }
3324                 else
3325                   {
3326                     // XEx at an odd location disables interrupt sampling
3327                     // also for the next instruction pair. ISOLTS-785 02g,
3328                     // 776 04g
3329                     // Set the inhibit flag
3330                     // (I assume RPx behaves in the same way)
3331                     if ((cpu.PPR.IC & 1) == 1)
3332                       {
3333                         cpu.wasInhibited = true;
3334                       }
3335                   }
3336 
3337 // Multics executes a CPU connect instruction (which should eventually cause a
3338 // connect fault) while interrupts are inhibited and an IOM interrupt is
3339 // pending. Multics then executes a DIS instruction (Delay Until Interrupt
3340 // Set). This should cause the processor to "sleep" until an interrupt is
3341 // signaled. The DIS instruction sees that an interrupt is pending, sets
3342 // cpu.interrupt_flag to signal that the CPU to service the interrupt and
3343 // resumes the CPU.
3344 //
3345 // The CPU state machine sets up to fetch the next instruction. If checks to
3346 // see if this instruction should check for interrupts or faults according to
3347 // the complex rules (interrupts inhibited, even address, not RPT or XEC,
3348 // etc.); it this case, the test fails as the next instruction is at an odd
3349 // address. If the test had passed, the cpu.interrupt_flag would be set or
3350 // cleared depending on the pending interrupt state data, AND the cpu.g7_flag
3351 // would be set or cleared depending on the faults pending data (in this case,
3352 // the connect fault).
3353 //
3354 // Because the flags were not updated, after the test, cpu.interrupt_flag is
3355 // set (since the DIS instruction set it) and cpu.g7_flag is not set.
3356 //
3357 // Next, the CPU sees the that cpu.interrupt flag is set, and starts the
3358 // interrupt cycle despite the fact that a higher priority g7 fault is pending.
3359 
3360 // To fix this, check (or recheck) g7 if an interrupt is going to be faulted.
3361 // Either DIS set interrupt_flag and FETCH_cycle didn't so g7 needs to be
3362 // checked, or FETCH_cycle did check it when it set interrupt_flag in which
3363 // case it is being rechecked here. It is [locally] idempotent and light
3364 // weight, so this should be okay.
3365 
3366 // not necessary any more because of is_dis logic
3367 
3368 
3369 
3370 
3371                 if (cpu.g7_flag)
3372                   {
3373                       cpu.g7_flag        = false;
3374                       cpu.interrupt_flag = false;
3375                       // T&D: the fault is recognized as the next pair's
3376                       // address is formed: the SCU data has the new even
3377                       // instruction, the previous odd one, XSF off and
3378                       // RFI on (refetch) (PA865 03A)
3379                       if (cpu.tanddFetched)
3380                         {
3381                           cpu.cu.IRODD = tanddIRODD;
3382                           cpu.cu.XSF   = 0;
3383                           cpu.lufRFI   = true;
3384                           cpu.tanddFetchFault = true;
3385                         }
3386                       // The fault comes between instructions: a fault
3387                       // pair that does not transfer resumes at the IC, the
3388                       // instruction not yet executed (PS702 03A, CU-HR
3389                       // overflow trap to an STC1/STC1 pair); not for DIS
3390                       cpu.g7FetchFault = ! is_dis;
3391                       sim_debug (DBG_CYCLE, & cpu_dev,
3392                                  "call doG7Fault (%d)\r\n", !noCheckTR);
3393                       doG7Fault (cpup, !noCheckTR);
3394                   }
3395                 if (cpu.interrupt_flag)
3396                   {
3397 // This is the only place cycle is set to INTERRUPT_cycle; therefore
3398 // return from interrupt can safely assume the it should set the cycle
3399 // to FETCH_cycle.
3400                     CPT (cpt1U, 15); // interrupt
3401                     // T&D: as for a g7 fault above (PA865 03B)
3402                     cpu.tanddFetchIntr = cpu.tanddFetched;
3403                     cpu.tanddIRODD     = tanddIRODD;
3404                     set_cpu_cycle (cpup, INTERRUPT_cycle);
3405                     break;
3406                   }
3407 
3408 // "While in absolute mode or privileged mode the lockup fault is signalled at
3409 // the end of the time limit set in the lockup timer but is not recognized
3410 // until the 32 millisecond limit. If the processor returns to normal mode or
3411 // BAR mode after the fault has been signalled but before the 32 millisecond
3412 // limit, the fault is recognized before any instruction in the new mode is
3413 // executed."
3414 
3415           /*FALLTHRU*/ /* fall through */ /* fallthrough */
3416           case PSEUDO_FETCH_cycle:
3417 
3418             tmp_priv_mode = is_priv_mode (cpup);
3419             if (! (luf_flag && tmp_priv_mode))
3420               cpu.lufCounter ++;
3421 
3422             if (LUF_OVER (cpu.CMR.luf))
3423               {
3424                 if (tmp_priv_mode)
3425                   {
3426                     // In priv. mode the LUF is noted but not executed
3427                     cpu.lufOccurred = true;
3428                   }
3429                 else
3430                   {
3431                     do_LUF_fault (cpup);
3432                   }
3433               } // lufCounter > luf_limit
3434 
3435             // After 32ms, the LUF fires regardless of priv.
3436             if (LUF_OVER (4))
3437               {
3438                 do_LUF_fault (cpup);
3439               }
3440 
3441             // If the LUF occurred in priv. mode and we left priv. mode,
3442             // fault.
3443             if (! tmp_priv_mode && cpu.lufOccurred)
3444               {
3445                 do_LUF_fault (cpup);
3446               }
3447 
3448 
3449 
3450 
3451 
3452 
3453 
3454 
3455 
3456 
3457 
3458 
3459 
3460 
3461 
3462 
3463 
3464 
3465 
3466 
3467 
3468 
3469 
3470 
3471 
3472 
3473 
3474 
3475 
3476 
3477 
3478 
3479             if (cpu.cycle == PSEUDO_FETCH_cycle)
3480               {
3481                 cpu.apu.lastCycle    = INSTRUCTION_FETCH;
3482                 cpu.cu.XSF           = 0;
3483                 cpu.cu.TSN_VALID [0] = 0;
3484                 cpu.TPR.TSR          = cpu.PPR.PSR;
3485                 cpu.TPR.TRR          = cpu.PPR.PRR;
3486                 cpu.wasInhibited     = false;
3487               }
3488             else if (cpu.tanddFetched)
3489               {
3490                 cpu.tanddFetched = false;   // fetched at the start (T&D)
3491               }
3492             else
3493               {
3494                 CPT (cpt1U, 20); // not XEC or RPx
3495                 cpu.isExec               = false;
3496                 cpu.isXED                = false;
3497                 // fetch next instruction into current instruction struct
3498                 //clr_went_appending (); // XXX not sure this is the right
3499                                          //  place
3500                 cpu.cu.XSF               = 0;
3501 sim_debug (DBG_TRACEEXT, & cpu_dev, "fetchCycle bit 29 sets XSF to 0\r\n");
3502                 cpu.cu.TSN_VALID [0]     = 0;
3503                 cpu.TPR.TSR              = cpu.PPR.PSR;
3504                 cpu.TPR.TRR              = cpu.PPR.PRR;
3505                 PNL (cpu.prepare_state   = ps_PIA);
3506                 PNL (L68_ (cpu.INS_FETCH = true;))
3507                 fetchInstruction (cpup, cpu.PPR.IC);
3508               }
3509 
3510             CPT (cpt1U, 21); // go to exec cycle
3511             advanceG7Faults (cpup);
3512             set_cpu_cycle (cpup, EXEC_cycle);
3513             break;
3514 
3515           case EXEC_cycle:
3516           case FAULT_EXEC_cycle:
3517           case INTERRUPT_EXEC_cycle:
3518             {
3519 #if defined(THREADZ) || defined(LOCKLESS)
3520 
3521               // Have we been told to becomes a slave?
3522               if (UNLIKELY (cpu.becomeSlave)) {
3523                 cpu.becomeSlave = false;
3524                 // Wait for the master to wake up. becomeClockMaster sets
3525                 // syncClockMode just after becomeSlave, so this is a short
3526                 // wait; but the master may already have given up (DIS, cycle
3527                 // limit) before this CPU got here, and then syncClockMode
3528                 // stays false: don't wait for it forever.
3529                 uint32 startMs = sim_os_msec ();
3530                 while (! syncClockMode &&
3531                        sim_os_msec () - startMs < slaveStartLimitMs) {
3532                   sim_usleep (1);
3533                 }
3534                 // Force the poll below
3535                 cpu.syncClockModePoll = 0;
3536               }
3537 
3538               // Ready to check sync clock mode?
3539               if (cpu.syncClockModeCache || --cpu.syncClockModePoll <= 0) {
3540 
3541                 cpu.syncClockModePoll = cpu.tweaks.isolts_mode ? 1 : syncClockModePollRate;
3542 
3543                 // Are the clocks synchronized?
3544                 if (syncClockMode) {
3545 
3546                   // Remember that this thread is synchronized
3547                   cpu.syncClockModeCache = true;
3548 
3549                   // Are we the master?
3550                   if (syncClockModeMasterIdx == current_running_cpu_idx) {
3551 
3552                     // Master
3553                     cpu.masterCycleCnt ++;
3554                     if (cpu.masterCycleCnt > masterCycleCntlimit) {
3555 # ifdef SYNCTEST
3556                       sim_printf ("too many cycles\r\n");
3557 # endif
3558                       giveupClockMaster (cpup);
3559                       goto bail;
3560                     }
3561 
3562                     // Have we used up our allocation?
3563                     if (cpu.workAllocation <= 0) {
3564 # ifdef SYNCTEST
3565                       allocCount ++;
3566 # endif
3567 
3568                       // If sim_usleep(1) actually takes only 1 us, then this
3569                       // will be at least 2 seconds.
3570                       //int64_t waitTimeout = 2000000;
3571                       // Quick testing shows it is closer to 2 minutes...
3572                       int64_t waitTimeout = 100000;
3573 
3574                       // Has everyone used up their allocation?
3575                       while (1) {  // while others still have work to do
3576                         bool alldone = true;
3577                         for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
3578                           if (cpus[i].inMultics && cpus[i].workAllocation > 0) {
3579                             wakeCPU (i);
3580                             alldone = false;
3581                             //break;
3582                           } // up and working
3583                         } // cpus
3584                         if (alldone) {
3585                           // Everyone has used up there allocations; dole out some more work
3586                           for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
3587                             if (cpus[i].inMultics) {
3588                               cpus[i].workAllocation += cpu.tweaks.isolts_mode ? 1 : workAllocationQuantum;
3589                               wakeCPU (i);
3590                             }
3591                           }
3592                           break; // while (1)
3593                         } // alldone
3594                         if (waitTimeout-- < 0) {
3595                           // timed out waiting for everyone to finish their
3596                           // work allocation; assume something is fouled.
3597                           sim_printf ("Clock master CPU %c timed out\r\n", "ABCDEFGH"[current_running_cpu_idx]);
3598                           for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
3599                             if (cpus[i].inMultics && cpus[i].workAllocation > 0) {
3600                               sim_printf ("CPU %c remaining allocation: %ld\r\n", "ABCDEFGH"[i], cpus[i].workAllocation);
3601                             }
3602                           }
3603                           sim_printf ("Conceding clock mastery...\r\n");
3604                           cpu.syncClockModeCache = false;
3605                           giveupClockMaster (cpup);
3606                           goto bail;
3607                         }
3608                         sim_usleep (1);
3609                       } // while (1) -- while others still have work to do
3610                     } // have we used up our allocation
3611                     // We are master and have work allocated; fall through
3612                     // and do some work
3613 
3614                   } else { // Master/slave?
3615 
3616                     // We are not the master; must be a slave
3617 
3618                     // Have we just become a slave?
3619                     if (! cpu.isSlave) {
3620                       //HDBGNote (NULL, __func__, "CPU%c Becoming slave", cpu.cpuIdx + 'A');
3621 # ifdef SYNCTEST
3622                      sim_printf ("CPU%c becoming slave\r\n", cpu.cpuIdx + 'A');
3623 # endif
3624                     }
3625                     cpu.isSlave = true;
3626 
3627                     // Wait for allocation, but not forever (see slaveWaitLimitMs)
3628                     uint32 waitStartMs = sim_os_msec ();
3629                     while (syncClockMode && cpu.workAllocation <= 0) {
3630                       if (sim_os_msec () - waitStartMs >= slaveWaitLimitMs) {
3631                         uint masterIdx = syncClockModeMasterIdx;
3632                         sim_printf ("Clock slave CPU %c: no work allocation from clock master CPU %c "
3633                                     "for %u s; ending clock sync\r\n",
3634                                     "ABCDEFGH"[current_running_cpu_idx], "ABCDEFGH"[masterIdx],
3635                                     (unsigned) (slaveWaitLimitMs / 1000));
3636                         if (syncClockMode && masterIdx < N_CPU_UNITS_MAX)
3637                           giveupClockMaster (& cpus[masterIdx]);
3638                         break;
3639                       }
3640                       sim_usleep (1);
3641                     }
3642 
3643                     // We are slave and have work allocated; fall through
3644                     // and do some work
3645 
3646                   } // master/slave
3647 
3648                 } else { // ! syncClockMode
3649                   // Forget that this thread is synchronized
3650                   cpu.syncClockModeCache = false;
3651                   if (cpu.isSlave) {
3652                     //HDBGNote (cpup, __func__, "Free; free at last%s", "");
3653 # ifdef SYNCTEST
3654                     sim_printf ("CPU%c free; free at last\r\n", cpu.cpuIdx + 'A');
3655 # endif
3656                     cpu.isSlave = false;
3657                   }
3658                 } // ! syncClockMode
3659               } // polling
3660           bail:
3661 
3662 #endif
3663 
3664 #if defined(THREADZ) || defined(LOCKLESS)
3665               if (LIKELY (! cpu.tweaks.isolts_mode) &&
3666                   UNLIKELY (! cpu.inMultics)) {
3667                 cpu.inMultics = true;
3668               }
3669 #endif /* defined(THREADZ) || defined(LOCKLESS) */
3670 
3671               CPT (cpt1U, 22); // exec cycle
3672 
3673 #if defined(LOCKLESS)
3674                 if (stall_point_active)
3675                   {
3676                     for (int i = 0; i < N_STALL_POINTS; i ++)
3677                       if (stall_points[i].segno  && stall_points[i].segno  == cpu.PPR.PSR &&
3678                           stall_points[i].offset && stall_points[i].offset == cpu.PPR.IC)
3679                         {
3680 # if defined(CTRACE)
3681                           (void)fprintf (stderr, "%10lu %s stall %d\r\n", seqno (), cpunstr[current_running_cpu_idx], i);
3682 # endif
3683                           //sim_printf ("stall %2d %05o:%06o\r\n", i, stall_points[i].segno, stall_points[i].offset);
3684                           sim_usleep(stall_points[i].time);
3685                           break;
3686                         }
3687                   }
3688 #endif
3689 
3690               // The only time we are going to execute out of IRODD is
3691               // during RPD, at which time interrupts are automatically
3692               // inhibited; so the following can ignore RPD harmlessly
3693               if (GET_I (cpu.cu.IWB))
3694                 cpu.wasInhibited = true;
3695 
3696               cpu.lufExecIC    = cpu.PPR.IC;
3697               cpu.lufAfterXfer = false;
3698               t_stat ret = executeInstruction (cpup);
3699               DO_WORK_EXEC;
3700               CPT (cpt1U, 23); // execution complete
3701               cpu.lastTag = ci->tag;
3702               cpu.rptXnSaved = false;
3703 
3704               if (cpu.tweaks.l68_mode)
3705                 {
3706                   add_l68_CU_history (cpup);
3707                   if (cpu.adr_trap_lock)
3708                     {
3709                       cpu.adr_trap_lock = false;
3710                       if (cpu.MR.ihrrs)
3711                         cpu.MR.ihr = 0;
3712                     }
3713                 }
3714               else
3715                 add_dps8m_CU_history (cpup);
3716 
3717               if (ret > 0)
3718                 {
3719                    reason = ret;
3720                    break;
3721                 }
3722 
3723               if (ret == CONT_XEC)
3724                 {
3725                   CPT (cpt1U, 27); // XEx instruction
3726                   cpu.wasXfer = false;
3727                   cpu.isExec  = true;
3728                   if (cpu.cu.xdo)
3729                     cpu.isXED = true;
3730 
3731                   cpu.cu.XSF           = 0;
3732                   cpu.cu.TSN_VALID [0] = 0;
3733                   cpu.TPR.TSR          = cpu.PPR.PSR;
3734                   cpu.TPR.TRR          = cpu.PPR.PRR;
3735                   break;
3736                 }
3737 
3738               if (ret == CONT_TRA || ret == CONT_RET)
3739                 {
3740                   CPT (cpt1U, 24); // transfer instruction
3741                   cpu.cu.xde  = cpu.cu.xdo = 0;
3742                   cpu.isExec  = false;
3743                   cpu.isXED   = false;
3744                   // even for CONT_RET else isolts 886 fails
3745                   cpu.wasXfer = true;
3746 
3747                   if (cpu.cycle != EXEC_cycle) // fault or interrupt
3748                     {
3749                       clearFaultCycle (cpup);
3750 
3751 // BAR mode:  [NBAR] is set ON (taking the processor
3752 // out of BAR mode) by the execution of any transfer instruction
3753 // other than tss during a fault or interrupt trap.
3754 
3755                       if (! (cpu.currentInstruction.opcode == 0715 &&
3756                          cpu.currentInstruction.opcodeX == 0))
3757                         {
3758                           CPT (cpt1U, 9); // nbar set
3759                           SET_I_NBAR;
3760                         }
3761 
3762                       if (!clear_temporary_absolute_mode (cpup))
3763                         {
3764                           // didn't go appending
3765                           sim_debug (DBG_TRACEEXT, & cpu_dev,
3766                                      "setting ABS mode\r\n");
3767                           CPT (cpt1U, 10); // temporary absolute mode
3768                           set_addr_mode (cpup, ABSOLUTE_mode);
3769                         }
3770                       else
3771                         {
3772                           // went appending
3773                           sim_debug (DBG_TRACEEXT, & cpu_dev,
3774                                      "not setting ABS mode\r\n");
3775                         }
3776 
3777                     } // fault or interrupt
3778 
3779                   //if (TST_I_ABS && get_went_appending ())
3780                   if (TST_I_ABS && cpu.cu.XSF)
3781                     {
3782                       set_addr_mode (cpup, APPEND_mode);
3783                     }
3784 
3785                   if (ret == CONT_TRA)
3786                     {
3787                       // PSEUDO_FETCH_cycle does not check interrupts/g7faults
3788                       cpu.wasXfer = false;
3789                       cpu.lufXferIC    = cpu.lufExecIC;
3790                       cpu.lufAfterXfer = true;
3791                       set_cpu_cycle (cpup, PSEUDO_FETCH_cycle);
3792                     }
3793                   else
3794                     set_cpu_cycle (cpup, FETCH_cycle);
3795                   break;   // Don't bump PPR.IC, instruction already did it
3796                 }
3797 
3798               if (ret == CONT_DIS)
3799                 {
3800                   CPT (cpt1U, 25); // DIS instruction
3801 
3802 #if defined(THREADZ) || defined(LOCKLESS)
3803                   // If we do a DIS is clock sync, skip the sleep
3804                   if (cpu.syncClockModeCache) {
3805                     break;
3806                 }
3807 #endif
3808 
3809 // If we get here, we have encountered a DIS instruction in EXEC_cycle.
3810 //
3811 // We need to idle the CPU until one of the following conditions:
3812 //
3813 //  An external interrupt occurs.
3814 //  The Timer Register underflows.
3815 //  The emulator polled devices need polling.
3816 //
3817 // The external interrupt will only be posted to the CPU engine if the
3818 // device poll posts an interrupt. This means that we do not need to
3819 // detect the interrupts here; if we wake up and poll the devices, the
3820 // interrupt will be detected by the DIS instruction when it is re-executed.
3821 //
3822 // The Timer Register is a fast, high-precision timer but Multics uses it
3823 // in only two ways: detecting I/O lockup during early boot, and process
3824 // quantum scheduling (1/4 second for Multics).
3825 //
3826 // Neither of these require high resolution or high accuracy.
3827 //
3828 // The goal of the polling code is sample at about 100Hz; updating the timer
3829 // register at that rate should suffice.
3830 //
3831 //    sleep for 1/100 of a second
3832 //    update the polling state to trigger a poll
3833 //    update the timer register by 1/100 of a second
3834 //    force the scp queues to process
3835 //    continue processing
3836 //
3837 
3838 // The sim_usleep logic is not smart enough w.r.t. ISOLTS.
3839 // The sleep should only happen if all running processors are in DIS mode.
3840                   // 1/100 is .01 secs.
3841                   // *1000 is 10  milliseconds
3842                   // *1000 is 10000 microseconds
3843                   // in uSec;
3844 #if defined(THREADZ) || defined(LOCKLESS)
3845 
3846 // XXX If interrupt inhibit set, then sleep forever instead of TRO
3847                   // rTR is 512KHz; sleepCPU is in 1Mhz
3848                   //   rTR * 1,000,000 / 512,000
3849                   //   rTR * 1000 / 512
3850                   //   rTR * 500 / 256
3851                   //   rTR * 250 / 128
3852                   //   rTR * 125 / 64
3853 
3854 # if defined(NO_TIMEWAIT)
3855                   //sim_usleep (sys_opts.sys_poll_interval * 1000 /*10000*/ );
3856                   struct timespec req, rem;
3857                   uint ms        = sys_opts.sys_poll_interval;
3858                   long int nsec  = (long int) ms * 1000L * 1000L;
3859                   req.tv_nsec    = nsec;
3860                   req.tv_sec    += req.tv_nsec / 1000000000L;
3861                   req.tv_nsec   %= 1000000000L;
3862                   int rc         = nanosleep (& req, & rem); // XXX Does this work on Windows ???
3863                   // Awakened early?
3864                   if (rc == -1)
3865                     {
3866                        ms = (uint) (rem.tv_nsec / 1000 + req.tv_sec * 1000);
3867                     }
3868                   word27 ticks = ms * 512;
3869                   if (cpu.rTR <= ticks)
3870                     {
3871                       if (cpu.tweaks.tro_enable) {
3872                         setG7fault (current_running_cpu_idx, FAULT_TRO);
3873                       }
3874                       cpu.rTR = (cpu.rTR - ticks) & MASK27;
3875                     }
3876                   else
3877                     cpu.rTR = (cpu.rTR - ticks) & MASK27;
3878 
3879                   if (cpu.rTR == 0)
3880                     cpu.rTR = MASK27;
3881 # else // !NO_TIMEWAIT
3882                   // unsigned long left = cpu.rTR * 125u / 64u;
3883                   // ubsan
3884                   unsigned long left = (unsigned long) ((uint64) (cpu.rTR) * 125u / 64u);
3885 
3886 
3887 
3888 
3889 
3890 
3891 
3892 
3893                   unsigned long nowLeft = left;
3894                   if (!sample_interrupts (cpup))
3895                     {
3896                       nowLeft = sleepCPU (left);
3897                     }
3898                   if (nowLeft)
3899                     {
3900                       // sleepCPU uses a clock that is not guaranteed to be monotonic, and occasionally returns nowLeft > left.
3901                       // Don't run rTR backwards if that happens
3902                       if (nowLeft <= left) {
3903                         cpu.rTR = (word27) (left * 64 / 125);
3904                       }
3905                     }
3906                   else
3907                     {
3908                       // We slept until timer runout
3909                       if (cpu.tweaks.tro_enable)
3910                         {
3911                           lock_scu ();
3912                           setG7fault (current_running_cpu_idx, FAULT_TRO);
3913                           unlock_scu ();
3914                         }
3915                       cpu.rTR = MASK27;
3916                     }
3917 # endif // !NO_TIMEWAIT
3918                   cpu.rTRticks = 0;
3919                   break;
3920 #else // ! (THREADZ || LOCKLESS)
3921                   //sim_sleep (10000);
3922                   sim_usleep (sys_opts.sys_poll_interval * 1000/*10000*/);
3923                   // Trigger I/O polling
3924 # if defined(CONSOLE_FIX)
3925 #  if defined(THREADZ) || defined(LOCKLESS)
3926                   lock_libuv ();
3927 #  endif
3928 # endif
3929                   uv_run (ev_poll_loop, UV_RUN_NOWAIT);
3930 # if defined(CONSOLE_FIX)
3931 #  if defined(THREADZ) || defined(LOCKLESS)
3932                   unlock_libuv ();
3933 #  endif
3934 # endif
3935                   fast_queue_subsample = 0;
3936 
3937                   sim_interval = 0;
3938                   // Timer register runs at 512 KHz
3939                   // 512000 is 1 second
3940                   // 512000/100 -> 5120  is .01 second
3941 
3942                   cpu.rTRticks = 0;
3943                   // Would we have underflowed while sleeping?
3944                   //if ((cpu.rTR & ~ MASK27) || cpu.rTR <= 5120)
3945                   //if (cpu.rTR <= 5120)
3946 
3947                   // Timer register runs at 512 KHz
3948                   // 512Khz / 512 is millisecods
3949                   if (cpu.rTR <= sys_opts.sys_poll_interval * 512)
3950                     {
3951                       if (cpu.tweaks.tro_enable) {
3952                         setG7fault (current_running_cpu_idx, FAULT_TRO);
3953                       }
3954                       cpu.rTR = (cpu.rTR - sys_opts.sys_poll_interval * 512) & MASK27;
3955                     }
3956                   else
3957                     cpu.rTR = (cpu.rTR - sys_opts.sys_poll_interval * 512) & MASK27;
3958                   if (cpu.rTR == 0)
3959                     cpu.rTR = MASK27;
3960 #endif // ! (THREADZ || LOCKLESS)
3961                   /*NOTREACHED*/ /* unreachable */
3962                   break;
3963                 }
3964 
3965               cpu.wasXfer = false;
3966 
3967               if (ret < 0)
3968                 {
3969                   sim_warn ("executeInstruction returned %d?\r\n", ret);
3970                   break;
3971                 }
3972 
3973               if ((! cpu.cu.repeat_first) &&
3974                   (cpu.cu.rpt ||
3975                    (cpu.cu.rd && (cpu.PPR.IC & 1)) ||
3976                    cpu.cu.rl))
3977                 {
3978                   CPT (cpt1U, 26); // RPx instruction
3979                   if (cpu.cu.rd)
3980                     -- cpu.PPR.IC;
3981                   cpu.wasXfer = false;
3982                   set_cpu_cycle (cpup, FETCH_cycle);
3983                   break;
3984                 }
3985 
3986               // If we just did the odd word of a fault pair
3987               if (cpu.cycle == FAULT_EXEC_cycle &&
3988                   !cpu.cu.xde && cpu.cu.xdo)
3989                 {
3990                   clear_temporary_absolute_mode (cpup);
3991                   cu_safe_restore (cpup);
3992                   CPT (cpt1U, 12); // cu restored
3993                   clearFaultCycle (cpup);
3994                   // cu_safe_restore calls decode_instruction ()
3995                   // we can determine the instruction length.
3996                   // decode_instruction() restores ci->info->ndes
3997                   cpu.wasXfer  = false;
3998                   cpu.isExec   = false;
3999                   cpu.isXED    = false;
4000 
4001                   if (cpu.g7FetchFault)
4002                     cpu.g7FetchFault = false;
4003                   else
4004                     {
4005                       cpu.PPR.IC  += ci->info->ndes;
4006                       cpu.PPR.IC ++;
4007                     }
4008 
4009                   set_cpu_cycle (cpup, FETCH_cycle);
4010                   break;
4011                 }
4012 
4013               // If we just did the odd word of a interrupt pair
4014               if (cpu.cycle == INTERRUPT_EXEC_cycle &&
4015                   !cpu.cu.xde && cpu.cu.xdo)
4016                 {
4017                   clear_temporary_absolute_mode (cpup);
4018                   cu_safe_restore (cpup);
4019                   // cpu.cu.xdo = 0;
4020 // The only place cycle is set to INTERRUPT_cycle in FETCH_cycle; therefore
4021 // we can safely assume that is the state that should be restored.
4022                   CPT (cpt1U, 12); // cu restored
4023                   cpu.wasXfer = false;
4024                   cpu.isExec  = false;
4025                   cpu.isXED   = false;
4026 
4027                   set_cpu_cycle (cpup, FETCH_cycle);
4028                   break;
4029                 }
4030 
4031               // Even word of fault or interrupt pair or xed
4032               if (cpu.cu.xde && cpu.cu.xdo)
4033                 {
4034                   // Get the odd
4035                   cpu.cu.IWB           = cpu.cu.IRODD;
4036                   cpu.cu.xde           = 0;
4037                   cpu.isExec           = true;
4038                   cpu.isXED            = true;
4039                   cpu.cu.XSF           = 0;
4040                   cpu.cu.TSN_VALID [0] = 0;
4041                   cpu.TPR.TSR          = cpu.PPR.PSR;
4042                   cpu.TPR.TRR          = cpu.PPR.PRR;
4043                   break; // go do the odd word
4044                 }
4045 
4046               if (cpu.cu.xde || cpu.cu.xdo)  // we are in an XEC/XED
4047                 {
4048                   cpu.cu.xde        = cpu.cu.xdo = 0;
4049                   cpu.isExec        = false;
4050                   cpu.isXED         = false;
4051                   CPT (cpt1U, 27);           // XEx instruction
4052                   cpu.wasXfer       = false;
4053                   cpu.PPR.IC ++;
4054                   if (ci->info->ndes > 0)
4055                     cpu.PPR.IC     += ci->info->ndes;
4056                   cpu.wasInhibited  = true;
4057                   set_cpu_cycle (cpup, FETCH_cycle);
4058                   break;
4059                 }
4060 
4061               //ASSURE (cpu.cycle == EXEC_cycle);
4062               if (cpu.cycle != EXEC_cycle)
4063                 sim_warn ("expected EXEC_cycle (%d)\r\n", cpu.cycle);
4064 
4065               cpu.cu.xde = cpu.cu.xdo = 0;
4066               cpu.isExec = false;
4067               cpu.isXED  = false;
4068 
4069               // use prefetched instruction from cpu.cu.IRODD
4070               // we must have finished an instruction at an even location
4071               // skip multiword EIS instructions
4072               // skip repeat instructions for now
4073               // skip dis - we may need to take interrupts/g7faults
4074               // skip if (last instruction) wrote to current instruction range
4075               //  the hardware really does this and isolts tests it
4076               //  Multics Differences Manual DPS8 70/M
4077               //  should take segment number into account?
4078               if ((cpu.PPR.IC & 1) == 0 &&
4079                   ci->info->ndes == 0 &&
4080                   !cpu.cu.repeat_first && !cpu.cu.rpt && !cpu.cu.rd && !cpu.cu.rl &&
4081                   !(cpu.currentInstruction.opcode == 0616 && cpu.currentInstruction.opcodeX == 0) &&
4082                   (cpu.PPR.IC & ~3u) != (cpu.last_write  & ~3u))
4083                 {
4084                   cpu.PPR.IC ++;
4085                   cpu.wasXfer = false;
4086                   cpu.cu.IWB  = cpu.cu.IRODD;
4087                   set_cpu_cycle (cpup, PSEUDO_FETCH_cycle);
4088                   break;
4089                 }
4090 
4091               cpu.PPR.IC ++;
4092               if (ci->info->ndes > 0)
4093                 cpu.PPR.IC += ci->info->ndes;
4094 
4095               CPT (cpt1U, 28); // enter fetch cycle
4096               cpu.wasXfer = false;
4097               set_cpu_cycle (cpup, FETCH_cycle);
4098             }
4099             break;
4100 
4101           case SYNC_FAULT_RTN_cycle:
4102             {
4103               CPT (cpt1U, 29); // sync. fault return
4104               // cu_safe_restore should have restored CU.IWB, so
4105               // we can determine the instruction length.
4106               // decode_instruction() restores ci->info->ndes
4107 
4108               cpu.PPR.IC += ci->info->ndes;
4109               cpu.PPR.IC ++;
4110               cpu.wasXfer = false;
4111               set_cpu_cycle (cpup, FETCH_cycle);
4112             }
4113             break;
4114 
4115           case FAULT_cycle:
4116             {
4117               CPT (cpt1U, 30); // fault cycle
4118               // In the FAULT CYCLE, the processor safe-stores the Control
4119               // Unit Data (see Section 3) into program-invisible holding
4120               // registers in preparation for a Store Control Unit ( scu)
4121               // instruction, then enters temporary absolute mode, forces the
4122               // current ring of execution C(PPR.PRR) to 0, and generates a
4123               // computed address for the fault trap pair by concatenating
4124               // the setting of the FAULT BASE switches on the processor
4125               // configuration panel with twice the fault number (see Table
4126               // 7-1).  This computed address and the operation code for the
4127               // Execute Double (xed) instruction are forced into the
4128               // instruction register and executed as an instruction. Note
4129               // that the execution of the instruction is not done in a
4130               // normal EXECUTE CYCLE but in the FAULT CYCLE with the
4131               // processor in temporary absolute mode.
4132 
4133               // F(A)NP should never be stored when faulting.
4134               // ISOLTS-865 01a,870 02d
4135               // Unconditional reset of APU status to FABS breaks boot.
4136               // Checking for F(A)NP here is equivalent to checking that the
4137               // last append cycle has made it as far as H/I without a fault.
4138               // Also reset it on TRB fault. ISOLTS-870 05a
4139               // T&D: not for a group 7 fault recognized at a fetch, which
4140               // keeps the fetch's FANP/FAP (PA865 03A)
4141               // Nor for a store fault, which comes from the final memory
4142               // access itself: the status stays FAP/FANP (PA885 10B)
4143               // L68: the fault keeps the APU status of the last appending
4144               // cycle, e.g. PI-AP and FAP of the instruction fetch (PA865
4145               // 01A, PA885 01A-10A expect it in SCU word 0)
4146               if (((cpu.cu.APUCycleBits & 060) || cpu.secret_addressing_mode) &&
4147                   ! cpu.tanddFetchFault && cpu.faultNumber != FAULT_STR &&
4148                   ! cpu.tweaks.l68_mode)
4149                   set_apu_status (cpup, apuStatus_FABS);
4150               cpu.tanddFetchFault = false;
4151 
4152               // XXX the whole fault cycle should be rewritten as an xed
4153               // instruction pushed to IWB and executed
4154 
4155               // AL39: TRB fault doesn't safestore CUD - the original fault
4156               // CUD should be stored
4157 
4158               // ISOLTS-870 05a: CUD[5] and IWB are safe stored, possibly
4159               //  due to CU overlap
4160 
4161               // keep IRODD untouched if TRB occurred in an even location
4162               if (cpu.faultNumber != FAULT_TRB || cpu.cu.xde == 0)
4163                 {
4164                   cu_safe_store (cpup);
4165                 }
4166               else
4167                 {
4168                   word36 tmpIRODD = cpu.scu_data[7];
4169                   cu_safe_store (cpup);
4170                   cpu.scu_data[7] = tmpIRODD;
4171                 }
4172               if (cpu.scuRFI)   // see doFault
4173                 putbits36_1 (& cpu.scu_data[5], 27, 1);
4174               cpu.scuRFI = false;
4175               // see doFault; only when the next pair is in the same page
4176               if (cpu.l68OddFault && (cpu.l68PairAddr & 01777) <= 01775)
4177                 core_read (cpup, cpu.l68PairAddr + 3, & cpu.scu_data[7], __func__);
4178               cpu.l68OddFault = false;
4179               CPT (cpt1U, 31); // safe store complete
4180 
4181               // Temporary absolute mode
4182               set_temporary_absolute_mode (cpup);
4183 
4184               // Set to ring 0
4185               cpu.PPR.PRR = 0;
4186               cpu.TPR.TRR = 0;
4187 
4188               // (12-bits of which the top-most 7-bits are used)
4189               uint fltAddress = (cpu.switches.FLT_BASE << 5) & 07740;
4190               L68_ (
4191                 if (cpu.is_FFV)
4192                   {
4193                     cpu.is_FFV = false;
4194                     CPTUR (cptUseMR);
4195                     // The high 15 bits
4196                     fltAddress = (cpu.MR.FFV & MASK15) << 3;
4197                   }
4198               )
4199 
4200               // absolute address of fault YPair
4201               word24 addr = fltAddress + 2 * cpu.faultNumber;
4202 
4203               if (cpu.restart)
4204                 {
4205                   cpu.restart = false;
4206                   addr = cpu.restart_address;
4207                 }
4208 
4209               // EXECUTE DATA SWITCHES: XED Y runs the pair at Y; any other
4210               // instruction runs as the even word, with a NOP after it
4211               bool switches = cpu.execSwitches;
4212               word36 sw = cpu.switches.data_switches;
4213               cpu.execSwitches = false;
4214               if (switches && ((sw >> 8) & 01777) == (0717u << 1))
4215                 {
4216                   addr     = (word24) GETHI (sw);
4217                   switches = false;
4218                 }
4219               if (switches)
4220                 {
4221                   cpu.cu.IWB   = sw;
4222                   cpu.cu.IRODD = 0000000011000; // nop
4223                 }
4224               else
4225                 core_read2 (cpup, addr, & cpu.cu.IWB, & cpu.cu.IRODD, __func__);
4226 #if defined(TESTING)
4227               HDBGMRead (addr, cpu.cu.IWB, "fault even");
4228               HDBGMRead (addr + 1, cpu.cu.IRODD, "fault odd");
4229 #endif
4230               cpu.cu.xde = 1;
4231               cpu.cu.xdo = 1;
4232               cpu.isExec = true;
4233               cpu.isXED  = true;
4234 
4235               CPT (cpt1U, 33); // set fault exec cycle
4236               set_cpu_cycle (cpup, FAULT_EXEC_cycle);
4237 
4238               break;
4239             }
4240 
4241           }  // switch (cpu.cycle)
4242       }
4243     while (reason == 0);
4244 
4245 leave:
4246 #if defined(THREADZ) || defined(LOCKLESS)
4247     cpu.executing = false;
4248     cpu.inMultics = false;
4249 #endif /* defined(THREADZ) || defined(LOCKLESS) */
4250 #if defined(TESTING)
4251     HDBGPrint ();
4252 #endif
4253 
4254     for (unsigned short n = 0; n < N_CPU_UNITS_MAX; n++)
4255       {
4256 #if !defined(SCHED_NEVER_YIELD)
4257         lockYieldAll     = lockYieldAll     + (unsigned long long)cpus[n].coreLockState.lockYield;
4258 #endif /* if !defined(SCHED_NEVER_YIELD) */
4259         lockWaitMaxAll   = lockWaitMaxAll   + (unsigned long long)cpus[n].coreLockState.lockWaitMax;
4260         lockWaitAll      = lockWaitAll      + (unsigned long long)cpus[n].coreLockState.lockWait;
4261         lockImmediateAll = lockImmediateAll + (unsigned long long)cpus[n].coreLockState.lockImmediate;
4262         lockCntAll       = lockCntAll       + (unsigned long long)cpus[n].coreLockState.lockCnt;
4263         instrCntAll      = instrCntAll      + (unsigned long long)cpus[n].instrCnt;
4264         cycleCntAll      = cycleCntAll      + (unsigned long long)cpus[n].cycleCnt;
4265       }
4266 
4267     (void)fflush(stderr);
4268     (void)fflush(stdout);
4269 
4270 # if !defined(PERF_STRIP)
4271     if (cycleCntAll > (unsigned long long)cpu.cycleCnt)
4272       {
4273 # endif /*if !defined(PERF_STRIP) */
4274         sim_msg ("\r\n");
4275         sim_msg ("\r+---------------------------------+\r\n");
4276         sim_msg ("\r|     Aggregate CPU Statistics    |\r\n");
4277         sim_msg ("\r+---------------------------------+\r\n");
4278         (void)fflush(stderr);
4279         (void)fflush(stdout);
4280 # if defined(WIN_STDIO)
4281         sim_msg ("\r|  cycles        %15llu  |\r\n", cycleCntAll);
4282         sim_msg ("\r|  instructions  %15llu  |\r\n", instrCntAll);
4283         (void)fflush(stderr);
4284         (void)fflush(stdout);
4285         sim_msg ("\r+---------------------------------+\r\n");
4286         sim_msg ("\r|  lockCnt       %15llu  |\r\n", lockCntAll);
4287         sim_msg ("\r|  lockImmediate %15llu  |\r\n", lockImmediateAll);
4288         (void)fflush(stderr);
4289         (void)fflush(stdout);
4290         sim_msg ("\r+---------------------------------+\r\n");
4291         sim_msg ("\r|  lockWait      %15llu  |\r\n", lockWaitAll);
4292         sim_msg ("\r|  lockWaitMax   %15llu  |\r\n", lockWaitMaxAll);
4293         (void)fflush(stderr);
4294         (void)fflush(stdout);
4295 #  if !defined(SCHED_NEVER_YIELD)
4296         sim_msg ("\r|  lockYield     %15llu  |\r\n", lockYieldAll);
4297 #  else
4298         sim_msg ("\r|  lockYield                ----  |\r\n");
4299 #  endif /* if !defined(SCHED_NEVER_YIELD) */
4300         sim_msg ("\r+---------------------------------+\r\n");
4301         (void)fflush(stderr);
4302         (void)fflush(stdout);
4303 # else
4304         sim_msg ("\r|  cycles        %'15llu  |\r\n", cycleCntAll);
4305         sim_msg ("\r|  instructions  %'15llu  |\r\n", instrCntAll);
4306         (void)fflush(stderr);
4307         (void)fflush(stdout);
4308         sim_msg ("\r+---------------------------------+\r\n");
4309         sim_msg ("\r|  lockCnt       %'15llu  |\r\n", lockCntAll);
4310         sim_msg ("\r|  lockImmediate %'15llu  |\r\n", lockImmediateAll);
4311         (void)fflush(stderr);
4312         (void)fflush(stdout);
4313         sim_msg ("\r+---------------------------------+\r\n");
4314         sim_msg ("\r|  lockWait      %'15llu  |\r\n", lockWaitAll);
4315         sim_msg ("\r|  lockWaitMax   %'15llu  |\r\n", lockWaitMaxAll);
4316         (void)fflush(stderr);
4317         (void)fflush(stdout);
4318 #  if !defined(SCHED_NEVER_YIELD)
4319         sim_msg ("\r|  lockYield     %'15llu  |\r\n", lockYieldAll);
4320 #  else
4321         sim_msg ("\r|  lockYield                ----  |\r\n");
4322 #  endif /* if !defined(SCHED_NEVER_YIELD) */
4323         sim_msg ("\r+---------------------------------+\r\n");
4324         (void)fflush(stderr);
4325         (void)fflush(stdout);
4326 # endif /* if defined(WIN_STDIO) */
4327 # if !defined(PERF_STRIP)
4328       }
4329 # else
4330     sim_msg("\r\n");
4331 # endif /* if !defined(PERF_STRIP) */
4332 
4333 
4334 
4335 
4336 
4337 
4338 
4339 
4340 
4341 
4342 
4343 #if defined(THREADZ) || defined(LOCKLESS)
4344     if (running_perf_test == false)
4345       sim_usleep(2000000); // Delay (up to 2s) to allow for stats gathering
4346     stopCPUThread();
4347 #endif
4348 
4349 #if defined(M_SHARED)
4350 // scp needs to have the IC statically allocated, so a placeholder
4351 // was created. Update the placeholder so the IC can be seen via scp
4352 // and restarting sim_instr won't lose the place.
4353 
4354     set_cpu_idx (0); //-V779
4355     dummy_IC = cpu.PPR.IC;
4356 #endif
4357 
4358     return reason;
4359   }
4360 
4361 /*
4362  * cd@libertyhaven.com - sez ...
4363  *  If the instruction addresses a block of four words, the target of the
4364  * instruction is supposed to be an address that is aligned on a four-word
4365  * boundary (0 mod 4). If not, the processor will grab the four-word block
4366  * containing that address that begins on a four-word boundary, even if it
4367  * has to go back 1 to 3 words. Analogous explanation for 8, 16, and 32 cases.
4368  *
4369  * olin@olinsibert.com - sez ...
4370  *  It means that the appropriate low bits of the address are forced to zero.
4371  * So it's the previous words, not the succeeding words, that are used to
4372  * satisfy the request. -- Olin
4373  */
4374 
4375 int operand_size (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4376   {
4377     DCDstruct * i = & cpu.currentInstruction;
4378     if (i->info->flags & (READ_OPERAND | STORE_OPERAND))
4379         return 1;
4380     else if (i->info->flags & (READ_YPAIR | STORE_YPAIR))
4381         return 2;
4382     else if (i->info->flags & (READ_YBLOCK8 | STORE_YBLOCK8))
4383         return 8;
4384     else if (i->info->flags & (READ_YBLOCK16 | STORE_YBLOCK16))
4385         return 16;
4386     else if (i->info->flags & (READ_YBLOCK32 | STORE_YBLOCK32))
4387         return 32;
4388     return 0;
4389   }
4390 
4391 // read instruction operands
4392 
4393 void readOperandRead (cpu_state_t * cpup, word18 addr) {
     /* [previous][next][first][last][top][bottom][index][help] */
4394   CPT (cpt1L, 6); // read_operand
4395 
4396 #if defined(THREADZ)
4397   DCDstruct * i = & cpu.currentInstruction;
4398   if (RMWOP (i)) // ldac, ldqc, stac, stacq, snzc
4399     lock_rmw ();
4400 #endif
4401 
4402   switch (operand_size (cpup)) {
4403     case 1:
4404       CPT (cpt1L, 7); // word
4405       ReadOperandRead (cpup, addr, & cpu.CY);
4406       break;
4407     case 2:
4408       CPT (cpt1L, 8); // double word
4409       addr &= 0777776;   // make even
4410       Read2OperandRead (cpup, addr, cpu.Ypair);
4411       break;
4412     case 8:
4413       CPT (cpt1L, 9); // oct word
4414       addr &= 0777770;   // make on 8-word boundary
4415       Read8 (cpup, addr, cpu.Yblock8, cpu.currentInstruction.b29);
4416       break;
4417     case 16:
4418       CPT (cpt1L, 10); // 16 words
4419       addr &= 0777770;   // make on 8-word boundary
4420       Read16 (cpup, addr, cpu.Yblock16);
4421       break;
4422     case 32:
4423       CPT (cpt1L, 11); // 32 words
4424       addr &= 0777740;   // make on 32-word boundary
4425       for (uint j = 0 ; j < 32 ; j += 1)
4426         ReadOperandRead (cpup, addr + j, cpu.Yblock32 + j);
4427       break;
4428   }
4429 }
4430 
4431 void readOperandRMW (cpu_state_t * cpup, word18 addr) {
     /* [previous][next][first][last][top][bottom][index][help] */
4432   CPT (cpt1L, 6); // read_operand
4433   switch (operand_size (cpup)) {
4434     case 1:
4435       CPT (cpt1L, 7); // word
4436       ReadOperandRMW (cpup, addr, & cpu.CY);
4437       break;
4438     case 2:
4439       CPT (cpt1L, 8); // double word
4440       addr &= 0777776;   // make even
4441       Read2OperandRead (cpup, addr, cpu.Ypair);
4442       break;
4443     case 8:
4444       CPT (cpt1L, 9); // oct word
4445       addr &= 0777770;   // make on 8-word boundary
4446       Read8 (cpup, addr, cpu.Yblock8, cpu.currentInstruction.b29);
4447       break;
4448     case 16:
4449       CPT (cpt1L, 10); // 16 words
4450       addr &= 0777770;   // make on 8-word boundary
4451       Read16 (cpup, addr, cpu.Yblock16);
4452       break;
4453     case 32:
4454       CPT (cpt1L, 11); // 32 words
4455       addr &= 0777740;   // make on 32-word boundary
4456       for (uint j = 0 ; j < 32 ; j += 1)
4457         ReadOperandRMW (cpup, addr + j, cpu.Yblock32 + j);
4458       break;
4459   }
4460 }
4461 
4462 // write instruction operands
4463 
4464 t_stat write_operand (cpu_state_t * cpup, word18 addr, UNUSED processor_cycle_type cyctyp)
     /* [previous][next][first][last][top][bottom][index][help] */
4465   {
4466     switch (operand_size (cpup))
4467       {
4468         case 1:
4469             CPT (cpt1L, 12); // word
4470             WriteOperandStore (cpup, addr, cpu.CY);
4471             break;
4472         case 2:
4473             CPT (cpt1L, 13); // double word
4474             addr &= 0777776;   // make even
4475             Write2OperandStore (cpup, addr + 0, cpu.Ypair);
4476             break;
4477         case 8:
4478             CPT (cpt1L, 14); // 8 words
4479             addr &= 0777770;   // make on 8-word boundary
4480             Write8 (cpup, addr, cpu.Yblock8, cpu.currentInstruction.b29);
4481             break;
4482         case 16:
4483             CPT (cpt1L, 15); // 16 words
4484             addr &= 0777770;   // make on 8-word boundary
4485             Write16 (cpup, addr, cpu.Yblock16);
4486             break;
4487         case 32:
4488             CPT (cpt1L, 16); // 32 words
4489             addr &= 0777740;   // make on 32-word boundary
4490             //for (uint j = 0 ; j < 32 ; j += 1)
4491                 //Write (addr + j, cpu.Yblock32[j], OPERAND_STORE);
4492             Write32 (cpup, addr, cpu.Yblock32);
4493             break;
4494       }
4495 
4496 #if defined(THREADZ)
4497     if (cyctyp == OPERAND_STORE)
4498       {
4499         DCDstruct * i = & cpu.currentInstruction;
4500         if (RMWOP (i))
4501           unlock_mem ();
4502       }
4503 #endif
4504     return SCPE_OK;
4505 
4506   }
4507 
4508 #if !defined(SPEED)
4509 t_stat set_mem_watch (int32 arg, const char * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
4510   {
4511     if (strlen (buf) == 0)
4512       {
4513         if (arg)
4514           {
4515             sim_warn ("no argument to watch?\r\n");
4516             return SCPE_ARG;
4517           }
4518         sim_msg ("Clearing all watch points\r\n");
4519         (void)memset (& watch_bits, 0, sizeof (watch_bits));
4520         return SCPE_OK;
4521       }
4522     char * end;
4523     long int n = strtol (buf, & end, 0);
4524     if (* end || n < 0 || n >= MEMSIZE)
4525       {
4526         sim_warn ("Invalid argument to watch? %ld\r\n", (long) n);
4527         return SCPE_ARG;
4528       }
4529     watch_bits [n] = arg != 0;
4530     return SCPE_OK;
4531   }
4532 #endif /* if !defined(SPEED) */
4533 
4534 /*!
4535  * "Raw" core interface ....
4536  */
4537 
4538 #if !defined(SPEED)
4539 static void nem_check (word24 addr, const char * context)
     /* [previous][next][first][last][top][bottom][index][help] */
4540   {
4541     cpu_state_t * cpup = _cpup;
4542     if (lookup_cpu_mem_map (cpup, addr) < 0)
4543       {
4544         doFault (FAULT_STR, fst_str_nea,  context);
4545       }
4546   }
4547 #endif /* if !defined(SPEED) */
4548 
4549 // static uint get_scu_unit_idx (word24 addr, word24 * offset)
4550 //   {
4551 //     int cpu_port_num = lookup_cpu_mem_map (addr, offset);
4552 //     if (cpu_port_num < 0) // Can't happen, we passed nem_check above
4553 //       {
4554 //         sim_warn ("cpu_port_num < 0");
4555 //         doFault (FAULT_STR, fst_str_nea,  __func__);
4556 //       }
4557 //     return cables->cpu_to_scu [current_running_cpu_idx][cpu_port_num].scu_unit_idx;
4558 //   }
4559 
4560 #if !defined(SPEED) || !defined(INLINE_CORE)
4561 int core_read (cpu_state_t * cpup, word24 addr, word36 *data, const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
4562   {
4563     SC_LOCKOUT_WAIT ();
4564     BAD_PARITY_READ (addr);
4565     PNL (cpu.portBusy = true;)
4566     SC_MAP_ADDR (addr, addr);
4567 # if !defined(LOCKLESS)
4568     if (M[addr] & MEM_UNINITIALIZED)
4569       {
4570         sim_debug (DBG_WARN, & cpu_dev,
4571                    "Uninitialized memory accessed at address %08o; "
4572                    "IC is 0%06o:0%06o (%s(\r\n",
4573                    addr, cpu.PPR.PSR, cpu.PPR.IC, ctx);
4574       }
4575 # endif /* if !defined(LOCKLESS) */
4576 # if !defined(SPEED)
4577     if (watch_bits [addr])
4578       {
4579         sim_msg ("WATCH [%llu] %05o:%06o read   %08o %012llo (%s)\r\n",
4580                     (long long unsigned int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC, addr,
4581                     (long long unsigned int)M [addr], ctx);
4582         traceInstruction (0);
4583       }
4584 # endif /* if !defined(SPEED) */
4585 # if defined(LOCKLESS)
4586 #  if !defined(SUNLINT)
4587     word36 v;
4588     LOAD_ACQ_CORE_WORD(v, addr);
4589     *data = v & DMASK;
4590 #  endif /* if !defined(SUNLINT) */
4591 # else
4592     *data = M[addr] & DMASK;
4593 # endif /* if defined(LOCKLESS) */
4594 
4595     DO_WORK_MEM;
4596     sim_debug (DBG_CORE, & cpu_dev,
4597                "core_read  %08o %012"PRIo64" (%s)\r\n",
4598                 addr, * data, ctx);
4599     PNL (trackport (addr, * data));
4600     return 0;
4601   }
4602 #endif
4603 
4604 #if defined(LOCKLESS)
4605 int core_read_lock (cpu_state_t * cpup, word24 addr, word36 *data, UNUSED const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
4606 {
4607     if (nBadParity && cpu.tweaks.tandd_mode && bad_parity_marked (addr))
4608       cpu.scLockedOut = true;
4609     BAD_PARITY_READ (addr);
4610     SC_MAP_ADDR (addr, addr);
4611     LOCK_CORE_WORD(addr, & cpu.coreLockState);
4612     if (cpu.coreLockState.locked_addr != 0) {
4613       sim_warn ("core_read_lock: locked %08o locked_addr %08o %c %05o:%06o\r\n",
4614                 addr, cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
4615                 cpu.PPR.PSR, cpu.PPR.IC);
4616       core_unlock_all (cpup);
4617     }
4618     cpu.coreLockState.locked_addr = addr;
4619 # if !defined(SUNLINT)
4620     word36 v;
4621     LOAD_ACQ_CORE_WORD(v, addr);
4622     * data = v & DMASK;
4623 # endif /* if !defined(SUNLINT) */
4624     return 0;
4625 }
4626 #endif
4627 
4628 #if !defined(SPEED) || !defined(INLINE_CORE)
4629 int core_write (cpu_state_t * cpup, word24 addr, word36 data, const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
4630   {
4631     SC_LOCKOUT_WAIT ();
4632     BAD_PARITY_WRITE (addr);
4633     PNL (cpu.portBusy = true;)
4634     SC_MAP_ADDR (addr, addr);
4635     if (cpu.tweaks.isolts_mode)
4636       {
4637         if (cpu.MR.sdpap)
4638           {
4639             sim_warn ("failing to implement sdpap\r\n");
4640             cpu.MR.sdpap = 0;
4641           }
4642         if (cpu.MR.separ)
4643           {
4644             sim_warn ("failing to implement separ\r\n");
4645                 cpu.MR.separ = 0;
4646           }
4647       }
4648 # if defined(LOCKLESS)
4649     LOCK_CORE_WORD(addr, & cpu.coreLockState);
4650 #  if !defined(SUNLINT)
4651     STORE_REL_CORE_WORD(addr, data);
4652 #  endif /* if !defined(SUNLINT) */
4653 # else
4654     M[addr] = data & DMASK;
4655 # endif /* if defined(LOCKLESS) */
4656 # if !defined(SPEED)
4657     if (watch_bits [addr])
4658       {
4659         sim_msg ("WATCH [%llu] %05o:%06o write  %08llo %012llo (%s)\r\n",
4660                  (long long unsigned int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
4661                  (long long unsigned int)addr, (unsigned long long int)M [addr], ctx);
4662         traceInstruction (0);
4663       }
4664 # endif /* if !defined(SPEED) */
4665     DO_WORK_MEM;
4666     sim_debug (DBG_CORE, & cpu_dev,
4667                "core_write %08o %012"PRIo64" (%s)\r\n",
4668                 addr, data, ctx);
4669     PNL (trackport (addr, data));
4670     return 0;
4671   }
4672 #endif /* if !defined(SPEED) || !defined(INLINE_CORE) */
4673 
4674 #if defined(LOCKLESS)
4675 int core_write_unlock (cpu_state_t * cpup, word24 addr, word36 data, UNUSED const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
4676 {
4677     BAD_PARITY_WRITE (addr);
4678     SC_MAP_ADDR (addr, addr);
4679     if (cpu.coreLockState.locked_addr != addr)
4680       {
4681         sim_warn ("core_write_unlock: locked %08o locked_addr %08o %c %05o:%06o\r\n",
4682                   addr,        cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
4683                   cpu.PPR.PSR, cpu.PPR.IC);
4684        core_unlock_all (cpup);
4685       }
4686 
4687 # if !defined(SUNLINT)
4688     STORE_REL_CORE_WORD(addr, data);
4689 # endif /* if !defined(SUNLINT) */
4690     cpu.coreLockState.locked_addr = 0;
4691     return 0;
4692 }
4693 
4694 int core_unlock_all (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4695 {
4696   if (cpu.coreLockState.locked_addr != 0) {
4697       sim_warn ("core_unlock_all: locked %08o %c %05o:%06o\r\n",
4698                 cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
4699                 cpu.PPR.PSR,     cpu.PPR.IC);
4700 # if !defined(SUNLINT)
4701       STORE_REL_CORE_WORD(cpu.coreLockState.locked_addr, M[cpu.coreLockState.locked_addr]);
4702 # endif /* if !defined(SUNLINT) */
4703       cpu.coreLockState.locked_addr = 0;
4704   }
4705   return 0;
4706 }
4707 #endif
4708 
4709 #if !defined(SPEED) || !defined(INLINE_CORE)
4710 int core_write_zone (cpu_state_t * cpup, word24 addr, word36 data, const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
4711   {
4712     SC_LOCKOUT_WAIT ();
4713     BAD_PARITY_WRITE (addr);
4714     PNL (cpu.portBusy = true;)
4715     if (cpu.tweaks.isolts_mode)
4716       {
4717         if (cpu.MR.sdpap)
4718           {
4719             sim_warn ("failing to implement sdpap\r\n");
4720             cpu.MR.sdpap = 0;
4721           }
4722         if (cpu.MR.separ)
4723           {
4724             sim_warn ("failing to implement separ\r\n");
4725             cpu.MR.separ = 0;
4726           }
4727       }
4728     word24 mapAddr = 0;
4729     SC_MAP_ADDR (addr, mapAddr);
4730 # if defined(LOCKLESS)
4731     word36 v;
4732     core_read_lock(cpup, addr,  &v, ctx);
4733     v = (v & ~cpu.zone) | (data & cpu.zone);
4734     core_write_unlock(cpup, addr, v, ctx);
4735 # else
4736     M[mapAddr] = (M[mapAddr] & ~cpu.zone) | (data & cpu.zone);
4737 # endif
4738     cpu.useZone = false; // Safety
4739 # if !defined(SPEED)
4740     if (watch_bits [mapAddr])
4741       {
4742         sim_msg ("WATCH [%llu] %05o:%06o writez %08llo %012llo (%s)\r\n",
4743                 (unsigned long long int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
4744                 (unsigned long long int)mapAddr, (unsigned long long int)M [mapAddr], ctx);
4745         traceInstruction (0);
4746       }
4747 # endif
4748     DO_WORK_MEM;
4749     sim_debug (DBG_CORE, & cpu_dev,
4750                "core_write_zone %08o %012"PRIo64" (%s)\r\n",
4751                 mapAddr, data, ctx);
4752     PNL (trackport (mapAddr, data));
4753     return 0;
4754   }
4755 #endif
4756 
4757 #if !defined(SPEED) || !defined(INLINE_CORE)
4758 int core_read2 (cpu_state_t * cpup, word24 addr, word36 *even, word36 *odd, const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
4759   {
4760     SC_LOCKOUT_WAIT ();
4761     BAD_PARITY_READ (addr & ~1u);
4762     BAD_PARITY_READ (addr | 1u);
4763     PNL (cpu.portBusy = true;)
4764 # if defined(LOCKLESS)
4765     /*LINTED E_FUNC_VAR_UNUSED*/ /* Appease SUNLINT */
4766     word36 v;
4767 # endif
4768     if (addr & 1)
4769       {
4770         sim_debug (DBG_MSG, & cpu_dev,
4771                    "warning: subtracting 1 from pair at %o in "
4772                    "core_read2 (%s)\r\n", addr, ctx);
4773         addr &= (word24)~1; /* make it an even address */
4774       }
4775     SC_MAP_ADDR (addr, addr);
4776 # if !defined(LOCKLESS)
4777     if (M[addr] & MEM_UNINITIALIZED)
4778       {
4779         sim_debug (DBG_WARN, & cpu_dev,
4780                    "Uninitialized memory accessed at address %08o; "
4781                    "IC is 0%06o:0%06o (%s)\r\n",
4782                    addr, cpu.PPR.PSR, cpu.PPR.IC, ctx);
4783       }
4784 # endif
4785 # if !defined(SPEED)
4786     if (watch_bits [addr])
4787       {
4788         sim_msg ("WATCH [%llu] %05o:%06o read2  %08llo %012llo (%s)\r\n",
4789                  (unsigned long long int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
4790                  (unsigned long long int)addr, (unsigned long long int)M [addr], ctx);
4791         traceInstruction (0);
4792       }
4793 # endif
4794 # if defined(LOCKLESS)
4795 #  if !defined(SUNLINT)
4796     LOAD_ACQ_CORE_WORD(v, addr);
4797     if (v & MEM_LOCKED)
4798       sim_warn ("core_read2: even locked %08o locked_addr %08o %c %05o:%06o\r\n",
4799                 addr,        cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
4800                 cpu.PPR.PSR, cpu.PPR.IC);
4801     *even = v & DMASK;
4802     addr++;
4803 #  endif /* if !defined(SUNLINT) */
4804 # else
4805     *even = M[addr++] & DMASK;
4806 # endif
4807     sim_debug (DBG_CORE, & cpu_dev,
4808                "core_read2 %08o %012"PRIo64" (%s)\r\n",
4809                 addr - 1, * even, ctx);
4810 
4811     // if the even address is OK, the odd will be
4812     //nem_check (addr,  "core_read2 nem");
4813 # if !defined(LOCKLESS)
4814     if (M[addr] & MEM_UNINITIALIZED)
4815       {
4816         sim_debug (DBG_WARN, & cpu_dev,
4817                    "Uninitialized memory accessed at address %08o; "
4818                    "IC is 0%06o:0%06o (%s)\r\n",
4819                     addr, cpu.PPR.PSR, cpu.PPR.IC, ctx);
4820       }
4821 # endif
4822 # if !defined(SPEED)
4823     if (watch_bits [addr])
4824       {
4825         sim_msg ("WATCH [%llu] %05o:%06o read2  %08llo %012llo (%s)\r\n",
4826                  (unsigned long long int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
4827                  (unsigned long long int)addr, (unsigned long long int)M [addr], ctx);
4828         traceInstruction (0);
4829       }
4830 # endif
4831 # if defined(LOCKLESS)
4832 #  if !defined(SUNLINT)
4833     LOAD_ACQ_CORE_WORD(v, addr);
4834     if (v & MEM_LOCKED)
4835       sim_warn ("core_read2: odd locked %08o locked_addr %08o %c %05o:%06o\r\n",
4836                 addr,        cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
4837                 cpu.PPR.PSR, cpu.PPR.IC);
4838     *odd = v & DMASK;
4839 #  endif /* if !defined(SUNLINT) */
4840 # else
4841     *odd = M[addr] & DMASK;
4842 # endif
4843     sim_debug (DBG_CORE, & cpu_dev,
4844                "core_read2 %08o %012"PRIo64" (%s)\r\n",
4845                 addr, * odd, ctx);
4846     DO_WORK_MEM;
4847     PNL (trackport (addr - 1, * even));
4848     return 0;
4849   }
4850 #endif
4851 
4852 #if !defined(SPEED) || !defined(INLINE_CORE)
4853 int core_write2 (cpu_state_t * cpup, word24 addr, word36 even, word36 odd, const char * ctx) {
     /* [previous][next][first][last][top][bottom][index][help] */
4854   SC_LOCKOUT_WAIT ();
4855   BAD_PARITY_WRITE (addr & ~1u);
4856   BAD_PARITY_WRITE (addr | 1u);
4857   PNL (cpu.portBusy = true;)
4858   if (addr & 1) {
4859     sim_debug (DBG_MSG, & cpu_dev,
4860                "warning: subtracting 1 from pair at %o in core_write2 " "(%s)\r\n",
4861                addr, ctx);
4862     addr &= (word24)~1; /* make it even a dress, or iron a skirt ;) */
4863   }
4864   SC_MAP_ADDR (addr, addr);
4865   if (cpu.tweaks.isolts_mode) {
4866     if (cpu.MR.sdpap) {
4867       sim_warn ("failing to implement sdpap\r\n");
4868       cpu.MR.sdpap = 0;
4869     }
4870     if (cpu.MR.separ) {
4871       sim_warn ("failing to implement separ\r\n");
4872       cpu.MR.separ = 0;
4873     }
4874   }
4875 
4876 # if !defined(SPEED)
4877   if (watch_bits [addr]) {
4878     sim_msg ("WATCH [%llu] %05o:%06o write2 %08llo %012llo (%s)\r\n",
4879              (unsigned long long int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
4880              (unsigned long long int)addr, (unsigned long long int)even, ctx);
4881     traceInstruction (0);
4882   }
4883 # endif
4884 # if defined(LOCKLESS)
4885   LOCK_CORE_WORD(addr, & cpu.coreLockState);
4886 #  if !defined(SUNLINT)
4887   STORE_REL_CORE_WORD(addr, even);
4888 #  endif /* if !defined(SUNLINT) */
4889   addr++;
4890 # else
4891   M[addr++] = even & DMASK;
4892 # endif
4893   sim_debug (DBG_CORE, & cpu_dev, "core_write2 %08o %012llo (%s)\r\n", addr - 1,
4894           (long long unsigned int)even, ctx);
4895 
4896   // If the even address is OK, the odd will be
4897   //mem_check (addr,  "core_write2 nem");
4898 
4899 # if !defined(SPEED)
4900   if (watch_bits [addr]) {
4901     sim_msg ("WATCH [%llu] %05o:%06o write2 %08llo %012llo (%s)\r\n",
4902              (long long unsigned int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
4903              (long long unsigned int)addr, (long long unsigned int)odd, ctx);
4904     traceInstruction (0);
4905   }
4906 # endif
4907 # if defined(LOCKLESS)
4908   LOCK_CORE_WORD(addr, & cpu.coreLockState);
4909 #  if !defined(SUNLINT)
4910   STORE_REL_CORE_WORD(addr, odd);
4911 #  endif /* if !defined(SUNLINT) */
4912 # else
4913   M[addr] = odd & DMASK;
4914 # endif
4915   DO_WORK_MEM;
4916   PNL (trackport (addr - 1, even));
4917   sim_debug (DBG_CORE, & cpu_dev, "core_write2 %08o %012"PRIo64" (%s)\r\n", addr, odd, ctx);
4918   return 0;
4919 }
4920 #endif
4921 
4922 /*
4923  * Instruction fetcher ...
4924  * Fetch + decode instruction at 18-bit address 'addr'
4925  */
4926 
4927 /*
4928  * Instruction decoder .....
4929  */
4930 
4931 void decode_instruction (cpu_state_t * cpup, word36 inst, DCDstruct * p)
     /* [previous][next][first][last][top][bottom][index][help] */
4932   {
4933     CPT (cpt1L, 17); // instruction decoder
4934     //(void)memset (p, 0, sizeof (DCDstruct));
4935     // only these two flags need explicit clearing before the new instruction is decoded.
4936     // Every other field is explicitly assigned below.
4937     p->stiTally = false;
4938     p->restart  = false;
4939 
4940     p->opcode   = GET_OP (inst);   // get opcode
4941     p->opcodeX  = GET_OPX(inst);   // opcode extension
4942     p->opcode10 = p->opcode | (p->opcodeX ? 01000 : 0); //-V536
4943     p->address  = GET_ADDR (inst); // address field from instruction
4944     p->b29      = GET_A (inst);    // "A" the indirect via pointer register flag
4945     p->i        = GET_I (inst);    // "I" inhibit interrupt flag
4946     p->tag      = GET_TAG (inst);  // instruction tag
4947 
4948     p->info     = get_iwb_info  (p);     // get info for IWB instruction
4949 
4950     if (p->info->flags & IGN_B29)
4951         p->b29 = 0;   // make certain 'a' bit is valid always
4952 
4953     if (p->info->ndes > 0)
4954       {
4955         p->b29 = 0;
4956         p->tag = 0;
4957         if (p->info->ndes > 1)
4958           {
4959             (void)memset (& cpu.currentEISinstruction, 0,
4960                           sizeof (cpu.currentEISinstruction));
4961           }
4962       }
4963   }
4964 
4965 // MM stuff ...
4966 
4967 //
4968 // is_priv_mode()
4969 //
4970 // Report whether or or not the CPU is in privileged mode.
4971 // True if in absolute mode or if priv bit is on in segment TPR.TSR
4972 // The processor executes instructions in privileged mode when forming
4973 // addresses in absolute mode or when forming addresses in append mode and the
4974 // segment descriptor word (SDW) for the segment in execution specifies a
4975 // privileged procedure and the execution ring is equal to zero.
4976 //
4977 // PPR.P A flag controlling execution of privileged instructions.
4978 //
4979 // Its value is 1 (permitting execution of privileged instructions) if PPR.PRR
4980 // is 0 and the privileged bit in the segment descriptor word (SDW.P) for the
4981 // procedure is 1; otherwise, its value is 0.
4982 //
4983 
4984 int is_priv_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4985   {
4986 // Back when it was ABS/APP/BAR, this test was right; now that
4987 // it is ABS/APP,BAR/NBAR, check bar mode.
4988 // Fixes ISOLTS 890 05a.
4989     if (get_bar_mode (cpup))
4990       return 0;
4991 
4992 // PPR.P is only relevant if we're in APPEND mode. ABSOLUTE mode ignores it.
4993     if (get_addr_mode (cpup) == ABSOLUTE_mode)
4994       return 1;
4995     else if (cpu.PPR.P)
4996       return 1;
4997 
4998     return 0;
4999   }
5000 
5001 /*
5002  * get_bar_mode: During fault processing, we do not want to fetch and execute
5003  * the fault vector instructions in BAR mode. We leverage the
5004  * secret_addressing_mode flag that is set in set_TEMPORARY_ABSOLUTE_MODE to
5005  * direct us to ignore the I_NBAR indicator register.
5006  */
5007 
5008 bool get_bar_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5009   {
5010     return ! (cpu.secret_addressing_mode || TST_I_NBAR);
5011   }
5012 
5013 addr_modes_e get_addr_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5014   {
5015     if (cpu.secret_addressing_mode)
5016         return ABSOLUTE_mode; // This is not the mode you are looking for
5017 
5018     // went_appending does not alter privileged state (only enables appending)
5019     // the went_appending check is only required by ABSA, AFAICT
5020     // pft 02b 013255, ISOLTS-860
5021     //if (cpu.went_appending)
5022     //    return APPEND_mode;
5023 
5024     if (TST_I_ABS)
5025       {
5026           return ABSOLUTE_mode;
5027       }
5028     else
5029       {
5030           return APPEND_mode;
5031       }
5032   }
5033 
5034 /*
5035  * set_addr_mode()
5036  *
5037  * Put the CPU into the specified addressing mode.   This involves
5038  * setting a couple of IR flags and the PPR priv flag.
5039  */
5040 
5041 void set_addr_mode (cpu_state_t * cpup, addr_modes_e mode)
     /* [previous][next][first][last][top][bottom][index][help] */
5042   {
5043 //    cpu.cu.XSF = false;
5044 //sim_debug (DBG_TRACEEXT, & cpu_dev, "set_addr_mode bit 29 sets XSF to 0\r\n");
5045     //cpu.went_appending = false;
5046 // Temporary hack to fix fault/intr pair address mode state tracking
5047 //   1. secret_addressing_mode is only set in fault/intr pair processing.
5048 //   2. Assume that the only set_addr_mode that will occur is the b29 special
5049 //   case or ITx.
5050     //if (secret_addressing_mode && mode == APPEND_mode)
5051       //set_went_appending ();
5052 
5053     cpu.secret_addressing_mode = false;
5054     if (mode == ABSOLUTE_mode)
5055       {
5056         CPT (cpt1L, 22); // set abs mode
5057         sim_debug (DBG_DEBUG, & cpu_dev, "APU: Setting absolute mode.\r\n");
5058 
5059         SET_I_ABS;
5060         cpu.PPR.P = 1;
5061       }
5062     else if (mode == APPEND_mode)
5063       {
5064         CPT (cpt1L, 23); // set append mode
5065         if (! TST_I_ABS && TST_I_NBAR)
5066           sim_debug (DBG_DEBUG, & cpu_dev, "APU: Keeping append mode.\r\n");
5067         else
5068           sim_debug (DBG_DEBUG, & cpu_dev, "APU: Setting append mode.\r\n");
5069 
5070         CLR_I_ABS;
5071       }
5072     else
5073       {
5074         sim_debug (DBG_ERR, & cpu_dev,
5075                   "APU: Unable to determine address mode.\r\n");
5076         sim_warn ("APU: Unable to determine address mode. Can't happen!\r\n");
5077       }
5078   }
5079 
5080 /*
5081  * stuff to handle BAR mode ...
5082  */
5083 
5084 /*
5085  * The Base Address Register provides automatic hardware Address relocation and
5086  * Address range limitation when the processor is in BAR mode.
5087  *
5088  * BAR.BASE: Contains the 9 high-order bits of an 18-bit address relocation
5089  * constant. The low-order bits are generated as zeros.
5090  *
5091  * BAR.BOUND: Contains the 9 high-order bits of the unrelocated address limit.
5092  * The low- order bits are generated as zeros. An attempt to access main memory
5093  * beyond this limit causes a store fault, out of bounds. A value of 0 is truly
5094  * 0, indicating a null memory range.
5095  *
5096  * In BAR mode, the base address register (BAR) is used. The BAR contains an
5097  * address bound and a base address. All computed addresses are relocated by
5098  * adding the base address. The relocated address is combined with the
5099  * procedure pointer register to form the virtual memory address. A program is
5100  * kept within certain limits by subtracting the unrelocated computed address
5101  * from the address bound. If the result is zero or negative, the relocated
5102  * address is out of range, and a store fault occurs.
5103  */
5104 
5105 // CANFAULT
5106 word18 get_BAR_address (cpu_state_t * cpup, word18 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
5107   {
5108     if (cpu . BAR.BOUND == 0)
5109         // store fault, out of bounds.
5110         doFault (FAULT_STR, fst_str_oob, "BAR store fault; out of bounds");
5111 
5112     // A program is kept within certain limits by subtracting the
5113     // unrelocated computed address from the address bound. If the result
5114     // is zero or negative, the relocated address is out of range, and a
5115     // store fault occurs.
5116     //
5117     // BAR.BOUND - CA <= 0
5118     // BAR.BOUND <= CA
5119     // CA >= BAR.BOUND
5120     //
5121     if (addr >= (((word18) cpu . BAR.BOUND) << 9))
5122         // store fault, out of bounds.
5123         doFault (FAULT_STR, fst_str_oob, "BAR store fault; out of bounds");
5124 
5125     word18 barAddr = (addr + (((word18) cpu . BAR.BASE) << 9)) & 0777777;
5126     return barAddr;
5127   }
5128 
5129 //=============================================================================
5130 
5131 static void add_history (cpu_state_t * cpup, uint hset, word36 w0, word36 w1)
     /* [previous][next][first][last][top][bottom][index][help] */
5132   {
5133     //if (cpu.MR.emr)
5134       {
5135         cpu.history [hset] [cpu.history_cyclic[hset]] [0] = w0;
5136         cpu.history [hset] [cpu.history_cyclic[hset]] [1] = w1;
5137         cpu.history_cyclic[hset] = (cpu.history_cyclic[hset] + 1) % N_MODEL_HIST_SIZE;
5138       }
5139   }
5140 
5141 void add_history_force (cpu_state_t * cpup, uint hset, word36 w0, word36 w1)
     /* [previous][next][first][last][top][bottom][index][help] */
5142   {
5143     cpu.history [hset] [cpu.history_cyclic[hset]] [0] = w0;
5144     cpu.history [hset] [cpu.history_cyclic[hset]] [1] = w1;
5145     cpu.history_cyclic[hset] = (cpu.history_cyclic[hset] + 1) % N_MODEL_HIST_SIZE;
5146   }
5147 
5148 void add_dps8m_CU_history (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5149   {
5150     if (cpu.skip_cu_hist)
5151       return;
5152     if (! cpu.MR_cache.emr)
5153       return;
5154     if (! cpu.MR_cache.ihr)
5155       return;
5156     if (cpu.MR_cache.hrxfr && ! cpu.wasXfer)
5157       return;
5158 
5159     word36 flags   = 0; // XXX fill out
5160     word5 proccmd  = 0; // XXX fill out
5161     word7 flags2   = 0; // XXX fill out
5162     word36 w0      = 0, w1 = 0;
5163     w0            |= flags & 0777777000000;
5164     w0            |= IWB_IRODD & MASK18;
5165     w1            |= ((word36)(cpu.iefpFinalAddress & MASK24) << 12);
5166     w1            |= (proccmd & MASK5) << 7;
5167     w1            |= flags2 & 0176;
5168     add_history (cpup, CU_HIST_REG, w0, w1);
5169   }
5170 
5171 #if !defined(QUIET_UNUSED)
5172 void add_dps8m_DU_OU_history (cpu_state_t * cpup, word36 flags, word18 ICT, word9 RS_REG, word9 flags2)
     /* [previous][next][first][last][top][bottom][index][help] */
5173   {
5174     word36 w0  = flags, w1 = 0;
5175     w1        |= (ICT & MASK18) << 18;
5176     w1        |= (RS_REG & MASK9) << 9;
5177     w1        |= flags2 & MASK9;
5178     add_history (cpup, DPS8M_DU_OU_HIST_REG, w0, w1);
5179   }
5180 
5181 void add_dps8m_APU_history (cpu_state_t * cpup, word15 ESN, word21 flags, word24 RMA, word3 RTRR, word9 flags2)
     /* [previous][next][first][last][top][bottom][index][help] */
5182   {
5183     word36 w0  = 0, w1 = 0;
5184     w0        |= (ESN & MASK15) << 21;
5185     w0        |= flags & MASK21;
5186     w1        |= (RMA & MASK24) << 12;
5187     w1        |= (RTRR & MASK3) << 9;
5188     w1        |= flags2 & MASK9;
5189     add_history (cpu.tweaks.l68_mode ? L68_APU_HIST_REG : DPS8M_APU_HIST_REG, w0, w1);
5190   }
5191 
5192 void add_dps8m_EAPU_history (word18 ZCA, word18 opcode)
     /* [previous][next][first][last][top][bottom][index][help] */
5193   {
5194     word36 w0  = 0;
5195     w0        |= (ZCA & MASK18) << 18;
5196     w0        |= opcode & MASK18;
5197     add_history (DPS8M_EAPU_HIST_REG, w0, 0);
5198     //cpu.eapu_hist[cpu.eapu_cyclic].ZCA = ZCA;
5199     //cpu.eapu_hist[cpu.eapu_cyclic].opcode = opcode;
5200     //cpu.history_cyclic[DPS8M_EAPU_HIST_REG] =
5201       //(cpu.history_cyclic[DPS8M_EAPU_HIST_REG] + 1) % N_DPS8M_HIST_SIZE;
5202   }
5203 #endif
5204 
5205 // According to ISOLTS
5206 //
5207 //   0 PIA
5208 //   1 POA
5209 //   2 RIW
5210 //   3 SIW
5211 //   4 POT
5212 //   5 PON
5213 //   6 RAW
5214 //   7 SAW
5215 //   8 TRGO
5216 //   9 XDE
5217 //  10 XDO
5218 //  11 IC
5219 //  12 RPTS
5220 //  13 WI
5221 //  14 AR F/E
5222 //  15 XIP
5223 //  16 FLT
5224 //  17 COMPL. ADD BASE
5225 //  18:23 OPCODE/TAG
5226 //  24:29 ADDREG
5227 //  30:34 COMMAND A/B/C/D/E
5228 //  35:38 PORT A/B/C/D
5229 //  39 FB XEC
5230 //  40 INS FETCH
5231 //  41 CU STORE
5232 //  42 OU STORE
5233 //  43 CU LOAD
5234 //  44 OU LOAD
5235 //  45 RB DIRECT
5236 //  46 -PC BUSY
5237 //  47 PORT BUSY
5238 
5239 // The L68 CU history register is strobed on every control unit cycle
5240 // (AL39: "the conditions for the last 16 control unit cycles"), so an
5241 // instruction pair fetch, or a transfer's read of its target pair, makes
5242 // an entry of its own (INS-FETCH); the CU-HR counter overflow trap counts
5243 // these too (PM701 02C).
5244 static void add_l68_CU_history_entry (cpu_state_t * cpup, bool ins_fetch)
     /* [previous][next][first][last][top][bottom][index][help] */
5245   {
5246     CPT (cpt1L, 24); // add cu hist
5247     if (cpu.skip_cu_hist)
5248       return;
5249     if (! cpu.MR_cache.emr)
5250       return;
5251     if (! cpu.MR_cache.ihr)
5252       return;
5253     // O.C$ (bit 29): strobe only the instruction whose opcode matches the
5254     // MR OPCODE field (PM700 02Y)
5255     if (getbits36_1 (cpu.MR_cache.r, 29) &&
5256         (ins_fetch ||
5257          cpu.currentInstruction.opcode != getbits36_9 (cpu.MR_cache.r, 18) ||
5258          (cpu.currentInstruction.opcodeX ? 1u : 0u) != getbits36_1 (cpu.MR_cache.r, 27)))
5259       return;
5260 
5261     word36 w0 = 0, w1 = 0;
5262 
5263     // 0 PIA
5264     // 1 POA
5265     // 2 RIW
5266     // 3 SIW
5267     // 4 POT
5268     // 5 PON
5269     // 6 RAW
5270     // 7 SAW
5271     PNL (putbits36_8 (& w0, 0, cpu.prepare_state);)
5272     // 8 TRG
5273     putbits36_1  (& w0, 8, cpu.wasXfer);
5274     // 9 XDE
5275     putbits36_1  (& w0, 9, cpu.cu.xde);
5276     // 10 XDO
5277     putbits36_1  (& w0, 10, cpu.cu.xdo);
5278     // 11 IC
5279     putbits36_1  (& w0, 11, USE_IRODD?1:0);
5280     // 12 RPT
5281     putbits36_1  (& w0, 12, cpu.cu.rpt);
5282     // 13 WI Wait for instruction fetch XXX Not tracked
5283     // 14 ARF "AR F/E" Address register Full/Empty Address has valid data
5284     PNL (putbits36_1 (& w0, 14, cpu.AR_F_E);)
5285     // 15 !XA/Z "-XIP NOT prepare interrupt address"
5286     putbits36_1  (& w0, 15, cpu.cycle != INTERRUPT_cycle?1:0);
5287     // 16 !FA/Z Not tracked. (cu.-FL?)
5288     putbits36_1  (& w0, 16, cpu.cycle != FAULT_cycle?1:0);
5289     // 17 M/S  (master/slave, cu.-BASE?, NOT BAR MODE)
5290     putbits36_1  (& w0, 17, TSTF (cpu.cu.IR, I_NBAR)?1:0);
5291     // 18:35 IWR (lower half of IWB)
5292     putbits36_18 (& w0, 18, (word18) (IWB_IRODD & MASK18));
5293 
5294     // 36:53 CA
5295     putbits36_18 (& w1, 0, cpu.TPR.CA);
5296     // 54:58 CMD system controller command XXX
5297     // 59:62 SEL port select (XXX ignoring "only valid if port A-D is selected")
5298     PNL (putbits36_1 (& w1, 59-36, (cpu.portSelect == 0)?1:0);)
5299     PNL (putbits36_1 (& w1, 60-36, (cpu.portSelect == 1)?1:0);)
5300     PNL (putbits36_1 (& w1, 61-36, (cpu.portSelect == 2)?1:0);)
5301     PNL (putbits36_1 (& w1, 62-36, (cpu.portSelect == 3)?1:0);)
5302     // 63 XEC-INT An interrupt is present
5303     putbits36_1 (& w1, 63-36, cpu.interrupt_flag?1:0);
5304     // 64 INS-FETCH Perform an instruction fetch
5305     putbits36_1 (& w1, 64-36, ins_fetch?1:0);
5306     // 65 CU-STORE Control unit store cycle XXX
5307     // 66 OU-STORE Operations unit store cycle XXX
5308     // 67 CU-LOAD Control unit load cycle XXX
5309     // 68 OU-LOAD Operations unit load cycle XXX
5310     // 69 DIRECT Direct cycle XXX
5311     // 70 -PC-BUSY Port control logic not busy XXX
5312     // 71 BUSY Port interface busy XXX
5313 
5314     add_history (cpup, CU_HIST_REG, w0, w1);
5315 
5316     // Check for overflow
5317     CPTUR (cptUseMR);
5318     if (cpu.MR.hrhlt && cpu.history_cyclic[CU_HIST_REG] == 0)
5319       {
5320         //cpu.history_cyclic[CU_HIST_REG] = 15;
5321         if (cpu.MR.ihrrs)
5322           {
5323             cpu.MR.ihr = 0;
5324           }
5325         set_FFV_fault (cpup, 4);
5326         return;
5327       }
5328   }
5329 
5330 void add_l68_CU_history (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5331   {
5332     add_l68_CU_history_entry (cpup, false);
5333   }
5334 
5335 void add_l68_CU_fetch_history (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5336   {
5337     add_l68_CU_history_entry (cpup, true);
5338   }
5339 
5340 // du history register inputs(actual names)
5341 // bit 00= fpol-cx;010       bit 36= fdud-dg;112
5342 // bit 01= fpop-cx;010       bit 37= fgdlda-dc;010
5343 // bit 02= need-desc-bd;000  bit 38= fgdldb-dc;010
5344 // bit 03= sel-adr-bd;000    bit 39= fgdldc-dc;010
5345 // bit 04= dlen=direct-bd;000bit 40= fnld1-dp;110
5346 // bit 05= dfrst-bd;021      bit 41= fgldp1-dc;110
5347 // bit 06= fexr-bd;010       bit 42= fnld2-dp;110
5348 // bit 07= dlast-frst-bd;010 bit 43= fgldp2-dc;110
5349 // bit 08= ddu-ldea-bd;000   bit 44= fanld1-dp;110
5350 // bit 09= ddu-stea-bd;000   bit 45= fanld2-dp;110
5351 // bit 10= dredo-bd;030      bit 46= fldwrt1-dp;110
5352 // bit 11= dlvl<wd-sz-bg;000 bit 47= fldwrt2-dp;110
5353 // bit 12= exh-bg;000        bit 48= data-avldu-cm;000
5354 // bit 13= dend-seg-bd;111   bit 49= fwrt1-dp;110
5355 // bit 14= dend-bd;000       bit 50= fgstr-dc;110
5356 // bit 15= du=rd+wrt-bd;010  bit 51= fanstr-dp;110
5357 // bit 16= ptra00-bd;000     bit 52= fstr-op-av-dg;010
5358 // bit 17= ptra01-bd;000     bit 53= fend-seg-dg;010
5359 // bit 18= fa/i1-bd;110      bit 54= flen<128-dg;010
5360 // bit 19= fa/i2-bd;110      bit 55= fgch-dp;110
5361 // bit 20= fa/i3-bd;110      bit 56= fanpk-dp;110
5362 // bit 21= wrd-bd;000        bit 57= fexmop-dl;110
5363 // bit 22= nine-bd;000       bit 58= fblnk-dp;100
5364 // bit 23= six-bd;000        bit 59= unused
5365 // bit 24= four-bd;000       bit 60= dgbd-dc;100
5366 // bit 25= bit-bd;000        bit 61= dgdb-dc;100
5367 // bit 26= unused            bit 62= dgsp-dc;100
5368 // bit 27= unused            bit 63= ffltg-dc;110
5369 // bit 28= unused            bit 64= frnd-dg;120
5370 // bit 29= unused            bit 65= dadd-gate-dc;100
5371 // bit 30= fsampl-bd;111     bit 66= dmp+dv-gate-db;100
5372 // bit 31= dfrst-ct-bd;010   bit 67= dxpn-gate-dg;100
5373 // bit 32= adj-lenint-cx;000 bit 68= unused
5374 // bit 33= fintrptd-cx;010   bit 69= unused
5375 // bit 34= finhib-stc1-cx;010bit 70= unused
5376 // bit 35= unused            bit 71= unused
5377 
5378 void add_l68_DU_history (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5379   {
5380     CPT (cpt1L, 25); // add du hist
5381     PNL (add_history (cpup, L68_DU_HIST_REG, cpu.du.cycle1, cpu.du.cycle2);)
5382   }
5383 
5384 void add_l68_OU_history (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
5385   {
5386     CPT (cpt1L, 26); // add ou hist
5387     word36 w0 = 0, w1 = 0;
5388 
5389     // 0-16 RP
5390     //   0-8 OP CODE
5391     putbits36_9 (& w0,       0,       cpu.ou.RS);
5392 
5393     //   9 CHAR
5394     putbits36_1 (& w0,       9,       cpu.ou.characterOperandSize ? 1 : 0);
5395 
5396     //   10-12 TAG 1/2/3
5397     putbits36_3 (& w0,       10,      cpu.ou.characterOperandOffset);
5398 
5399     //   13 CRFLAG
5400     putbits36_1 (& w0,       13,      cpu.ou.crflag);
5401 
5402     //   14 DRFLAG
5403     putbits36_1 (& w0,       14,      cpu.ou.directOperandFlag ? 1 : 0);
5404 
5405     //   15-16 EAC
5406     putbits36_2 (& w0,       15,      cpu.ou.eac);
5407 
5408     // 17 0
5409     // 18-26 RS REG
5410     putbits36_9 (& w0,       18,      cpu.ou.RS);
5411 
5412     // 27 RB1 FULL
5413     putbits36_1 (& w0,       27,      cpu.ou.RB1_FULL);
5414 
5415     // 28 RP FULL
5416     putbits36_1 (& w0,       28,      cpu.ou.RP_FULL);
5417 
5418     // 29 RS FULL
5419     putbits36_1 (& w0,       29,      cpu.ou.RS_FULL);
5420 
5421     // 30-35 GIN/GOS/GD1/GD2/GOE/GOA
5422     putbits36_6 (& w0,       30,      (word6) (cpu.ou.cycle >> 3));
5423 
5424     // 36-38 GOM/GON/GOF
5425     putbits36_3 (& w1,       36-36,   (word3) cpu.ou.cycle);
5426 
5427     // 39 STR OP
5428     putbits36_1 (& w1,       39-36,   cpu.ou.STR_OP);
5429 
5430     // 40 -DA-AV XXX
5431 
5432     // 41-50 stuvwyyzAB -A-REG -Q-REG -X0-REG .. -X7-REG
5433     putbits36_10 (& w1,      41-36,
5434                   (word10) ~opcodes10 [cpu.ou.RS].reg_use);
5435 
5436     // 51-53 0
5437 
5438     // 54-71 ICT TRACKER
5439     putbits36_18 (& w1,      54 - 36, cpu.PPR.IC);
5440 
5441     add_history (cpup, L68_OU_HIST_REG, w0, w1);
5442   }
5443 
5444 // According to ISOLTS
5445 //  0:2 OPCODE RP
5446 //  3 9 BIT CHAR
5447 //  4:6 TAG 3/4/5
5448 //  7 CR FLAG
5449 //  8 DIR FLAG
5450 //  9 RP15
5451 // 10 RP16
5452 // 11 SPARE
5453 // 12:14 OPCODE RS
5454 // 15 RB1 FULL
5455 // 16 RP FULL
5456 // 17 RS FULL
5457 // 18 GIN
5458 // 19 GOS
5459 // 20 GD1
5460 // 21 GD2
5461 // 22 GOE
5462 // 23 GOA
5463 // 24 GOM
5464 // 25 GON
5465 // 26 GOF
5466 // 27 STORE OP
5467 // 28 DA NOT
5468 // 29:38 COMPLEMENTED REGISTER IN USE FLAG A/Q/0/1/2/3/4/5/6/7
5469 // 39 ?
5470 // 40 ?
5471 // 41 ?
5472 // 42:47 ICT TRACT
5473 
5474 // XXX add_APU_history
5475 
5476 //  0:5 SEGMENT NUMBER
5477 //  6 SNR/ESN
5478 //  7 TSR/ESN
5479 //  8 FSDPTW
5480 //  9 FPTW2
5481 // 10 MPTW
5482 // 11 FANP
5483 // 12 FAP
5484 // 13 AMSDW
5485 // 14:15 AMSDW #
5486 // 16 AMPTW
5487 // 17:18 AMPW #
5488 // 19 ACV/DF
5489 // 20:27 ABSOLUTE MEMORY ADDRESS
5490 // 28 TRR #
5491 // 29 FLT HLD
5492 
5493 void add_l68_APU_history (cpu_state_t * cpup, enum APUH_e op)
     /* [previous][next][first][last][top][bottom][index][help] */
5494   {
5495     CPT (cpt1L, 28); // add apu hist
5496     word36 w0 = 0, w1 = 0;
5497 
5498     w0 = op; // set 17-24 FDSPTW/.../FAP bits
5499 
5500     // 0-14 ESN
5501     putbits36_15 (& w0,      0,  cpu.TPR.TSR);
5502     // 15-16 BSY
5503     PNL (putbits36_1 (& w0,  15, (cpu.apu.state & apu_ESN_SNR) ? 1 : 0);)
5504     PNL (putbits36_1 (& w0,  16, (cpu.apu.state & apu_ESN_TSR) ? 1 : 0);)
5505     // 25 SDWAMM
5506     putbits36_1 (& w0,       25, cpu.cu.SDWAMM);
5507     // 26-29 SDWAMR
5508     putbits36_4 (& w0,       26, (word4) cpu.SDWAMR);
5509     // 30 PTWAMM
5510     putbits36_1 (& w0,       30, cpu.cu.PTWAMM);
5511     // 31-34 PTWAMR
5512     putbits36_4 (& w0,       31, (word4) cpu.PTWAMR);
5513     // 35 FLT
5514     PNL (putbits36_1 (& w0,  35, (cpu.apu.state & apu_FLT) ? 1 : 0);)
5515 
5516     // 36-59 ADD
5517     PNL (putbits36_24 (& w1, 0,  cpu.APUMemAddr);)
5518     // 60-62 TRR
5519     putbits36_3 (& w1,       24, cpu.TPR.TRR);
5520     // 66 XXX Multiple match error in SDWAM
5521     // 70 Segment is encachable
5522     putbits36_1 (& w1,       34, cpu.SDW0.C);
5523     // 71 XXX Multiple match error in PTWAM
5524 
5525     add_history (cpup, L68_APU_HIST_REG, w0, w1);
5526   }
5527 
5528 #if defined(THREADZ) || defined(LOCKLESS)
5529 //static pthread_mutex_t debug_lock = PTHREAD_MUTEX_INITIALIZER;
5530 
5531 static const char * get_dbg_verb (uint32 dbits, DEVICE * dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
5532   {
5533     static const char * debtab_none    = "DEBTAB_ISNULL";
5534     static const char * debtab_nomatch = "DEBTAB_NOMATCH";
5535     const char * some_match            = NULL;
5536     int32 offset                       = 0;
5537 
5538     if (dptr->debflags == 0)
5539       return debtab_none;
5540 
5541     dbits &= dptr->dctrl;     /* Look for just the bits that matched */
5542 
5543     /* Find matching words for bitmask */
5544     while ((offset < 32) && dptr->debflags[offset].name)
5545       {
5546         if (dptr->debflags[offset].mask == dbits)   /* All Bits Match */
5547           return dptr->debflags[offset].name;
5548         if (dptr->debflags[offset].mask & dbits)
5549           some_match = dptr->debflags[offset].name;
5550         offset ++;
5551       }
5552     return some_match ? some_match : debtab_nomatch;
5553   }
5554 
5555 void dps8_sim_debug (uint32 dbits, DEVICE * dptr, unsigned long long cnt, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
5556   {
5557     //pthread_mutex_lock (& debug_lock);
5558     if (sim_deb && dptr && (dptr->dctrl & dbits))
5559       {
5560         const char * debug_type = get_dbg_verb (dbits, dptr);
5561         char stackbuf[STACKBUFSIZE];
5562         int32 bufsize           = sizeof (stackbuf);
5563         char * buf              = stackbuf;
5564         va_list arglist;
5565         int32 i, j, len;
5566         struct timespec t;
5567         clock_gettime(CLOCK_REALTIME, &t);
5568 
5569         buf [bufsize-1] = '\0';
5570 
5571         while (1)
5572           {                 /* format passed string, args */
5573             va_start (arglist, fmt);
5574             len = vsnprintf (buf, (int)((unsigned long)(bufsize)-1), fmt, arglist);
5575             va_end (arglist);
5576 
5577 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
5578 
5579             if ((len < 0) || (len >= bufsize-1))
5580               {
5581                 if (buf != stackbuf)
5582                   FREE (buf);
5583                 if (bufsize >= (INT_MAX / 2))
5584                   return;                                   /* too big */
5585                 bufsize = bufsize * 2;
5586                 if (bufsize < len + 2)
5587                   bufsize = len + 2;
5588                 buf = (char *) malloc ((unsigned long) bufsize);
5589                 if (buf == NULL)                            /* out of memory */
5590                   return;
5591                 buf[bufsize-1] = '\0';
5592                 continue;
5593               }
5594             break;
5595           }
5596 
5597 /* Output the formatted data expanding newlines where they exist */
5598 
5599         for (i = j = 0; i < len; ++i)
5600           {
5601             if ('\n' == buf[i])
5602               {
5603                 if (i >= j)
5604                   {
5605                     if ((i != j) || (i == 0))
5606                       {
5607                           (void)fprintf (sim_deb, "%lld.%06ld: DBG(%lld) %o: %s %s %.*s\r\n",
5608                                          (long long)t.tv_sec, t.tv_nsec/1000, cnt,
5609                                          current_running_cpu_idx, dptr->name, debug_type, i-j, &buf[j]);
5610                       }
5611                   }
5612                 j = i + 1;
5613               }
5614           }
5615 
5616         /* Set unterminated flag for next time */
5617         if (buf != stackbuf)
5618           FREE (buf);
5619       }
5620     //pthread_mutex_unlock (& debug_lock);
5621   }
5622 #endif
5623 
5624 void setupPROM (uint cpuNo, unsigned char * PROM) {
     /* [previous][next][first][last][top][bottom][index][help] */
5625 // 58009997-040 MULTICS Differences Manual DPS 8-70M Aug83
5626 //
5627 // THESE OFFSETS ARE IN OCTAL
5628 //
5629 //  0-13 CPU Model Number
5630 // 13-25 CPU Serial Number
5631 // 26-33 Date-Ship code (YYMMDD)
5632 // 34-40 CPU ID Field (reference RSW 2)
5633 //  Byte 40: Bits 03 (Bits 32-35 of RSW 2 Field
5634 //           Bit 4=1 Hex Option included
5635 //           Bit 5=1 RSCR (Clock) is Slave Mode included
5636 //           Bits 6-7 Reserved for later use.
5637 //       50: Operating System Use
5638 // 51-1777(8) To be defined.
5639 // NOTE: There is the possibility of disagreement between the
5640 //       ID bits of RSW 2 and the ID bits of PROM locations
5641 //       35-40. This condition could result when alterable
5642 //       configuration condition is contained in the PROM.
5643 //       The user is advised to ignore the PROM fields which
5644 //       contain the processor fault vector base (GCOS III)
5645 //       and the processor number and rely on the RSW 2 bits
5646 //       for this purpose. Bits 14-16 of the RSW 2 should be
5647 //       ignored and the bits representing this information in
5648 //       the PROM should be treated as valid.
5649 
5650 // "0-13" disagrees with Multics source (start_pl1); it interprets
5651 // it as "0-12"; most likely a typo in 58009997-040.
5652 
5653 // CAC notes: I interpret the fields as
5654 //  0-12 CPU Model Number                                          //  0-10  11 chars
5655 // 13-25 CPU Serial Number // 13 chars                             // 11-21  11 chars
5656 // 26-33 Date-Ship code (YYMMDD) // 8 chars (enough for YYYYMMDD). // 22-27   6 chars
5657 // 34-40 CPU ID Field (reference RSW 2)                            // 28-32   5 chars
5658 //  Byte 40: Bits 03 (Bits 32-35 of RSW 2 Field                    //    32
5659 //           Bit 4=1 Hex Option included
5660 //           Bit 5=1 RSCR (Clock) is Slave Mode included
5661 //           Bits 6-7 Reserved for later use.
5662 //       50: Operating System Use                                  //    40
5663 
5664   word36 rsw2 = 0;
5665 
5666   // The PROM copy of RSW 2 contains a canonical RSW 2 rather than the actual RSW 2.
5667   //   The port interlace is set to 0
5668   //   The fault base is set to 2 (Multics)
5669   //   Processor mode is set to 0 (Multics)
5670 
5671   //  0 -   3   4   Port interlace = 0000
5672   putbits36_4 (& rsw2,  0,   0);
5673   //  4 -   5   2   CPU type  01 = DPS8
5674   putbits36_2 (& rsw2,  4,  001);
5675   //  6 - 12    7   Fault Base  = 2
5676   putbits36_7 (& rsw2,  6,   2);
5677   // 13 - 13    1   PROM Present = 1
5678   putbits36_1 (& rsw2,  13,  1);
5679   // 14 - 18    5   Pad 00000
5680   putbits36_5 (& rsw2,  14,  0);
5681   // 19 - 19    1   CPU  1 = DPS8
5682   putbits36_1 (& rsw2,  19,  1);
5683   // 20 - 20    1   8K Cache  1 = Present
5684   putbits36_1 (& rsw2,  20,  cpus[cpuNo].options.cache_installed ? 1 : 0);
5685   // 21 - 22    2   Pad
5686   putbits36_2 (& rsw2,  21,  0);
5687   // 23 - 23    1   Always 1 for Multics CPU
5688   putbits36_1 (& rsw2,  23,  1);
5689   // 24 - 24    1   Proc Mode Bit
5690   putbits36_1 (& rsw2,  24,  0);
5691   // 25 - 28    4   Pad
5692   putbits36_4 (& rsw2,  25,  0);
5693   // 29 - 32    4   CPU speed options
5694   putbits36_4 (& rsw2,  29,  cpus[cpuNo].options.proc_speed & 017LL);
5695   // 33 - 35    3   CPU number
5696   putbits36_3 (& rsw2,  33,  cpus[cpuNo].switches.cpu_num & 07LL);
5697 
5698   word4 rsw2Ext = 0;
5699   if (cpus[cpuNo].options.hex_mode_installed)
5700     rsw2Ext |= 010;  // bit 4
5701   if (cpus[cpuNo].options.clock_slave_installed)
5702     rsw2Ext |= 004;  // bit 5
5703   // bits 6,7 reserved for future use
5704 
5705   char serial[12];
5706   (void)sprintf (serial, "%-11u", cpus[cpuNo].switches.serno);
5707 
5708 #if defined(VER_H_PROM_SHIP)
5709   char * ship = VER_H_PROM_SHIP;
5710 #else
5711   char * ship = "200101";
5712 #endif /* VER_H_PROM_SHIP */
5713 
5714 #if !defined(VER_H_PROM_MAJOR_VER)
5715 # define VER_H_PROM_MAJOR_VER "999"
5716 #endif /* VER_H_PROM_MAJOR_VER */
5717 
5718 #if !defined(VER_H_PROM_MINOR_VER)
5719 # define VER_H_PROM_MINOR_VER "999"
5720 #endif /* VER_H_PROM_MINOR_VER */
5721 
5722 #if !defined(VER_H_PROM_PATCH_VER)
5723 # define VER_H_PROM_PATCH_VER "999"
5724 #endif /* VER_H_PROM_PATCH_VER */
5725 
5726 #if !defined(VER_H_PROM_OTHER_VER)
5727 # define VER_H_PROM_OTHER_VER "999"
5728 #endif /* VER_H_PROM_OTHER_VER */
5729 
5730 #if !defined(VER_H_GIT_RELT)
5731 # define VER_H_GIT_RELT "X"
5732 #endif /* VER_H_GIT_RELT */
5733 
5734 #if !defined(VER_H_PROM_VER_TEXT)
5735 # define VER_H_PROM_VER_TEXT "Unknown                      "
5736 #endif /* VER_H_PROM_VER_TEXT */
5737 
5738 #if defined(BUILD_PROM_OSA_TEXT)
5739 # define BURN_PROM_OSA_TEXT BUILD_PROM_OSA_TEXT
5740 #else
5741 # if !defined(VER_H_PROM_OSA_TEXT)
5742 #  define BURN_PROM_OSA_TEXT "Unknown Build Op Sys"
5743 # else
5744 #  define BURN_PROM_OSA_TEXT VER_H_PROM_OSA_TEXT
5745 # endif /* VER_H_PROM_OSA_TEXT */
5746 #endif /* BUILD_PROM_OSA_TEXT */
5747 
5748 #if defined(BUILD_PROM_OSV_TEXT)
5749 # define BURN_PROM_OSV_TEXT BUILD_PROM_OSV_TEXT
5750 #else
5751 # if !defined(VER_H_PROM_OSV_TEXT)
5752 #  define BURN_PROM_OSV_TEXT "Unknown Build Arch. "
5753 # else
5754 #  define BURN_PROM_OSV_TEXT VER_H_PROM_OSV_TEXT
5755 # endif /* VER_H_PROM_OSV_TEXT */
5756 #endif /* BUILD_PROM_OSV_TEXT */
5757 
5758 #if defined(BUILD_PROM_TSA_TEXT)
5759 # define BURN_PROM_TSA_TEXT BUILD_PROM_TSA_TEXT
5760 #else
5761 # if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
5762 #  define VER_H_PROM_TSA_TEXT "Intel x86_64 (AMD64)"
5763 # elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
5764 #  define VER_H_PROM_TSA_TEXT "Intel ix86 (32-bit) "
5765 # elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
5766 #  define VER_H_PROM_TSA_TEXT "AArch64/ARM64/64-bit"
5767 # elif defined(_M_ARM) || defined(__arm__)
5768 #  define VER_H_PROM_TSA_TEXT "AArch32/ARM32/32-bit"
5769 # elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
5770 #  define VER_H_PROM_TSA_TEXT "Intel Itanium (IA64)"
5771 # elif defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
5772   defined(__POWERPC64__) || \
5773   defined(_M_PPC64) || \
5774   defined(__PPC64) || \
5775   defined(_ARCH_PPC64)
5776 #  define VER_H_PROM_TSA_TEXT "Power ISA (64-bit)  "
5777 # elif defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || \
5778   defined(__PPC) || \
5779   defined(__ppc32__) || \
5780   defined(__PPC32__) || \
5781   defined(__powerpc32__) || \
5782   defined(__POWERPC32__) || \
5783   defined(_M_PPC32) || \
5784   defined(__PPC32)
5785 #  define VER_H_PROM_TSA_TEXT "PowerPC ISA (32-bit)"
5786 # elif defined(__s390x__)
5787 #  define VER_H_PROM_TSA_TEXT "IBM z/Architecture  "
5788 # elif defined(__s390__)
5789 #  define VER_H_PROM_TSA_TEXT "IBM ESA System/390  "
5790 # elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
5791 #  define VER_H_PROM_TSA_TEXT "J-Core J2 Open CPU  "
5792 # elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
5793 #  define VER_H_PROM_TSA_TEXT "Hitachi/Renesas SH-4"
5794 # elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
5795 #  define VER_H_PROM_TSA_TEXT "Hitachi/Renesas SH-2"
5796 # elif defined(__alpha__)
5797 #  define VER_H_PROM_TSA_TEXT "Alpha AXP           "
5798 # elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
5799 #  define VER_H_PROM_TSA_TEXT "HP PA-RISC          "
5800 # elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
5801 #  define VER_H_PROM_TSA_TEXT "SiCortex ICE-9      "
5802 # elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
5803 #  define VER_H_PROM_TSA_TEXT "MIPS64              "
5804 # elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
5805 #  define VER_H_PROM_TSA_TEXT "MIPS                "
5806 # elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || defined(__OR1K__) || defined(__OPENRISC1K__)
5807 #  define VER_H_PROM_TSA_TEXT "OpenRISC            "
5808 # elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
5809 #  define VER_H_PROM_TSA_TEXT "SPARC64             "
5810 # elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
5811 #  define VER_H_PROM_TSA_TEXT "SPARC               "
5812 # elif defined(__riscv) || defined(__riscv__)
5813 #  define VER_H_PROM_TSA_TEXT "RISC-V              "
5814 # elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__e2k64__)
5815 #  if defined(__iset__)
5816 #   if __iset__ > 0
5817 #    if __iset__ == 1
5818 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v1      "
5819 #    elif __iset__ == 2
5820 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v2      "
5821 #    elif __iset__ == 3
5822 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v3      "
5823 #    elif __iset__ == 4
5824 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v4      "
5825 #    elif __iset__ == 5
5826 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v5      "
5827 #    elif __iset__ == 6
5828 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v6      "
5829 #    elif __iset__ == 7
5830 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v7      "
5831 #    elif __iset__ == 8
5832 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v8      "
5833 #    elif __iset__ == 9
5834 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v9      "
5835 #    elif __iset__ == 10
5836 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v10     "
5837 #    else
5838 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus         "
5839 #    endif
5840 #   else
5841 #    define VER_H_PROM_TSA_TEXT "MCST Elbrus         "
5842 #   endif
5843 #  else
5844 #   define VER_H_PROM_TSA_TEXT "MCST Elbrus         "
5845 #  endif
5846 # elif defined(__myriad2__)
5847 #  define VER_H_PROM_TSA_TEXT "Myriad2             "
5848 # elif defined(__loongarch64) || defined(__loongarch__)
5849 #  define VER_H_PROM_TSA_TEXT "LoongArch           "
5850 # elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5851 #  define VER_H_PROM_TSA_TEXT "Motorola m68k       "
5852 # elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5853 #  define VER_H_PROM_TSA_TEXT "Motorola m88k       "
5854 # elif defined(__VAX__) || defined(__vax__)
5855 #  define VER_H_PROM_TSA_TEXT "VAX                 "
5856 # elif defined(__NIOS2__) || defined(__nios2__)
5857 #  define VER_H_PROM_TSA_TEXT "Altera Nios II      "
5858 # elif defined(__MICROBLAZE__) || defined(__microblaze__)
5859 #  define VER_H_PROM_TSA_TEXT "Xilinx MicroBlaze   "
5860 # elif defined(__kvx__) || defined(__KVX__) || defined(__KVX_64__)
5861 #  define VER_H_PROM_TSA_TEXT "Kalray KVX          "
5862 # endif
5863 # if !defined(VER_H_PROM_TSA_TEXT)
5864 #  define BURN_PROM_TSA_TEXT "Unknown Target Arch."
5865 # else
5866 #  define BURN_PROM_TSA_TEXT VER_H_PROM_TSA_TEXT
5867 # endif /* VER_H_PROM_TSA_TEXT */
5868 #endif /* BUILD_PROM_TSA_TEXT */
5869 
5870 #if (defined(__WIN__) || defined(_WIN32) || defined(IS_WINDOWS) || defined(_MSC_VER) || defined(__MINGW32__) || \
5871         defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)) && !defined(__CYGWIN__)
5872 # define DC_IS_WINDOWS 1
5873 #else
5874 # define DC_IS_WINDOWS 0
5875 #endif
5876 
5877 #if defined(BUILD_PROM_TSV_TEXT)
5878 # define BURN_PROM_TSV_TEXT BUILD_PROM_TSV_TEXT
5879 #else
5880 # if DC_IS_WINDOWS
5881 #  define VER_H_PROM_TSV_TEXT "Microsoft Windows   "
5882 # elif defined(__CYGWIN__)
5883 #  define VER_H_PROM_TSV_TEXT "Windows/Cygwin      "
5884 # elif (defined(__sunos) || defined(__sun) || defined(__sun__)) && (defined(SYSV) || defined(__SVR4) || defined(__SVR4__) || \
5885         defined(__svr4__))
5886 #  if defined(__illumos__)
5887 #   define VER_H_PROM_TSV_TEXT "illumos             "
5888 #  else
5889 #   define VER_H_PROM_TSV_TEXT "Solaris             "
5890 #  endif
5891 # elif defined(__APPLE__) && defined(__MACH__)
5892 #  define VER_H_PROM_TSV_TEXT "Apple macOS         "
5893 # elif defined(__GNU__) && !defined(__linux__)
5894 #  define VER_H_PROM_TSV_TEXT "GNU/Hurd            "
5895 # elif defined(__ANDROID__) && defined(__ANDROID_API__)
5896 #  if defined(__linux__)
5897 #   define VER_H_PROM_TSV_TEXT "Android/Linux       "
5898 #  else
5899 #   define VER_H_PROM_TSV_TEXT "Android             "
5900 #  endif
5901 # elif defined(__lynxOS__) || defined(__LYNXOS__) || defined(LynxOS) || defined(LYNXOS)
5902 #  define VER_H_PROM_TSV_TEXT "LynxOS              "
5903 # elif defined(__HELENOS__)
5904 #  define VER_H_PROM_TSV_TEXT "HelenOS             "
5905 # elif defined(__linux__)
5906 #  if defined(__BIONIC__)
5907 #   define VER_H_PROM_TSV_TEXT "Linux/Bionic-libc   "
5908 #  elif defined(__UCLIBC__) || defined(UCLIBC)
5909 #   define VER_H_PROM_TSV_TEXT "Linux/uClibc        "
5910 #  elif defined(__NEWLIB__)
5911 #   define VER_H_PROM_TSV_TEXT "Linux/Newlib        "
5912 #  elif defined(__dietlibc__)
5913 #   define VER_H_PROM_TSV_TEXT "Linux/Diet-libc     "
5914 #  elif defined(__GLIBC__)
5915 #   define VER_H_PROM_TSV_TEXT "GNU/Linux           "
5916 #  else
5917 #   define VER_H_PROM_TSV_TEXT "Linux               "
5918 #  endif
5919 # elif defined(__HAIKU__)
5920 #  define VER_H_PROM_TSV_TEXT "Haiku               "
5921 # elif defined(__serenity__)
5922 #  define VER_H_PROM_TSV_TEXT "SerenityOS          "
5923 # elif defined(__FreeBSD__)
5924 #  define VER_H_PROM_TSV_TEXT "FreeBSD             "
5925 # elif defined(__NetBSD__)
5926 #  define VER_H_PROM_TSV_TEXT "NetBSD              "
5927 # elif defined(__OpenBSD__)
5928 #  define VER_H_PROM_TSV_TEXT "OpenBSD             "
5929 # elif defined(__DragonFly__)
5930 #  define VER_H_PROM_TSV_TEXT "DragonFly BSD       "
5931 # elif defined(_AIX)
5932 #  if !defined(__PASE__)
5933 #   define VER_H_PROM_TSV_TEXT "IBM AIX             "
5934 #  else
5935 #   define VER_H_PROM_TSV_TEXT "IBM OS/400 (PASE)   "
5936 #  endif
5937 # elif defined(__VXWORKS__) || defined(__VXWORKS) || defined(__vxworks) || defined(__vxworks__) || defined(_VxWorks)
5938 #  if !defined(__RTP__)
5939 #   define VER_H_PROM_TSV_TEXT "VxWorks             "
5940 #  else
5941 #   define VER_H_PROM_TSV_TEXT "VxWorks RTP         "
5942 #  endif
5943 # elif defined(__rtems__)
5944 #  if defined(__FreeBSD_version)
5945 #   define VER_H_PROM_TSV_TEXT "RTEMS/LibBSD        "
5946 #  else
5947 #   define VER_H_PROM_TSV_TEXT "RTEMS               "
5948 #  endif
5949 # elif defined(__ZEPHYR__)
5950 #  define VER_H_PROM_TSV_TEXT "Zephyr              "
5951 # elif defined(ti_sysbios_BIOS___VERS) || defined(ti_sysbios_BIOS__top__)
5952 #  define VER_H_PROM_TSV_TEXT "TI-RTOS (SYS/BIOS)  "
5953 # elif defined(__OSV__) // -V1040
5954 #  define VER_H_PROM_TSV_TEXT "OSv                 "
5955 # elif defined(MINIX) || defined(MINIX3) || defined(MINIX315) || defined(__minix__) || defined(__minix3__) || defined(__minix315__)
5956 #  define VER_H_PROM_TSV_TEXT "Minix               "
5957 # elif defined(__QNX__)
5958 #  if defined(__QNXNTO__)
5959 #   define VER_H_PROM_TSV_TEXT "QNX Neutrino        "
5960 #  else
5961 #   define VER_H_PROM_TSV_TEXT "QNX                 "
5962 #  endif
5963 # elif defined(__managarm__)
5964 #  define VER_H_PROM_TSV_TEXT "Managarm            "
5965 # endif
5966 # if !defined(VER_H_PROM_TSV_TEXT)
5967 #  define BURN_PROM_TSV_TEXT "Unknown Target OpSys"
5968 # else
5969 #  define BURN_PROM_TSV_TEXT VER_H_PROM_TSV_TEXT
5970 # endif /* VER_H_PROM_TSV_TEXT */
5971 #endif /* BUILD_PROM_TSV_TEXT */
5972 
5973 #if !defined(VER_H_GIT_DATE_SHORT)
5974 # define VER_H_GIT_DATE_SHORT "2021-01-01"
5975 #endif /* if !defined(VER_H_GIT_DATE_SHORT) */
5976 
5977 #if !defined(BURN_PROM_BUILD_NUM)
5978 # define BURN_PROM_BUILD_NUM "        "
5979 #endif /* if !defined(BURN_PROM_BUILD_NUM) */
5980 
5981 #define BURN(offset, length, string) memcpy ((char *) PROM + (offset), string, length)
5982 #define BURN1(offset, byte) PROM[offset] = (char) (byte)
5983 
5984   (void)memset (PROM, 255, 1024);
5985 
5986   //   Offset Length  Data
5987   BURN  ( 00,  11,  "DPS 8/SIM M");                //    0-10  CPU model ("XXXXXXXXXXX")       //-V1086
5988   BURN  (013,  11,  serial);                       //   11-21  CPU serial ("DDDDDDDDDDD")      //-V1086
5989   BURN  (026,   6,  ship);                         //   22-27  CPU ship date ("YYMMDD")        //-V1086
5990   BURN1 (034,       getbits36_8 (rsw2,  0));       //   34     RSW 2 bits  0- 7                //-V1086
5991   BURN1 (035,       getbits36_8 (rsw2,  8));       //   35     RSW 2 bits  8-15                //-V1086
5992   BURN1 (036,       getbits36_8 (rsw2, 16));       //   36     RSW 2 bits 16-23                //-V1086
5993   BURN1 (037,       getbits36_8 (rsw2, 24));       //   37     RSW 2 bits 24-31                //-V1086
5994   BURN1 (040,     ((getbits36_4 (rsw2, 32) << 4) \
5995                                | rsw2Ext));        //   40     RSW 2 bits 32-35, options bits  //-V1086
5996 
5997   /* Begin extended PROM data */
5998   BURN  ( 60,   1,  "2");                          //   60     PROM Layout Version Number      //-V1086
5999   BURN  ( 70,  10,  VER_H_GIT_DATE_SHORT);         //   70     Release Git Commit Date         //-V1086
6000   BURN  ( 80,   3,  VER_H_PROM_MAJOR_VER);         //   80     Major Release Number            //-V1086
6001   BURN  ( 83,   3,  VER_H_PROM_MINOR_VER);         //   83     Minor Release Number            //-V1086
6002   BURN  ( 86,   3,  VER_H_PROM_PATCH_VER);         //   86     Patch Release Number            //-V1086
6003   BURN  ( 89,   3,  VER_H_PROM_OTHER_VER);         //   89     Iteration Release Number        //-V1086
6004   BURN  ( 92,   8,  BURN_PROM_BUILD_NUM);          //   92     Reserved for Build Number       //-V1086
6005   BURN  (100,   1,  VER_H_GIT_RELT);               //  100     Release Type                    //-V1086
6006   BURN  (101,  29,  VER_H_PROM_VER_TEXT);          //  101     Release Text                    //-V1086
6007   BURN  (130,  20,  BURN_PROM_OSA_TEXT);           //  130     Build System Architecture       //-V1086
6008   BURN  (150,  20,  BURN_PROM_OSV_TEXT);           //  150     Build System Operating System   //-V1086
6009   BURN  (170,  20,  BURN_PROM_TSA_TEXT);           //  170     Target System Architecture      //-V1086
6010   BURN  (190,  20,  BURN_PROM_TSV_TEXT);           //  190     Target System Architecture      //-V1086
6011 }
6012 
6013 void cpuStats (uint cpuNo) {
     /* [previous][next][first][last][top][bottom][index][help] */
6014   if (! cpus[cpuNo].cycleCnt)
6015     return;
6016 
6017 /* Detect Haiku pthread_getcpuclockid availability */
6018 #if defined(__HAIKU__)
6019 # if HAS_INCLUDE(<syscall_clock_info.h>)
6020 #  include <syscall_clock_info.h>
6021 # endif
6022 # if !defined(_SYSTEM_SYSCALL_CLOCK_INFO_H)
6023 #  if !defined(HAIKU_NO_PTHREAD_GETCPUCLOCKID)
6024 #   define HAIKU_NO_PTHREAD_GETCPUCLOCKID
6025 #  endif
6026 # endif
6027 #endif
6028 
6029 /* Clang and SunCC may not define __illumos__ but we require it
6030  * here to check for pthread_getcpuclockid availability */
6031 #if defined(__sun) || defined(__sun__)
6032 # if !defined(__illumos__)
6033 #  if HAS_INCLUDE(<sys/sysevent.h>)
6034 #   include <sys/sysevent.h>
6035 #  endif
6036 #  if defined(ILLUMOS_VENDOR) || defined(ILLUMOS_KERN_PUB)
6037 #   define __illumos__
6038 #  endif
6039 # endif
6040 #endif
6041 
6042   double cpu_seconds = 0;
6043   int cpu_millis = 0;
6044   char cpu_ftime[64] = {0};
6045 #if (defined(THREADZ) || defined(LOCKLESS))
6046 # if !defined(HAIKU_NO_PTHREAD_GETCPUCLOCKID) && !defined(__illumos__) && \
6047      !defined(__APPLE__) && !defined(__PASE__) && !defined(__serenity__)
6048   struct timespec cpu_time;
6049   clockid_t clock_id;
6050   if (pthread_getcpuclockid (cpus[cpuNo].thread_id, &clock_id) == 0) {
6051     if (clock_gettime (clock_id, &cpu_time) == 0) {
6052       cpu_seconds = (double)cpu_time.tv_sec + cpu_time.tv_nsec / 1e9;
6053     }
6054   }
6055 # endif
6056 #endif
6057 
6058   if (cpu_seconds > 0 && cpus[cpuNo].instrCnt > 0) {
6059     int cpu_hours = (int)(cpu_seconds / 3600);
6060     int cpu_minutes = (int)((cpu_seconds - cpu_hours * 3600) / 60);
6061     int cpu_secs = (int)(cpu_seconds - (cpu_hours * 3600) - (cpu_minutes * 60));
6062     struct tm cpu_tm = {0};
6063     cpu_tm.tm_hour = cpu_hours;
6064     cpu_tm.tm_min = cpu_minutes;
6065     cpu_tm.tm_sec = cpu_secs;
6066     strftime(cpu_ftime, sizeof(cpu_ftime), "%H:%M:%S", &cpu_tm);
6067     cpu_millis = (int)((cpu_seconds - (cpu_hours * 3600) - (cpu_minutes * 60) - cpu_secs) * 1000);
6068   }
6069 
6070   (void)fflush(stderr);
6071   (void)fflush(stdout);
6072   sim_msg ("\r\n");
6073   (void)fflush(stdout);
6074   (void)fflush(stderr);
6075   sim_msg ("\r+---------------------------------+\r\n");
6076   sim_msg ("\r|         CPU %c Statistics        |\r\n", 'A' + cpuNo);
6077   sim_msg ("\r+---------------------------------+\r\n");
6078   if (cpu_seconds > 0 && cpus[cpuNo].instrCnt > 0) {
6079     sim_msg ("\r|  CPU Time Used %11s.%03d  |\r\n", cpu_ftime, cpu_millis);
6080     sim_msg ("\r+---------------------------------+\r\n");
6081   }
6082   (void)fflush(stdout);
6083   (void)fflush(stderr);
6084 #if defined(_AIX) && !defined(__PASE__)
6085   struct rusage rusage;
6086   if (!pthread_getrusage_np(cpus[cpuNo].thread_id, &rusage, PTHRDSINFO_RUSAGE_COLLECT)) {
6087     sim_msg ("\r|  Volun. CtxtSw %'15llu  |\r\n", (unsigned long long)rusage.ru_nvcsw);
6088     sim_msg ("\r|  Invol. CtxtSw %'15llu  |\r\n", (unsigned long long)rusage.ru_nivcsw);
6089     sim_msg ("\r+---------------------------------+\r\n");
6090   }
6091 #endif
6092 #if defined(WIN_STDIO)
6093   sim_msg ("\r|  cycles        %15llu  |\r\n", (unsigned long long)cpus[cpuNo].cycleCnt);
6094   sim_msg ("\r|  instructions  %15llu  |\r\n", (unsigned long long)cpus[cpuNo].instrCnt);
6095   (void)fflush(stdout);
6096   (void)fflush(stderr);
6097   sim_msg ("\r+---------------------------------+\r\n");
6098   sim_msg ("\r|  lockCnt       %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockCnt);
6099   sim_msg ("\r|  lockImmediate %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockImmediate);
6100   (void)fflush(stdout);
6101   (void)fflush(stderr);
6102   sim_msg ("\r+---------------------------------+\r\n");
6103   sim_msg ("\r|  lockWait      %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockWait);
6104   sim_msg ("\r|  lockWaitMax   %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockWaitMax);
6105   (void)fflush(stdout);
6106   (void)fflush(stderr);
6107 # if !defined(SCHED_NEVER_YIELD)
6108   sim_msg ("\r|  lockYield     %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockYield);
6109   (void)fflush(stdout);
6110   (void)fflush(stderr);
6111 # else
6112   sim_msg ("\r|  lockYield                ----  |\r\n");
6113   (void)fflush(stdout);
6114   (void)fflush(stderr);
6115 # endif /* if !defined(SCHED_NEVER_YIELD) */
6116   sim_msg ("\r+---------------------------------+");
6117   (void)fflush(stdout);
6118   (void)fflush(stderr);
6119 # if !defined(UCACHE)
6120 #  if !defined(UCACHE_STATS)
6121   sim_msg ("\r\n");
6122 #  endif
6123 # endif
6124   (void)fflush(stdout);
6125   (void)fflush(stderr);
6126 #else
6127   sim_msg ("\r|  cycles        %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].cycleCnt);
6128   sim_msg ("\r|  instructions  %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].instrCnt);
6129   (void)fflush(stdout);
6130   (void)fflush(stderr);
6131   sim_msg ("\r+---------------------------------+\r\n");
6132   sim_msg ("\r|  lockCnt       %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockCnt);
6133   sim_msg ("\r|  lockImmediate %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockImmediate);
6134   (void)fflush(stdout);
6135   (void)fflush(stderr);
6136   sim_msg ("\r+---------------------------------+\r\n");
6137   sim_msg ("\r|  lockWait      %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockWait);
6138   sim_msg ("\r|  lockWaitMax   %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockWaitMax);
6139   (void)fflush(stdout);
6140   (void)fflush(stderr);
6141 # if !defined(SCHED_NEVER_YIELD)
6142   sim_msg ("\r|  lockYield     %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockYield);
6143   (void)fflush(stdout);
6144   (void)fflush(stderr);
6145 # else
6146   sim_msg ("\r|  lockYield                ----  |\r\n");
6147   (void)fflush(stdout);
6148   (void)fflush(stderr);
6149 # endif /* if !defined(SCHED_NEVER_YIELD) */
6150   sim_msg ("\r+---------------------------------+");
6151   (void)fflush(stdout);
6152   (void)fflush(stderr);
6153 # if !defined(UCACHE)
6154 #  if !defined(UCACHE_STATS)
6155   sim_msg ("\r\n");
6156 #  endif
6157 # endif
6158   (void)fflush(stderr);
6159   (void)fflush(stdout);
6160 #endif
6161 
6162 #if defined(UCACHE_STATS)
6163   ucacheStats (cpuNo);
6164 #endif
6165 
6166 
6167 
6168 
6169 
6170 
6171 
6172 }
6173 
6174 bool running_perf_test;
6175 
6176 #if defined(THREADZ) || defined(LOCKLESS)
6177 # include <locale.h>
6178 # include "segldr.h"
6179 
6180 void perfTest (char * testName) {
     /* [previous][next][first][last][top][bottom][index][help] */
6181   running_perf_test = true;
6182 
6183   if (testName == NULL)
6184     testName = "strip.mem";
6185 
6186 # if !defined(NO_LOCALE)
6187   (void) setlocale(LC_NUMERIC, "");
6188 # endif
6189 
6190   // dps8m_init_strip
6191 # if !defined(_AIX)
6192   system_state = aligned_malloc (sizeof (struct system_state_s));
6193 # else
6194   system_state = malloc (sizeof (struct system_state_s));
6195 # endif
6196   if (!system_state)
6197     {
6198       (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
6199                      __func__, __FILE__, __LINE__);
6200 # if defined(USE_BACKTRACE)
6201 #  if defined(SIGUSR2)
6202       (void)raise(SIGUSR2);
6203       /*NOTREACHED*/ /* unreachable */
6204 #  endif /* if defined(SIGUSR2) */
6205 # endif /* if defined(USE_BACKTRACE) */
6206       abort();
6207     }
6208 # if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32) && !defined(__PASE__)
6209   if (0 == sim_free_memory || sim_free_memory >= 192000000) {
6210     if (mlock(system_state, sizeof(struct system_state_s)) == -1) {
6211       mlock_failure = true;
6212     }
6213   } else {
6214 #  if defined(TESTING)
6215     sim_warn ("Low memory - no memory locking attempted.\r\n");
6216 #  else
6217     (void)system_state;
6218 #  endif
6219   }
6220 # endif
6221   M = system_state->M;
6222 # if defined(M_SHARED)
6223   cpus = system_state->cpus;
6224 # endif /* if defined(M_SHARED) */
6225   (void) memset (cpus, 0, sizeof (cpu_state_t) * N_CPU_UNITS_MAX);
6226   for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
6227     cpus[i].switches.FLT_BASE = 2; // Some of the UnitTests assume this
6228     cpus[i].instrCnt = 0;
6229     cpus[i].cycleCnt = 0;
6230     for (int j = 0; j < N_FAULTS; j ++)
6231       cpus[i].faultCnt [j] = 0;
6232   }
6233 
6234   cpus[0].tweaks.enable_emcall = 1;
6235   opc_dev.numunits = 1;
6236   cpu_reset_unit_idx (0, false);
6237   set_cpu_cycle (& cpus[0], FETCH_cycle);
6238   mrestore (testName);
6239   _cpup = & cpus[0];
6240   threadz_sim_instr ();
6241 }
6242 #endif

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