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     mgp_process_event ();
1549 # endif /* if defined(WITH_MGP_DEV) */
1550 # if defined(WITH_NET_DEV)
1551     net_process_event ();
1552 # endif /* if defined(WITH_NET_DEV) */
1553     PNL (panel_process_event ());
1554   }
1555 #endif /* if !defined(PERF_STRIP) */
1556 
1557 // called once initialization
1558 
1559 void cpu_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1560   {
1561 // !!!! Do not use 'cpu' in this routine; usage of 'cpus' violates 'restrict'
1562 // !!!! attribute
1563 
1564     M = system_state->M;
1565 #if defined(M_SHARED)
1566     cpus = system_state->cpus;
1567 #endif /* if defined(M_SHARED) */
1568 
1569 #if !defined(SPEED)
1570     (void)memset (& watch_bits, 0, sizeof (watch_bits));
1571 #endif /* if !defined(SPEED) */
1572 
1573     set_cpu_idx (0);
1574 
1575     (void)memset (cpus, 0, sizeof (cpu_state_t) * N_CPU_UNITS_MAX);
1576 
1577 #if !defined(PERF_STRIP)
1578     get_serial_number (_cpup);
1579 
1580     ev_poll_loop = uv_default_loop ();
1581     uv_timer_init (ev_poll_loop, & ev_poll_handle);
1582     // 10 ms == 100Hz
1583     unsigned int poll_interval = sys_opts.sys_poll_interval;
1584     uv_timer_start (& ev_poll_handle, ev_poll_cb, poll_interval, poll_interval);
1585 #endif /* if !defined(PERF_STRIP) */
1586     // TODO: reset *all* other structures to zero
1587 
1588     cpu_state_t * cpup = _cpup;
1589 
1590     cpu.instrCnt = 0;
1591     cpu.cycleCnt = 0;
1592     for (int i = 0; i < N_FAULTS; i ++)
1593       cpu.faultCnt [i] = 0;
1594 
1595 #if defined(MATRIX)
1596     initializeTheMatrix ();
1597 #endif /* if defined(MATRIX) */
1598   }
1599 
1600 static void cpu_reset (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1601   {
1602     for (uint i = 0; i < N_CPU_UNITS_MAX; i ++)
1603       {
1604         cpu_reset_unit_idx (i, true);
1605       }
1606 
1607     set_cpu_idx (0);
1608 
1609 #if defined(TESTING)
1610     cpu_state_t * cpup = _cpup;
1611     sim_debug (DBG_INFO, & cpu_dev, "CPU reset: Running\r\n");
1612 #endif
1613   }
1614 
1615 static t_stat sim_cpu_reset (UNUSED DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1616   {
1617     //(void)memset (M, -1, MEMSIZE * sizeof (word36));
1618 
1619     // Fill DPS8M memory with zeros, plus a flag only visible to the emulator
1620     // marking the memory as uninitialized.
1621 
1622     cpu_reset ();
1623     return SCPE_OK;
1624   }
1625 
1626 /* Memory examine */
1627 //  t_stat examine_routine (t_val *eval_array, t_addr addr, UNIT *uptr, int32
1628 //  switches)
1629 //  Copy  sim_emax consecutive addresses for unit uptr, starting
1630 //  at addr, into eval_array. The switch variable has bit<n> set if the n'th
1631 //  letter was specified as a switch to the examine command.
1632 // Not true...
1633 
1634 static t_stat cpu_ex (t_value *vptr, t_addr addr, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
1635                       UNUSED int32 sw)
1636   {
1637     if (addr>= MEMSIZE)
1638         return SCPE_NXM;
1639     if (vptr != NULL)
1640       {
1641         *vptr = M[addr] & DMASK;
1642       }
1643     return SCPE_OK;
1644   }
1645 
1646 /* Memory deposit */
1647 
1648 static t_stat cpu_dep (t_value val, t_addr addr, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
1649                        UNUSED int32 sw)
1650   {
1651     if (addr >= MEMSIZE) return SCPE_NXM;
1652     M[addr] = val & DMASK;
1653     return SCPE_OK;
1654   }
1655 
1656 /*
1657  * register stuff ...
1658  */
1659 
1660 #if defined(M_SHARED)
1661 // scp has to have a statically allocated IC to refer to.
1662 static word18 dummy_IC;
1663 #endif
1664 
1665 static REG cpu_reg[] =
1666   {
1667     // IC must be the first; see sim_PC.
1668 #if defined(M_SHARED)
1669     { ORDATA (IC, dummy_IC,       VASIZE), 0, 0, 0 },
1670 #else
1671     { ORDATA (IC, cpus[0].PPR.IC, VASIZE), 0, 0, 0 },
1672 #endif
1673     { NULL, NULL, 0, 0, 0, 0,  NULL, NULL, 0, 0, 0 }
1674   };
1675 
1676 /*
1677  * scp interface
1678  */
1679 
1680 REG *sim_PC = & cpu_reg[0];
1681 
1682 /* CPU device descriptor */
1683 
1684 DEVICE cpu_dev =
1685   {
1686     "CPU",          // name
1687     cpu_unit,       // units
1688     cpu_reg,        // registers
1689     cpu_mod,        // modifiers
1690     N_CPU_UNITS,    // #units
1691     8,              // address radix
1692     PASIZE,         // address width
1693     1,              // addr increment
1694     8,              // data radix
1695     36,             // data width
1696     & cpu_ex,       // examine routine
1697     & cpu_dep,      // deposit routine
1698     & sim_cpu_reset,// reset routine
1699     & cpu_boot,     // boot routine
1700     NULL,           // attach routine
1701     NULL,           // detach routine
1702     NULL,           // context
1703     DEV_DEBUG,      // device flags
1704     0,              // debug control flags
1705     cpu_dt,         // debug flag names
1706     NULL,           // memory size change
1707     NULL,           // logical name
1708     NULL,           // help
1709     NULL,           // attach help
1710     NULL,           // help context
1711     NULL,           // description
1712     NULL
1713   };
1714 
1715 #if defined(M_SHARED)
1716 cpu_state_t * cpus = NULL;
1717 #else
1718 cpu_state_t cpus [N_CPU_UNITS_MAX];
1719 #endif
1720 #if defined(THREADZ) || defined(LOCKLESS)
1721 __thread cpu_state_t * restrict _cpup;
1722 #else
1723 cpu_state_t * restrict _cpup;
1724 #endif
1725 
1726 // Scan the SCUs; it one has an interrupt present, return the fault pair
1727 // address for the highest numbered interrupt on that SCU. If no interrupts
1728 // are found, return 1.
1729 
1730 // Called with SCU lock set
1731 
1732 static uint get_highest_intr (cpu_state_t *cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1733   {
1734     uint fp = 1;
1735     for (uint scu_unit_idx = 0; scu_unit_idx < N_SCU_UNITS_MAX; scu_unit_idx ++)
1736       {
1737         if (cpu.events.XIP [scu_unit_idx])
1738           {
1739             fp = scu_get_highest_intr (scu_unit_idx); // CALLED WITH SCU LOCK
1740             if (fp != 1)
1741               break;
1742           }
1743       }
1744     return fp;
1745   }
1746 
1747 bool sample_interrupts (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1748   {
1749     cpu.lufCounter = 0;
1750     for (uint scu_unit_idx = 0; scu_unit_idx < N_SCU_UNITS_MAX; scu_unit_idx ++)
1751       {
1752         if (cpu.events.XIP [scu_unit_idx])
1753           {
1754             return true;
1755           }
1756       }
1757     return false;
1758   }
1759 
1760 t_stat simh_hooks (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
1761   {
1762     int reason = 0;
1763 
1764     if (breakEnable && stop_cpu)
1765       return STOP_STOP;
1766 
1767     if (cpu.tweaks.isolts_mode == 0)
1768       {
1769         // check clock queue
1770         if (sim_interval <= 0)
1771           {
1772             reason = sim_process_event ();
1773             if ((! breakEnable) && reason == SCPE_STOP)
1774               reason = SCPE_OK;
1775             if (reason)
1776               return reason;
1777           }
1778       }
1779 
1780     sim_interval --;
1781 
1782 #if !defined(THREADZ) && !defined(LOCKLESS)
1783 // This is needed for BCE_TRAP in install scripts
1784     // sim_brk_test expects a 32 bit address; PPR.IC into the low 18, and
1785     // PPR.PSR into the high 12
1786     if (sim_brk_summ &&
1787         sim_brk_test ((cpu.PPR.IC & 0777777) |
1788                       ((((t_addr) cpu.PPR.PSR) & 037777) << 18),
1789                       SWMASK ('E')))  /* breakpoint? */
1790       return STOP_BKPT; /* stop simulation */
1791 # if !defined(SPEED)
1792     if (sim_deb_break && cpu.cycleCnt >= sim_deb_break)
1793       return STOP_BKPT; /* stop simulation */
1794 # endif /* if !defined(SPEED) */
1795 #endif /* if !defined(THREADZ) && !defined(LOCKLESS) */
1796 
1797     return reason;
1798   }
1799 
1800 #if defined(PANEL68)
1801 static void panel_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1802   {
1803     cpu_state_t * cpup = _cpup;
1804     // INITIALIZE pressed; treat at as a BOOT.
1805     if (cpu.panelInitialize && cpu.DATA_panel_s_trig_sw == 0)
1806       {
1807          // Wait for release
1808          while (cpu.panelInitialize)
1809            ;
1810          if (cpu.DATA_panel_init_sw)
1811            cpu_reset_unit_idx (ASSUME0, true); // INITIALIZE & CLEAR
1812          else
1813            cpu_reset_unit_idx (ASSUME0, false); // INITIALIZE
1814          // XXX Until a boot switch is wired up
1815          do_boot ();
1816       }
1817     // EXECUTE pressed; EXECUTE PB set, EXECUTE FAULT set
1818     if (cpu.DATA_panel_s_trig_sw == 0 &&
1819         cpu.DATA_panel_execute_sw &&  // EXECUTE button
1820         cpu.DATA_panel_scope_sw &&    // 'EXECUTE PB/SCOPE REPEAT' set to PB
1821         cpu.DATA_panel_exec_sw == 0)  // 'EXECUTE SWITCH/EXECUTE FAULT'
1822                                       //  set to FAULT
1823       {
1824         // Wait for release
1825         while (cpu.DATA_panel_execute_sw)
1826           ;
1827 
1828         if (cpu.DATA_panel_exec_sw) // EXECUTE SWITCH
1829           {
1830             cpu_reset_unit_idx (ASSUME0, false);
1831             cpu.cu.IWB = cpu.switches.data_switches;
1832             set_cpu_cycle (cpup, EXEC_cycle);
1833           }
1834          else // EXECUTE FAULT
1835           {
1836             setG7fault (current_running_cpu_idx, FAULT_EXF);
1837           }
1838       }
1839   }
1840 #endif
1841 
1842 #if defined(THREADZ) || defined(LOCKLESS)
1843 bool bce_dis_called = false;
1844 
1845 // The hypervisor CPU for the threadz model
1846 t_stat sim_instr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1847   {
1848     cpu_state_t * cpup = _cpup;
1849     t_stat reason = 0;
1850 
1851 
1852 
1853 
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     if (cpuThreadz[0].run == false)
1896           createCPUThread (0);
1897     do
1898       {
1899         // Process deferred events and breakpoints
1900         reason = simh_hooks (cpup);
1901         if (reason)
1902           {
1903             break;
1904           }
1905 
1906 
1907 
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         if (bce_dis_called) {
1933           //return STOP_STOP;
1934           reason = STOP_STOP;
1935           break;
1936         }
1937 
1938 # if !defined(PERF_STRIP)
1939 // Loop runs at 1000 Hz
1940 
1941 #  if defined(LOCKLESS)
1942         lock_iom();
1943 #  endif
1944         lock_libuv ();
1945         uv_run (ev_poll_loop, UV_RUN_NOWAIT);
1946         unlock_libuv ();
1947 #  if defined(LOCKLESS)
1948         unlock_iom();
1949 #  endif
1950         PNL (panel_process_event ());
1951 
1952         int con_unit_idx = check_attn_key ();
1953         if (con_unit_idx != -1)
1954           console_attn_idx (con_unit_idx);
1955 # endif
1956 
1957 # if defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
1958         struct timespec next_time;
1959         clock_gettime (CLOCK_REALTIME, & next_time);
1960         next_time.tv_nsec += 1000l * 1000l;
1961         if (next_time.tv_nsec >= 1000l * 1000l *1000l)
1962           {
1963             next_time.tv_nsec -= 1000l * 1000l *1000l;
1964             next_time.tv_sec  += (time_t) 1;
1965           }
1966         struct timespec new_time;
1967         do
1968           {
1969             pthread_mutex_lock (& iom_start_lock);
1970             pthread_cond_timedwait (& iomCond,
1971                                     & iom_start_lock,
1972                                     & next_time);
1973             pthread_mutex_unlock (& iom_start_lock);
1974             lock_iom();
1975             lock_libuv ();
1976 
1977             iomProcess ();
1978 
1979             unlock_libuv ();
1980             unlock_iom ();
1981 
1982             clock_gettime (CLOCK_REALTIME, & new_time);
1983           }
1984         while ((next_time.tv_sec == new_time.tv_sec) ? (next_time.tv_nsec > new_time.tv_nsec) : \
1985                                                        (next_time.tv_sec  > new_time.tv_sec));
1986 # else
1987         sim_usleep (1000); // 1000 us == 1 ms == 1/1000 sec.
1988 # endif
1989       }
1990     while (reason == 0); //-V654
1991 
1992     for (uint cpuNo = 0; cpuNo < N_CPU_UNITS_MAX; cpuNo ++) {
1993       cpuStats (cpuNo);
1994     }
1995 
1996 # if defined(TESTING)
1997     HDBGPrint ();
1998 # endif
1999     return reason;
2000   }
2001 #endif
2002 
2003 #if !defined(THREADZ) && !defined(LOCKLESS)
2004 static uint fast_queue_subsample = 0;
2005 #endif
2006 
2007 //
2008 // Okay, let's treat this as a state machine
2009 //
2010 //  INTERRUPT_cycle
2011 //     clear interrupt, load interrupt pair into instruction buffer
2012 //     set INTERRUPT_EXEC_cycle
2013 //  INTERRUPT_EXEC_cycle
2014 //     execute instruction in instruction buffer
2015 //     if (! transfer) set INTERUPT_EXEC2_cycle
2016 //     else set FETCH_cycle
2017 //  INTERRUPT_EXEC2_cycle
2018 //     execute odd instruction in instruction buffer
2019 //     set INTERUPT_EXEC2_cycle
2020 //
2021 //  FAULT_cycle
2022 //     fetch fault pair into instruction buffer
2023 //     set FAULT_EXEC_cycle
2024 //  FAULT_EXEC_cycle
2025 //     execute instructions in instruction buffer
2026 //     if (! transfer) set FAULT_EXE2_cycle
2027 //     else set FETCH_cycle
2028 //  FAULT_EXEC2_cycle
2029 //     execute odd instruction in instruction buffer
2030 //     set FETCH_cycle
2031 //
2032 //  FETCH_cycle
2033 //     fetch instruction into instruction buffer
2034 //     set EXEC_cycle
2035 //
2036 //  EXEC_cycle
2037 //     execute instruction in instruction buffer
2038 //     if (repeat conditions) keep cycling
2039 //     if (pair) set EXEC2_cycle
2040 //     else set FETCH_cycle
2041 //  EXEC2_cycle
2042 //     execute odd instruction in instruction buffer
2043 //
2044 //  XEC_cycle
2045 //     load instruction into instruction buffer
2046 //     set EXEC_cycle
2047 //
2048 //  XED_cycle
2049 //     load instruction pair into instruction buffer
2050 //     set EXEC_cycle
2051 //
2052 // other extant cycles:
2053 //  ABORT_cycle
2054 
2055 #if defined(THREADZ) || defined(LOCKLESS)
2056 void * cpu_thread_main (void * arg)
     /* [previous][next][first][last][top][bottom][index][help] */
2057   {
2058     int myid = * (int *) arg;
2059     set_cpu_idx ((uint) myid);
2060     unsigned char umyid = (unsigned char)toupper('a' + (int)myid);
2061     char thread_name[SIR_MAXPID] = {0};
2062     char temp_thread_name[SIR_MAXPID] = {0};
2063 
2064     _cpup->thread_id = pthread_self();
2065 
2066     if (realtime_ok) {
2067       set_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2068       check_realtime_priority (pthread_self(), realtime_max_priority() - 1);
2069     } else {
2070 # if !defined(__QNX__)
2071       (void)sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
2072 # endif
2073     }
2074     _sir_snprintf_trunc(thread_name, SIR_MAXPID, "CPU %c", (unsigned int)umyid);
2075     if (!_sir_setthreadname(thread_name) || !_sir_getthreadname(temp_thread_name))
2076       (void)sir_info ("%s thread created (TID " SIR_TIDFORMAT ")",
2077         thread_name, PID_CAST _sir_gettid());
2078     else
2079       (void)sir_info ("Thread created (TID " SIR_TIDFORMAT ")",
2080         PID_CAST _sir_gettid());
2081 # if defined(TESTING) && defined(__APPLE__) && defined(__MACH__)
2082     (void)sir_info ("Mach thread ID: 0x%x", pthread_mach_thread_np(pthread_self()));
2083 # endif /* if defined(TESTING) && defined(__APPLE__) && defined(__MACH__) */
2084     bool warned = false;
2085     if (realtime_ok) {
2086       if (myid + 2 > nprocs) {
2087         (void)sir_warn ("Total number of supervisor and CPU threads (%lu) exceeds available host parallelism (%lu)!",
2088                         (unsigned long)(myid) + 2, (unsigned long)nprocs);
2089         warned = true;
2090       }
2091       if (!warned && nprocs >= 2 && ncores >= 1 && nprocs >= ncores && myid + 2 > ncores) {
2092         (void)sir_warn ("Total number of supervisor and CPU threads (%lu) exceeds physical host core count (%lu)!",
2093                         (unsigned long)(myid) + 2, (unsigned long)ncores);
2094       }
2095     } else {
2096       if (myid + 1 > nprocs) {
2097         (void)sir_warn ("Total number of CPU threads (%lu) exceeds available host parallelism (%lu)!",
2098                         (unsigned long)(myid) + 1, (unsigned long)nprocs);
2099         warned = true;
2100       }
2101       if (!warned && ncores >= 1 && nprocs >= ncores && myid + 1 > ncores) {
2102         (void)sir_warn ("Total number of CPU threads (%lu) exceeds physical host core count (%lu)!",
2103                         (unsigned long)(myid) + 1, (unsigned long)ncores);
2104       }
2105     }
2106     setSignals ();
2107     threadz_sim_instr ();
2108     return NULL;
2109   }
2110 #endif // THREADZ
2111 
2112 NO_RETURN
2113 static void do_LUF_fault (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2114   {
2115     CPT (cpt1U, 16); // LUF
2116     cpu.lufCounter  = 0;
2117     cpu.lufOccurred = false;
2118 // This is a hack to fix ISOLTS 776. ISOLTS checks that the TR has
2119 // decremented by the LUF timeout value. To implement this, we set
2120 // the TR to the expected value.
2121 
2122 // LUF  time
2123 //  0    2ms
2124 //  1    4ms
2125 //  2    8ms
2126 //  3   16ms
2127 // units
2128 // you have: 2ms
2129 // units
2130 // You have: 512000Hz
2131 // You want: 1/2ms
2132 //    * 1024
2133 //    / 0.0009765625
2134 //
2135 //  TR = 1024 << LUF
2136     if (cpu.tweaks.isolts_mode)
2137       cpu.shadowTR = (word27) cpu.TR0 - (1024u << (is_priv_mode (cpup) ? 4 : cpu.CMR.luf));
2138 
2139 // The logic fails for test 785:
2140 // set slave mode, LUF time 16ms.
2141 // loop for 15.9 ms.
2142 // set master mode.
2143 // loop for 15.9 ms. The LUF should be noticed, and lufOccurred set.
2144 // return to slave mode. The LUF should fire, with the timer register
2145 // being set for 31.1 ms.
2146 
2147 // XXX: Without accurate cycle timing or simply fudging the results,
2148 // I don't see how to fix this one.
2149 
2150     doFault (FAULT_LUF, fst_zero, "instruction cycle lockup");
2151   }
2152 
2153 #if !defined(THREADZ) && !defined(LOCKLESS)
2154 # define threadz_sim_instr sim_instr
2155 #endif
2156 
2157 /*
2158  * addr_modes_e get_addr_mode()
2159  *
2160  * Report what mode the CPU is in.
2161  * This is determined by examining a couple of IR flags.
2162  *
2163  * TODO: get_addr_mode() probably belongs in the CPU source file.
2164  *
2165  */
2166 
2167 static void set_temporary_absolute_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2168   {
2169     CPT (cpt1L, 20); // set temp. abs. mode
2170     cpu.secret_addressing_mode = true;
2171     cpu.cu.XSF = false;
2172 sim_debug (DBG_TRACEEXT, & cpu_dev, "set_temporary_absolute_mode bit 29 sets XSF to 0\r\n");
2173     //cpu.went_appending = false;
2174   }
2175 
2176 static bool clear_temporary_absolute_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
2177   {
2178     CPT (cpt1L, 21); // clear temp. abs. mode
2179     cpu.secret_addressing_mode = false;
2180     return cpu.cu.XSF;
2181     //return cpu.went_appending;
2182   }
2183 
2184 #if defined(THREADZ) || defined(LOCKLESS)
2185 static const int workAllocationQuantum = 64;
2186 static const int syncClockModePollRate = 64;
2187 static const int masterCycleCntlimit = 2048;
2188 
2189 void becomeClockMaster (uint cpuNum) {
     /* [previous][next][first][last][top][bottom][index][help] */
2190   //HDBGNote (cpup, __func__, "entry%s.", "");
2191 # ifdef SYNCTEST
2192   sim_printf ("CPU%c %s entry\r\n", cpuNum + 'A', __func__);
2193   allocCount = 0;
2194 # endif
2195 
2196   //lockSync ();  // Only one CPU can manage the sync at a time; if more then one CPU is started
2197   // at once, the second will hang here until the first is finished. If this proves to be
2198   // a problem, then we need a mechanism for the second one to join the sync parade.
2199   if (syncClockMode) {
2200     // Someone else is already clock master; let them rule
2201     //sim_printf ("%s: someone else beat us here.\r\n", __func__);
2202     //HDBGNote (cpup, __func__, "someone else beat us here.%s", "");
2203     return;
2204   }
2205 
2206   syncClockModeMasterIdx = cpuNum;
2207   cpu_state_t * cpup = & cpus[cpuNum];
2208   cpu.syncClockModeMaster = true; // This CPU is the clock master
2209   cpu.masterCycleCnt = 0;
2210   cpu.syncClockModeCache = true;
2211   for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
2212     if (i != cpuNum) { // not the new master
2213       cpus[i].workAllocation = 0;
2214       __asm volatile ("");
2215       atomic_thread_fence (memory_order_seq_cst); //-V779
2216       if (cpus[i].inMultics && ! cpus[i].isSlave) { // it is up but not yet a slave
2217         cpus[i].syncClockModePoll = 0;
2218         __asm volatile ("");
2219         atomic_thread_fence (memory_order_seq_cst);
2220         cpus[i].becomeSlave = true;
2221         __asm volatile ("");
2222         atomic_thread_fence (memory_order_seq_cst);
2223       } // candidate
2224     } // not target CPU
2225   } // every CPU
2226 
2227   __asm volatile ("");
2228   atomic_thread_fence (memory_order_seq_cst);
2229   syncClockMode = true;
2230 
2231   __asm volatile ("");
2232   atomic_thread_fence (memory_order_seq_cst);
2233   //HDBGNote (cpup, __func__, "becomes clock master%s", "");
2234 } // becomeClockMaster
2235 
2236 void giveupClockMaster (cpu_state_t * cpup) {
     /* [previous][next][first][last][top][bottom][index][help] */
2237   //HDBGNote (cpup, __func__, "entry%s", "");
2238 # ifdef SYNCTEST
2239   //HDBGNote (cpup, __func__, "alloc count %d", allocCount);
2240   sim_printf ("CPU%c %s entry\r\n", cpu.cpuIdx + 'A', __func__);
2241   sim_printf ("CPU%c Alloc count %d\r\n", cpu.cpuIdx + 'A', allocCount);
2242 # endif
2243   __asm volatile ("");
2244   cpu.syncClockModeMaster = false; //-V779
2245   __asm volatile ("");
2246   syncClockMode = false; // Free the other processors
2247   __asm volatile ("");
2248   for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
2249     cpus[i].syncClockModeCache = false;
2250   }
2251   __asm volatile ("");
2252   atomic_thread_fence (memory_order_seq_cst);
2253   //unlockSync (); // And let someone else grab sync mode
2254 }
2255 #endif
2256 
2257 t_stat threadz_sim_instr (void)
     /* [previous][next][first][last][top][bottom][index][help] */
2258   {
2259     cpu_state_t * cpup = _cpup;
2260   //cpu.have_tst_lock = false;
2261 
2262 #if !defined(SCHED_NEVER_YIELD)
2263     unsigned long long lockYieldAll     = 0;
2264 #endif /* if !defined(SCHED_NEVER_YIELD) */
2265     unsigned long long lockWaitMaxAll   = 0;
2266     unsigned long long lockWaitAll      = 0;
2267     unsigned long long lockImmediateAll = 0;
2268     unsigned long long lockCntAll       = 0;
2269     unsigned long long instrCntAll      = 0;
2270     unsigned long long cycleCntAll      = 0;
2271 
2272     t_stat reason = 0;
2273 
2274 #if !defined(THREADZ) && !defined(LOCKLESS)
2275     set_cpu_idx (0);
2276 # if defined(M_SHARED)
2277 // scp needs to have the IC statically allocated, so a placeholder was
2278 // created.
2279 
2280     // Copy the placeholder so the IC can be set
2281     cpus [0].PPR.IC = dummy_IC;
2282 # endif
2283 
2284 #endif
2285 
2286     // This allows long jumping to the top of the state machine
2287     int val = setjmp (cpu.jmpMain);
2288 
2289     switch (val)
2290       {
2291         case JMP_ENTRY:
2292         case JMP_REENTRY:
2293             reason = 0;
2294             break;
2295         case JMP_SYNC_FAULT_RETURN:
2296             set_cpu_cycle (cpup, SYNC_FAULT_RTN_cycle);
2297             break;
2298         case JMP_STOP:
2299             reason = STOP_STOP;
2300             goto leave;
2301         case JMP_REFETCH:
2302 
2303             // Not necessarily so, but the only times
2304             // this path is taken is after an RCU returning
2305             // from an interrupt, which could only happen if
2306             // was xfer was false; or in a DIS cycle, in
2307             // which case we want it false so interrupts
2308             // can happen.
2309             cpu.wasXfer = false;
2310 
2311             set_cpu_cycle (cpup, FETCH_cycle);
2312             break;
2313         case JMP_RESTART:
2314             set_cpu_cycle (cpup, EXEC_cycle);
2315             break;
2316         case JMP_FORCE_RESTART:
2317           // The configuration has been changed on a CPU that
2318           // has been started and in DIS idle. DIS sees the
2319           // forceRestart flag and longjmps here.
2320           // cpu_reset_unit_idx will update the CPU state to
2321           // match the new configuration and set the
2322           // state to enter DIS.
2323           cpu_reset_unit_idx (current_running_cpu_idx, false);
2324 #if defined(THREADZ) || defined(LOCKLESS)
2325           // Were we a clock master?
2326           if (syncClockMode && syncClockModeMasterIdx == current_running_cpu_idx)
2327             giveupClockMaster (cpup);
2328 #endif
2329           break;
2330         default:
2331           sim_warn ("longjmp value of %d unhandled\r\n", val);
2332             goto leave;
2333       }
2334 
2335     // Main instruction fetch/decode loop
2336 
2337     DCDstruct * ci = & cpu.currentInstruction;
2338 
2339     if (cpu.restart)
2340       {
2341         set_cpu_cycle (cpup, FAULT_cycle);
2342       }
2343 
2344 #if defined(THREADZ) || defined(LOCKLESS)
2345     // These are used to signal createCPUThread that the "round
2346     // up the slaves" code above has run; they must be set
2347     // after that. This line will prevent the compiler from
2348     // hoisting them.
2349     __asm volatile ("");
2350     cpu.executing = true; //-V779
2351     if (cpu.tweaks.isolts_mode) {
2352       ;
2353     } else {
2354       cpu.inMultics = true;
2355     }
2356 #endif
2357 
2358     do
2359       {
2360 
2361         reason = 0;
2362 
2363 #if !defined(THREADZ) && !defined(LOCKLESS)
2364         // Process deferred events and breakpoints
2365         reason = simh_hooks (cpup);
2366         if (reason)
2367           {
2368             break;
2369           }
2370 
2371 // The event poll is consuming 40% of the CPU according to pprof.
2372 // We only want to process at 100Hz; yet we are testing at ~1MHz.
2373 // If we only test every 1000 cycles, we shouldn't miss by more then
2374 // 10%...
2375 
2376         //if ((! cpu.wasInhibited) && fast_queue_subsample ++ > 1024) // ~ 1KHz
2377         //static uint fastQueueSubsample = 0;
2378         if (fast_queue_subsample ++ > sys_opts.sys_poll_check_rate) // ~ 1KHz
2379           {
2380             fast_queue_subsample = 0;
2381 # if defined(CONSOLE_FIX)
2382 #  if defined(THREADZ) || defined(LOCKLESS)
2383             lock_libuv ();
2384 #  endif
2385 # endif
2386             uv_run (ev_poll_loop, UV_RUN_NOWAIT);
2387 # if defined(CONSOLE_FIX)
2388 #  if defined(THREADZ) || defined(LOCKLESS)
2389             unlock_libuv ();
2390 #  endif
2391 # endif
2392             PNL (panel_process_event ());
2393           }
2394 #endif // ! THREADZ
2395 
2396         cpu.cycleCnt ++;
2397 
2398 #if defined(THREADZ)
2399         // If we faulted somewhere with the memory lock set, clear it.
2400         unlock_mem_force ();
2401 
2402         // wait on run/switch
2403         cpuRunningWait ();
2404 #endif // THREADZ
2405 #if defined(LOCKLESS)
2406         core_unlock_all (cpup);
2407 #endif // LOCKLESS
2408 
2409 #if !defined(LOCKLESS)
2410         int con_unit_idx = check_attn_key ();
2411         if (con_unit_idx != -1)
2412           console_attn_idx (con_unit_idx);
2413 #endif
2414 
2415 #if !defined(THREADZ) && !defined(LOCKLESS)
2416         if (cpu.tweaks.isolts_mode)
2417           {
2418             if (cpu.cycle != FETCH_cycle)
2419               {
2420                 // Sync. the TR with the emulator clock.
2421                 cpu.rTRlsb ++;
2422                 if (cpu.rTRlsb >= 4)
2423                   {
2424                     cpu.rTRlsb   = 0;
2425                     cpu.shadowTR = (cpu.shadowTR - 1) & MASK27;
2426                     if (cpu.shadowTR == 0) // passing through 0...
2427                       {
2428                         if (cpu.tweaks.tro_enable)
2429                           setG7fault (current_running_cpu_idx, FAULT_TRO);
2430                       }
2431                   }
2432               }
2433           }
2434 #endif
2435 
2436 // Check for TR underflow. The TR is stored in a uint32_t, but is 27 bits wide.
2437 // The TR update code decrements the TR; if it passes through 0, the high bits
2438 // will be set.
2439 
2440 // If we assume a 1 MIPS reference platform, the TR would be decremented every
2441 // two instructions (1/2 MHz)
2442 
2443 
2444 
2445 
2446 
2447 
2448 # define TR_RATE 2
2449 
2450         //cpu.rTR      -= cpu.rTRticks / TR_RATE;
2451         // ubsan
2452         cpu.rTR = (word27) (((word27s) cpu.rTR) - (word27s) (cpu.rTRticks / TR_RATE));
2453         cpu.rTRticks %= TR_RATE;
2454 
2455 
2456 
2457         if (cpu.rTR & ~MASK27)
2458           {
2459             cpu.rTR &= MASK27;
2460             if (cpu.tweaks.tro_enable) {
2461               setG7fault (current_running_cpu_idx, FAULT_TRO);
2462             }
2463           }
2464 
2465         sim_debug (DBG_CYCLE, & cpu_dev, "Cycle is %s\r\n",
2466                    cycle_str (cpu.cycle));
2467 
2468         switch (cpu.cycle)
2469           {
2470             case INTERRUPT_cycle:
2471               {
2472                 CPT (cpt1U, 0); // Interrupt cycle
2473                 // In the INTERRUPT CYCLE, the processor safe-stores
2474                 // the Control Unit Data (see Section 3) into
2475                 // program-invisible holding registers in preparation
2476                 // for a Store Control Unit (scu) instruction, enters
2477                 // temporary absolute mode, and forces the current
2478                 // ring of execution C(PPR.PRR) to
2479                 // 0. It then issues an XEC system controller command
2480                 // to the system controller on the highest priority
2481                 // port for which there is a bit set in the interrupt
2482                 // present register.
2483 
2484                 uint intr_pair_addr = get_highest_intr (cpup);
2485 #if defined(TESTING)
2486                 HDBGIntr (intr_pair_addr, "");
2487 #endif
2488                 cpu.cu.FI_ADDR = (word5) (intr_pair_addr / 2);
2489                 cu_safe_store (cpup);
2490                 // XXX the whole interrupt cycle should be rewritten as an xed
2491                 // instruction pushed to IWB and executed
2492 
2493                 CPT (cpt1U, 1); // safe store complete
2494                 // Temporary absolute mode
2495                 set_temporary_absolute_mode (cpup);
2496 
2497                 // Set to ring 0
2498                 cpu.PPR.PRR = 0;
2499                 cpu.TPR.TRR = 0;
2500 
2501                 sim_debug (DBG_INTR, & cpu_dev, "intr_pair_addr %u flag %d\r\n",
2502                            intr_pair_addr, cpu.interrupt_flag);
2503 #if !defined(SPEED)
2504                 if_sim_debug (DBG_INTR, & cpu_dev)
2505                     traceInstruction (DBG_INTR);
2506 #endif /* if !defined(SPEED) */
2507                 // Check that an interrupt is actually pending
2508                 if (cpu.interrupt_flag)
2509                   {
2510                     CPT (cpt1U, 2); // interrupt pending
2511                     // clear interrupt, load interrupt pair into instruction
2512                     // buffer; set INTERRUPT_EXEC_cycle.
2513 
2514                     // In the h/w this is done later, but doing it now allows
2515                     // us to avoid clean up for no interrupt pending.
2516 
2517                     if (intr_pair_addr != 1) // no interrupts
2518                       {
2519                         CPT (cpt1U, 3); // interrupt identified
2520 
2521                         // get interrupt pair
2522                         core_read2 (cpup, intr_pair_addr,
2523                                     & cpu.cu.IWB, & cpu.cu.IRODD, __func__);
2524 #if defined(TESTING)
2525                         HDBGMRead (intr_pair_addr, cpu.cu.IWB, "intr even");
2526                         HDBGMRead (intr_pair_addr + 1, cpu.cu.IRODD, "intr odd");
2527 #endif
2528                         cpu.cu.xde = 1;
2529                         cpu.cu.xdo = 1;
2530                         cpu.isExec = true;
2531                         cpu.isXED  = true;
2532 
2533                         CPT (cpt1U, 4); // interrupt pair fetched
2534                         cpu.interrupt_flag = false;
2535                         set_cpu_cycle (cpup, INTERRUPT_EXEC_cycle);
2536                         break;
2537                       } // int_pair != 1
2538                   } // interrupt_flag
2539 
2540                 // If we get here, there was no interrupt
2541 
2542                 CPT (cpt1U, 5); // interrupt pair spurious
2543                 cpu.interrupt_flag = false;
2544                 clear_temporary_absolute_mode (cpup);
2545                 // Restores addressing mode
2546                 cu_safe_restore (cpup);
2547                 // We can only get here if wasXfer was
2548                 // false, so we can assume it still is.
2549                 cpu.wasXfer = false;
2550 // The only place cycle is set to INTERRUPT_cycle in FETCH_cycle; therefore
2551 // we can safely assume that is the state that should be restored.
2552                 set_cpu_cycle (cpup, FETCH_cycle);
2553               }
2554               break;
2555 
2556             case FETCH_cycle:
2557 #if defined(PANEL68)
2558                 (void)memset (cpu.cpt, 0, sizeof (cpu.cpt));
2559 #endif
2560                 CPT (cpt1U, 13); // fetch cycle
2561 
2562                 PNL (L68_ (cpu.INS_FETCH = false;))
2563 
2564 // "If the interrupt inhibit bit is not set in the current instruction
2565 // word at the point of the next sequential instruction pair virtual
2566 // address formation, the processor samples the [group 7 and interrupts]."
2567 
2568 // Since XEx/RPx may overwrite IWB, we must remember
2569 // the inhibit bits (cpu.wasInhibited).
2570 
2571 // If the instruction pair virtual address being formed is the result of a
2572 // transfer of control condition or if the current instruction is
2573 // Execute (xec), Execute Double (xed), Repeat (rpt), Repeat Double (rpd),
2574 // or Repeat Link (rpl), the group 7 faults and interrupt present lines are
2575 // not sampled.
2576 
2577 // Group 7 Faults
2578 //
2579 // Shutdown
2580 //
2581 // An external power shutdown condition has been detected. DC POWER shutdown
2582 // will occur in approximately one millisecond.
2583 //
2584 // Timer Runout
2585 //
2586 // The timer register has decremented to or through the value zero. If the
2587 // processor is in privileged mode or absolute mode, recognition of this fault
2588 // is delayed until a return to normal mode or BAR mode. Counting in the timer
2589 // register continues.
2590 //
2591 // Connect
2592 //
2593 // A connect signal ($CON strobe) has been received from a system controller.
2594 // This event is to be distinguished from a Connect Input/Output Channel (cioc)
2595 // instruction encountered in the program sequence.
2596 
2597                 // check BAR bound and raise store fault if above
2598                 // pft 04d 10070, ISOLTS-776 06ad
2599                 if (get_bar_mode (cpup))
2600                     get_BAR_address (cpup, cpu.PPR.IC);
2601 
2602                 // Don't check timer runout if privileged
2603                 // ISOLTS-776 04bcf, 785 02c
2604                 // (but do if in a DIS instruction with bit28 clear)
2605                 bool tmp_priv_mode = is_priv_mode (cpup);
2606                 bool is_dis        = cpu.currentInstruction.opcode  == 0616 &&
2607                                      cpu.currentInstruction.opcodeX == 0;
2608                 bool noCheckTR     = tmp_priv_mode &&
2609                                      !(is_dis && GET_I (cpu.cu.IWB) == 0);
2610 
2611                 if (is_dis)
2612                   {
2613                     // take interrupts and g7 faults as long as
2614                     // last instruction is DIS (??)
2615                     cpu.interrupt_flag = sample_interrupts (cpup);
2616                     cpu.g7_flag =
2617                               noCheckTR ? bG7PendingNoTRO (cpup) : bG7Pending (cpup);
2618                   }
2619                 else if (! (cpu.cu.xde | cpu.cu.xdo |
2620                        cpu.cu.rpt | cpu.cu.rd | cpu.cu.rl))
2621                   {
2622                     if ((!cpu.wasInhibited) &&
2623                         (cpu.PPR.IC & 1) == 0 &&
2624                         (! cpu.wasXfer))
2625                       {
2626                         CPT (cpt1U, 14); // sampling interrupts
2627                         cpu.interrupt_flag = sample_interrupts (cpup);
2628                         cpu.g7_flag =
2629                           noCheckTR ? bG7PendingNoTRO (cpup) : bG7Pending (cpup);
2630                       }
2631                     cpu.wasInhibited = false;
2632                   }
2633                 else
2634                   {
2635                     // XEx at an odd location disables interrupt sampling
2636                     // also for the next instruction pair. ISOLTS-785 02g,
2637                     // 776 04g
2638                     // Set the inhibit flag
2639                     // (I assume RPx behaves in the same way)
2640                     if ((cpu.PPR.IC & 1) == 1)
2641                       {
2642                         cpu.wasInhibited = true;
2643                       }
2644                   }
2645 
2646 // Multics executes a CPU connect instruction (which should eventually cause a
2647 // connect fault) while interrupts are inhibited and an IOM interrupt is
2648 // pending. Multics then executes a DIS instruction (Delay Until Interrupt
2649 // Set). This should cause the processor to "sleep" until an interrupt is
2650 // signaled. The DIS instruction sees that an interrupt is pending, sets
2651 // cpu.interrupt_flag to signal that the CPU to service the interrupt and
2652 // resumes the CPU.
2653 //
2654 // The CPU state machine sets up to fetch the next instruction. If checks to
2655 // see if this instruction should check for interrupts or faults according to
2656 // the complex rules (interrupts inhibited, even address, not RPT or XEC,
2657 // etc.); it this case, the test fails as the next instruction is at an odd
2658 // address. If the test had passed, the cpu.interrupt_flag would be set or
2659 // cleared depending on the pending interrupt state data, AND the cpu.g7_flag
2660 // would be set or cleared depending on the faults pending data (in this case,
2661 // the connect fault).
2662 //
2663 // Because the flags were not updated, after the test, cpu.interrupt_flag is
2664 // set (since the DIS instruction set it) and cpu.g7_flag is not set.
2665 //
2666 // Next, the CPU sees the that cpu.interrupt flag is set, and starts the
2667 // interrupt cycle despite the fact that a higher priority g7 fault is pending.
2668 
2669 // To fix this, check (or recheck) g7 if an interrupt is going to be faulted.
2670 // Either DIS set interrupt_flag and FETCH_cycle didn't so g7 needs to be
2671 // checked, or FETCH_cycle did check it when it set interrupt_flag in which
2672 // case it is being rechecked here. It is [locally] idempotent and light
2673 // weight, so this should be okay.
2674 
2675 // not necessary any more because of is_dis logic
2676 
2677 
2678 
2679 
2680                 if (cpu.g7_flag)
2681                   {
2682                       cpu.g7_flag        = false;
2683                       cpu.interrupt_flag = false;
2684                       sim_debug (DBG_CYCLE, & cpu_dev,
2685                                  "call doG7Fault (%d)\r\n", !noCheckTR);
2686                       doG7Fault (cpup, !noCheckTR);
2687                   }
2688                 if (cpu.interrupt_flag)
2689                   {
2690 // This is the only place cycle is set to INTERRUPT_cycle; therefore
2691 // return from interrupt can safely assume the it should set the cycle
2692 // to FETCH_cycle.
2693                     CPT (cpt1U, 15); // interrupt
2694                     set_cpu_cycle (cpup, INTERRUPT_cycle);
2695                     break;
2696                   }
2697 
2698 // "While in absolute mode or privileged mode the lockup fault is signalled at
2699 // the end of the time limit set in the lockup timer but is not recognized
2700 // until the 32 millisecond limit. If the processor returns to normal mode or
2701 // BAR mode after the fault has been signalled but before the 32 millisecond
2702 // limit, the fault is recognized before any instruction in the new mode is
2703 // executed."
2704 
2705           /*FALLTHRU*/ /* fall through */ /* fallthrough */
2706           case PSEUDO_FETCH_cycle:
2707 
2708             tmp_priv_mode = is_priv_mode (cpup);
2709             if (! (luf_flag && tmp_priv_mode))
2710               cpu.lufCounter ++;
2711 
2712             if (cpu.lufCounter > luf_limits[cpu.CMR.luf])
2713               {
2714                 if (tmp_priv_mode)
2715                   {
2716                     // In priv. mode the LUF is noted but not executed
2717                     cpu.lufOccurred = true;
2718                   }
2719                 else
2720                   {
2721                     do_LUF_fault (cpup);
2722                   }
2723               } // lufCounter > luf_limit
2724 
2725             // After 32ms, the LUF fires regardless of priv.
2726             if (cpu.lufCounter > luf_limits[4])
2727               {
2728                 do_LUF_fault (cpup);
2729               }
2730 
2731             // If the LUF occurred in priv. mode and we left priv. mode,
2732             // fault.
2733             if (! tmp_priv_mode && cpu.lufOccurred)
2734               {
2735                 do_LUF_fault (cpup);
2736               }
2737 
2738 
2739 
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             if (cpu.cycle == PSEUDO_FETCH_cycle)
2770               {
2771                 cpu.apu.lastCycle    = INSTRUCTION_FETCH;
2772                 cpu.cu.XSF           = 0;
2773                 cpu.cu.TSN_VALID [0] = 0;
2774                 cpu.TPR.TSR          = cpu.PPR.PSR;
2775                 cpu.TPR.TRR          = cpu.PPR.PRR;
2776                 cpu.wasInhibited     = false;
2777               }
2778             else
2779               {
2780                 CPT (cpt1U, 20); // not XEC or RPx
2781                 cpu.isExec               = false;
2782                 cpu.isXED                = false;
2783                 // fetch next instruction into current instruction struct
2784                 //clr_went_appending (); // XXX not sure this is the right
2785                                          //  place
2786                 cpu.cu.XSF               = 0;
2787 sim_debug (DBG_TRACEEXT, & cpu_dev, "fetchCycle bit 29 sets XSF to 0\r\n");
2788                 cpu.cu.TSN_VALID [0]     = 0;
2789                 cpu.TPR.TSR              = cpu.PPR.PSR;
2790                 cpu.TPR.TRR              = cpu.PPR.PRR;
2791                 PNL (cpu.prepare_state   = ps_PIA);
2792                 PNL (L68_ (cpu.INS_FETCH = true;))
2793                 fetchInstruction (cpup, cpu.PPR.IC);
2794               }
2795 
2796             CPT (cpt1U, 21); // go to exec cycle
2797             advanceG7Faults (cpup);
2798             set_cpu_cycle (cpup, EXEC_cycle);
2799             break;
2800 
2801           case EXEC_cycle:
2802           case FAULT_EXEC_cycle:
2803           case INTERRUPT_EXEC_cycle:
2804             {
2805 #if defined(THREADZ) || defined(LOCKLESS)
2806 
2807               // Have we been told to becomes a slave?
2808               if (UNLIKELY (cpu.becomeSlave)) {
2809                 cpu.becomeSlave = false;
2810                 // Wait for the master to wake up
2811                 while (! syncClockMode) {
2812                   sim_usleep (1);
2813                 }
2814                 // Force the poll below
2815                 cpu.syncClockModePoll = 0;
2816               }
2817 
2818               // Ready to check sync clock mode?
2819               if (cpu.syncClockModeCache || --cpu.syncClockModePoll <= 0) {
2820 
2821                 cpu.syncClockModePoll = cpu.tweaks.isolts_mode ? 1 : syncClockModePollRate;
2822 
2823                 // Are the clocks synchronized?
2824                 if (syncClockMode) {
2825 
2826                   // Remember that this thread is synchronized
2827                   cpu.syncClockModeCache = true;
2828 
2829                   // Are we the master?
2830                   if (syncClockModeMasterIdx == current_running_cpu_idx) {
2831 
2832                     // Master
2833                     cpu.masterCycleCnt ++;
2834                     if (cpu.masterCycleCnt > masterCycleCntlimit) {
2835 # ifdef SYNCTEST
2836                       sim_printf ("too many cycles\r\n");
2837 # endif
2838                       giveupClockMaster (cpup);
2839                       goto bail;
2840                     }
2841 
2842                     // Have we used up our allocation?
2843                     if (cpu.workAllocation <= 0) {
2844 # ifdef SYNCTEST
2845                       allocCount ++;
2846 # endif
2847 
2848                       // If sim_usleep(1) actually takes only 1 us, then this
2849                       // will be at least 2 seconds.
2850                       //int64_t waitTimeout = 2000000;
2851                       // Quick testing shows it is closer to 2 minutes...
2852                       int64_t waitTimeout = 100000;
2853 
2854                       // Has everyone used up their allocation?
2855                       while (1) {  // while others still have work to do
2856                         bool alldone = true;
2857                         for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
2858                           if (cpus[i].inMultics && cpus[i].workAllocation > 0) {
2859                             wakeCPU (i);
2860                             alldone = false;
2861                             //break;
2862                           } // up and working
2863                         } // cpus
2864                         if (alldone) {
2865                           // Everyone has used up there allocations; dole out some more work
2866                           for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
2867                             if (cpus[i].inMultics) {
2868                               cpus[i].workAllocation += cpu.tweaks.isolts_mode ? 1 : workAllocationQuantum;
2869                               wakeCPU (i);
2870                             }
2871                           }
2872                           break; // while (1)
2873                         } // alldone
2874                         if (waitTimeout-- < 0) {
2875                           // timed out waiting for everyone to finish their
2876                           // work allocation; assume something is fouled.
2877                           sim_printf ("Clock master CPU %c timed out\r\n", "ABCDEFGH"[current_running_cpu_idx]);
2878                           for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
2879                             if (cpus[i].inMultics && cpus[i].workAllocation > 0) {
2880                               sim_printf ("CPU %c remaining allocation: %ld\r\n", "ABCDEFGH"[i], cpus[i].workAllocation);
2881                             }
2882                           }
2883                           sim_printf ("Conceding clock mastery...\r\n");
2884                           cpu.syncClockModeCache = false;
2885                           giveupClockMaster (cpup);
2886                           goto bail;
2887                         }
2888                         sim_usleep (1);
2889                       } // while (1) -- while others still have work to do
2890                     } // have we used up our allocation
2891                     // We are master and have work allocated; fall through
2892                     // and do some work
2893 
2894                   } else { // Master/slave?
2895 
2896                     // We are not the master; must be a slave
2897 
2898                     // Have we just become a slave?
2899                     if (! cpu.isSlave) {
2900                       //HDBGNote (NULL, __func__, "CPU%c Becoming slave", cpu.cpuIdx + 'A');
2901 # ifdef SYNCTEST
2902                      sim_printf ("CPU%c becoming slave\r\n", cpu.cpuIdx + 'A');
2903 # endif
2904                     }
2905                     cpu.isSlave = true;
2906 
2907                     // Wait for allocation
2908                     while (syncClockMode && cpu.workAllocation <= 0)
2909                       sim_usleep (1);
2910 
2911                     // We are slave and have work allocated; fall through
2912                     // and do some work
2913 
2914                   } // master/slave
2915 
2916                 } else { // ! syncClockMode
2917                   // Forget that this thread is synchronized
2918                   cpu.syncClockModeCache = false;
2919                   if (cpu.isSlave) {
2920                     //HDBGNote (cpup, __func__, "Free; free at last%s", "");
2921 # ifdef SYNCTEST
2922                     sim_printf ("CPU%c free; free at last\r\n", cpu.cpuIdx + 'A');
2923 # endif
2924                     cpu.isSlave = false;
2925                   }
2926                 } // ! syncClockMode
2927               } // polling
2928           bail:
2929 
2930 #endif
2931 
2932 #if defined(THREADZ) || defined(LOCKLESS)
2933               if (LIKELY (! cpu.tweaks.isolts_mode) &&
2934                   UNLIKELY (! cpu.inMultics)) {
2935                 cpu.inMultics = true;
2936               }
2937 #endif /* defined(THREADZ) || defined(LOCKLESS) */
2938 
2939               CPT (cpt1U, 22); // exec cycle
2940 
2941 #if defined(LOCKLESS)
2942                 if (stall_point_active)
2943                   {
2944                     for (int i = 0; i < N_STALL_POINTS; i ++)
2945                       if (stall_points[i].segno  && stall_points[i].segno  == cpu.PPR.PSR &&
2946                           stall_points[i].offset && stall_points[i].offset == cpu.PPR.IC)
2947                         {
2948 # if defined(CTRACE)
2949                           (void)fprintf (stderr, "%10lu %s stall %d\r\n", seqno (), cpunstr[current_running_cpu_idx], i);
2950 # endif
2951                           //sim_printf ("stall %2d %05o:%06o\r\n", i, stall_points[i].segno, stall_points[i].offset);
2952                           sim_usleep(stall_points[i].time);
2953                           break;
2954                         }
2955                   }
2956 #endif
2957 
2958               // The only time we are going to execute out of IRODD is
2959               // during RPD, at which time interrupts are automatically
2960               // inhibited; so the following can ignore RPD harmlessly
2961               if (GET_I (cpu.cu.IWB))
2962                 cpu.wasInhibited = true;
2963 
2964               t_stat ret = executeInstruction (cpup);
2965               DO_WORK_EXEC;
2966               CPT (cpt1U, 23); // execution complete
2967 
2968               if (cpu.tweaks.l68_mode)
2969                 add_l68_CU_history (cpup);
2970               else
2971                 add_dps8m_CU_history (cpup);
2972 
2973               if (ret > 0)
2974                 {
2975                    reason = ret;
2976                    break;
2977                 }
2978 
2979               if (ret == CONT_XEC)
2980                 {
2981                   CPT (cpt1U, 27); // XEx instruction
2982                   cpu.wasXfer = false;
2983                   cpu.isExec  = true;
2984                   if (cpu.cu.xdo)
2985                     cpu.isXED = true;
2986 
2987                   cpu.cu.XSF           = 0;
2988                   cpu.cu.TSN_VALID [0] = 0;
2989                   cpu.TPR.TSR          = cpu.PPR.PSR;
2990                   cpu.TPR.TRR          = cpu.PPR.PRR;
2991                   break;
2992                 }
2993 
2994               if (ret == CONT_TRA || ret == CONT_RET)
2995                 {
2996                   CPT (cpt1U, 24); // transfer instruction
2997                   cpu.cu.xde  = cpu.cu.xdo = 0;
2998                   cpu.isExec  = false;
2999                   cpu.isXED   = false;
3000                   // even for CONT_RET else isolts 886 fails
3001                   cpu.wasXfer = true;
3002 
3003                   if (cpu.cycle != EXEC_cycle) // fault or interrupt
3004                     {
3005                       clearFaultCycle (cpup);
3006 
3007 // BAR mode:  [NBAR] is set ON (taking the processor
3008 // out of BAR mode) by the execution of any transfer instruction
3009 // other than tss during a fault or interrupt trap.
3010 
3011                       if (! (cpu.currentInstruction.opcode == 0715 &&
3012                          cpu.currentInstruction.opcodeX == 0))
3013                         {
3014                           CPT (cpt1U, 9); // nbar set
3015                           SET_I_NBAR;
3016                         }
3017 
3018                       if (!clear_temporary_absolute_mode (cpup))
3019                         {
3020                           // didn't go appending
3021                           sim_debug (DBG_TRACEEXT, & cpu_dev,
3022                                      "setting ABS mode\r\n");
3023                           CPT (cpt1U, 10); // temporary absolute mode
3024                           set_addr_mode (cpup, ABSOLUTE_mode);
3025                         }
3026                       else
3027                         {
3028                           // went appending
3029                           sim_debug (DBG_TRACEEXT, & cpu_dev,
3030                                      "not setting ABS mode\r\n");
3031                         }
3032 
3033                     } // fault or interrupt
3034 
3035                   //if (TST_I_ABS && get_went_appending ())
3036                   if (TST_I_ABS && cpu.cu.XSF)
3037                     {
3038                       set_addr_mode (cpup, APPEND_mode);
3039                     }
3040 
3041                   if (ret == CONT_TRA)
3042                     {
3043                       // PSEUDO_FETCH_cycle does not check interrupts/g7faults
3044                       cpu.wasXfer = false;
3045                       set_cpu_cycle (cpup, PSEUDO_FETCH_cycle);
3046                     }
3047                   else
3048                     set_cpu_cycle (cpup, FETCH_cycle);
3049                   break;   // Don't bump PPR.IC, instruction already did it
3050                 }
3051 
3052               if (ret == CONT_DIS)
3053                 {
3054                   CPT (cpt1U, 25); // DIS instruction
3055 
3056 #if defined(THREADZ) || defined(LOCKLESS)
3057                   // If we do a DIS is clock sync, skip the sleep
3058                   if (cpu.syncClockModeCache) {
3059                     break;
3060                 }
3061 #endif
3062 
3063 // If we get here, we have encountered a DIS instruction in EXEC_cycle.
3064 //
3065 // We need to idle the CPU until one of the following conditions:
3066 //
3067 //  An external interrupt occurs.
3068 //  The Timer Register underflows.
3069 //  The emulator polled devices need polling.
3070 //
3071 // The external interrupt will only be posted to the CPU engine if the
3072 // device poll posts an interrupt. This means that we do not need to
3073 // detect the interrupts here; if we wake up and poll the devices, the
3074 // interrupt will be detected by the DIS instruction when it is re-executed.
3075 //
3076 // The Timer Register is a fast, high-precision timer but Multics uses it
3077 // in only two ways: detecting I/O lockup during early boot, and process
3078 // quantum scheduling (1/4 second for Multics).
3079 //
3080 // Neither of these require high resolution or high accuracy.
3081 //
3082 // The goal of the polling code is sample at about 100Hz; updating the timer
3083 // register at that rate should suffice.
3084 //
3085 //    sleep for 1/100 of a second
3086 //    update the polling state to trigger a poll
3087 //    update the timer register by 1/100 of a second
3088 //    force the scp queues to process
3089 //    continue processing
3090 //
3091 
3092 // The sim_usleep logic is not smart enough w.r.t. ISOLTS.
3093 // The sleep should only happen if all running processors are in DIS mode.
3094                   // 1/100 is .01 secs.
3095                   // *1000 is 10  milliseconds
3096                   // *1000 is 10000 microseconds
3097                   // in uSec;
3098 #if defined(THREADZ) || defined(LOCKLESS)
3099 
3100 // XXX If interrupt inhibit set, then sleep forever instead of TRO
3101                   // rTR is 512KHz; sleepCPU is in 1Mhz
3102                   //   rTR * 1,000,000 / 512,000
3103                   //   rTR * 1000 / 512
3104                   //   rTR * 500 / 256
3105                   //   rTR * 250 / 128
3106                   //   rTR * 125 / 64
3107 
3108 # if defined(NO_TIMEWAIT)
3109                   //sim_usleep (sys_opts.sys_poll_interval * 1000 /*10000*/ );
3110                   struct timespec req, rem;
3111                   uint ms        = sys_opts.sys_poll_interval;
3112                   long int nsec  = (long int) ms * 1000L * 1000L;
3113                   req.tv_nsec    = nsec;
3114                   req.tv_sec    += req.tv_nsec / 1000000000L;
3115                   req.tv_nsec   %= 1000000000L;
3116                   int rc         = nanosleep (& req, & rem); // XXX Does this work on Windows ???
3117                   // Awakened early?
3118                   if (rc == -1)
3119                     {
3120                        ms = (uint) (rem.tv_nsec / 1000 + req.tv_sec * 1000);
3121                     }
3122                   word27 ticks = ms * 512;
3123                   if (cpu.rTR <= ticks)
3124                     {
3125                       if (cpu.tweaks.tro_enable) {
3126                         setG7fault (current_running_cpu_idx, FAULT_TRO);
3127                       }
3128                       cpu.rTR = (cpu.rTR - ticks) & MASK27;
3129                     }
3130                   else
3131                     cpu.rTR = (cpu.rTR - ticks) & MASK27;
3132 
3133                   if (cpu.rTR == 0)
3134                     cpu.rTR = MASK27;
3135 # else // !NO_TIMEWAIT
3136                   // unsigned long left = cpu.rTR * 125u / 64u;
3137                   // ubsan
3138                   unsigned long left = (unsigned long) ((uint64) (cpu.rTR) * 125u / 64u);
3139 
3140 
3141 
3142 
3143 
3144 
3145 
3146 
3147                   unsigned long nowLeft = left;
3148                   if (!sample_interrupts (cpup))
3149                     {
3150                       nowLeft = sleepCPU (left);
3151                     }
3152                   if (nowLeft)
3153                     {
3154                       // sleepCPU uses a clock that is not guaranteed to be monotonic, and occasionally returns nowLeft > left.
3155                       // Don't run rTR backwards if that happens
3156                       if (nowLeft <= left) {
3157                         cpu.rTR = (word27) (left * 64 / 125);
3158                       }
3159                     }
3160                   else
3161                     {
3162                       // We slept until timer runout
3163                       if (cpu.tweaks.tro_enable)
3164                         {
3165                           lock_scu ();
3166                           setG7fault (current_running_cpu_idx, FAULT_TRO);
3167                           unlock_scu ();
3168                         }
3169                       cpu.rTR = MASK27;
3170                     }
3171 # endif // !NO_TIMEWAIT
3172                   cpu.rTRticks = 0;
3173                   break;
3174 #else // ! (THREADZ || LOCKLESS)
3175                   //sim_sleep (10000);
3176                   sim_usleep (sys_opts.sys_poll_interval * 1000/*10000*/);
3177                   // Trigger I/O polling
3178 # if defined(CONSOLE_FIX)
3179 #  if defined(THREADZ) || defined(LOCKLESS)
3180                   lock_libuv ();
3181 #  endif
3182 # endif
3183                   uv_run (ev_poll_loop, UV_RUN_NOWAIT);
3184 # if defined(CONSOLE_FIX)
3185 #  if defined(THREADZ) || defined(LOCKLESS)
3186                   unlock_libuv ();
3187 #  endif
3188 # endif
3189                   fast_queue_subsample = 0;
3190 
3191                   sim_interval = 0;
3192                   // Timer register runs at 512 KHz
3193                   // 512000 is 1 second
3194                   // 512000/100 -> 5120  is .01 second
3195 
3196                   cpu.rTRticks = 0;
3197                   // Would we have underflowed while sleeping?
3198                   //if ((cpu.rTR & ~ MASK27) || cpu.rTR <= 5120)
3199                   //if (cpu.rTR <= 5120)
3200 
3201                   // Timer register runs at 512 KHz
3202                   // 512Khz / 512 is millisecods
3203                   if (cpu.rTR <= sys_opts.sys_poll_interval * 512)
3204                     {
3205                       if (cpu.tweaks.tro_enable) {
3206                         setG7fault (current_running_cpu_idx, FAULT_TRO);
3207                       }
3208                       cpu.rTR = (cpu.rTR - sys_opts.sys_poll_interval * 512) & MASK27;
3209                     }
3210                   else
3211                     cpu.rTR = (cpu.rTR - sys_opts.sys_poll_interval * 512) & MASK27;
3212                   if (cpu.rTR == 0)
3213                     cpu.rTR = MASK27;
3214 #endif // ! (THREADZ || LOCKLESS)
3215                   /*NOTREACHED*/ /* unreachable */
3216                   break;
3217                 }
3218 
3219               cpu.wasXfer = false;
3220 
3221               if (ret < 0)
3222                 {
3223                   sim_warn ("executeInstruction returned %d?\r\n", ret);
3224                   break;
3225                 }
3226 
3227               if ((! cpu.cu.repeat_first) &&
3228                   (cpu.cu.rpt ||
3229                    (cpu.cu.rd && (cpu.PPR.IC & 1)) ||
3230                    cpu.cu.rl))
3231                 {
3232                   CPT (cpt1U, 26); // RPx instruction
3233                   if (cpu.cu.rd)
3234                     -- cpu.PPR.IC;
3235                   cpu.wasXfer = false;
3236                   set_cpu_cycle (cpup, FETCH_cycle);
3237                   break;
3238                 }
3239 
3240               // If we just did the odd word of a fault pair
3241               if (cpu.cycle == FAULT_EXEC_cycle &&
3242                   !cpu.cu.xde && cpu.cu.xdo)
3243                 {
3244                   clear_temporary_absolute_mode (cpup);
3245                   cu_safe_restore (cpup);
3246                   CPT (cpt1U, 12); // cu restored
3247                   clearFaultCycle (cpup);
3248                   // cu_safe_restore calls decode_instruction ()
3249                   // we can determine the instruction length.
3250                   // decode_instruction() restores ci->info->ndes
3251                   cpu.wasXfer  = false;
3252                   cpu.isExec   = false;
3253                   cpu.isXED    = false;
3254 
3255                   cpu.PPR.IC  += ci->info->ndes;
3256                   cpu.PPR.IC ++;
3257 
3258                   set_cpu_cycle (cpup, FETCH_cycle);
3259                   break;
3260                 }
3261 
3262               // If we just did the odd word of a interrupt pair
3263               if (cpu.cycle == INTERRUPT_EXEC_cycle &&
3264                   !cpu.cu.xde && cpu.cu.xdo)
3265                 {
3266                   clear_temporary_absolute_mode (cpup);
3267                   cu_safe_restore (cpup);
3268                   // cpu.cu.xdo = 0;
3269 // The only place cycle is set to INTERRUPT_cycle in FETCH_cycle; therefore
3270 // we can safely assume that is the state that should be restored.
3271                   CPT (cpt1U, 12); // cu restored
3272                   cpu.wasXfer = false;
3273                   cpu.isExec  = false;
3274                   cpu.isXED   = false;
3275 
3276                   set_cpu_cycle (cpup, FETCH_cycle);
3277                   break;
3278                 }
3279 
3280               // Even word of fault or interrupt pair or xed
3281               if (cpu.cu.xde && cpu.cu.xdo)
3282                 {
3283                   // Get the odd
3284                   cpu.cu.IWB           = cpu.cu.IRODD;
3285                   cpu.cu.xde           = 0;
3286                   cpu.isExec           = true;
3287                   cpu.isXED            = true;
3288                   cpu.cu.XSF           = 0;
3289                   cpu.cu.TSN_VALID [0] = 0;
3290                   cpu.TPR.TSR          = cpu.PPR.PSR;
3291                   cpu.TPR.TRR          = cpu.PPR.PRR;
3292                   break; // go do the odd word
3293                 }
3294 
3295               if (cpu.cu.xde || cpu.cu.xdo)  // we are in an XEC/XED
3296                 {
3297                   cpu.cu.xde        = cpu.cu.xdo = 0;
3298                   cpu.isExec        = false;
3299                   cpu.isXED         = false;
3300                   CPT (cpt1U, 27);           // XEx instruction
3301                   cpu.wasXfer       = false;
3302                   cpu.PPR.IC ++;
3303                   if (ci->info->ndes > 0)
3304                     cpu.PPR.IC     += ci->info->ndes;
3305                   cpu.wasInhibited  = true;
3306                   set_cpu_cycle (cpup, FETCH_cycle);
3307                   break;
3308                 }
3309 
3310               //ASSURE (cpu.cycle == EXEC_cycle);
3311               if (cpu.cycle != EXEC_cycle)
3312                 sim_warn ("expected EXEC_cycle (%d)\r\n", cpu.cycle);
3313 
3314               cpu.cu.xde = cpu.cu.xdo = 0;
3315               cpu.isExec = false;
3316               cpu.isXED  = false;
3317 
3318               // use prefetched instruction from cpu.cu.IRODD
3319               // we must have finished an instruction at an even location
3320               // skip multiword EIS instructions
3321               // skip repeat instructions for now
3322               // skip dis - we may need to take interrupts/g7faults
3323               // skip if (last instruction) wrote to current instruction range
3324               //  the hardware really does this and isolts tests it
3325               //  Multics Differences Manual DPS8 70/M
3326               //  should take segment number into account?
3327               if ((cpu.PPR.IC & 1) == 0 &&
3328                   ci->info->ndes == 0 &&
3329                   !cpu.cu.repeat_first && !cpu.cu.rpt && !cpu.cu.rd && !cpu.cu.rl &&
3330                   !(cpu.currentInstruction.opcode == 0616 && cpu.currentInstruction.opcodeX == 0) &&
3331                   (cpu.PPR.IC & ~3u) != (cpu.last_write  & ~3u))
3332                 {
3333                   cpu.PPR.IC ++;
3334                   cpu.wasXfer = false;
3335                   cpu.cu.IWB  = cpu.cu.IRODD;
3336                   set_cpu_cycle (cpup, PSEUDO_FETCH_cycle);
3337                   break;
3338                 }
3339 
3340               cpu.PPR.IC ++;
3341               if (ci->info->ndes > 0)
3342                 cpu.PPR.IC += ci->info->ndes;
3343 
3344               CPT (cpt1U, 28); // enter fetch cycle
3345               cpu.wasXfer = false;
3346               set_cpu_cycle (cpup, FETCH_cycle);
3347             }
3348             break;
3349 
3350           case SYNC_FAULT_RTN_cycle:
3351             {
3352               CPT (cpt1U, 29); // sync. fault return
3353               // cu_safe_restore should have restored CU.IWB, so
3354               // we can determine the instruction length.
3355               // decode_instruction() restores ci->info->ndes
3356 
3357               cpu.PPR.IC += ci->info->ndes;
3358               cpu.PPR.IC ++;
3359               cpu.wasXfer = false;
3360               set_cpu_cycle (cpup, FETCH_cycle);
3361             }
3362             break;
3363 
3364           case FAULT_cycle:
3365             {
3366               CPT (cpt1U, 30); // fault cycle
3367               // In the FAULT CYCLE, the processor safe-stores the Control
3368               // Unit Data (see Section 3) into program-invisible holding
3369               // registers in preparation for a Store Control Unit ( scu)
3370               // instruction, then enters temporary absolute mode, forces the
3371               // current ring of execution C(PPR.PRR) to 0, and generates a
3372               // computed address for the fault trap pair by concatenating
3373               // the setting of the FAULT BASE switches on the processor
3374               // configuration panel with twice the fault number (see Table
3375               // 7-1).  This computed address and the operation code for the
3376               // Execute Double (xed) instruction are forced into the
3377               // instruction register and executed as an instruction. Note
3378               // that the execution of the instruction is not done in a
3379               // normal EXECUTE CYCLE but in the FAULT CYCLE with the
3380               // processor in temporary absolute mode.
3381 
3382               // F(A)NP should never be stored when faulting.
3383               // ISOLTS-865 01a,870 02d
3384               // Unconditional reset of APU status to FABS breaks boot.
3385               // Checking for F(A)NP here is equivalent to checking that the
3386               // last append cycle has made it as far as H/I without a fault.
3387               // Also reset it on TRB fault. ISOLTS-870 05a
3388               if ((cpu.cu.APUCycleBits & 060) || cpu.secret_addressing_mode)
3389                   set_apu_status (cpup, apuStatus_FABS);
3390 
3391               // XXX the whole fault cycle should be rewritten as an xed
3392               // instruction pushed to IWB and executed
3393 
3394               // AL39: TRB fault doesn't safestore CUD - the original fault
3395               // CUD should be stored
3396 
3397               // ISOLTS-870 05a: CUD[5] and IWB are safe stored, possibly
3398               //  due to CU overlap
3399 
3400               // keep IRODD untouched if TRB occurred in an even location
3401               if (cpu.faultNumber != FAULT_TRB || cpu.cu.xde == 0)
3402                 {
3403                   cu_safe_store (cpup);
3404                 }
3405               else
3406                 {
3407                   word36 tmpIRODD = cpu.scu_data[7];
3408                   cu_safe_store (cpup);
3409                   cpu.scu_data[7] = tmpIRODD;
3410                 }
3411               CPT (cpt1U, 31); // safe store complete
3412 
3413               // Temporary absolute mode
3414               set_temporary_absolute_mode (cpup);
3415 
3416               // Set to ring 0
3417               cpu.PPR.PRR = 0;
3418               cpu.TPR.TRR = 0;
3419 
3420               // (12-bits of which the top-most 7-bits are used)
3421               uint fltAddress = (cpu.switches.FLT_BASE << 5) & 07740;
3422               L68_ (
3423                 if (cpu.is_FFV)
3424                   {
3425                     cpu.is_FFV = false;
3426                     CPTUR (cptUseMR);
3427                     // The high 15 bits
3428                     fltAddress = (cpu.MR.FFV & MASK15) << 3;
3429                   }
3430               )
3431 
3432               // absolute address of fault YPair
3433               word24 addr = fltAddress + 2 * cpu.faultNumber;
3434 
3435               if (cpu.restart)
3436                 {
3437                   cpu.restart = false;
3438                   addr = cpu.restart_address;
3439                 }
3440 
3441               core_read2 (cpup, addr, & cpu.cu.IWB, & cpu.cu.IRODD, __func__);
3442 #if defined(TESTING)
3443               HDBGMRead (addr, cpu.cu.IWB, "fault even");
3444               HDBGMRead (addr + 1, cpu.cu.IRODD, "fault odd");
3445 #endif
3446               cpu.cu.xde = 1;
3447               cpu.cu.xdo = 1;
3448               cpu.isExec = true;
3449               cpu.isXED  = true;
3450 
3451               CPT (cpt1U, 33); // set fault exec cycle
3452               set_cpu_cycle (cpup, FAULT_EXEC_cycle);
3453 
3454               break;
3455             }
3456 
3457           }  // switch (cpu.cycle)
3458       }
3459     while (reason == 0);
3460 
3461 leave:
3462 #if defined(THREADZ) || defined(LOCKLESS)
3463     cpu.executing = false;
3464     cpu.inMultics = false;
3465 #endif /* defined(THREADZ) || defined(LOCKLESS) */
3466 #if defined(TESTING)
3467     HDBGPrint ();
3468 #endif
3469 
3470     for (unsigned short n = 0; n < N_CPU_UNITS_MAX; n++)
3471       {
3472 #if !defined(SCHED_NEVER_YIELD)
3473         lockYieldAll     = lockYieldAll     + (unsigned long long)cpus[n].coreLockState.lockYield;
3474 #endif /* if !defined(SCHED_NEVER_YIELD) */
3475         lockWaitMaxAll   = lockWaitMaxAll   + (unsigned long long)cpus[n].coreLockState.lockWaitMax;
3476         lockWaitAll      = lockWaitAll      + (unsigned long long)cpus[n].coreLockState.lockWait;
3477         lockImmediateAll = lockImmediateAll + (unsigned long long)cpus[n].coreLockState.lockImmediate;
3478         lockCntAll       = lockCntAll       + (unsigned long long)cpus[n].coreLockState.lockCnt;
3479         instrCntAll      = instrCntAll      + (unsigned long long)cpus[n].instrCnt;
3480         cycleCntAll      = cycleCntAll      + (unsigned long long)cpus[n].cycleCnt;
3481       }
3482 
3483     (void)fflush(stderr);
3484     (void)fflush(stdout);
3485 
3486 # if !defined(PERF_STRIP)
3487     if (cycleCntAll > (unsigned long long)cpu.cycleCnt)
3488       {
3489 # endif /*if !defined(PERF_STRIP) */
3490         sim_msg ("\r\n");
3491         sim_msg ("\r+---------------------------------+\r\n");
3492         sim_msg ("\r|     Aggregate CPU Statistics    |\r\n");
3493         sim_msg ("\r+---------------------------------+\r\n");
3494         (void)fflush(stderr);
3495         (void)fflush(stdout);
3496 # if defined(WIN_STDIO)
3497         sim_msg ("\r|  cycles        %15llu  |\r\n", cycleCntAll);
3498         sim_msg ("\r|  instructions  %15llu  |\r\n", instrCntAll);
3499         (void)fflush(stderr);
3500         (void)fflush(stdout);
3501         sim_msg ("\r+---------------------------------+\r\n");
3502         sim_msg ("\r|  lockCnt       %15llu  |\r\n", lockCntAll);
3503         sim_msg ("\r|  lockImmediate %15llu  |\r\n", lockImmediateAll);
3504         (void)fflush(stderr);
3505         (void)fflush(stdout);
3506         sim_msg ("\r+---------------------------------+\r\n");
3507         sim_msg ("\r|  lockWait      %15llu  |\r\n", lockWaitAll);
3508         sim_msg ("\r|  lockWaitMax   %15llu  |\r\n", lockWaitMaxAll);
3509         (void)fflush(stderr);
3510         (void)fflush(stdout);
3511 #  if !defined(SCHED_NEVER_YIELD)
3512         sim_msg ("\r|  lockYield     %15llu  |\r\n", lockYieldAll);
3513 #  else
3514         sim_msg ("\r|  lockYield                ----  |\r\n");
3515 #  endif /* if !defined(SCHED_NEVER_YIELD) */
3516         sim_msg ("\r+---------------------------------+\r\n");
3517         (void)fflush(stderr);
3518         (void)fflush(stdout);
3519 # else
3520         sim_msg ("\r|  cycles        %'15llu  |\r\n", cycleCntAll);
3521         sim_msg ("\r|  instructions  %'15llu  |\r\n", instrCntAll);
3522         (void)fflush(stderr);
3523         (void)fflush(stdout);
3524         sim_msg ("\r+---------------------------------+\r\n");
3525         sim_msg ("\r|  lockCnt       %'15llu  |\r\n", lockCntAll);
3526         sim_msg ("\r|  lockImmediate %'15llu  |\r\n", lockImmediateAll);
3527         (void)fflush(stderr);
3528         (void)fflush(stdout);
3529         sim_msg ("\r+---------------------------------+\r\n");
3530         sim_msg ("\r|  lockWait      %'15llu  |\r\n", lockWaitAll);
3531         sim_msg ("\r|  lockWaitMax   %'15llu  |\r\n", lockWaitMaxAll);
3532         (void)fflush(stderr);
3533         (void)fflush(stdout);
3534 #  if !defined(SCHED_NEVER_YIELD)
3535         sim_msg ("\r|  lockYield     %'15llu  |\r\n", lockYieldAll);
3536 #  else
3537         sim_msg ("\r|  lockYield                ----  |\r\n");
3538 #  endif /* if !defined(SCHED_NEVER_YIELD) */
3539         sim_msg ("\r+---------------------------------+\r\n");
3540         (void)fflush(stderr);
3541         (void)fflush(stdout);
3542 # endif /* if defined(WIN_STDIO) */
3543 # if !defined(PERF_STRIP)
3544       }
3545 # else
3546     sim_msg("\r\n");
3547 # endif /* if !defined(PERF_STRIP) */
3548 
3549 
3550 
3551 
3552 
3553 
3554 
3555 
3556 
3557 
3558 
3559 #if defined(THREADZ) || defined(LOCKLESS)
3560     if (running_perf_test == false)
3561       sim_usleep(2000000); // Delay (up to 2s) to allow for stats gathering
3562     stopCPUThread();
3563 #endif
3564 
3565 #if defined(M_SHARED)
3566 // scp needs to have the IC statically allocated, so a placeholder
3567 // was created. Update the placeholder so the IC can be seen via scp
3568 // and restarting sim_instr won't lose the place.
3569 
3570     set_cpu_idx (0); //-V779
3571     dummy_IC = cpu.PPR.IC;
3572 #endif
3573 
3574     return reason;
3575   }
3576 
3577 /*
3578  * cd@libertyhaven.com - sez ...
3579  *  If the instruction addresses a block of four words, the target of the
3580  * instruction is supposed to be an address that is aligned on a four-word
3581  * boundary (0 mod 4). If not, the processor will grab the four-word block
3582  * containing that address that begins on a four-word boundary, even if it
3583  * has to go back 1 to 3 words. Analogous explanation for 8, 16, and 32 cases.
3584  *
3585  * olin@olinsibert.com - sez ...
3586  *  It means that the appropriate low bits of the address are forced to zero.
3587  * So it's the previous words, not the succeeding words, that are used to
3588  * satisfy the request. -- Olin
3589  */
3590 
3591 int operand_size (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3592   {
3593     DCDstruct * i = & cpu.currentInstruction;
3594     if (i->info->flags & (READ_OPERAND | STORE_OPERAND))
3595         return 1;
3596     else if (i->info->flags & (READ_YPAIR | STORE_YPAIR))
3597         return 2;
3598     else if (i->info->flags & (READ_YBLOCK8 | STORE_YBLOCK8))
3599         return 8;
3600     else if (i->info->flags & (READ_YBLOCK16 | STORE_YBLOCK16))
3601         return 16;
3602     else if (i->info->flags & (READ_YBLOCK32 | STORE_YBLOCK32))
3603         return 32;
3604     return 0;
3605   }
3606 
3607 // read instruction operands
3608 
3609 void readOperandRead (cpu_state_t * cpup, word18 addr) {
     /* [previous][next][first][last][top][bottom][index][help] */
3610   CPT (cpt1L, 6); // read_operand
3611 
3612 #if defined(THREADZ)
3613   DCDstruct * i = & cpu.currentInstruction;
3614   if (RMWOP (i)) // ldac, ldqc, stac, stacq, snzc
3615     lock_rmw ();
3616 #endif
3617 
3618   switch (operand_size (cpup)) {
3619     case 1:
3620       CPT (cpt1L, 7); // word
3621       ReadOperandRead (cpup, addr, & cpu.CY);
3622       break;
3623     case 2:
3624       CPT (cpt1L, 8); // double word
3625       addr &= 0777776;   // make even
3626       Read2OperandRead (cpup, addr, cpu.Ypair);
3627       break;
3628     case 8:
3629       CPT (cpt1L, 9); // oct word
3630       addr &= 0777770;   // make on 8-word boundary
3631       Read8 (cpup, addr, cpu.Yblock8, cpu.currentInstruction.b29);
3632       break;
3633     case 16:
3634       CPT (cpt1L, 10); // 16 words
3635       addr &= 0777770;   // make on 8-word boundary
3636       Read16 (cpup, addr, cpu.Yblock16);
3637       break;
3638     case 32:
3639       CPT (cpt1L, 11); // 32 words
3640       addr &= 0777740;   // make on 32-word boundary
3641       for (uint j = 0 ; j < 32 ; j += 1)
3642         ReadOperandRead (cpup, addr + j, cpu.Yblock32 + j);
3643       break;
3644   }
3645 }
3646 
3647 void readOperandRMW (cpu_state_t * cpup, word18 addr) {
     /* [previous][next][first][last][top][bottom][index][help] */
3648   CPT (cpt1L, 6); // read_operand
3649   switch (operand_size (cpup)) {
3650     case 1:
3651       CPT (cpt1L, 7); // word
3652       ReadOperandRMW (cpup, addr, & cpu.CY);
3653       break;
3654     case 2:
3655       CPT (cpt1L, 8); // double word
3656       addr &= 0777776;   // make even
3657       Read2OperandRead (cpup, addr, cpu.Ypair);
3658       break;
3659     case 8:
3660       CPT (cpt1L, 9); // oct word
3661       addr &= 0777770;   // make on 8-word boundary
3662       Read8 (cpup, addr, cpu.Yblock8, cpu.currentInstruction.b29);
3663       break;
3664     case 16:
3665       CPT (cpt1L, 10); // 16 words
3666       addr &= 0777770;   // make on 8-word boundary
3667       Read16 (cpup, addr, cpu.Yblock16);
3668       break;
3669     case 32:
3670       CPT (cpt1L, 11); // 32 words
3671       addr &= 0777740;   // make on 32-word boundary
3672       for (uint j = 0 ; j < 32 ; j += 1)
3673         ReadOperandRMW (cpup, addr + j, cpu.Yblock32 + j);
3674       break;
3675   }
3676 }
3677 
3678 // write instruction operands
3679 
3680 t_stat write_operand (cpu_state_t * cpup, word18 addr, UNUSED processor_cycle_type cyctyp)
     /* [previous][next][first][last][top][bottom][index][help] */
3681   {
3682     switch (operand_size (cpup))
3683       {
3684         case 1:
3685             CPT (cpt1L, 12); // word
3686             WriteOperandStore (cpup, addr, cpu.CY);
3687             break;
3688         case 2:
3689             CPT (cpt1L, 13); // double word
3690             addr &= 0777776;   // make even
3691             Write2OperandStore (cpup, addr + 0, cpu.Ypair);
3692             break;
3693         case 8:
3694             CPT (cpt1L, 14); // 8 words
3695             addr &= 0777770;   // make on 8-word boundary
3696             Write8 (cpup, addr, cpu.Yblock8, cpu.currentInstruction.b29);
3697             break;
3698         case 16:
3699             CPT (cpt1L, 15); // 16 words
3700             addr &= 0777770;   // make on 8-word boundary
3701             Write16 (cpup, addr, cpu.Yblock16);
3702             break;
3703         case 32:
3704             CPT (cpt1L, 16); // 32 words
3705             addr &= 0777740;   // make on 32-word boundary
3706             //for (uint j = 0 ; j < 32 ; j += 1)
3707                 //Write (addr + j, cpu.Yblock32[j], OPERAND_STORE);
3708             Write32 (cpup, addr, cpu.Yblock32);
3709             break;
3710       }
3711 
3712 #if defined(THREADZ)
3713     if (cyctyp == OPERAND_STORE)
3714       {
3715         DCDstruct * i = & cpu.currentInstruction;
3716         if (RMWOP (i))
3717           unlock_mem ();
3718       }
3719 #endif
3720     return SCPE_OK;
3721 
3722   }
3723 
3724 #if !defined(SPEED)
3725 t_stat set_mem_watch (int32 arg, const char * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
3726   {
3727     if (strlen (buf) == 0)
3728       {
3729         if (arg)
3730           {
3731             sim_warn ("no argument to watch?\r\n");
3732             return SCPE_ARG;
3733           }
3734         sim_msg ("Clearing all watch points\r\n");
3735         (void)memset (& watch_bits, 0, sizeof (watch_bits));
3736         return SCPE_OK;
3737       }
3738     char * end;
3739     long int n = strtol (buf, & end, 0);
3740     if (* end || n < 0 || n >= MEMSIZE)
3741       {
3742         sim_warn ("Invalid argument to watch? %ld\r\n", (long) n);
3743         return SCPE_ARG;
3744       }
3745     watch_bits [n] = arg != 0;
3746     return SCPE_OK;
3747   }
3748 #endif /* if !defined(SPEED) */
3749 
3750 /*!
3751  * "Raw" core interface ....
3752  */
3753 
3754 #if !defined(SPEED)
3755 static void nem_check (word24 addr, const char * context)
     /* [previous][next][first][last][top][bottom][index][help] */
3756   {
3757     cpu_state_t * cpup = _cpup;
3758     if (lookup_cpu_mem_map (cpup, addr) < 0)
3759       {
3760         doFault (FAULT_STR, fst_str_nea,  context);
3761       }
3762   }
3763 #endif /* if !defined(SPEED) */
3764 
3765 // static uint get_scu_unit_idx (word24 addr, word24 * offset)
3766 //   {
3767 //     int cpu_port_num = lookup_cpu_mem_map (addr, offset);
3768 //     if (cpu_port_num < 0) // Can't happen, we passed nem_check above
3769 //       {
3770 //         sim_warn ("cpu_port_num < 0");
3771 //         doFault (FAULT_STR, fst_str_nea,  __func__);
3772 //       }
3773 //     return cables->cpu_to_scu [current_running_cpu_idx][cpu_port_num].scu_unit_idx;
3774 //   }
3775 
3776 #if !defined(SPEED) || !defined(INLINE_CORE)
3777 int core_read (cpu_state_t * cpup, word24 addr, word36 *data, const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
3778   {
3779     PNL (cpu.portBusy = true;)
3780     SC_MAP_ADDR (addr, addr);
3781 # if !defined(LOCKLESS)
3782     if (M[addr] & MEM_UNINITIALIZED)
3783       {
3784         sim_debug (DBG_WARN, & cpu_dev,
3785                    "Uninitialized memory accessed at address %08o; "
3786                    "IC is 0%06o:0%06o (%s(\r\n",
3787                    addr, cpu.PPR.PSR, cpu.PPR.IC, ctx);
3788       }
3789 # endif /* if !defined(LOCKLESS) */
3790 # if !defined(SPEED)
3791     if (watch_bits [addr])
3792       {
3793         sim_msg ("WATCH [%llu] %05o:%06o read   %08o %012llo (%s)\r\n",
3794                     (long long unsigned int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC, addr,
3795                     (long long unsigned int)M [addr], ctx);
3796         traceInstruction (0);
3797       }
3798 # endif /* if !defined(SPEED) */
3799 # if defined(LOCKLESS)
3800 #  if !defined(SUNLINT)
3801     word36 v;
3802     LOAD_ACQ_CORE_WORD(v, addr);
3803     *data = v & DMASK;
3804 #  endif /* if !defined(SUNLINT) */
3805 # else
3806     *data = M[addr] & DMASK;
3807 # endif /* if defined(LOCKLESS) */
3808 
3809     DO_WORK_MEM;
3810     sim_debug (DBG_CORE, & cpu_dev,
3811                "core_read  %08o %012"PRIo64" (%s)\r\n",
3812                 addr, * data, ctx);
3813     PNL (trackport (addr, * data));
3814     return 0;
3815   }
3816 #endif
3817 
3818 #if defined(LOCKLESS)
3819 int core_read_lock (cpu_state_t * cpup, word24 addr, word36 *data, UNUSED const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
3820 {
3821     SC_MAP_ADDR (addr, addr);
3822     LOCK_CORE_WORD(addr, & cpu.coreLockState);
3823     if (cpu.coreLockState.locked_addr != 0) {
3824       sim_warn ("core_read_lock: locked %08o locked_addr %08o %c %05o:%06o\r\n",
3825                 addr, cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
3826                 cpu.PPR.PSR, cpu.PPR.IC);
3827       core_unlock_all (cpup);
3828     }
3829     cpu.coreLockState.locked_addr = addr;
3830 # if !defined(SUNLINT)
3831     word36 v;
3832     LOAD_ACQ_CORE_WORD(v, addr);
3833     * data = v & DMASK;
3834 # endif /* if !defined(SUNLINT) */
3835     return 0;
3836 }
3837 #endif
3838 
3839 #if !defined(SPEED) || !defined(INLINE_CORE)
3840 int core_write (cpu_state_t * cpup, word24 addr, word36 data, const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
3841   {
3842     PNL (cpu.portBusy = true;)
3843     SC_MAP_ADDR (addr, addr);
3844     if (cpu.tweaks.isolts_mode)
3845       {
3846         if (cpu.MR.sdpap)
3847           {
3848             sim_warn ("failing to implement sdpap\r\n");
3849             cpu.MR.sdpap = 0;
3850           }
3851         if (cpu.MR.separ)
3852           {
3853             sim_warn ("failing to implement separ\r\n");
3854                 cpu.MR.separ = 0;
3855           }
3856       }
3857 # if defined(LOCKLESS)
3858     LOCK_CORE_WORD(addr, & cpu.coreLockState);
3859 #  if !defined(SUNLINT)
3860     STORE_REL_CORE_WORD(addr, data);
3861 #  endif /* if !defined(SUNLINT) */
3862 # else
3863     M[addr] = data & DMASK;
3864 # endif /* if defined(LOCKLESS) */
3865 # if !defined(SPEED)
3866     if (watch_bits [addr])
3867       {
3868         sim_msg ("WATCH [%llu] %05o:%06o write  %08llo %012llo (%s)\r\n",
3869                  (long long unsigned int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
3870                  (long long unsigned int)addr, (unsigned long long int)M [addr], ctx);
3871         traceInstruction (0);
3872       }
3873 # endif /* if !defined(SPEED) */
3874     DO_WORK_MEM;
3875     sim_debug (DBG_CORE, & cpu_dev,
3876                "core_write %08o %012"PRIo64" (%s)\r\n",
3877                 addr, data, ctx);
3878     PNL (trackport (addr, data));
3879     return 0;
3880   }
3881 #endif /* if !defined(SPEED) || !defined(INLINE_CORE) */
3882 
3883 #if defined(LOCKLESS)
3884 int core_write_unlock (cpu_state_t * cpup, word24 addr, word36 data, UNUSED const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
3885 {
3886     SC_MAP_ADDR (addr, addr);
3887     if (cpu.coreLockState.locked_addr != addr)
3888       {
3889         sim_warn ("core_write_unlock: locked %08o locked_addr %08o %c %05o:%06o\r\n",
3890                   addr,        cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
3891                   cpu.PPR.PSR, cpu.PPR.IC);
3892        core_unlock_all (cpup);
3893       }
3894 
3895 # if !defined(SUNLINT)
3896     STORE_REL_CORE_WORD(addr, data);
3897 # endif /* if !defined(SUNLINT) */
3898     cpu.coreLockState.locked_addr = 0;
3899     return 0;
3900 }
3901 
3902 int core_unlock_all (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
3903 {
3904   if (cpu.coreLockState.locked_addr != 0) {
3905       sim_warn ("core_unlock_all: locked %08o %c %05o:%06o\r\n",
3906                 cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
3907                 cpu.PPR.PSR,     cpu.PPR.IC);
3908 # if !defined(SUNLINT)
3909       STORE_REL_CORE_WORD(cpu.coreLockState.locked_addr, M[cpu.coreLockState.locked_addr]);
3910 # endif /* if !defined(SUNLINT) */
3911       cpu.coreLockState.locked_addr = 0;
3912   }
3913   return 0;
3914 }
3915 #endif
3916 
3917 #if !defined(SPEED) || !defined(INLINE_CORE)
3918 int core_write_zone (cpu_state_t * cpup, word24 addr, word36 data, const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
3919   {
3920     PNL (cpu.portBusy = true;)
3921     if (cpu.tweaks.isolts_mode)
3922       {
3923         if (cpu.MR.sdpap)
3924           {
3925             sim_warn ("failing to implement sdpap\r\n");
3926             cpu.MR.sdpap = 0;
3927           }
3928         if (cpu.MR.separ)
3929           {
3930             sim_warn ("failing to implement separ\r\n");
3931             cpu.MR.separ = 0;
3932           }
3933       }
3934     word24 mapAddr = 0;
3935     SC_MAP_ADDR (addr, mapAddr);
3936 # if defined(LOCKLESS)
3937     word36 v;
3938     core_read_lock(cpup, addr,  &v, ctx);
3939     v = (v & ~cpu.zone) | (data & cpu.zone);
3940     core_write_unlock(cpup, addr, v, ctx);
3941 # else
3942     M[mapAddr] = (M[mapAddr] & ~cpu.zone) | (data & cpu.zone);
3943 # endif
3944     cpu.useZone = false; // Safety
3945 # if !defined(SPEED)
3946     if (watch_bits [mapAddr])
3947       {
3948         sim_msg ("WATCH [%llu] %05o:%06o writez %08llo %012llo (%s)\r\n",
3949                 (unsigned long long int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
3950                 (unsigned long long int)mapAddr, (unsigned long long int)M [mapAddr], ctx);
3951         traceInstruction (0);
3952       }
3953 # endif
3954     DO_WORK_MEM;
3955     sim_debug (DBG_CORE, & cpu_dev,
3956                "core_write_zone %08o %012"PRIo64" (%s)\r\n",
3957                 mapAddr, data, ctx);
3958     PNL (trackport (mapAddr, data));
3959     return 0;
3960   }
3961 #endif
3962 
3963 #if !defined(SPEED) || !defined(INLINE_CORE)
3964 int core_read2 (cpu_state_t * cpup, word24 addr, word36 *even, word36 *odd, const char * ctx)
     /* [previous][next][first][last][top][bottom][index][help] */
3965   {
3966     PNL (cpu.portBusy = true;)
3967 # if defined(LOCKLESS)
3968     /*LINTED E_FUNC_VAR_UNUSED*/ /* Appease SUNLINT */
3969     word36 v;
3970 # endif
3971     if (addr & 1)
3972       {
3973         sim_debug (DBG_MSG, & cpu_dev,
3974                    "warning: subtracting 1 from pair at %o in "
3975                    "core_read2 (%s)\r\n", addr, ctx);
3976         addr &= (word24)~1; /* make it an even address */
3977       }
3978     SC_MAP_ADDR (addr, addr);
3979 # if !defined(LOCKLESS)
3980     if (M[addr] & MEM_UNINITIALIZED)
3981       {
3982         sim_debug (DBG_WARN, & cpu_dev,
3983                    "Uninitialized memory accessed at address %08o; "
3984                    "IC is 0%06o:0%06o (%s)\r\n",
3985                    addr, cpu.PPR.PSR, cpu.PPR.IC, ctx);
3986       }
3987 # endif
3988 # if !defined(SPEED)
3989     if (watch_bits [addr])
3990       {
3991         sim_msg ("WATCH [%llu] %05o:%06o read2  %08llo %012llo (%s)\r\n",
3992                  (unsigned long long int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
3993                  (unsigned long long int)addr, (unsigned long long int)M [addr], ctx);
3994         traceInstruction (0);
3995       }
3996 # endif
3997 # if defined(LOCKLESS)
3998 #  if !defined(SUNLINT)
3999     LOAD_ACQ_CORE_WORD(v, addr);
4000     if (v & MEM_LOCKED)
4001       sim_warn ("core_read2: even locked %08o locked_addr %08o %c %05o:%06o\r\n",
4002                 addr,        cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
4003                 cpu.PPR.PSR, cpu.PPR.IC);
4004     *even = v & DMASK;
4005     addr++;
4006 #  endif /* if !defined(SUNLINT) */
4007 # else
4008     *even = M[addr++] & DMASK;
4009 # endif
4010     sim_debug (DBG_CORE, & cpu_dev,
4011                "core_read2 %08o %012"PRIo64" (%s)\r\n",
4012                 addr - 1, * even, ctx);
4013 
4014     // if the even address is OK, the odd will be
4015     //nem_check (addr,  "core_read2 nem");
4016 # if !defined(LOCKLESS)
4017     if (M[addr] & MEM_UNINITIALIZED)
4018       {
4019         sim_debug (DBG_WARN, & cpu_dev,
4020                    "Uninitialized memory accessed at address %08o; "
4021                    "IC is 0%06o:0%06o (%s)\r\n",
4022                     addr, cpu.PPR.PSR, cpu.PPR.IC, ctx);
4023       }
4024 # endif
4025 # if !defined(SPEED)
4026     if (watch_bits [addr])
4027       {
4028         sim_msg ("WATCH [%llu] %05o:%06o read2  %08llo %012llo (%s)\r\n",
4029                  (unsigned long long int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
4030                  (unsigned long long int)addr, (unsigned long long int)M [addr], ctx);
4031         traceInstruction (0);
4032       }
4033 # endif
4034 # if defined(LOCKLESS)
4035 #  if !defined(SUNLINT)
4036     LOAD_ACQ_CORE_WORD(v, addr);
4037     if (v & MEM_LOCKED)
4038       sim_warn ("core_read2: odd locked %08o locked_addr %08o %c %05o:%06o\r\n",
4039                 addr,        cpu.coreLockState.locked_addr, current_running_cpu_idx + 'A',
4040                 cpu.PPR.PSR, cpu.PPR.IC);
4041     *odd = v & DMASK;
4042 #  endif /* if !defined(SUNLINT) */
4043 # else
4044     *odd = M[addr] & DMASK;
4045 # endif
4046     sim_debug (DBG_CORE, & cpu_dev,
4047                "core_read2 %08o %012"PRIo64" (%s)\r\n",
4048                 addr, * odd, ctx);
4049     DO_WORK_MEM;
4050     PNL (trackport (addr - 1, * even));
4051     return 0;
4052   }
4053 #endif
4054 
4055 #if !defined(SPEED) || !defined(INLINE_CORE)
4056 int core_write2 (cpu_state_t * cpup, word24 addr, word36 even, word36 odd, const char * ctx) {
     /* [previous][next][first][last][top][bottom][index][help] */
4057   PNL (cpu.portBusy = true;)
4058   if (addr & 1) {
4059     sim_debug (DBG_MSG, & cpu_dev,
4060                "warning: subtracting 1 from pair at %o in core_write2 " "(%s)\r\n",
4061                addr, ctx);
4062     addr &= (word24)~1; /* make it even a dress, or iron a skirt ;) */
4063   }
4064   SC_MAP_ADDR (addr, addr);
4065   if (cpu.tweaks.isolts_mode) {
4066     if (cpu.MR.sdpap) {
4067       sim_warn ("failing to implement sdpap\r\n");
4068       cpu.MR.sdpap = 0;
4069     }
4070     if (cpu.MR.separ) {
4071       sim_warn ("failing to implement separ\r\n");
4072       cpu.MR.separ = 0;
4073     }
4074   }
4075 
4076 # if !defined(SPEED)
4077   if (watch_bits [addr]) {
4078     sim_msg ("WATCH [%llu] %05o:%06o write2 %08llo %012llo (%s)\r\n",
4079              (unsigned long long int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
4080              (unsigned long long int)addr, (unsigned long long int)even, ctx);
4081     traceInstruction (0);
4082   }
4083 # endif
4084 # if defined(LOCKLESS)
4085   LOCK_CORE_WORD(addr, & cpu.coreLockState);
4086 #  if !defined(SUNLINT)
4087   STORE_REL_CORE_WORD(addr, even);
4088 #  endif /* if !defined(SUNLINT) */
4089   addr++;
4090 # else
4091   M[addr++] = even & DMASK;
4092 # endif
4093   sim_debug (DBG_CORE, & cpu_dev, "core_write2 %08o %012llo (%s)\r\n", addr - 1,
4094           (long long unsigned int)even, ctx);
4095 
4096   // If the even address is OK, the odd will be
4097   //mem_check (addr,  "core_write2 nem");
4098 
4099 # if !defined(SPEED)
4100   if (watch_bits [addr]) {
4101     sim_msg ("WATCH [%llu] %05o:%06o write2 %08llo %012llo (%s)\r\n",
4102              (long long unsigned int)cpu.cycleCnt, cpu.PPR.PSR, cpu.PPR.IC,
4103              (long long unsigned int)addr, (long long unsigned int)odd, ctx);
4104     traceInstruction (0);
4105   }
4106 # endif
4107 # if defined(LOCKLESS)
4108   LOCK_CORE_WORD(addr, & cpu.coreLockState);
4109 #  if !defined(SUNLINT)
4110   STORE_REL_CORE_WORD(addr, odd);
4111 #  endif /* if !defined(SUNLINT) */
4112 # else
4113   M[addr] = odd & DMASK;
4114 # endif
4115   DO_WORK_MEM;
4116   PNL (trackport (addr - 1, even));
4117   sim_debug (DBG_CORE, & cpu_dev, "core_write2 %08o %012"PRIo64" (%s)\r\n", addr, odd, ctx);
4118   return 0;
4119 }
4120 #endif
4121 
4122 /*
4123  * Instruction fetcher ...
4124  * Fetch + decode instruction at 18-bit address 'addr'
4125  */
4126 
4127 /*
4128  * Instruction decoder .....
4129  */
4130 
4131 void decode_instruction (cpu_state_t * cpup, word36 inst, DCDstruct * p)
     /* [previous][next][first][last][top][bottom][index][help] */
4132   {
4133     CPT (cpt1L, 17); // instruction decoder
4134     (void)memset (p, 0, sizeof (DCDstruct));
4135 
4136     p->opcode   = GET_OP (inst);   // get opcode
4137     p->opcodeX  = GET_OPX(inst);   // opcode extension
4138     p->opcode10 = p->opcode | (p->opcodeX ? 01000 : 0); //-V536
4139     p->address  = GET_ADDR (inst); // address field from instruction
4140     p->b29      = GET_A (inst);    // "A" the indirect via pointer register flag
4141     p->i        = GET_I (inst);    // "I" inhibit interrupt flag
4142     p->tag      = GET_TAG (inst);  // instruction tag
4143 
4144     p->info     = get_iwb_info  (p);     // get info for IWB instruction
4145 
4146     if (p->info->flags & IGN_B29)
4147         p->b29 = 0;   // make certain 'a' bit is valid always
4148 
4149     if (p->info->ndes > 0)
4150       {
4151         p->b29 = 0;
4152         p->tag = 0;
4153         if (p->info->ndes > 1)
4154           {
4155             (void)memset (& cpu.currentEISinstruction, 0,
4156                           sizeof (cpu.currentEISinstruction));
4157           }
4158       }
4159   }
4160 
4161 // MM stuff ...
4162 
4163 //
4164 // is_priv_mode()
4165 //
4166 // Report whether or or not the CPU is in privileged mode.
4167 // True if in absolute mode or if priv bit is on in segment TPR.TSR
4168 // The processor executes instructions in privileged mode when forming
4169 // addresses in absolute mode or when forming addresses in append mode and the
4170 // segment descriptor word (SDW) for the segment in execution specifies a
4171 // privileged procedure and the execution ring is equal to zero.
4172 //
4173 // PPR.P A flag controlling execution of privileged instructions.
4174 //
4175 // Its value is 1 (permitting execution of privileged instructions) if PPR.PRR
4176 // is 0 and the privileged bit in the segment descriptor word (SDW.P) for the
4177 // procedure is 1; otherwise, its value is 0.
4178 //
4179 
4180 int is_priv_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4181   {
4182 // Back when it was ABS/APP/BAR, this test was right; now that
4183 // it is ABS/APP,BAR/NBAR, check bar mode.
4184 // Fixes ISOLTS 890 05a.
4185     if (get_bar_mode (cpup))
4186       return 0;
4187 
4188 // PPR.P is only relevant if we're in APPEND mode. ABSOLUTE mode ignores it.
4189     if (get_addr_mode (cpup) == ABSOLUTE_mode)
4190       return 1;
4191     else if (cpu.PPR.P)
4192       return 1;
4193 
4194     return 0;
4195   }
4196 
4197 /*
4198  * get_bar_mode: During fault processing, we do not want to fetch and execute
4199  * the fault vector instructions in BAR mode. We leverage the
4200  * secret_addressing_mode flag that is set in set_TEMPORARY_ABSOLUTE_MODE to
4201  * direct us to ignore the I_NBAR indicator register.
4202  */
4203 
4204 bool get_bar_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4205   {
4206     return ! (cpu.secret_addressing_mode || TST_I_NBAR);
4207   }
4208 
4209 addr_modes_e get_addr_mode (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4210   {
4211     if (cpu.secret_addressing_mode)
4212         return ABSOLUTE_mode; // This is not the mode you are looking for
4213 
4214     // went_appending does not alter privileged state (only enables appending)
4215     // the went_appending check is only required by ABSA, AFAICT
4216     // pft 02b 013255, ISOLTS-860
4217     //if (cpu.went_appending)
4218     //    return APPEND_mode;
4219 
4220     if (TST_I_ABS)
4221       {
4222           return ABSOLUTE_mode;
4223       }
4224     else
4225       {
4226           return APPEND_mode;
4227       }
4228   }
4229 
4230 /*
4231  * set_addr_mode()
4232  *
4233  * Put the CPU into the specified addressing mode.   This involves
4234  * setting a couple of IR flags and the PPR priv flag.
4235  */
4236 
4237 void set_addr_mode (cpu_state_t * cpup, addr_modes_e mode)
     /* [previous][next][first][last][top][bottom][index][help] */
4238   {
4239 //    cpu.cu.XSF = false;
4240 //sim_debug (DBG_TRACEEXT, & cpu_dev, "set_addr_mode bit 29 sets XSF to 0\r\n");
4241     //cpu.went_appending = false;
4242 // Temporary hack to fix fault/intr pair address mode state tracking
4243 //   1. secret_addressing_mode is only set in fault/intr pair processing.
4244 //   2. Assume that the only set_addr_mode that will occur is the b29 special
4245 //   case or ITx.
4246     //if (secret_addressing_mode && mode == APPEND_mode)
4247       //set_went_appending ();
4248 
4249     cpu.secret_addressing_mode = false;
4250     if (mode == ABSOLUTE_mode)
4251       {
4252         CPT (cpt1L, 22); // set abs mode
4253         sim_debug (DBG_DEBUG, & cpu_dev, "APU: Setting absolute mode.\r\n");
4254 
4255         SET_I_ABS;
4256         cpu.PPR.P = 1;
4257       }
4258     else if (mode == APPEND_mode)
4259       {
4260         CPT (cpt1L, 23); // set append mode
4261         if (! TST_I_ABS && TST_I_NBAR)
4262           sim_debug (DBG_DEBUG, & cpu_dev, "APU: Keeping append mode.\r\n");
4263         else
4264           sim_debug (DBG_DEBUG, & cpu_dev, "APU: Setting append mode.\r\n");
4265 
4266         CLR_I_ABS;
4267       }
4268     else
4269       {
4270         sim_debug (DBG_ERR, & cpu_dev,
4271                   "APU: Unable to determine address mode.\r\n");
4272         sim_warn ("APU: Unable to determine address mode. Can't happen!\r\n");
4273       }
4274   }
4275 
4276 /*
4277  * stuff to handle BAR mode ...
4278  */
4279 
4280 /*
4281  * The Base Address Register provides automatic hardware Address relocation and
4282  * Address range limitation when the processor is in BAR mode.
4283  *
4284  * BAR.BASE: Contains the 9 high-order bits of an 18-bit address relocation
4285  * constant. The low-order bits are generated as zeros.
4286  *
4287  * BAR.BOUND: Contains the 9 high-order bits of the unrelocated address limit.
4288  * The low- order bits are generated as zeros. An attempt to access main memory
4289  * beyond this limit causes a store fault, out of bounds. A value of 0 is truly
4290  * 0, indicating a null memory range.
4291  *
4292  * In BAR mode, the base address register (BAR) is used. The BAR contains an
4293  * address bound and a base address. All computed addresses are relocated by
4294  * adding the base address. The relocated address is combined with the
4295  * procedure pointer register to form the virtual memory address. A program is
4296  * kept within certain limits by subtracting the unrelocated computed address
4297  * from the address bound. If the result is zero or negative, the relocated
4298  * address is out of range, and a store fault occurs.
4299  */
4300 
4301 // CANFAULT
4302 word18 get_BAR_address (cpu_state_t * cpup, word18 addr)
     /* [previous][next][first][last][top][bottom][index][help] */
4303   {
4304     if (cpu . BAR.BOUND == 0)
4305         // store fault, out of bounds.
4306         doFault (FAULT_STR, fst_str_oob, "BAR store fault; out of bounds");
4307 
4308     // A program is kept within certain limits by subtracting the
4309     // unrelocated computed address from the address bound. If the result
4310     // is zero or negative, the relocated address is out of range, and a
4311     // store fault occurs.
4312     //
4313     // BAR.BOUND - CA <= 0
4314     // BAR.BOUND <= CA
4315     // CA >= BAR.BOUND
4316     //
4317     if (addr >= (((word18) cpu . BAR.BOUND) << 9))
4318         // store fault, out of bounds.
4319         doFault (FAULT_STR, fst_str_oob, "BAR store fault; out of bounds");
4320 
4321     word18 barAddr = (addr + (((word18) cpu . BAR.BASE) << 9)) & 0777777;
4322     return barAddr;
4323   }
4324 
4325 //=============================================================================
4326 
4327 static void add_history (cpu_state_t * cpup, uint hset, word36 w0, word36 w1)
     /* [previous][next][first][last][top][bottom][index][help] */
4328   {
4329     //if (cpu.MR.emr)
4330       {
4331         cpu.history [hset] [cpu.history_cyclic[hset]] [0] = w0;
4332         cpu.history [hset] [cpu.history_cyclic[hset]] [1] = w1;
4333         cpu.history_cyclic[hset] = (cpu.history_cyclic[hset] + 1) % N_MODEL_HIST_SIZE;
4334       }
4335   }
4336 
4337 void add_history_force (cpu_state_t * cpup, uint hset, word36 w0, word36 w1)
     /* [previous][next][first][last][top][bottom][index][help] */
4338   {
4339     cpu.history [hset] [cpu.history_cyclic[hset]] [0] = w0;
4340     cpu.history [hset] [cpu.history_cyclic[hset]] [1] = w1;
4341     cpu.history_cyclic[hset] = (cpu.history_cyclic[hset] + 1) % N_MODEL_HIST_SIZE;
4342   }
4343 
4344 void add_dps8m_CU_history (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4345   {
4346     if (cpu.skip_cu_hist)
4347       return;
4348     if (! cpu.MR_cache.emr)
4349       return;
4350     if (! cpu.MR_cache.ihr)
4351       return;
4352     if (cpu.MR_cache.hrxfr && ! cpu.wasXfer)
4353       return;
4354 
4355     word36 flags   = 0; // XXX fill out
4356     word5 proccmd  = 0; // XXX fill out
4357     word7 flags2   = 0; // XXX fill out
4358     word36 w0      = 0, w1 = 0;
4359     w0            |= flags & 0777777000000;
4360     w0            |= IWB_IRODD & MASK18;
4361     w1            |= ((word36)(cpu.iefpFinalAddress & MASK24) << 12);
4362     w1            |= (proccmd & MASK5) << 7;
4363     w1            |= flags2 & 0176;
4364     add_history (cpup, CU_HIST_REG, w0, w1);
4365   }
4366 
4367 #if !defined(QUIET_UNUSED)
4368 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] */
4369   {
4370     word36 w0  = flags, w1 = 0;
4371     w1        |= (ICT & MASK18) << 18;
4372     w1        |= (RS_REG & MASK9) << 9;
4373     w1        |= flags2 & MASK9;
4374     add_history (cpup, DPS8M_DU_OU_HIST_REG, w0, w1);
4375   }
4376 
4377 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] */
4378   {
4379     word36 w0  = 0, w1 = 0;
4380     w0        |= (ESN & MASK15) << 21;
4381     w0        |= flags & MASK21;
4382     w1        |= (RMA & MASK24) << 12;
4383     w1        |= (RTRR & MASK3) << 9;
4384     w1        |= flags2 & MASK9;
4385     add_history (cpu.tweaks.l68_mode ? L68_APU_HIST_REG : DPS8M_APU_HIST_REG, w0, w1);
4386   }
4387 
4388 void add_dps8m_EAPU_history (word18 ZCA, word18 opcode)
     /* [previous][next][first][last][top][bottom][index][help] */
4389   {
4390     word36 w0  = 0;
4391     w0        |= (ZCA & MASK18) << 18;
4392     w0        |= opcode & MASK18;
4393     add_history (DPS8M_EAPU_HIST_REG, w0, 0);
4394     //cpu.eapu_hist[cpu.eapu_cyclic].ZCA = ZCA;
4395     //cpu.eapu_hist[cpu.eapu_cyclic].opcode = opcode;
4396     //cpu.history_cyclic[DPS8M_EAPU_HIST_REG] =
4397       //(cpu.history_cyclic[DPS8M_EAPU_HIST_REG] + 1) % N_DPS8M_HIST_SIZE;
4398   }
4399 #endif
4400 
4401 // According to ISOLTS
4402 //
4403 //   0 PIA
4404 //   1 POA
4405 //   2 RIW
4406 //   3 SIW
4407 //   4 POT
4408 //   5 PON
4409 //   6 RAW
4410 //   7 SAW
4411 //   8 TRGO
4412 //   9 XDE
4413 //  10 XDO
4414 //  11 IC
4415 //  12 RPTS
4416 //  13 WI
4417 //  14 AR F/E
4418 //  15 XIP
4419 //  16 FLT
4420 //  17 COMPL. ADD BASE
4421 //  18:23 OPCODE/TAG
4422 //  24:29 ADDREG
4423 //  30:34 COMMAND A/B/C/D/E
4424 //  35:38 PORT A/B/C/D
4425 //  39 FB XEC
4426 //  40 INS FETCH
4427 //  41 CU STORE
4428 //  42 OU STORE
4429 //  43 CU LOAD
4430 //  44 OU LOAD
4431 //  45 RB DIRECT
4432 //  46 -PC BUSY
4433 //  47 PORT BUSY
4434 
4435 void add_l68_CU_history (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4436   {
4437     CPT (cpt1L, 24); // add cu hist
4438 // XXX strobe on opcode match
4439     if (cpu.skip_cu_hist)
4440       return;
4441     if (! cpu.MR_cache.emr)
4442       return;
4443     if (! cpu.MR_cache.ihr)
4444       return;
4445 
4446     word36 w0 = 0, w1 = 0;
4447 
4448     // 0 PIA
4449     // 1 POA
4450     // 2 RIW
4451     // 3 SIW
4452     // 4 POT
4453     // 5 PON
4454     // 6 RAW
4455     // 7 SAW
4456     PNL (putbits36_8 (& w0, 0, cpu.prepare_state);)
4457     // 8 TRG
4458     putbits36_1  (& w0, 8, cpu.wasXfer);
4459     // 9 XDE
4460     putbits36_1  (& w0, 9, cpu.cu.xde);
4461     // 10 XDO
4462     putbits36_1  (& w0, 10, cpu.cu.xdo);
4463     // 11 IC
4464     putbits36_1  (& w0, 11, USE_IRODD?1:0);
4465     // 12 RPT
4466     putbits36_1  (& w0, 12, cpu.cu.rpt);
4467     // 13 WI Wait for instruction fetch XXX Not tracked
4468     // 14 ARF "AR F/E" Address register Full/Empty Address has valid data
4469     PNL (putbits36_1 (& w0, 14, cpu.AR_F_E);)
4470     // 15 !XA/Z "-XIP NOT prepare interrupt address"
4471     putbits36_1  (& w0, 15, cpu.cycle != INTERRUPT_cycle?1:0);
4472     // 16 !FA/Z Not tracked. (cu.-FL?)
4473     putbits36_1  (& w0, 16, cpu.cycle != FAULT_cycle?1:0);
4474     // 17 M/S  (master/slave, cu.-BASE?, NOT BAR MODE)
4475     putbits36_1  (& w0, 17, TSTF (cpu.cu.IR, I_NBAR)?1:0);
4476     // 18:35 IWR (lower half of IWB)
4477     putbits36_18 (& w0, 18, (word18) (IWB_IRODD & MASK18));
4478 
4479     // 36:53 CA
4480     putbits36_18 (& w1, 0, cpu.TPR.CA);
4481     // 54:58 CMD system controller command XXX
4482     // 59:62 SEL port select (XXX ignoring "only valid if port A-D is selected")
4483     PNL (putbits36_1 (& w1, 59-36, (cpu.portSelect == 0)?1:0);)
4484     PNL (putbits36_1 (& w1, 60-36, (cpu.portSelect == 1)?1:0);)
4485     PNL (putbits36_1 (& w1, 61-36, (cpu.portSelect == 2)?1:0);)
4486     PNL (putbits36_1 (& w1, 62-36, (cpu.portSelect == 3)?1:0);)
4487     // 63 XEC-INT An interrupt is present
4488     putbits36_1 (& w1, 63-36, cpu.interrupt_flag?1:0);
4489     // 64 INS-FETCH Perform an instruction fetch
4490     PNL (putbits36_1 (& w1, 64-36, cpu.INS_FETCH?1:0);)
4491     // 65 CU-STORE Control unit store cycle XXX
4492     // 66 OU-STORE Operations unit store cycle XXX
4493     // 67 CU-LOAD Control unit load cycle XXX
4494     // 68 OU-LOAD Operations unit load cycle XXX
4495     // 69 DIRECT Direct cycle XXX
4496     // 70 -PC-BUSY Port control logic not busy XXX
4497     // 71 BUSY Port interface busy XXX
4498 
4499     add_history (cpup, CU_HIST_REG, w0, w1);
4500 
4501     // Check for overflow
4502     CPTUR (cptUseMR);
4503     if (cpu.MR.hrhlt && cpu.history_cyclic[CU_HIST_REG] == 0)
4504       {
4505         //cpu.history_cyclic[CU_HIST_REG] = 15;
4506         if (cpu.MR.ihrrs)
4507           {
4508             cpu.MR.ihr = 0;
4509           }
4510         set_FFV_fault (cpup, 4);
4511         return;
4512       }
4513   }
4514 
4515 // du history register inputs(actual names)
4516 // bit 00= fpol-cx;010       bit 36= fdud-dg;112
4517 // bit 01= fpop-cx;010       bit 37= fgdlda-dc;010
4518 // bit 02= need-desc-bd;000  bit 38= fgdldb-dc;010
4519 // bit 03= sel-adr-bd;000    bit 39= fgdldc-dc;010
4520 // bit 04= dlen=direct-bd;000bit 40= fnld1-dp;110
4521 // bit 05= dfrst-bd;021      bit 41= fgldp1-dc;110
4522 // bit 06= fexr-bd;010       bit 42= fnld2-dp;110
4523 // bit 07= dlast-frst-bd;010 bit 43= fgldp2-dc;110
4524 // bit 08= ddu-ldea-bd;000   bit 44= fanld1-dp;110
4525 // bit 09= ddu-stea-bd;000   bit 45= fanld2-dp;110
4526 // bit 10= dredo-bd;030      bit 46= fldwrt1-dp;110
4527 // bit 11= dlvl<wd-sz-bg;000 bit 47= fldwrt2-dp;110
4528 // bit 12= exh-bg;000        bit 48= data-avldu-cm;000
4529 // bit 13= dend-seg-bd;111   bit 49= fwrt1-dp;110
4530 // bit 14= dend-bd;000       bit 50= fgstr-dc;110
4531 // bit 15= du=rd+wrt-bd;010  bit 51= fanstr-dp;110
4532 // bit 16= ptra00-bd;000     bit 52= fstr-op-av-dg;010
4533 // bit 17= ptra01-bd;000     bit 53= fend-seg-dg;010
4534 // bit 18= fa/i1-bd;110      bit 54= flen<128-dg;010
4535 // bit 19= fa/i2-bd;110      bit 55= fgch-dp;110
4536 // bit 20= fa/i3-bd;110      bit 56= fanpk-dp;110
4537 // bit 21= wrd-bd;000        bit 57= fexmop-dl;110
4538 // bit 22= nine-bd;000       bit 58= fblnk-dp;100
4539 // bit 23= six-bd;000        bit 59= unused
4540 // bit 24= four-bd;000       bit 60= dgbd-dc;100
4541 // bit 25= bit-bd;000        bit 61= dgdb-dc;100
4542 // bit 26= unused            bit 62= dgsp-dc;100
4543 // bit 27= unused            bit 63= ffltg-dc;110
4544 // bit 28= unused            bit 64= frnd-dg;120
4545 // bit 29= unused            bit 65= dadd-gate-dc;100
4546 // bit 30= fsampl-bd;111     bit 66= dmp+dv-gate-db;100
4547 // bit 31= dfrst-ct-bd;010   bit 67= dxpn-gate-dg;100
4548 // bit 32= adj-lenint-cx;000 bit 68= unused
4549 // bit 33= fintrptd-cx;010   bit 69= unused
4550 // bit 34= finhib-stc1-cx;010bit 70= unused
4551 // bit 35= unused            bit 71= unused
4552 
4553 void add_l68_DU_history (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4554   {
4555     CPT (cpt1L, 25); // add du hist
4556     PNL (add_history (cpup, L68_DU_HIST_REG, cpu.du.cycle1, cpu.du.cycle2);)
4557   }
4558 
4559 void add_l68_OU_history (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
4560   {
4561     CPT (cpt1L, 26); // add ou hist
4562     word36 w0 = 0, w1 = 0;
4563 
4564     // 0-16 RP
4565     //   0-8 OP CODE
4566     PNL (putbits36_9 (& w0,  0,       cpu.ou.RS);)
4567 
4568     //   9 CHAR
4569     putbits36_1 (& w0,       9,       cpu.ou.characterOperandSize ? 1 : 0);
4570 
4571     //   10-12 TAG 1/2/3
4572     putbits36_3 (& w0,       10,      cpu.ou.characterOperandOffset);
4573 
4574     //   13 CRFLAG
4575     putbits36_1 (& w0,       13,      cpu.ou.crflag);
4576 
4577     //   14 DRFLAG
4578     putbits36_1 (& w0,       14,      cpu.ou.directOperandFlag ? 1 : 0);
4579 
4580     //   15-16 EAC
4581     putbits36_2 (& w0,       15,      cpu.ou.eac);
4582 
4583     // 17 0
4584     // 18-26 RS REG
4585     PNL (putbits36_9 (& w0,  18,      cpu.ou.RS);)
4586 
4587     // 27 RB1 FULL
4588     putbits36_1 (& w0,       27,      cpu.ou.RB1_FULL);
4589 
4590     // 28 RP FULL
4591     putbits36_1 (& w0,       28,      cpu.ou.RP_FULL);
4592 
4593     // 29 RS FULL
4594     putbits36_1 (& w0,       29,      cpu.ou.RS_FULL);
4595 
4596     // 30-35 GIN/GOS/GD1/GD2/GOE/GOA
4597     putbits36_6 (& w0,       30,      (word6) (cpu.ou.cycle >> 3));
4598 
4599     // 36-38 GOM/GON/GOF
4600     putbits36_3 (& w1,       36-36,   (word3) cpu.ou.cycle);
4601 
4602     // 39 STR OP
4603     putbits36_1 (& w1,       39-36,   cpu.ou.STR_OP);
4604 
4605     // 40 -DA-AV XXX
4606 
4607     // 41-50 stuvwyyzAB -A-REG -Q-REG -X0-REG .. -X7-REG
4608     PNL (putbits36_10 (& w1, 41-36,
4609          (word10) ~opcodes10 [cpu.ou.RS].reg_use);)
4610 
4611     // 51-53 0
4612 
4613     // 54-71 ICT TRACKER
4614     putbits36_18 (& w1,      54 - 36, cpu.PPR.IC);
4615 
4616     add_history (cpup, L68_OU_HIST_REG, w0, w1);
4617   }
4618 
4619 // According to ISOLTS
4620 //  0:2 OPCODE RP
4621 //  3 9 BIT CHAR
4622 //  4:6 TAG 3/4/5
4623 //  7 CR FLAG
4624 //  8 DIR FLAG
4625 //  9 RP15
4626 // 10 RP16
4627 // 11 SPARE
4628 // 12:14 OPCODE RS
4629 // 15 RB1 FULL
4630 // 16 RP FULL
4631 // 17 RS FULL
4632 // 18 GIN
4633 // 19 GOS
4634 // 20 GD1
4635 // 21 GD2
4636 // 22 GOE
4637 // 23 GOA
4638 // 24 GOM
4639 // 25 GON
4640 // 26 GOF
4641 // 27 STORE OP
4642 // 28 DA NOT
4643 // 29:38 COMPLEMENTED REGISTER IN USE FLAG A/Q/0/1/2/3/4/5/6/7
4644 // 39 ?
4645 // 40 ?
4646 // 41 ?
4647 // 42:47 ICT TRACT
4648 
4649 // XXX add_APU_history
4650 
4651 //  0:5 SEGMENT NUMBER
4652 //  6 SNR/ESN
4653 //  7 TSR/ESN
4654 //  8 FSDPTW
4655 //  9 FPTW2
4656 // 10 MPTW
4657 // 11 FANP
4658 // 12 FAP
4659 // 13 AMSDW
4660 // 14:15 AMSDW #
4661 // 16 AMPTW
4662 // 17:18 AMPW #
4663 // 19 ACV/DF
4664 // 20:27 ABSOLUTE MEMORY ADDRESS
4665 // 28 TRR #
4666 // 29 FLT HLD
4667 
4668 void add_l68_APU_history (cpu_state_t * cpup, enum APUH_e op)
     /* [previous][next][first][last][top][bottom][index][help] */
4669   {
4670     CPT (cpt1L, 28); // add apu hist
4671     word36 w0 = 0, w1 = 0;
4672 
4673     w0 = op; // set 17-24 FDSPTW/.../FAP bits
4674 
4675     // 0-14 ESN
4676     putbits36_15 (& w0,      0,  cpu.TPR.TSR);
4677     // 15-16 BSY
4678     PNL (putbits36_1 (& w0,  15, (cpu.apu.state & apu_ESN_SNR) ? 1 : 0);)
4679     PNL (putbits36_1 (& w0,  16, (cpu.apu.state & apu_ESN_TSR) ? 1 : 0);)
4680     // 25 SDWAMM
4681     putbits36_1 (& w0,       25, cpu.cu.SDWAMM);
4682     // 26-29 SDWAMR
4683     putbits36_4 (& w0,       26, (word4) cpu.SDWAMR);
4684     // 30 PTWAMM
4685     putbits36_1 (& w0,       30, cpu.cu.PTWAMM);
4686     // 31-34 PTWAMR
4687     putbits36_4 (& w0,       31, (word4) cpu.PTWAMR);
4688     // 35 FLT
4689     PNL (putbits36_1 (& w0,  35, (cpu.apu.state & apu_FLT) ? 1 : 0);)
4690 
4691     // 36-59 ADD
4692     PNL (putbits36_24 (& w1, 0,  cpu.APUMemAddr);)
4693     // 60-62 TRR
4694     putbits36_3 (& w1,       24, cpu.TPR.TRR);
4695     // 66 XXX Multiple match error in SDWAM
4696     // 70 Segment is encachable
4697     putbits36_1 (& w1,       34, cpu.SDW0.C);
4698     // 71 XXX Multiple match error in PTWAM
4699 
4700     add_history (cpup, L68_APU_HIST_REG, w0, w1);
4701   }
4702 
4703 #if defined(THREADZ) || defined(LOCKLESS)
4704 //static pthread_mutex_t debug_lock = PTHREAD_MUTEX_INITIALIZER;
4705 
4706 static const char * get_dbg_verb (uint32 dbits, DEVICE * dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
4707   {
4708     static const char * debtab_none    = "DEBTAB_ISNULL";
4709     static const char * debtab_nomatch = "DEBTAB_NOMATCH";
4710     const char * some_match            = NULL;
4711     int32 offset                       = 0;
4712 
4713     if (dptr->debflags == 0)
4714       return debtab_none;
4715 
4716     dbits &= dptr->dctrl;     /* Look for just the bits that matched */
4717 
4718     /* Find matching words for bitmask */
4719     while ((offset < 32) && dptr->debflags[offset].name)
4720       {
4721         if (dptr->debflags[offset].mask == dbits)   /* All Bits Match */
4722           return dptr->debflags[offset].name;
4723         if (dptr->debflags[offset].mask & dbits)
4724           some_match = dptr->debflags[offset].name;
4725         offset ++;
4726       }
4727     return some_match ? some_match : debtab_nomatch;
4728   }
4729 
4730 void dps8_sim_debug (uint32 dbits, DEVICE * dptr, unsigned long long cnt, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
4731   {
4732     //pthread_mutex_lock (& debug_lock);
4733     if (sim_deb && dptr && (dptr->dctrl & dbits))
4734       {
4735         const char * debug_type = get_dbg_verb (dbits, dptr);
4736         char stackbuf[STACKBUFSIZE];
4737         int32 bufsize           = sizeof (stackbuf);
4738         char * buf              = stackbuf;
4739         va_list arglist;
4740         int32 i, j, len;
4741         struct timespec t;
4742         clock_gettime(CLOCK_REALTIME, &t);
4743 
4744         buf [bufsize-1] = '\0';
4745 
4746         while (1)
4747           {                 /* format passed string, args */
4748             va_start (arglist, fmt);
4749             len = vsnprintf (buf, (int)((unsigned long)(bufsize)-1), fmt, arglist);
4750             va_end (arglist);
4751 
4752 /* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
4753 
4754             if ((len < 0) || (len >= bufsize-1))
4755               {
4756                 if (buf != stackbuf)
4757                   FREE (buf);
4758                 if (bufsize >= (INT_MAX / 2))
4759                   return;                                   /* too big */
4760                 bufsize = bufsize * 2;
4761                 if (bufsize < len + 2)
4762                   bufsize = len + 2;
4763                 buf = (char *) malloc ((unsigned long) bufsize);
4764                 if (buf == NULL)                            /* out of memory */
4765                   return;
4766                 buf[bufsize-1] = '\0';
4767                 continue;
4768               }
4769             break;
4770           }
4771 
4772 /* Output the formatted data expanding newlines where they exist */
4773 
4774         for (i = j = 0; i < len; ++i)
4775           {
4776             if ('\n' == buf[i])
4777               {
4778                 if (i >= j)
4779                   {
4780                     if ((i != j) || (i == 0))
4781                       {
4782                           (void)fprintf (sim_deb, "%lld.%06ld: DBG(%lld) %o: %s %s %.*s\r\n",
4783                                          (long long)t.tv_sec, t.tv_nsec/1000, cnt,
4784                                          current_running_cpu_idx, dptr->name, debug_type, i-j, &buf[j]);
4785                       }
4786                   }
4787                 j = i + 1;
4788               }
4789           }
4790 
4791         /* Set unterminated flag for next time */
4792         if (buf != stackbuf)
4793           FREE (buf);
4794       }
4795     //pthread_mutex_unlock (& debug_lock);
4796   }
4797 #endif
4798 
4799 void setupPROM (uint cpuNo, unsigned char * PROM) {
     /* [previous][next][first][last][top][bottom][index][help] */
4800 // 58009997-040 MULTICS Differences Manual DPS 8-70M Aug83
4801 //
4802 // THESE OFFSETS ARE IN OCTAL
4803 //
4804 //  0-13 CPU Model Number
4805 // 13-25 CPU Serial Number
4806 // 26-33 Date-Ship code (YYMMDD)
4807 // 34-40 CPU ID Field (reference RSW 2)
4808 //  Byte 40: Bits 03 (Bits 32-35 of RSW 2 Field
4809 //           Bit 4=1 Hex Option included
4810 //           Bit 5=1 RSCR (Clock) is Slave Mode included
4811 //           Bits 6-7 Reserved for later use.
4812 //       50: Operating System Use
4813 // 51-1777(8) To be defined.
4814 // NOTE: There is the possibility of disagreement between the
4815 //       ID bits of RSW 2 and the ID bits of PROM locations
4816 //       35-40. This condition could result when alterable
4817 //       configuration condition is contained in the PROM.
4818 //       The user is advised to ignore the PROM fields which
4819 //       contain the processor fault vector base (GCOS III)
4820 //       and the processor number and rely on the RSW 2 bits
4821 //       for this purpose. Bits 14-16 of the RSW 2 should be
4822 //       ignored and the bits representing this information in
4823 //       the PROM should be treated as valid.
4824 
4825 // "0-13" disagrees with Multics source (start_pl1); it interprets
4826 // it as "0-12"; most likely a typo in 58009997-040.
4827 
4828 // CAC notes: I interpret the fields as
4829 //  0-12 CPU Model Number                                          //  0-10  11 chars
4830 // 13-25 CPU Serial Number // 13 chars                             // 11-21  11 chars
4831 // 26-33 Date-Ship code (YYMMDD) // 8 chars (enough for YYYYMMDD). // 22-27   6 chars
4832 // 34-40 CPU ID Field (reference RSW 2)                            // 28-32   5 chars
4833 //  Byte 40: Bits 03 (Bits 32-35 of RSW 2 Field                    //    32
4834 //           Bit 4=1 Hex Option included
4835 //           Bit 5=1 RSCR (Clock) is Slave Mode included
4836 //           Bits 6-7 Reserved for later use.
4837 //       50: Operating System Use                                  //    40
4838 
4839   word36 rsw2 = 0;
4840 
4841   // The PROM copy of RSW 2 contains a canonical RSW 2 rather than the actual RSW 2.
4842   //   The port interlace is set to 0
4843   //   The fault base is set to 2 (Multics)
4844   //   Processor mode is set to 0 (Multics)
4845 
4846   //  0 -   3   4   Port interlace = 0000
4847   putbits36_4 (& rsw2,  0,   0);
4848   //  4 -   5   2   CPU type  01 = DPS8
4849   putbits36_2 (& rsw2,  4,  001);
4850   //  6 - 12    7   Fault Base  = 2
4851   putbits36_7 (& rsw2,  6,   2);
4852   // 13 - 13    1   PROM Present = 1
4853   putbits36_1 (& rsw2,  13,  1);
4854   // 14 - 18    5   Pad 00000
4855   putbits36_5 (& rsw2,  14,  0);
4856   // 19 - 19    1   CPU  1 = DPS8
4857   putbits36_1 (& rsw2,  19,  1);
4858   // 20 - 20    1   8K Cache  1 = Present
4859   putbits36_1 (& rsw2,  20,  cpus[cpuNo].options.cache_installed ? 1 : 0);
4860   // 21 - 22    2   Pad
4861   putbits36_2 (& rsw2,  21,  0);
4862   // 23 - 23    1   Always 1 for Multics CPU
4863   putbits36_1 (& rsw2,  23,  1);
4864   // 24 - 24    1   Proc Mode Bit
4865   putbits36_1 (& rsw2,  24,  0);
4866   // 25 - 28    4   Pad
4867   putbits36_4 (& rsw2,  25,  0);
4868   // 29 - 32    4   CPU speed options
4869   putbits36_4 (& rsw2,  29,  cpus[cpuNo].options.proc_speed & 017LL);
4870   // 33 - 35    3   CPU number
4871   putbits36_3 (& rsw2,  33,  cpus[cpuNo].switches.cpu_num & 07LL);
4872 
4873   word4 rsw2Ext = 0;
4874   if (cpus[cpuNo].options.hex_mode_installed)
4875     rsw2Ext |= 010;  // bit 4
4876   if (cpus[cpuNo].options.clock_slave_installed)
4877     rsw2Ext |= 004;  // bit 5
4878   // bits 6,7 reserved for future use
4879 
4880   char serial[12];
4881   (void)sprintf (serial, "%-11u", cpus[cpuNo].switches.serno);
4882 
4883 #if defined(VER_H_PROM_SHIP)
4884   char * ship = VER_H_PROM_SHIP;
4885 #else
4886   char * ship = "200101";
4887 #endif /* VER_H_PROM_SHIP */
4888 
4889 #if !defined(VER_H_PROM_MAJOR_VER)
4890 # define VER_H_PROM_MAJOR_VER "999"
4891 #endif /* VER_H_PROM_MAJOR_VER */
4892 
4893 #if !defined(VER_H_PROM_MINOR_VER)
4894 # define VER_H_PROM_MINOR_VER "999"
4895 #endif /* VER_H_PROM_MINOR_VER */
4896 
4897 #if !defined(VER_H_PROM_PATCH_VER)
4898 # define VER_H_PROM_PATCH_VER "999"
4899 #endif /* VER_H_PROM_PATCH_VER */
4900 
4901 #if !defined(VER_H_PROM_OTHER_VER)
4902 # define VER_H_PROM_OTHER_VER "999"
4903 #endif /* VER_H_PROM_OTHER_VER */
4904 
4905 #if !defined(VER_H_GIT_RELT)
4906 # define VER_H_GIT_RELT "X"
4907 #endif /* VER_H_GIT_RELT */
4908 
4909 #if !defined(VER_H_PROM_VER_TEXT)
4910 # define VER_H_PROM_VER_TEXT "Unknown                      "
4911 #endif /* VER_H_PROM_VER_TEXT */
4912 
4913 #if defined(BUILD_PROM_OSA_TEXT)
4914 # define BURN_PROM_OSA_TEXT BUILD_PROM_OSA_TEXT
4915 #else
4916 # if !defined(VER_H_PROM_OSA_TEXT)
4917 #  define BURN_PROM_OSA_TEXT "Unknown Build Op Sys"
4918 # else
4919 #  define BURN_PROM_OSA_TEXT VER_H_PROM_OSA_TEXT
4920 # endif /* VER_H_PROM_OSA_TEXT */
4921 #endif /* BUILD_PROM_OSA_TEXT */
4922 
4923 #if defined(BUILD_PROM_OSV_TEXT)
4924 # define BURN_PROM_OSV_TEXT BUILD_PROM_OSV_TEXT
4925 #else
4926 # if !defined(VER_H_PROM_OSV_TEXT)
4927 #  define BURN_PROM_OSV_TEXT "Unknown Build Arch. "
4928 # else
4929 #  define BURN_PROM_OSV_TEXT VER_H_PROM_OSV_TEXT
4930 # endif /* VER_H_PROM_OSV_TEXT */
4931 #endif /* BUILD_PROM_OSV_TEXT */
4932 
4933 #if defined(BUILD_PROM_TSA_TEXT)
4934 # define BURN_PROM_TSA_TEXT BUILD_PROM_TSA_TEXT
4935 #else
4936 # if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64)
4937 #  define VER_H_PROM_TSA_TEXT "Intel x86_64 (AMD64)"
4938 # elif defined(_M_IX86) || defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__ix86)
4939 #  define VER_H_PROM_TSA_TEXT "Intel ix86 (32-bit) "
4940 # elif defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__)
4941 #  define VER_H_PROM_TSA_TEXT "AArch64/ARM64/64-bit"
4942 # elif defined(_M_ARM) || defined(__arm__)
4943 #  define VER_H_PROM_TSA_TEXT "AArch32/ARM32/32-bit"
4944 # elif defined(__ia64__) || defined(_M_IA64) || defined(__itanium__)
4945 #  define VER_H_PROM_TSA_TEXT "Intel Itanium (IA64)"
4946 # elif defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__) || defined(__powerpc64__) || \
4947   defined(__POWERPC64__) || \
4948   defined(_M_PPC64) || \
4949   defined(__PPC64) || \
4950   defined(_ARCH_PPC64)
4951 #  define VER_H_PROM_TSA_TEXT "Power ISA (64-bit)  "
4952 # elif defined(__ppc__) || defined(__PPC__) || defined(__powerpc__) || defined(__POWERPC__) || defined(_M_PPC) || \
4953   defined(__PPC) || \
4954   defined(__ppc32__) || \
4955   defined(__PPC32__) || \
4956   defined(__powerpc32__) || \
4957   defined(__POWERPC32__) || \
4958   defined(_M_PPC32) || \
4959   defined(__PPC32)
4960 #  define VER_H_PROM_TSA_TEXT "PowerPC ISA (32-bit)"
4961 # elif defined(__s390x__)
4962 #  define VER_H_PROM_TSA_TEXT "IBM z/Architecture  "
4963 # elif defined(__s390__)
4964 #  define VER_H_PROM_TSA_TEXT "IBM ESA System/390  "
4965 # elif defined(__J2__) || defined(__J2P__) || defined(__j2__) || defined(__j2p__)
4966 #  define VER_H_PROM_TSA_TEXT "J-Core J2 Open CPU  "
4967 # elif defined(__SH4__) || defined(__sh4__) || defined(__SH4) || defined(__sh4)
4968 #  define VER_H_PROM_TSA_TEXT "Hitachi/Renesas SH-4"
4969 # elif defined(__SH2__) || defined(__sh2__) || defined(__SH2) || defined(__sh2)
4970 #  define VER_H_PROM_TSA_TEXT "Hitachi/Renesas SH-2"
4971 # elif defined(__alpha__)
4972 #  define VER_H_PROM_TSA_TEXT "Alpha AXP           "
4973 # elif defined(__hppa__) || defined(__HPPA__) || defined(__PARISC__) || defined(__parisc__)
4974 #  define VER_H_PROM_TSA_TEXT "HP PA-RISC          "
4975 # elif defined(__ICE9__) || defined(__ice9__) || defined(__ICE9) || defined(__ice9)
4976 #  define VER_H_PROM_TSA_TEXT "SiCortex ICE-9      "
4977 # elif defined(mips64) || defined(__mips64__) || defined(MIPS64) || defined(_MIPS64_) || defined(__mips64)
4978 #  define VER_H_PROM_TSA_TEXT "MIPS64              "
4979 # elif defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) || defined(__mips)
4980 #  define VER_H_PROM_TSA_TEXT "MIPS                "
4981 # elif defined(__OpenRISC__) || defined(__OPENRISC__) || defined(__openrisc__) || defined(__OR1K__) || defined(__OPENRISC1K__)
4982 #  define VER_H_PROM_TSA_TEXT "OpenRISC            "
4983 # elif defined(__sparc64) || defined(__SPARC64) || defined(__SPARC64__) || defined(__sparc64__)
4984 #  define VER_H_PROM_TSA_TEXT "SPARC64             "
4985 # elif defined(__sparc) || defined(__SPARC) || defined(__SPARC__) || defined(__sparc__)
4986 #  define VER_H_PROM_TSA_TEXT "SPARC               "
4987 # elif defined(__riscv) || defined(__riscv__)
4988 #  define VER_H_PROM_TSA_TEXT "RISC-V              "
4989 # elif defined(__e2k__) || defined(__E2K__) || defined(__elbrus64__) || defined(__elbrus__) || defined(__ELBRUS__) || defined(__e2k64__)
4990 #  if defined(__iset__)
4991 #   if __iset__ > 0
4992 #    if __iset__ == 1
4993 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v1      "
4994 #    elif __iset__ == 2
4995 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v2      "
4996 #    elif __iset__ == 3
4997 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v3      "
4998 #    elif __iset__ == 4
4999 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v4      "
5000 #    elif __iset__ == 5
5001 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v5      "
5002 #    elif __iset__ == 6
5003 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v6      "
5004 #    elif __iset__ == 7
5005 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v7      "
5006 #    elif __iset__ == 8
5007 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v8      "
5008 #    elif __iset__ == 9
5009 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v9      "
5010 #    elif __iset__ == 10
5011 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus v10     "
5012 #    else
5013 #     define VER_H_PROM_TSA_TEXT "MCST Elbrus         "
5014 #    endif
5015 #   else
5016 #    define VER_H_PROM_TSA_TEXT "MCST Elbrus         "
5017 #   endif
5018 #  else
5019 #   define VER_H_PROM_TSA_TEXT "MCST Elbrus         "
5020 #  endif
5021 # elif defined(__myriad2__)
5022 #  define VER_H_PROM_TSA_TEXT "Myriad2             "
5023 # elif defined(__loongarch64) || defined(__loongarch__)
5024 #  define VER_H_PROM_TSA_TEXT "LoongArch           "
5025 # elif defined(_m68851) || defined(__m68k__) || defined(__m68000__) || defined(__M68K)
5026 #  define VER_H_PROM_TSA_TEXT "Motorola m68k       "
5027 # elif defined(__m88k__) || defined(__m88000__) || defined(__M88K)
5028 #  define VER_H_PROM_TSA_TEXT "Motorola m88k       "
5029 # elif defined(__VAX__) || defined(__vax__)
5030 #  define VER_H_PROM_TSA_TEXT "VAX                 "
5031 # elif defined(__NIOS2__) || defined(__nios2__)
5032 #  define VER_H_PROM_TSA_TEXT "Altera Nios II      "
5033 # elif defined(__MICROBLAZE__) || defined(__microblaze__)
5034 #  define VER_H_PROM_TSA_TEXT "Xilinx MicroBlaze   "
5035 # elif defined(__kvx__) || defined(__KVX__) || defined(__KVX_64__)
5036 #  define VER_H_PROM_TSA_TEXT "Kalray KVX          "
5037 # endif
5038 # if !defined(VER_H_PROM_TSA_TEXT)
5039 #  define BURN_PROM_TSA_TEXT "Unknown Target Arch."
5040 # else
5041 #  define BURN_PROM_TSA_TEXT VER_H_PROM_TSA_TEXT
5042 # endif /* VER_H_PROM_TSA_TEXT */
5043 #endif /* BUILD_PROM_TSA_TEXT */
5044 
5045 #if (defined(__WIN__) || defined(_WIN32) || defined(IS_WINDOWS) || defined(_MSC_VER) || defined(__MINGW32__) || \
5046         defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)) && !defined(__CYGWIN__)
5047 # define DC_IS_WINDOWS 1
5048 #else
5049 # define DC_IS_WINDOWS 0
5050 #endif
5051 
5052 #if defined(BUILD_PROM_TSV_TEXT)
5053 # define BURN_PROM_TSV_TEXT BUILD_PROM_TSV_TEXT
5054 #else
5055 # if DC_IS_WINDOWS
5056 #  define VER_H_PROM_TSV_TEXT "Microsoft Windows   "
5057 # elif defined(__CYGWIN__)
5058 #  define VER_H_PROM_TSV_TEXT "Windows/Cygwin      "
5059 # elif (defined(__sunos) || defined(__sun) || defined(__sun__)) && (defined(SYSV) || defined(__SVR4) || defined(__SVR4__) || \
5060         defined(__svr4__))
5061 #  if defined(__illumos__)
5062 #   define VER_H_PROM_TSV_TEXT "illumos             "
5063 #  else
5064 #   define VER_H_PROM_TSV_TEXT "Solaris             "
5065 #  endif
5066 # elif defined(__APPLE__) && defined(__MACH__)
5067 #  define VER_H_PROM_TSV_TEXT "Apple macOS         "
5068 # elif defined(__GNU__) && !defined(__linux__)
5069 #  define VER_H_PROM_TSV_TEXT "GNU/Hurd            "
5070 # elif defined(__ANDROID__) && defined(__ANDROID_API__)
5071 #  if defined(__linux__)
5072 #   define VER_H_PROM_TSV_TEXT "Android/Linux       "
5073 #  else
5074 #   define VER_H_PROM_TSV_TEXT "Android             "
5075 #  endif
5076 # elif defined(__lynxOS__) || defined(__LYNXOS__) || defined(LynxOS) || defined(LYNXOS)
5077 #  define VER_H_PROM_TSV_TEXT "LynxOS              "
5078 # elif defined(__HELENOS__)
5079 #  define VER_H_PROM_TSV_TEXT "HelenOS             "
5080 # elif defined(__linux__)
5081 #  if defined(__BIONIC__)
5082 #   define VER_H_PROM_TSV_TEXT "Linux/Bionic-libc   "
5083 #  elif defined(__UCLIBC__) || defined(UCLIBC)
5084 #   define VER_H_PROM_TSV_TEXT "Linux/uClibc        "
5085 #  elif defined(__NEWLIB__)
5086 #   define VER_H_PROM_TSV_TEXT "Linux/Newlib        "
5087 #  elif defined(__dietlibc__)
5088 #   define VER_H_PROM_TSV_TEXT "Linux/Diet-libc     "
5089 #  elif defined(__GLIBC__)
5090 #   define VER_H_PROM_TSV_TEXT "GNU/Linux           "
5091 #  else
5092 #   define VER_H_PROM_TSV_TEXT "Linux               "
5093 #  endif
5094 # elif defined(__HAIKU__)
5095 #  define VER_H_PROM_TSV_TEXT "Haiku               "
5096 # elif defined(__serenity__)
5097 #  define VER_H_PROM_TSV_TEXT "SerenityOS          "
5098 # elif defined(__FreeBSD__)
5099 #  define VER_H_PROM_TSV_TEXT "FreeBSD             "
5100 # elif defined(__NetBSD__)
5101 #  define VER_H_PROM_TSV_TEXT "NetBSD              "
5102 # elif defined(__OpenBSD__)
5103 #  define VER_H_PROM_TSV_TEXT "OpenBSD             "
5104 # elif defined(__DragonFly__)
5105 #  define VER_H_PROM_TSV_TEXT "DragonFly BSD       "
5106 # elif defined(_AIX)
5107 #  if !defined(__PASE__)
5108 #   define VER_H_PROM_TSV_TEXT "IBM AIX             "
5109 #  else
5110 #   define VER_H_PROM_TSV_TEXT "IBM OS/400 (PASE)   "
5111 #  endif
5112 # elif defined(__VXWORKS__) || defined(__VXWORKS) || defined(__vxworks) || defined(__vxworks__) || defined(_VxWorks)
5113 #  if !defined(__RTP__)
5114 #   define VER_H_PROM_TSV_TEXT "VxWorks             "
5115 #  else
5116 #   define VER_H_PROM_TSV_TEXT "VxWorks RTP         "
5117 #  endif
5118 # elif defined(__rtems__)
5119 #  if defined(__FreeBSD_version)
5120 #   define VER_H_PROM_TSV_TEXT "RTEMS/LibBSD        "
5121 #  else
5122 #   define VER_H_PROM_TSV_TEXT "RTEMS               "
5123 #  endif
5124 # elif defined(__ZEPHYR__)
5125 #  define VER_H_PROM_TSV_TEXT "Zephyr              "
5126 # elif defined(ti_sysbios_BIOS___VERS) || defined(ti_sysbios_BIOS__top__)
5127 #  define VER_H_PROM_TSV_TEXT "TI-RTOS (SYS/BIOS)  "
5128 # elif defined(__OSV__) // -V1040
5129 #  define VER_H_PROM_TSV_TEXT "OSv                 "
5130 # elif defined(MINIX) || defined(MINIX3) || defined(MINIX315) || defined(__minix__) || defined(__minix3__) || defined(__minix315__)
5131 #  define VER_H_PROM_TSV_TEXT "Minix               "
5132 # elif defined(__QNX__)
5133 #  if defined(__QNXNTO__)
5134 #   define VER_H_PROM_TSV_TEXT "QNX Neutrino        "
5135 #  else
5136 #   define VER_H_PROM_TSV_TEXT "QNX                 "
5137 #  endif
5138 # elif defined(__managarm__)
5139 #  define VER_H_PROM_TSV_TEXT "Managarm            "
5140 # endif
5141 # if !defined(VER_H_PROM_TSV_TEXT)
5142 #  define BURN_PROM_TSV_TEXT "Unknown Target OpSys"
5143 # else
5144 #  define BURN_PROM_TSV_TEXT VER_H_PROM_TSV_TEXT
5145 # endif /* VER_H_PROM_TSV_TEXT */
5146 #endif /* BUILD_PROM_TSV_TEXT */
5147 
5148 #if !defined(VER_H_GIT_DATE_SHORT)
5149 # define VER_H_GIT_DATE_SHORT "2021-01-01"
5150 #endif /* if !defined(VER_H_GIT_DATE_SHORT) */
5151 
5152 #if !defined(BURN_PROM_BUILD_NUM)
5153 # define BURN_PROM_BUILD_NUM "        "
5154 #endif /* if !defined(BURN_PROM_BUILD_NUM) */
5155 
5156 #define BURN(offset, length, string) memcpy ((char *) PROM + (offset), string, length)
5157 #define BURN1(offset, byte) PROM[offset] = (char) (byte)
5158 
5159   (void)memset (PROM, 255, 1024);
5160 
5161   //   Offset Length  Data
5162   BURN  ( 00,  11,  "DPS 8/SIM M");                //    0-10  CPU model ("XXXXXXXXXXX")       //-V1086
5163   BURN  (013,  11,  serial);                       //   11-21  CPU serial ("DDDDDDDDDDD")      //-V1086
5164   BURN  (026,   6,  ship);                         //   22-27  CPU ship date ("YYMMDD")        //-V1086
5165   BURN1 (034,       getbits36_8 (rsw2,  0));       //   34     RSW 2 bits  0- 7                //-V1086
5166   BURN1 (035,       getbits36_8 (rsw2,  8));       //   35     RSW 2 bits  8-15                //-V1086
5167   BURN1 (036,       getbits36_8 (rsw2, 16));       //   36     RSW 2 bits 16-23                //-V1086
5168   BURN1 (037,       getbits36_8 (rsw2, 24));       //   37     RSW 2 bits 24-31                //-V1086
5169   BURN1 (040,     ((getbits36_4 (rsw2, 32) << 4) \
5170                                | rsw2Ext));        //   40     RSW 2 bits 32-35, options bits  //-V1086
5171 
5172   /* Begin extended PROM data */
5173   BURN  ( 60,   1,  "2");                          //   60     PROM Layout Version Number      //-V1086
5174   BURN  ( 70,  10,  VER_H_GIT_DATE_SHORT);         //   70     Release Git Commit Date         //-V1086
5175   BURN  ( 80,   3,  VER_H_PROM_MAJOR_VER);         //   80     Major Release Number            //-V1086
5176   BURN  ( 83,   3,  VER_H_PROM_MINOR_VER);         //   83     Minor Release Number            //-V1086
5177   BURN  ( 86,   3,  VER_H_PROM_PATCH_VER);         //   86     Patch Release Number            //-V1086
5178   BURN  ( 89,   3,  VER_H_PROM_OTHER_VER);         //   89     Iteration Release Number        //-V1086
5179   BURN  ( 92,   8,  BURN_PROM_BUILD_NUM);          //   92     Reserved for Build Number       //-V1086
5180   BURN  (100,   1,  VER_H_GIT_RELT);               //  100     Release Type                    //-V1086
5181   BURN  (101,  29,  VER_H_PROM_VER_TEXT);          //  101     Release Text                    //-V1086
5182   BURN  (130,  20,  BURN_PROM_OSA_TEXT);           //  130     Build System Architecture       //-V1086
5183   BURN  (150,  20,  BURN_PROM_OSV_TEXT);           //  150     Build System Operating System   //-V1086
5184   BURN  (170,  20,  BURN_PROM_TSA_TEXT);           //  170     Target System Architecture      //-V1086
5185   BURN  (190,  20,  BURN_PROM_TSV_TEXT);           //  190     Target System Architecture      //-V1086
5186 }
5187 
5188 void cpuStats (uint cpuNo) {
     /* [previous][next][first][last][top][bottom][index][help] */
5189   if (! cpus[cpuNo].cycleCnt)
5190     return;
5191 
5192 /* Detect Haiku pthread_getcpuclockid availability */
5193 #if defined(__HAIKU__)
5194 # if HAS_INCLUDE(<syscall_clock_info.h>)
5195 #  include <syscall_clock_info.h>
5196 # endif
5197 # if !defined(_SYSTEM_SYSCALL_CLOCK_INFO_H)
5198 #  if !defined(HAIKU_NO_PTHREAD_GETCPUCLOCKID)
5199 #   define HAIKU_NO_PTHREAD_GETCPUCLOCKID
5200 #  endif
5201 # endif
5202 #endif
5203 
5204 /* Clang and SunCC may not define __illumos__ but we require it
5205  * here to check for pthread_getcpuclockid availability */
5206 #if defined(__sun) || defined(__sun__)
5207 # if !defined(__illumos__)
5208 #  if HAS_INCLUDE(<sys/sysevent.h>)
5209 #   include <sys/sysevent.h>
5210 #  endif
5211 #  if defined(ILLUMOS_VENDOR) || defined(ILLUMOS_KERN_PUB)
5212 #   define __illumos__
5213 #  endif
5214 # endif
5215 #endif
5216 
5217   double cpu_seconds = 0;
5218   int cpu_millis = 0;
5219   char cpu_ftime[64] = {0};
5220 #if (defined(THREADZ) || defined(LOCKLESS))
5221 # if !defined(HAIKU_NO_PTHREAD_GETCPUCLOCKID) && !defined(__illumos__) && \
5222      !defined(__APPLE__) && !defined(__PASE__) && !defined(__serenity__)
5223   struct timespec cpu_time;
5224   clockid_t clock_id;
5225   if (pthread_getcpuclockid (cpus[cpuNo].thread_id, &clock_id) == 0) {
5226     if (clock_gettime (clock_id, &cpu_time) == 0) {
5227       cpu_seconds = (double)cpu_time.tv_sec + cpu_time.tv_nsec / 1e9;
5228     }
5229   }
5230 # endif
5231 #endif
5232 
5233   if (cpu_seconds > 0 && cpus[cpuNo].instrCnt > 0) {
5234     int cpu_hours = (int)(cpu_seconds / 3600);
5235     int cpu_minutes = (int)((cpu_seconds - cpu_hours * 3600) / 60);
5236     int cpu_secs = (int)(cpu_seconds - (cpu_hours * 3600) - (cpu_minutes * 60));
5237     struct tm cpu_tm = {0};
5238     cpu_tm.tm_hour = cpu_hours;
5239     cpu_tm.tm_min = cpu_minutes;
5240     cpu_tm.tm_sec = cpu_secs;
5241     strftime(cpu_ftime, sizeof(cpu_ftime), "%H:%M:%S", &cpu_tm);
5242     cpu_millis = (int)((cpu_seconds - (cpu_hours * 3600) - (cpu_minutes * 60) - cpu_secs) * 1000);
5243   }
5244 
5245   (void)fflush(stderr);
5246   (void)fflush(stdout);
5247   sim_msg ("\r\n");
5248   (void)fflush(stdout);
5249   (void)fflush(stderr);
5250   sim_msg ("\r+---------------------------------+\r\n");
5251   sim_msg ("\r|         CPU %c Statistics        |\r\n", 'A' + cpuNo);
5252   sim_msg ("\r+---------------------------------+\r\n");
5253   if (cpu_seconds > 0 && cpus[cpuNo].instrCnt > 0) {
5254     sim_msg ("\r|  CPU Time Used %11s.%03d  |\r\n", cpu_ftime, cpu_millis);
5255     sim_msg ("\r+---------------------------------+\r\n");
5256   }
5257   (void)fflush(stdout);
5258   (void)fflush(stderr);
5259 #if defined(_AIX) && !defined(__PASE__)
5260   struct rusage rusage;
5261   if (!pthread_getrusage_np(cpus[cpuNo].thread_id, &rusage, PTHRDSINFO_RUSAGE_COLLECT)) {
5262     sim_msg ("\r|  Volun. CtxtSw %'15llu  |\r\n", (unsigned long long)rusage.ru_nvcsw);
5263     sim_msg ("\r|  Invol. CtxtSw %'15llu  |\r\n", (unsigned long long)rusage.ru_nivcsw);
5264     sim_msg ("\r+---------------------------------+\r\n");
5265   }
5266 #endif
5267 #if defined(WIN_STDIO)
5268   sim_msg ("\r|  cycles        %15llu  |\r\n", (unsigned long long)cpus[cpuNo].cycleCnt);
5269   sim_msg ("\r|  instructions  %15llu  |\r\n", (unsigned long long)cpus[cpuNo].instrCnt);
5270   (void)fflush(stdout);
5271   (void)fflush(stderr);
5272   sim_msg ("\r+---------------------------------+\r\n");
5273   sim_msg ("\r|  lockCnt       %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockCnt);
5274   sim_msg ("\r|  lockImmediate %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockImmediate);
5275   (void)fflush(stdout);
5276   (void)fflush(stderr);
5277   sim_msg ("\r+---------------------------------+\r\n");
5278   sim_msg ("\r|  lockWait      %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockWait);
5279   sim_msg ("\r|  lockWaitMax   %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockWaitMax);
5280   (void)fflush(stdout);
5281   (void)fflush(stderr);
5282 # if !defined(SCHED_NEVER_YIELD)
5283   sim_msg ("\r|  lockYield     %15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockYield);
5284   (void)fflush(stdout);
5285   (void)fflush(stderr);
5286 # else
5287   sim_msg ("\r|  lockYield                ----  |\r\n");
5288   (void)fflush(stdout);
5289   (void)fflush(stderr);
5290 # endif /* if !defined(SCHED_NEVER_YIELD) */
5291   sim_msg ("\r+---------------------------------+");
5292   (void)fflush(stdout);
5293   (void)fflush(stderr);
5294 # if !defined(UCACHE)
5295 #  if !defined(UCACHE_STATS)
5296   sim_msg ("\r\n");
5297 #  endif
5298 # endif
5299   (void)fflush(stdout);
5300   (void)fflush(stderr);
5301 #else
5302   sim_msg ("\r|  cycles        %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].cycleCnt);
5303   sim_msg ("\r|  instructions  %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].instrCnt);
5304   (void)fflush(stdout);
5305   (void)fflush(stderr);
5306   sim_msg ("\r+---------------------------------+\r\n");
5307   sim_msg ("\r|  lockCnt       %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockCnt);
5308   sim_msg ("\r|  lockImmediate %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockImmediate);
5309   (void)fflush(stdout);
5310   (void)fflush(stderr);
5311   sim_msg ("\r+---------------------------------+\r\n");
5312   sim_msg ("\r|  lockWait      %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockWait);
5313   sim_msg ("\r|  lockWaitMax   %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockWaitMax);
5314   (void)fflush(stdout);
5315   (void)fflush(stderr);
5316 # if !defined(SCHED_NEVER_YIELD)
5317   sim_msg ("\r|  lockYield     %'15llu  |\r\n", (unsigned long long)cpus[cpuNo].coreLockState.lockYield);
5318   (void)fflush(stdout);
5319   (void)fflush(stderr);
5320 # else
5321   sim_msg ("\r|  lockYield                ----  |\r\n");
5322   (void)fflush(stdout);
5323   (void)fflush(stderr);
5324 # endif /* if !defined(SCHED_NEVER_YIELD) */
5325   sim_msg ("\r+---------------------------------+");
5326   (void)fflush(stdout);
5327   (void)fflush(stderr);
5328 # if !defined(UCACHE)
5329 #  if !defined(UCACHE_STATS)
5330   sim_msg ("\r\n");
5331 #  endif
5332 # endif
5333   (void)fflush(stderr);
5334   (void)fflush(stdout);
5335 #endif
5336 
5337 #if defined(UCACHE_STATS)
5338   ucacheStats (cpuNo);
5339 #endif
5340 
5341 
5342 
5343 
5344 
5345 
5346 
5347 }
5348 
5349 bool running_perf_test;
5350 
5351 #if defined(THREADZ) || defined(LOCKLESS)
5352 # include <locale.h>
5353 # include "segldr.h"
5354 
5355 void perfTest (char * testName) {
     /* [previous][next][first][last][top][bottom][index][help] */
5356   running_perf_test = true;
5357 
5358   if (testName == NULL)
5359     testName = "strip.mem";
5360 
5361 # if !defined(NO_LOCALE)
5362   (void) setlocale(LC_NUMERIC, "");
5363 # endif
5364 
5365   // dps8m_init_strip
5366 # if !defined(_AIX)
5367   system_state = aligned_malloc (sizeof (struct system_state_s));
5368 # else
5369   system_state = malloc (sizeof (struct system_state_s));
5370 # endif
5371   if (!system_state)
5372     {
5373       (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
5374                      __func__, __FILE__, __LINE__);
5375 # if defined(USE_BACKTRACE)
5376 #  if defined(SIGUSR2)
5377       (void)raise(SIGUSR2);
5378       /*NOTREACHED*/ /* unreachable */
5379 #  endif /* if defined(SIGUSR2) */
5380 # endif /* if defined(USE_BACKTRACE) */
5381       abort();
5382     }
5383 # if !defined(__MINGW64__) && !defined(__MINGW32__) && !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32) && !defined(__PASE__)
5384   if (0 == sim_free_memory || sim_free_memory >= 192000000) {
5385     if (mlock(system_state, sizeof(struct system_state_s)) == -1) {
5386       mlock_failure = true;
5387     }
5388   } else {
5389 #  if defined(TESTING)
5390     sim_warn ("Low memory - no memory locking attempted.\r\n");
5391 #  else
5392     (void)system_state;
5393 #  endif
5394   }
5395 # endif
5396   M = system_state->M;
5397 # if defined(M_SHARED)
5398   cpus = system_state->cpus;
5399 # endif /* if defined(M_SHARED) */
5400   (void) memset (cpus, 0, sizeof (cpu_state_t) * N_CPU_UNITS_MAX);
5401   for (int i = 0; i < N_CPU_UNITS_MAX; i ++) {
5402     cpus[i].switches.FLT_BASE = 2; // Some of the UnitTests assume this
5403     cpus[i].instrCnt = 0;
5404     cpus[i].cycleCnt = 0;
5405     for (int j = 0; j < N_FAULTS; j ++)
5406       cpus[i].faultCnt [j] = 0;
5407   }
5408 
5409   cpus[0].tweaks.enable_emcall = 1;
5410   opc_dev.numunits = 1;
5411   cpu_reset_unit_idx (0, false);
5412   set_cpu_cycle (& cpus[0], FETCH_cycle);
5413   mrestore (testName);
5414   _cpup = & cpus[0];
5415   threadz_sim_instr ();
5416 }
5417 #endif

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