root/src/dps8/dps8_cpu.c

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

DEFINITIONS

This source file includes following definitions.
  1. cpu_show_config
  2. cpu_set_config
  3. cpu_show_nunits
  4. cpu_set_nunits
  5. cpu_show_kips
  6. cpu_set_kips
  7. cpu_show_stall
  8. cpu_set_stall
  9. setCPUConfigL68
  10. setCPUConfigDPS8M
  11. cycle_str
  12. set_cpu_cycle
  13. set_cpu_idx
  14. cpu_reset_unit_idx
  15. simh_cpu_reset_and_clear_unit
  16. simh_cpu_reset_unit
  17. str_SDW0
  18. cpu_boot
  19. setup_scbank_map
  20. lookup_cpu_mem_map
  21. get_serial_number
  22. do_stats
  23. ev_poll_cb
  24. cpu_init
  25. cpu_reset
  26. sim_cpu_reset
  27. cpu_ex
  28. cpu_dep
  29. get_highest_intr
  30. sample_interrupts
  31. simh_hooks
  32. panel_process_event
  33. sim_instr
  34. cpu_thread_main
  35. do_LUF_fault
  36. set_temporary_absolute_mode
  37. clear_temporary_absolute_mode
  38. becomeClockMaster
  39. giveupClockMaster
  40. threadz_sim_instr
  41. operand_size
  42. readOperandRead
  43. readOperandRMW
  44. write_operand
  45. set_mem_watch
  46. nem_check
  47. core_read
  48. core_read_lock
  49. core_write
  50. core_write_unlock
  51. core_unlock_all
  52. core_write_zone
  53. core_read2
  54. core_write2
  55. decode_instruction
  56. is_priv_mode
  57. get_bar_mode
  58. get_addr_mode
  59. set_addr_mode
  60. get_BAR_address
  61. add_history
  62. add_history_force
  63. add_dps8m_CU_history
  64. add_dps8m_DU_OU_history
  65. add_dps8m_APU_history
  66. add_dps8m_EAPU_history
  67. add_l68_CU_history
  68. add_l68_DU_history
  69. add_l68_OU_history
  70. add_l68_APU_history
  71. get_dbg_verb
  72. dps8_sim_debug
  73. setupPROM
  74. cpuStats
  75. perfTest

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

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