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

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