root/src/dps8/dps8_addrmods.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_Cr
  2. op_desc_str
  3. do_ITP
  4. do_ITS
  5. do_ITS_ITP
  6. updateIWB
  7. do_caf

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: 410f7ba2-f62d-11ec-b7d6-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2007-2013 Michael Mondy
   9  * Copyright (c) 2012-2016 Harry Reed
  10  * Copyright (c) 2013-2018 Charles Anthony
  11  * Copyright (c) 2021-2024 The DPS8M Development Team
  12  *
  13  * This software is made available under the terms of the ICU License.
  14  * See the LICENSE.md file at the top-level directory of this distribution.
  15  *
  16  * ---------------------------------------------------------------------------
  17  */
  18 
  19 #include <stdio.h>
  20 #include "dps8.h"
  21 #include "dps8_sys.h"
  22 #include "dps8_iom.h"
  23 #include "dps8_cable.h"
  24 #include "dps8_cpu.h"
  25 #include "dps8_scu.h"
  26 #include "dps8_faults.h"
  27 #include "dps8_addrmods.h"
  28 #include "dps8_append.h"
  29 #include "dps8_ins.h"
  30 #include "dps8_iefp.h"
  31 #include "dps8_opcodetable.h"
  32 #include "dps8_utils.h"
  33 #if defined(THREADZ) || defined(LOCKLESS)
  34 # include "threadz.h"
  35 #endif
  36 
  37 #define DBG_CTR cpu.cycleCnt
  38 
  39 // Computed Address Formation Flowcharts
  40 
  41 //
  42 // return contents of register indicated by Td
  43 //
  44 
  45 static word18 get_Cr (cpu_state_t * cpup, word4 Tdes)
     /* [previous][next][first][last][top][bottom][index][help] */
  46   {
  47     cpu.ou.directOperandFlag = false;
  48 
  49     if (Tdes == TD_N)
  50       return 0;
  51 
  52     if (Tdes & 010) // Xn
  53       return cpu.rX [X (Tdes)];
  54 
  55     switch (Tdes)
  56       {
  57         case TD_N:  // rY = address from opcode
  58           return 0;
  59 
  60         case TD_AU: // rY + C(A)0,17
  61 #if defined(TESTING)
  62           HDBGRegAR ("au");
  63 #endif
  64           return GETHI (cpu.rA);
  65 
  66         case TD_QU: // rY + C(Q)0,17
  67 #if defined(TESTING)
  68           HDBGRegAR ("qu");
  69 #endif
  70           return GETHI (cpu.rQ);
  71 
  72         case TD_DU: // none; operand has the form y || (00...0)18
  73           cpu.ou.directOperand = 0;
  74           SETHI (cpu.ou.directOperand, cpu.rY);
  75           cpu.ou.directOperandFlag = true;
  76 
  77           sim_debug (DBG_ADDRMOD, & cpu_dev,
  78                     "%s(TD_DU): rY=%06o directOperand=%012"PRIo64"\n",
  79                     __func__, cpu.rY, cpu.ou.directOperand);
  80 
  81           return 0;
  82 
  83         case TD_IC: // rY + C (PPR.IC)
  84           return cpu.PPR.IC;
  85 
  86         case TD_AL: // rY + C(A)18,35
  87 #if defined(TESTING)
  88           HDBGRegAR ("al");
  89 #endif
  90           return GETLO (cpu.rA);
  91 
  92         case TD_QL: // rY + C(Q)18,35
  93 #if defined(TESTING)
  94           HDBGRegAR ("ql");
  95 #endif
  96           return GETLO (cpu.rQ);
  97 
  98         case TD_DL: // none; operand has the form (00...0)18 || y
  99             cpu.ou.directOperand = 0;
 100             SETLO (cpu.ou.directOperand, cpu.rY);
 101             cpu.ou.directOperandFlag = true;
 102 
 103             sim_debug (DBG_ADDRMOD, & cpu_dev,
 104                        "%s(TD_DL): rY=%06o directOperand=%012"PRIo64"\n",
 105                        __func__, cpu.rY, cpu.ou.directOperand);
 106 
 107             return 0;
 108       }
 109     return 0;
 110   }
 111 
 112 static char * op_desc_str (cpu_state_t * cpup, char * temp)
     /* [previous][next][first][last][top][bottom][index][help] */
 113   {
 114     DCDstruct * i = & cpu.currentInstruction;
 115 
 116     strcpy (temp, "");
 117 
 118     if (READOP (i))
 119       {
 120         switch (operand_size (cpup))
 121           {
 122             case 1:
 123               strcat (temp, "readCY");
 124               break;
 125 
 126             case 2:
 127               strcat (temp, "readCYpair2");
 128               break;
 129 
 130             case 8:
 131               strcat (temp, "readCYblock8");
 132               break;
 133 
 134             case 16:
 135               strcat (temp, "readCYblock16");
 136               break;
 137 
 138             case 32:
 139               strcat (temp, "readCYblock32");
 140               break;
 141           }
 142       }
 143 
 144     if (WRITEOP (i))
 145       {
 146         if (strlen (temp))
 147           strcat (temp, "/");
 148 
 149         switch (operand_size (cpup))
 150           {
 151             case 1:
 152               strcat (temp, "writeCY");
 153               break;
 154 
 155             case 2:
 156               strcat (temp, "writeCYpair2");
 157               break;
 158 
 159             case 8:
 160               strcat (temp, "writeCYblock8");
 161               break;
 162 
 163             case 16:
 164               strcat (temp, "writeCYblock16");
 165               break;
 166 
 167             case 32:
 168               strcat (temp, "writeCYblock32");
 169               break;
 170           }
 171       }
 172 
 173     if (TRANSOP (i))
 174       {
 175         if (strlen (temp))
 176           strcat (temp, "/");
 177 
 178         strcat (temp, "prepareCA (TRA)");
 179       }
 180 
 181     if (! READOP (i) && ! WRITEOP (i) && ! TRANSOP (i) &&
 182         i -> info -> flags & PREPARE_CA)
 183       {
 184         if (strlen (temp))
 185           strcat (temp, "/");
 186 
 187         strcat (temp, "prepareCA");
 188       }
 189 
 190     return temp;    //"op_desc_str (???)";
 191   }
 192 
 193 static void do_ITP (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
 194   {
 195     sim_debug (DBG_APPENDING, & cpu_dev,
 196                "ITP Pair: PRNUM=%o BITNO=%o WORDNO=%o MOD=%o\n",
 197                GET_ITP_PRNUM (cpu.itxPair), GET_ITP_WORDNO (cpu.itxPair),
 198                GET_ITP_BITNO (cpu.itxPair), GET_ITP_MOD (cpu.itxPair));
 199     //
 200     // For n = C(ITP.PRNUM):
 201     // C(PRn.SNR) -> C(TPR.TSR)
 202     // maximum of ( C(PRn.RNR), C(SDW.R1), C(TPR.TRR) ) -> C(TPR.TRR)
 203     // C(ITP.BITNO) -> C(TPR.TBR)
 204     // C(PRn.WORDNO) + C(ITP.WORDNO) + C(r) -> C(TPR.CA)
 205 
 206     // Notes:
 207     // 1. r = C(CT-HOLD) if the instruction word or preceding indirect word
 208     //    specified indirect then register modification, or
 209     // 2. r = C(ITP.MOD.Td) if the instruction word or preceding indirect word
 210     //   specified register then indirect modification and ITP.MOD.Tm specifies
 211     //    either register or register then indirect modification.
 212     // 3. SDW.R1 is the upper limit of the read/write ring bracket for the
 213     // segment C(TPR.TSR) (see Section 8).
 214     //
 215 
 216     word3 n = GET_ITP_PRNUM (cpu.itxPair);
 217     CPTUR (cptUsePRn + n);
 218 #if defined(TESTING)
 219     HDBGRegPRR (n, "ITP");
 220 #endif
 221     cpu.TPR.TSR  = cpu.PR[n].SNR;
 222     cpu.TPR.TRR  = max3 (cpu.PR[n].RNR, cpu.RSDWH_R1, cpu.TPR.TRR);
 223     cpu.TPR.TBR  = GET_ITP_BITNO (cpu.itxPair);
 224     cpu.TPR.CA   = cpu.PAR[n].WORDNO + GET_ITP_WORDNO (cpu.itxPair);
 225     cpu.TPR.CA  &= AMASK;
 226     cpu.rY       = cpu.TPR.CA;
 227 
 228     cpu.rTAG = GET_ITP_MOD (cpu.itxPair);
 229 
 230     cpu.cu.itp          = 1;
 231     cpu.cu.TSN_PRNO[0]  = n;
 232     cpu.cu.TSN_VALID[0] = 1;
 233 
 234     return;
 235   }
 236 
 237 static void do_ITS (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
 238   {
 239     sim_debug (DBG_APPENDING, & cpu_dev,
 240                "ITS Pair: SEGNO=%o RN=%o WORDNO=%o BITNO=%o MOD=%o\n",
 241                GET_ITS_SEGNO (cpu.itxPair), GET_ITS_RN (cpu.itxPair),
 242                GET_ITS_WORDNO (cpu.itxPair), GET_ITS_BITNO (cpu.itxPair),
 243                GET_ITS_MOD (cpu.itxPair));
 244     // C(ITS.SEGNO) -> C(TPR.TSR)
 245     // maximum of ( C(ITS.RN), C(SDW.R1), C(TPR.TRR) ) -> C(TPR.TRR)
 246     // C(ITS.BITNO) -> C(TPR.TBR)
 247     // C(ITS.WORDNO) + C(r) -> C(TPR.CA)
 248     //
 249     // 1. r = C(CT-HOLD) if the instruction word or preceding indirect word
 250     //    specified indirect then register modification, or
 251     // 2. r = C(ITS.MOD.Td) if the instruction word or preceding indirect word
 252     //    specified register then indirect modification and ITS.MOD.Tm specifies
 253     //    either register or register then indirect modification.
 254     // 3. SDW.R1 is the upper limit of the read/write ring bracket for the
 255     //    segment C(TPR.TSR) (see Section 8).
 256 
 257     cpu.TPR.TSR = GET_ITS_SEGNO (cpu.itxPair);
 258 
 259     sim_debug (DBG_APPENDING, & cpu_dev,
 260                "ITS Pair Ring: RN %o RSDWH_R1 %o TRR %o max %o\n",
 261                GET_ITS_RN (cpu.itxPair), cpu.RSDWH_R1, cpu.TPR.TRR,
 262                max3 (GET_ITS_RN (cpu.itxPair), cpu.RSDWH_R1, cpu.TPR.TRR));
 263 
 264     cpu.TPR.TRR  = max3 (GET_ITS_RN (cpu.itxPair), cpu.RSDWH_R1, cpu.TPR.TRR);
 265     cpu.TPR.TBR  = GET_ITS_BITNO (cpu.itxPair);
 266     cpu.TPR.CA   = GET_ITS_WORDNO (cpu.itxPair);
 267     cpu.TPR.CA  &= AMASK;
 268 
 269     cpu.rY = cpu.TPR.CA;
 270 
 271     cpu.rTAG = GET_ITS_MOD (cpu.itxPair);
 272 
 273     cpu.cu.its = 1;
 274 
 275     return;
 276   }
 277 
 278 // CANFAULT
 279 static void do_ITS_ITP (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
 280   {
 281     word6 ind_tag = GET_TAG (cpu.itxPair [0]);
 282 
 283     sim_debug (DBG_APPENDING, & cpu_dev,
 284                "do_ITS/ITP: %012"PRIo64" %012"PRIo64"\n",
 285                cpu.itxPair[0], cpu.itxPair[1]);
 286 
 287     // Whenever the processor is forming a virtual address two special address
 288     // modifiers may be specified and are effective under certain restrictive
 289     // conditions. The special address modifiers are shown in Table 6-4 and
 290     // discussed in the paragraphs below.
 291     //
 292     //  The conditions for which the special address modifiers are effective
 293     //  are as follows:
 294     //
 295     // 1. The instruction word (or preceding indirect word) must specify
 296     // indirect then register or register then indirect modification.
 297     //
 298     // 2. The computed address for the indirect word must be even.
 299     //
 300     // If these conditions are satisfied, the processor examines the indirect
 301     // word TAG field for the special address modifiers.
 302     //
 303     // If either condition is violated, the indirect word TAG field is
 304     // interpreted as a normal address modifier and the presence of a special
 305     // address modifier will cause an illegal procedure, illegal modifier,
 306     // fault.
 307 
 308     if (ISITS (ind_tag))
 309         do_ITS (cpup);
 310     else
 311         do_ITP (cpup);
 312 
 313     //set_went_appending ();
 314     cpu.cu.XSF = 1;
 315     sim_debug (DBG_APPENDING, & cpu_dev, "do_ITS_ITP sets XSF to 1\n");
 316   }
 317 
 318 void updateIWB (cpu_state_t * cpup, word18 addr, word6 tag)
     /* [previous][next][first][last][top][bottom][index][help] */
 319   {
 320     word36 * wb;
 321     if (USE_IRODD)
 322       wb = & cpu.cu.IRODD;
 323     else
 324       wb = & cpu.cu.IWB;
 325     sim_debug (DBG_ADDRMOD, & cpu_dev,
 326                "updateIWB: IWB was %012"PRIo64" %06o %s\n",
 327                * wb, GET_ADDR (* wb),
 328                extMods [GET_TAG (* wb)].mod);
 329 
 330     putbits36_18 (wb,  0, addr);
 331     putbits36_6  (wb, 30, tag);
 332     putbits36_1  (wb, 29, 0);
 333 
 334     sim_debug (DBG_ADDRMOD, & cpu_dev,
 335                "updateIWB: IWB now %012"PRIo64" %06o %s\n",
 336                * wb, GET_ADDR (* wb),
 337                extMods [GET_TAG (* wb)].mod);
 338 
 339     decode_instruction (cpup, IWB_IRODD, & cpu.currentInstruction);
 340   }
 341 
 342 //
 343 // Input:
 344 //   cu.IWB
 345 //   currentInstruction
 346 //   TPR.TSR
 347 //   TPR.TRR
 348 //   TPR.TBR // XXX check to see if this is initialized
 349 //   TPR.CA
 350 //
 351 //  Output:
 352 //   TPR.CA
 353 //   directOperandFlag
 354 //
 355 // CANFAULT
 356 
 357 void do_caf (cpu_state_t * cpup)
     /* [previous][next][first][last][top][bottom][index][help] */
 358   {
 359     if (cpu.currentInstruction.b29 == 0)
 360       {
 361         cpu.TPR.CA = GET_ADDR (IWB_IRODD);
 362       }
 363     else
 364       {
 365         word3 n = GET_PRN(IWB_IRODD);  // get PRn
 366 #if defined(TESTING)
 367         HDBGRegPRR (n, "b29");
 368 #endif
 369         word15 offset = GET_OFFSET(IWB_IRODD);
 370         cpu.TPR.CA = (cpu.PAR[n].WORDNO + SIGNEXT15_18 (offset))
 371                       & MASK18;
 372       }
 373     char buf [256];
 374     sim_debug (DBG_ADDRMOD, & cpu_dev,
 375                "%s(Entry): operType:%s TPR.CA=%06o\n",
 376                 __func__, op_desc_str (cpup, buf), cpu.TPR.CA);
 377     sim_debug (DBG_ADDRMOD, & cpu_dev,
 378                "%s(Entry): CT_HOLD %o\n",
 379                 __func__, cpu.cu.CT_HOLD);
 380 
 381     DCDstruct * i = & cpu.currentInstruction;
 382 
 383     word6 Tm = 0;
 384     word6 Td = 0;
 385 
 386     /* word6 iTAG; */   // tag of word preceding an indirect fetch
 387 
 388     cpu.ou.directOperandFlag = false;
 389 
 390     if (i -> info -> flags & NO_TAG) // for instructions line STCA/STCQ
 391       cpu.rTAG = 0;
 392     else
 393       cpu.rTAG = GET_TAG (IWB_IRODD);
 394 
 395     int lockupCnt = 0;
 396 #define lockupLimit 4096 // approx. 2 ms
 397 
 398 startCA:;
 399 
 400     if (++ lockupCnt > lockupLimit)
 401       {
 402         doFault (FAULT_LUF, fst_zero, "Lockup in addrmod");
 403       }
 404 
 405     Td = GET_TD (cpu.rTAG);
 406     Tm = GET_TM (cpu.rTAG);
 407 
 408     // CT_HOLD is set to 0 on instruction setup; if it is non-zero here,
 409     // we must have faulted during an indirect word fetch. Restore
 410     // state and restart the fetch.
 411     if (cpu.cu.CT_HOLD)
 412       {
 413         sim_debug (DBG_ADDRMOD, & cpu_dev,
 414                    "%s(startCA): restart; CT_HOLD %02o\n",
 415                    __func__, cpu.cu.CT_HOLD);
 416        // Part of ISOLTS tst885 ir
 417        if (cpu.tweaks.isolts_mode &&
 418            GET_TM(cpu.cu.CT_HOLD) == TM_IT && GET_TD (cpu.cu.CT_HOLD) == IT_DIC &&
 419                 cpu.cu.pot == 1 && GET_ADDR (IWB_IRODD) == cpu.TPR.CA)
 420          {
 421            cpu.TPR.CA--;
 422            sim_warn ("%s: correct CA\n", __func__);
 423          }
 424        if (Tm == TM_IT && (Td == IT_IDC || Td == IT_DIC))
 425          {
 426            cpu.cu.pot = 1;
 427          }
 428       }
 429     else
 430       {
 431         // not CT_HOLD
 432         cpu.cu.its = 0;
 433         cpu.cu.itp = 0;
 434         cpu.cu.pot = 0;
 435       }
 436     sim_debug (DBG_ADDRMOD, & cpu_dev,
 437                "%s(startCA): TAG=%02o(%s) Tm=%o Td=%o CT_HOLD %02o\n",
 438                __func__, cpu.rTAG, get_mod_string (buf, cpu.rTAG), Tm, Td, cpu.cu.CT_HOLD);
 439 
 440     switch (Tm)
 441       {
 442         case TM_R:
 443           goto R_MOD;
 444         case TM_RI:
 445           goto RI_MOD;
 446         case TM_IT:
 447           goto IT_MOD;
 448         case TM_IR:
 449           goto IR_MOD;
 450         default:
 451           break;
 452       }
 453 
 454     sim_printf ("%s(startCA): unknown Tm??? %o\n",
 455                 __func__, GET_TM (cpu.rTAG));
 456     sim_warn ("(startCA): unknown Tmi; can't happen!\n");
 457     return;
 458 
 459     // Register modification. Fig 6-3
 460     R_MOD:;
 461       {
 462         if (Td == TD_N) // TPR.CA = address from opcode
 463           {
 464             //updateIWB (identity) // known that Td is 0.
 465             return;
 466           }
 467 
 468         word18 Cr = get_Cr (cpup, Td);
 469 
 470         sim_debug (DBG_ADDRMOD, & cpu_dev, "R_MOD: Cr=%06o\n", Cr);
 471 
 472         if (cpu.ou.directOperandFlag)
 473           {
 474             sim_debug (DBG_ADDRMOD, & cpu_dev,
 475                        "R_MOD: directOperand = %012"PRIo64"\n",
 476                        cpu.ou.directOperand);
 477             return;
 478           }
 479 
 480         // For the case of RPT/RPD, the instruction decoder has
 481         // verified that Tm is R or RI, and Td is X1..X7.
 482         if (cpu.cu.rpt || cpu.cu.rd | cpu.cu.rl)
 483           {
 484             if (cpu.currentInstruction.b29)
 485               {
 486                 word3 PRn = GET_PRN(IWB_IRODD);
 487 #if defined(TESTING)
 488                 HDBGRegPRR (PRn, "rpx b29");
 489 #endif
 490                 CPTUR (cptUsePRn + PRn);
 491                 cpu.TPR.CA = Cr + cpu.PR [PRn].WORDNO;
 492                 cpu.TPR.CA &= AMASK;
 493               }
 494             else
 495               {
 496                 cpu.TPR.CA = Cr;
 497               }
 498           }
 499         else
 500           {
 501             cpu.TPR.CA += Cr;
 502             cpu.TPR.CA &= MASK18;   // keep to 18-bits
 503           }
 504         sim_debug (DBG_ADDRMOD, & cpu_dev, "R_MOD: TPR.CA=%06o\n",
 505                    cpu.TPR.CA);
 506 
 507         return;
 508       } // R_MOD
 509 
 510     // Figure 6-4. Register Then Indirect Modification Flowchart
 511     RI_MOD:;
 512       {
 513         sim_debug (DBG_ADDRMOD, & cpu_dev, "RI_MOD: Td=%o\n", Td);
 514 
 515         if (Td == TD_DU || Td == TD_DL)
 516           doFault (FAULT_IPR, fst_ill_mod,
 517                    "RI_MOD: Td == TD_DU || Td == TD_DL");
 518 
 519         if (Td != TD_N)
 520           {
 521             word18 Cr = get_Cr (cpup, Td);  // C(r)
 522 
 523             // We don''t need to worry about direct operand here, since du
 524             // and dl are disallowed above
 525 
 526             sim_debug (DBG_ADDRMOD, & cpu_dev,
 527                        "RI_MOD: Cr=%06o CA(Before)=%06o\n", Cr, cpu.TPR.CA);
 528 
 529             if (cpu.cu.rpt || cpu.cu.rd || cpu.cu.rl)
 530               {
 531                 if (cpu.currentInstruction.b29)
 532                   {
 533                     word3 PRn = GET_PRN(IWB_IRODD);
 534 #if defined(TESTING)
 535                     HDBGRegPRR (PRn, "rpx b29");
 536 #endif
 537                     CPTUR (cptUsePRn + PRn);
 538                     cpu.TPR.CA = Cr + cpu.PR [PRn].WORDNO;
 539                   }
 540                 else
 541                   {
 542                     cpu.TPR.CA = Cr;
 543                   }
 544                 cpu.TPR.CA &= AMASK;
 545               }
 546             else
 547               {
 548                 cpu.TPR.CA += Cr;
 549                 cpu.TPR.CA &= MASK18;   // keep to 18-bits
 550               }
 551             sim_debug (DBG_ADDRMOD, & cpu_dev,
 552                        "RI_MOD: CA(After)=%06o\n", cpu.TPR.CA);
 553           }
 554 
 555         // - Multics link snap code (adjust_mc) sets rTAG to TM_RI
 556         // - After directed faults RI modifier after IR modifier end up here
 557         // - In both cases continue with indirect chain
 558         if (GET_TM(cpu.cu.CT_HOLD) == TM_IR)
 559           {
 560             goto IR_MOD_2;
 561           }
 562 
 563         // If the indirect word faults, on restart the CA will be the post
 564         // register modification value, so we want to prevent it from
 565         // happening again on restart
 566         word18 saveCA = cpu.TPR.CA;
 567         ReadIndirect (cpup);
 568 
 569         if ((saveCA & 1) == 0 && (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0])))
 570           {
 571             do_ITS_ITP (cpup);
 572             updateIWB (cpup, cpu.TPR.CA, cpu.rTAG);
 573           }
 574         else
 575           {
 576             cpu.rTAG = GET_TAG (cpu.itxPair[0]);
 577             if (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0]))
 578               {
 579                 sim_warn ("%s: itp/its at odd address\n", __func__);
 580 #if defined(TESTING)
 581                 traceInstruction (0);
 582 #endif
 583               }
 584             if (!(cpu.cu.rpt || cpu.cu.rd || cpu.cu.rl))
 585               {
 586                 updateIWB (cpup, GET_ADDR (cpu.itxPair[0]), cpu.rTAG);
 587               }
 588             // F2 and F3 fault tests after updateIW
 589             if (GET_TM (cpu.rTAG) == TM_IT)
 590               {
 591                 if (GET_TD (cpu.rTAG) == IT_F2)
 592                   {
 593                     doFault (FAULT_F2, fst_zero, "RI_MOD: IT_F2 (0)");
 594                   }
 595                 if (GET_TD (cpu.rTAG) == IT_F3)
 596                   {
 597                     doFault (FAULT_F3, fst_zero, "RI_MOD: IT_F3");
 598                   }
 599               }
 600             cpu.TPR.CA = GETHI (cpu.itxPair[0]);
 601             cpu.rY = cpu.TPR.CA;
 602           }
 603         // "In the case of RI modification, only one indirect reference is made
 604         // per repeated execution. The TAG field of the indirect word is not
 605         // interpreted.  The indirect word is treated as though it had R
 606         // modification with R = N."
 607 
 608         // Check for fault causing tags before updating the IWB, so the
 609         // instruction restart will reload the offending indirect word.
 610         sim_debug (DBG_ADDRMOD, & cpu_dev,
 611                    "RI_MOD: cpu.itxPair[0]=%012"PRIo64
 612                    " TPR.CA=%06o rTAG=%02o\n",
 613                    cpu.itxPair[0], cpu.TPR.CA, cpu.rTAG);
 614         // If repeat, the indirection chain is limited, so it is not needed
 615         // to clear the tag; the delta code later on needs the tag to know
 616         // which X register to update
 617         if (cpu.cu.rpt || cpu.cu.rd || cpu.cu.rl)
 618           return;
 619 
 620         goto startCA;
 621       } // RI_MOD
 622 
 623     // Figure 6-5. Indirect Then Register Modification Flowchart
 624     IR_MOD:;
 625       {
 626       IR_MOD_1:;
 627 
 628         sim_debug (DBG_ADDRMOD, & cpu_dev,
 629                    "IR_MOD: CT_HOLD=%o %o\n", cpu.cu.CT_HOLD, Td);
 630 
 631       IR_MOD_2:;
 632 
 633         if (++ lockupCnt > lockupLimit)
 634           {
 635             doFault (FAULT_LUF, fst_zero, "Lockup in addrmod IR mode");
 636           }
 637 
 638         sim_debug (DBG_ADDRMOD, & cpu_dev,
 639                    "IR_MOD: fetching indirect word from %06o\n",
 640                    cpu.TPR.CA);
 641 
 642         word18 saveCA = cpu.TPR.CA;
 643         ReadIndirect (cpup);
 644 
 645         // ReadIndirect does NOT update cpu.rTAG anymore
 646         if (GET_TM(cpu.rTAG) == TM_IR)
 647           cpu.cu.CT_HOLD = cpu.rTAG;
 648 
 649         if ((saveCA & 1) == 0 && (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0])))
 650           {
 651             do_ITS_ITP (cpup);
 652           }
 653         else
 654           {
 655             if (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0]))
 656               {
 657                 sim_warn ("%s: itp/its at odd address\n", __func__);
 658 #if defined(TESTING)
 659                 traceInstruction (0);
 660 #endif
 661               }
 662             cpu.TPR.CA = GETHI (cpu.itxPair[0]);
 663             cpu.rY = cpu.TPR.CA;
 664             cpu.rTAG = GET_TAG (cpu.itxPair[0]);
 665           }
 666 
 667         sim_debug (DBG_ADDRMOD, & cpu_dev,
 668                    "IR_MOD: CT_HOLD=%o\n", cpu.cu.CT_HOLD);
 669         Td = GET_TD (cpu.rTAG);
 670         Tm = GET_TM (cpu.rTAG);
 671 
 672         sim_debug (DBG_ADDRMOD, & cpu_dev,
 673                    "IR_MOD1: cpu.itxPair[0]=%012"PRIo64
 674                    " TPR.CA=%06o Tm=%o Td=%02o (%s)\n",
 675                    cpu.itxPair[0], cpu.TPR.CA, Tm, Td,
 676                    get_mod_string (buf, GET_TAG (cpu.itxPair[0])));
 677 
 678         switch (Tm)
 679           {
 680             case TM_IT:
 681               {
 682                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 683                            "IR_MOD(TM_IT): Td=%02o => %02o\n",
 684                            Td, cpu.cu.CT_HOLD);
 685 
 686                 if (Td == IT_F2 || Td == IT_F3)
 687                   {
 688                     updateIWB(cpup, cpu.TPR.CA, cpu.rTAG);
 689                     // Abort. FT2 or 3
 690                     switch (Td)
 691                       {
 692                         case IT_F2:
 693                           cpu.TPR.CA = saveCA;
 694                           doFault (FAULT_F2, fst_zero, "TM_IT: IT_F2 (1)");
 695 
 696                         /*FALLTHRU*/ /* fall through */ /* fallthrough */
 697                         case IT_F3:
 698                           cpu.TPR.CA = saveCA;
 699                           doFault (FAULT_F3, fst_zero, "TM_IT: IT_F3");
 700                       }
 701                   }
 702                 // fall through to TM_R
 703 #if !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) && !defined(__SUNPRO_CC_COMPAT)
 704                 /*FALLTHRU*/ /* fall through */ /* fallthrough */
 705 # if defined(__GNUC__) && __GNUC__ > 6
 706                 __attribute__ ((fallthrough));
 707 # endif /* if defined(__GNUC__) && __GNUC__ > 6 */
 708                 /*FALLTHRU*/ /* fall through */ /* fallthrough */
 709 # if defined(__clang__)
 710                 (void)0;
 711 # endif /* if defined(__clang__) */
 712 #endif
 713               } // TM_IT
 714 
 715             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 716             case TM_R:
 717               {
 718                 word6 Td_hold = GET_TD (cpu.cu.CT_HOLD);
 719                 cpu.rTAG = (TM_R | Td_hold);
 720                 updateIWB (cpup, cpu.TPR.CA, cpu.rTAG);
 721                 goto startCA;
 722               } // TM_R
 723 
 724             case TM_RI:
 725               {
 726                 if (Td == TD_DU || Td == TD_DL)
 727                   doFault (FAULT_IPR, fst_ill_mod,
 728                            "RI_MOD: Td == TD_DU || Td == TD_DL");
 729 
 730                 word18 Cr = get_Cr (cpup, Td);
 731 
 732                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 733                            "IR_MOD(TM_RI): Td=%o Cr=%06o TPR.CA(Before)=%06o\n",
 734                            Td, Cr, cpu.TPR.CA);
 735 
 736                 cpu.TPR.CA += Cr;
 737                 cpu.TPR.CA &= MASK18;   // keep to 18-bits
 738 
 739                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 740                                "IR_MOD(TM_RI): TPR.CA=%06o\n", cpu.TPR.CA);
 741 
 742                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 743                            "IR_MOD(TM_RI): TPR.CA(After)=%06o\n",
 744                            cpu.TPR.CA);
 745 
 746                 // Don't add register twice if next indirection faults
 747                 updateIWB (cpup, cpu.TPR.CA, (TM_RI|TD_N));
 748                 goto IR_MOD_2;
 749               } // TM_RI
 750 
 751             case TM_IR:
 752               {
 753                 updateIWB (cpup, cpu.TPR.CA, cpu.rTAG); // XXX guessing here...
 754                 goto IR_MOD_1;
 755               } // TM_IR
 756           } // TM
 757 
 758         sim_printf ("%s(IR_MOD): unknown Tm??? %o\n",
 759                     __func__, GET_TM (cpu.rTAG));
 760         return;
 761       } // IR_MOD
 762 
 763     IT_MOD:;
 764       {
 765         //    IT_SD     = 004,
 766         //    IT_SCR    = 005,
 767         //    IT_CI     = 010,
 768         //    IT_I      = 011,
 769         //    IT_SC     = 012,
 770         //    IT_AD     = 013,
 771         //    IT_DI     = 014,
 772         //    IT_DIC    = 015,
 773         //    IT_ID     = 016,
 774         //    IT_IDC    = 017
 775         word6 idwtag, delta;
 776         word24 Yi = (word24) -1;
 777 
 778         switch (Td)
 779           {
 780             // XXX this is probably wrong. ITS/ITP are not standard addr mods
 781             case SPEC_ITP:
 782             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 783             case SPEC_ITS:
 784               {
 785                 doFault(FAULT_IPR, fst_ill_mod, "ITx in IT_MOD)");
 786               }
 787 
 788             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 789             case 2:
 790               {
 791                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 792                            "IT_MOD(): illegal procedure, illegal modifier, "
 793                            "fault Td=%o\n", Td);
 794                 doFault (FAULT_IPR, fst_ill_mod,
 795                          "IT_MOD(): illegal procedure, illegal modifier, "
 796                          "fault");
 797               }
 798 
 799             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 800             case IT_F1:
 801               {
 802                 doFault(FAULT_F1, fst_zero, "IT_MOD: IT_F1");
 803               }
 804 
 805             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 806             case IT_F2:
 807               {
 808                 doFault(FAULT_F2, fst_zero, "IT_MOD: IT_F2 (2)");
 809               }
 810 
 811             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 812             case IT_F3:
 813               {
 814                 doFault(FAULT_F3, fst_zero, "IT_MOD: IT_F3");
 815               }
 816 
 817             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 818             case IT_CI:  // Character indirect (Td = 10)
 819             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 820             case IT_SC:  // Sequence character (Td = 12)
 821             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 822             case IT_SCR: // Sequence character reverse (Td = 5)
 823               {
 824                 // There is complexity with managing page faults and tracking
 825                 // the indirect word address and the operand address.
 826                 //
 827                 // To address this, we force those pages in during PREPARE_CA,
 828                 // so that they won't fault during operand read/write.
 829 
 830                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 831                            "IT_MOD CI/SC/SCR reading indirect word from %06o\n",
 832                            cpu.TPR.CA);
 833 
 834                 //
 835                 // Get the indirect word
 836                 //
 837 
 838                 word36 indword;
 839                 word18 indaddr = cpu.TPR.CA;
 840                 ReadAPUDataRead (cpup, indaddr, & indword);
 841 #if defined(LOCKLESS)
 842                 word24 phys_address = cpu.iefpFinalAddress;
 843 #endif
 844 
 845                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 846                            "IT_MOD CI/SC/SCR indword=%012"PRIo64"\n", indword);
 847 
 848                 //
 849                 // Parse and validate the indirect word
 850                 //
 851 
 852                 Yi           = GET_ADDR (indword);
 853                 word6 sz     = GET_TB (GET_TAG (indword));
 854                 word3 os     = GET_CF (GET_TAG (indword));
 855                 word12 tally = GET_TALLY (indword);
 856 
 857                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 858                            "IT_MOD CI/SC/SCR size=%o offset=%o Yi=%06o\n",
 859                            sz, os, Yi);
 860 
 861                 if (sz == TB6 && os > 5)
 862                   // generate an illegal procedure, illegal modifier fault
 863                   doFault (FAULT_IPR, fst_ill_mod,
 864                            "co size == TB6 && offset > 5");
 865 
 866                 if (sz == TB9 && os > 3)
 867                   // generate an illegal procedure, illegal modifier fault
 868                   doFault (FAULT_IPR, fst_ill_mod,
 869                            "co size == TB9 && offset > 3");
 870 
 871                 // Save data in OU registers for readOperands/writeOperands
 872 
 873                 cpu.TPR.CA                    = Yi;
 874                 cpu.ou.character_address      = Yi;
 875                 cpu.ou.characterOperandSize   = sz;
 876                 cpu.ou.characterOperandOffset = os;
 877 
 878                 // CI uses the address, and SC uses the pre-increment address;
 879                 // but SCR use the post-decrement address
 880                 if (Td == IT_SCR)
 881                   {
 882                     // For each reference to the indirect word, the character
 883                     // counter, cf, is reduced by 1 and the TALLY field is
 884                     // increased by 1 before the computed address is formed.
 885                     //
 886                     // Character count arithmetic is modulo 6 for 6-bit
 887                     // characters and modulo 4 for 9-bit bytes. If the
 888                     // character count, cf, underflows to -1, it is reset to 5
 889                     // for 6-bit characters or to 3 for 9-bit bytes and ADDRESS
 890                     // is reduced by 1. ADDRESS arithmetic is modulo 2^18.
 891                     // TALLY arithmetic is modulo 4096.
 892                     //
 893                     // If the TALLY field overflows to 0, the tally runout
 894                     // indicator is set ON, otherwise it is set OFF. The
 895                     // computed address is the (possibly) decremented value of
 896                     // the ADDRESS field of the indirect word. The effective
 897                     // character/byte number is the decremented value of the
 898                     // character position count, cf, field of the indirect
 899                     // word.
 900 
 901                     if (os == 0)
 902                       {
 903                         if (sz == TB6)
 904                             os = 5;
 905                         else
 906                             os = 3;
 907                         Yi -= 1;
 908                         Yi &= MASK18;
 909                       }
 910                     else
 911                       {
 912                         os -= 1;
 913                       }
 914 
 915                     CPT (cpt2L, 5); // Update IT Tally; SCR
 916                     tally ++;
 917                     tally &= 07777; // keep to 12-bits
 918 
 919                     // Update saved values
 920 
 921                     cpu.TPR.CA                    = Yi;
 922                     cpu.ou.character_address      = Yi;
 923                     cpu.ou.characterOperandSize   = sz;
 924                     cpu.ou.characterOperandOffset = os;
 925                   }
 926 
 927 // What if readOperands and/of writeOperands fault? On restart, doCAF will be
 928 // called again and the indirect word would incorrectly be updated a second
 929 // time.
 930 //
 931 // We don't care about read/write access violations; in general, they are not
 932 // restarted.
 933 //
 934 // We can avoid page faults by preemptively fetching the data word.
 935 
 936                 //
 937                 // Get the data word
 938                 //
 939 
 940                 cpu.cu.pot = 1;
 941 
 942 #if defined(LOCKLESSXXX)
 943                 // gives warnings as another lock is acquired in between
 944                 Read (cpu.TPR.CA, & cpu.ou.character_data, (i->info->flags & RMW) == \
 945                         STORE_OPERAND ? OPERAND_RMW : OPERAND_READ);
 946 #else
 947                 ReadOperandRead (cpup, cpu.TPR.CA, & cpu.ou.character_data);
 948 #endif
 949 #if defined(LOCKLESS)
 950                 cpu.char_word_address = cpu.iefpFinalAddress;
 951 #endif
 952 
 953                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 954                            "IT_MOD CI/SC/SCR data=%012"PRIo64"\n",
 955                            cpu.ou.character_data);
 956 
 957                 cpu.cu.pot = 0;
 958 
 959                 if (Td == IT_SC)
 960                   {
 961                     // For each reference to the indirect word, the character
 962                     // counter, cf, is increased by 1 and the TALLY field is
 963                     // reduced by 1 after the computed address is formed.
 964                     // Character count arithmetic is modulo 6 for 6-bit
 965                     // characters and modulo 4 for 9-bit bytes. If the
 966                     // character count, cf, overflows to 6 for 6-bit characters
 967                     // or to 4 for 9-bit bytes, it is reset to 0 and ADDRESS is
 968                     // increased by 1. ADDRESS arithmetic is modulo 2^18. TALLY
 969                     // arithmetic is modulo 4096. If the TALLY field is reduced
 970                     // to 0, the tally runout indicator is set ON, otherwise it
 971                     // is set OFF.
 972 
 973                     os ++;
 974 
 975                     if (((sz == TB6) && (os > 5)) ||
 976                         ((sz == TB9) && (os > 3)))
 977                       {
 978                         os = 0;
 979                         Yi += 1;
 980                         Yi &= MASK18;
 981                       }
 982                     CPT (cpt2L, 6); // Update IT Tally; SC
 983                     tally --;
 984                     tally &= 07777; // keep to 12-bits
 985                   }
 986 
 987                 if (Td == IT_SC || Td == IT_SCR)
 988                   {
 989                     sim_debug (DBG_ADDRMOD, & cpu_dev,
 990                                    "update IT tally now %o\n", tally);
 991 
 992                     //word36 new_indword = (word36) (((word36) Yi << 18) |
 993                     //                    (((word36) tally & 07777) << 6) |
 994                     //                    cpu.ou.characterOperandSize |
 995                     //                    cpu.ou.characterOperandOffset);
 996                     //Write (cpu.TPR.CA,  new_indword, APU_DATA_STORE);
 997 #if defined(LOCKLESS)
 998                     word36 indword_new;
 999                     core_read_lock(cpup, phys_address, &indword_new, __func__);
1000                     if (indword_new != indword)
1001                       sim_warn("indword changed from %llo to %llo\n",
1002                                (long long unsigned int)indword,
1003                                (long long unsigned int)indword_new);
1004 #endif
1005                     putbits36_18 (& indword,  0, Yi);
1006                     putbits36_12 (& indword, 18, tally);
1007                     putbits36_3  (& indword, 33, os);
1008 #if defined(LOCKLESS)
1009                     core_write_unlock(cpup, phys_address, indword, __func__);
1010 #else
1011                     WriteAPUDataStore (cpup, indaddr, indword);
1012 #endif
1013 
1014                     SC_I_TALLY (tally == 0);
1015 
1016                     sim_debug (DBG_ADDRMOD, & cpu_dev,
1017                                "update IT wrote tally word %012"PRIo64
1018                                " to %06o\n",
1019                                indword, cpu.TPR.CA);
1020                   }
1021 
1022                 // readOperand and writeOperand will not use cpu.TPR.CA; they
1023                 // will use the saved address, size, offset and data.
1024                 cpu.TPR.CA = cpu.ou.character_address;
1025                 return;
1026               } // IT_CI, IT_SC, IT_SCR
1027 
1028             case IT_I: // Indirect (Td = 11)
1029               {
1030                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1031                            "IT_MOD(IT_I): reading indirect word from %06o\n",
1032                            cpu.TPR.CA);
1033 
1034                 //Read2 (cpu.TPR.CA, cpu.itxPair, INDIRECT_WORD_FETCH);
1035                 ReadIndirect (cpup);
1036 
1037                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1038                            "IT_MOD(IT_I): indword=%012"PRIo64"\n",
1039                            cpu.itxPair[0]);
1040 
1041                 cpu.TPR.CA = GET_ADDR (cpu.itxPair[0]);
1042                 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1043                 return;
1044               } // IT_I
1045 
1046             case IT_AD: ///< Add delta (Td = 13)
1047               {
1048                 // The TAG field of the indirect word is interpreted as a
1049                 // 6-bit, unsigned, positive address increment value, delta.
1050                 // For each reference to the indirect word, the ADDRESS field
1051                 // is increased by delta and the TALLY field is reduced by 1
1052                 // after the computed address is formed. ADDRESS arithmetic is
1053                 // modulo 2^18. TALLY arithmetic is modulo 4096. If the TALLY
1054                 // field is reduced to 0, the tally runout indicator is set ON,
1055                 // otherwise it is set OFF. The computed address is the value
1056                 // of the unmodified ADDRESS field of the indirect word.
1057 
1058                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1059                            "IT_MOD(IT_AD): reading indirect word from %06o\n",
1060                            cpu.TPR.CA);
1061 
1062 #if defined(THREADZ)
1063                 lock_rmw ();
1064 #endif
1065 
1066                 word18 saveCA = cpu.TPR.CA;
1067                 word36 indword;
1068                 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1069 
1070                 cpu.AM_tally  = GET_TALLY (indword); // 12-bits
1071                 delta         = GET_DELTA (indword); // 6-bits
1072                 Yi            = GETHI (indword);        // from where data live
1073 
1074                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1075                            "IT_MOD(IT_AD): indword=%012"PRIo64"\n",
1076                            indword);
1077                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1078                            "IT_MOD(IT_AD): address:%06o tally:%04o "
1079                            "delta:%03o\n",
1080                            Yi, cpu.AM_tally, delta);
1081 
1082                 cpu.TPR.CA = Yi;
1083                 word18 computedAddress = cpu.TPR.CA;
1084 
1085                 Yi += delta;
1086                 Yi &= MASK18;
1087 
1088                 cpu.AM_tally -= 1;
1089                 cpu.AM_tally &= 07777; // keep to 12-bits
1090                 // breaks emacs
1091                 //if (cpu.AM_tally == 0)
1092                   //SET_I_TALLY;
1093                 SC_I_TALLY (cpu.AM_tally == 0);
1094                 indword = (word36) (((word36) Yi << 18) |
1095                                     (((word36) cpu.AM_tally & 07777) << 6) |
1096                                     delta);
1097 #if defined(LOCKLESS)
1098                 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1099 #else
1100                 WriteAPUDataStore (cpup, saveCA, indword);
1101 #endif
1102 
1103 #if defined(THREADZ)
1104                 unlock_rmw ();
1105 #endif
1106 
1107                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1108                            "IT_MOD(IT_AD): wrote tally word %012"PRIo64
1109                            " to %06o\n",
1110                            indword, saveCA);
1111 
1112                 cpu.TPR.CA = computedAddress;
1113                 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1114                 return;
1115               } // IT_AD
1116 
1117             case IT_SD: ///< Subtract delta (Td = 4)
1118               {
1119                 // The TAG field of the indirect word is interpreted as a
1120                 // 6-bit, unsigned, positive address increment value, delta.
1121                 // For each reference to the indirect word, the ADDRESS field
1122                 // is reduced by delta and the TALLY field is increased by 1
1123                 // before the computed address is formed. ADDRESS arithmetic is
1124                 // modulo 2^18. TALLY arithmetic is modulo 4096. If the TALLY
1125                 // field overflows to 0, the tally runout indicator is set ON,
1126                 // otherwise it is set OFF. The computed address is the value
1127                 // of the decremented ADDRESS field of the indirect word.
1128 
1129 #if defined(THREADZ)
1130                 lock_rmw ();
1131 #endif
1132 
1133                 word18 saveCA = cpu.TPR.CA;
1134                 word36 indword;
1135                 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1136 
1137                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1138                            "IT_MOD(IT_SD): reading indirect word from %06o\n",
1139                            cpu.TPR.CA);
1140                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1141                 delta = GET_DELTA (indword); // 6-bits
1142                 Yi    = GETHI (indword);     // from where data live
1143 
1144                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1145                            "IT_MOD(IT_SD): indword=%012"PRIo64"\n",
1146                            indword);
1147                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1148                            "IT_MOD(IT_SD): address:%06o tally:%04o "
1149                            "delta:%03o\n",
1150                            Yi, cpu.AM_tally, delta);
1151 
1152                 Yi -= delta;
1153                 Yi &= MASK18;
1154                 cpu.TPR.CA = Yi;
1155 
1156                 cpu.AM_tally += 1;
1157                 cpu.AM_tally &= 07777; // keep to 12-bits
1158                 if (cpu.AM_tally == 0)
1159                   SET_I_TALLY;
1160 
1161                 // write back out indword
1162                 indword = (word36) (((word36) Yi << 18) |
1163                                     (((word36) cpu.AM_tally & 07777) << 6) |
1164                                     delta);
1165 #if defined(LOCKLESS)
1166                 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1167 #else
1168                 WriteAPUDataStore (cpup, saveCA, indword);
1169 #endif
1170 
1171 #if defined(THREADZ)
1172                 unlock_rmw ();
1173 #endif
1174 
1175                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1176                            "IT_MOD(IT_SD): wrote tally word %012"PRIo64
1177                            " to %06o\n",
1178                            indword, saveCA);
1179 
1180                 cpu.TPR.CA = Yi;
1181                 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1182                 return;
1183               } // IT_SD
1184 
1185             case IT_DI: ///< Decrement address, increment tally (Td = 14)
1186               {
1187                 // For each reference to the indirect word, the ADDRESS field
1188                 // is reduced by 1 and the TALLY field is increased by 1 before
1189                 // the computed address is formed. ADDRESS arithmetic is modulo
1190                 // 2^18. TALLY arithmetic is modulo 4096. If the TALLY field
1191                 // overflows to 0, the tally runout indicator is set ON,
1192                 // otherwise it is set OFF. The TAG field of the indirect word
1193                 // is ignored. The computed address is the value of the
1194                 // decremented ADDRESS field.
1195 
1196                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1197                            "IT_MOD(IT_DI): reading indirect word from %06o\n",
1198                            cpu.TPR.CA);
1199 
1200 #if defined(THREADZ)
1201                 lock_rmw ();
1202 #endif
1203 
1204                 word18 saveCA = cpu.TPR.CA;
1205                 word36 indword;
1206                 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1207 
1208                 Yi           = GETHI (indword);
1209                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1210                 word6 junk   = GET_TAG (indword);   // get tag field, but ignore it
1211 
1212                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1213                            "IT_MOD(IT_DI): indword=%012"PRIo64"\n",
1214                            indword);
1215                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1216                            "IT_MOD(IT_DI): address:%06o tally:%04o\n",
1217                            Yi, cpu.AM_tally);
1218 
1219                 Yi -= 1;
1220                 Yi &= MASK18;
1221                 cpu.TPR.CA = Yi;
1222 
1223                 cpu.AM_tally += 1;
1224                 cpu.AM_tally &= 07777; // keep to 12-bits
1225                 SC_I_TALLY (cpu.AM_tally == 0);
1226 
1227                 // write back out indword
1228 
1229                 indword = (word36) (((word36) cpu.TPR.CA << 18) |
1230                                     ((word36) cpu.AM_tally << 6) |
1231                                     junk);
1232 
1233                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1234                            "IT_MOD(IT_DI): writing indword=%012"PRIo64" to "
1235                            "addr %06o\n",
1236                            indword, saveCA);
1237 
1238 #if defined(LOCKLESS)
1239                 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1240 #else
1241                 WriteAPUDataStore (cpup, saveCA, indword);
1242 #endif
1243 
1244 #if defined(THREADZ)
1245                 unlock_rmw ();
1246 #endif
1247                 cpu.TPR.CA = Yi;
1248                 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1249                 return;
1250               } // IT_DI
1251 
1252             case IT_ID: ///< Increment address, decrement tally (Td = 16)
1253               {
1254                 // For each reference to the indirect word, the ADDRESS field
1255                 // is increased by 1 and the TALLY field is reduced by 1 after
1256                 // the computed address is formed. ADDRESS arithmetic is modulo
1257                 // 2^18. TALLY arithmetic is modulo 4096. If the TALLY field is
1258                 // reduced to 0, the tally runout indicator is set ON,
1259                 // otherwise it is set OFF. The TAG field of the indirect word
1260                 // is ignored. The computed address is the value of the
1261                 // unmodified ADDRESS field.
1262 
1263                 word18 saveCA = cpu.TPR.CA;
1264 
1265                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1266                            "IT_MOD(IT_ID): fetching indirect word from %06o\n",
1267                            cpu.TPR.CA);
1268 
1269 #if defined(THREADZ)
1270                 lock_rmw ();
1271 #endif
1272 
1273                 word36 indword;
1274                 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1275 
1276                 Yi = GETHI (indword);
1277                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1278                 // get tag field, but ignore it
1279                 word6 junk = GET_TAG (indword);
1280                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1281                            "IT_MOD(IT_ID): indword=%012"PRIo64
1282                            " Yi=%06o tally=%04o\n",
1283                            indword, Yi, cpu.AM_tally);
1284 
1285                 cpu.TPR.CA = Yi;
1286                 word18 computedAddress = cpu.TPR.CA;
1287 
1288                 Yi += 1;
1289                 Yi &= MASK18;
1290 
1291                 cpu.AM_tally -= 1;
1292                 cpu.AM_tally &= 07777; // keep to 12-bits
1293 
1294                 // XXX Breaks boot?
1295                 //if (cpu.AM_tally == 0)
1296                   //SET_I_TALLY;
1297                 SC_I_TALLY (cpu.AM_tally == 0);
1298 
1299                 // write back out indword
1300                 indword = (word36) (((word36) Yi << 18) |
1301                                     ((word36) cpu.AM_tally << 6) |
1302                                     junk);
1303 
1304                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1305                            "IT_MOD(IT_ID): writing indword=%012"PRIo64" to "
1306                            "addr %06o\n",
1307                            indword, saveCA);
1308 
1309 #if defined(LOCKLESS)
1310                 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1311 #else
1312                 WriteAPUDataStore (cpup, saveCA, indword);
1313 #endif
1314 
1315 #if defined(THREADZ)
1316                 unlock_rmw ();
1317 #endif
1318 
1319                 cpu.TPR.CA = computedAddress;
1320                 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1321                 return;
1322               } // IT_ID
1323 
1324             // Decrement address, increment tally, and continue (Td = 15)
1325             case IT_DIC:
1326               {
1327                 // The action for this variation is identical to that for the
1328                 // decrement address, increment tally variation except that the
1329                 // TAG field of the indirect word is interpreted and
1330                 // continuation of the indirect chain is possible. If the TAG
1331                 // of the indirect word invokes a register, that is, specifies
1332                 // r, ri, or ir modification, the effective Td value for the
1333                 // register is forced to "null" before the next computed
1334                 // address is formed.
1335 
1336                 // a:RJ78/idc1
1337                 // The address and tally fields are used as described under the
1338                 // ID variation. The tag field uses the set of variations for
1339                 // instruction address modification under the following
1340                 // restrictions: no variation is permitted that requires an
1341                 // indexing modification in the DIC cycle since the indexing
1342                 // adder is being used by the tally phase of the operation.
1343                 // Thus, permissible variations are any allowable form of IT or
1344                 // IR, but if RI or R is used, R must equal N (RI and R forced
1345                 // to N).
1346 
1347                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1348                            "IT_MOD(IT_DIC): fetching indirect word from %06o\n",
1349                            cpu.TPR.CA);
1350 
1351 #if defined(THREADZ)
1352                 lock_rmw ();
1353 #endif
1354 
1355                 word18 saveCA = cpu.TPR.CA;
1356                 word36 indword;
1357                 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1358 
1359                 cpu.cu.pot = 0;
1360 
1361                 Yi = GETHI (indword);
1362                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1363                 idwtag = GET_TAG (indword);
1364 
1365                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1366                            "IT_MOD(IT_DIC): indword=%012"PRIo64" Yi=%06o "
1367                            "tally=%04o idwtag=%02o\n",
1368                            indword, Yi, cpu.AM_tally, idwtag);
1369 
1370                 word24 YiSafe2 = Yi; // save indirect address for later use
1371 
1372                 Yi -= 1;
1373                 Yi &= MASK18;
1374 
1375                 cpu.AM_tally += 1;
1376                 cpu.AM_tally &= 07777; // keep to 12-bits
1377 // Set the tally after the indirect word is processed; if it faults, the IR
1378 // should be unchanged. ISOLTS ps791 test-02g
1379                 //SC_I_TALLY (cpu.AM_tally == 0);
1380                 //if (cpu.AM_tally == 0)
1381                   //SET_I_TALLY;
1382 
1383                 // write back out indword
1384                 indword = (word36) (((word36) Yi << 18) |
1385                           ((word36) cpu.AM_tally << 6) | idwtag);
1386 
1387                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1388                            "IT_MOD(IT_DIC): writing indword=%012"PRIo64" to "
1389                            "addr %06o\n", indword, saveCA);
1390 
1391 #if defined(LOCKLESS)
1392                 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1393 #else
1394                 WriteAPUDataStore (cpup, saveCA, indword);
1395 #endif
1396 
1397 #if defined(THREADZ)
1398                 unlock_rmw ();
1399 #endif
1400                 // If the TAG of the indirect word invokes a register, that is,
1401                 // specifies r, ri, or ir modification, the effective Td value
1402                 // for the register is forced to "null" before the next
1403                 // computed address is formed.
1404 
1405                 // Thus, permissible variations are any allowable form of IT or
1406                 // IR, but if RI or R is used, R must equal N (RI and R forced
1407                 // to N).
1408                 cpu.TPR.CA = Yi;
1409 
1410                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1411                            "IT_MOD(IT_DIC): new CT_HOLD %02o new TAG %02o\n",
1412                            cpu.rTAG, idwtag);
1413                 cpu.cu.CT_HOLD = cpu.rTAG;
1414                 cpu.rTAG = idwtag;
1415 
1416                 Tm = GET_TM (cpu.rTAG);
1417                 if (Tm == TM_RI || Tm == TM_R)
1418                   {
1419                      if (GET_TD (cpu.rTAG) != 0)
1420                        {
1421                          doFault (FAULT_IPR, fst_ill_mod,
1422                                   "DIC Incorrect address modifier");
1423                        }
1424                   }
1425 
1426 // Set the tally after the indirect word is processed; if it faults, the IR
1427 // should be unchanged. ISOLTS ps791 test-02g
1428                 SC_I_TALLY (cpu.AM_tally == 0);
1429                 if (cpu.tweaks.isolts_mode)
1430                   updateIWB (cpup, YiSafe2, cpu.rTAG);
1431                 else
1432                   updateIWB (cpup, cpu.TPR.CA, cpu.rTAG);
1433                 goto startCA;
1434               } // IT_DIC
1435 
1436             // Increment address, decrement tally, and continue (Td = 17)
1437             case IT_IDC:
1438               {
1439                 // The action for this variation is identical to that for the
1440                 // increment address, decrement tally variation except that the
1441                 // TAG field of the indirect word is interpreted and
1442                 // continuation of the indirect chain is possible. If the TAG
1443                 // of the indirect word invokes a register, that is, specifies
1444                 // r, ri, or ir modification, the effective Td value for the
1445                 // register is forced to "null" before the next computed
1446                 // address is formed.
1447 
1448                 // a:RJ78/idc1
1449                 // The address and tally fields are used as described under the
1450                 // ID variation. The tag field uses the set of variations for
1451                 // instruction address modification under the following
1452                 // restrictions: no variation is permitted that requires an
1453                 // indexing modification in the IDC cycle since the indexing
1454                 // adder is being used by the tally phase of the operation.
1455                 // Thus, permissible variations are any allowable form of IT or
1456                 // IR, but if RI or R is used, R must equal N (RI and R forced
1457                 // to N).
1458 
1459                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1460                            "IT_MOD(IT_IDC): fetching indirect word from %06o\n",
1461                            cpu.TPR.CA);
1462 
1463 #if defined(THREADZ)
1464                 lock_rmw ();
1465 #endif
1466 
1467                 word18 saveCA = cpu.TPR.CA;
1468                 word36 indword;
1469                 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1470 
1471                 cpu.cu.pot = 0;
1472 
1473                 Yi           = GETHI (indword);
1474                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1475                 idwtag       = GET_TAG (indword);
1476 
1477                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1478                            "IT_MOD(IT_IDC): indword=%012"PRIo64" Yi=%06o "
1479                            "tally=%04o idwtag=%02o\n",
1480                            indword, Yi, cpu.AM_tally, idwtag);
1481 
1482                 word24 YiSafe = Yi; // save indirect address for later use
1483 
1484                 Yi += 1;
1485                 Yi &= MASK18;
1486 
1487                 cpu.AM_tally -= 1;
1488                 cpu.AM_tally &= 07777; // keep to 12-bits
1489 // Set the tally after the indirect word is processed; if it faults, the IR
1490 // should be unchanged. ISOLTS ps791 test-02f
1491                 //SC_I_TALLY (cpu.AM_tally == 0);
1492 
1493                 // write back out indword
1494                 indword = (word36) (((word36) Yi << 18) |
1495                                     ((word36) cpu.AM_tally << 6) |
1496                                     idwtag);
1497 
1498                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1499                            "IT_MOD(IT_IDC): writing indword=%012"PRIo64""
1500                            " to addr %06o\n",
1501                            indword, saveCA);
1502 
1503 #if defined(LOCKLESS)
1504                 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1505 #else
1506                 WriteAPUDataStore (cpup, saveCA, indword);
1507 #endif
1508 
1509 #if defined(THREADZ)
1510                 unlock_rmw ();
1511 #endif
1512 
1513                 // If the TAG of the indirect word invokes a register, that is,
1514                 // specifies r, ri, or ir modification, the effective Td value
1515                 // for the register is forced to "null" before the next
1516                 // computed address is formed.
1517                 // But for the dps88 you can use everything but ir/ri.
1518 
1519                 // Thus, permissible variations are any allowable form of IT or
1520                 // IR, but if RI or R is used, R must equal N (RI and R forced
1521                 // to N).
1522                 cpu.TPR.CA = YiSafe;
1523 
1524                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1525                            "IT_MOD(IT_IDC): new CT_HOLD %02o new TAG %02o\n",
1526                            cpu.rTAG, idwtag);
1527                 cpu.cu.CT_HOLD = cpu.rTAG;
1528                 cpu.rTAG = idwtag;
1529 
1530                 Tm = GET_TM (cpu.rTAG);
1531                 if (Tm == TM_RI || Tm == TM_R)
1532                   {
1533                      if (GET_TD (cpu.rTAG) != 0)
1534                        {
1535                          doFault (FAULT_IPR, fst_ill_mod,
1536                                   "IDC Incorrect address modifier");
1537                        }
1538                   }
1539 
1540 // Set the tally after the indirect word is processed; if it faults, the IR
1541 // should be unchanged. ISOLTS ps791 test-02f
1542                 SC_I_TALLY (cpu.AM_tally == 0);
1543                 updateIWB (cpup, cpu.TPR.CA, cpu.rTAG);
1544 
1545                 goto startCA;
1546               } // IT_IDC
1547           } // Td
1548         sim_printf ("IT_MOD/Td how did we get here?\n");
1549         return;
1550      } // IT_MOD
1551   } // do_caf

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