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. read_operand
  42. write_operand
  43. set_mem_watch
  44. nem_check
  45. core_read
  46. core_read_lock
  47. core_write
  48. core_write_unlock
  49. core_unlock_all
  50. core_write_zone
  51. core_read2
  52. core_write2
  53. decode_instruction
  54. is_priv_mode
  55. get_bar_mode
  56. get_addr_mode
  57. set_addr_mode
  58. get_BAR_address
  59. add_history
  60. add_history_force
  61. add_dps8m_CU_history
  62. add_dps8m_DU_OU_history
  63. add_dps8m_APU_history
  64. add_dps8m_EAPU_history
  65. add_l68_CU_history
  66. add_l68_DU_history
  67. add_l68_OU_history
  68. add_l68_APU_history
  69. get_dbg_verb
  70. dps8_sim_debug
  71. setupPROM

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

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