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