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

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