root/src/dps8/dps8_addrmods.c

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

DEFINITIONS

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

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

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