1 /*
2 * vim: filetype=c:tabstop=4:ai:expandtab
3 * SPDX-License-Identifier: ICU
4 * scspell-id: 72d91a53-f62d-11ec-a98f-80ee73e9b8e7
5 *
6 * ---------------------------------------------------------------------------
7 *
8 * Copyright (c) 2007-2013 Michael Mondy
9 * Copyright (c) 2012-2016 Harry Reed
10 * Copyright (c) 2013-2022 Charles Anthony
11 * Copyright (c) 2015-2021 Eric Swenson
12 * Copyright (c) 2021-2022 The DPS8M Development Team
13 *
14 * All rights reserved.
15 *
16 * This software is made available under the terms of the ICU
17 * License, version 1.8.1 or later. For more details, see the
18 * LICENSE.md file at the top-level directory of this distribution.
19 *
20 * ---------------------------------------------------------------------------
21 */
22
23 #ifndef __STDC_WANT_IEC_60559_BFP_EXT__
24 # define __STDC_WANT_IEC_60559_BFP_EXT__ 1
25 #endif /* ifndef __STDC_WANT_IEC_60559_BFP_EXT__ */
26
27 #include <sys/types.h>
28
29 #ifdef __APPLE__
30 # undef SCHED_NEVER_YIELD
31 # define SCHED_NEVER_YIELD 1
32 # include <mach/thread_policy.h>
33 # include <mach/task_info.h>
34 # include <sys/types.h>
35 # include <sys/sysctl.h>
36 # include <mach/thread_policy.h>
37 # include <mach/thread_act.h>
38 #endif /* ifdef __APPLE__ */
39
40 #include "../simh/sim_timer.h"
41 #include "hdbg.h"
42
43 #define N_CPU_UNITS 1 // Default
44
45 // JMP_ENTRY must be 0, which is the return value of the setjmp initial
46 // entry
47 #define JMP_ENTRY 0
48 #define JMP_REENTRY 1
49 #define JMP_STOP 2
50 #define JMP_SYNC_FAULT_RETURN 3
51 #define JMP_REFETCH 4
52 #define JMP_RESTART 5
53
54 // The CPU supports 3 addressing modes
55 // [CAC] I tell a lie: 4 modes...
56 // [CAC] I tell another lie: 5 modes...
57
58 typedef enum
59 {
60 ABSOLUTE_mode,
61 APPEND_mode,
62 } addr_modes_e;
63
64 // The control unit of the CPU is always in one of several states. We
65 // don't currently use all of the states used in the physical CPU.
66 // The FAULT_EXEC cycle did not exist in the physical hardware.
67
68 typedef enum
69 {
70 FAULT_cycle,
71 EXEC_cycle,
72 FAULT_EXEC_cycle,
73 INTERRUPT_cycle,
74 INTERRUPT_EXEC_cycle,
75 FETCH_cycle,
76 PSEUDO_FETCH_cycle,
77 SYNC_FAULT_RTN_cycle,
78 } cycles_e;
79
80 struct tpr_s
81 {
82 word3 TRR; // The current effective ring number
83 word15 TSR; // The current effective segment number
84 word6 TBR; // The current bit offset as calculated from ITS and ITP
85 // pointer pairs.
86 word18 CA; // The current computed address relative to the origin of the
87 // segment whose segment number is in TPR.TSR
88 };
89
90 struct ppr_s
91 {
92 word3 PRR; // The number of the ring in which the process is executing.
93 // It is set to the effective ring number of the procedure
94 // segment when control is transferred to the procedure.
95 word15 PSR; // The segment number of the procedure being executed.
96 word1 P; // A flag controlling execution of privileged instructions.
97 // Its value is 1 (permitting execution of privileged
98 // instructions) if PPR.PRR is 0 and the privileged bit in
99 // the segment descriptor word (SDW.P) for the procedure is
100 // 1; otherwise, its value is 0.
101 word18 IC; // The word offset from the origin of the procedure segment
102 // to the current instruction. (same as PPR.IC)
103 };
104
105 /////
106 // The terms "pointer register" and "address register" both apply to the same
107 // physical hardware. The distinction arises from the manner in which the
108 // register is used and in the interpretation of the register contents.
109 // "Pointer register" refers to the register as used by the appending unit and
110 // "address register" refers to the register as used by the decimal unit.
111 //
112 // The three forms are compatible and may be freely intermixed. For example,
113 // PRn may be loaded in pointer register form with the Effective Pointer to
114 // Pointer Register n (eppn) instruction, then modified in pointer register
115 // form with the Effective Address to Word/Bit Number of Pointer Register n
116 // (eawpn) instruction, then further modified in address register form
117 // (assuming character size k) with the Add k-Bit Displacement to Address
118 // Register (akbd) instruction, and finally invoked in operand descriptor form
119 // by the use of MF.AR in an EIS multiword instruction .
120 //
121 // The reader's attention is directed to the presence of two bit number
122 // registers, PRn.BITNO and ARn.BITNO. Because the Multics processor was
123 // implemented as an enhancement to an existing design, certain apparent
124 // anomalies appear. One of these is the difference in the handling of
125 // unaligned data items by the appending unit and decimal unit. The decimal
126 // unit handles all unaligned data items with a 9-bit byte number and bit
127 // offset within the byte. Conversion from the description given in the EIS
128 // operand descriptor is done automatically by the hardware. The appending unit
129 // maintains compatibility with the earlier generation Multics processor by
130 // handling all unaligned data items with a bit offset from the prior word
131 // boundary; again with any necessary conversion done automatically by the
132 // hardware. Thus, a pointer register, PRn, may be loaded from an ITS pointer
133 // pair having a pure bit offset and modified by one of the EIS address
134 // register instructions (a4bd, s9bd, etc.) using character displacement
135 // counts. The automatic conversion performed ensures that the pointer
136 // register, PRi, and its matching address register, ARi, both describe the
137 // same physical bit in main memory.
138 //
139 // N.B. Subtle differences between the interpretation of PR/AR. Need to take
140 // this into account.
141 //
142 // * For Pointer Registers:
143 // - PRn.WORDNO The offset in words from the base or origin of the
144 // segment to the data item.
145 // - PRn.BITNO The number of the bit within PRn.WORDNO that is the
146 // first bit of the data item. Data items aligned on word
147 // boundaries always have the value 0. Unaligned data items
148 // may have any value in the range [1,35].
149 //
150 // * For Address Registers:
151 // - ARn.WORDNO The offset in words relative to the current addressing
152 // base referent (segment origin, BAR.BASE, or absolute 0
153 // depending on addressing mode) to the word containing the
154 // next data item element.
155 // - ARn.CHAR The number of the 9-bit byte within ARn.WORDNO
156 // containing the first bit of the next data item element.
157 // - ARn.BITNO The number of the bit within ARn.CHAR that is the
158 // first bit of the next data item element.
159 /////
160
161 struct par_s
162 {
163 word15 SNR; // The segment number of the segment containing the data
164 // item described by the pointer register.
165 word3 RNR; // The final effective ring number value calculated during
166 // execution of the instruction that last loaded the PR.
167
168 word6 PR_BITNO; // The number of the bit within PRn.WORDNO that is the
169 // first bit of the data item. Data items aligned on word
170 // boundaries always have the value 0. Unaligned data
171 // items may have any value in the range [1,35].
172 word2 AR_CHAR;
173 word4 AR_BITNO;
174
175 word18 WORDNO; // The offset in words from the base or origin of the
176 // segment to the data item.
177 };
178
179 // N.B. remember there are subtle differences between AR/PR.BITNO
180
181 #define AR PAR
182 #define PR PAR
183
184 struct bar_s
185 {
186 word9 BASE; // Contains the 9 high-order bits of an 18-bit address
187 // relocation constant. The low-order bits are generated
188 // as zeros.
189 word9 BOUND; // Contains the 9 high-order bits of the unrelocated
190 // address limit. The low- order bits are generated as
191 // zeros. An attempt to access main memory beyond this
192 // limit causes a store fault, out of bounds. A value of
193 // 0 is truly 0, indicating a null memory range.
194 };
195
196 struct dsbr_s
197 {
198 word24 ADDR; // If DSBR.U = 1, the 24-bit absolute main memory address
199 // of the origin of the current descriptor segment;
200 // otherwise, the 24-bit absolute main memory address of
201 // the page table for the current descriptor segment.
202 word14 BND; // The 14 most significant bits of the highest Y-block16
203 // address of the descriptor segment that can be
204 // addressed without causing an access violation, out of
205 // segment bounds, fault.
206 word1 U; // A flag specifying whether the descriptor segment is
207 // unpaged (U = 1) or paged (U = 0).
208 word12 STACK; // The upper 12 bits of the 15-bit stack base segment
209 // number. It is used only during the execution of the
210 // call6 instruction. (See Section 8 for a discussion
211 // of generation of the stack segment number.)
212 };
213
214 // The segment descriptor word (SDW) pair contains information that controls
215 // the access to a segment. The SDW for segment n is located at offset 2n in
216 // the descriptor segment whose description is currently loaded into the
217 // descriptor segment base register (DSBR).
218
219 struct sdw_s
220 {
221 word24 ADDR; // The 24-bit absolute main memory address of the page
222 // table for the target segment if SDWAM.U = 0;
223 // otherwise, the 24-bit absolute main memory address
224 // of the origin of the target segment.
225 word3 R1; // Upper limit of read/write ring bracket
226 word3 R2; // Upper limit of read/execute ring bracket
227 word3 R3; // Upper limit of call ring bracket
228 word14 BOUND; // The 14 high-order bits of the last Y-block16 address
229 // within the segment that can be referenced without an
230 // access violation, out of segment bound, fault.
231 word1 R; // Read permission bit. If this bit is set ON, read
232 // access requests are allowed.
233 word1 E; // Execute permission bit. If this bit is set ON, the SDW
234 // may be loaded into the procedure pointer register
235 // (PPR) and instructions fetched from the segment for
236 // execution.
237 word1 W; // Write permission bit. If this bit is set ON, write
238 // access requests are allowed.
239 word1 P; // Privileged flag bit. If this bit is set ON, privileged
240 // instructions from the segment may be executed if
241 // PPR.PRR is 0.
242 word1 U; // Unpaged flag bit. If this bit is set ON, the segment
243 // is unpaged and SDWAM.ADDR is the 24-bit absolute
244 // main memory address of the origin of the segment. If
245 // this bit is set OFF, the segment is paged andis
246 // SDWAM.ADDR the 24-bit absolute main memory address of
247 // the page table for the segment.
248 word1 G; // Gate control bit. If this bit is set OFF, calls and
249 // transfers into the segment must be to an offset no
250 // greater than the value of SDWAM.CL as described
251 // below.
252 word1 C; // Cache control bit. If this bit is set ON, data and/or
253 // instructions from the segment may be placed in the
254 // cache memory.
255 word14 EB; // Call limiter (entry bound) value. If SDWAM.G is set
256 // OFF, transfers of control into the segment must be to
257 // segment addresses no greater than this value.
258 word15 POINTER; // The effective segment number used to fetch this SDW
259 // from main memory.
260 word1 DF; // Directed fault flag (called F in AL39).
261 // * 0 = page not in main memory; execute directed fault
262 // FC
263 // * 1 = page is in main memory
264 word2 FC; // Directed fault number for page fault.
265 word1 FE; // Full/empty bit. If this bit is set ON, the SDW in the
266 // register is valid. If this bit is set OFF, a hit is
267 // not possible. All SDWAM.F bits are set OFF by the
268 // instructions that clear the SDWAM.
269 // L68: word4
270 // DPS8M: word6
271 word6 USE;
272 // Usage count for the register. The SDWAM.USE field is
273 // used to maintain a strict FIFO queue order among the
274 // SDWs. When an SDW is matched, its USE value is set to
275 // 15 (newest) on the DPS/L68 and to 63 on the DPS 8M,
276 // and the queue is reordered. SDWs newly fetched from
277 // main memory replace the SDW with USE value 0 (oldest)
278 // and the queue is reordered.
279 };
280
281 typedef struct sdw_s sdw_s;
282 typedef struct sdw_s sdw0_s;
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338 // PTW as used by APU
339
340 struct ptw_s
341 {
342 word18 ADDR; // The 18 high-order bits of the 24-bit absolute
343 // main memory address of the page.
344 word1 U; // * 1 = page has been used (referenced)
345 word1 M; // Page modified flag bit. This bit is set ON whenever
346 // the PTW is used for a store type instruction. When
347 // the bit changes value from 0 to 1, a special
348 // extra cycle is generated to write it back into the
349 // PTW in the page table in main memory.
350 word1 DF; // Directed fault flag
351 // * 0 = page not in main memory; execute directed fault FC
352 // * 1 = page is in main memory
353 word2 FC; // Directed fault number for page fault.
354 word15 POINTER; // The effective segment number used to fetch this PTW
355 // from main memory.
356 word12 PAGENO; // The 12 high-order bits of the 18-bit computed
357 // address (TPR.CA) used to fetch this PTW from main
358 // memory.
359 word1 FE; // Full/empty bit. If this bit is set ON, the PTW in
360 // the register is valid. If this bit is set OFF, a
361 // hit is not possible. All PTWAM.F bits are set OFF
362 // by the instructions that clear the PTWAM.
363 // DPS8M: word6
364 // L68: word4
365 word6 USE;
366 // Usage count for the register. The PTWAM.USE field
367 // is used to maintain a strict FIFO queue order
368 // among the PTWs. When an PTW is matched its USE
369 // value is set to 15 (newest) on the DPS/L68 and to
370 // 63 on the DPS 8M, and the queue is reordered.
371 // PTWs newly fetched from main memory replace the
372 // PTW with USE value 0 (oldest) and the queue is
373 // reordered.
374 };
375
376 typedef struct ptw_s ptw_s;
377 typedef struct ptw_s ptw0_s;
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398 //
399 // Cache Mode Register
400 //
401
402 struct cache_mode_register_s
403 {
404 word15 cache_dir_address;
405 word1 par_bit;
406 word1 lev_ful;
407 word1 csh1_on; // 1: The lower half of the cache memory is active and
408 // enabled as per the state of inst_on
409 word1 csh2_on; // 1: The upper half of the cache memory is active and
410 // enabled as per the state of inst_on
411 // L68 only
412 word1 opnd_on; // 1: The cache memory (if active) is used for operands.
413
414 word1 inst_on; // 1: The cache memory (if active) is used for
415 // instructions.
416 // When the cache-to-register mode flag (bit 59 of the cache mode register)
417 // is set ON, the processor is forced to fetch the operands of all
418 // double-precision operations unit load operations from the cache memory.
419 // Y0,12 are ignored, Y15,21 select a column, and Y13,14 select a level.
420 // All other operations (e.g., instruction fetches, single-precision
421 // operands, etc.) are treated normally.
422 word1 csh_reg;
423 word1 str_asd;
424 word1 col_ful;
425 word2 rro_AB;
426 word1 bypass_cache; // DPS8M only
427 word2 luf; // LUF value
428 // 0 1 2 3
429 // Lockup time
430 // 2ms 4ms 8ms 16ms
431 // The lockup timer is set to 16ms when the
432 // processor is initialized.
433 };
434
435 typedef struct cache_mode_register_s cache_mode_register_s;
436
437 typedef struct mode_register_s
438 {
439 word36 r;
440 // L68 only
441 // 8M L68
442 word15 FFV; // 0 FFV 0 - 14
443 word1 OC_TRAP; // 0 a 16
444 word1 ADR_TRAP; // 0 b 17
445 word9 OPCODE; // 0 OPCODE 18 - 26
446 word1 OPCODEX; // 0 OPCODE 27
447
448 // word1 cuolin; // a c 18 control unit overlap inhibit
449 // word1 solin; // b d 19 store overlap inhibit
450 word1 sdpap; // c e 20 store incorrect data parity
451 word1 separ; // d f 21 store incorrect ZAC
452 // word2 tm; // e g 22 - 23 timing margins
453 // word2 vm; // f h 24 - 25 voltage margins
454 // 0 0 26 history register overflow trap
455 // 0 0 27 strobe HR on opcode match
456 word1 hrhlt; // g i 28 history register overflow trap
457
458 // DPS8M only
459 word1 hrxfr; // h j 29 strobe HR on transfer made
460 // L68 only
461 // h j 29 strobe HR on opcode match
462 word1 ihr; // i k 30 Enable HR
463 word1 ihrrs; // j 31 HR reset options
464 // l 31 HR lock control
465 // k 32 margin control
466 // m 32 test mode indicator
467 // DPS8M only
468 word1 hexfp; // l 0 33 hex mode
469 // 0 0 34
470 word1 emr; // m n 35 enable MR
471 } mode_register_s;
472
473 extern DEVICE cpu_dev;
474
475 typedef struct MOP_struct_s
476 {
477 char * mopName; // name of microoperation
478 int (* f) (void); // pointer to mop() [returns character to be stored]
479 } MOP_struct;
480
481 // address of an EIS operand
482 typedef struct EISaddr_s
483 {
484 #ifndef EIS_PTR
485 word18 address; // 18-bit virtual address
486 #endif
487
488 word36 data;
489 word1 bit;
490 eRW mode;
491
492 int last_bit_posn; // track for caching tests
493
494 // for type of data being address by this object
495
496 // eisDataType _type; // type of data - alphanumeric/numeric
497
498 #ifndef EIS_PTR3
499 int TA; // type of Alphanumeric chars in src
500 #endif
501 int TN; // type of Numeric chars in src
502 int cPos;
503 int bPos;
504
505 #ifndef EIS_PTR4
506 // for when using AR/PR register addressing
507 word15 SNR; // The segment number of the segment containing the
508 // data item described by the pointer register.
509 word3 RNR; // The effective ring number value calculated during
510 // execution of the instruction that last loaded
511 MemoryAccessType mat; // memory access type for operation
512 #endif
513
514 // Cache
515
516 // There is a cache for each operand, but they do not cross check;
517 // this means that if one of them has a cached dirty word, the
518 // others will not check for a hit, and will use the old value.
519 // AL39 warns that overlapping operands can cause unexpected behavior
520 // due to caching issues, so the this behavior is closer to the actual
521 // h/w then to the theoretical need for cache consistency.
522
523 // We don't need to cache mat or TPR because they will be constant
524 // across an instruction.
525
526 bool cacheValid;
527 bool cacheDirty;
528 #define paragraphSz 8
529 #define paragraphMask 077777770
530 #define paragraphOffsetMask 07
531 word36 cachedParagraph [paragraphSz];
532 bool wordDirty [paragraphSz];
533 word18 cachedAddr;
534
535 } EISaddr;
536
537 typedef struct EISstruct_s
538 {
539 word36 op [3]; // raw operand descriptors
540 #define OP1 op [0] // 1st descriptor (2nd ins word)
541 #define OP2 op [1] // 2nd descriptor (3rd ins word)
542 #define OP3 op [2] // 3rd descriptor (4th ins word)
543
544 bool P; // 4-bit data sign character control
545
546 uint MF [3];
547 #define MF1 MF [0] // Modification field for operand descriptor 1
548 #define MF2 MF [1] // Modification field for operand descriptor 2
549 #define MF3 MF [2] // Modification field for operand descriptor 3
550
551 uint CN [3];
552 #define CN1 CN [0]
553 #define CN2 CN [1]
554 #define CN3 CN [2]
555
556 uint WN [3];
557 #define WN1 WN [0]
558 #define WN2 WN [1]
559 #define WN3 CN [2]
560
561 uint C [3];
562 #define C1 C [0]
563 #define C2 C [1]
564 #define C3 C [2]
565
566 uint B [3];
567 #define B1 B [0]
568 #define B2 B [1]
569 #define B3 B [2]
570
571 uint N [3];
572 #define N1 N [0]
573 #define N2 N [1]
574 #define N3 N [2]
575
576 uint TN [3]; // type numeric
577 #define TN1 TN [0]
578 #define TN2 TN [1]
579 #define TN3 TN [2]
580
581 #ifdef EIS_PTR3
582 # define TA1 cpu.du.TAk[0]
583 # define TA2 cpu.du.TAk[1]
584 # define TA3 cpu.du.TAk[2]
585 #else
586
587 uint TA [3]; // type alphanumeric
588 # define TA1 TA [0]
589 # define TA2 TA [1]
590 # define TA3 TA [2]
591 #endif
592
593 uint S [3]; // Sign and decimal type of number
594 #define S1 S [0]
595 #define S2 S [1]
596 #define S3 S [2]
597
598 int SF [3]; // scale factor
599 #define SF1 SF [0]
600 #define SF2 SF [1]
601 #define SF3 SF [2]
602
603 word18 _flags; // flags set during operation
604 word18 _faults; // faults generated by instruction
605
606 word72s x; // a signed, 128-bit integers for playing with ...
607
608 // Stuff for Micro-operations and Edit instructions...
609
610 word9 editInsertionTable [8]; // 8 9-bit chars
611
612 int mopIF; // current micro-operation IF field
613 MOP_struct *m; // pointer to current MOP struct
614
615 word9 inBuffer [64]; // decimal unit input buffer
616 word9 *in; // pointer to current read position in inBuffer
617 uint inBufferCnt; // number of characters in inBuffer
618 word9 outBuffer [64]; // output buffer
619 word9 *out; // pointer to current write position in outBuffer;
620
621 int exponent; // For decimal floating-point (evil)
622 int sign; // For signed decimal (1, -1)
623
624 #ifdef EIS_PTR2
625 # define KMOP 1
626 #else
627 EISaddr *mopAddress; // mopAddress, pointer to addr [0], [1], or [2]
628 #endif
629
630 int mopTally; // number of micro-ops
631 int mopPos; // current mop char posn
632
633 // Edit Flags
634 // The processor provides the following four edit flags for use by the
635 // micro operations.
636
637 bool mopES; // End Suppression flag; initially OFF, set ON by
638 // a micro operation when zero-suppression ends.
639 bool mopSN; // Sign flag; initially set OFF if the sending
640 // string has an alphanumeric descriptor or an
641 // unsigned numeric descriptor. If the sending
642 // string has a signed numeric descriptor, the
643 // sign is initially read from the sending string
644 // from the digit position defined by the sign
645 // and the decimal type field (S); SN is set
646 // OFF if positive, ON if negative. If all
647 // digits are zero, the data is assumed positive
648 // and the SN flag is set OFF, even when the
649 // sign is negative.
650 bool mopZ; // Zero flag; initially set ON. It is set OFF
651 // whenever a sending string character that is not
652 // decimal zero is moved into the receiving string.
653 bool mopBZ; // Blank-when-zero flag; initially set OFF and
654 // set ON by either the ENF or SES micro
655 // operation. If, at the completion of a move
656 // (L1 exhausted), both the Z and BZ flags are
657 // ON, the receiving string is filled with
658 // character 1 of the edit insertion table.
659
660 EISaddr addr [3];
661
662 #define ADDR1 addr [0]
663 int srcTally; // number of chars in src (max 63)
664 int srcTA; // type of Alphanumeric chars in src
665 int srcSZ; // size of chars in src (4-, 6-, or 9-bits)
666
667 #define ADDR2 addr [1]
668
669 #define ADDR3 addr [2]
670 int dstTally; // number of chars in dst (max 63)
671 int dstSZ; // size of chars in dst (4-, 6-, or 9-bits)
672
673 bool mvne; // for MSES micro-op. True when mvne, false when mve
674 } EISstruct;
675
676 // Instruction decode structure. Used to represent instruction information
677
678 typedef struct DCDstruct_s
679 {
680 struct opcode_s * info; // opcode_s *
681 uint32 opcode; // opcode
682 bool opcodeX; // opcode extension
683 uint32 opcode10; // opcode | (opcodeX ? 01000 : 0)
684 word18 address; // bits 0-17 of instruction
685 word1 b29; // bit-29 - address via pointer register. Usually.
686 bool i; // interrupt inhibit bit.
687 word6 tag; // instruction tag
688
689 bool stiTally; // for sti instruction
690 bool restart; // instruction is to be restarted
691 } DCDstruct;
692
693 // Emulator-only interrupt and fault info
694
695 typedef struct
696 {
697 vol int fault [N_FAULT_GROUPS];
698 // only one fault in groups 1..6 can be pending
699 vol bool XIP [N_SCU_UNITS_MAX];
700 } events_t;
701
702 // Physical Switches
703
704 enum procModeSettings { procModeGCOS = 1, procModeMultics = 0 };
705
706 // Switches on the Processor's maintenance and configuration panels
707 typedef struct
708 {
709 uint FLT_BASE; // normally 7 MSB of 12bit fault base addr
710 uint cpu_num; // zero for CPU 'A', one for 'B' etc.
711 word36 data_switches;
712 word18 addr_switches;
713 uint assignment [N_CPU_PORTS];
714 uint interlace [N_CPU_PORTS]; // 0/2/4
715 uint enable [N_CPU_PORTS];
716 uint init_enable [N_CPU_PORTS];
717 uint store_size [N_CPU_PORTS]; // 0-7 encoding 32K-4M
718 enum procModeSettings procMode; // 1 bit Read by rsw instruction; format unknown
719
720 bool enable_cache; // Enable 8K cache
721 bool sdwam_enable; // Enable Segment Descriptor WAM
722 bool ptwam_enable; // Enable Page Table WAM
723
724 // CPU serial number; not strictly a switch; on DPS8/M, burned into the CPU PROM
725 uint serno;
726 } switches_t;
727
728 // Optional H/W
729 typedef struct {
730 uint proc_speed; // 4 bits Read by rsw instruction; format unknown
731 bool hex_mode_installed;
732 bool prom_installed;
733 bool cache_installed;
734 bool clock_slave_installed;
735 } optionsType;
736
737 // Hardware tweaks
738 typedef struct {
739 uint report_faults; // If set, faults are reported and ignored
740 uint tro_enable; // If set, Timer runout faults are generated.
741 uint drl_fatal; // If set, DRL instructions halt the CPU
742 bool useMap; // If set, consult memory configuration switches to translate memory addresses to SCU memory banks
743 uint dis_enable; // If non-zero, DIS instruction works
744 uint halt_on_unimp; // If non-zero, halt CPU on unimplemented instruction instead of faulting
745 bool isolts_mode; // If true, CPU is configured to run ISOLTS.
746 uint enable_wam; // If zero, the simulated cache is ignored and always returns "miss"; turning it on incurs a large performance hit.
747 bool enable_emcall; // If set, the instruction set is extended with simulator debugging instructions
748 bool nodis; // If true, start CPU in FETCH cycle; else start in DIS instruction
749 bool l68_mode; // False: DPS8/M; True: 6180
750 } tweaksType;
751
752 enum ou_cycle_e
753 {
754 ou_GIN = 0400,
755 ou_GOS = 0200,
756 ou_GD1 = 0100,
757 ou_GD2 = 0040,
758 ou_GOE = 0020,
759 ou_GOA = 0010,
760 ou_GOM = 0004,
761 ou_GON = 0002,
762 ou_GOF = 0001
763 };
764
765 typedef struct
766 {
767 // Operations Unit/Address Modification
768 bool directOperandFlag;
769 word36 directOperand;
770 word6 characterOperandSize; // just the left most bit
771 word3 characterOperandOffset;
772 word18 character_address;
773 word36 character_data;
774 bool crflag;
775
776 // L68 only
777 word2 eac;
778 word1 RB1_FULL;
779 word1 RP_FULL;
780 word1 RS_FULL;
781 word9 cycle;
782 word1 STR_OP;
783 // End L68 only
784
785 #ifdef PANEL68
786 word9 RS;
787 word4 opsz;
788 word10 reguse;
789 #endif
790 } ou_unit_data_t;
791
792 // APU history operation parameter
793
794 enum APUH_e
795 {
796 APUH_FDSPTW = 1llu << (35 - 17),
797 APUH_MDSPTW = 1llu << (35 - 18),
798 APUH_FSDWP = 1llu << (35 - 19),
799 APUH_FPTW = 1llu << (35 - 20),
800 APUH_FPTW2 = 1llu << (35 - 21),
801 APUH_MPTW = 1llu << (35 - 22),
802 APUH_FANP = 1llu << (35 - 23),
803 APUH_FAP = 1llu << (35 - 24)
804 };
805
806 enum {
807 // AL39 pg 64 APU hist.
808 apu_FLT = 1ll << (33 - 0), // 0 l FLT Access violation or directed
809 // fault on this cycle
810 // 1-2 a BSY Data source for ESN
811 apu_ESN_PSR = 0, // 00 PPR.PSR
812 apu_ESN_SNR = 1ll << (33- 1), // 01 PRn.SNR
813 apu_ESN_TSR = 1ll << (33- 2), // 10 TPR.TSR
814 // 11 not used
815 // 3 PRAP
816 apu_HOLD = 1ll << (33- 4), // 4 HOLD An access violation or
817 // directed fault is waiting
818 // 5 FRIW
819 // 6 XSF
820 // 7 STF
821 apu_TP_P = 1ll << (33- 8), // 8 TP P Guessing PPR.p set from
822 // SDW.P
823 apu_PP_P = 1ll << (33- 9), // 9 PP P PPR.P?
824 // 10 ?
825 // 11 S-ON Segment on?
826 // 12 ZMAS
827 // 13 SDMF Seg. Descr. Modify?
828 // 14 SFND
829 // 15 ?
830 // 16 P-ON Page on?
831 // 17 ZMAP
832 // 18 PTMF
833 // 19 PFND
834 apu_FDPT = 1ll << (33-20), // 20 b FDPT Fetch descriptor segment PTW
835 apu_MDPT = 1ll << (33-21), // 21 c MDPT Modify descriptor segment PTW
836 apu_FSDP = 1ll << (33-22), // 22 d FSDP Fetch SDW paged descr. seg.
837 apu_FSDN = 1ll << (33-23), // 23 FSDN Fetch SDW non-paged
838 apu_FPTW = 1ll << (33-24), // 24 e FPTW Fetch PTW
839 apu_MPTW = 1ll << (33-25), // 25 g MPTW Modify PTW
840 apu_FPTW2 = 1ll << (33-26), // 26 f FPT2 // Fetch prepage
841 apu_FAP = 1ll << (33-27), // 27 i FAP Final address fetch from
842 // paged seg.
843 apu_FANP = 1ll << (33-28), // 28 h FANP Final address fetch from
844 // non-paged segment
845 // 29 FAAB Final address absolute?
846 apu_FA = 1ll << (33-30), // 30 FA Final address?
847 // 31 EAAU
848 apu_PIAU = 1ll << (33-32) // 32 PIAU Instruction fetch?
849 // 33 TGAU
850 };
851
852 typedef struct
853 {
854 processor_cycle_type lastCycle;
855 #ifdef PANEL68
856 word34 state;
857 #endif
858 } apu_unit_data_t;
859
860 typedef struct
861 {
862 // NB: Some of the data normally stored here is represented
863 // elsewhere -- e.g.,the PPR is a variable outside of this
864 // struct. Other data is live and only stored here.
865
866 // This is a collection of flags and registers from the
867 // appending unit and the control unit. The scu and rcu
868 // instructions store and load these values to an 8 word
869 // memory block.
870 //
871 // The CU data may only be valid for use with the scu and
872 // rcu instructions.
873 //
874 // Comments indicate format as stored in 8 words by the scu
875 // instruction.
876
877 // NOTE: PPR (procedure pointer register) is a combination of registers:
878 // From the Appending Unit
879 // PRR bits [0..2] of word 0
880 // PSR bits [3..17] of word 0
881 // P bit 18 of word 0
882 // From the Control Unit
883 // IC bits [0..17] of word 4
884
885 /* word 0 */
886 // 0-2 PRR is stored in PPR
887 // 3-17 PSR is stored in PPR
888 // 18 P is stored in PPR
889 word1 XSF; // 19 XSF External segment flag
890 word1 SDWAMM; // 20 SDWAMM Match on SDWAM
891 word1 SD_ON; // 21 SDWAM enabled
892 word1 PTWAMM; // 22 PTWAMM Match on PTWAM
893 word1 PT_ON; // 23 PTWAM enabled
894
895
896
897
898
899
900
901
902
903
904
905
906
907 word12 APUCycleBits;
908
909
910 /* word 1 */
911 // AVF Access Violation Fault
912 // SF Store Fault
913 // IPF Illegal Procedure Fault
914 //
915 word1 IRO_ISN; // 0 IRO AVF Illegal Ring Order
916 // ISN SF Illegal segment number
917 word1 OEB_IOC; // 1 ORB AVF Out of execute bracket [sic] should
918 // be OEB?
919 // IOC IPF Illegal op code
920 word1 EOFF_IAIM;
921 // 2 E-OFF AVF Execute bit is off
922 // IA+IM IPF Illegal address of modifier
923 word1 ORB_ISP; // 3 ORB AVF Out of read bracket
924 // ISP IPF Illegal slave procedure
925 word1 ROFF_IPR;// 4 R-OFF AVF Read bit is off
926 // IPR IPF Illegal EIS digit
927 word1 OWB_NEA; // 5 OWB AVF Out of write bracket
928 // NEA SF Nonexistent address
929 word1 WOFF_OOB;// 6 W-OFF AVF Write bit is off
930 // OOB SF Out of bounds (BAR mode)
931 word1 NO_GA; // 7 NO GA AVF Not a gate
932 word1 OCB; // 8 OCB AVF Out of call bracket
933 word1 OCALL; // 9 OCALL AVF Outward call
934 word1 BOC; // 10 BOC AVF Bad outward call
935 // PTWAM error is DPS8M only
936 word1 PTWAM_ER;// 11 PTWAM_ER AVF PTWAM error // inward return
937 word1 CRT; // 12 CRT AVF Cross ring transfer
938 word1 RALR; // 13 RALR AVF Ring alarm
939 // On DPS8M a SDWAM error, on DP8/L68 a WAM error
940 word1 SDWAM_ER;// 14 SWWAM_ER AVF SDWAM error
941 word1 OOSB; // 15 OOSB AVF Out of segment bounds
942 word1 PARU; // 16 PARU Parity fault - processor parity upper
943 word1 PARL; // 17 PARL Parity fault - processor parity lower
944 word1 ONC1; // 18 ONC1 Operation not complete fault error #1
945 word1 ONC2; // 19 ONC2 Operation not complete fault error #2
946 word4 IA; // 20-23 IA System control illegal action lines
947 word3 IACHN; // 24-26 IACHN Illegal action processor port
948 word3 CNCHN; // 27-29 CNCHN Connect fault - connect processor port
949 word5 FI_ADDR; // 30-34 F/I ADDR Modulo 2 fault/interrupt vector address
950 word1 FLT_INT; // 35 F/I 0 = interrupt; 1 = fault
951
952 /* word 2 */
953 // 0- 2 TRR
954 // 3-17 TSR
955 // 18-21 PTW
956 // 18 PTWAM levels A, B enabled
957 // 19 PTWAM levels C, D enabled
958 // 20 PTWAM levels A, B match
959 // 21 PTWAM levels C, D match
960 // 22-25 SDW
961 // 22 SDWAM levels A, B enabled
962 // 23 SDWAM levels C, D enabled
963 // 24 SDWAM levels A, B match
964 // 25 SDWAM levels C, D match
965 // 26 0
966 // 27-29 CPU CPU Number
967 word6 delta; // 30-35 DELTA addr increment for repeats
968
969 /* word 3 */
970 // 0-17 0
971 // 18-21 TSNA Pointer register number for non-EIS
972 // operands or EIS Operand #1
973 // 18-20 PRNO Pointer register number
974 // 21 PRNO is valid
975 // 22-25 TSNB Pointer register number for EIS operand #2
976 // 22-24 PRNO Pointer register number
977 // 25 PRNO is valid
978 // 26-29 TSNC Pointer register number for EIS operand #2
979 // 26-28 PRNO Pointer register number
980 // 29 PRNO is valid
981 word3 TSN_PRNO [3];
982 word1 TSN_VALID [3];
983
984 // 30-35 TEMP BIT Current bit offset (TPR.TBR)
985
986 /* word 4 */
987 // 0-17 PPR.IC
988 word18 IR; // 18-35 Indicator register
989 // 18 ZER0
990 // 19 NEG
991 // 20 CARY
992 // 21 OVFL
993 // 22 EOVF
994 // 23 EUFL
995 // 24 OFLM
996 // 25 TRO
997 // 26 PAR
998 // 27 PARM
999 // 28 -BM
1000 // 29 TRU
1001 // 30 MIF
1002 // 31 ABS
1003 // 32 HEX [sic] Figure 3-32 is wrong.
1004 // 33-35 0
1005
1006 /* word 5 */
1007
1008 // 0-17 COMPUTED ADDRESS (TPR.CA)
1009 word1 repeat_first;
1010 // 18 RF First cycle of all repeat instructions
1011 word1 rpt; // 19 RPT Execute an Repeat (rpt) instruction
1012 word1 rd; // 20 RD Execute an Repeat Double (rpd) instruction
1013 word1 rl; // 21 RL Execute a Repeat Link (rpl) instruction
1014 word1 pot; // 22 POT Prepare operand tally
1015 // 23 PON Prepare operand no tally
1016 //xde xdo
1017 // 0 0 no execute -> 0 0
1018 // 1 0 execute XEC -> 0 0
1019 // 1 1 execute even of XED -> 0 1
1020 // 0 1 execute odd of XED -> 0 0
1021 word1 xde; // 24 XDE Execute instruction from Execute Double even
1022 // pair
1023 word1 xdo; // 25 XDO Execute instruction from Execute Double odd pair
1024 word1 itp; // 26 ITP Execute ITP indirect cycle
1025 word1 rfi; // 27 RFI Restart this instruction
1026 word1 its; // 28 ITS Execute ITS indirect cycle
1027 word1 FIF; // 29 FIF Fault occurred during instruction fetch
1028 word6 CT_HOLD; // 30-35 CT HOLD contents of the "remember modifier" register
1029
1030 /* word 6 */
1031 word36 IWB;
1032
1033 /* word 7 */
1034 word36 IRODD; /* Instr holding register; odd word of last pair fetched */
1035 } ctl_unit_data_t;
1036
1037 #define USE_IRODD (cpu.cu.rd && ((cpu. PPR.IC & 1) != 0))
1038 #define IWB_IRODD (USE_IRODD ? cpu.cu.IRODD : cpu.cu.IWB)
1039
1040 // L68 only
1041 enum du_cycle1_e
1042 {
1043 // 0 -FPOL Prepare operand length
1044 du1_nFPOL = 0400000000000ll,
1045 // 1 -FPOP Prepare operand pointer
1046 du1_nFPOP = 0200000000000ll,
1047 // 2 -NEED-DESC Need descriptor
1048 du1_nNEED_DESC = 0100000000000ll,
1049 // 3 -SEL-ADR Select address register
1050 du1_nSEL_DIR = 0040000000000ll,
1051 // 4 -DLEN=DIRECT Length equals direct
1052 du1_nDLEN_DIRECT = 0020000000000ll,
1053 // 5 -DFRST Descriptor processed for first time
1054 du1_nDFRST = 0010000000000ll,
1055 // 6 -FEXR Extended register modification
1056 du1_nFEXR = 0004000000000ll,
1057 // 7 -DLAST-FRST Last cycle of DFRST
1058 du1_nLAST_DFRST = 0002000000000ll,
1059 // 8 -DDU-LDEA Decimal unit load (lpl?)
1060 du1_nDDU_LDEA = 0001000000000ll,
1061 // 9 -DDU-STAE Decimal unit store (spl?)
1062 du1_nDDU_STEA = 0000400000000ll,
1063 // 10 -DREDO Redo operation without pointer and length update
1064 du1_nDREDO = 0000200000000ll,
1065 // 11 -DLVL<WD-SZ Load with count less than word size
1066 du1_nDLVL_WD_SZ = 0000100000000ll,
1067 // 12 -EXH Exhaust
1068 du1_nEXH = 0000040000000ll,
1069 // 13 DEND-SEQ End of sequence
1070 du1_DEND_SEQ = 0000020000000ll,
1071 // 14 -DEND End of instruction
1072 du1_nEND = 0000010000000ll,
1073 // 15 -DU=RD+WRT Decimal unit write-back
1074 du1_nDU_RD_WRT = 0000004000000ll,
1075 // 16 -PTRA00 PR address bit 0
1076 du1_nPTRA00 = 0000002000000ll,
1077 // 17 -PTRA01 PR address bit 1
1078 du1_nPTRA01 = 0000001000000ll,
1079 // 18 FA/Il Descriptor l active
1080 du1_FA_I1 = 0000000400000ll,
1081 // 19 FA/I2 Descriptor 2 active
1082 du1_FA_I2 = 0000000200000ll,
1083 // 20 FA/I3 Descriptor 3 active
1084 du1_FA_I3 = 0000000100000ll,
1085 // 21 -WRD Word operation
1086 du1_nWRD = 0000000040000ll,
1087 // 22 -NINE 9-bit character operation
1088 du1_nNINE = 0000000020000ll,
1089 // 23 -SIX 6-bit character operation
1090 du1_nSIX = 0000000010000ll,
1091 // 24 -FOUR 4-bit character operation
1092 du1_nFOUR = 0000000004000ll,
1093 // 25 -BIT Bit operation
1094 du1_nBIT = 0000000002000ll,
1095 // 26 Unused
1096 // = 0000000001000ll,
1097 // 27 Unused
1098 // = 0000000000400ll,
1099 // 28 Unused
1100 // = 0000000000200ll,
1101 // 29 Unused
1102 // = 0000000000100ll,
1103 // 30 FSAMPL Sample for mid-instruction interrupt
1104 du1_FSAMPL = 0000000000040ll,
1105 // 31 -DFRST-CT Specified first count of a sequence
1106 du1_nDFRST_CT = 0000000000020ll,
1107 // 32 -ADJ-LENGTH Adjust length
1108 du1_nADJ_LENTGH = 0000000000010ll,
1109 // 33 -INTRPTD Mid-instruction interrupt
1110 du1_nINTRPTD = 0000000000004ll,
1111 // 34 -INHIB Inhibit STC1 (force "STC0")
1112 du1_nINHIB = 0000000000002ll,
1113 // 35 Unused
1114 // = 0000000000001ll,
1115 };
1116
1117 // L68 only
1118 enum du_cycle2_e
1119 {
1120 // 36 DUD Decimal unit idle
1121 du2_DUD = 0400000000000ll,
1122 // 37 -GDLDA Descriptor load gate A
1123 du2_nGDLDA = 0200000000000ll,
1124 // 38 -GDLDB Descriptor load gate B
1125 du2_nGDLDB = 0100000000000ll,
1126 // 39 -GDLDC Descriptor load gate C
1127 du2_nGDLDC = 0040000000000ll,
1128 // 40 NLD1 Prepare alignment count for first numeric operand load
1129 du2_NLD1 = 0020000000000ll,
1130 // 41 GLDP1 Numeric operand one load gate
1131 du2_GLDP1 = 0010000000000ll,
1132 // 42 NLD2 Prepare alignment count for second numeric operand load
1133 du2_NLD2 = 0004000000000ll,
1134 // 43 GLDP2 Numeric operand two load gate
1135 du2_GLDP2 = 0002000000000ll,
1136 // 44 ANLD1 Alphanumeric operand one load gate
1137 du2_ANLD1 = 0001000000000ll,
1138 // 45 ANLD2 Alphanumeric operand two load gate
1139 du2_ANLD2 = 0000400000000ll,
1140 // 46 LDWRT1 Load rewrite register one gate (XXX Guess indirect desc. MFkID)
1141 du2_LDWRT1 = 0000200000000ll,
1142 // 47 LDWRT2 Load rewrite register two gate (XXX Guess indirect desc. MFkID)
1143 du2_LDWRT2 = 0000100000000ll,
1144 // 50 -DATA-AVLDU Decimal unit data available
1145 du2_nDATA_AVLDU = 0000040000000ll,
1146 // 49 WRT1 Rewrite register one loaded
1147 du2_WRT1 = 0000020000000ll,
1148 // 50 GSTR Numeric store gate
1149 du2_GSTR = 0000010000000ll,
1150 // 51 ANSTR Alphanumeric store gate
1151 du2_ANSTR = 0000004000000ll,
1152 // 52 FSTR-OP-AV Operand available to be stored
1153 du2_FSTR_OP_AV = 0000002000000ll,
1154 // 53 -FEND-SEQ End sequence flag
1155 du2_nFEND_SEQ = 0000001000000ll,
1156 // 54 -FLEN<128 Length less than 128
1157 du2_nFLEN_128 = 0000000400000ll,
1158 // 55 FGCH Character operation gate
1159 du2_FGCH = 0000000200000ll,
1160 // 56 FANPK Alphanumeric packing cycle gate
1161 du2_FANPK = 0000000100000ll,
1162 // 57 FEXMOP Execute MOP gate
1163 du2_FEXOP = 0000000040000ll,
1164 // 58 FBLNK Blanking gate
1165 du2_FBLNK = 0000000020000ll,
1166 // 59 Unused
1167 // = 0000000010000ll,
1168 // 60 DGBD Binary to decimal execution gate
1169 du2_DGBD = 0000000004000ll,
1170 // 61 DGDB Decimal to binary execution gate
1171 du2_DGDB = 0000000002000ll,
1172 // 62 DGSP Shift procedure gate
1173 du2_DGSP = 0000000001000ll,
1174 // 63 FFLTG Floating result flag
1175 du2_FFLTG = 0000000000400ll,
1176 // 64 FRND Rounding flag
1177 du2_FRND = 0000000000200ll,
1178 // 65 DADD-GATE Add/subtract execute gate
1179 du2_DADD_GATE = 0000000000100ll,
1180 // 66 DMP+DV-GATE Multiply/divide execution gate
1181 du2_DMP_DV_GATE = 0000000000040ll,
1182 // 67 DXPN-GATE Exponent network execution gate
1183 du2_DXPN_GATE = 0000000000020ll,
1184 // 68 Unused
1185 // = 0000000000010ll,
1186 // 69 Unused
1187 // = 0000000000004ll,
1188 // 70 Unused
1189 // = 0000000000002ll,
1190 // 71 Unused
1191 // = 0000000000001ll,
1192 };
1193
1194 // L68 only
1195 #define DU_CYCLE_GDLDA { clrmask (& cpu.du.cycle2, du2_nGDLDA); \
1196 setmask (& cpu.du.cycle2, du2_nGDLDB | du2_nGDLDC); }
1197 #define DU_CYCLE_GDLDB { clrmask (& cpu.du.cycle2, du2_nGDLDB); \
1198 setmask (& cpu.du.cycle2, du2_nGDLDA | du2_nGDLDC); }
1199 #define DU_CYCLE_GDLDC { clrmask (& cpu.du.cycle2, du2_nGDLDC); \
1200 setmask (& cpu.du.cycle2, du2_nGDLDA | du2_nGDLDB); }
1201 #define DU_CYCLE_FA_I1 setmask (& cpu.du.cycle1, du1_FA_I1)
1202 #define DU_CYCLE_FA_I2 setmask (& cpu.du.cycle1, du1_FA_I2)
1203 #define DU_CYCLE_FA_I3 setmask (& cpu.du.cycle1, du1_FA_I3)
1204 #define DU_CYCLE_ANLD1 setmask (& cpu.du.cycle2, du2_ANLD1)
1205 #define DU_CYCLE_ANLD2 setmask (& cpu.du.cycle2, du2_ANLD2)
1206 #define DU_CYCLE_NLD1 setmask (& cpu.du.cycle2, du2_NLD1)
1207 #define DU_CYCLE_NLD2 setmask (& cpu.du.cycle2, du2_NLD2)
1208 #define DU_CYCLE_FRND setmask (& cpu.du.cycle2, du2_FRND)
1209 #define DU_CYCLE_DGBD setmask (& cpu.du.cycle2, du2_DGBD)
1210 #define DU_CYCLE_DGDB setmask (& cpu.du.cycle2, du2_DGDB)
1211 #define DU_CYCLE_DDU_LDEA clrmask (& cpu.du.cycle1, du1_nDDU_LDEA)
1212 #define DU_CYCLE_DDU_STEA clrmask (& cpu.du.cycle1, du1_nDDU_STEA)
1213 #define DU_CYCLE_END clrmask (& cpu.du.cycle1, du1_nEND)
1214 #define DU_CYCLE_LDWRT1 setmask (& cpu.du.cycle2, du2_LDWRT1)
1215 #define DU_CYCLE_LDWRT2 setmask (& cpu.du.cycle2, du2_LDWRT2)
1216 #define DU_CYCLE_FEXOP setmask (& cpu.du.cycle2, du2_FEXOP)
1217 #define DU_CYCLE_ANSTR setmask (& cpu.du.cycle2, du2_ANSTR)
1218 #define DU_CYCLE_GSTR setmask (& cpu.du.cycle2, du2_GSTR)
1219 #define DU_CYCLE_FLEN_128 clrmask (& cpu.du.cycle2, du2_nFLEN_128)
1220 #define DU_CYCLE_FDUD { cpu.du.cycle1 = \
1221 du1_nFPOL | \
1222 du1_nFPOP | \
1223 du1_nNEED_DESC | \
1224 du1_nSEL_DIR | \
1225 du1_nDLEN_DIRECT | \
1226 du1_nDFRST | \
1227 du1_nFEXR | \
1228 du1_nLAST_DFRST | \
1229 du1_nDDU_LDEA | \
1230 du1_nDDU_STEA | \
1231 du1_nDREDO | \
1232 du1_nDLVL_WD_SZ | \
1233 du1_nEXH | \
1234 du1_nEND | \
1235 du1_nDU_RD_WRT | \
1236 du1_nWRD | \
1237 du1_nNINE | \
1238 du1_nSIX | \
1239 du1_nFOUR | \
1240 du1_nBIT | \
1241 du1_nINTRPTD | \
1242 du1_nINHIB; \
1243 cpu.du.cycle2 = \
1244 du2_DUD | \
1245 du2_nGDLDA | \
1246 du2_nGDLDB | \
1247 du2_nGDLDC | \
1248 du2_nDATA_AVLDU | \
1249 du2_nFEND_SEQ | \
1250 du2_nFLEN_128; \
1251 }
1252 #define DU_CYCLE_nDUD clrmask (& cpu.du.cycle2, du2_DUD)
1253
1254 #ifdef PANEL68
1255 // Control points
1256
1257 # define CPT(R,C) cpu.cpt[R][C]=1
1258 # define CPTUR(C) cpu.cpt[cpt5L][C]=1
1259 #else
1260 # define CPT(R,C)
1261 # define CPTUR(C)
1262 #endif
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355 typedef struct du_unit_data_t
1356 {
1357 // Word 0
1358
1359 // 0- 8 9 Zeros
1360 word1 Z; // 9 1 Z All bit-string instruction results
1361 // are zero
1362 word1 NOP; // 10 1 0 Negative overpunch found in 6-4
1363 // expanded move
1364 word24 CHTALLY; // 12-35 24 CHTALLY The number of characters examined
1365 // by the scm, scmr, scd,
1366 // scdr, tct, or tctr instructions
1367 // (up to the interrupt or match)
1368
1369 // Word 1
1370
1371 // 0-35 26 Zeros
1372
1373 // Word 2
1374
1375 // word24 D1_PTR; // 0-23 24 D1 PTR Address of the last double-word
1376 // accessed by operand descriptor 1;
1377 // bits 17-23 (bit-address) valid
1378 // only for initial access
1379 // 24 1 Zero
1380 // word2 TA1; // 25-26 2 TA1 Alphanumeric type of operand
1381 // descriptor 1
1382 // 27-29 3 Zeroes
1383 // 30 1 I Decimal unit interrupted flag; a
1384 // copy of the mid-instruction
1385 // interrupt fault indicator
1386 // word1 F1; // 31 1 F1 First time; data in operand
1387 // descriptor 1 is valid
1388 // word1 A1; // 32 1 A1 Operand descriptor 1 is active
1389 // 33-35 3 Zeroes
1390
1391 // Word 3
1392
1393 word10 LEVEL1; // 0- 9 10 LEVEL 1 Difference in the count of
1394 // characters loaded into the and
1395 // processor characters not acted
1396 // upon
1397 // word24 D1_RES; // 12-35 24 D1 RES Count of characters remaining in
1398 // operand descriptor 1
1399
1400 // Word 4
1401
1402 // word24 D2_PTR; // 0-23 24 D2 PTR Address of the last double-word
1403 // accessed by operand descriptor 2;
1404 // bits 17-23 (bit-address) valid
1405 // only for initial access
1406 // 24 1 Zero
1407 // word2 TA2; // 25-26 2 TA2 Alphanumeric type of operand
1408 // descriptor 2
1409 // 27-29 3 Zeroes
1410 word1 R; // 30 1 R Last cycle performed must be
1411 // repeated
1412 // word1 F2; // 31 1 F2 First time; data in operand
1413 // descriptor 2 is valid
1414 // word1 A2; // 32 1 A2 Operand descriptor 2 is active
1415 // 33-35 3 Zeroes
1416
1417 // Word 5
1418
1419 word10 LEVEL2; // 0- 9 10 LEVEL 2 Same as LEVEL 1, but used mainly
1420 // for OP 2 information
1421 // word24 D2_RES; // 12-35 24 D2 RES Count of characters remaining in
1422 // operand descriptor 2
1423
1424 // Word 6
1425
1426 // word24 D3_PTR; // 0-23 24 D3 PTR Address of the last double-word
1427 // accessed by operand descriptor 3;
1428 // bits 17-23 (bit-address) valid
1429 // only for initial access
1430 // 24 1 Zero
1431 // word2 TA3; // 25-26 2 TA3 Alphanumeric type of operand
1432 // descriptor 3
1433 // 27-29 3 Zeroes
1434 // 30 1 R Last cycle performed must be
1435 // repeated
1436 // [XXX: what is the difference between
1437 // this and word4.R]
1438 // word1 F3; // 31 1 F3 First time; data in operand
1439 // descriptor 3 is valid
1440 // word1 A3; // 32 1 A3 Operand descriptor 3 is active
1441 word3 JMP; // 33-35 3 JMP Descriptor count; number of words
1442 // to skip to find the next
1443 // instruction following this
1444 // multiword instruction
1445
1446 // Word 7
1447
1448 // 0-12 12 Zeroes
1449 // word24 D3_RES; // 12-35 24 D3 RES Count of characters remaining in
1450 // operand descriptor 3
1451
1452 // Fields from above reorganized for generality
1453 word2 TAk [3];
1454
1455 // D_PTR is a word24 divided into a 18 bit address, and a 6-bit bitno/char
1456 // field
1457
1458 word18 Dk_PTR_W [3];
1459 #define D1_PTR_W Dk_PTR_W [0]
1460 #define D2_PTR_W Dk_PTR_W [1]
1461 #define D3_PTR_W Dk_PTR_W [2]
1462
1463 word6 Dk_PTR_B [3];
1464 #define D1_PTR_B Dk_PTR_B [0]
1465 #define D2_PTR_B Dk_PTR_B [1]
1466 #define D3_PTR_B Dk_PTR_B [2]
1467
1468 word24 Dk_RES [3];
1469 #define D_RES Dk_RES
1470 #define D1_RES Dk_RES [0]
1471 #define D2_RES Dk_RES [1]
1472 #define D3_RES Dk_RES [2]
1473
1474 word1 Fk [3];
1475 //#define F Fk
1476 #define F1 Fk [0]
1477 #define F2 Fk [0]
1478 #define F3 Fk [0]
1479
1480 word1 Ak [3];
1481
1482 // Working storage for EIS instruction processing.
1483
1484 // These values must be restored on instruction restart
1485 word7 MF [3]; // Modifier fields for each instruction.
1486
1487 // Image of LPL/SPL for ISOLTS compliance
1488 word36 image [8];
1489
1490 #ifdef PANEL68
1491 word37 cycle1;
1492 word37 cycle2;
1493 word1 POL; // Prepare operand length
1494 word1 POP; // Prepare operand pointer
1495 #endif
1496 } du_unit_data_t;
1497
1498 #ifdef PANEL68
1499 // prepare_state bits
1500 enum
1501 {
1502 ps_PIA = 0200,
1503 ps_POA = 0100,
1504 ps_RIW = 0040,
1505 ps_SIW = 0020,
1506 ps_POT = 0010,
1507 ps_PON = 0004,
1508 ps_RAW = 0002,
1509 ps_SAW = 0001
1510 };
1511 #endif
1512
1513 // History registers
1514
1515 // CU History register flag2 field bit
1516
1517 enum { CUH_XINT = 0100, CUH_IFT = 040, CUH_CRD = 020, CUH_MRD = 010,
1518 CUH_MSTO = 04, CUH_PIB = 02 };
1519
1520 #define N_DPS8M_WAM_ENTRIES 64
1521 #define N_DPS8M_WAM_MASK 077
1522 #define N_L68_WAM_ENTRIES 16
1523 #define N_L68_WAM_MASK 017
1524 #define N_NAX_WAM_ENTRIES 64
1525 #define N_MODEL_WAM_ENTRIES (cpu.tweaks.l68_mode ? N_L68_WAM_ENTRIES : N_DPS8M_WAM_ENTRIES)
1526
1527 typedef struct
1528 {
1529
1530 EISstruct currentEISinstruction;
1531
1532 unsigned long long cycleCnt;
1533 unsigned long long instrCnt;
1534 unsigned long long instrCntT0;
1535 unsigned long long instrCntT1;
1536 unsigned long long lockCnt;
1537 unsigned long long lockImmediate;
1538 unsigned long long lockWait;
1539 unsigned long long lockWaitMax;
1540 #ifndef SCHED_NEVER_YIELD
1541 unsigned long long lockYield;
1542 #endif /* ifndef SCHED_NEVER_YIELD */
1543
1544 // From the control unit history register:
1545 _fault_subtype subFault; // saved by doFault
1546
1547 word36 rA; // accumulator
1548 word36 rQ; // quotient
1549
1550 fault_acv_subtype_ acvFaults; // pending ACV faults
1551
1552 sdw_s * SDW; // working SDW
1553
1554 // Zone mask
1555 word36 zone;
1556
1557 ptw_s * PTW;
1558
1559 word36 CY; // C(Y) operand data from memory
1560
1561 uint64 lufCounter;
1562
1563 _fault_subtype dlySubFltNum;
1564
1565 const char * dlyCtx;
1566
1567 word36 faultRegister [2];
1568
1569 word36 itxPair [2];
1570
1571 //#if defined(THREADZ) || defined(LOCKLESS)
1572 // struct timespec rTRTime; // time when rTR was set
1573 //#endif
1574
1575 mode_register_s MR;
1576 // Changes to the mode register history bits do not take affect until
1577 // the next instruction (ISOLTS 700 2a). Cache the values here so
1578 // that post register updates can see the old values.
1579 mode_register_s MR_cache;
1580
1581 DCDstruct currentInstruction;
1582
1583 ou_unit_data_t ou;
1584
1585 word36 Ypair[2]; // 2-words
1586 word36 Yblock8[8]; // 8-words
1587 word36 Yblock16[16]; // 16-words
1588 word36 Yblock32[32]; // 32-words
1589
1590 word36 scu_data[8]; // For SCU instruction
1591
1592 ctl_unit_data_t cu;
1593 du_unit_data_t du;
1594
1595 switches_t switches;
1596 optionsType options;
1597 tweaksType tweaks;
1598 switches_t isolts_switches_save;
1599
1600 jmp_buf jmpMain; // This is the entry to the CPU state machine
1601
1602 unsigned long faultCnt [N_FAULTS];
1603
1604 _fault_subtype g7SubFaults [N_FAULTS];
1605
1606 word36 history [N_HIST_SETS] [N_MAX_HIST_SIZE] [2];
1607
1608 cycles_e cycle;
1609
1610 _fault faultNumber; // fault number saved by doFault
1611
1612 apu_unit_data_t apu;
1613
1614 word27 rTR; // timer [map: TR, 9 0's]
1615 #if defined(THREADZ) || defined(LOCKLESS)
1616 uint rTRsample;
1617 #endif
1618
1619 word24 rY; // address operand
1620
1621 word18 lnk; // rpl link value
1622
1623 uint g7FaultsPreset;
1624 uint g7Faults;
1625
1626 word24 iefpFinalAddress;
1627
1628 // ISOLTS fine grain TR estimation
1629 uint rTRlsb;
1630 uint shadowTR;
1631 uint TR0; // The value that the TR was set to.
1632
1633 // Arguments for delayed overflow fault
1634 _fault dlyFltNum;
1635
1636 word18 last_write;
1637
1638 #ifdef LOCKLESS
1639 word24 locked_addr;
1640 word24 char_word_address;
1641 #endif
1642
1643 word24 rmw_address;
1644
1645 uint restart_address;
1646
1647 struct
1648 {
1649 word15 PSR;
1650 word3 PRR;
1651 word18 IC;
1652 } cu_data; // For STCD instruction
1653 uint rTRticks;
1654
1655 struct tpr_s TPR; // Temporary Pointer Register
1656 struct ppr_s PPR; // Procedure Pointer Register
1657 struct dsbr_s DSBR; // Descriptor Segment Base Register
1658 ptw0_s PTW0; // a PTW not in PTWAM (PTWx1)
1659
1660 uint history_cyclic [N_HIST_SETS]; // 0..63
1661
1662 sdw_s SDW0; // a SDW not in SDWAM
1663 sdw_s _s;
1664
1665 word18 rX [8]; // index
1666
1667 // Nmber of banks in each SCU
1668 uint sc_num_banks [N_SCU_UNITS_MAX];
1669
1670 // Caching some cabling data for interrupt handling.
1671 // When a CPU calls get_highest_intr(), it needs to know
1672 // what port on the SCU it is attached to. Because of port
1673 // expanders several CPUs can be attached to an SCU port,
1674 // mapping from the CPU to the SCU is easier to query
1675 uint scu_port[N_SCU_UNITS_MAX];
1676
1677 // L68 FFV faults
1678
1679 uint FFV_faults_preset;
1680 uint FFV_faults;
1681 uint FFV_fault_number;
1682
1683 #ifdef AFFINITY
1684 uint affinity;
1685 #endif
1686
1687 events_t events;
1688
1689 word24 pad[16];
1690
1691 struct par_s PAR [8]; // pointer/address registers
1692
1693 ptw_s PTWAM [N_NAX_WAM_ENTRIES];
1694
1695 // Map memory address through memory configuration switches
1696 // Minimum allocation chunk is 64K (SCBANK_SZ)
1697 // addr / SCBANK_SZ => bank_number
1698 // scbank_map[bank_number] is address of the bank in M. -1 is unmapped.
1699 int sc_addr_map [N_SCBANKS];
1700 // The SCU number holding each bank
1701 int sc_scu_map [N_SCBANKS];
1702
1703 sdw_s SDWAM [N_NAX_WAM_ENTRIES]; // Segment Descriptor Word Associative Memory
1704
1705 // Address Modification tally
1706 word12 AM_tally;
1707
1708 struct bar_s BAR; // Base Address Register
1709
1710 cache_mode_register_s CMR;
1711
1712 // The following are all from the control unit history register:
1713
1714 bool interrupt_flag; // an interrupt is pending in this cycle
1715 bool g7_flag; // a g7 fault is pending in this cycle;
1716
1717 bool wasXfer; // The previous instruction was a transfer
1718
1719 bool wasInhibited; // One or both of the previous instruction
1720 // pair was interrupt inhibited.
1721
1722 bool isExec; // The instruction being executed is the target of
1723 // an XEC or XED instruction
1724 bool isXED; // The instruction being executed is the target of an
1725 // XEC instruction
1726
1727 bool isolts_switches_saved;
1728
1729 word8 rE; // exponent [map: rE, 28 0's]
1730
1731 word6 rTAG; // instruction tag
1732 word3 rRALR; // ring alarm [3b] [map: 33 0's, RALR]
1733 word3 RSDWH_R1; // Track the ring number of the last SDW
1734
1735 // L68: word4
1736 // DPS8M: word6
1737 word6 SDWAMR;
1738
1739 // Zone mask
1740 bool useZone;
1741
1742 // L68: word4
1743 // DPS8M: word6
1744 word6 PTWAMR;
1745
1746 // G7 faults
1747 bool bTroubleFaultCycle;
1748
1749 bool lufOccurred;
1750 bool secret_addressing_mode;
1751 // Used by LCPR to prevent the LCPR instruction from being recorded
1752 // in the CU.
1753 bool skip_cu_hist;
1754
1755 // If the instruction wants overflow thrown after operand write
1756 bool dlyFlt;
1757
1758 bool restart;
1759
1760 // L68 FFV faults
1761 bool is_FFV;
1762
1763 #ifdef ROUND_ROBIN
1764 bool isRunning;
1765 #endif
1766
1767 #ifdef AFFINITY
1768 bool set_affinity;
1769 #endif
1770
1771 #ifdef SPEED
1772 # define SC_MAP_ADDR(addr,real_addr) \
1773 if (cpu.tweaks.useMap) \
1774 { \
1775 uint pgnum = addr / SCBANK_SZ; \
1776 uint os = addr % SCBANK_SZ; \
1777 int base = cpu.sc_addr_map[pgnum]; \
1778 if (base < 0) \
1779 { \
1780 doFault (FAULT_STR, fst_str_nea, __func__); \
1781 } \
1782 real_addr = (uint) base + os; \
1783 } \
1784 else \
1785 real_addr = addr;
1786 #else
1787 # define SC_MAP_ADDR(addr,real_addr) \
1788 if (cpu.tweaks.useMap) \
1789 { \
1790 uint pgnum = addr / SCBANK_SZ; \
1791 uint os = addr % SCBANK_SZ; \
1792 int base = cpu.sc_addr_map[pgnum]; \
1793 if (base < 0) \
1794 { \
1795 doFault (FAULT_STR, fst_str_nea, __func__); \
1796 } \
1797 real_addr = (uint) base + os; \
1798 } \
1799 else \
1800 { \
1801 nem_check (addr, __func__); \
1802 real_addr = addr; \
1803 }
1804 #endif
1805
1806 #ifdef PANEL68
1807 // Intermediate data collection for APU SCROLL
1808 word18 lastPTWOffset;
1809 // The L68 APU SCROLL 4U has an entry "ACSD"; I am interpreting it as
1810 // on: lastPTRAddr was a DSPTW
1811 // off: lastPTRAddr was a PTW
1812 bool lastPTWIsDS;
1813 word18 APUDataBusOffset;
1814 word24 APUDataBusAddr;
1815 word24 APUMemAddr;
1816 word1 panel4_red_ready_light_state;
1817 word1 panel7_enabled_light_state;
1818 // The state of the panel switches
1819 volatile word15 APU_panel_segno_sw;
1820 volatile word1 APU_panel_enable_match_ptw_sw; // lock
1821 volatile word1 APU_panel_enable_match_sdw_sw; // lock
1822 volatile word1 APU_panel_scroll_select_ul_sw;
1823 volatile word4 APU_panel_scroll_select_n_sw;
1824 volatile word4 APU_panel_scroll_wheel_sw;
1825 //volatile word18 APU_panel_addr_sw;
1826 volatile word18 APU_panel_enter_sw;
1827 volatile word18 APU_panel_display_sw;
1828 volatile word4 CP_panel_wheel_sw;
1829 volatile word4 DATA_panel_ds_sw;
1830 volatile word4 DATA_panel_d1_sw;
1831 volatile word4 DATA_panel_d2_sw;
1832 volatile word4 DATA_panel_d3_sw;
1833 volatile word4 DATA_panel_d4_sw;
1834 volatile word4 DATA_panel_d5_sw;
1835 volatile word4 DATA_panel_d6_sw;
1836 volatile word4 DATA_panel_d7_sw;
1837 volatile word4 DATA_panel_wheel_sw;
1838 volatile word4 DATA_panel_addr_stop_sw;
1839 volatile word1 DATA_panel_enable_sw;
1840 volatile word1 DATA_panel_validate_sw;
1841 volatile word1 DATA_panel_auto_fast_sw; // lock
1842 volatile word1 DATA_panel_auto_slow_sw; // lock
1843 volatile word4 DATA_panel_cycle_sw; // lock
1844 volatile word1 DATA_panel_step_sw; // lock
1845 volatile word1 DATA_panel_s_trig_sw;
1846 volatile word1 DATA_panel_execute_sw; // lock
1847 volatile word1 DATA_panel_scope_sw;
1848 volatile word1 DATA_panel_init_sw; // lock
1849 volatile word1 DATA_panel_exec_sw; // lock
1850 volatile word4 DATA_panel_hr_sel_sw;
1851 volatile word4 DATA_panel_trackers_sw;
1852 volatile bool panelInitialize;
1853
1854 // Intermediate data collection for DATA SCROLL
1855 bool portBusy;
1856 word2 portSelect;
1857 word36 portAddr [N_CPU_PORTS];
1858 word36 portData [N_CPU_PORTS];
1859 // Intermediate data collection for CU
1860 word36 IWRAddr;
1861 word7 dataMode; // 0100 9 bit
1862 // 0040 6 bit
1863 // 0020 4 bit
1864 // 0010 1 bit
1865 // 0004 36 bit
1866 // 0002 alphanumeric
1867 // 0001 numeric
1868 word8 prepare_state;
1869 bool DACVpDF;
1870 bool AR_F_E;
1871 bool INS_FETCH;
1872 // Control Points data acquisition
1873 word1 cpt [28] [36];
1874 #endif
1875 #define cpt1U 0 // Instruction processing tracking
1876 #define cpt1L 1 // Instruction processing tracking
1877 #define cpt2U 2 // Instruction execution tracking
1878 #define cpt2L 3 // Instruction execution tracking
1879 #define cpt3U 4 // Register usage
1880 #define cpt3L 5 // Register usage
1881 #define cpt4U 6
1882 #define cpt4L 7
1883 #define cpt5U 8
1884 #define cpt5L 9
1885 #define cpt6U 10
1886 #define cpt6L 11
1887 #define cpt7U 12
1888 #define cpt7L 13
1889 #define cpt8U 14
1890 #define cpt8L 15
1891 #define cpt9U 16
1892 #define cpt9L 17
1893 #define cpt10U 18
1894 #define cpt10L 19
1895 #define cpt11U 20
1896 #define cpt11L 21
1897 #define cpt12U 22
1898 #define cpt12L 23
1899 #define cpt13U 24
1900 #define cpt13L 25
1901 #define cpt14U 26
1902 #define cpt14L 27
1903
1904 #define cptUseE 0
1905 #define cptUseBAR 1
1906 #define cptUseTR 2
1907 #define cptUseRALR 3
1908 #define cptUsePRn 4 // 4 - 11
1909 #define cptUseDSBR 12
1910 #define cptUseFR 13
1911 #define cptUseMR 14
1912 #define cptUseCMR 15
1913 #define cptUseIR 16
1914 } cpu_state_t;
1915
1916 #ifdef M_SHARED
1917 extern cpu_state_t * cpus;
1918 #else
1919 extern cpu_state_t cpus [N_CPU_UNITS_MAX];
1920 #endif
1921
1922 #if defined(THREADZ) || defined(LOCKLESS)
1923 extern __thread cpu_state_t * restrict cpup;
1924 #else
1925 extern cpu_state_t * restrict cpup;
1926 #endif
1927 #define cpu (* cpup)
1928
1929 #define N_STALL_POINTS 16
1930 struct stall_point_s
1931 {
1932 word15 segno;
1933 word18 offset;
1934 useconds_t time;
1935 };
1936 extern struct stall_point_s stall_points [N_STALL_POINTS];
1937 extern bool stall_point_active;
1938
1939 uint set_cpu_idx (uint cpuNum);
1940 #if defined(THREADZ) || defined(LOCKLESS)
1941 extern __thread uint current_running_cpu_idx;
1942 extern bool bce_dis_called;
1943 #else
1944 # ifdef ROUND_ROBIN
1945 extern uint current_running_cpu_idx;
1946 # else
1947 # define current_running_cpu_idx 0
1948 # endif
1949 #endif
1950
1951 // Support code to access ARn.BITNO, ARn.CHAR, PRn.BITNO
1952
1953 #define GET_PR_BITNO(n) (cpu.PAR[n].PR_BITNO)
1954 #define GET_AR_BITNO(n) (cpu.PAR[n].AR_BITNO)
1955 #define GET_AR_CHAR(n) (cpu.PAR[n].AR_CHAR)
1956 static inline void SET_PR_BITNO (uint n, word6 b)
/* ![[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)
*/
1957 {
1958 cpu.PAR[n].PR_BITNO = b;
1959 cpu.PAR[n].AR_BITNO = (b % 9) & MASK4;
1960 cpu.PAR[n].AR_CHAR = (b / 9) & MASK2;
1961 }
1962 static inline void SET_AR_CHAR_BITNO (uint n, word2 c, word4 b)
/* ![[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)
*/
1963 {
1964 cpu.PAR[n].PR_BITNO = c * 9 + b;
1965 cpu.PAR[n].AR_BITNO = b & MASK4;
1966 cpu.PAR[n].AR_CHAR = c & MASK2;
1967 }
1968
1969 bool sample_interrupts (void);
1970 t_stat simh_hooks (void);
1971 int operand_size (void);
1972 t_stat read_operand (word18 addr, processor_cycle_type cyctyp);
1973 t_stat write_operand (word18 addr, processor_cycle_type acctyp);
1974
1975 #ifdef PANEL68
1976 static inline void trackport (word24 a, word36 d)
/* ![[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)
*/
1977 {
1978 // Simplifying assumption: 4 * 4MW SCUs
1979 word2 port = (a >> 22) & MASK2;
1980 cpu.portSelect = port;
1981 cpu.portAddr [port] = a;
1982 cpu.portData [port] = d;
1983 cpu.portBusy = false;
1984 }
1985 #endif
1986
1987 #if defined(SPEED) && defined(INLINE_CORE)
1988 // Ugh. Circular dependencies XXX
1989 void doFault (_fault faultNumber, _fault_subtype faultSubtype,
/* ![[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)
*/
1990 const char * faultMsg) NO_RETURN;
1991 extern const _fault_subtype fst_str_nea;
1992
1993 static inline int core_read (word24 addr, word36 *data, \
1994 UNUSED const char * ctx)
1995 {
1996 PNL (cpu.portBusy = true;)
1997 SC_MAP_ADDR (addr, addr);
1998 * data = M[addr] & DMASK;
1999 # ifdef TR_WORK_MEM
2000 cpu.rTRticks ++;
2001 # endif
2002 PNL (trackport (addr, * data);)
2003 return 0;
2004 }
2005
2006 static inline int core_write (word24 addr, word36 data, \
/* ![[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)
*/
2007 UNUSED const char * ctx)
2008 {
2009 PNL (cpu.portBusy = true;)
2010 SC_MAP_ADDR (addr, addr);
2011 if (cpu.tweaks.isolts_mode)
2012 {
2013 if (cpu.MR.sdpap)
2014 {
2015 sim_warn ("failing to implement sdpap\n");
2016 cpu.MR.sdpap = 0;
2017 }
2018 if (cpu.MR.separ)
2019 {
2020 sim_warn ("failing to implement separ\n");
2021 cpu.MR.separ = 0;
2022 }
2023 }
2024 M[addr] = data & DMASK;
2025 # ifdef TR_WORK_MEM
2026 cpu.rTRticks ++;
2027 # endif
2028 PNL (trackport (addr, data);)
2029 return 0;
2030 }
2031
2032 static inline int core_write_zone (word24 addr, word36 data, \
/* ![[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)
*/
2033 UNUSED const char * ctx)
2034 {
2035 PNL (cpu.portBusy = true;)
2036 SC_MAP_ADDR (addr, addr);
2037 if (cpu.tweaks.isolts_mode)
2038 {
2039 if (cpu.MR.sdpap)
2040 {
2041 sim_warn ("failing to implement sdpap\n");
2042 cpu.MR.sdpap = 0;
2043 }
2044 if (cpu.MR.separ)
2045 {
2046 sim_warn ("failing to implement separ\n");
2047 cpu.MR.separ = 0;
2048 }
2049 }
2050 M[addr] = (M[addr] & ~cpu.zone) | (data & cpu.zone);
2051 cpu.useZone = false; // Safety
2052 # ifdef TR_WORK_MEM
2053 cpu.rTRticks ++;
2054 # endif
2055 PNL (trackport (addr, data);)
2056 return 0;
2057 }
2058
2059 static inline int core_read2 (word24 addr, word36 *even, word36 *odd,
/* ![[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)
*/
2060 UNUSED const char * ctx)
2061 {
2062 PNL (cpu.portBusy = true;)
2063 SC_MAP_ADDR (addr, addr);
2064 *even = M[addr++] & DMASK;
2065 *odd = M[addr] & DMASK;
2066 # ifdef TR_WORK_MEM
2067 cpu.rTRticks ++;
2068 # endif
2069 PNL (trackport (addr - 1, * even);)
2070 return 0;
2071 }
2072
2073 static inline int core_write2 (word24 addr, word36 even, word36 odd,
/* ![[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)
*/
2074 UNUSED const char * ctx)
2075 {
2076 PNL (cpu.portBusy = true;)
2077 SC_MAP_ADDR (addr, addr);
2078 if (cpu.tweaks.isolts_mode)
2079 {
2080 if (cpu.MR.sdpap)
2081 {
2082 sim_warn ("failing to implement sdpap\n");
2083 cpu.MR.sdpap = 0;
2084 }
2085 if (cpu.MR.separ)
2086 {
2087 sim_warn ("failing to implement separ\n");
2088 cpu.MR.separ = 0;
2089 }
2090 }
2091 M[addr++] = even;
2092 M[addr] = odd;
2093 PNL (trackport (addr - 1, even);)
2094 # ifdef TR_WORK_MEM
2095 cpu.rTRticks ++;
2096 # endif
2097 return 0;
2098 }
2099 #else
2100 int core_read (word24 addr, word36 *data, const char * ctx);
2101 int core_write (word24 addr, word36 data, const char * ctx);
2102 int core_write_zone (word24 addr, word36 data, const char * ctx);
2103 int core_read2 (word24 addr, word36 *even, word36 *odd, const char * ctx);
2104 int core_write2 (word24 addr, word36 even, word36 odd, const char * ctx);
2105 #endif // defined(SPEED) && defined(INLINE_CORE)
2106
2107 #ifdef LOCKLESS
2108
2109 /*
2110 * Atomic operations to use defined as follows:
2111 *
2112 * AIX_ATOMICS - IBM AIX atomics
2113 * BSD_ATOMICS - FreeBSD atomics
2114 * GNU_ATOMICS - GNU atomics
2115 * SYNC_ATOMICS - GNU sync-style atomics
2116 *
2117 * The following are reserved and not yet implemented:
2118 *
2119 * ISO_ATOMICS - ISO/IEC 9899:2011 (C11) atomics
2120 * NT_ATOMICS - Microsoft Windows NT atomics
2121 *
2122 * For further details, see:
2123 *
2124 * AIX_ATOMICS:
2125 * https://www.ibm.com/docs/en/aix/7.3?topic=services-atomic-operations
2126 *
2127 * BSD_ATOMICS:
2128 * https://www.freebsd.org/cgi/man.cgi?query=atomic&sektion=9&format=html
2129 * https://man.dragonflybsd.org/?command=atomic§ion=9
2130 *
2131 * GNU_ATOMICS:
2132 * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
2133 *
2134 * SYNC_ATOMICS:
2135 * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
2136 *
2137 * ISO_ATOMICS:
2138 * https://en.cppreference.com/w/c/atomic
2139 *
2140 * NT_ATOMICS:
2141 * https://docs.microsoft.com/en-us/windows/win32/sync/synchronization-functions
2142 * https://docs.microsoft.com/en-us/windows/win32/sync/interlocked-variable-access
2143 */
2144
2145 // AIX_ATOMICS are SYNC_ATOMICS (for now)
2146 # if ( defined (AIX_ATOMICS) && \
2147 (! (defined (SYNC_ATOMICS))))
2148 # define SYNC_ATOMICS 1
2149 # endif
2150
2151 // FreeBSD atomics (default on for FreeBSD)
2152 # if (! defined (GNU_ATOMICS)) && (! defined (SYNC_ATOMICS)) && \
2153 (! defined (BSD_ATOMICS)) && (! defined (AIX_ATOMICS))
2154 # if defined(__FreeBSD__) \
2155 || defined(__FreeBSD_kernel__) \
2156 || defined(__DragonFly__)
2157 # undef BSD_ATOMICS
2158 # define BSD_ATOMICS 1
2159 # endif
2160 # endif
2161
2162 // Otherwise, default to GNU_ATOMICS
2163 # if (! defined (GNU_ATOMICS)) && (! defined (BSD_ATOMICS)) && \
2164 (! defined (SYNC_ATOMICS)) && (! defined (AIX_ATOMICS))
2165 # undef GNU_ATOMICS
2166 # define GNU_ATOMICS 1
2167 # endif
2168
2169 int core_read_lock (word24 addr, word36 *data, const char * ctx);
2170 int core_write_unlock (word24 addr, word36 data, const char * ctx);
2171 int core_unlock_all(void);
2172
2173 # define DEADLOCK_DETECT 0x40000000U
2174 # define MEM_LOCKED_BIT 61
2175 # define MEM_LOCKED (1LLU<<MEM_LOCKED_BIT)
2176
2177 # ifndef SCHED_NEVER_YIELD
2178 # undef SCHED_YIELD
2179 # define SCHED_YIELD \
2180 do \
2181 { \
2182 if ((i & 0xff) == 0) \
2183 { \
2184 sched_yield(); \
2185 cpu.lockYield++; \
2186 } \
2187 } \
2188 while(0)
2189 # else
2190 # undef SCHED_YIELD
2191 # define SCHED_YIELD \
2192 do \
2193 { \
2194 } \
2195 while(0)
2196 # endif /* ifndef SCHED_NEVER_YIELD */
2197
2198 # if defined (BSD_ATOMICS)
2199 # include <machine/atomic.h>
2200
2201 # define LOCK_CORE_WORD(addr) \
2202 do \
2203 { \
2204 unsigned int i = DEADLOCK_DETECT; \
2205 while ( atomic_testandset_64((volatile uint64_t *)&M[addr], \
2206 MEM_LOCKED_BIT) == 1 && i > 0) \
2207 { \
2208 i--; \
2209 SCHED_YIELD; \
2210 } \
2211 if (i == 0) \
2212 { \
2213 sim_warn ("%s: locked %x addr %x deadlock\n", __func__, \
2214 cpu.locked_addr, addr); \
2215 } \
2216 cpu.lockCnt++; \
2217 if (i == DEADLOCK_DETECT) \
2218 cpu.lockImmediate++; \
2219 cpu.lockWait += (DEADLOCK_DETECT-i); \
2220 cpu.lockWaitMax = ((DEADLOCK_DETECT-i) > cpu.lockWaitMax) ? \
2221 (DEADLOCK_DETECT-i) : cpu.lockWaitMax; \
2222 } \
2223 while (0)
2224
2225 # define LOAD_ACQ_CORE_WORD(res, addr) \
2226 do \
2227 { \
2228 res = atomic_load_acq_64((volatile uint64_t *)&M[addr]); \
2229 } \
2230 while (0)
2231
2232 # define STORE_REL_CORE_WORD(addr, data) \
2233 do \
2234 { \
2235 atomic_store_rel_64((volatile uint64_t *)&M[addr], data & DMASK); \
2236 } \
2237 while (0)
2238
2239 # endif // BSD_ATOMICS
2240
2241 # if defined(GNU_ATOMICS)
2242
2243 # define LOCK_CORE_WORD(addr) \
2244 do \
2245 { \
2246 unsigned int i = DEADLOCK_DETECT; \
2247 while ((__atomic_fetch_or((volatile uint64_t *)&M[addr], \
2248 MEM_LOCKED, __ATOMIC_ACQ_REL) & MEM_LOCKED) \
2249 && i > 0) \
2250 { \
2251 i--; \
2252 SCHED_YIELD; \
2253 } \
2254 if (i == 0) \
2255 { \
2256 sim_warn ("%s: locked %x addr %x deadlock\n", \
2257 __func__, cpu.locked_addr, addr); \
2258 } \
2259 cpu.lockCnt++; \
2260 if (i == DEADLOCK_DETECT) \
2261 cpu.lockImmediate++; \
2262 cpu.lockWait += (DEADLOCK_DETECT-i); \
2263 cpu.lockWaitMax = ((DEADLOCK_DETECT-i) > \
2264 cpu.lockWaitMax) ? (DEADLOCK_DETECT-i) : \
2265 cpu.lockWaitMax; \
2266 } \
2267 while (0)
2268
2269 # define LOAD_ACQ_CORE_WORD(res, addr) \
2270 do \
2271 { \
2272 res = __atomic_load_n((volatile uint64_t *)&M[addr], \
2273 __ATOMIC_ACQUIRE); \
2274 } \
2275 while (0)
2276
2277 # define STORE_REL_CORE_WORD(addr, data) \
2278 do \
2279 { \
2280 __atomic_store_n((volatile uint64_t *)&M[addr], data & \
2281 DMASK, __ATOMIC_RELEASE); \
2282 } \
2283 while (0)
2284
2285 # endif // GNU_ATOMICS
2286
2287 # if defined(SYNC_ATOMICS)
2288 # ifdef MEMORY_ACCESS_NOT_STRONGLY_ORDERED
2289 # define MEM_BARRIER() do { __sync_synchronize(); } while (0)
2290 # else
2291 # define MEM_BARRIER() do {} while (0)
2292 # endif
2293
2294 # define LOCK_CORE_WORD(addr) \
2295 do \
2296 { \
2297 unsigned int i = DEADLOCK_DETECT; \
2298 while ((__sync_fetch_and_or((volatile uint64_t *)&M[addr], \
2299 MEM_LOCKED) & MEM_LOCKED) && i > 0) \
2300 { \
2301 i--; \
2302 SCHED_YIELD; \
2303 } \
2304 if (i == 0) \
2305 { \
2306 sim_warn ("%s: locked %x addr %x deadlock\n", __func__, \
2307 cpu.locked_addr, addr); \
2308 } \
2309 cpu.lockCnt++; \
2310 if (i == DEADLOCK_DETECT) \
2311 cpu.lockImmediate++; \
2312 cpu.lockWait += (DEADLOCK_DETECT-i); \
2313 cpu.lockWaitMax = ((DEADLOCK_DETECT-i) > cpu.lockWaitMax) ? \
2314 (DEADLOCK_DETECT-i) : cpu.lockWaitMax; \
2315 } \
2316 while (0)
2317
2318 # define LOAD_ACQ_CORE_WORD(res, addr) \
2319 do \
2320 { \
2321 res = M[addr]; \
2322 MEM_BARRIER(); \
2323 } \
2324 while (0)
2325
2326 # define STORE_REL_CORE_WORD(addr, data) \
2327 do \
2328 { \
2329 MEM_BARRIER(); \
2330 M[addr] = data & DMASK; \
2331 } \
2332 while (0)
2333
2334 # endif // SYNC_ATOMICS
2335 #endif // LOCKLESS
2336
2337 static inline void core_readN (word24 addr, word36 * data, uint n,
/* ![[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)
*/
2338 UNUSED const char * ctx)
2339 {
2340 for (uint i = 0; i < n; i ++)
2341 {
2342 core_read (addr + i, data + i, ctx);
2343 //HDBGMRead (addr + i, * (data + i), __func__);
2344 }
2345 }
2346
2347 static inline void core_writeN (word24 addr, word36 * data, uint n,
/* ![[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)
*/
2348 UNUSED const char * ctx)
2349 {
2350 for (uint i = 0; i < n; i ++)
2351 {
2352 core_write (addr + i, data [i], ctx);
2353 //HDBGMWrite (addr + i, * (data + i), __func__);
2354 }
2355 }
2356
2357 int is_priv_mode (void);
2358 //void set_went_appending (void);
2359 //void clr_went_appending (void);
2360 //bool get_went_appending (void);
2361 bool get_bar_mode (void);
2362 addr_modes_e get_addr_mode (void);
2363 void set_addr_mode (addr_modes_e mode);
2364 void decode_instruction (word36 inst, DCDstruct * p);
2365 #ifndef SPEED
2366 t_stat set_mem_watch (int32 arg, const char * buf);
2367 #endif
2368 char *str_SDW0 (char * buf, sdw_s *SDW);
2369 int lookup_cpu_mem_map (word24 addr);
2370 void cpu_init (void);
2371 void setup_scbank_map (void);
2372 void add_dps8m_CU_history (void);
2373 void add_dps8m_DUOU_history (word36 flags, word18 ICT, word9 RS_REG, word9 flags2);
2374 void add_dps8m_APU_history (word15 ESN, word21 flags, word24 RMA, word3 RTRR, word9 flags2);
2375 void add_dps8m_EAPU_history (word18 ZCA, word18 opcode);
2376 void add_l68_CU_history (void);
2377 void add_l68_OU_history (void);
2378 void add_l68_DU_history (void);
2379 void add_l68_APU_history (enum APUH_e op);
2380 void add_history_force (uint hset, word36 w0, word36 w1);
2381 void printPtid(pthread_t pt);
2382 word18 get_BAR_address(word18 addr);
2383 #if defined(THREADZ) || defined(LOCKLESS)
2384 t_stat threadz_sim_instr (void);
2385 void * cpu_thread_main (void * arg);
2386 #endif
2387 void cpu_reset_unit_idx (UNUSED uint cpun, bool clear_mem);
2388 void setupPROM (uint cpuNo, unsigned char * PROM);