root/src/dps8/dps8_append.c

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

DEFINITIONS

This source file includes following definitions.
  1. selftest_ptwaw
  2. do_ldbr
  3. fetch_dsptw
  4. modify_dsptw
  5. calc_hit_am
  6. fetch_sdw_from_sdwam
  7. fetch_psdw
  8. fetch_nsdw
  9. str_sdw
  10. dump_sdwam
  11. to_be_discarded_am
  12. load_sdwam
  13. fetch_ptw_from_ptwam
  14. fetch_ptw
  15. loadPTWAM
  16. modify_ptw
  17. do_ptw2
  18. str_access_type
  19. str_acv
  20. str_pct
  21. do_append_cycle
  22. do_append_cycle
  23. dbgLookupAddress

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * SPDX-License-Identifier: Multics
   5  * scspell-id: 4bc3e31c-f62d-11ec-bf00-80ee73e9b8e7
   6  *
   7  * ---------------------------------------------------------------------------
   8  *
   9  * Copyright (c) 2012-2016 Harry Reed
  10  * Copyright (c) 2013-2022 Charles Anthony
  11  * Copyright (c) 2017 Michal Tomek
  12  * Copyright (c) 2021-2025 The DPS8M Development Team
  13  *
  14  * This software is made available under the terms of the ICU License.
  15  * See the LICENSE.md file at the top-level directory of this distribution.
  16  *
  17  * ---------------------------------------------------------------------------
  18  *
  19  * This source file may contain code comments that adapt, include, and/or
  20  * incorporate Multics program code and/or documentation distributed under
  21  * the Multics License.  In the event of any discrepancy between code
  22  * comments herein and the original Multics materials, the original Multics
  23  * materials should be considered authoritative unless otherwise noted.
  24  * For more details and historical background, see the LICENSE.md file at
  25  * the top-level directory of this distribution.
  26  *
  27  * ---------------------------------------------------------------------------
  28  */
  29 
  30 #include <stdio.h>
  31 #include "dps8.h"
  32 #include "dps8_sys.h"
  33 #include "dps8_iom.h"
  34 #include "dps8_cable.h"
  35 #include "dps8_cpu.h"
  36 #include "dps8_addrmods.h"
  37 #include "dps8_faults.h"
  38 #include "dps8_scu.h"
  39 #include "dps8_append.h"
  40 #include "dps8_utils.h"
  41 #include "dps8_cache.h"
  42 #if defined(THREADZ) || defined(LOCKLESS)
  43 # include "threadz.h"
  44 #endif
  45 
  46 #define DBG_CTR cpu.cycleCnt
  47 
  48 /*
  49  * The appending unit ...
  50  */
  51 
  52 #if defined(TESTING)
  53 # define DBG_CTR cpu.cycleCnt
  54 # define DBGAPP(...) sim_debug (DBG_APPENDING, & cpu_dev, __VA_ARGS__)
  55 #else
  56 # define DBGAPP(...)
  57 #endif /* if defined(TESTING) */
  58 
  59 
  60 
  61 
  62 
  63 
  64 
  65 
  66 
  67 
  68 
  69 
  70 
  71 
  72 
  73 
  74 
  75 
  76 
  77 
  78 
  79 
  80 
  81 
  82 
  83 
  84 
  85 
  86 
  87 
  88 
  89 
  90 
  91 
  92 
  93 
  94 
  95 
  96 
  97 
  98 
  99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 107 
 108 
 109 
 110 
 111 
 112 
 113 
 114 
 115 #if defined(TESTING)
 116 static char *str_sdw (char * buf, sdw_s *SDW);
 117 #endif /* if defined(TESTING) */
 118 
 119 //
 120 //
 121 //  The Use of Bit 29 in the Instruction Word
 122 //  The reader is reminded that there is a preliminary step of loading TPR.CA
 123 //  with the ADDRESS field of the instruction word during instruction decode.
 124 //  If bit 29 of the instruction word is set to 1, modification by pointer
 125 //  register is invoked and the preliminary step is executed as follows:
 126 //  1. The ADDRESS field of the instruction word is interpreted as shown in
 127 //  Figure 6-7 below.
 128 //  2. C(PRn.SNR) -> C(TPR.TSR)
 129 //  3. maximum of ( C(PRn.RNR), C(TPR.TRR), C(PPR.PRR) ) -> C(TPR.TRR)
 130 //  4. C(PRn.WORDNO) + OFFSET -> C(TPR.CA) (NOTE: OFFSET is a signed binary
 131 //  number.)
 132 //  5. C(PRn.BITNO) -> TPR.BITNO
 133 //
 134 
 135 // Define this to do error detection on the PTWAM table.
 136 // Useful if PTWAM reports an error message, but it slows the emulator
 137 // down 50%
 138 
 139 #if defined(do_selftestPTWAM)
 140 static void selftest_ptwaw (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 141   {
 142     int usages[N_NAX_WAM_ENTRIES];
 143     for (int i = 0; i < N_MODEL_WAM_ENTRIES; i ++)
 144       usages[i] = -1;
 145 
 146     for (int i = 0; i < N_MODEL_WAM_ENTRIES; i ++)
 147       {
 148         ptw_s * p = cpu.PTWAM + i;
 149         if (p->USE > N_MODEL_WAM_ENTRIES - 1)
 150           sim_printf ("PTWAM[%d].USE is %d; > %d!\r\n",
 151                       i, p->USE, N_MODEL_WAM_ENTRIES - 1);
 152         if (usages[p->USE] != -1)
 153           sim_printf ("PTWAM[%d].USE is equal to PTWAM[%d].USE; %d\r\n",
 154                       i, usages[p->USE], p->USE);
 155         usages[p->USE] = i;
 156       }
 157     for (int i = 0; i < N_MODEL_WAM_ENTRIES; i ++)
 158       {
 159         if (usages[i] == -1)
 160           sim_printf ("No PTWAM had a USE of %d\r\n", i);
 161       }
 162   }
 163 #endif /* if defined(do_selftestPTWAM) */
 164 
 165 /*
 166  * implement ldbr instruction
 167  */
 168 
 169 void do_ldbr (cpu_state_t * cpup, word36 * Ypair)
     /* [previous][next][first][last][top][bottom][index][help] */
 170   {
 171     CPTUR (cptUseDSBR);
 172     if (cpu.tweaks.enable_wam)
 173       {
 174         if (cpu.cu.SD_ON)
 175           {
 176             // If SDWAM is enabled, then
 177             //   0 -> C(SDWAM(i).FULL) for i = 0, 1, ..., 15
 178             //   i -> C(SDWAM(i).USE) for i = 0, 1, ..., 15
 179             for (uint i = 0; i < N_MODEL_WAM_ENTRIES; i ++)
 180               {
 181                 cpu.SDWAM[i].FE = 0;
 182                 L68_ (cpu.SDWAM[i].USE = (word4) i;)
 183                 DPS8M_ (cpu.SDWAM[i].USE = 0;)
 184               }
 185           }
 186 
 187         if (cpu.cu.PT_ON)
 188           {
 189             // If PTWAM is enabled, then
 190             //   0 -> C(PTWAM(i).FULL) for i = 0, 1, ..., 15
 191             //   i -> C(PTWAM(i).USE) for i = 0, 1, ..., 15
 192             for (uint i = 0; i < N_MODEL_WAM_ENTRIES; i ++)
 193               {
 194                 cpu.PTWAM[i].FE = 0;
 195                 L68_ (cpu.PTWAM[i].USE = (word4) i;)
 196                 DPS8M_ (cpu.PTWAM[i].USE = 0;)
 197               }
 198 #if defined(do_selftestPTWAM)
 199             selftest_ptwaw ();
 200 #endif /* if defined(do_selftestPTWAM) */
 201           }
 202       }
 203     else
 204       {
 205         cpu.SDW0.FE  = 0;
 206         cpu.SDW0.USE = 0;
 207         cpu.PTW0.FE  = 0;
 208         cpu.PTW0.USE = 0;
 209       }
 210 
 211     // If cache is enabled, reset all cache column and level full flags
 212     if (cpu.switches.enable_cache && cpu.tweaks.enable_wam) {
 213       cacheReset (cpup);
 214     }
 215 
 216     // C(Y-pair) 0,23 -> C(DSBR.ADDR)
 217     cpu.DSBR.ADDR  = (Ypair[0] >> (35 - 23)) & PAMASK;
 218 
 219     // C(Y-pair) 37,50 -> C(DSBR.BOUND)
 220     cpu.DSBR.BND   = (Ypair[1] >> (71 - 50)) & 037777;
 221 
 222     // C(Y-pair) 55 -> C(DSBR.U)
 223     cpu.DSBR.U     = (Ypair[1] >> (71 - 55)) & 01;
 224 
 225     // C(Y-pair) 60,71 -> C(DSBR.STACK)
 226     cpu.DSBR.STACK = (Ypair[1] >> (71 - 71)) & 07777;
 227     DBGAPP ("ldbr 0 -> SDWAM/PTWAM[*].F, i -> SDWAM/PTWAM[i].USE, "
 228             "DSBR.ADDR 0%o, DSBR.BND 0%o, DSBR.U 0%o, DSBR.STACK 0%o\r\n",
 229             cpu.DSBR.ADDR, cpu.DSBR.BND, cpu.DSBR.U, cpu.DSBR.STACK);
 230   }
 231 
 232 /*
 233  * fetch descriptor segment PTW ...
 234  */
 235 
 236 // CANFAULT
 237 
 238 static void fetch_dsptw (cpu_state_t * cpup, word15 segno)
     /* [previous][next][first][last][top][bottom][index][help] */
 239   {
 240     DBGAPP ("%s segno 0%o\r\n", __func__, segno);
 241     PNL (L68_ (cpu.apu.state |= apu_FDPT;))
 242 
 243     if (2 * segno >= 16 * (cpu.DSBR.BND + 1))
 244       {
 245         DBGAPP ("%s ACV15\r\n", __func__);
 246         // generate access violation, out of segment bounds fault
 247         PNL (cpu.acvFaults |= ACV15;)
 248         PNL (L68_ (cpu.apu.state |= apu_FLT;))
 249         doFault (FAULT_ACV, fst_acv15,
 250                  "acvFault: fetch_dsptw out of segment bounds fault");
 251       }
 252     set_apu_status (cpup, apuStatus_DSPTW);
 253 
 254     //word24 y1 = (2u * segno) % 1024u;
 255     word24 x1 = (2u * segno) / 1024u; // floor
 256 
 257     PNL (cpu.lastPTWOffset = segno;)
 258     PNL (cpu.lastPTWIsDS = true;)
 259 
 260     word36 PTWx1;
 261     core_read (cpup, (cpu.DSBR.ADDR + x1) & PAMASK, & PTWx1, __func__); // NO_CACHE
 262 
 263     cpu.PTW0.ADDR = GETHI (PTWx1);
 264     cpu.PTW0.U    = TSTBIT (PTWx1, 9);
 265     cpu.PTW0.M    = TSTBIT (PTWx1, 6);
 266     cpu.PTW0.DF   = TSTBIT (PTWx1, 2);
 267     cpu.PTW0.FC   = PTWx1 & 3;
 268 
 269     L68_ (if (cpu.MR_cache.emr && cpu.MR_cache.ihr)
 270       add_l68_APU_history (cpup, APUH_FDSPTW);)
 271 
 272     DBGAPP ("%s x1 0%o DSBR.ADDR 0%o PTWx1 0%012"PRIo64" "
 273             "PTW0: ADDR 0%o U %o M %o F %o FC %o\r\n",
 274             __func__, x1, cpu.DSBR.ADDR, PTWx1, cpu.PTW0.ADDR, cpu.PTW0.U,
 275             cpu.PTW0.M, cpu.PTW0.DF, cpu.PTW0.FC);
 276   }
 277 
 278 /*
 279  * modify descriptor segment PTW (Set U=1) ...
 280  */
 281 
 282 // CANFAULT
 283 
 284 static void modify_dsptw (cpu_state_t * cpup, word15 segno)
     /* [previous][next][first][last][top][bottom][index][help] */
 285   {
 286     PNL (L68_ (cpu.apu.state |= apu_MDPT;))
 287 
 288     set_apu_status (cpup, apuStatus_MDSPTW);
 289 
 290     word24 x1 = (2u * segno) / 1024u; // floor
 291 
 292 #if defined(THREADZ)
 293     bool lck = get_rmw_lock ();
 294     if (! lck)
 295       lock_rmw ();
 296 #endif /* if defined(THREADZ) */
 297 
 298     word36 PTWx1;
 299 #if defined(LOCKLESS)
 300     core_read_lock (cpup, (cpu.DSBR.ADDR + x1) & PAMASK, & PTWx1, __func__); // NO_CACHE
 301     PTWx1 = SETBIT (PTWx1, 9);
 302     core_write_unlock (cpup, (cpu.DSBR.ADDR + x1) & PAMASK, PTWx1, __func__); // NO_CACHE
 303     cacheInvalidate (cpup, (cpu.DSBR.ADDR + x1) & PAMASK);  // keep this CPU's cache current (PA863, PA868)
 304 #else
 305     core_read (cpup, (cpu.DSBR.ADDR + x1) & PAMASK, & PTWx1, __func__); // NO_CACHE
 306     PTWx1 = SETBIT (PTWx1, 9);
 307     core_write (cpup, (cpu.DSBR.ADDR + x1) & PAMASK, PTWx1, __func__); // NO_CACHE
 308     cacheInvalidate (cpup, (cpu.DSBR.ADDR + x1) & PAMASK);  // keep this CPU's cache current (PA863, PA868)
 309 #endif /* if defined(LOCKLESS) */
 310 
 311 #if defined(THREADZ)
 312     if (! lck)
 313       unlock_rmw ();
 314 #endif /* if defined(THREADZ) */
 315 
 316     cpu.PTW0.U = 1;
 317     L68_ (if (cpu.MR_cache.emr && cpu.MR_cache.ihr)
 318       add_l68_APU_history (cpup, APUH_MDSPTW);)
 319   }
 320 
 321 // DPS8M: the 6 bit LRU belongs to the row (set) of the four levels; it
 322 // is updated, and read back by ssdr/sptr, for every level of the row,
 323 // full or not (PA866 02A)
 324 static word6 calc_hit_am (word6 LRU, uint hit_level)
     /* [previous][next][first][last][top][bottom][index][help] */
 325   {
 326 #if defined(TESTING)
 327     cpu_state_t * cpup = _cpup;
 328 #endif
 329     switch (hit_level)
 330       {
 331         case 0:  // hit level A
 332           return (LRU | 070);
 333         case 1:  // hit level B
 334           return ((LRU & 037) | 06);
 335         case 2:  // hit level C
 336           return ((LRU & 053) | 01);
 337         case 3:  // hit level D
 338           return (LRU & 064);
 339         default:
 340           DBGAPP ("%s: Invalid AM level\r\n", __func__);
 341           return 0;
 342      }
 343   }
 344 
 345 static sdw_s * fetch_sdw_from_sdwam (cpu_state_t * cpup, word15 segno) {
     /* [previous][next][first][last][top][bottom][index][help] */
 346   DBGAPP ("%s(0):segno=%05o\r\n", __func__, segno);
 347 
 348   // The AM match flags describe this append cycle (SCU word 0 bits 20,
 349   // 22); the PTW lookup, if any, follows (PA870 01A)
 350   cpu.cu.SDWAMM = 0;
 351   cpu.cu.PTWAMM = 0;
 352 
 353   if ((! cpu.tweaks.enable_wam || ! cpu.cu.SD_ON)) {
 354     DBGAPP ("%s(0): SDWAM disabled\r\n", __func__);
 355     return NULL;
 356   }
 357 
 358   if (cpu.tweaks.l68_mode) { // L68
 359     int nwam = N_L68_WAM_ENTRIES;
 360     for (int _n = 0; _n < nwam; _n++) {
 361       // make certain we initialize SDWAM prior to use!!!
 362       if (cpu.SDWAM[_n].FE && segno == cpu.SDWAM[_n].POINTER) {
 363         DBGAPP ("%s(1):found match for segno %05o " "at _n=%d\r\n", __func__, segno, _n);
 364 
 365         cpu.cu.SDWAMM = 1;
 366         cpu.SDWAMR = (word4) _n;
 367         cpu.SDW = & cpu.SDWAM[_n];
 368 
 369         // If the SDWAM match logic circuitry indicates a hit, all usage
 370         // counts (SDWAM.USE) greater than the usage count of the register
 371         // hit are decremented by one, the usage count of the register hit
 372         // is set to 15, and the contents of the register hit are read out
 373         // into the address preparation circuitry.
 374 
 375         for (int _h = 0; _h < nwam; _h++) {
 376           if (cpu.SDWAM[_h].USE > cpu.SDW->USE)
 377             cpu.SDWAM[_h].USE -= 1;
 378         }
 379         cpu.SDW->USE = N_L68_WAM_ENTRIES - 1;
 380 
 381         char buf[256];
 382         (void)buf;
 383 #if defined(TESTING)
 384         DBGAPP ("%s(2):SDWAM[%d]=%s\r\n", __func__, _n, str_sdw (buf, cpu.SDW));
 385 #endif /* if defined(TESTING) */
 386         return cpu.SDW;
 387       }
 388     }
 389   }
 390 
 391   if (! cpu.tweaks.l68_mode) { // DPS8M
 392     uint setno = segno & 017;
 393     uint toffset;
 394     sdw_s *p;
 395     for (toffset = 0; toffset < 64; toffset += 16) {
 396       p = & cpu.SDWAM[toffset + setno];
 397       if (p->FE && segno == p->POINTER) {
 398         DBGAPP ("%s(1):found match for segno %05o " "at _n=%d\r\n", __func__, segno, toffset + setno);
 399 
 400         cpu.cu.SDWAMM = 1;
 401         cpu.SDWAMR = (word6) (toffset + setno);
 402         cpu.SDW = p; // export pointer for appending
 403 
 404         word6 u = calc_hit_am (p->USE, toffset >> 4);
 405         for (toffset = 0; toffset < 64; toffset += 16) { // update LRU
 406           p = & cpu.SDWAM[toffset + setno];
 407           p->USE = u;
 408         }
 409 
 410         char buf[256];
 411         (void)buf;
 412 #if defined(TESTING)
 413         DBGAPP ("%s(2):SDWAM[%d]=%s\r\n", __func__, toffset + setno, str_sdw (buf, cpu.SDW));
 414 #endif /* if defined(TESTING) */
 415         return cpu.SDW;
 416       }
 417     }
 418   }
 419 #if defined(TESTING)
 420   DBGAPP ("%s(3):SDW for segment %05o not found in SDWAM\r\n", __func__, segno);
 421 #endif /* if defined(TESTING) */
 422   cpu.cu.SDWAMM = 0;
 423   return NULL;    // segment not referenced in SDWAM
 424 }
 425 
 426 /*
 427  * Fetches an SDW from a paged descriptor segment.
 428  */
 429 // CANFAULT
 430 
 431 static void fetch_psdw (cpu_state_t * cpup, word15 segno)
     /* [previous][next][first][last][top][bottom][index][help] */
 432   {
 433     DBGAPP ("%s(0):segno=%05o\r\n",
 434             __func__, segno);
 435 
 436     PNL (L68_ (cpu.apu.state |= apu_FSDP;))
 437 
 438     cpu.cu.SDWAMM = 0;
 439     cpu.cu.PTWAMM = 0;
 440     set_apu_status (cpup, apuStatus_SDWP);
 441     word24 y1 = (2 * segno) % 1024;
 442 
 443     word36 SDWeven, SDWodd;
 444 
 445     core_read2 (cpup, ((((word24) cpu.PTW0.ADDR & 0777760) << 6) + y1) & PAMASK, // NO_CACHE
 446                 & SDWeven, & SDWodd, __func__);
 447 
 448     // even word
 449     cpu.SDW0.ADDR  = (SDWeven >> 12) & 077777777;
 450     cpu.SDW0.R1    = (SDWeven >> 9)  & 7;
 451     cpu.SDW0.R2    = (SDWeven >> 6)  & 7;
 452     cpu.SDW0.R3    = (SDWeven >> 3)  & 7;
 453     cpu.SDW0.DF    = TSTBIT (SDWeven, 2);
 454     cpu.SDW0.FC    = SDWeven & 3;
 455 
 456     // odd word
 457     cpu.SDW0.BOUND = (SDWodd >> 21) & 037777;
 458     cpu.SDW0.R     = TSTBIT (SDWodd, 20);
 459     cpu.SDW0.E     = TSTBIT (SDWodd, 19);
 460     cpu.SDW0.W     = TSTBIT (SDWodd, 18);
 461     cpu.SDW0.P     = TSTBIT (SDWodd, 17);
 462     cpu.SDW0.U     = TSTBIT (SDWodd, 16);
 463     cpu.SDW0.G     = TSTBIT (SDWodd, 15);
 464     cpu.SDW0.C     = TSTBIT (SDWodd, 14);
 465     cpu.SDW0.EB    = SDWodd & 037777;
 466 
 467     L68_ (
 468       if (cpu.MR_cache.emr && cpu.MR_cache.ihr)
 469         add_l68_APU_history (cpup, APUH_FSDWP);
 470      )
 471     DBGAPP ("%s y1 0%o p->ADDR 0%o SDW 0%012"PRIo64" 0%012"PRIo64" "
 472             "ADDR %o R %o%o%o BOUND 0%o REWPUGC %o%o%o%o%o%o%o "
 473             "F %o FC %o FE %o USE %o\r\n",
 474             __func__, y1, cpu.PTW0.ADDR, SDWeven, SDWodd, cpu.SDW0.ADDR,
 475             cpu.SDW0.R1, cpu.SDW0.R2, cpu.SDW0.R3, cpu.SDW0.BOUND,
 476             cpu.SDW0.R, cpu.SDW0.E, cpu.SDW0.W, cpu.SDW0.P, cpu.SDW0.U,
 477             cpu.SDW0.G, cpu.SDW0.C, cpu.SDW0.DF, cpu.SDW0.FC, cpu.SDW0.FE,
 478             cpu.SDW0.USE);
 479   }
 480 
 481 // Nonpaged SDW Fetch
 482 // Fetches an SDW from an unpaged descriptor segment.
 483 // CANFAULT
 484 
 485 static void fetch_nsdw (cpu_state_t * cpup, word15 segno)
     /* [previous][next][first][last][top][bottom][index][help] */
 486   {
 487     DBGAPP ("%s (0):segno=%05o\r\n", __func__, segno);
 488 
 489     PNL (L68_ (cpu.apu.state |= apu_FSDN;))
 490 
 491     cpu.cu.SDWAMM = 0;
 492     cpu.cu.PTWAMM = 0;
 493     set_apu_status (cpup, apuStatus_SDWNP);
 494 
 495     if (2 * segno >= 16 * (cpu.DSBR.BND + 1))
 496       {
 497         DBGAPP ("%s (1):Access Violation, out of segment bounds for "
 498                 "segno=%05o DSBR.BND=%d\r\n",
 499                 __func__, segno, cpu.DSBR.BND);
 500         // generate access violation, out of segment bounds fault
 501         PNL (cpu.acvFaults |= ACV15;)
 502         PNL (L68_ (cpu.apu.state |= apu_FLT;))
 503         doFault (FAULT_ACV, fst_acv15,
 504                  "acvFault fetch_dsptw: out of segment bounds fault");
 505       }
 506     DBGAPP ("%s (2):fetching SDW from %05o\r\n",
 507             __func__, cpu.DSBR.ADDR + 2u * segno);
 508 
 509     word36 SDWeven, SDWodd;
 510     core_read2 (cpup, (cpu.DSBR.ADDR + 2u * segno) & PAMASK, // NO_CACHE
 511                 & SDWeven, & SDWodd, __func__);
 512 
 513     // even word
 514     cpu.SDW0.ADDR = (SDWeven >> 12) & 077777777;
 515     cpu.SDW0.R1   = (SDWeven >> 9)  & 7;
 516     cpu.SDW0.R2   = (SDWeven >> 6)  & 7;
 517     cpu.SDW0.R3   = (SDWeven >> 3)  & 7;
 518     cpu.SDW0.DF   = TSTBIT (SDWeven, 2);
 519     cpu.SDW0.FC   = SDWeven & 3;
 520 
 521     // odd word
 522     cpu.SDW0.BOUND = (SDWodd >> 21) & 037777;
 523     cpu.SDW0.R     = TSTBIT (SDWodd, 20);
 524     cpu.SDW0.E     = TSTBIT (SDWodd, 19);
 525     cpu.SDW0.W     = TSTBIT (SDWodd, 18);
 526     cpu.SDW0.P     = TSTBIT (SDWodd, 17);
 527     cpu.SDW0.U     = TSTBIT (SDWodd, 16);
 528     cpu.SDW0.G     = TSTBIT (SDWodd, 15);
 529     cpu.SDW0.C     = TSTBIT (SDWodd, 14);
 530     cpu.SDW0.EB    = SDWodd & 037777;
 531 
 532     L68_ (
 533       if (cpu.MR_cache.emr && cpu.MR_cache.ihr)
 534         add_l68_APU_history (cpup, 0 /* No fetch no paged bit */);
 535     )
 536 #if !defined(SPEED)
 537     char buf[256];
 538     (void)buf;
 539     DBGAPP ("%s (2):SDW0=%s\r\n", __func__, str_SDW0 (buf, & cpu.SDW0));
 540 #endif /* if !defined(SPEED) */
 541   }
 542 
 543 #if defined(TESTING)
 544 static char *str_sdw (char * buf, sdw_s *SDW)
     /* [previous][next][first][last][top][bottom][index][help] */
 545   {
 546     if (! SDW->FE)
 547       (void)sprintf (buf, "*** SDW Uninitialized ***");
 548     else
 549       (void)sprintf (buf,
 550                      "ADDR:%06o R1:%o R2:%o R3:%o BOUND:%o R:%o E:%o W:%o P:%o "
 551                      "U:%o G:%o C:%o CL:%o DF:%o FC:%o POINTER=%o USE=%d",
 552                      SDW->ADDR,    SDW->R1, SDW->R2, SDW->R3, SDW->BOUND,
 553                      SDW->R,       SDW->E,  SDW->W,  SDW->P,  SDW->U,
 554                      SDW->G,       SDW->C,  SDW->EB, SDW->DF, SDW->FC,
 555                      SDW->POINTER, SDW->USE);
 556     return buf;
 557   }
 558 
 559 /*
 560  * dump SDWAM...
 561  */
 562 
 563 t_stat dump_sdwam (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
 564   {
 565     char buf[256];
 566     (void)buf;
 567     for (int _n = 0; _n < N_MODEL_WAM_ENTRIES; _n++)
 568       {
 569         sdw_s *p = & cpu.SDWAM[_n];
 570 
 571         if (p->FE)
 572           sim_printf ("SDWAM n:%d %s\r\n", _n, str_sdw (buf, p));
 573       }
 574     return SCPE_OK;
 575   }
 576 #endif /* if defined(TESTING) */
 577 
 578 static uint to_be_discarded_am (word6 LRU)
     /* [previous][next][first][last][top][bottom][index][help] */
 579   {
 580 
 581 
 582 
 583 
 584 
 585 
 586 
 587 
 588 
 589 
 590 
 591 
 592     // The level older than the other three, in the sense calc_hit_am
 593     // sets the bits (as the #if 0 code above): 040 B older than A, 020
 594     // C older than A, 010 D older than A, 04 C older than B, 02 D older
 595     // than B, 01 D older than C. (PA866 04A: with LRU 0, level A.)
 596     if ((LRU & 070) == 0)   return 0;
 597     if ((LRU & 046) == 040) return 1;
 598     if ((LRU & 025) == 024) return 2;
 599     return 3;
 600   }
 601 
 602 /*
 603  * load the current in-core SDW0 into the SDWAM ...
 604  */
 605 
 606 static void load_sdwam (cpu_state_t * cpup, word15 segno, bool nomatch)
     /* [previous][next][first][last][top][bottom][index][help] */
 607   {
 608     cpu.SDW0.POINTER = segno;
 609     cpu.SDW0.USE = 0;
 610 
 611     cpu.SDW0.FE = true;     // in use by SDWAM
 612 
 613     cpu.SDW = & cpu.SDW0;
 614 
 615     if (nomatch || (! cpu.tweaks.enable_wam) || (! cpu.cu.SD_ON))
 616       {
 617         DBGAPP ("%s: SDWAM disabled\r\n", __func__);
 618         return;
 619       }
 620 
 621     if (cpu.tweaks.l68_mode) { // L68
 622       // If the SDWAM match logic does not indicate a hit, the SDW is fetched
 623       // from the descriptor segment in main memory and loaded into the SDWAM
 624       // register with usage count 0 (the oldest), all usage counts are
 625       // decremented by one with the newly loaded register rolling over from 0 to
 626       // 15, and the newly loaded register is read out into the address
 627       // preparation circuitry.
 628 
 629       for (int _n = 0; _n < N_L68_WAM_ENTRIES; _n++) {
 630         sdw_s * p = & cpu.SDWAM[_n];
 631         if (! p->FE || p->USE == 0) {
 632           DBGAPP ("%s(1):SDWAM[%d] FE=0 || USE=0\r\n", __func__, _n);
 633 
 634           * p = cpu.SDW0;
 635           p->POINTER = segno;
 636           p->USE = 0;
 637           p->FE = true;     // in use by SDWAM
 638 
 639           for (int _h = 0; _h < N_L68_WAM_ENTRIES; _h++) {
 640             sdw_s * q = & cpu.SDWAM[_h];
 641             q->USE -= 1;
 642             q->USE &= N_L68_WAM_MASK;
 643           }
 644 
 645           cpu.SDW = p;
 646 
 647           char buf[256];
 648           (void) buf;
 649 #if defined(TESTING)
 650           DBGAPP ("%s(2):SDWAM[%d]=%s\r\n", __func__, _n, str_sdw (buf, p));
 651 #endif /* if defined(TESTING) */
 652           return;
 653         }
 654       }
 655       // if we reach this, USE is scrambled
 656 #if defined(TESTING)
 657       DBGAPP ("%s(3) no USE=0 found for segment=%d\r\n", __func__, segno);
 658       sim_printf ("%s(%05o): no USE=0 found!\r\n", __func__, segno);
 659       dump_sdwam (cpup);
 660 #endif /* if defined(TESTING) */
 661     }
 662 
 663     if (! cpu.tweaks.l68_mode) { // DPS8M
 664       uint setno = segno & 017;
 665       uint toffset;
 666       sdw_s *p;
 667       for (toffset = 0; toffset < 64; toffset += 16) {
 668         p = & cpu.SDWAM[toffset + setno];
 669         if (!p->FE)
 670           break;
 671       }
 672       if (toffset == 64) { // all FE==1
 673         toffset = to_be_discarded_am (p->USE) << 4;
 674         p = & cpu.SDWAM[toffset + setno];
 675       }
 676       DBGAPP ("%s(1):SDWAM[%d] FE=0 || LRU\r\n", __func__, toffset + setno);
 677 
 678       word6 u = calc_hit_am (p->USE, toffset >> 4); // before loading the SDWAM!
 679       * p = cpu.SDW0; // load the SDW
 680       p->POINTER = segno;
 681       p->FE = true;  // in use
 682       p->loaded = true;
 683       cpu.SDW = p; // export pointer for appending
 684 
 685       for (uint toffset1 = 0; toffset1 < 64; toffset1 += 16) { // update LRU
 686         p = & cpu.SDWAM[toffset1 + setno];
 687         p->USE = u;
 688       }
 689 
 690       char buf[256];
 691       (void) buf;
 692 #if defined(TESTING)
 693       DBGAPP ("%s(2):SDWAM[%d]=%s\r\n", __func__, toffset + setno, str_sdw (buf, cpu.SDW));
 694 #endif /* if defined(TESTING) */
 695     } // DPS8M
 696   }
 697 
 698 static ptw_s * fetch_ptw_from_ptwam (cpu_state_t * cpup, word15 segno, word18 CA)
     /* [previous][next][first][last][top][bottom][index][help] */
 699   {
 700     if ((! cpu.tweaks.enable_wam) || (! cpu.cu.PT_ON))
 701       {
 702         DBGAPP ("%s: PTWAM disabled\r\n", __func__);
 703         return NULL;
 704       }
 705 
 706     if (cpu.tweaks.l68_mode) { // L68
 707       int nwam = N_L68_WAM_ENTRIES;
 708       for (int _n = 0; _n < nwam; _n++)
 709         {
 710           if (cpu.PTWAM[_n].FE && ((CA >> 6) & 07760) == cpu.PTWAM[_n].PAGENO &&
 711               cpu.PTWAM[_n].POINTER == segno)   //_initialized
 712             {
 713               DBGAPP ("%s: found match for segno=%o pageno=%o "
 714                       "at _n=%d\r\n",
 715                       __func__, segno, cpu.PTWAM[_n].PAGENO, _n);
 716               cpu.cu.PTWAMM = 1;
 717               cpu.PTWAMR = (word4) _n;
 718               cpu.PTW = & cpu.PTWAM[_n];
 719 
 720               // If the PTWAM match logic circuitry indicates a hit, all usage
 721               // counts (PTWAM.USE) greater than the usage count of the register
 722               // hit are decremented by one, the usage count of the register hit
 723               // is set to 15, and the contents of the register hit are read out
 724               // into the address preparation circuitry.
 725 
 726               for (int _h = 0; _h < nwam; _h++)
 727                 {
 728                   if (cpu.PTWAM[_h].USE > cpu.PTW->USE)
 729                     cpu.PTWAM[_h].USE -= 1; //PTW->USE -= 1;
 730                 }
 731               cpu.PTW->USE = N_L68_WAM_ENTRIES - 1;
 732 #if defined(do_selftestPTWAM)
 733               selftest_ptwaw ();
 734 #endif /* if defined(do_selftestPTWAM) */
 735               DBGAPP ("%s: ADDR 0%o U %o M %o F %o FC %o\r\n",
 736                       __func__, cpu.PTW->ADDR, cpu.PTW->U, cpu.PTW->M,
 737                       cpu.PTW->DF, cpu.PTW->FC);
 738               return cpu.PTW;
 739             }
 740         }
 741     }
 742 
 743     DPS8M_ (
 744       uint setno = (CA >> 10) & 017;
 745       uint toffset;
 746       ptw_s *p;
 747       for (toffset = 0; toffset < 64; toffset += 16)
 748         {
 749           p = & cpu.PTWAM[toffset + setno];
 750 
 751           if (p->FE && ((CA >> 6) & 07760) == p->PAGENO && p->POINTER == segno)
 752             {
 753               DBGAPP ("%s: found match for segno=%o pageno=%o "
 754                       "at _n=%d\r\n",
 755                       __func__, segno, p->PAGENO, toffset + setno);
 756               cpu.cu.PTWAMM = 1;
 757               cpu.PTWAMR = (word6) (toffset + setno);
 758               cpu.PTW = p; // export pointer for appending
 759 
 760               word6 u = calc_hit_am (p->USE, toffset >> 4);
 761               for (toffset = 0; toffset < 64; toffset += 16) // update LRU
 762                 {
 763                   p = & cpu.PTWAM[toffset + setno];
 764                   p->USE = u;
 765                 }
 766 
 767               DBGAPP ("%s: ADDR 0%o U %o M %o F %o FC %o\r\n",
 768                       __func__, cpu.PTW->ADDR, cpu.PTW->U, cpu.PTW->M,
 769                       cpu.PTW->DF, cpu.PTW->FC);
 770               return cpu.PTW;
 771             }
 772         }
 773      )
 774     cpu.cu.PTWAMM = 0;
 775     return NULL;    // page not referenced in PTWAM
 776   }
 777 
 778 static void fetch_ptw (cpu_state_t * cpup, sdw_s *sdw, word18 offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 779   {
 780     // AL39 p.5-7
 781     // Fetches a PTW from a page table other than a descriptor segment page
 782     // table and sets the page accessed bit (PTW.U)
 783     PNL (L68_ (cpu.apu.state |= apu_FPTW;))
 784     set_apu_status (cpup, apuStatus_PTW);
 785 
 786     //word24 y2 = offset % 1024;
 787     word24 x2 = (offset) / 1024; // floor
 788 
 789     word36 PTWx2;
 790 
 791     DBGAPP ("%s address %08o\r\n", __func__, sdw->ADDR + x2);
 792 
 793     PNL (cpu.lastPTWOffset = offset;)
 794     PNL (cpu.lastPTWIsDS = false;)
 795 
 796 #if defined(THREADZ)
 797     bool lck = get_rmw_lock ();
 798     if (! lck)
 799       lock_rmw ();
 800 #endif /* if defined(THREADZ) */
 801 #if defined(LOCKLESS)
 802     core_read_lock (cpup, (sdw->ADDR + x2) & PAMASK, & PTWx2, __func__); // NO_CACHE
 803 #else
 804     core_read (cpup, (sdw->ADDR + x2) & PAMASK, & PTWx2, __func__); // NO_CACHE
 805 #endif /* if defined(LOCKLESS) */
 806 
 807     cpu.PTW0.ADDR = GETHI  (PTWx2);
 808     cpu.PTW0.U    = TSTBIT (PTWx2, 9);
 809     cpu.PTW0.M    = TSTBIT (PTWx2, 6);
 810     cpu.PTW0.DF   = TSTBIT (PTWx2, 2);
 811     cpu.PTW0.FC   = PTWx2 & 3;
 812 
 813     // ISOLTS-861 02
 814 #if !defined(LOCKLESS)
 815     if (! cpu.PTW0.U)
 816 #endif /* if !defined(LOCKLESS) */
 817       {
 818         PTWx2 = SETBIT (PTWx2, 9);
 819 #if defined(LOCKLESS)
 820         core_write_unlock (cpup, (sdw->ADDR + x2) & PAMASK, PTWx2, __func__); // NO_CACHE
 821         cacheInvalidate (cpup, (sdw->ADDR + x2) & PAMASK);  // keep this CPU's cache current (PA863, PA868)
 822 #else
 823         core_write (cpup, (sdw->ADDR + x2) & PAMASK, PTWx2, __func__); // NO_CACHE
 824         cacheInvalidate (cpup, (sdw->ADDR + x2) & PAMASK);  // keep this CPU's cache current (PA863, PA868)
 825 #endif /* if defined(LOCKLESS) */
 826         cpu.PTW0.U = 1;
 827       }
 828 
 829 #if defined(THREADZ)
 830     if (! lck)
 831       unlock_rmw ();
 832 #endif /* if defined(THREADZ) */
 833 
 834     L68_ (if (cpu.MR_cache.emr && cpu.MR_cache.ihr)
 835       add_l68_APU_history (cpup, APUH_FPTW);)
 836 
 837     DBGAPP ("%s x2 0%o sdw->ADDR 0%o PTWx2 0%012"PRIo64" "
 838             "PTW0: ADDR 0%o U %o M %o F %o FC %o\r\n",
 839             __func__, x2, sdw->ADDR, PTWx2, cpu.PTW0.ADDR, cpu.PTW0.U,
 840             cpu.PTW0.M, cpu.PTW0.DF, cpu.PTW0.FC);
 841   }
 842 
 843 static void loadPTWAM (cpu_state_t * cpup, word15 segno, word18 offset, UNUSED bool nomatch)
     /* [previous][next][first][last][top][bottom][index][help] */
 844   {
 845     cpu.PTW0.PAGENO  = (offset >> 6) & 07760;
 846     cpu.PTW0.POINTER = segno;
 847     cpu.PTW0.USE     = 0;
 848     cpu.PTW0.FE      = true;
 849 
 850     cpu.PTW = & cpu.PTW0;
 851     if (nomatch || (! cpu.tweaks.enable_wam) || (! cpu.cu.PT_ON))
 852       {
 853         DBGAPP ("loadPTWAM: PTWAM disabled\r\n");
 854         return;
 855       }
 856 
 857     if (cpu.tweaks.l68_mode) { // L68
 858       // If the PTWAM match logic does not indicate a hit, the PTW is fetched
 859       // from main memory and loaded into the PTWAM register with usage count 0
 860       // (the oldest), all usage counts are decremented by one with the newly
 861       // loaded register rolling over from 0 to 15, and the newly loaded register
 862       // is read out into the address preparation circuitry.
 863 
 864       for (int _n = 0; _n < N_L68_WAM_ENTRIES; _n++)
 865         {
 866           ptw_s * p = & cpu.PTWAM[_n];
 867           if (! p->FE || p->USE == 0)
 868             {
 869               DBGAPP ("loadPTWAM(1):PTWAM[%d] FE=0 || USE=0\r\n", _n);
 870               *p = cpu.PTW0;
 871               p->PAGENO = (offset >> 6) & 07760;
 872               p->POINTER = segno;
 873               p->USE = 0;
 874               p->FE = true;
 875 
 876               for (int _h = 0; _h < N_L68_WAM_ENTRIES; _h++)
 877                 {
 878                   ptw_s * q = & cpu.PTWAM[_h];
 879                   q->USE -= 1;
 880                   q->USE &= N_L68_WAM_MASK;
 881                 }
 882 
 883               cpu.PTW = p;
 884               DBGAPP ("loadPTWAM(2): ADDR 0%o U %o M %o F %o FC %o "
 885                       "POINTER=%o PAGENO=%o USE=%d\r\n",
 886                       cpu.PTW->ADDR, cpu.PTW->U, cpu.PTW->M, cpu.PTW->DF,
 887                       cpu.PTW->FC, cpu.PTW->POINTER, cpu.PTW->PAGENO,
 888                       cpu.PTW->USE);
 889 #if defined(do_selftestPTWAM)
 890               selftest_ptwaw ();
 891 #endif /* if defined(do_selftestPTWAM) */
 892               return;
 893             }
 894         }
 895       // if we reach this, USE is scrambled
 896       sim_printf ("loadPTWAM(segno=%05o, offset=%012o): no USE=0 found!\r\n",
 897                   segno, offset);
 898     }
 899 
 900     DPS8M_ (
 901       uint setno = (offset >> 10) & 017;
 902       uint toffset;
 903       ptw_s *p;
 904       for (toffset = 0; toffset < 64; toffset += 16)
 905         {
 906           p = & cpu.PTWAM[toffset + setno];
 907           if (! p->FE)
 908             break;
 909         }
 910       if (toffset == 64) // all FE==1
 911         {
 912           toffset = to_be_discarded_am (p->USE) << 4;
 913           p = & cpu.PTWAM[toffset + setno];
 914         }
 915 
 916       DBGAPP ("loadPTWAM(1):PTWAM[%d] FE=0 || LRU\r\n",
 917               toffset + setno);
 918 
 919       word6 u = calc_hit_am (p->USE, toffset >> 4); // before loading the PTWAM
 920       * p = cpu.PTW0; // load the PTW
 921       p->PAGENO = (offset >> 6) & 07760;
 922       p->POINTER = segno;
 923       p->FE = true;  // in use
 924       p->loaded = true;
 925       cpu.PTW = p; // export pointer for appending
 926 
 927       for (uint toffset1 = 0; toffset1 < 64; toffset1 += 16) // update LRU
 928         {
 929           p = & cpu.PTWAM[toffset1 + setno];
 930           p->USE = u;
 931         }
 932 
 933       DBGAPP ("loadPTWAM(2): ADDR 0%o U %o M %o F %o FC %o POINTER=%o "
 934               "PAGENO=%o USE=%d\r\n",
 935               cpu.PTW->ADDR, cpu.PTW->U, cpu.PTW->M, cpu.PTW->DF,
 936               cpu.PTW->FC, cpu.PTW->POINTER, cpu.PTW->PAGENO, cpu.PTW->USE);
 937     )
 938   }
 939 
 940 /*
 941  * modify target segment PTW (Set M=1) ...
 942  */
 943 
 944 static void modify_ptw (cpu_state_t * cpup, sdw_s *sdw, word18 offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 945   {
 946     PNL (L68_ (cpu.apu.state |= apu_MPTW;))
 947     //word24 y2 = offset % 1024;
 948     word24 x2 = offset / 1024; // floor
 949 
 950     word36 PTWx2;
 951 
 952     set_apu_status (cpup, apuStatus_MPTW);
 953 
 954 #if defined(THREADZ)
 955     bool lck = get_rmw_lock ();
 956     if (! lck)
 957       lock_rmw ();
 958 #endif /* if defined(THREADZ) */
 959 #if defined(LOCKLESS)
 960     core_read_lock (cpup, (sdw->ADDR + x2) & PAMASK, & PTWx2, __func__); // NO_CACHE
 961     PTWx2 = SETBIT (PTWx2, 6);
 962     core_write_unlock (cpup, (sdw->ADDR + x2) & PAMASK, PTWx2, __func__); // NO_CACHE
 963     cacheInvalidate (cpup, (sdw->ADDR + x2) & PAMASK);  // keep this CPU's cache current (PA863, PA868)
 964 #else
 965     core_read (cpup, (sdw->ADDR + x2) & PAMASK, & PTWx2, __func__); // NO_CACHE
 966     PTWx2 = SETBIT (PTWx2, 6);
 967     core_write (cpup, (sdw->ADDR + x2) & PAMASK, PTWx2, __func__); // NO_CACHE
 968     cacheInvalidate (cpup, (sdw->ADDR + x2) & PAMASK);  // keep this CPU's cache current (PA863, PA868)
 969 #endif /* if defined(LOCKLESS) */
 970 #if defined(THREADZ)
 971     if (! lck)
 972       unlock_rmw ();
 973 #endif /* if defined(THREADZ) */
 974     cpu.PTW->M = 1;
 975     L68_ (if (cpu.MR_cache.emr && cpu.MR_cache.ihr)
 976       add_l68_APU_history (cpup, APUH_MPTW);)
 977   }
 978 
 979 static void do_ptw2 (cpu_state_t * cpup, sdw_s *sdw, word18 offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 980   {
 981     PNL (L68_ (cpu.apu.state |= apu_FPTW2;))
 982     set_apu_status (cpup, apuStatus_PTW2);
 983 
 984     //word24 y2 = offset % 1024;
 985     word24 x2 = (offset) / 1024; // floor
 986 
 987     word36 PTWx2n;
 988 
 989     DBGAPP ("%s address %08o\r\n", __func__, sdw->ADDR + x2 + 1);
 990 
 991     core_read (cpup, (sdw->ADDR + x2 + 1) & PAMASK, & PTWx2n, __func__); // NO_CACHE
 992 
 993     ptw_s PTW2;
 994     PTW2.ADDR = GETHI (PTWx2n);
 995     PTW2.U    = TSTBIT (PTWx2n, 9);
 996     PTW2.M    = TSTBIT (PTWx2n, 6);
 997     PTW2.DF   = TSTBIT (PTWx2n, 2);
 998     PTW2.FC   = PTWx2n & 3;
 999 
1000     L68_ (if (cpu.MR_cache.emr && cpu.MR_cache.ihr)
1001       add_l68_APU_history (cpup, APUH_FPTW2);)
1002 
1003     DBGAPP ("%s x2 0%o sdw->ADDR 0%o PTW2 0%012"PRIo64" "
1004             "PTW2: ADDR 0%o U %o M %o F %o FC %o\r\n",
1005             __func__, x2, sdw->ADDR, PTWx2n, PTW2.ADDR, PTW2.U, PTW2.M,
1006             PTW2.DF, PTW2.FC);
1007 
1008     // check that PTW2 is the next page of the same segment
1009     // ISOLTS 875 02a
1010     if ((PTW2.ADDR & 0777760) == (cpu.PTW->ADDR & 0777760) + 16)
1011        //Is PTW2.F set ON?
1012        if (! PTW2.DF)
1013            // initiate a directed fault
1014            doFault (FAULT_DF0 + PTW2.FC, fst_zero, "PTW2.F == 0");
1015   }
1016 
1017 /*
1018  * Is the instruction a SToRage OPeration ?
1019  */
1020 
1021 #if !defined(QUIET_UNUSED)
1022 static char *str_access_type (MemoryAccessType accessType)
     /* [previous][next][first][last][top][bottom][index][help] */
1023   {
1024     switch (accessType)
1025       {
1026         case UnknownMAT:        return "Unknown";
1027         case OperandRead:       return "OperandRead";
1028         case OperandWrite:      return "OperandWrite";
1029         default:                return "???";
1030       }
1031   }
1032 
1033 static char *str_acv (_fault_subtype acv)
     /* [previous][next][first][last][top][bottom][index][help] */
1034   {
1035     switch (acv)
1036       {
1037         case ACV0:  return "Illegal ring order (ACV0=IRO)";
1038         case ACV1:  return "Not in execute bracket (ACV1=OEB)";
1039         case ACV2:  return "No execute permission (ACV2=E-OFF)";
1040         case ACV3:  return "Not in read bracket (ACV3=ORB)";
1041         case ACV4:  return "No read permission (ACV4=R-OFF)";
1042         case ACV5:  return "Not in write bracket (ACV5=OWB)";
1043         case ACV6:  return "No write permission (ACV6=W-OFF)";
1044         case ACV7:  return "Call limiter fault (ACV7=NO GA)";
1045         case ACV8:  return "Out of call brackets (ACV8=OCB)";
1046         case ACV9:  return "Outward call (ACV9=OCALL)";
1047         case ACV10: return "Bad outward call (ACV10=BOC)";
1048         case ACV11: return "Inward return (ACV11=INRET) XXX ??";
1049         case ACV12: return "Invalid ring crossing (ACV12=CRT)";
1050         case ACV13: return "Ring alarm (ACV13=RALR)";
1051         case ACV14: return "Associative memory error XXX ??";
1052         case ACV15: return "Out of segment bounds (ACV15=OOSB)";
1053         //case ACDF0: return "Directed fault 0";
1054         //case ACDF1: return "Directed fault 1";
1055         //case ACDF2: return "Directed fault 2";
1056         //case ACDF3: return "Directed fault 3";
1057         default:
1058             break;
1059       }
1060   return "unhandled acv in str_acv";
1061   }
1062 #endif /* if !defined(QUIET_UNUSED) */
1063 
1064 #if defined (TESTING) || defined (OLDAPP)
1065 static char *str_pct (processor_cycle_type t)
     /* [previous][next][first][last][top][bottom][index][help] */
1066   {
1067     switch (t)
1068       {
1069         case UNKNOWN_CYCLE:       return "UNKNOWN_CYCLE";
1070         case OPERAND_STORE:       return "OPERAND_STORE";
1071         case OPERAND_READ:        return "OPERAND_READ";
1072         case INDIRECT_WORD_FETCH: return "INDIRECT_WORD_FETCH";
1073 # if defined(LOCKLESS)
1074         case OPERAND_RMW:         return "OPERAND_RMW";
1075         case APU_DATA_RMW:        return "APU_DATA_RMW";
1076 # endif /* if defined(LOCKLESS) */
1077         default:
1078             return "Unhandled processor_cycle_type";
1079       }
1080   }
1081 #endif
1082 
1083 #if !defined(OLDAPP)
1084 word24 do_append_cycle (cpu_state_t * cpup, processor_cycle_type thisCycle, word36 * data, uint nWords) {
     /* [previous][next][first][last][top][bottom][index][help] */
1085   switch (thisCycle) {
1086     case OPERAND_STORE:
1087       return doAppendCycleOperandStore (cpup, data, nWords);
1088     case OPERAND_READ:
1089       return doAppendCycleOperandRead (cpup, data, nWords);
1090     case INDIRECT_WORD_FETCH:
1091       return doAppendCycleIndirectWordFetch (cpup, data, nWords);
1092     case RTCD_OPERAND_FETCH:
1093       return doAppendCycleRTCDOperandFetch (cpup, data, nWords);
1094     case INSTRUCTION_FETCH:
1095       return doAppendCycleInstructionFetch (cpup, data, nWords);
1096     case APU_DATA_READ:
1097       return doAppendCycleAPUDataRead (cpup, data, nWords);
1098     case APU_DATA_STORE:
1099       return doAppendCycleAPUDataStore (cpup, data, nWords);
1100     case ABSA_CYCLE:
1101       return doAppendCycleABSA (cpup, data, nWords);
1102 # if defined(LOCKLESS)
1103     case OPERAND_RMW:
1104       return doAppendCycleOperandRMW (cpup, data, nWords);
1105     case APU_DATA_RMW:
1106       return doAppendCycleAPUDataRMW (cpup, data, nWords);
1107 # endif /* if defined(LOCKLESS) */
1108     case UNKNOWN_CYCLE:
1109     default:
1110       (void)fprintf (stderr, "\rFATAL: APU unknown cycle %llu! Aborting at %s[%s:%d]\r\n",
1111                      (long long unsigned)thisCycle, __func__, __FILE__, __LINE__);
1112 # if defined(USE_BACKTRACE)
1113 #  if defined(SIGUSR2)
1114       (void)raise(SIGUSR2);
1115       /*NOTREACHED*/ /* unreachable */
1116 #  endif /* if defined(SIGUSR2) */
1117 # endif /* if defined(USE_BACKTRACE) */
1118       abort();
1119   }
1120 }
1121 #endif /* if !defined(OLDAPP) */
1122 
1123 #if !defined(OLDAPP)
1124 # include "doAppendCycleOperandStore.h"
1125 # include "doAppendCycleOperandRead.h"
1126 # include "doAppendCycleIndirectWordFetch.h"
1127 # include "doAppendCycleRTCDOperandFetch.h"
1128 # include "doAppendCycleInstructionFetch.h"
1129 # include "doAppendCycleAPUDataRead.h"
1130 # include "doAppendCycleAPUDataStore.h"
1131 # include "doAppendCycleABSA.h"
1132 # if defined(LOCKLESS)
1133 #  include "doAppendCycleOperandRMW.h"
1134 #  include "doAppendCycleAPUDataRMW.h"
1135 # endif /* if defined(LOCKLESS) */
1136 #endif /* if !defined(OLDAPP) */
1137 
1138 #if defined(OLDAPP)
1139 /*
1140  * recoding APU functions to more closely match Fig 5,6 & 8 ...
1141  * Returns final address suitable for core_read/write
1142  */
1143 
1144 //
1145 // Phase 1:
1146 //
1147 //     A: Get the SDW
1148 //
1149 //     B: Check the ring
1150 //
1151 // Phase 2:
1152 //
1153 //     B1: If CALL6 operand
1154 //           goto E
1155 //         If instruction fetch or transfer instruction operand
1156 //           goto F
1157 //         If write
1158 //           check write permission
1159 //         else
1160 //           check read permission
1161 //         goto G
1162 //
1163 //     E: -- CALL6 operand handling
1164 //        Check execute and gate bits
1165 //        Get the ring
1166 //        goto G
1167 //
1168 //     F: -- instruction fetch or transfer instruction operand
1169 //        Check execute bit and ring
1170 //        goto D
1171 //
1172 //     D: Check RALR
1173 //        goto G
1174 //
1175 // Phase 3
1176 //
1177 //     G: Check BOUND
1178 //        If not paged
1179 //          goto H
1180 //        Fetch PTW
1181 //        Fetch prepage PTW
1182 //        Goto I
1183 //
1184 //     H: Compute final address
1185 //        Goto HI
1186 //
1187 //     I: If write
1188 //          set PTW.M
1189 //        Compute final address
1190 //        Goto HI
1191 //
1192 // Phase 4
1193 //
1194 //     HI: --
1195 //         If indirect word fetch
1196 //           goto J
1197 //         if rtcd operand fetch
1198 //           goto K
1199 //         if CALL6
1200 //           goto N
1201 //         If instruction fetch or transfer instruction operand
1202 //           goto L
1203 //         APU data movement?
1204 //           load/store APU data
1205 //
1206 //    K: Set PPR.P
1207 //         Goto J
1208 //
1209 //    J: return
1210 //
1211 
1212 // CANFAULT
1213 
1214 word24 do_append_cycle (processor_cycle_type thisCycle, word36 * data,
     /* [previous][next][first][last][top][bottom][index][help] */
1215                       uint nWords)
1216   {
1217     DCDstruct * i = & cpu.currentInstruction;
1218     DBGAPP ("do_append_cycle(Entry) thisCycle=%s\r\n",
1219             str_pct (thisCycle));
1220     DBGAPP ("do_append_cycle(Entry) lastCycle=%s\r\n",
1221             str_pct (cpu.apu.lastCycle));
1222     DBGAPP ("do_append_cycle(Entry) CA %06o\r\n",
1223             cpu.TPR.CA);
1224     DBGAPP ("do_append_cycle(Entry) n=%2u\r\n",
1225             nWords);
1226     DBGAPP ("do_append_cycle(Entry) PPR.PRR=%o PPR.PSR=%05o\r\n",
1227             cpu.PPR.PRR, cpu.PPR.PSR);
1228     DBGAPP ("do_append_cycle(Entry) TPR.TRR=%o TPR.TSR=%05o\r\n",
1229             cpu.TPR.TRR, cpu.TPR.TSR);
1230 
1231     if (i->b29)
1232       {
1233         DBGAPP ("do_append_cycle(Entry) isb29 PRNO %o\r\n",
1234                 GET_PRN (IWB_IRODD));
1235       }
1236 
1237     bool StrOp = (thisCycle == OPERAND_STORE ||
1238                   thisCycle == APU_DATA_STORE);
1239 
1240     bool nomatch = true;
1241     if (cpu.tweaks.enable_wam)
1242       {
1243         // AL39: The associative memory is ignored (forced to "no match") during
1244         // address preparation.
1245         // lptp,lptr,lsdp,lsdr,sptp,sptr,ssdp,ssdr
1246         // Unfortunately, ISOLTS doesn't try to execute any of these in append mode.
1247         // XXX should this be only for OPERAND_READ and OPERAND_STORE?
1248         nomatch = ((i->opcode == 0232 || i->opcode == 0254  ||
1249                     i->opcode == 0154 || i->opcode == 0173) &&   i->opcodeX) ||
1250                   ((i->opcode == 0557 || i->opcode == 0257) && ! i->opcodeX);
1251       }
1252 
1253     processor_cycle_type lastCycle = cpu.apu.lastCycle;
1254     cpu.apu.lastCycle = thisCycle;
1255 
1256     DBGAPP ("do_append_cycle(Entry) XSF %o\r\n", cpu.cu.XSF);
1257 
1258     PNL (L68_ (cpu.apu.state = 0;))
1259 
1260     cpu.RSDWH_R1 = 0;
1261 
1262     cpu.acvFaults = 0;
1263 
1264 //#define FMSG(x) x
1265 # define FMSG(x)
1266     FMSG (char * acvFaultsMsg = "<unknown>";)
1267 
1268     word24 finalAddress = (word24) -1;  // not everything requires a final
1269                                         // address
1270 
1271 ////////////////////////////////////////
1272 //
1273 // Sheet 1: "START APPEND"
1274 //
1275 ////////////////////////////////////////
1276 
1277 // START APPEND
1278     word3 n = 0; // PRn to be saved to TSN_PRNO
1279 
1280     // If the rtcd instruction is executed with the processor in absolute
1281     // mode with bit 29 of the instruction word set OFF and without
1282     // indirection through an ITP or ITS pair, then:
1283     //
1284     //   appending mode is entered for address preparation for the
1285     //   rtcd operand and is retained if the instruction executes
1286     //   successfully, and the effective segment number generated for
1287     //   the SDW fetch and subsequent loading into C(TPR.TSR) is equal
1288     //   to C(PPR.PSR) and may be undefined in absolute mode, and the
1289     //   effective ring number loaded into C(TPR.TRR) prior to the SDW
1290     //   fetch is equal to C(PPR.PRR) (which is 0 in absolute mode)
1291     //   implying that control is always transferred into ring 0.
1292     //
1293     if (thisCycle == RTCD_OPERAND_FETCH &&
1294         get_addr_mode() == ABSOLUTE_mode &&
1295         ! (cpu.cu.XSF || cpu.currentInstruction.b29) /*get_went_appending()*/)
1296       {
1297         cpu.TPR.TSR = 0;
1298         DBGAPP ("RTCD_OPERAND_FETCH ABSOLUTE mode set TSR %05o TRR %o\r\n",
1299                 cpu.TPR.TSR, cpu.TPR.TRR);
1300       }
1301 
1302     goto A;
1303 
1304 ////////////////////////////////////////
1305 //
1306 // Sheet 2: "A"
1307 //
1308 ////////////////////////////////////////
1309 
1310 //
1311 //  A:
1312 //    Get SDW
1313 
1314 A:;
1315 
1316     //PNL (cpu.APUMemAddr = address;)
1317     PNL (cpu.APUMemAddr = cpu.TPR.CA;)
1318 
1319     DBGAPP ("do_append_cycle(A)\r\n");
1320 
1321     // is SDW for C(TPR.TSR) in SDWAM?
1322     if (nomatch || ! fetch_sdw_from_sdwam (cpu.TPR.TSR))
1323       {
1324         // No
1325         DBGAPP ("do_append_cycle(A):SDW for segment %05o not in SDWAM\r\n",
1326                  cpu.TPR.TSR);
1327 
1328         DBGAPP ("do_append_cycle(A):DSBR.U=%o\r\n",
1329                 cpu.DSBR.U);
1330 
1331         if (cpu.DSBR.U == 0)
1332           {
1333             fetch_dsptw (cpu.TPR.TSR);
1334 
1335             if (! cpu.PTW0.DF)
1336               doFault (FAULT_DF0 + cpu.PTW0.FC, fst_zero,
1337                        "do_append_cycle(A): PTW0.F == 0");
1338 
1339             if (! cpu.PTW0.U)
1340               modify_dsptw (cpu.TPR.TSR);
1341 
1342             fetch_psdw (cpu.TPR.TSR);
1343           }
1344         else
1345           fetch_nsdw (cpu.TPR.TSR); // load SDW0 from descriptor segment table.
1346 
1347         if (cpu.SDW0.DF == 0)
1348           {
1349             if (thisCycle != ABSA_CYCLE)
1350               {
1351                 DBGAPP ("do_append_cycle(A): SDW0.F == 0! "
1352                         "Initiating directed fault\r\n");
1353                 // initiate a directed fault ...
1354                 doFault (FAULT_DF0 + cpu.SDW0.FC, fst_zero, "SDW0.F == 0");
1355               }
1356           }
1357         // load SDWAM .....
1358         load_sdwam (cpu.TPR.TSR, nomatch);
1359       }
1360     DBGAPP ("do_append_cycle(A) R1 %o R2 %o R3 %o E %o\r\n",
1361             cpu.SDW->R1, cpu.SDW->R2, cpu.SDW->R3, cpu.SDW->E);
1362 
1363     // Yes...
1364     cpu.RSDWH_R1 = cpu.SDW->R1;
1365 
1366 ////////////////////////////////////////
1367 //
1368 // Sheet 3: "B"
1369 //
1370 ////////////////////////////////////////
1371 
1372 //
1373 // B: Check the ring
1374 //
1375 
1376     DBGAPP ("do_append_cycle(B)\r\n");
1377 
1378     // check ring bracket consistency
1379 
1380     //C(SDW.R1) <= C(SDW.R2) <= C(SDW .R3)?
1381     if (! (cpu.SDW->R1 <= cpu.SDW->R2 && cpu.SDW->R2 <= cpu.SDW->R3))
1382       {
1383         // Set fault ACV0 = IRO
1384         cpu.acvFaults |= ACV0;
1385         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1386         FMSG (acvFaultsMsg = "acvFaults(B) C(SDW.R1) <= C(SDW.R2) <= "
1387                               "C(SDW .R3)";)
1388       }
1389 
1390     // lastCycle == RTCD_OPERAND_FETCH
1391     // if a fault happens between the RTCD_OPERAND_FETCH and the INSTRUCTION_FETCH
1392     // of the next instruction - this happens about 35 time for just booting  and
1393     // shutting down Multics -- a stored lastCycle is useless.
1394     // the opcode is preserved across faults and only replaced as the
1395     // INSTRUCTION_FETCH succeeds.
1396     if (thisCycle == INSTRUCTION_FETCH &&
1397         i->opcode == 0610  && ! i->opcodeX)
1398       goto C;
1399     else if (lastCycle == RTCD_OPERAND_FETCH)
1400       sim_warn ("%s: lastCycle == RTCD_OPERAND_FETCH opcode %0#o\r\n", __func__, i->opcode);
1401 
1402     //
1403     // B1: The operand is one of: an instruction, data to be read or data to be
1404     //     written
1405     //
1406 
1407     // Is OPCODE call6?
1408     if (thisCycle == OPERAND_READ && (i->info->flags & CALL6_INS))
1409       goto E;
1410 
1411 
1412 
1413 
1414 
1415 
1416 
1417 
1418 
1419 
1420 
1421 
1422 
1423 
1424 
1425 
1426 
1427 
1428 
1429 
1430 
1431 
1432     // Transfer or instruction fetch?
1433     if (thisCycle == INSTRUCTION_FETCH ||
1434         (thisCycle == OPERAND_READ && (i->info->flags & TRANSFER_INS)))
1435       goto F;
1436 
1437     //
1438     // check read bracket for read access
1439     //
1440 
1441 # if defined(LOCKLESS)
1442     if (!StrOp || thisCycle == OPERAND_RMW || thisCycle == APU_DATA_RMW) // -V560
1443 # else
1444     if (!StrOp)
1445 # endif /* if defined(LOCKLESS) */
1446       {
1447         DBGAPP ("do_append_cycle(B):!STR-OP\r\n");
1448 
1449         // No
1450         // C(TPR.TRR) > C(SDW .R2)?
1451         if (cpu.TPR.TRR > cpu.SDW->R2)
1452           {
1453             DBGAPP ("ACV3\r\n");
1454             DBGAPP ("do_append_cycle(B) ACV3\r\n");
1455             //Set fault ACV3 = ORB
1456             cpu.acvFaults |= ACV3;
1457             PNL (L68_ (cpu.apu.state |= apu_FLT;))
1458             FMSG (acvFaultsMsg = "acvFaults(B) C(TPR.TRR) > C(SDW .R2)";)
1459           }
1460 
1461         if (cpu.SDW->R == 0)
1462           {
1463             // isolts 870
1464             cpu.TPR.TRR = cpu.PPR.PRR;
1465 
1466             //C(PPR.PSR) = C(TPR.TSR)?
1467             if (cpu.PPR.PSR != cpu.TPR.TSR)
1468               {
1469                 DBGAPP ("ACV4\r\n");
1470                 DBGAPP ("do_append_cycle(B) ACV4\r\n");
1471                 //Set fault ACV4 = R-OFF
1472                 cpu.acvFaults |= ACV4;
1473                 PNL (L68_ (cpu.apu.state |= apu_FLT;))
1474                 FMSG (acvFaultsMsg = "acvFaults(B) C(PPR.PSR) = C(TPR.TSR)";)
1475               }
1476 
1477 
1478 
1479 
1480 
1481 
1482           }
1483       }
1484 
1485     //
1486     // check write bracket for write access
1487     //
1488 # if defined(LOCKLESS)
1489     if (StrOp || thisCycle == OPERAND_RMW || thisCycle == APU_DATA_RMW)
1490 # else
1491     if (StrOp)
1492 # endif /* if defined(LOCKLESS) */
1493       {
1494         DBGAPP ("do_append_cycle(B):STR-OP\r\n");
1495 
1496         // isolts 870
1497         if (cpu.TPR.TSR == cpu.PPR.PSR)
1498             cpu.TPR.TRR = cpu.PPR.PRR;
1499 
1500         // C(TPR.TRR) > C(SDW .R1)? Note typo in AL39, R2 should be R1
1501         if (cpu.TPR.TRR > cpu.SDW->R1)
1502           {
1503             DBGAPP ("ACV5 TRR %o R1 %o\r\n",
1504                     cpu.TPR.TRR, cpu.SDW->R1);
1505             //Set fault ACV5 = OWB
1506             cpu.acvFaults |= ACV5;
1507             PNL (L68_ (cpu.apu.state |= apu_FLT;))
1508             FMSG (acvFaultsMsg = "acvFaults(B) C(TPR.TRR) > C(SDW .R1)";)
1509           }
1510 
1511         if (! cpu.SDW->W)
1512           {
1513             // isolts 870
1514             cpu.TPR.TRR = cpu.PPR.PRR;
1515 
1516             DBGAPP ("ACV6\r\n");
1517             // Set fault ACV6 = W-OFF
1518             cpu.acvFaults |= ACV6;
1519             PNL (L68_ (cpu.apu.state |= apu_FLT;))
1520             FMSG (acvFaultsMsg = "acvFaults(B) ACV6 = W-OFF";)
1521           }
1522 
1523       }
1524     goto G;
1525 
1526 ////////////////////////////////////////
1527 //
1528 // Sheet 4: "C" "D"
1529 //
1530 ////////////////////////////////////////
1531 
1532 C:;
1533     DBGAPP ("do_append_cycle(C)\r\n");
1534 
1535     //
1536     // check ring bracket for instruction fetch after rtcd instruction
1537     //
1538     //   allow outbound transfers (cpu.TPR.TRR >= cpu.PPR.PRR)
1539     //
1540 
1541     // C(TPR.TRR) < C(SDW.R1)?
1542     // C(TPR.TRR) > C(SDW.R2)?
1543     if (cpu.TPR.TRR < cpu.SDW->R1 ||
1544         cpu.TPR.TRR > cpu.SDW->R2)
1545       {
1546         DBGAPP ("ACV1 c\r\n");
1547         DBGAPP ("acvFaults(C) ACV1 ! ( C(SDW .R1) %o <= C(TPR.TRR) %o <= C(SDW .R2) %o )\r\n",
1548                 cpu.SDW->R1, cpu.TPR.TRR, cpu.SDW->R2);
1549         //Set fault ACV1 = OEB
1550         cpu.acvFaults |= ACV1;
1551         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1552         FMSG (acvFaultsMsg = "acvFaults(C) C(SDW.R1 > C(TPR.TRR) > C(SDW.R2)";)
1553       }
1554     // SDW.E set ON?
1555     if (! cpu.SDW->E)
1556       {
1557         DBGAPP ("ACV2 a\r\n");
1558         DBGAPP ("do_append_cycle(C) ACV2\r\n");
1559         //Set fault ACV2 = E-OFF
1560         cpu.acvFaults |= ACV2;
1561         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1562         FMSG (acvFaultsMsg = "acvFaults(C) SDW.E";)
1563       }
1564     if (cpu.TPR.TRR > cpu.PPR.PRR)
1565       sim_warn ("rtcd: outbound call cpu.TPR.TRR %d cpu.PPR.PRR %d\r\n",
1566                 cpu.TPR.TRR, cpu.PPR.PRR);
1567     // C(TPR.TRR) >= C(PPR.PRR)
1568     if (cpu.TPR.TRR < cpu.PPR.PRR)
1569       {
1570         DBGAPP ("ACV11\r\n");
1571         DBGAPP ("do_append_cycle(C) ACV11\r\n");
1572         //Set fault ACV11 = INRET
1573         cpu.acvFaults |= ACV11;
1574         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1575         FMSG (acvFaultsMsg = "acvFaults(C) TRR>=PRR";)
1576       }
1577 
1578 D:;
1579     DBGAPP ("do_append_cycle(D)\r\n");
1580 
1581     // transfer or instruction fetch
1582 
1583     // check ring alarm to catch outbound transfers
1584 
1585     if (cpu.rRALR == 0)
1586         goto G;
1587 
1588     // C(PPR.PRR) < RALR?
1589     if (! (cpu.PPR.PRR < cpu.rRALR))
1590       {
1591         DBGAPP ("ACV13\r\n");
1592         DBGAPP ("acvFaults(D) C(PPR.PRR) %o < RALR %o\r\n",
1593                 cpu.PPR.PRR, cpu.rRALR);
1594         cpu.acvFaults |= ACV13;
1595         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1596         FMSG (acvFaultsMsg = "acvFaults(D) C(PPR.PRR) < RALR";)
1597       }
1598 
1599     goto G;
1600 
1601 ////////////////////////////////////////
1602 //
1603 // Sheet 5: "E"
1604 //
1605 ////////////////////////////////////////
1606 
1607 E:;
1608 
1609     //
1610     // check ring bracket for instruction fetch after call6 instruction
1611     //   (this is the call6 read operand)
1612     //
1613 
1614     DBGAPP ("do_append_cycle(E): CALL6\r\n");
1615     DBGAPP ("do_append_cycle(E): E %o G %o PSR %05o TSR %05o CA %06o "
1616             "EB %06o R %o%o%o TRR %o PRR %o\r\n",
1617             cpu.SDW->E, cpu.SDW->G, cpu.PPR.PSR, cpu.TPR.TSR, cpu.TPR.CA,
1618             cpu.SDW->EB, cpu.SDW->R1, cpu.SDW->R2, cpu.SDW->R3,
1619             cpu.TPR.TRR, cpu.PPR.PRR);
1620 
1621     //SDW.E set ON?
1622     if (! cpu.SDW->E)
1623       {
1624         DBGAPP ("ACV2 b\r\n");
1625         DBGAPP ("do_append_cycle(E) ACV2\r\n");
1626         // Set fault ACV2 = E-OFF
1627         cpu.acvFaults |= ACV2;
1628         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1629         FMSG (acvFaultsMsg = "acvFaults(E) SDW .E set OFF";)
1630       }
1631 
1632     //SDW .G set ON?
1633     if (cpu.SDW->G)
1634       goto E1;
1635 
1636     // C(PPR.PSR) = C(TPR.TSR)?
1637     if (cpu.PPR.PSR == cpu.TPR.TSR && ! TST_I_ABS)
1638       goto E1;
1639 
1640     // XXX This doesn't seem right
1641     // EB is word 15; masking address makes no sense; rather 0-extend EB
1642     // Fixes ISOLTS 880-01
1643     if (cpu.TPR.CA >= (word18) cpu.SDW->EB)
1644       {
1645         DBGAPP ("ACV7\r\n");
1646         DBGAPP ("do_append_cycle(E) ACV7\r\n");
1647         // Set fault ACV7 = NO GA
1648         cpu.acvFaults |= ACV7;
1649         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1650         FMSG (acvFaultsMsg = "acvFaults(E) TPR.CA4-17 >= SDW.CL";)
1651       }
1652 
1653 E1:
1654     DBGAPP ("do_append_cycle(E1): CALL6 (cont'd)\r\n");
1655 
1656     // C(TPR.TRR) > SDW.R3?
1657     if (cpu.TPR.TRR > cpu.SDW->R3)
1658       {
1659         DBGAPP ("ACV8\r\n");
1660         DBGAPP ("do_append_cycle(E) ACV8\r\n");
1661         //Set fault ACV8 = OCB
1662         cpu.acvFaults |= ACV8;
1663         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1664         FMSG (acvFaultsMsg = "acvFaults(E1) C(TPR.TRR) > SDW.R3";)
1665       }
1666 
1667     // C(TPR.TRR) < SDW.R1?
1668     if (cpu.TPR.TRR < cpu.SDW->R1)
1669       {
1670         DBGAPP ("ACV9\r\n");
1671         DBGAPP ("do_append_cycle(E) ACV9\r\n");
1672         // Set fault ACV9 = OCALL
1673         cpu.acvFaults |= ACV9;
1674         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1675         FMSG (acvFaultsMsg = "acvFaults(E1) C(TPR.TRR) < SDW.R1";)
1676       }
1677 
1678     // C(TPR.TRR) > C(PPR.PRR)?
1679     if (cpu.TPR.TRR > cpu.PPR.PRR)
1680       {
1681         // C(PPR.PRR) < SDW.R2?
1682         if (cpu.PPR.PRR < cpu.SDW->R2)
1683           {
1684             DBGAPP ("ACV10\r\n");
1685             DBGAPP ("do_append_cycle(E) ACV10\r\n");
1686             // Set fault ACV10 = BOC
1687             cpu.acvFaults |= ACV10;
1688             PNL (L68_ (cpu.apu.state |= apu_FLT;))
1689             FMSG (acvFaultsMsg = "acvFaults(E1) C(TPR.TRR) > C(PPR.PRR) && "
1690                   "C(PPR.PRR) < SDW.R2";)
1691           }
1692       }
1693 
1694     DBGAPP ("do_append_cycle(E1): CALL6 TPR.TRR %o SDW->R2 %o\r\n",
1695             cpu.TPR.TRR, cpu.SDW->R2);
1696 
1697     // C(TPR.TRR) > SDW.R2?
1698     if (cpu.TPR.TRR > cpu.SDW->R2)
1699       {
1700         // SDW.R2 -> C(TPR.TRR)
1701         cpu.TPR.TRR = cpu.SDW->R2;
1702       }
1703 
1704     DBGAPP ("do_append_cycle(E1): CALL6 TPR.TRR %o\r\n", cpu.TPR.TRR);
1705 
1706     goto G;
1707 
1708 ////////////////////////////////////////
1709 //
1710 // Sheet 6: "F"
1711 //
1712 ////////////////////////////////////////
1713 
1714 F:;
1715     PNL (L68_ (cpu.apu.state |= apu_PIAU;))
1716     DBGAPP ("do_append_cycle(F): transfer or instruction fetch\r\n");
1717 
1718     //
1719     // check ring bracket for instruction fetch
1720     //
1721 
1722     // C(TPR.TRR) < C(SDW .R1)?
1723     // C(TPR.TRR) > C(SDW .R2)?
1724     if (cpu.TPR.TRR < cpu.SDW->R1 ||
1725         cpu.TPR.TRR > cpu.SDW->R2)
1726       {
1727         DBGAPP ("ACV1 a/b\r\n");
1728         DBGAPP ("acvFaults(F) ACV1 !( C(SDW .R1) %o <= C(TPR.TRR) %o <= C(SDW .R2) %o )\r\n",
1729                 cpu.SDW->R1, cpu.TPR.TRR, cpu.SDW->R2);
1730         cpu.acvFaults |= ACV1;
1731         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1732         FMSG (acvFaultsMsg = "acvFaults(F) C(TPR.TRR) < C(SDW .R1)";)
1733       }
1734     // SDW .E set ON?
1735     if (! cpu.SDW->E)
1736       {
1737         DBGAPP ("ACV2 c\r\n");
1738         DBGAPP ("do_append_cycle(F) ACV2\r\n");
1739         cpu.acvFaults |= ACV2;
1740         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1741         FMSG (acvFaultsMsg = "acvFaults(F) SDW .E set OFF";)
1742       }
1743 
1744     // C(PPR.PRR) = C(TPR.TRR)?
1745     if (cpu.PPR.PRR != cpu.TPR.TRR)
1746       {
1747         DBGAPP ("ACV12\r\n");
1748         DBGAPP ("do_append_cycle(F) ACV12\r\n");
1749         //Set fault ACV12 = CRT
1750         cpu.acvFaults |= ACV12;
1751         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1752         FMSG (acvFaultsMsg = "acvFaults(F) C(PPR.PRR) != C(TPR.TRR)";)
1753       }
1754 
1755     goto D;
1756 
1757 ////////////////////////////////////////
1758 //
1759 // Sheet 7: "G"
1760 //
1761 ////////////////////////////////////////
1762 
1763 G:;
1764 
1765     DBGAPP ("do_append_cycle(G)\r\n");
1766 
1767     //C(TPR.CA)0,13 > SDW.BOUND?
1768     if (((cpu.TPR.CA >> 4) & 037777) > cpu.SDW->BOUND)
1769       {
1770         DBGAPP ("ACV15\r\n");
1771         DBGAPP ("do_append_cycle(G) ACV15\r\n");
1772         cpu.acvFaults |= ACV15;
1773         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1774         FMSG (acvFaultsMsg = "acvFaults(G) C(TPR.CA)0,13 > SDW.BOUND";)
1775         DBGAPP ("acvFaults(G) C(TPR.CA)0,13 > SDW.BOUND\r\n"
1776                 "   CA %06o CA>>4 & 037777 %06o SDW->BOUND %06o",
1777                 cpu.TPR.CA, ((cpu.TPR.CA >> 4) & 037777), cpu.SDW->BOUND);
1778       }
1779 
1780     if (cpu.acvFaults)
1781       {
1782         DBGAPP ("do_append_cycle(G) acvFaults\r\n");
1783         PNL (L68_ (cpu.apu.state |= apu_FLT;))
1784         // Initiate an access violation fault
1785         doFault (FAULT_ACV, (_fault_subtype) {.fault_acv_subtype=cpu.acvFaults},
1786                  "ACV fault");
1787       }
1788 
1789     // is segment C(TPR.TSR) paged?
1790     if (cpu.SDW->U)
1791       goto H; // Not paged
1792 
1793     // Yes. segment is paged ...
1794     // is PTW for C(TPR.CA) in PTWAM?
1795 
1796     DBGAPP ("do_append_cycle(G) CA %06o\r\n", cpu.TPR.CA);
1797     if (nomatch ||
1798         ! fetch_ptw_from_ptwam (cpu.SDW->POINTER, cpu.TPR.CA))  //TPR.CA))
1799       {
1800         fetch_ptw (cpu.SDW, cpu.TPR.CA);
1801         if (! cpu.PTW0.DF)
1802           {
1803             if (thisCycle != ABSA_CYCLE)
1804               {
1805                 // initiate a directed fault
1806                 doFault (FAULT_DF0 + cpu.PTW0.FC, (_fault_subtype) {.bits=0},
1807                          "PTW0.F == 0");
1808               }
1809           }
1810         loadPTWAM (cpu.SDW->POINTER, cpu.TPR.CA, nomatch); // load PTW0 to PTWAM
1811       }
1812 
1813     // Prepage mode?
1814     // check for "uninterruptible" EIS instruction
1815     // ISOLTS-878 02: mvn,cmpn,mvne,ad3d; obviously also
1816     // ad2/3d,sb2/3d,mp2/3d,dv2/3d
1817     // DH03 p.8-13: probably also mve,btd,dtb
1818     if (i->opcodeX && ((i->opcode & 0770)== 0200|| (i->opcode & 0770) == 0220
1819         || (i->opcode & 0770)== 020|| (i->opcode & 0770) == 0300))
1820       {
1821         do_ptw2 (cpu.SDW, cpu.TPR.CA);
1822       }
1823     goto I;
1824 
1825 ////////////////////////////////////////
1826 //
1827 // Sheet 8: "H", "I"
1828 //
1829 ////////////////////////////////////////
1830 
1831 H:;
1832     DBGAPP ("do_append_cycle(H): FANP\r\n");
1833 
1834     PNL (L68_ (cpu.apu.state |= apu_FANP;))
1835 
1836 
1837 
1838 
1839 
1840 
1841 
1842 
1843 
1844     set_apu_status (apuStatus_FANP);
1845 
1846     DBGAPP ("do_append_cycle(H): SDW->ADDR=%08o CA=%06o\r\n",
1847             cpu.SDW->ADDR, cpu.TPR.CA);
1848 
1849     if (thisCycle == RTCD_OPERAND_FETCH &&
1850         get_addr_mode () == ABSOLUTE_mode &&
1851         ! (cpu.cu.XSF || cpu.currentInstruction.b29) /*get_went_appending ()*/)
1852       {
1853         finalAddress = cpu.TPR.CA;
1854       }
1855     else
1856       {
1857         finalAddress = (cpu.SDW->ADDR & 077777760) + cpu.TPR.CA;
1858         finalAddress &= 0xffffff;
1859       }
1860     PNL (cpu.APUMemAddr = finalAddress;)
1861 
1862     DBGAPP ("do_append_cycle(H:FANP): (%05o:%06o) finalAddress=%08o\r\n",
1863             cpu.TPR.TSR, cpu.TPR.CA, finalAddress);
1864 
1865     //if (thisCycle == ABSA_CYCLE)
1866     //    goto J;
1867     goto HI;
1868 
1869 I:;
1870 
1871 // Set PTW.M
1872 
1873     DBGAPP ("do_append_cycle(I): FAP\r\n");
1874 # if defined(LOCKLESS)
1875     if ((StrOp ||
1876         thisCycle == OPERAND_RMW ||
1877         thisCycle == APU_DATA_RMW) && cpu.PTW->M == 0)  // is this the right way to do this?
1878 # else
1879     if (StrOp && cpu.PTW->M == 0)  // is this the right way to do this?
1880 # endif /* if defined(LOCKLESS) */
1881       {
1882        modify_ptw (cpu.SDW, cpu.TPR.CA);
1883       }
1884 
1885     // final address paged
1886     set_apu_status (apuStatus_FAP);
1887     PNL (L68_ (cpu.apu.state |= apu_FAP;))
1888 
1889     word24 y2 = cpu.TPR.CA % 1024;
1890 
1891     // AL39: The hardware ignores low order bits of the main memory page
1892     // address according to page size
1893     finalAddress = (((word24)cpu.PTW->ADDR & 0777760) << 6) + y2;
1894     finalAddress &= 0xffffff;
1895     PNL (cpu.APUMemAddr = finalAddress;)
1896 
1897     L68_ (if (cpu.MR_cache.emr && cpu.MR_cache.ihr)
1898       add_l68_APU_history (APUH_FAP);)
1899 
1900     DBGAPP ("do_append_cycle(H:FAP): (%05o:%06o) finalAddress=%08o\r\n",
1901             cpu.TPR.TSR, cpu.TPR.CA, finalAddress);
1902 
1903     //if (thisCycle == ABSA_CYCLE)
1904     //    goto J;
1905     goto HI;
1906 
1907 HI:
1908     DBGAPP ("do_append_cycle(HI)\r\n");
1909 
1910     // isolts 870
1911     if (thisCycle != ABSA_CYCLE)
1912       {
1913         cpu.cu.XSF = 1;
1914         if (cpu.currentInstruction.b29)
1915           cpu.xsfScu = true;
1916         sim_debug (DBG_TRACEEXT, & cpu_dev, "loading of cpu.TPR.TSR sets XSF to 1\r\n");
1917       }
1918 
1919     if (thisCycle == OPERAND_STORE && cpu.useZone)
1920       {
1921         cache_write_zone (finalAddress, * data, str_pct (thisCycle));
1922       }
1923     else if (StrOp)
1924       {
1925         cache_writeN (finalAddress, data, nWords, str_pct (thisCycle));
1926       }
1927     else
1928       {
1929 # if defined(LOCKLESS)
1930         if ((thisCycle == OPERAND_RMW || thisCycle == APU_DATA_RMW) && nWords == 1)
1931           {
1932             cache_read_lock (finalAddress, data, str_pct (thisCycle));
1933           }
1934         else
1935           {
1936             if (thisCycle == OPERAND_RMW || thisCycle == APU_DATA_RMW)
1937               sim_warn("do_append_cycle: RMW nWords %d != 1\r\n", nWords);
1938             cache_readN (finalAddress, data, nWords, str_pct (thisCycle));
1939           }
1940 # else
1941         if (thisCycle != ABSA_CYCLE)
1942           cache_readN (finalAddress, data, nWords, str_pct (thisCycle));
1943 # endif /* if defined(LOCKLESS) */
1944       }
1945 
1946     // Was this an indirect word fetch?
1947     if (thisCycle == INDIRECT_WORD_FETCH)
1948       goto J;
1949 
1950     // Was this an rtcd operand fetch?
1951     if (thisCycle == RTCD_OPERAND_FETCH)
1952       goto K;
1953 
1954     // is OPCODE call6?
1955     if (thisCycle == OPERAND_READ && (i->info->flags & CALL6_INS))
1956       goto N;
1957 
1958     // Transfer or instruction fetch?
1959     if (thisCycle == INSTRUCTION_FETCH ||
1960         (thisCycle == OPERAND_READ && (i->info->flags & TRANSFER_INS)))
1961       goto L;
1962 
1963     // APU data movement?
1964     //  handled above
1965    goto Exit;
1966 
1967 ////////////////////////////////////////
1968 //
1969 // Sheet 9: "J"
1970 //
1971 ////////////////////////////////////////
1972 
1973 // Indirect operand fetch
1974 
1975 J:;
1976     DBGAPP ("do_append_cycle(J)\r\n");
1977 
1978     // ri or ir & TPC.CA even?
1979     word6 tag = GET_TAG (IWB_IRODD);
1980     if ((GET_TM (tag) == TM_IR || GET_TM (tag) == TM_RI) &&
1981         (cpu.TPR.CA & 1) == 0)
1982       {
1983         if (ISITS (* data))
1984           goto O;
1985         if (ISITP (* data))
1986           goto P;
1987       }
1988 
1989     // C(Y) tag == other indirect?
1990     //   TM_R never indirects
1991     //   TM_RI always indirects
1992     //   TM_IR always indirects
1993     //   TM_IT always indirects
1994 
1995 
1996 
1997 
1998 
1999 
2000 
2001 
2002 
2003 
2004 
2005 
2006 
2007 
2008 
2009 
2010 
2011 
2012 
2013 
2014 
2015 
2016 
2017 
2018 
2019 
2020 
2021 
2022     if ((* data) & 060)
2023 
2024       {
2025         // C(Y)0,17 -> C(IWB)0,17
2026         // C(Y)30,35 -> C(IWB)30,35
2027         // 0 -> C(IWB)29
2028         //updateIWB (GET_ADDR (* data), (* data) & MASK6);
2029         //cpu.cu.TSN_PRNO[0] = n;
2030         //cpu.cu.TSN_VALID[0] = 1;
2031 
2032       }
2033 
2034      goto Exit;
2035 
2036 ////////////////////////////////////////
2037 //
2038 // Sheet 10: "K", "L", "M", "N"
2039 //
2040 ////////////////////////////////////////
2041 
2042 K:; // RTCD operand fetch
2043     DBGAPP ("do_append_cycle(K)\r\n");
2044 
2045     word3 y = GET_ITS_RN (data);
2046 
2047     // C(Y-pair)3,17 -> C(PPR.PSR)
2048     // We set TSR here; TSR will be copied to PSR at KL
2049     cpu.TPR.TSR = GET_ITS_SEGNO (data);
2050 
2051     // Maximum of
2052     // C(Y-pair)18,20; C(TPR.TRR); C(SDW.R1) -> C(PPR.PRR)
2053     // We set TRR here as well
2054     cpu.PPR.PRR = cpu.TPR.TRR = max3 (y, cpu.TPR.TRR, cpu.RSDWH_R1);
2055 
2056     // C(Y-pair)36,53 -> C(PPR.IC)
2057     // We set CA here; copied to IC  at KL
2058     cpu.TPR.CA = GET_ITS_WORDNO (data);
2059 
2060     // If C(PPR.PRR) = 0 then C(SDW.P) -> C(PPR.P);
2061     //     otherwise 0 -> C(PPR.P)
2062     // Done at M
2063 
2064     goto KL;
2065 
2066 L:; // Transfer or instruction fetch
2067 
2068     DBGAPP ("do_append_cycle(L)\r\n");
2069 
2070     // Is OPCODE tspn?
2071     if (thisCycle == OPERAND_READ && (i->info->flags & TSPN_INS))
2072       {
2073         //word3 n;
2074         if (i->opcode <= 0273)
2075           n = (i->opcode & 3);
2076         else
2077           n = (i->opcode & 3) + 4;
2078 
2079         // C(PPR.PRR) -> C(PRn .RNR)
2080         // C(PPR.PSR) -> C(PRn .SNR)
2081         // C(PPR.IC)  -> C(PRn .WORDNO)
2082         // 000000     -> C(PRn .BITNO)
2083         cpu.PR[n].RNR = cpu.PPR.PRR;
2084 // According the AL39, the PSR is 'undefined' in absolute mode.
2085 // ISOLTS thinks means don't change the operand
2086         if (get_addr_mode () == APPEND_mode)
2087           cpu.PR[n].SNR = cpu.PPR.PSR;
2088         cpu.PR[n].WORDNO = (cpu.PPR.IC + 1) & MASK18;
2089         SET_PR_BITNO (n, 0);
2090 # if defined(TESTING)
2091         HDBGRegPRW (n, "app tspn");
2092 # endif /* if defined(TESTING) */
2093       }
2094 
2095     // lastCycle == RTCD_OPERAND_FETCH
2096 
2097     if (thisCycle == INSTRUCTION_FETCH &&
2098         i->opcode == 0610  && ! i->opcodeX)
2099       {
2100         // C(PPR.PRR) -> C(PRn.RNR) for n = (0, 1, ..., 7)
2101         // Use TRR here; PRR not set until KL
2102         CPTUR (cptUsePRn + 0);
2103         CPTUR (cptUsePRn + 1);
2104         CPTUR (cptUsePRn + 2);
2105         CPTUR (cptUsePRn + 3);
2106         CPTUR (cptUsePRn + 4);
2107         CPTUR (cptUsePRn + 5);
2108         CPTUR (cptUsePRn + 6);
2109         CPTUR (cptUsePRn + 7);
2110         cpu.PR[0].RNR =
2111         cpu.PR[1].RNR =
2112         cpu.PR[2].RNR =
2113         cpu.PR[3].RNR =
2114         cpu.PR[4].RNR =
2115         cpu.PR[5].RNR =
2116         cpu.PR[6].RNR =
2117         cpu.PR[7].RNR = cpu.TPR.TRR;
2118 # if defined(TESTING)
2119         HDBGRegPRW (0, "app rtcd");
2120         HDBGRegPRW (1, "app rtcd");
2121         HDBGRegPRW (2, "app rtcd");
2122         HDBGRegPRW (3, "app rtcd");
2123         HDBGRegPRW (4, "app rtcd");
2124         HDBGRegPRW (5, "app rtcd");
2125         HDBGRegPRW (6, "app rtcd");
2126         HDBGRegPRW (7, "app rtcd");
2127 # endif /* if defined(TESTING) */
2128       }
2129     goto KL;
2130 
2131 KL:
2132     DBGAPP ("do_append_cycle(KL)\r\n");
2133 
2134     // C(TPR.TSR) -> C(PPR.PSR)
2135     cpu.PPR.PSR   = cpu.TPR.TSR;
2136     // C(TPR.CA)  -> C(PPR.IC)
2137     cpu.PPR.IC    = cpu.TPR.CA;
2138 
2139     goto M;
2140 
2141 M: // Set P
2142     DBGAPP ("do_append_cycle(M)\r\n");
2143 
2144     // C(TPR.TRR) = 0?
2145     if (cpu.TPR.TRR == 0)
2146       {
2147         // C(SDW.P) -> C(PPR.P)
2148         cpu.PPR.P = cpu.SDW->P;
2149       }
2150     else
2151       {
2152         // 0 C(PPR.P)
2153         cpu.PPR.P = 0;
2154       }
2155 
2156     goto Exit;
2157 
2158 N: // CALL6
2159     DBGAPP ("do_append_cycle(N)\r\n");
2160 
2161     // C(TPR.TRR) = C(PPR.PRR)?
2162     if (cpu.TPR.TRR == cpu.PPR.PRR)
2163       {
2164         // C(PR6.SNR) -> C(PR7.SNR)
2165         cpu.PR[7].SNR = cpu.PR[6].SNR;
2166         DBGAPP ("do_append_cycle(N) PR7.SNR = PR6.SNR %05o\r\n", cpu.PR[7].SNR);
2167       }
2168     else
2169       {
2170         // C(DSBR.STACK) || C(TPR.TRR) -> C(PR7.SNR)
2171         cpu.PR[7].SNR = ((word15) (cpu.DSBR.STACK << 3)) | cpu.TPR.TRR;
2172         DBGAPP ("do_append_cycle(N) STACK %05o TRR %o\r\n",
2173                 cpu.DSBR.STACK, cpu.TPR.TRR);
2174         DBGAPP ("do_append_cycle(N) PR7.SNR = STACK||TRR  %05o\r\n", cpu.PR[7].SNR);
2175       }
2176 
2177     // C(TPR.TRR) -> C(PR7.RNR)
2178     cpu.PR[7].RNR = cpu.TPR.TRR;
2179     // 00...0 -> C(PR7.WORDNO)
2180     cpu.PR[7].WORDNO = 0;
2181     // 000000 -> C(PR7.BITNO)
2182     SET_PR_BITNO (7, 0);
2183 # if defined(TESTING)
2184     HDBGRegPRW (7, "app call6");
2185 # endif /* if defined(TESTING) */
2186     // C(TPR.TRR) -> C(PPR.PRR)
2187     cpu.PPR.PRR   = cpu.TPR.TRR;
2188     // C(TPR.TSR) -> C(PPR.PSR)
2189     cpu.PPR.PSR   = cpu.TPR.TSR;
2190     // C(TPR.CA)  -> C(PPR.IC)
2191     cpu.PPR.IC    = cpu.TPR.CA;
2192 
2193     goto M;
2194 
2195 ////////////////////////////////////////
2196 //
2197 // Sheet 11: "O", "P"
2198 //
2199 ////////////////////////////////////////
2200 
2201 O:; // ITS, RTCD
2202     DBGAPP ("do_append_cycle(O)\r\n");
2203     word3 its_RNR = GET_ITS_RN (data);
2204     DBGAPP ("do_append_cycle(O) TRR %o RSDWH.R1 %o ITS.RNR %o\r\n",
2205             cpu.TPR.TRR, cpu.RSDWH_R1, its_RNR);
2206 
2207     // Maximum of
2208     //  C(Y)18,20;  C(TPR.TRR); C(SDW.R1) -> C(TPR.TRR)
2209     cpu.TPR.TRR = max3 (its_RNR, cpu.TPR.TRR, cpu.RSDWH_R1);
2210     DBGAPP ("do_append_cycle(O) Set TRR to %o\r\n", cpu.TPR.TRR);
2211 
2212     goto Exit;
2213 
2214 P:; // ITP
2215 
2216     DBGAPP ("do_append_cycle(P)\r\n");
2217 
2218     n = GET_ITP_PRNUM (data);
2219     DBGAPP ("do_append_cycle(P) TRR %o RSDWH.R1 %o PR[n].RNR %o\r\n",
2220             cpu.TPR.TRR, cpu.RSDWH_R1, cpu.PR[n].RNR);
2221 
2222     // Maximum of
2223     // cpu.PR[n].RNR;  C(TPR.TRR); C(SDW.R1) -> C(TPR.TRR)
2224     cpu.TPR.TRR = max3 (cpu.PR[n].RNR, cpu.TPR.TRR, cpu.RSDWH_R1);
2225     DBGAPP ("do_append_cycle(P) Set TRR to %o\r\n", cpu.TPR.TRR);
2226 
2227     goto Exit;
2228 
2229 Exit:;
2230 
2231     PNL (cpu.APUDataBusOffset = cpu.TPR.CA;)
2232     PNL (cpu.APUDataBusAddr = finalAddress;)
2233 
2234     PNL (L68_ (cpu.apu.state |= apu_FA;))
2235 
2236     DBGAPP ("do_append_cycle (Exit) PRR %o PSR %05o P %o IC %06o\r\n",
2237             cpu.PPR.PRR, cpu.PPR.PSR, cpu.PPR.P, cpu.PPR.IC);
2238     DBGAPP ("do_append_cycle (Exit) TRR %o TSR %05o TBR %02o CA %06o\r\n",
2239             cpu.TPR.TRR, cpu.TPR.TSR, cpu.TPR.TBR, cpu.TPR.CA);
2240 
2241     return finalAddress;    // or 0 or -1???
2242   }
2243 #endif /* if defined(OLDAPP) */
2244 
2245 // Translate a segno:offset to a absolute address.
2246 // Return 0 if successful.
2247 
2248 #if defined(TESTING)
2249 int dbgLookupAddress (word18 segno, word18 offset, word24 * finalAddress,
     /* [previous][next][first][last][top][bottom][index][help] */
2250                       char * * msg)
2251   {
2252     cpu_state_t * cpup = _cpup;
2253     // Local copies so we don't disturb machine state
2254 
2255     ptw_s PTW1;
2256     sdw_s SDW1;
2257 
2258    if (2u * segno >= 16u * (cpu.DSBR.BND + 1u))
2259      {
2260        if (msg)
2261          * msg = "DSBR boundary violation.";
2262        return 1;
2263      }
2264 
2265     if (cpu.DSBR.U == 0)
2266       {
2267         // fetch_dsptw
2268 
2269         word24 y1 = (2 * segno) % 1024;
2270         word24 x1 = (2 * segno) / 1024; // floor
2271 
2272         word36 PTWx1;
2273         core_read (cpup, (cpu.DSBR.ADDR + x1) & PAMASK, & PTWx1, __func__); // NO_CACHE
2274 
2275         PTW1.ADDR = GETHI (PTWx1);
2276         PTW1.U = TSTBIT (PTWx1, 9);
2277         PTW1.M = TSTBIT (PTWx1, 6);
2278         PTW1.DF = TSTBIT (PTWx1, 2);
2279         PTW1.FC = PTWx1 & 3;
2280 
2281         if (! PTW1.DF)
2282           {
2283             if (msg)
2284               * msg = "!PTW0.F";
2285             return 2;
2286           }
2287 
2288         // fetch_psdw
2289 
2290         y1 = (2 * segno) % 1024;
2291 
2292         word36 SDWeven, SDWodd;
2293 
2294         core_read2 (cpup, ((((word24)PTW1. ADDR & 0777760) << 6) + y1) & PAMASK, // NO_CACHE
2295                     & SDWeven, & SDWodd, __func__);
2296 
2297         // even word
2298         SDW1.ADDR = (SDWeven >> 12) & 077777777;
2299         SDW1.R1   = (SDWeven >> 9)  & 7;
2300         SDW1.R2   = (SDWeven >> 6)  & 7;
2301         SDW1.R3   = (SDWeven >> 3)  & 7;
2302         SDW1.DF   = TSTBIT (SDWeven, 2);
2303         SDW1.FC   = SDWeven & 3;
2304 
2305         // odd word
2306         SDW1.BOUND = (SDWodd >> 21) & 037777;
2307         SDW1.R     = TSTBIT (SDWodd, 20);
2308         SDW1.E     = TSTBIT (SDWodd, 19);
2309         SDW1.W     = TSTBIT (SDWodd, 18);
2310         SDW1.P     = TSTBIT (SDWodd, 17);
2311         SDW1.U     = TSTBIT (SDWodd, 16);
2312         SDW1.G     = TSTBIT (SDWodd, 15);
2313         SDW1.C     = TSTBIT (SDWodd, 14);
2314         SDW1.EB    = SDWodd & 037777;
2315       }
2316     else // ! DSBR.U
2317       {
2318         // fetch_nsdw
2319 
2320         word36 SDWeven, SDWodd;
2321 
2322         core_read2 (cpup, (cpu.DSBR.ADDR + 2 * segno) & PAMASK, // NO_CACHE
2323                     & SDWeven, & SDWodd, __func__);
2324 
2325         // even word
2326         SDW1.ADDR = (SDWeven >> 12) & 077777777;
2327         SDW1.R1   = (SDWeven >> 9)  & 7;
2328         SDW1.R2   = (SDWeven >> 6)  & 7;
2329         SDW1.R3   = (SDWeven >> 3)  & 7;
2330         SDW1.DF   = TSTBIT (SDWeven, 2);
2331         SDW1.FC   = SDWeven & 3;
2332 
2333         // odd word
2334         SDW1.BOUND = (SDWodd >> 21) & 037777;
2335         SDW1.R     = TSTBIT (SDWodd, 20);
2336         SDW1.E     = TSTBIT (SDWodd, 19);
2337         SDW1.W     = TSTBIT (SDWodd, 18);
2338         SDW1.P     = TSTBIT (SDWodd, 17);
2339         SDW1.U     = TSTBIT (SDWodd, 16);
2340         SDW1.G     = TSTBIT (SDWodd, 15);
2341         SDW1.C     = TSTBIT (SDWodd, 14);
2342         SDW1.EB    = SDWodd & 037777;
2343 
2344       }
2345 
2346     if (SDW1.DF == 0)
2347       {
2348         if (msg)
2349           * msg = "!SDW0.F != 0";
2350         return 3;
2351       }
2352 
2353     if (((offset >> 4) & 037777) > SDW1.BOUND)
2354       {
2355         if (msg)
2356           * msg = "C(TPR.CA)0,13 > SDW.BOUND";
2357         return 4;
2358       }
2359 
2360     // is segment C(TPR.TSR) paged?
2361     if (SDW1.U)
2362       {
2363         * finalAddress = (SDW1.ADDR + offset) & PAMASK;
2364       }
2365     else
2366       {
2367         // fetch_ptw
2368         word24 y2 = offset % 1024;
2369         word24 x2 = (offset) / 1024; // floor
2370 
2371         word36 PTWx2;
2372 
2373         core_read (cpup, (SDW1.ADDR + x2) & PAMASK, & PTWx2, __func__); // NO_CACHE
2374 
2375         PTW1.ADDR = GETHI (PTWx2);
2376         PTW1.U    = TSTBIT (PTWx2, 9);
2377         PTW1.M    = TSTBIT (PTWx2, 6);
2378         PTW1.DF   = TSTBIT (PTWx2, 2);
2379         PTW1.FC   = PTWx2 & 3;
2380 
2381         if (! PTW1.DF)
2382           {
2383             if (msg)
2384               * msg = "!PTW0.F";
2385             return 5;
2386           }
2387 
2388         y2 = offset % 1024;
2389 
2390         * finalAddress = ((((word24)PTW1.ADDR & 0777760) << 6) + y2) & PAMASK;
2391       }
2392     if (msg)
2393       * msg = "";
2394     return 0;
2395   }
2396 #endif /* if defined(TESTING) */

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