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

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