1 /*
2  * Copyright (c) 2012-2016 Harry Reed
3  * Copyright (c) 2012 Dave Jordan
4  * Copyright (c) 2013-2018 Charles Anthony
5  * Copyright (c) 2016 Jean-Michel Merliot
6  * Copyright (c) 2021 The DPS8M Development Team
7  *
8  * All rights reserved.
9  *
10  * This software is made available under the terms of the ICU
11  * License, version 1.8.1 or later.  For more details, see the
12  * LICENSE.md file at the top-level directory of this distribution.
13  */
14 
15 #ifndef DPS8_H
16 # define DPS8_H
17 
18 # include <stdio.h>
19 # include <stdbool.h>
20 # include <errno.h>
21 # include <inttypes.h>
22 # include <sys/stat.h>
23 # include <sys/time.h>
24 # include <setjmp.h>  // for setjmp/longjmp used by interrupts & faults
25 
26 # if (defined(__APPLE__) && defined(__MACH__)) || defined(__ANDROID__)
27 #  include <libgen.h>  // needed for OS/X and Android
28 # endif
29 
30 # ifndef L68
31 #  ifndef DPS8M
32 #   define DPS8M
33 #  endif
34 # endif
35 
36 # ifdef NEED_128
37 typedef struct { uint64_t h; uint64_t l; } __uint128_t;
38 typedef struct { int64_t h;  uint64_t l; }  __int128_t;
39 #  define construct_128(h, l) ((uint128) { (h), (l) })
40 #  define construct_s128(h, l) ((int128) { (h), (l) })
41 # endif /* ifdef NEED_128 */
42 
43 // Quiet compiler unused warnings
44 # define QUIET_UNUSED
45 
46 # ifndef TESTING
47 // Enable speed over debugging if not TESTING
48 #  define SPEED
49 # endif /* ifndef TESTING */
50 
51 // Enable round-robin multi-CPU
52 //#define ROUND_ROBIN
53 
54 // Experimential dial_out line disconnect delay
55 // FNP polled ~100Hz; 2 secs. is 200 polls
56 # define DISC_DELAY 200
57 
58 //
59 // Dependencies
60 //
61 
62 // PANEL only works on L68
63 # ifdef PANEL
64 #  ifdef DPS8M
65 #   error "PANEL works with L68, not DPS8M"
66 #  endif
67 #  ifndef L68
68 #   define L68
69 #  endif
70 # endif
71 
72 # ifdef PANEL
73 #  define PNL(x) x
74 # else
75 #  define PNL(x)
76 # endif
77 
78 # ifdef L68
79 #  define L68_(x) x
80 # else
81 #  define L68_(x)
82 # endif
83 
84 # ifdef DPS8M
85 #  define DPS8M_(x) x
86 # else
87 #  define DPS8M_(x)
88 # endif
89 
90 // debugging tool
91 # ifdef TESTING
92 #  define IF1 if (cpu.switches.isolts_mode)
93 # else
94 #  define IF1 if (0)
95 # endif
96 
97 //#define OSCAR
98 
99 // DPS8-M support Hex Mode Floating Point
100 # ifdef DPS8M
101 #  define HEX_MODE
102 # endif
103 
104 // Instruction profiler
105 // #define MATRIX
106 
107 // Run TR on work done, not wall clock.
108 // Define one of these; tied to memory access (MEM) or to instruction
109 // execution (EXEC)
110 
111 //#define TR_WORK_MEM
112 # define TR_WORK_EXEC
113 
114 // Multi-threading may require 'volatile' in some place; make it easy
115 // to support both configurations
116 
117 # if defined(THREADZ) || defined(LOCKLESS)
118 #  define vol volatile
119 # else
120 #  define vol
121 # endif
122 
123 # ifndef NEED_128
124 #  ifdef PRIu64
125 #   undef PRIu64
126 #  endif
127 #  ifndef PRIu64
128 #   define PRIu64 "llu"
129 #  endif
130 #  ifdef PRId64
131 #   undef PRId64
132 #  endif
133 #  ifndef PRId64
134 #   define PRId64 "lld"
135 #  endif
136 #  ifdef PRIo64
137 #   undef PRIo64
138 #  endif
139 #  ifndef PRIo64
140 #   define PRIo64 "llo"
141 #  endif
142 # endif
143 
144 # include "sim_defs.h"                                   /* simulator defns */
145 # include "sim_tape.h"
146 
147 // patch supplied by Dave Jordan (jordandave@gmail.com) 29 Nov 2012
148 # ifdef __MINGW32__
149 #  include <stdint.h>
150 typedef t_uint64    u_int64_t;
151 # endif
152 typedef t_uint64    uint64;
153 # ifndef _AIX
154 typedef t_int64     int64;
155 # else
156 typedef long        int64;
157 # endif
158 
159 /* Data types */
160 
161 typedef uint8       word1;
162 typedef uint8       word2;
163 typedef uint8       word3;
164 typedef uint8       word4;
165 typedef uint8       word5;
166 typedef uint8       word6;
167 typedef uint8       word7;
168 typedef uint8       word8;
169 typedef int8        word8s; // signed 8-bit quantity
170 typedef uint16      word9;
171 typedef uint16      word10;
172 typedef uint16      word11;
173 typedef uint16      word12;
174 typedef uint16      word13;
175 typedef uint16      word14;
176 typedef uint16      word15;
177 typedef uint16      word16;
178 typedef uint32      word17;
179 typedef uint32      word18;
180 typedef uint32      word19;
181 typedef int32       word18s;
182 typedef uint32      word20;
183 typedef uint32      word21;
184 typedef uint32      word22;
185 typedef uint32      word23;
186 typedef uint32      word24;
187 typedef uint32      word27;
188 typedef uint32      word28;
189 typedef uint32      word32;
190 typedef uint64      word34;
191 typedef uint64      word36;
192 typedef uint64      word37;
193 typedef uint64      word38;
194 typedef int64       word36s;
195 typedef __uint128_t word72;
196 typedef __int128_t  word72s;
197 typedef __uint128_t word73;
198 typedef __uint128_t word74;
199 
200 typedef __uint128_t uint128;
201 typedef __int128_t  int128;
202 
203 typedef word36      float36;    // single precision float
204 typedef word72      float72;    // double precision float
205 
206 typedef unsigned int uint;      // efficient unsigned int, at least 32 bits
207 
208 # include "dps8_simh.h"
209 # include "dps8_sys.h"
210 # include "dps8_math128.h"
211 # include "dps8_hw_consts.h"
212 # include "dps8_em_consts.h"
213 
214 
215 # define SETF(flags, x)         flags = ((flags) |  (x))
216 # define CLRF(flags, x)         flags = ((flags) & ~(x))
217 # define TSTF(flags, x)         (((flags) & (x)) ? 1 : 0)
218 # define SCF(cond, flags, x)    { if (cond) SETF((flags), x); else CLRF((flags), x); }
219 
220 # define SETBIT(dst, bitno)      ((dst)  |  (1LLU << (bitno)))
221 # define CLRBIT(dst, bitno)      ((dst)  & ~(1LLU << (bitno)))
222 # define TSTBIT(dst, bitno)      (((dst) &  (1LLU << (bitno))) ? 1: 0)
223 
224 typedef enum
225   {
226     UNKNOWN_CYCLE = 0,
227     OPERAND_STORE,
228     OPERAND_READ,
229     INDIRECT_WORD_FETCH,
230     RTCD_OPERAND_FETCH,
231     INSTRUCTION_FETCH,
232     APU_DATA_READ,
233     APU_DATA_STORE,
234     ABSA_CYCLE,
235 # ifdef LOCKLESS
236     OPERAND_RMW,
237     APU_DATA_RMW,
238 # endif
239   } processor_cycle_type;
240 
241 # ifndef LOCKLESS
242 #  define OPERAND_RMW   OPERAND_READ
243 #  define APU_DATA_RMW  APU_DATA_READ
244 # endif
245 
246 # ifndef EIS_PTR4
247 // some breakpoint stuff ...
248 typedef enum
249   {
250     UnknownMAT       = 0,
251     OperandRead,
252     OperandWrite,
253     viaPR
254   } MemoryAccessType;
255 # endif
256 
257 // get 6-bit char @ pos
258 # define GETCHAR(src, pos) (word6)(((word36)src >> (word36)((5 - pos) * 6)) & 077)
259 // get 9-bit byte @ pos
260 # define GETBYTE(src, pos) (word9)(((word36)src >> (word36)((3 - pos) * 9)) & 0777)
261 
262 # ifdef NEED_128
263 #  define YPAIRTO72(ypair) construct_128 ((ypair[0] >> 28) & MASK8,       \
264                                        ((ypair[0] & MASK28) << 36)    | \
265                                         (ypair[1] & MASK36));
266 # else
267 #  define YPAIRTO72(ypair)    (((((word72)(ypair[0] & DMASK)) << 36)    | \
268                                         (ypair[1] & DMASK)) & MASK72)
269 # endif
270 
271 # define GET_TALLY(src) (((src) >> 6) & MASK12)   // 12-bits
272 # define GET_DELTA(src)  ((src) & MASK6)          // 6-bits
273 
274 # ifndef max
275 #  define max(a,b)    max2((a),(b))
276 # endif
277 # define max2(a,b)   ((a) > (b) ? (a) : (b))
278 # define max3(a,b,c) max((a), max((b),(c)))
279 
280 # ifndef min
281 #  define min(a,b)    min2((a),(b))
282 # endif
283 # define min2(a,b)   ((a) < (b) ? (a) : (b))
284 # define min3(a,b,c) min((a), min((b),(c)))
285 
286 // opcode metadata (flag) ...
287 typedef enum
288   {
289     READ_OPERAND    = (1U <<  0),  // fetches/reads operand (CA) from memory
290     STORE_OPERAND   = (1U <<  1),  // stores/writes operand to memory (its a STR-OP)
291 # define RMW             (READ_OPERAND | STORE_OPERAND) // a Read-Modify-Write instruction
292     READ_YPAIR      = (1U <<  2),  // fetches/reads Y-pair operand (CA) from memory
293     STORE_YPAIR     = (1U <<  3),  // stores/writes Y-pair operand to memory
294     READ_YBLOCK8    = (1U <<  4),  // fetches/reads Y-block8 operand (CA) from memory
295     NO_RPT          = (1U <<  5),  // Repeat instructions not allowed
296 //#define NO_RPD          (1U << 6)
297     NO_RPL          = (1U <<  7),
298 //#define NO_RPX          (NO_RPT | NO_RPD | NO_RPL)
299     READ_YBLOCK16   = (1U <<  8),  // fetches/reads Y-block16 operands from memory
300     STORE_YBLOCK16  = (1U <<  9),  // fetches/reads Y-block16 operands from memory
301     TRANSFER_INS    = (1U << 10),  // a transfer instruction
302     TSPN_INS        = (1U << 11),  // a TSPn instruction
303     CALL6_INS       = (1U << 12),  // a call6 instruction
304     PREPARE_CA      = (1U << 13),  // prepare TPR.CA for instruction
305     STORE_YBLOCK8   = (1U << 14),  // stores/writes Y-block8 operand to memory
306     IGN_B29         = (1U << 15),  // Bit-29 has an instruction specific meaning. Ignore.
307     NO_TAG          = (1U << 16),  // tag is interpreted differently and for addressing purposes is effectively 0
308     PRIV_INS        = (1U << 17),  // priveleged instruction
309     NO_BAR          = (1U << 18),  // not allowed in BAR mode
310 //  NO_XEC          = (1U << 19),  // can't be executed via xec/xed
311     NO_XED          = (1U << 20),  // No execution via XEC/XED instruction
312 
313 // EIS operand types
314 
315 # define EOP_ALPHA 1U
316 
317 // bits 21, 22
318     EOP1_ALPHA      = (EOP_ALPHA << 21),
319     EOP1_MASK       = (3U << 21),
320 # define EOP1_SHIFT 21
321 
322 // bits 23, 24
323     EOP2_ALPHA      = (EOP_ALPHA << 23),
324     EOP2_MASK       = (3U << 23),
325 # define EOP2_SHIFT 23
326 
327 // bits 25, 26
328     EOP3_ALPHA      = (EOP_ALPHA << 25),
329     EOP3_MASK       = (3U << 25),
330 # define EOP3_SHIFT 25
331 
332     READ_YBLOCK32   = (1U << 27),  // fetches/reads Y-block16 operands from memory
333     STORE_YBLOCK32  = (1U << 28),  // fetches/reads Y-block16 operands from memory
334   } opc_flag;
335 
336 
337 // opcode metadata (disallowed) modifications
338 typedef enum opc_mod
339   {
340     NO_DU                 = (1U << 0),   // No DU modification allowed (Can these 2 be combined into 1?)
341     NO_DL                 = (1U << 1),   // No DL modification allowed
342 # define NO_DUDL         (NO_DU | NO_DL)
343 
344     NO_CI                 = (1U << 2),   // No character indirect modification (can these next 3 be combined?_
345     NO_SC                 = (1U << 3),   // No sequence character modification
346     NO_SCR                = (1U << 4),   // No sequence character reverse modification
347 # define NO_CSS          (NO_CI | NO_SC | NO_SCR)
348 
349 # define NO_DLCSS        (NO_DU   | NO_CSS)
350 # define NO_DDCSS        (NO_DUDL | NO_CSS)
351 
352     ONLY_AU_QU_AL_QL_XN   = (1U << 5)    // None except au, qu, al, ql, xn
353   } opc_mod;
354 
355 // None except au, qu, al, ql, xn for MF1 and REG
356 // None except du, au, qu, al, ql, xn for MF2
357 // None except au, qu, al, ql, xn for MF1, MF2, and MF3
358 
359 
360 # define IS_NONE(tag) (!(tag))
361 /*! non-tally: du or dl */
362 # define IS_DD(tag) ((_TM(tag) != 040U) && \
363     ((_TD(tag) == 003U) || (_TD(tag) == 007U)))
364 /*! tally: ci, sc, or scr */
365 # define IS_CSS(tag) ((_TM(tag) == 040U) && \
366     ((_TD(tag) == 050U) || (_TD(tag) == 052U) || \
367     (_TD(tag) == 045U)))
368 # define IS_DDCSS(tag) (IS_DD(tag) || IS_CSS(tag))
369 /*! just dl or css */
370 # define IS_DCSS(tag) (((_TM(tag) != 040U) && (_TD(tag) == 007U)) || IS_CSS(tag))
371 
372 // !%WRD  ~0200000  017
373 // !%9    ~0100000  027
374 // !%6    ~0040000  033
375 // !%4    ~0020000  035
376 // !%1    ~0010000  036
377 enum reg_use { is_WRD =  0174000,
378                is_9  =   0274000,
379                is_6  =   0334000,
380                is_4  =   0354000,
381                is_1  =   0364000,
382                is_DU =   04000,
383                is_OU =   02000,
384                ru_A  =   02000 | 01000,
385                ru_Q  =   02000 |  0400,
386                ru_X0 =   02000 |  0200,
387                ru_X1 =   02000 |  0100,
388                ru_X2 =   02000 |   040,
389                ru_X3 =   02000 |   020,
390                ru_X4 =   02000 |   010,
391                ru_X5 =   02000 |    04,
392                ru_X6 =   02000 |    02,
393                ru_X7 =   02000 |    01,
394                ru_none = 02000 |     0 };
395 //, ru_notou = 1024 };
396 
397 # define ru_AQ (ru_A | ru_Q)
398 # define ru_Xn(n) (1 << (7 - (n)))
399 
400 // Basic + EIS opcodes .....
401 struct opcode_s {
402     const char *mne;       // mnemonic
403     opc_flag flags;        // various and sundry flags
404     opc_mod mods;          // disallowed addr mods
405     uint ndes;             // number of operand descriptor words for instruction (mw EIS)
406     enum reg_use reg_use;  // register usage
407 };
408 
409 // operations stuff
410 
411 /*! Y of instruc word */
412 # define Y(i) (i & MASKHI18)
413 /*! X from opcodes in instruc word */
414 # define OPSX(i) ((i & 0007000LLU) >> 9)
415 /*! X from OP_* enum, and X from  */
416 # define X(i) (i & 07U)
417 
418 enum { OP_1     = 00001U,
419     OP_E        = 00002U,
420     OP_BAR      = 00003U,
421     OP_IC       = 00004U,
422     OP_A        = 00005U,
423     OP_Q        = 00006U,
424     OP_AQ       = 00007U,
425     OP_IR       = 00010U,
426     OP_TR       = 00011U,
427     OP_REGS     = 00012U,
428 
429     /* 645/6180 */
430     OP_CPR      = 00021U,
431     OP_DBR      = 00022U,
432     OP_PTP      = 00023U,
433     OP_PTR      = 00024U,
434     OP_RA       = 00025U,
435     OP_SDP      = 00026U,
436     OP_SDR      = 00027U,
437 
438     OP_X        = 01000U
439 };
440 
441 
442 enum eCAFoper {
443     unknown = 0,
444     readCY,
445     writeCY,
446     rmwCY,      // Read-Modify-Write
447 //    readCYpair,
448 //    writeCYpair,
449 //    readCYblock8,
450 //    writeCYblock8,
451 //    readCYblock16,
452 //    writeCYblock16,
453 
454     prepareCA,
455 };
456 typedef enum eCAFoper eCAFoper;
457 
458 # define READOP(i) ((bool) (i->info->flags      &  \
459                            (READ_OPERAND       |  \
460                             READ_YPAIR         |  \
461                             READ_YBLOCK8       |  \
462                             READ_YBLOCK16      |  \
463                             READ_YBLOCK32)))
464 
465 # define WRITEOP(i) ((bool) (i->info->flags     &  \
466                             (STORE_OPERAND     |  \
467                              STORE_YPAIR       |  \
468                              STORE_YBLOCK8     |  \
469                              STORE_YBLOCK16    |  \
470                              STORE_YBLOCK32)))
471 
472 // if it's both read and write it's a RMW
473 # define RMWOP(i) ((bool) READOP(i) && WRITEOP(i))
474 
475 # define TRANSOP(i) ((bool) (i->info->flags & (TRANSFER_INS) ))
476 
477 //
478 // EIS stuff ...
479 //
480 
481 // Numeric operand descriptors
482 
483 
484 // AL39 Table 4-3. Alphanumeric Data Type (TA) Codes
485 enum
486   {
487     CTA9 = 0U,       // 9-bit bytes
488     CTA6 = 1U,       // 6-bit characters
489     CTA4 = 2U,       // 4-bit decimal
490     CTAILL = 3U      // Illegal
491   };
492 
493 // TN - Type Numeric AL39 Table 4-3. Alphanumeric Data Type (TN) Codes
494 enum
495   {
496     CTN9 = 0U,   // 9-bit
497     CTN4 = 1U    // 4-bit
498   };
499 
500 // S - Sign and Decimal Type (AL39 Table 4-4. Sign and Decimal Type (S) Codes)
501 
502 enum
503   {
504     CSFL = 0U,  // Floating-point, leading sign
505     CSLS = 1U,  // Scaled fixed-point, leading sign
506     CSTS = 2U,  // Scaled fixed-point, trailing sign
507     CSNS = 3U   // Scaled fixed-point, unsigned
508   };
509 
510 
511 enum
512   {
513     // Address register flag. This flag controls interpretation of the ADDRESS
514     // field of the operand descriptor just as the "A" flag controls
515     // interpretation of the ADDRESS field of the basic and EIS single-word
516     // instructions.
517     MFkAR = 0x40U,
518     // Register length control. If RL = 0, then the length (N) field of the
519     // operand descriptor contains the length of the operand. If RL = 1, then
520     // the length (N) field of the operand descriptor contains a selector value
521     // specifying a register holding the operand length. Operand length is
522     // interpreted as units of the data size (1-, 4-, 6-, or 9-bit) given in
523     // the associated operand descriptor.
524     MFkRL = 0x20U,
525     // Indirect descriptor control. If ID = 1 for Mfk, then the kth word
526     // following the instruction word is an indirect pointer to the operand
527     // descriptor for the kth operand; otherwise, that word is the operand
528     // descriptor.
529     MFkID = 0x10U,
530 
531     MFkREGMASK = 0xfU
532   };
533 
534 
535 // EIS instruction take on a life of their own. Need to take into account
536 // RNR/SNR/BAR etc.
537 typedef enum
538   {
539     eisUnknown = 0, // uninitialized
540     eisTA = 1,      // type alphanumeric
541     eisTN = 2,      // type numeric
542     eisBIT = 3      // bit string
543   } eisDataType;
544 
545 typedef enum
546   {
547     eRWreadBit = 0,
548     eRWwriteBit
549   } eRW;
550 
551 // Misc constants and macros
552 
553 # define ARRAY_SIZE(a) ( sizeof(a) / sizeof((a)[0]) )
554 
555 # if defined (__MINGW64__) || \
556     defined (__MINGW32__) || \
557     defined (__GNUC__) || \
558     defined (__clang_version__)
559 #  define NO_RETURN __attribute__ ((noreturn))
560 #  define UNUSED    __attribute__ ((unused))
561 # else
562 #  define NO_RETURN
563 #  define UNUSED
564 # endif
565 
566 # define MAX_DEV_NAME_LEN 64
567 
568 #endif // ifdef DPS8_H
569