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