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