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

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