root/src/dps8/dps8_cpu.c

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

DEFINITIONS

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

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

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