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