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

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