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