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
  74. perfTest

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

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