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 sim_debug (DBG_APPENDING, & cpu_dev, "do_ITS_ITP sets XSF to 1\r\n");
316 }
317
318 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)
*/
319 {
320 word36 * wb;
321 if (USE_IRODD)
322 wb = & cpu.cu.IRODD;
323 else
324 wb = & cpu.cu.IWB;
325 sim_debug (DBG_ADDRMOD, & cpu_dev,
326 "updateIWB: IWB was %012"PRIo64" %06o %s\r\n",
327 * wb, GET_ADDR (* wb),
328 extMods [GET_TAG (* wb)].mod);
329
330 putbits36_18 (wb, 0, addr);
331 putbits36_6 (wb, 30, tag);
332 putbits36_1 (wb, 29, 0);
333
334 sim_debug (DBG_ADDRMOD, & cpu_dev,
335 "updateIWB: IWB now %012"PRIo64" %06o %s\r\n",
336 * wb, GET_ADDR (* wb),
337 extMods [GET_TAG (* wb)].mod);
338
339 decode_instruction (cpup, IWB_IRODD, & cpu.currentInstruction);
340 }
341
342 //
343 // Input:
344 // cu.IWB
345 // currentInstruction
346 // TPR.TSR
347 // TPR.TRR
348 // TPR.TBR // XXX check to see if this is initialized
349 // TPR.CA
350 //
351 // Output:
352 // TPR.CA
353 // directOperandFlag
354 //
355 // CANFAULT
356
357 void do_caf (cpu_state_t * cpup)
/* ![[previous]](../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)
*/
358 {
359 if (cpu.currentInstruction.b29 == 0)
360 {
361 cpu.TPR.CA = GET_ADDR (IWB_IRODD);
362 }
363 else
364 {
365 word3 n = GET_PRN(IWB_IRODD); // get PRn
366 #if defined(TESTING)
367 HDBGRegPRR (n, "b29");
368 #endif
369 word15 offset = GET_OFFSET(IWB_IRODD);
370 cpu.TPR.CA = (cpu.PAR[n].WORDNO + SIGNEXT15_18 (offset))
371 & MASK18;
372 }
373 char buf [256];
374 sim_debug (DBG_ADDRMOD, & cpu_dev,
375 "%s(Entry): operType:%s TPR.CA=%06o\r\n",
376 __func__, op_desc_str (cpup, buf), cpu.TPR.CA);
377 sim_debug (DBG_ADDRMOD, & cpu_dev,
378 "%s(Entry): CT_HOLD %o\r\n",
379 __func__, cpu.cu.CT_HOLD);
380
381 DCDstruct * i = & cpu.currentInstruction;
382
383 word6 Tm = 0;
384 word6 Td = 0;
385
386 /* word6 iTAG; */ // tag of word preceding an indirect fetch
387
388 cpu.ou.directOperandFlag = false;
389
390 if (i -> info -> flags & NO_TAG) // for instructions line STCA/STCQ
391 cpu.rTAG = 0;
392 else
393 cpu.rTAG = GET_TAG (IWB_IRODD);
394
395 int lockupCnt = 0;
396 #define lockupLimit 4096 // approx. 2 ms
397
398 startCA:;
399
400 if (++ lockupCnt > lockupLimit)
401 {
402 doFault (FAULT_LUF, fst_zero, "Lockup in addrmod");
403 }
404
405 Td = GET_TD (cpu.rTAG);
406 Tm = GET_TM (cpu.rTAG);
407
408 // CT_HOLD is set to 0 on instruction setup; if it is non-zero here,
409 // we must have faulted during an indirect word fetch. Restore
410 // state and restart the fetch.
411 if (cpu.cu.CT_HOLD)
412 {
413 sim_debug (DBG_ADDRMOD, & cpu_dev,
414 "%s(startCA): restart; CT_HOLD %02o\r\n",
415 __func__, cpu.cu.CT_HOLD);
416 // Part of ISOLTS tst885 ir
417 if (cpu.tweaks.isolts_mode &&
418 GET_TM(cpu.cu.CT_HOLD) == TM_IT && GET_TD (cpu.cu.CT_HOLD) == IT_DIC &&
419 cpu.cu.pot == 1 && GET_ADDR (IWB_IRODD) == cpu.TPR.CA)
420 {
421 cpu.TPR.CA--;
422 sim_warn ("%s: correct CA\r\n", __func__);
423 }
424 if (Tm == TM_IT && (Td == IT_IDC || Td == IT_DIC))
425 {
426 cpu.cu.pot = 1;
427 }
428 }
429 else
430 {
431 // not CT_HOLD
432 cpu.cu.its = 0;
433 cpu.cu.itp = 0;
434 cpu.cu.pot = 0;
435 }
436 sim_debug (DBG_ADDRMOD, & cpu_dev,
437 "%s(startCA): TAG=%02o(%s) Tm=%o Td=%o CT_HOLD %02o\r\n",
438 __func__, cpu.rTAG, get_mod_string (buf, cpu.rTAG), Tm, Td, cpu.cu.CT_HOLD);
439
440 switch (Tm)
441 {
442 case TM_R:
443 goto R_MOD;
444 case TM_RI:
445 goto RI_MOD;
446 case TM_IT:
447 goto IT_MOD;
448 case TM_IR:
449 goto IR_MOD;
450 default:
451 break;
452 }
453
454 sim_printf ("%s(startCA): unknown Tm??? %o\r\n",
455 __func__, GET_TM (cpu.rTAG));
456 sim_warn ("(startCA): unknown Tmi; can't happen!\r\n");
457 return;
458
459 // Register modification. Fig 6-3
460 R_MOD:;
461 {
462 if (Td == TD_N) // TPR.CA = address from opcode
463 {
464 //updateIWB (identity) // known that Td is 0.
465 return;
466 }
467
468 word18 Cr = get_Cr (cpup, Td);
469
470 sim_debug (DBG_ADDRMOD, & cpu_dev, "R_MOD: Cr=%06o\r\n", Cr);
471
472 if (cpu.ou.directOperandFlag)
473 {
474 sim_debug (DBG_ADDRMOD, & cpu_dev,
475 "R_MOD: directOperand = %012"PRIo64"\r\n",
476 cpu.ou.directOperand);
477 return;
478 }
479
480 // For the case of RPT/RPD, the instruction decoder has
481 // verified that Tm is R or RI, and Td is X1..X7.
482 if (cpu.cu.rpt || cpu.cu.rd | cpu.cu.rl)
483 {
484 if (cpu.currentInstruction.b29)
485 {
486 word3 PRn = GET_PRN(IWB_IRODD);
487 #if defined(TESTING)
488 HDBGRegPRR (PRn, "rpx b29");
489 #endif
490 CPTUR (cptUsePRn + PRn);
491 cpu.TPR.CA = Cr + cpu.PR [PRn].WORDNO;
492 cpu.TPR.CA &= AMASK;
493 }
494 else
495 {
496 cpu.TPR.CA = Cr;
497 }
498 }
499 else
500 {
501 cpu.TPR.CA += Cr;
502 cpu.TPR.CA &= MASK18; // keep to 18-bits
503 }
504 sim_debug (DBG_ADDRMOD, & cpu_dev, "R_MOD: TPR.CA=%06o\r\n",
505 cpu.TPR.CA);
506
507 return;
508 } // R_MOD
509
510 // Figure 6-4. Register Then Indirect Modification Flowchart
511 RI_MOD:;
512 {
513 sim_debug (DBG_ADDRMOD, & cpu_dev, "RI_MOD: Td=%o\r\n", Td);
514
515 if (Td == TD_DU || Td == TD_DL)
516 doFault (FAULT_IPR, fst_ill_mod,
517 "RI_MOD: Td == TD_DU || Td == TD_DL");
518
519 if (Td != TD_N)
520 {
521 word18 Cr = get_Cr (cpup, Td); // C(r)
522
523 // We don''t need to worry about direct operand here, since du
524 // and dl are disallowed above
525
526 sim_debug (DBG_ADDRMOD, & cpu_dev,
527 "RI_MOD: Cr=%06o CA(Before)=%06o\r\n", Cr, cpu.TPR.CA);
528
529 if (cpu.cu.rpt || cpu.cu.rd || cpu.cu.rl)
530 {
531 if (cpu.currentInstruction.b29)
532 {
533 word3 PRn = GET_PRN(IWB_IRODD);
534 #if defined(TESTING)
535 HDBGRegPRR (PRn, "rpx b29");
536 #endif
537 CPTUR (cptUsePRn + PRn);
538 cpu.TPR.CA = Cr + cpu.PR [PRn].WORDNO;
539 }
540 else
541 {
542 cpu.TPR.CA = Cr;
543 }
544 cpu.TPR.CA &= AMASK;
545 }
546 else
547 {
548 cpu.TPR.CA += Cr;
549 cpu.TPR.CA &= MASK18; // keep to 18-bits
550 }
551 sim_debug (DBG_ADDRMOD, & cpu_dev,
552 "RI_MOD: CA(After)=%06o\r\n", cpu.TPR.CA);
553 }
554
555 // - Multics link snap code (adjust_mc) sets rTAG to TM_RI
556 // - After directed faults RI modifier after IR modifier end up here
557 // - In both cases continue with indirect chain
558 if (GET_TM(cpu.cu.CT_HOLD) == TM_IR)
559 {
560 goto IR_MOD_2;
561 }
562
563 // If the indirect word faults, on restart the CA will be the post
564 // register modification value, so we want to prevent it from
565 // happening again on restart
566 word18 saveCA = cpu.TPR.CA;
567 ReadIndirect (cpup);
568
569 if ((saveCA & 1) == 0 && (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0])))
570 {
571 do_ITS_ITP (cpup);
572 updateIWB (cpup, cpu.TPR.CA, cpu.rTAG);
573 }
574 else
575 {
576 cpu.rTAG = GET_TAG (cpu.itxPair[0]);
577 if (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0]))
578 {
579 sim_warn ("%s: itp/its at odd address\r\n", __func__);
580 #if defined(TESTING)
581 traceInstruction (0);
582 #endif
583 }
584 if (!(cpu.cu.rpt || cpu.cu.rd || cpu.cu.rl))
585 {
586 updateIWB (cpup, GET_ADDR (cpu.itxPair[0]), cpu.rTAG);
587 }
588 // F2 and F3 fault tests after updateIW
589 if (GET_TM (cpu.rTAG) == TM_IT)
590 {
591 if (GET_TD (cpu.rTAG) == IT_F2)
592 {
593 doFault (FAULT_F2, fst_zero, "RI_MOD: IT_F2 (0)");
594 }
595 if (GET_TD (cpu.rTAG) == IT_F3)
596 {
597 doFault (FAULT_F3, fst_zero, "RI_MOD: IT_F3");
598 }
599 }
600 cpu.TPR.CA = GETHI (cpu.itxPair[0]);
601 cpu.rY = cpu.TPR.CA;
602 }
603 // "In the case of RI modification, only one indirect reference is made
604 // per repeated execution. The TAG field of the indirect word is not
605 // interpreted. The indirect word is treated as though it had R
606 // modification with R = N."
607
608 // Check for fault causing tags before updating the IWB, so the
609 // instruction restart will reload the offending indirect word.
610 sim_debug (DBG_ADDRMOD, & cpu_dev,
611 "RI_MOD: cpu.itxPair[0]=%012"PRIo64
612 " TPR.CA=%06o rTAG=%02o\r\n",
613 cpu.itxPair[0], cpu.TPR.CA, cpu.rTAG);
614 // If repeat, the indirection chain is limited, so it is not needed
615 // to clear the tag; the delta code later on needs the tag to know
616 // which X register to update
617 if (cpu.cu.rpt || cpu.cu.rd || cpu.cu.rl)
618 return;
619
620 goto startCA;
621 } // RI_MOD
622
623 // Figure 6-5. Indirect Then Register Modification Flowchart
624 IR_MOD:;
625 {
626 IR_MOD_1:;
627
628 sim_debug (DBG_ADDRMOD, & cpu_dev,
629 "IR_MOD: CT_HOLD=%o %o\r\n", cpu.cu.CT_HOLD, Td);
630
631 IR_MOD_2:;
632
633 if (++ lockupCnt > lockupLimit)
634 {
635 doFault (FAULT_LUF, fst_zero, "Lockup in addrmod IR mode");
636 }
637
638 sim_debug (DBG_ADDRMOD, & cpu_dev,
639 "IR_MOD: fetching indirect word from %06o\r\n",
640 cpu.TPR.CA);
641
642 word18 saveCA = cpu.TPR.CA;
643 ReadIndirect (cpup);
644
645 // ReadIndirect does NOT update cpu.rTAG anymore
646 if (GET_TM(cpu.rTAG) == TM_IR)
647 cpu.cu.CT_HOLD = cpu.rTAG;
648
649 if ((saveCA & 1) == 0 && (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0])))
650 {
651 do_ITS_ITP (cpup);
652 }
653 else
654 {
655 if (ISITP (cpu.itxPair[0]) || ISITS (cpu.itxPair[0]))
656 {
657 sim_warn ("%s: itp/its at odd address\r\n", __func__);
658 #if defined(TESTING)
659 traceInstruction (0);
660 #endif
661 }
662 cpu.TPR.CA = GETHI (cpu.itxPair[0]);
663 cpu.rY = cpu.TPR.CA;
664 cpu.rTAG = GET_TAG (cpu.itxPair[0]);
665 }
666
667 sim_debug (DBG_ADDRMOD, & cpu_dev,
668 "IR_MOD: CT_HOLD=%o\r\n", cpu.cu.CT_HOLD);
669 Td = GET_TD (cpu.rTAG);
670 Tm = GET_TM (cpu.rTAG);
671
672 sim_debug (DBG_ADDRMOD, & cpu_dev,
673 "IR_MOD1: cpu.itxPair[0]=%012"PRIo64
674 " TPR.CA=%06o Tm=%o Td=%02o (%s)\r\n",
675 cpu.itxPair[0], cpu.TPR.CA, Tm, Td,
676 get_mod_string (buf, GET_TAG (cpu.itxPair[0])));
677
678 switch (Tm)
679 {
680 case TM_IT:
681 {
682 sim_debug (DBG_ADDRMOD, & cpu_dev,
683 "IR_MOD(TM_IT): Td=%02o => %02o\r\n",
684 Td, cpu.cu.CT_HOLD);
685
686 if (Td == IT_F2 || Td == IT_F3)
687 {
688 updateIWB(cpup, cpu.TPR.CA, cpu.rTAG);
689 // Abort. FT2 or 3
690 switch (Td)
691 {
692 case IT_F2:
693 cpu.TPR.CA = saveCA;
694 doFault (FAULT_F2, fst_zero, "TM_IT: IT_F2 (1)");
695
696 /*FALLTHRU*/ /* fall through */ /* fallthrough */
697 case IT_F3:
698 cpu.TPR.CA = saveCA;
699 doFault (FAULT_F3, fst_zero, "TM_IT: IT_F3");
700 }
701 }
702 // fall through to TM_R
703 #if !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) && !defined(__SUNPRO_CC_COMPAT)
704 /*FALLTHRU*/ /* fall through */ /* fallthrough */
705 # if defined(__GNUC__) && __GNUC__ > 6
706 __attribute__ ((fallthrough));
707 # endif /* if defined(__GNUC__) && __GNUC__ > 6 */
708 /*FALLTHRU*/ /* fall through */ /* fallthrough */
709 # if defined(__clang__)
710 (void)0;
711 # endif /* if defined(__clang__) */
712 #endif
713 } // TM_IT
714
715 /*FALLTHRU*/ /* fall through */ /* fallthrough */
716 case TM_R:
717 {
718 word6 Td_hold = GET_TD (cpu.cu.CT_HOLD);
719 cpu.rTAG = (TM_R | Td_hold);
720 updateIWB (cpup, cpu.TPR.CA, cpu.rTAG);
721 goto startCA;
722 } // TM_R
723
724 case TM_RI:
725 {
726 if (Td == TD_DU || Td == TD_DL)
727 doFault (FAULT_IPR, fst_ill_mod,
728 "RI_MOD: Td == TD_DU || Td == TD_DL");
729
730 word18 Cr = get_Cr (cpup, Td);
731
732 sim_debug (DBG_ADDRMOD, & cpu_dev,
733 "IR_MOD(TM_RI): Td=%o Cr=%06o TPR.CA(Before)=%06o\r\n",
734 Td, Cr, cpu.TPR.CA);
735
736 cpu.TPR.CA += Cr;
737 cpu.TPR.CA &= MASK18; // keep to 18-bits
738
739 sim_debug (DBG_ADDRMOD, & cpu_dev,
740 "IR_MOD(TM_RI): TPR.CA=%06o\r\n", cpu.TPR.CA);
741
742 sim_debug (DBG_ADDRMOD, & cpu_dev,
743 "IR_MOD(TM_RI): TPR.CA(After)=%06o\r\n",
744 cpu.TPR.CA);
745
746 // Don't add register twice if next indirection faults
747 updateIWB (cpup, cpu.TPR.CA, (TM_RI|TD_N));
748 goto IR_MOD_2;
749 } // TM_RI
750
751 case TM_IR:
752 {
753 updateIWB (cpup, cpu.TPR.CA, cpu.rTAG); // XXX guessing here...
754 goto IR_MOD_1;
755 } // TM_IR
756 } // TM
757
758 sim_printf ("%s(IR_MOD): unknown Tm??? %o\r\n",
759 __func__, GET_TM (cpu.rTAG));
760 return;
761 } // IR_MOD
762
763 IT_MOD:;
764 {
765 // IT_SD = 004,
766 // IT_SCR = 005,
767 // IT_CI = 010,
768 // IT_I = 011,
769 // IT_SC = 012,
770 // IT_AD = 013,
771 // IT_DI = 014,
772 // IT_DIC = 015,
773 // IT_ID = 016,
774 // IT_IDC = 017
775 word6 idwtag, delta;
776 word24 Yi = (word24) -1;
777
778 switch (Td)
779 {
780 // XXX this is probably wrong. ITS/ITP are not standard addr mods
781 case SPEC_ITP:
782 /*FALLTHRU*/ /* fall through */ /* fallthrough */
783 case SPEC_ITS:
784 {
785 doFault(FAULT_IPR, fst_ill_mod, "ITx in IT_MOD)");
786 }
787
788 /*FALLTHRU*/ /* fall through */ /* fallthrough */
789 case 2:
790 {
791 sim_debug (DBG_ADDRMOD, & cpu_dev,
792 "IT_MOD(): illegal procedure, illegal modifier, "
793 "fault Td=%o\r\n", Td);
794 doFault (FAULT_IPR, fst_ill_mod,
795 "IT_MOD(): illegal procedure, illegal modifier, "
796 "fault");
797 }
798
799 /*FALLTHRU*/ /* fall through */ /* fallthrough */
800 case IT_F1:
801 {
802 doFault(FAULT_F1, fst_zero, "IT_MOD: IT_F1");
803 }
804
805 /*FALLTHRU*/ /* fall through */ /* fallthrough */
806 case IT_F2:
807 {
808 doFault(FAULT_F2, fst_zero, "IT_MOD: IT_F2 (2)");
809 }
810
811 /*FALLTHRU*/ /* fall through */ /* fallthrough */
812 case IT_F3:
813 {
814 doFault(FAULT_F3, fst_zero, "IT_MOD: IT_F3");
815 }
816
817 /*FALLTHRU*/ /* fall through */ /* fallthrough */
818 case IT_CI: // Character indirect (Td = 10)
819 /*FALLTHRU*/ /* fall through */ /* fallthrough */
820 case IT_SC: // Sequence character (Td = 12)
821 /*FALLTHRU*/ /* fall through */ /* fallthrough */
822 case IT_SCR: // Sequence character reverse (Td = 5)
823 {
824 // There is complexity with managing page faults and tracking
825 // the indirect word address and the operand address.
826 //
827 // To address this, we force those pages in during PREPARE_CA,
828 // so that they won't fault during operand read/write.
829
830 sim_debug (DBG_ADDRMOD, & cpu_dev,
831 "IT_MOD CI/SC/SCR reading indirect word from %06o\r\n",
832 cpu.TPR.CA);
833
834 //
835 // Get the indirect word
836 //
837
838 word36 indword;
839 word18 indaddr = cpu.TPR.CA;
840 ReadAPUDataRead (cpup, indaddr, & indword);
841 #if defined(LOCKLESS)
842 word24 phys_address = cpu.iefpFinalAddress;
843 #endif
844
845 sim_debug (DBG_ADDRMOD, & cpu_dev,
846 "IT_MOD CI/SC/SCR indword=%012"PRIo64"\r\n", indword);
847
848 //
849 // Parse and validate the indirect word
850 //
851
852 Yi = GET_ADDR (indword);
853 word6 sz = GET_TB (GET_TAG (indword));
854 word3 os = GET_CF (GET_TAG (indword));
855 word12 tally = GET_TALLY (indword);
856
857 sim_debug (DBG_ADDRMOD, & cpu_dev,
858 "IT_MOD CI/SC/SCR size=%o offset=%o Yi=%06o\r\n",
859 sz, os, Yi);
860
861 if (sz == TB6 && os > 5)
862 // generate an illegal procedure, illegal modifier fault
863 doFault (FAULT_IPR, fst_ill_mod,
864 "co size == TB6 && offset > 5");
865
866 if (sz == TB9 && os > 3)
867 // generate an illegal procedure, illegal modifier fault
868 doFault (FAULT_IPR, fst_ill_mod,
869 "co size == TB9 && offset > 3");
870
871 // Save data in OU registers for readOperands/writeOperands
872
873 cpu.TPR.CA = Yi;
874 cpu.ou.character_address = Yi;
875 cpu.ou.characterOperandSize = sz;
876 cpu.ou.characterOperandOffset = os;
877
878 // CI uses the address, and SC uses the pre-increment address;
879 // but SCR use the post-decrement address
880 if (Td == IT_SCR)
881 {
882 // For each reference to the indirect word, the character
883 // counter, cf, is reduced by 1 and the TALLY field is
884 // increased by 1 before the computed address is formed.
885 //
886 // Character count arithmetic is modulo 6 for 6-bit
887 // characters and modulo 4 for 9-bit bytes. If the
888 // character count, cf, underflows to -1, it is reset to 5
889 // for 6-bit characters or to 3 for 9-bit bytes and ADDRESS
890 // is reduced by 1. ADDRESS arithmetic is modulo 2^18.
891 // TALLY arithmetic is modulo 4096.
892 //
893 // If the TALLY field overflows to 0, the tally runout
894 // indicator is set ON, otherwise it is set OFF. The
895 // computed address is the (possibly) decremented value of
896 // the ADDRESS field of the indirect word. The effective
897 // character/byte number is the decremented value of the
898 // character position count, cf, field of the indirect
899 // word.
900
901 if (os == 0)
902 {
903 if (sz == TB6)
904 os = 5;
905 else
906 os = 3;
907 Yi -= 1;
908 Yi &= MASK18;
909 }
910 else
911 {
912 os -= 1;
913 }
914
915 CPT (cpt2L, 5); // Update IT Tally; SCR
916 tally ++;
917 tally &= 07777; // keep to 12-bits
918
919 // Update saved values
920
921 cpu.TPR.CA = Yi;
922 cpu.ou.character_address = Yi;
923 cpu.ou.characterOperandSize = sz;
924 cpu.ou.characterOperandOffset = os;
925 }
926
927 // What if readOperands and/of writeOperands fault? On restart, doCAF will be
928 // called again and the indirect word would incorrectly be updated a second
929 // time.
930 //
931 // We don't care about read/write access violations; in general, they are not
932 // restarted.
933 //
934 // We can avoid page faults by preemptively fetching the data word.
935
936 //
937 // Get the data word
938 //
939
940 cpu.cu.pot = 1;
941
942 #if defined(LOCKLESSXXX)
943 // gives warnings as another lock is acquired in between
944 Read (cpu.TPR.CA, & cpu.ou.character_data, (i->info->flags & RMW) == \
945 STORE_OPERAND ? OPERAND_RMW : OPERAND_READ);
946 #else
947 ReadOperandRead (cpup, cpu.TPR.CA, & cpu.ou.character_data);
948 #endif
949 #if defined(LOCKLESS)
950 cpu.char_word_address = cpu.iefpFinalAddress;
951 #endif
952
953 sim_debug (DBG_ADDRMOD, & cpu_dev,
954 "IT_MOD CI/SC/SCR data=%012"PRIo64"\r\n",
955 cpu.ou.character_data);
956
957 cpu.cu.pot = 0;
958
959 if (Td == IT_SC)
960 {
961 // For each reference to the indirect word, the character
962 // counter, cf, is increased by 1 and the TALLY field is
963 // reduced by 1 after the computed address is formed.
964 // Character count arithmetic is modulo 6 for 6-bit
965 // characters and modulo 4 for 9-bit bytes. If the
966 // character count, cf, overflows to 6 for 6-bit characters
967 // or to 4 for 9-bit bytes, it is reset to 0 and ADDRESS is
968 // increased by 1. ADDRESS arithmetic is modulo 2^18. TALLY
969 // arithmetic is modulo 4096. If the TALLY field is reduced
970 // to 0, the tally runout indicator is set ON, otherwise it
971 // is set OFF.
972
973 os ++;
974
975 if (((sz == TB6) && (os > 5)) ||
976 ((sz == TB9) && (os > 3)))
977 {
978 os = 0;
979 Yi += 1;
980 Yi &= MASK18;
981 }
982 CPT (cpt2L, 6); // Update IT Tally; SC
983 tally --;
984 tally &= 07777; // keep to 12-bits
985 }
986
987 if (Td == IT_SC || Td == IT_SCR)
988 {
989 sim_debug (DBG_ADDRMOD, & cpu_dev,
990 "update IT tally now %o\r\n", tally);
991
992 //word36 new_indword = (word36) (((word36) Yi << 18) |
993 // (((word36) tally & 07777) << 6) |
994 // cpu.ou.characterOperandSize |
995 // cpu.ou.characterOperandOffset);
996 //Write (cpu.TPR.CA, new_indword, APU_DATA_STORE);
997 #if defined(LOCKLESS)
998 word36 indword_new;
999 core_read_lock(cpup, phys_address, &indword_new, __func__);
1000 if (indword_new != indword)
1001 sim_warn("indword changed from %llo to %llo\r\n",
1002 (long long unsigned int)indword,
1003 (long long unsigned int)indword_new);
1004 #endif
1005 putbits36_18 (& indword, 0, Yi);
1006 putbits36_12 (& indword, 18, tally);
1007 putbits36_3 (& indword, 33, os);
1008 #if defined(LOCKLESS)
1009 core_write_unlock(cpup, phys_address, indword, __func__);
1010 #else
1011 WriteAPUDataStore (cpup, indaddr, indword);
1012 #endif
1013
1014 SC_I_TALLY (tally == 0);
1015
1016 sim_debug (DBG_ADDRMOD, & cpu_dev,
1017 "update IT wrote tally word %012"PRIo64
1018 " to %06o\r\n",
1019 indword, cpu.TPR.CA);
1020 }
1021
1022 // readOperand and writeOperand will not use cpu.TPR.CA; they
1023 // will use the saved address, size, offset and data.
1024 cpu.TPR.CA = cpu.ou.character_address;
1025 return;
1026 } // IT_CI, IT_SC, IT_SCR
1027
1028 case IT_I: // Indirect (Td = 11)
1029 {
1030 sim_debug (DBG_ADDRMOD, & cpu_dev,
1031 "IT_MOD(IT_I): reading indirect word from %06o\r\n",
1032 cpu.TPR.CA);
1033
1034 //Read2 (cpu.TPR.CA, cpu.itxPair, INDIRECT_WORD_FETCH);
1035 ReadIndirect (cpup);
1036
1037 sim_debug (DBG_ADDRMOD, & cpu_dev,
1038 "IT_MOD(IT_I): indword=%012"PRIo64"\r\n",
1039 cpu.itxPair[0]);
1040
1041 cpu.TPR.CA = GET_ADDR (cpu.itxPair[0]);
1042 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1043 return;
1044 } // IT_I
1045
1046 case IT_AD: ///< Add delta (Td = 13)
1047 {
1048 // The TAG field of the indirect word is interpreted as a
1049 // 6-bit, unsigned, positive address increment value, delta.
1050 // For each reference to the indirect word, the ADDRESS field
1051 // is increased by delta and the TALLY field is reduced by 1
1052 // after the computed address is formed. ADDRESS arithmetic is
1053 // modulo 2^18. TALLY arithmetic is modulo 4096. If the TALLY
1054 // field is reduced to 0, the tally runout indicator is set ON,
1055 // otherwise it is set OFF. The computed address is the value
1056 // of the unmodified ADDRESS field of the indirect word.
1057
1058 sim_debug (DBG_ADDRMOD, & cpu_dev,
1059 "IT_MOD(IT_AD): reading indirect word from %06o\r\n",
1060 cpu.TPR.CA);
1061
1062 #if defined(THREADZ)
1063 lock_rmw ();
1064 #endif
1065
1066 word18 saveCA = cpu.TPR.CA;
1067 word36 indword;
1068 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1069
1070 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1071 delta = GET_DELTA (indword); // 6-bits
1072 Yi = GETHI (indword); // from where data live
1073
1074 sim_debug (DBG_ADDRMOD, & cpu_dev,
1075 "IT_MOD(IT_AD): indword=%012"PRIo64"\r\n",
1076 indword);
1077 sim_debug (DBG_ADDRMOD, & cpu_dev,
1078 "IT_MOD(IT_AD): address:%06o tally:%04o "
1079 "delta:%03o\r\n",
1080 Yi, cpu.AM_tally, delta);
1081
1082 cpu.TPR.CA = Yi;
1083 word18 computedAddress = cpu.TPR.CA;
1084
1085 Yi += delta;
1086 Yi &= MASK18;
1087
1088 cpu.AM_tally -= 1;
1089 cpu.AM_tally &= 07777; // keep to 12-bits
1090 // breaks emacs
1091 //if (cpu.AM_tally == 0)
1092 //SET_I_TALLY;
1093 SC_I_TALLY (cpu.AM_tally == 0);
1094 indword = (word36) (((word36) Yi << 18) |
1095 (((word36) cpu.AM_tally & 07777) << 6) |
1096 delta);
1097 #if defined(LOCKLESS)
1098 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1099 #else
1100 WriteAPUDataStore (cpup, saveCA, indword);
1101 #endif
1102
1103 #if defined(THREADZ)
1104 unlock_rmw ();
1105 #endif
1106
1107 sim_debug (DBG_ADDRMOD, & cpu_dev,
1108 "IT_MOD(IT_AD): wrote tally word %012"PRIo64
1109 " to %06o\r\n",
1110 indword, saveCA);
1111
1112 cpu.TPR.CA = computedAddress;
1113 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1114 return;
1115 } // IT_AD
1116
1117 case IT_SD: ///< Subtract delta (Td = 4)
1118 {
1119 // The TAG field of the indirect word is interpreted as a
1120 // 6-bit, unsigned, positive address increment value, delta.
1121 // For each reference to the indirect word, the ADDRESS field
1122 // is reduced by delta and the TALLY field is increased by 1
1123 // before the computed address is formed. ADDRESS arithmetic is
1124 // modulo 2^18. TALLY arithmetic is modulo 4096. If the TALLY
1125 // field overflows to 0, the tally runout indicator is set ON,
1126 // otherwise it is set OFF. The computed address is the value
1127 // of the decremented ADDRESS field of the indirect word.
1128
1129 #if defined(THREADZ)
1130 lock_rmw ();
1131 #endif
1132
1133 word18 saveCA = cpu.TPR.CA;
1134 word36 indword;
1135 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1136
1137 sim_debug (DBG_ADDRMOD, & cpu_dev,
1138 "IT_MOD(IT_SD): reading indirect word from %06o\r\n",
1139 cpu.TPR.CA);
1140 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1141 delta = GET_DELTA (indword); // 6-bits
1142 Yi = GETHI (indword); // from where data live
1143
1144 sim_debug (DBG_ADDRMOD, & cpu_dev,
1145 "IT_MOD(IT_SD): indword=%012"PRIo64"\r\n",
1146 indword);
1147 sim_debug (DBG_ADDRMOD, & cpu_dev,
1148 "IT_MOD(IT_SD): address:%06o tally:%04o "
1149 "delta:%03o\r\n",
1150 Yi, cpu.AM_tally, delta);
1151
1152 Yi -= delta;
1153 Yi &= MASK18;
1154 cpu.TPR.CA = Yi;
1155
1156 cpu.AM_tally += 1;
1157 cpu.AM_tally &= 07777; // keep to 12-bits
1158 if (cpu.AM_tally == 0)
1159 SET_I_TALLY;
1160
1161 // write back out indword
1162 indword = (word36) (((word36) Yi << 18) |
1163 (((word36) cpu.AM_tally & 07777) << 6) |
1164 delta);
1165 #if defined(LOCKLESS)
1166 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1167 #else
1168 WriteAPUDataStore (cpup, saveCA, indword);
1169 #endif
1170
1171 #if defined(THREADZ)
1172 unlock_rmw ();
1173 #endif
1174
1175 sim_debug (DBG_ADDRMOD, & cpu_dev,
1176 "IT_MOD(IT_SD): wrote tally word %012"PRIo64
1177 " to %06o\r\n",
1178 indword, saveCA);
1179
1180 cpu.TPR.CA = Yi;
1181 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1182 return;
1183 } // IT_SD
1184
1185 case IT_DI: ///< Decrement address, increment tally (Td = 14)
1186 {
1187 // For each reference to the indirect word, the ADDRESS field
1188 // is reduced by 1 and the TALLY field is increased by 1 before
1189 // the computed address is formed. ADDRESS arithmetic is modulo
1190 // 2^18. TALLY arithmetic is modulo 4096. If the TALLY field
1191 // overflows to 0, the tally runout indicator is set ON,
1192 // otherwise it is set OFF. The TAG field of the indirect word
1193 // is ignored. The computed address is the value of the
1194 // decremented ADDRESS field.
1195
1196 sim_debug (DBG_ADDRMOD, & cpu_dev,
1197 "IT_MOD(IT_DI): reading indirect word from %06o\r\n",
1198 cpu.TPR.CA);
1199
1200 #if defined(THREADZ)
1201 lock_rmw ();
1202 #endif
1203
1204 word18 saveCA = cpu.TPR.CA;
1205 word36 indword;
1206 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1207
1208 Yi = GETHI (indword);
1209 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1210 word6 junk = GET_TAG (indword); // get tag field, but ignore it
1211
1212 sim_debug (DBG_ADDRMOD, & cpu_dev,
1213 "IT_MOD(IT_DI): indword=%012"PRIo64"\r\n",
1214 indword);
1215 sim_debug (DBG_ADDRMOD, & cpu_dev,
1216 "IT_MOD(IT_DI): address:%06o tally:%04o\r\n",
1217 Yi, cpu.AM_tally);
1218
1219 Yi -= 1;
1220 Yi &= MASK18;
1221 cpu.TPR.CA = Yi;
1222
1223 cpu.AM_tally += 1;
1224 cpu.AM_tally &= 07777; // keep to 12-bits
1225 SC_I_TALLY (cpu.AM_tally == 0);
1226
1227 // write back out indword
1228
1229 indword = (word36) (((word36) cpu.TPR.CA << 18) |
1230 ((word36) cpu.AM_tally << 6) |
1231 junk);
1232
1233 sim_debug (DBG_ADDRMOD, & cpu_dev,
1234 "IT_MOD(IT_DI): writing indword=%012"PRIo64" to "
1235 "addr %06o\r\n",
1236 indword, saveCA);
1237
1238 #if defined(LOCKLESS)
1239 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1240 #else
1241 WriteAPUDataStore (cpup, saveCA, indword);
1242 #endif
1243
1244 #if defined(THREADZ)
1245 unlock_rmw ();
1246 #endif
1247 cpu.TPR.CA = Yi;
1248 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1249 return;
1250 } // IT_DI
1251
1252 case IT_ID: ///< Increment address, decrement tally (Td = 16)
1253 {
1254 // For each reference to the indirect word, the ADDRESS field
1255 // is increased by 1 and the TALLY field is reduced by 1 after
1256 // the computed address is formed. ADDRESS arithmetic is modulo
1257 // 2^18. TALLY arithmetic is modulo 4096. If the TALLY field is
1258 // reduced to 0, the tally runout indicator is set ON,
1259 // otherwise it is set OFF. The TAG field of the indirect word
1260 // is ignored. The computed address is the value of the
1261 // unmodified ADDRESS field.
1262
1263 word18 saveCA = cpu.TPR.CA;
1264
1265 sim_debug (DBG_ADDRMOD, & cpu_dev,
1266 "IT_MOD(IT_ID): fetching indirect word from %06o\r\n",
1267 cpu.TPR.CA);
1268
1269 #if defined(THREADZ)
1270 lock_rmw ();
1271 #endif
1272
1273 word36 indword;
1274 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1275
1276 Yi = GETHI (indword);
1277 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1278 // get tag field, but ignore it
1279 word6 junk = GET_TAG (indword);
1280 sim_debug (DBG_ADDRMOD, & cpu_dev,
1281 "IT_MOD(IT_ID): indword=%012"PRIo64
1282 " Yi=%06o tally=%04o\r\n",
1283 indword, Yi, cpu.AM_tally);
1284
1285 cpu.TPR.CA = Yi;
1286 word18 computedAddress = cpu.TPR.CA;
1287
1288 Yi += 1;
1289 Yi &= MASK18;
1290
1291 cpu.AM_tally -= 1;
1292 cpu.AM_tally &= 07777; // keep to 12-bits
1293
1294 // XXX Breaks boot?
1295 //if (cpu.AM_tally == 0)
1296 //SET_I_TALLY;
1297 SC_I_TALLY (cpu.AM_tally == 0);
1298
1299 // write back out indword
1300 indword = (word36) (((word36) Yi << 18) |
1301 ((word36) cpu.AM_tally << 6) |
1302 junk);
1303
1304 sim_debug (DBG_ADDRMOD, & cpu_dev,
1305 "IT_MOD(IT_ID): writing indword=%012"PRIo64" to "
1306 "addr %06o\r\n",
1307 indword, saveCA);
1308
1309 #if defined(LOCKLESS)
1310 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1311 #else
1312 WriteAPUDataStore (cpup, saveCA, indword);
1313 #endif
1314
1315 #if defined(THREADZ)
1316 unlock_rmw ();
1317 #endif
1318
1319 cpu.TPR.CA = computedAddress;
1320 updateIWB (cpup, cpu.TPR.CA, (TM_R|TD_N));
1321 return;
1322 } // IT_ID
1323
1324 // Decrement address, increment tally, and continue (Td = 15)
1325 case IT_DIC:
1326 {
1327 // The action for this variation is identical to that for the
1328 // decrement address, increment tally variation except that the
1329 // TAG field of the indirect word is interpreted and
1330 // continuation of the indirect chain is possible. If the TAG
1331 // of the indirect word invokes a register, that is, specifies
1332 // r, ri, or ir modification, the effective Td value for the
1333 // register is forced to "null" before the next computed
1334 // address is formed.
1335
1336 // a:RJ78/idc1
1337 // The address and tally fields are used as described under the
1338 // ID variation. The tag field uses the set of variations for
1339 // instruction address modification under the following
1340 // restrictions: no variation is permitted that requires an
1341 // indexing modification in the DIC cycle since the indexing
1342 // adder is being used by the tally phase of the operation.
1343 // Thus, permissible variations are any allowable form of IT or
1344 // IR, but if RI or R is used, R must equal N (RI and R forced
1345 // to N).
1346
1347 sim_debug (DBG_ADDRMOD, & cpu_dev,
1348 "IT_MOD(IT_DIC): fetching indirect word from %06o\r\n",
1349 cpu.TPR.CA);
1350
1351 #if defined(THREADZ)
1352 lock_rmw ();
1353 #endif
1354
1355 word18 saveCA = cpu.TPR.CA;
1356 word36 indword;
1357 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1358
1359 cpu.cu.pot = 0;
1360
1361 Yi = GETHI (indword);
1362 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1363 idwtag = GET_TAG (indword);
1364
1365 sim_debug (DBG_ADDRMOD, & cpu_dev,
1366 "IT_MOD(IT_DIC): indword=%012"PRIo64" Yi=%06o "
1367 "tally=%04o idwtag=%02o\r\n",
1368 indword, Yi, cpu.AM_tally, idwtag);
1369
1370 word24 YiSafe2 = Yi; // save indirect address for later use
1371
1372 Yi -= 1;
1373 Yi &= MASK18;
1374
1375 cpu.AM_tally += 1;
1376 cpu.AM_tally &= 07777; // keep to 12-bits
1377 // Set the tally after the indirect word is processed; if it faults, the IR
1378 // should be unchanged. ISOLTS ps791 test-02g
1379 //SC_I_TALLY (cpu.AM_tally == 0);
1380 //if (cpu.AM_tally == 0)
1381 //SET_I_TALLY;
1382
1383 // write back out indword
1384 indword = (word36) (((word36) Yi << 18) |
1385 ((word36) cpu.AM_tally << 6) | idwtag);
1386
1387 sim_debug (DBG_ADDRMOD, & cpu_dev,
1388 "IT_MOD(IT_DIC): writing indword=%012"PRIo64" to "
1389 "addr %06o\r\n", indword, saveCA);
1390
1391 #if defined(LOCKLESS)
1392 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1393 #else
1394 WriteAPUDataStore (cpup, saveCA, indword);
1395 #endif
1396
1397 #if defined(THREADZ)
1398 unlock_rmw ();
1399 #endif
1400 // If the TAG of the indirect word invokes a register, that is,
1401 // specifies r, ri, or ir modification, the effective Td value
1402 // for the register is forced to "null" before the next
1403 // computed address is formed.
1404
1405 // Thus, permissible variations are any allowable form of IT or
1406 // IR, but if RI or R is used, R must equal N (RI and R forced
1407 // to N).
1408 cpu.TPR.CA = Yi;
1409
1410 sim_debug (DBG_ADDRMOD, & cpu_dev,
1411 "IT_MOD(IT_DIC): new CT_HOLD %02o new TAG %02o\r\n",
1412 cpu.rTAG, idwtag);
1413 cpu.cu.CT_HOLD = cpu.rTAG;
1414 cpu.rTAG = idwtag;
1415
1416 Tm = GET_TM (cpu.rTAG);
1417 if (Tm == TM_RI || Tm == TM_R)
1418 {
1419 if (GET_TD (cpu.rTAG) != 0)
1420 {
1421 doFault (FAULT_IPR, fst_ill_mod,
1422 "DIC Incorrect address modifier");
1423 }
1424 }
1425
1426 // Set the tally after the indirect word is processed; if it faults, the IR
1427 // should be unchanged. ISOLTS ps791 test-02g
1428 SC_I_TALLY (cpu.AM_tally == 0);
1429 if (cpu.tweaks.isolts_mode)
1430 updateIWB (cpup, YiSafe2, cpu.rTAG);
1431 else
1432 updateIWB (cpup, cpu.TPR.CA, cpu.rTAG);
1433 goto startCA;
1434 } // IT_DIC
1435
1436 // Increment address, decrement tally, and continue (Td = 17)
1437 case IT_IDC:
1438 {
1439 // The action for this variation is identical to that for the
1440 // increment address, decrement tally variation except that the
1441 // TAG field of the indirect word is interpreted and
1442 // continuation of the indirect chain is possible. If the TAG
1443 // of the indirect word invokes a register, that is, specifies
1444 // r, ri, or ir modification, the effective Td value for the
1445 // register is forced to "null" before the next computed
1446 // address is formed.
1447
1448 // a:RJ78/idc1
1449 // The address and tally fields are used as described under the
1450 // ID variation. The tag field uses the set of variations for
1451 // instruction address modification under the following
1452 // restrictions: no variation is permitted that requires an
1453 // indexing modification in the IDC cycle since the indexing
1454 // adder is being used by the tally phase of the operation.
1455 // Thus, permissible variations are any allowable form of IT or
1456 // IR, but if RI or R is used, R must equal N (RI and R forced
1457 // to N).
1458
1459 sim_debug (DBG_ADDRMOD, & cpu_dev,
1460 "IT_MOD(IT_IDC): fetching indirect word from %06o\r\n",
1461 cpu.TPR.CA);
1462
1463 #if defined(THREADZ)
1464 lock_rmw ();
1465 #endif
1466
1467 word18 saveCA = cpu.TPR.CA;
1468 word36 indword;
1469 ReadAPUDataRMW (cpup, cpu.TPR.CA, & indword);
1470
1471 cpu.cu.pot = 0;
1472
1473 Yi = GETHI (indword);
1474 cpu.AM_tally = GET_TALLY (indword); // 12-bits
1475 idwtag = GET_TAG (indword);
1476
1477 sim_debug (DBG_ADDRMOD, & cpu_dev,
1478 "IT_MOD(IT_IDC): indword=%012"PRIo64" Yi=%06o "
1479 "tally=%04o idwtag=%02o\r\n",
1480 indword, Yi, cpu.AM_tally, idwtag);
1481
1482 word24 YiSafe = Yi; // save indirect address for later use
1483
1484 Yi += 1;
1485 Yi &= MASK18;
1486
1487 cpu.AM_tally -= 1;
1488 cpu.AM_tally &= 07777; // keep to 12-bits
1489 // Set the tally after the indirect word is processed; if it faults, the IR
1490 // should be unchanged. ISOLTS ps791 test-02f
1491 //SC_I_TALLY (cpu.AM_tally == 0);
1492
1493 // write back out indword
1494 indword = (word36) (((word36) Yi << 18) |
1495 ((word36) cpu.AM_tally << 6) |
1496 idwtag);
1497
1498 sim_debug (DBG_ADDRMOD, & cpu_dev,
1499 "IT_MOD(IT_IDC): writing indword=%012"PRIo64""
1500 " to addr %06o\r\n",
1501 indword, saveCA);
1502
1503 #if defined(LOCKLESS)
1504 core_write_unlock(cpup, cpu.iefpFinalAddress, indword, __func__);
1505 #else
1506 WriteAPUDataStore (cpup, saveCA, indword);
1507 #endif
1508
1509 #if defined(THREADZ)
1510 unlock_rmw ();
1511 #endif
1512
1513 // If the TAG of the indirect word invokes a register, that is,
1514 // specifies r, ri, or ir modification, the effective Td value
1515 // for the register is forced to "null" before the next
1516 // computed address is formed.
1517 // But for the dps88 you can use everything but ir/ri.
1518
1519 // Thus, permissible variations are any allowable form of IT or
1520 // IR, but if RI or R is used, R must equal N (RI and R forced
1521 // to N).
1522 cpu.TPR.CA = YiSafe;
1523
1524 sim_debug (DBG_ADDRMOD, & cpu_dev,
1525 "IT_MOD(IT_IDC): new CT_HOLD %02o new TAG %02o\r\n",
1526 cpu.rTAG, idwtag);
1527 cpu.cu.CT_HOLD = cpu.rTAG;
1528 cpu.rTAG = idwtag;
1529
1530 Tm = GET_TM (cpu.rTAG);
1531 if (Tm == TM_RI || Tm == TM_R)
1532 {
1533 if (GET_TD (cpu.rTAG) != 0)
1534 {
1535 doFault (FAULT_IPR, fst_ill_mod,
1536 "IDC Incorrect address modifier");
1537 }
1538 }
1539
1540 // Set the tally after the indirect word is processed; if it faults, the IR
1541 // should be unchanged. ISOLTS ps791 test-02f
1542 SC_I_TALLY (cpu.AM_tally == 0);
1543 updateIWB (cpup, cpu.TPR.CA, cpu.rTAG);
1544
1545 goto startCA;
1546 } // IT_IDC
1547 } // Td
1548 sim_printf ("IT_MOD/Td how did we get here?\r\n");
1549 return;
1550 } // IT_MOD
1551 } // do_caf