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