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-2023 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         // Check for fault causing tags before updating the IWB, so the
 612         // instruction restart will reload the offending indirect word.
 613         sim_debug (DBG_ADDRMOD, & cpu_dev,
 614                    "RI_MOD: cpu.itxPair[0]=%012"PRIo64
 615                    " TPR.CA=%06o rTAG=%02o\n",
 616                    cpu.itxPair[0], cpu.TPR.CA, cpu.rTAG);
 617         // If repeat, the indirection chain is limited, so it is not needed
 618         // to clear the tag; the delta code later on needs the tag to know
 619         // which X register to update
 620         if (cpu.cu.rpt || cpu.cu.rd || cpu.cu.rl)
 621           return;
 622 
 623         goto startCA;
 624       } // RI_MOD
 625 
 626     // Figure 6-5. Indirect Then Register Modification Flowchart
 627     IR_MOD:;
 628       {
 629       IR_MOD_1:;
 630 
 631         sim_debug (DBG_ADDRMOD, & cpu_dev,
 632                    "IR_MOD: CT_HOLD=%o %o\n", cpu.cu.CT_HOLD, Td);
 633 
 634       IR_MOD_2:;
 635 
 636         if (++ lockupCnt > lockupLimit)
 637           {
 638             doFault (FAULT_LUF, fst_zero, "Lockup in addrmod IR mode");
 639           }
 640 
 641         sim_debug (DBG_ADDRMOD, & cpu_dev,
 642                    "IR_MOD: fetching indirect word from %06o\n",
 643                    cpu.TPR.CA);
 644 
 645         word18 saveCA = cpu.TPR.CA;
 646         ReadIndirect ();
 647 
 648         // ReadIndirect does NOT update cpu.rTAG anymore
 649         if (GET_TM(cpu.rTAG) == TM_IR)
 650           cpu.cu.CT_HOLD = cpu.rTAG;
 651 
 652         if ((saveCA & 1) == 0 && (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0])))
 653           {
 654             do_ITS_ITP ();
 655           }
 656         else
 657           {
 658             if (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0]))
 659               {
 660                 sim_warn ("%s: itp/its at odd address\n", __func__);
 661 #ifdef TESTING
 662                 traceInstruction (0);
 663 #endif
 664               }
 665             cpu.TPR.CA = GETHI (cpu.itxPair[0]);
 666             cpu.rY = cpu.TPR.CA;
 667             cpu.rTAG = GET_TAG (cpu.itxPair[0]);
 668           }
 669 
 670         sim_debug (DBG_ADDRMOD, & cpu_dev,
 671                    "IR_MOD: CT_HOLD=%o\n", cpu.cu.CT_HOLD);
 672         Td = GET_TD (cpu.rTAG);
 673         Tm = GET_TM (cpu.rTAG);
 674 
 675         sim_debug (DBG_ADDRMOD, & cpu_dev,
 676                    "IR_MOD1: cpu.itxPair[0]=%012"PRIo64
 677                    " TPR.CA=%06o Tm=%o Td=%02o (%s)\n",
 678                    cpu.itxPair[0], cpu.TPR.CA, Tm, Td,
 679                    get_mod_string (buf, GET_TAG (cpu.itxPair[0])));
 680 
 681         switch (Tm)
 682           {
 683             case TM_IT:
 684               {
 685                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 686                            "IR_MOD(TM_IT): Td=%02o => %02o\n",
 687                            Td, cpu.cu.CT_HOLD);
 688 
 689                 if (Td == IT_F2 || Td == IT_F3)
 690                   {
 691                     updateIWB(cpu.TPR.CA, cpu.rTAG);
 692                     // Abort. FT2 or 3
 693                     switch (Td)
 694                       {
 695                         case IT_F2:
 696                           cpu.TPR.CA = saveCA;
 697                           doFault (FAULT_F2, fst_zero, "TM_IT: IT_F2 (1)");
 698 
 699                         /*FALLTHRU*/
 700                         case IT_F3:
 701                           cpu.TPR.CA = saveCA;
 702                           doFault (FAULT_F3, fst_zero, "TM_IT: IT_F3");
 703                       }
 704                   }
 705                 // fall through to TM_R
 706 #ifndef __SUNPRO_C
 707 # ifndef __SUNPRO_CC
 708 #  ifndef __SUNPRO_CC_COMPAT
 709                 /*FALLTHRU*/
 710                 /* fall through */
 711 #   if defined(__GNUC__) && __GNUC__ > 6
 712                 __attribute__ ((fallthrough));
 713 #   endif
 714                 /*FALLTHRU*/
 715 #   ifdef __clang__
 716                 (void)0;
 717 #   endif
 718 #  endif
 719 # endif
 720 #endif
 721               } // TM_IT
 722 
 723             /*FALLTHRU*/ /* fall through */ /* fallthrough */
 724             case TM_R:
 725               {
 726                 word6 Td_hold = GET_TD (cpu.cu.CT_HOLD);
 727                 cpu.rTAG = (TM_R | Td_hold);
 728                 updateIWB (cpu.TPR.CA, cpu.rTAG);
 729                 goto startCA;
 730               } // TM_R
 731 
 732             case TM_RI:
 733               {
 734                 if (Td == TD_DU || Td == TD_DL)
 735                   doFault (FAULT_IPR, fst_ill_mod,
 736                            "RI_MOD: Td == TD_DU || Td == TD_DL");
 737 
 738                 word18 Cr = get_Cr (Td);
 739 
 740                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 741                            "IR_MOD(TM_RI): Td=%o Cr=%06o TPR.CA(Before)=%06o\n",
 742                            Td, Cr, cpu.TPR.CA);
 743 
 744                 cpu.TPR.CA += Cr;
 745                 cpu.TPR.CA &= MASK18;   // keep to 18-bits
 746 
 747                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 748                                "IR_MOD(TM_RI): TPR.CA=%06o\n", cpu.TPR.CA);
 749 
 750                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 751                            "IR_MOD(TM_RI): TPR.CA(After)=%06o\n",
 752                            cpu.TPR.CA);
 753 
 754                 // Don't add register twice if next indirection faults
 755                 updateIWB (cpu.TPR.CA, (TM_RI|TD_N));
 756                 goto IR_MOD_2;
 757               } // TM_RI
 758 
 759             case TM_IR:
 760               {
 761                 updateIWB (cpu.TPR.CA, cpu.rTAG); // XXX guessing here...
 762                 goto IR_MOD_1;
 763               } // TM_IR
 764           } // TM
 765 
 766         sim_printf ("%s(IR_MOD): unknown Tm??? %o\n",
 767                     __func__, GET_TM (cpu.rTAG));
 768         return;
 769       } // IR_MOD
 770 
 771     IT_MOD:;
 772       {
 773         //    IT_SD     = 004,
 774         //    IT_SCR    = 005,
 775         //    IT_CI     = 010,
 776         //    IT_I      = 011,
 777         //    IT_SC     = 012,
 778         //    IT_AD     = 013,
 779         //    IT_DI     = 014,
 780         //    IT_DIC    = 015,
 781         //    IT_ID     = 016,
 782         //    IT_IDC    = 017
 783         word6 idwtag, delta;
 784         word24 Yi = (word24) -1;
 785 
 786         switch (Td)
 787           {
 788             // XXX this is probably wrong. ITS/ITP are not standard addr mods
 789             case SPEC_ITP:
 790             /*FALLTHRU*/
 791             case SPEC_ITS:
 792               {
 793                 doFault(FAULT_IPR, fst_ill_mod, "ITx in IT_MOD)");
 794               }
 795 
 796             /*FALLTHRU*/
 797             case 2:
 798               {
 799                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 800                            "IT_MOD(): illegal procedure, illegal modifier, "
 801                            "fault Td=%o\n", Td);
 802                 doFault (FAULT_IPR, fst_ill_mod,
 803                          "IT_MOD(): illegal procedure, illegal modifier, "
 804                          "fault");
 805               }
 806 
 807             /*FALLTHRU*/
 808             case IT_F1:
 809               {
 810                 doFault(FAULT_F1, fst_zero, "IT_MOD: IT_F1");
 811               }
 812 
 813             /*FALLTHRU*/
 814             case IT_F2:
 815               {
 816                 doFault(FAULT_F2, fst_zero, "IT_MOD: IT_F2 (2)");
 817               }
 818 
 819             /*FALLTHRU*/
 820             case IT_F3:
 821               {
 822                 doFault(FAULT_F3, fst_zero, "IT_MOD: IT_F3");
 823               }
 824 
 825             /*FALLTHRU*/
 826             case IT_CI:  // Character indirect (Td = 10)
 827             /*FALLTHRU*/
 828             case IT_SC:  // Sequence character (Td = 12)
 829             /*FALLTHRU*/
 830             case IT_SCR: // Sequence character reverse (Td = 5)
 831               {
 832                 // There is complexity with managing page faults and tracking
 833                 // the indirect word address and the operand address.
 834                 //
 835                 // To address this, we force those pages in during PREPARE_CA,
 836                 // so that they won't fault during operand read/write.
 837 
 838                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 839                            "IT_MOD CI/SC/SCR reading indirect word from %06o\n",
 840                            cpu.TPR.CA);
 841 
 842                 //
 843                 // Get the indirect word
 844                 //
 845 
 846                 word36 indword;
 847                 word18 indaddr = cpu.TPR.CA;
 848                 ReadAPUDataRead (indaddr, & indword);
 849 #ifdef LOCKLESS
 850                 word24 phys_address = cpu.iefpFinalAddress;
 851 #endif
 852 
 853                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 854                            "IT_MOD CI/SC/SCR indword=%012"PRIo64"\n", indword);
 855 
 856                 //
 857                 // Parse and validate the indirect word
 858                 //
 859 
 860                 Yi           = GET_ADDR (indword);
 861                 word6 sz     = GET_TB (GET_TAG (indword));
 862                 word3 os     = GET_CF (GET_TAG (indword));
 863                 word12 tally = GET_TALLY (indword);
 864 
 865                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 866                            "IT_MOD CI/SC/SCR size=%o offset=%o Yi=%06o\n",
 867                            sz, os, Yi);
 868 
 869                 if (sz == TB6 && os > 5)
 870                   // generate an illegal procedure, illegal modifier fault
 871                   doFault (FAULT_IPR, fst_ill_mod,
 872                            "co size == TB6 && offset > 5");
 873 
 874                 if (sz == TB9 && os > 3)
 875                   // generate an illegal procedure, illegal modifier fault
 876                   doFault (FAULT_IPR, fst_ill_mod,
 877                            "co size == TB9 && offset > 3");
 878 
 879                 // Save data in OU registers for readOperands/writeOperands
 880 
 881                 cpu.TPR.CA                    = Yi;
 882                 cpu.ou.character_address      = Yi;
 883                 cpu.ou.characterOperandSize   = sz;
 884                 cpu.ou.characterOperandOffset = os;
 885 
 886                 // CI uses the address, and SC uses the pre-increment address;
 887                 // but SCR use the post-decrement address
 888                 if (Td == IT_SCR)
 889                   {
 890                     // For each reference to the indirect word, the character
 891                     // counter, cf, is reduced by 1 and the TALLY field is
 892                     // increased by 1 before the computed address is formed.
 893                     //
 894                     // Character count arithmetic is modulo 6 for 6-bit
 895                     // characters and modulo 4 for 9-bit bytes. If the
 896                     // character count, cf, underflows to -1, it is reset to 5
 897                     // for 6-bit characters or to 3 for 9-bit bytes and ADDRESS
 898                     // is reduced by 1. ADDRESS arithmetic is modulo 2^18.
 899                     // TALLY arithmetic is modulo 4096.
 900                     //
 901                     // If the TALLY field overflows to 0, the tally runout
 902                     // indicator is set ON, otherwise it is set OFF. The
 903                     // computed address is the (possibly) decremented value of
 904                     // the ADDRESS field of the indirect word. The effective
 905                     // character/byte number is the decremented value of the
 906                     // character position count, cf, field of the indirect
 907                     // word.
 908 
 909                     if (os == 0)
 910                       {
 911                         if (sz == TB6)
 912                             os = 5;
 913                         else
 914                             os = 3;
 915                         Yi -= 1;
 916                         Yi &= MASK18;
 917                       }
 918                     else
 919                       {
 920                         os -= 1;
 921                       }
 922 
 923                     CPT (cpt2L, 5); // Update IT Tally; SCR
 924                     tally ++;
 925                     tally &= 07777; // keep to 12-bits
 926 
 927                     // Update saved values
 928 
 929                     cpu.TPR.CA                    = Yi;
 930                     cpu.ou.character_address      = Yi;
 931                     cpu.ou.characterOperandSize   = sz;
 932                     cpu.ou.characterOperandOffset = os;
 933                   }
 934 
 935 // What if readOperands and/of writeOperands fault? On restart, doCAF will be
 936 // called again and the indirect word would incorrectly be updated a second
 937 // time.
 938 //
 939 // We don't care about read/write access violations; in general, they are not
 940 // restarted.
 941 //
 942 // We can avoid page faults by preemptively fetching the data word.
 943 
 944                 //
 945                 // Get the data word
 946                 //
 947 
 948                 cpu.cu.pot = 1;
 949 
 950 #ifdef LOCKLESSXXX
 951                 // gives warnings as another lock is acquired in between
 952                 Read (cpu.TPR.CA, & cpu.ou.character_data, (i->info->flags & RMW) == \
 953                         STORE_OPERAND ? OPERAND_RMW : OPERAND_READ);
 954 #else
 955                 ReadOperandRead (cpu.TPR.CA, & cpu.ou.character_data);
 956 #endif
 957 #ifdef LOCKLESS
 958                 cpu.char_word_address = cpu.iefpFinalAddress;
 959 #endif
 960 
 961                 sim_debug (DBG_ADDRMOD, & cpu_dev,
 962                            "IT_MOD CI/SC/SCR data=%012"PRIo64"\n",
 963                            cpu.ou.character_data);
 964 
 965                 cpu.cu.pot = 0;
 966 
 967                 if (Td == IT_SC)
 968                   {
 969                     // For each reference to the indirect word, the character
 970                     // counter, cf, is increased by 1 and the TALLY field is
 971                     // reduced by 1 after the computed address is formed.
 972                     // Character count arithmetic is modulo 6 for 6-bit
 973                     // characters and modulo 4 for 9-bit bytes. If the
 974                     // character count, cf, overflows to 6 for 6-bit characters
 975                     // or to 4 for 9-bit bytes, it is reset to 0 and ADDRESS is
 976                     // increased by 1. ADDRESS arithmetic is modulo 2^18. TALLY
 977                     // arithmetic is modulo 4096. If the TALLY field is reduced
 978                     // to 0, the tally runout indicator is set ON, otherwise it
 979                     // is set OFF.
 980 
 981                     os ++;
 982 
 983                     if (((sz == TB6) && (os > 5)) ||
 984                         ((sz == TB9) && (os > 3)))
 985                       {
 986                         os = 0;
 987                         Yi += 1;
 988                         Yi &= MASK18;
 989                       }
 990                     CPT (cpt2L, 6); // Update IT Tally; SC
 991                     tally --;
 992                     tally &= 07777; // keep to 12-bits
 993                   }
 994 
 995                 if (Td == IT_SC || Td == IT_SCR)
 996                   {
 997                     sim_debug (DBG_ADDRMOD, & cpu_dev,
 998                                    "update IT tally now %o\n", tally);
 999 
1000                     //word36 new_indword = (word36) (((word36) Yi << 18) |
1001                     //                    (((word36) tally & 07777) << 6) |
1002                     //                    cpu.ou.characterOperandSize |
1003                     //                    cpu.ou.characterOperandOffset);
1004                     //Write (cpu.TPR.CA,  new_indword, APU_DATA_STORE);
1005 #ifdef LOCKLESS
1006                     word36 indword_new;
1007                     core_read_lock(phys_address, &indword_new, __func__);
1008                     if (indword_new != indword)
1009                       sim_warn("indword changed from %llo to %llo\n",
1010                                (long long unsigned int)indword,
1011                                (long long unsigned int)indword_new);
1012 #endif
1013                     putbits36_18 (& indword,  0, Yi);
1014                     putbits36_12 (& indword, 18, tally);
1015                     putbits36_3  (& indword, 33, os);
1016 #ifdef LOCKLESS
1017                     core_write_unlock(phys_address, indword, __func__);
1018 #else
1019                     WriteAPUDataStore (indaddr, indword);
1020 #endif
1021 
1022                     SC_I_TALLY (tally == 0);
1023 
1024                     sim_debug (DBG_ADDRMOD, & cpu_dev,
1025                                "update IT wrote tally word %012"PRIo64
1026                                " to %06o\n",
1027                                indword, cpu.TPR.CA);
1028                   }
1029 
1030                 // readOperand and writeOperand will not use cpu.TPR.CA; they
1031                 // will use the saved address, size, offset and data.
1032                 cpu.TPR.CA = cpu.ou.character_address;
1033                 return;
1034               } // IT_CI, IT_SC, IT_SCR
1035 
1036             case IT_I: // Indirect (Td = 11)
1037               {
1038                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1039                            "IT_MOD(IT_I): reading indirect word from %06o\n",
1040                            cpu.TPR.CA);
1041 
1042                 //Read2 (cpu.TPR.CA, cpu.itxPair, INDIRECT_WORD_FETCH);
1043                 ReadIndirect ();
1044 
1045                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1046                            "IT_MOD(IT_I): indword=%012"PRIo64"\n",
1047                            cpu.itxPair[0]);
1048 
1049                 cpu.TPR.CA = GET_ADDR (cpu.itxPair[0]);
1050                 updateIWB (cpu.TPR.CA, (TM_R|TD_N));
1051                 return;
1052               } // IT_I
1053 
1054             case IT_AD: ///< Add delta (Td = 13)
1055               {
1056                 // The TAG field of the indirect word is interpreted as a
1057                 // 6-bit, unsigned, positive address increment value, delta.
1058                 // For each reference to the indirect word, the ADDRESS field
1059                 // is increased by delta and the TALLY field is reduced by 1
1060                 // after the computed address is formed. ADDRESS arithmetic is
1061                 // modulo 2^18. TALLY arithmetic is modulo 4096. If the TALLY
1062                 // field is reduced to 0, the tally runout indicator is set ON,
1063                 // otherwise it is set OFF. The computed address is the value
1064                 // of the unmodified ADDRESS field of the indirect word.
1065 
1066                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1067                            "IT_MOD(IT_AD): reading indirect word from %06o\n",
1068                            cpu.TPR.CA);
1069 
1070 #ifdef THREADZ
1071                 lock_rmw ();
1072 #endif
1073 
1074                 word18 saveCA = cpu.TPR.CA;
1075                 word36 indword;
1076                 ReadAPUDataRMW (cpu.TPR.CA, & indword);
1077 
1078                 cpu.AM_tally  = GET_TALLY (indword); // 12-bits
1079                 delta         = GET_DELTA (indword); // 6-bits
1080                 Yi            = GETHI (indword);        // from where data live
1081 
1082                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1083                            "IT_MOD(IT_AD): indword=%012"PRIo64"\n",
1084                            indword);
1085                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1086                            "IT_MOD(IT_AD): address:%06o tally:%04o "
1087                            "delta:%03o\n",
1088                            Yi, cpu.AM_tally, delta);
1089 
1090                 cpu.TPR.CA = Yi;
1091                 word18 computedAddress = cpu.TPR.CA;
1092 
1093                 Yi += delta;
1094                 Yi &= MASK18;
1095 
1096                 cpu.AM_tally -= 1;
1097                 cpu.AM_tally &= 07777; // keep to 12-bits
1098                 // breaks emacs
1099                 //if (cpu.AM_tally == 0)
1100                   //SET_I_TALLY;
1101                 SC_I_TALLY (cpu.AM_tally == 0);
1102                 indword = (word36) (((word36) Yi << 18) |
1103                                     (((word36) cpu.AM_tally & 07777) << 6) |
1104                                     delta);
1105 #ifdef LOCKLESS
1106                 core_write_unlock(cpu.iefpFinalAddress, indword, __func__);
1107 #else
1108                 WriteAPUDataStore (saveCA, indword);
1109 #endif
1110 
1111 #ifdef THREADZ
1112                 unlock_rmw ();
1113 #endif
1114 
1115                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1116                            "IT_MOD(IT_AD): wrote tally word %012"PRIo64
1117                            " to %06o\n",
1118                            indword, saveCA);
1119 
1120                 cpu.TPR.CA = computedAddress;
1121                 updateIWB (cpu.TPR.CA, (TM_R|TD_N));
1122                 return;
1123               } // IT_AD
1124 
1125             case IT_SD: ///< Subtract delta (Td = 4)
1126               {
1127                 // The TAG field of the indirect word is interpreted as a
1128                 // 6-bit, unsigned, positive address increment value, delta.
1129                 // For each reference to the indirect word, the ADDRESS field
1130                 // is reduced by delta and the TALLY field is increased by 1
1131                 // before the computed address is formed. ADDRESS arithmetic is
1132                 // modulo 2^18. TALLY arithmetic is modulo 4096. If the TALLY
1133                 // field overflows to 0, the tally runout indicator is set ON,
1134                 // otherwise it is set OFF. The computed address is the value
1135                 // of the decremented ADDRESS field of the indirect word.
1136 
1137 #ifdef THREADZ
1138                 lock_rmw ();
1139 #endif
1140 
1141                 word18 saveCA = cpu.TPR.CA;
1142                 word36 indword;
1143                 ReadAPUDataRMW (cpu.TPR.CA, & indword);
1144 
1145                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1146                            "IT_MOD(IT_SD): reading indirect word from %06o\n",
1147                            cpu.TPR.CA);
1148                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1149                 delta = GET_DELTA (indword); // 6-bits
1150                 Yi    = GETHI (indword);     // from where data live
1151 
1152                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1153                            "IT_MOD(IT_SD): indword=%012"PRIo64"\n",
1154                            indword);
1155                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1156                            "IT_MOD(IT_SD): address:%06o tally:%04o "
1157                            "delta:%03o\n",
1158                            Yi, cpu.AM_tally, delta);
1159 
1160                 Yi -= delta;
1161                 Yi &= MASK18;
1162                 cpu.TPR.CA = Yi;
1163 
1164                 cpu.AM_tally += 1;
1165                 cpu.AM_tally &= 07777; // keep to 12-bits
1166                 if (cpu.AM_tally == 0)
1167                   SET_I_TALLY;
1168 
1169                 // write back out indword
1170                 indword = (word36) (((word36) Yi << 18) |
1171                                     (((word36) cpu.AM_tally & 07777) << 6) |
1172                                     delta);
1173 #ifdef LOCKLESS
1174                 core_write_unlock(cpu.iefpFinalAddress, indword, __func__);
1175 #else
1176                 WriteAPUDataStore (saveCA, indword);
1177 #endif
1178 
1179 #ifdef THREADZ
1180                 unlock_rmw ();
1181 #endif
1182 
1183                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1184                            "IT_MOD(IT_SD): wrote tally word %012"PRIo64
1185                            " to %06o\n",
1186                            indword, saveCA);
1187 
1188                 cpu.TPR.CA = Yi;
1189                 updateIWB (cpu.TPR.CA, (TM_R|TD_N));
1190                 return;
1191               } // IT_SD
1192 
1193             case IT_DI: ///< Decrement address, increment tally (Td = 14)
1194               {
1195                 // For each reference to the indirect word, the ADDRESS field
1196                 // is reduced by 1 and the TALLY field is increased by 1 before
1197                 // the computed address is formed. ADDRESS arithmetic is modulo
1198                 // 2^18. TALLY arithmetic is modulo 4096. If the TALLY field
1199                 // overflows to 0, the tally runout indicator is set ON,
1200                 // otherwise it is set OFF. The TAG field of the indirect word
1201                 // is ignored. The computed address is the value of the
1202                 // decremented ADDRESS field.
1203 
1204                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1205                            "IT_MOD(IT_DI): reading indirect word from %06o\n",
1206                            cpu.TPR.CA);
1207 
1208 #ifdef THREADZ
1209                 lock_rmw ();
1210 #endif
1211 
1212                 word18 saveCA = cpu.TPR.CA;
1213                 word36 indword;
1214                 ReadAPUDataRMW (cpu.TPR.CA, & indword);
1215 
1216                 Yi           = GETHI (indword);
1217                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1218                 word6 junk   = GET_TAG (indword);   // get tag field, but ignore it
1219 
1220                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1221                            "IT_MOD(IT_DI): indword=%012"PRIo64"\n",
1222                            indword);
1223                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1224                            "IT_MOD(IT_DI): address:%06o tally:%04o\n",
1225                            Yi, cpu.AM_tally);
1226 
1227                 Yi -= 1;
1228                 Yi &= MASK18;
1229                 cpu.TPR.CA = Yi;
1230 
1231                 cpu.AM_tally += 1;
1232                 cpu.AM_tally &= 07777; // keep to 12-bits
1233                 SC_I_TALLY (cpu.AM_tally == 0);
1234 
1235                 // write back out indword
1236 
1237                 indword = (word36) (((word36) cpu.TPR.CA << 18) |
1238                                     ((word36) cpu.AM_tally << 6) |
1239                                     junk);
1240 
1241                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1242                            "IT_MOD(IT_DI): writing indword=%012"PRIo64" to "
1243                            "addr %06o\n",
1244                            indword, saveCA);
1245 
1246 #ifdef LOCKLESS
1247                 core_write_unlock(cpu.iefpFinalAddress, indword, __func__);
1248 #else
1249                 WriteAPUDataStore (saveCA, indword);
1250 #endif
1251 
1252 #ifdef THREADZ
1253                 unlock_rmw ();
1254 #endif
1255                 cpu.TPR.CA = Yi;
1256                 updateIWB (cpu.TPR.CA, (TM_R|TD_N));
1257                 return;
1258               } // IT_DI
1259 
1260             case IT_ID: ///< Increment address, decrement tally (Td = 16)
1261               {
1262                 // For each reference to the indirect word, the ADDRESS field
1263                 // is increased by 1 and the TALLY field is reduced by 1 after
1264                 // the computed address is formed. ADDRESS arithmetic is modulo
1265                 // 2^18. TALLY arithmetic is modulo 4096. If the TALLY field is
1266                 // reduced to 0, the tally runout indicator is set ON,
1267                 // otherwise it is set OFF. The TAG field of the indirect word
1268                 // is ignored. The computed address is the value of the
1269                 // unmodified ADDRESS field.
1270 
1271                 word18 saveCA = cpu.TPR.CA;
1272 
1273                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1274                            "IT_MOD(IT_ID): fetching indirect word from %06o\n",
1275                            cpu.TPR.CA);
1276 
1277 #ifdef THREADZ
1278                 lock_rmw ();
1279 #endif
1280 
1281                 word36 indword;
1282                 ReadAPUDataRMW (cpu.TPR.CA, & indword);
1283 
1284                 Yi = GETHI (indword);
1285                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1286                 // get tag field, but ignore it
1287                 word6 junk = GET_TAG (indword);
1288                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1289                            "IT_MOD(IT_ID): indword=%012"PRIo64
1290                            " Yi=%06o tally=%04o\n",
1291                            indword, Yi, cpu.AM_tally);
1292 
1293                 cpu.TPR.CA = Yi;
1294                 word18 computedAddress = cpu.TPR.CA;
1295 
1296                 Yi += 1;
1297                 Yi &= MASK18;
1298 
1299                 cpu.AM_tally -= 1;
1300                 cpu.AM_tally &= 07777; // keep to 12-bits
1301 
1302                 // XXX Breaks boot?
1303                 //if (cpu.AM_tally == 0)
1304                   //SET_I_TALLY;
1305                 SC_I_TALLY (cpu.AM_tally == 0);
1306 
1307                 // write back out indword
1308                 indword = (word36) (((word36) Yi << 18) |
1309                                     ((word36) cpu.AM_tally << 6) |
1310                                     junk);
1311 
1312                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1313                            "IT_MOD(IT_ID): writing indword=%012"PRIo64" to "
1314                            "addr %06o\n",
1315                            indword, saveCA);
1316 
1317 #ifdef LOCKLESS
1318                 core_write_unlock(cpu.iefpFinalAddress, indword, __func__);
1319 #else
1320                 WriteAPUDataStore (saveCA, indword);
1321 #endif
1322 
1323 #ifdef THREADZ
1324                 unlock_rmw ();
1325 #endif
1326 
1327                 cpu.TPR.CA = computedAddress;
1328                 updateIWB (cpu.TPR.CA, (TM_R|TD_N));
1329                 return;
1330               } // IT_ID
1331 
1332             // Decrement address, increment tally, and continue (Td = 15)
1333             case IT_DIC:
1334               {
1335                 // The action for this variation is identical to that for the
1336                 // decrement address, increment tally variation except that the
1337                 // TAG field of the indirect word is interpreted and
1338                 // continuation of the indirect chain is possible. If the TAG
1339                 // of the indirect word invokes a register, that is, specifies
1340                 // r, ri, or ir modification, the effective Td value for the
1341                 // register is forced to "null" before the next computed
1342                 // address is formed.
1343 
1344                 // a:RJ78/idc1
1345                 // The address and tally fields are used as described under the
1346                 // ID variation. The tag field uses the set of variations for
1347                 // instruction address modification under the following
1348                 // restrictions: no variation is permitted that requires an
1349                 // indexing modification in the DIC cycle since the indexing
1350                 // adder is being used by the tally phase of the operation.
1351                 // Thus, permissible variations are any allowable form of IT or
1352                 // IR, but if RI or R is used, R must equal N (RI and R forced
1353                 // to N).
1354 
1355                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1356                            "IT_MOD(IT_DIC): fetching indirect word from %06o\n",
1357                            cpu.TPR.CA);
1358 
1359 #ifdef THREADZ
1360                 lock_rmw ();
1361 #endif
1362 
1363                 word18 saveCA = cpu.TPR.CA;
1364                 word36 indword;
1365                 ReadAPUDataRMW (cpu.TPR.CA, & indword);
1366 
1367                 cpu.cu.pot = 0;
1368 
1369                 Yi = GETHI (indword);
1370                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1371                 idwtag = GET_TAG (indword);
1372 
1373                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1374                            "IT_MOD(IT_DIC): indword=%012"PRIo64" Yi=%06o "
1375                            "tally=%04o idwtag=%02o\n",
1376                            indword, Yi, cpu.AM_tally, idwtag);
1377 
1378                 word24 YiSafe2 = Yi; // save indirect address for later use
1379 
1380                 Yi -= 1;
1381                 Yi &= MASK18;
1382 
1383                 cpu.AM_tally += 1;
1384                 cpu.AM_tally &= 07777; // keep to 12-bits
1385 // Set the tally after the indirect word is processed; if it faults, the IR
1386 // should be unchanged. ISOLTS ps791 test-02g
1387                 //SC_I_TALLY (cpu.AM_tally == 0);
1388                 //if (cpu.AM_tally == 0)
1389                   //SET_I_TALLY;
1390 
1391                 // write back out indword
1392                 indword = (word36) (((word36) Yi << 18) |
1393                           ((word36) cpu.AM_tally << 6) | idwtag);
1394 
1395                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1396                            "IT_MOD(IT_DIC): writing indword=%012"PRIo64" to "
1397                            "addr %06o\n", indword, saveCA);
1398 
1399 #ifdef LOCKLESS
1400                 core_write_unlock(cpu.iefpFinalAddress, indword, __func__);
1401 #else
1402                 WriteAPUDataStore (saveCA, indword);
1403 #endif
1404 
1405 #ifdef THREADZ
1406                 unlock_rmw ();
1407 #endif
1408                 // If the TAG of the indirect word invokes a register, that is,
1409                 // specifies r, ri, or ir modification, the effective Td value
1410                 // for the register is forced to "null" before the next
1411                 // computed address is formed.
1412 
1413                 // Thus, permissible variations are any allowable form of IT or
1414                 // IR, but if RI or R is used, R must equal N (RI and R forced
1415                 // to N).
1416                 cpu.TPR.CA = Yi;
1417 
1418                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1419                            "IT_MOD(IT_DIC): new CT_HOLD %02o new TAG %02o\n",
1420                            cpu.rTAG, idwtag);
1421                 cpu.cu.CT_HOLD = cpu.rTAG;
1422                 cpu.rTAG = idwtag;
1423 
1424                 Tm = GET_TM (cpu.rTAG);
1425                 if (Tm == TM_RI || Tm == TM_R)
1426                   {
1427                      if (GET_TD (cpu.rTAG) != 0)
1428                        {
1429                          doFault (FAULT_IPR, fst_ill_mod,
1430                                   "DIC Incorrect address modifier");
1431                        }
1432                   }
1433 
1434 // Set the tally after the indirect word is processed; if it faults, the IR
1435 // should be unchanged. ISOLTS ps791 test-02g
1436                 SC_I_TALLY (cpu.AM_tally == 0);
1437                 if (cpu.tweaks.isolts_mode)
1438                   updateIWB (YiSafe2, cpu.rTAG);
1439                 else
1440                   updateIWB (cpu.TPR.CA, cpu.rTAG);
1441                 goto startCA;
1442               } // IT_DIC
1443 
1444             // Increment address, decrement tally, and continue (Td = 17)
1445             case IT_IDC:
1446               {
1447                 // The action for this variation is identical to that for the
1448                 // increment address, decrement tally variation except that the
1449                 // TAG field of the indirect word is interpreted and
1450                 // continuation of the indirect chain is possible. If the TAG
1451                 // of the indirect word invokes a register, that is, specifies
1452                 // r, ri, or ir modification, the effective Td value for the
1453                 // register is forced to "null" before the next computed
1454                 // address is formed.
1455 
1456                 // a:RJ78/idc1
1457                 // The address and tally fields are used as described under the
1458                 // ID variation. The tag field uses the set of variations for
1459                 // instruction address modification under the following
1460                 // restrictions: no variation is permitted that requires an
1461                 // indexing modification in the IDC cycle since the indexing
1462                 // adder is being used by the tally phase of the operation.
1463                 // Thus, permissible variations are any allowable form of IT or
1464                 // IR, but if RI or R is used, R must equal N (RI and R forced
1465                 // to N).
1466 
1467                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1468                            "IT_MOD(IT_IDC): fetching indirect word from %06o\n",
1469                            cpu.TPR.CA);
1470 
1471 #ifdef THREADZ
1472                 lock_rmw ();
1473 #endif
1474 
1475                 word18 saveCA = cpu.TPR.CA;
1476                 word36 indword;
1477                 ReadAPUDataRMW (cpu.TPR.CA, & indword);
1478 
1479                 cpu.cu.pot = 0;
1480 
1481                 Yi           = GETHI (indword);
1482                 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1483                 idwtag       = GET_TAG (indword);
1484 
1485                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1486                            "IT_MOD(IT_IDC): indword=%012"PRIo64" Yi=%06o "
1487                            "tally=%04o idwtag=%02o\n",
1488                            indword, Yi, cpu.AM_tally, idwtag);
1489 
1490                 word24 YiSafe = Yi; // save indirect address for later use
1491 
1492                 Yi += 1;
1493                 Yi &= MASK18;
1494 
1495                 cpu.AM_tally -= 1;
1496                 cpu.AM_tally &= 07777; // keep to 12-bits
1497 // Set the tally after the indirect word is processed; if it faults, the IR
1498 // should be unchanged. ISOLTS ps791 test-02f
1499                 //SC_I_TALLY (cpu.AM_tally == 0);
1500 
1501                 // write back out indword
1502                 indword = (word36) (((word36) Yi << 18) |
1503                                     ((word36) cpu.AM_tally << 6) |
1504                                     idwtag);
1505 
1506                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1507                            "IT_MOD(IT_IDC): writing indword=%012"PRIo64""
1508                            " to addr %06o\n",
1509                            indword, saveCA);
1510 
1511 #ifdef LOCKLESS
1512                 core_write_unlock(cpu.iefpFinalAddress, indword, __func__);
1513 #else
1514                 WriteAPUDataStore (saveCA, indword);
1515 #endif
1516 
1517 #ifdef THREADZ
1518                 unlock_rmw ();
1519 #endif
1520 
1521                 // If the TAG of the indirect word invokes a register, that is,
1522                 // specifies r, ri, or ir modification, the effective Td value
1523                 // for the register is forced to "null" before the next
1524                 // computed address is formed.
1525                 // But for the dps88 you can use everything but ir/ri.
1526 
1527                 // Thus, permissible variations are any allowable form of IT or
1528                 // IR, but if RI or R is used, R must equal N (RI and R forced
1529                 // to N).
1530                 cpu.TPR.CA = YiSafe;
1531 
1532                 sim_debug (DBG_ADDRMOD, & cpu_dev,
1533                            "IT_MOD(IT_IDC): new CT_HOLD %02o new TAG %02o\n",
1534                            cpu.rTAG, idwtag);
1535                 cpu.cu.CT_HOLD = cpu.rTAG;
1536                 cpu.rTAG = idwtag;
1537 
1538                 Tm = GET_TM (cpu.rTAG);
1539                 if (Tm == TM_RI || Tm == TM_R)
1540                   {
1541                      if (GET_TD (cpu.rTAG) != 0)
1542                        {
1543                          doFault (FAULT_IPR, fst_ill_mod,
1544                                   "IDC Incorrect address modifier");
1545                        }
1546                   }
1547 
1548 // Set the tally after the indirect word is processed; if it faults, the IR
1549 // should be unchanged. ISOLTS ps791 test-02f
1550                 SC_I_TALLY (cpu.AM_tally == 0);
1551                 updateIWB (cpu.TPR.CA, cpu.rTAG);
1552 
1553                 goto startCA;
1554               } // IT_IDC
1555           } // Td
1556         sim_printf ("IT_MOD/Td how did we get here?\n");
1557         return;
1558      } // IT_MOD
1559   } // do_caf

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