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