~ubuntu-branches/ubuntu/jaunty/simh/jaunty

« back to all changes in this revision

Viewing changes to HP2100/hp2100_cpu1.c

  • Committer: Bazaar Package Importer
  • Author(s): Vince Mulhollon
  • Date: 2007-04-13 20:16:15 UTC
  • mfrom: (1.1.7 upstream) (2.1.3 lenny)
  • Revision ID: james.westby@ubuntu.com-20070413201615-jiar46bgkrs0dw2h
Tags: 3.7.0-1
* New upstream released 03-Feb-2007
* i7094 added which emulates the IBM 7090/7094
* Upstream has converted almost entirely to pdf format for docs
* All manpages updated
* All docs are registered with the doc-base system

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* hp2100_cpu1.c: HP 2100 EAU and UIG simulator
 
1
/* hp2100_cpu1.c: HP 2100/1000 EAU simulator and UIG dispatcher
2
2
 
3
 
   Copyright (c) 2005, Robert M. Supnik
 
3
   Copyright (c) 2005-2007, Robert M. Supnik
4
4
 
5
5
   Permission is hereby granted, free of charge, to any person obtaining a
6
6
   copy of this software and associated documentation files (the "Software"),
23
23
   used in advertising or otherwise to promote the sale, use or other dealings
24
24
   in this Software without prior written authorization from Robert M Supnik.
25
25
 
26
 
   CPU1         Extended arithmetic and optional microcode instructions
 
26
   CPU1         Extended arithmetic and optional microcode dispatchers
27
27
 
28
 
   22-Feb-05    JDB     Fixed missing MPCK on JRS target
29
 
                        Removed EXECUTE instruction (is NOP in actual microcode)
30
 
   18-Feb-05    JDB     Add 2100/21MX Fast FORTRAN Processor instructions
 
28
   04-Jan-07    JDB     Added special DBI dispatcher for non-INT64 diagnostic
 
29
   29-Dec-06    JDB     Allows RRR as NOP if 2114 (diag config test)
 
30
   01-Dec-06    JDB     Substitutes FPP for firmware FP if HAVE_INT64
 
31
   16-Oct-06    JDB     Generalized operands for F-Series FP types
 
32
   26-Sep-06    JDB     Split hp2100_cpu1.c into multiple modules to simplify extensions
 
33
                        Added iotrap parameter to UIG dispatchers for RTE microcode
 
34
   22-Feb-05    JDB     Removed EXECUTE instruction (is NOP in actual microcode)
31
35
   21-Jan-05    JDB     Reorganized CPU option and operand processing flags
32
36
                        Split code along microcode modules
33
37
   15-Jan-05    RMS     Cloned from hp2100_cpu.c
37
41
        (5955-0282, Mar-1980)
38
42
   - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation
39
43
        (92851-90001, Mar-1981)
 
44
   - Macro/1000 Reference Manual (92059-90001, Dec-1992)
40
45
 
41
46
   Additional references are listed with the associated firmware
42
47
   implementations, as are the HP option model numbers pertaining to the
43
48
   applicable CPUs.
44
49
 
45
 
   This source file contains the Extended Arithmetic Unit and various optional
46
 
   User Instruction Group (a.k.a. "Macro") instruction sets for the 2100 and
47
 
   21MX CPUs.  Unit flags indicate which options are present in the current
48
 
   system.
 
50
   This source file contains the Extended Arithmetic Unit simulator and the User
 
51
   Instruction Group (a.k.a. "Macro") dispatcher for the 2100 and 1000 (21MX)
 
52
   CPUs.  The UIG simulators reside in separate source files, due to the large
 
53
   number of firmware options available for the 1000 machines.  Unit flags
 
54
   indicate which options are present in the current system.
 
55
 
 
56
   This module also provides generalized instruction operand processing.
49
57
 
50
58
   The microcode address space of the 2100 encompassed four modules of 256 words
51
 
   each.  The 21MX M-series expanded that to sixteen modules, and the 21MX
52
 
   E-series expanded that still further to sixty-four modules.  Each CPU had its
53
 
   own microinstruction set, although the micromachines of the various 21MX
 
59
   each.  The 1000 M-series expanded that to sixteen modules, and the 1000
 
60
   E/F-series expanded that still further to sixty-four modules.  Each CPU had
 
61
   its own microinstruction set, although the micromachines of the various 1000
54
62
   models were similar internally.
55
63
 
56
64
   Regarding option instruction sets, there was some commonality across CPU
57
65
   types.  EAU instructions were identical across all models, and the floating
58
 
   point set was the same on the 2100 and 21MX.  Other options implemented
 
66
   point set was the same on the 2100 and 1000.  Other options implemented
59
67
   proper instruction supersets (e.g., the Fast FORTRAN Processor from 2100 to
60
 
   21MX-M to 21MX-E to 21MX-F) or functional equivalence with differing code
61
 
   points (the 2000 I/O Processor from 2100 to 21MX).
 
68
   1000-M to 1000-E to 1000-F) or functional equivalence with differing code
 
69
   points (the 2000 I/O Processor from 2100 to 1000 and extended-precision
 
70
   floating-point instructions from 1000-E to 1000-F).
62
71
 
63
72
   The 2100 decoded the EAU and UIG sets separately in hardware and supported
64
73
   only the UIG 0 code points.  Bits 7-4 of a UIG instruction decoded one of
66
75
   entry points could be used directly (as for the floating-point instructions),
67
76
   or additional decoding based on bits 3-0 could be implemented.
68
77
 
69
 
   The 21MX generalized the instruction decoding to a series of microcoded
 
78
   The 1000 generalized the instruction decoding to a series of microcoded
70
79
   jumps, based on the bits in the instruction.  Bits 15-8 indicated the group
71
80
   of the current instruction: EAU (200, 201, 202, 210, and 211), UIG 0 (212),
72
81
   or UIG 1 (203 and 213).  UIG 0, UIG 1, and some EAU instructions were decoded
76
85
   set, so modules needed only to be concerned with decoding their individual
77
86
   entry points within the module.
78
87
 
79
 
   While the 2100 and 21MX hardware decoded these instruction sets differently,
80
 
   the decoding mechanism of the simulation follows that of the 21MX E-series.
 
88
   While the 2100 and 1000 hardware decoded these instruction sets differently,
 
89
   the decoding mechanism of the simulation follows that of the 1000 E/F-series.
81
90
   Where needed, CPU type- or model-specific behavior is simulated.
82
91
 
83
 
   The design of the 21MX microinstruction set was such that executing an
 
92
   The design of the 1000 microinstruction set was such that executing an
84
93
   instruction for which no microcode was present (e.g., executing a FFP
85
94
   instruction when the FFP firmware was not installed) resulted in a NOP.
86
95
   Under simulation, such execution causes an undefined instruction stop.
87
96
*/
88
97
 
89
 
#include <setjmp.h>
90
98
#include "hp2100_defs.h"
91
99
#include "hp2100_cpu.h"
92
 
#include "hp2100_fp1.h"
93
 
 
94
 
/* Operand processing encoding */
95
 
 
96
 
#define OP_NUL          0                               /* no operand */
97
 
#define OP_CON          1                               /* operand is a constant */
98
 
#define OP_VAR          2                               /* operand is a variable */
99
 
#define OP_ADR          3                               /* operand is an address */
100
 
#define OP_ADK          4                               /* op is addr of 1-word const */
101
 
#define OP_ADF          5                               /* op is addr of 2-word const */
102
 
#define OP_ADX          6                               /* op is addr of 3-word const */
103
 
#define OP_ADT          7                               /* op is addr of 4-word const */
104
 
 
105
 
#define OP_N_FLAGS      3                               /* number of flag bits */
106
 
#define OP_M_FLAGS      ((1 << OP_N_FLAGS) - 1)         /* mask for flag bits */
107
 
 
108
 
#define OP_N_F          4                               /* number of op fields */
109
 
 
110
 
#define OP_V_F1         (0 * OP_N_FLAGS)                /* 1st operand field */
111
 
#define OP_V_F2         (1 * OP_N_FLAGS)                /* 2nd operand field */
112
 
#define OP_V_F3         (2 * OP_N_FLAGS)                /* 3rd operand field */
113
 
#define OP_V_F4         (3 * OP_N_FLAGS)                /* 4th operand field */
114
 
 
115
 
/* Operand patterns */
116
 
 
117
 
#define OP_N            (OP_NUL)
118
 
#define OP_C            (OP_CON << OP_V_F1)
119
 
#define OP_V            (OP_VAR << OP_V_F1)
120
 
#define OP_A            (OP_ADR << OP_V_F1)
121
 
#define OP_K            (OP_ADK << OP_V_F1)
122
 
#define OP_F            (OP_ADF << OP_V_F1)
123
 
#define OP_CV           ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2))
124
 
#define OP_AC           ((OP_ADR << OP_V_F1) | (OP_CON << OP_V_F2))
125
 
#define OP_AA           ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2))
126
 
#define OP_AK           ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2))
127
 
#define OP_AX           ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2))
128
 
#define OP_KV           ((OP_ADK << OP_V_F1) | (OP_VAR << OP_V_F2))
129
 
#define OP_KA           ((OP_ADK << OP_V_F1) | (OP_ADR << OP_V_F2))
130
 
#define OP_KK           ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2))
131
 
#define OP_CVA          ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2) | \
132
 
                        (OP_ADR << OP_V_F3))
133
 
#define OP_AAF          ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
134
 
                        (OP_ADF << OP_V_F3))
135
 
#define OP_AAX          ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
136
 
                        (OP_ADX << OP_V_F3))
137
 
#define OP_AXX          ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2) | \
138
 
                        (OP_ADX << OP_V_F3))
139
 
#define OP_AAXX         ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
140
 
                        (OP_ADX << OP_V_F3) | (OP_ADX << OP_V_F4))
141
 
#define OP_KKKK         ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \
142
 
                        (OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4))
143
 
 
144
 
typedef uint32 OP_PAT;                                  /* operand pattern */
145
 
typedef uint32 OPS[OP_N_F * 2];                         /* operand array */
146
 
 
147
 
extern uint16 ABREG[2];
148
 
extern uint32 PC;
149
 
extern uint32 err_PC;
150
 
extern uint32 XR;
151
 
extern uint32 YR;
152
 
extern uint32 E;
153
 
extern uint32 O;
154
 
extern uint32 dms_enb;
155
 
extern uint32 dms_ump;
156
 
extern uint32 dms_sr;
157
 
extern uint32 dms_vr;
158
 
extern uint32 mp_fence;
159
 
extern uint32 iop_sp;
160
 
extern uint32 ion_defer;
161
 
extern uint16 pcq[PCQ_SIZE];
162
 
extern uint32 pcq_p;
163
 
extern uint32 stop_inst;
164
 
extern UNIT cpu_unit;
165
 
 
166
 
t_stat cpu_eau (uint32 IR, uint32 intrq);               /* EAU group handler */
167
 
t_stat cpu_uig_0 (uint32 IR, uint32 intrq);             /* UIG group 0 handler */
168
 
t_stat cpu_uig_1 (uint32 IR, uint32 intrq);             /* UIG group 1 handler */
169
 
 
170
 
static t_stat cpu_fp (uint32 IR, uint32 intrq);         /* Floating-point */
171
 
static t_stat cpu_ffp (uint32 IR, uint32 intrq);        /* Fast FORTRAN Processor */
172
 
static t_stat cpu_iop (uint32 IR, uint32 intrq);        /* 2000 I/O Processor */
173
 
static t_stat cpu_dms (uint32 IR, uint32 intrq);        /* Dynamic mapping system */
174
 
static t_stat cpu_eig (uint32 IR, uint32 intrq);        /* Extended instruction group */
175
 
static t_stat get_ops (OP_PAT pattern, OPS op, uint32 irq);     /* operand processor */
176
 
 
177
 
extern uint32 f_as (uint32 op, t_bool sub);             /* FAD/FSB */
178
 
extern uint32 f_mul (uint32 op);                        /* FMP */
179
 
extern uint32 f_div (uint32 op);                        /* FDV */
180
 
extern uint32 f_fix (void);                             /* FIX */
181
 
extern uint32 f_flt (void);                             /* FLT */
182
 
extern uint32 f_pack (int32 expon);                     /* .PACK helper */
183
 
extern void f_unpack (void);                            /* .FLUN helper */
184
 
extern void f_pwr2 (int32 n);                           /* .PWR2 helper */
 
100
#include "hp2100_cpu1.h"
 
101
 
 
102
#if defined (HAVE_INT64)                                /* int64 support available */
 
103
extern t_stat cpu_fpp (uint32 IR, uint32 intrq);        /* Floating Point Processor */
 
104
extern t_stat cpu_sis (uint32 IR, uint32 intrq);        /* Scientific Instruction */
 
105
#else                                                   /* int64 support unavailable */
 
106
extern t_stat cpu_fp  (uint32 IR, uint32 intrq);        /* Firmware Floating Point */
 
107
#endif                                                  /* end of int64 support */
 
108
 
 
109
extern t_stat cpu_ffp (uint32 IR, uint32 intrq);        /* Fast FORTRAN Processor */
 
110
extern t_stat cpu_ds  (uint32 IR, uint32 intrq);        /* Distributed Systems */
 
111
extern t_stat cpu_vis (uint32 IR, uint32 intrq);        /* Vector Instruction */
 
112
extern t_stat cpu_dbi (uint32 IR, uint32 intrq);        /* Double integer */
 
113
extern t_stat cpu_rte_vma (uint32 IR, uint32 intrq);    /* RTE-4/6 EMA/VMA */
 
114
extern t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap);  /* RTE-6 OS */
 
115
extern t_stat cpu_iop (uint32 IR, uint32 intrq);        /* 2000 I/O Processor */
 
116
extern t_stat cpu_signal  (uint32 IR, uint32 intrq);    /* SIGNAL/1000 Instructions */
 
117
extern t_stat cpu_dms (uint32 IR, uint32 intrq);        /* Dynamic mapping system */
 
118
extern t_stat cpu_eig (uint32 IR, uint32 intrq);        /* Extended instruction group */
185
119
 
186
120
/* EAU
187
121
 
189
123
   operands, including multiply, divide, shifts, and rotates.  Option
190
124
   implementation by CPU was as follows:
191
125
 
192
 
      2116    2100   21MX-M  21MX-E  21MX-F
193
 
     ------  ------  ------  ------  ------
194
 
     12579A   std     std     std     std
 
126
      2114    2115    2116    2100   1000-M  1000-E  1000-F
 
127
     ------  ------  ------  ------  ------  ------  ------
 
128
      N/A    12579A  12579A   std     std     std     std
195
129
 
196
130
   The instruction codes are mapped to routines as follows:
197
131
 
198
132
     Instr.    Bits
199
 
      Code   15-8 7-4   2116    2100   21MX-M  21MX-E  21MX-F  Note
 
133
      Code   15-8 7-4   2116    2100   1000-M  1000-E  1000-F  Note
200
134
     ------  ---- ---  ------  ------  ------  ------  ------  ---------------------
201
 
     100000   200  00                           DIAG    DIAG   Unsupported
 
135
     100000   200  00                          [diag]  [diag]  [self test]
202
136
     100020   200  01   ASL     ASL     ASL     ASL     ASL    Bits 3-0 encode shift
203
137
     100040   200  02   LSL     LSL     LSL     LSL     LSL    Bits 3-0 encode shift
204
 
     100060   200  03                          TIMER   TIMER   Unsupported
 
138
     100060   200  03                          TIMER   TIMER   [deterministic delay]
205
139
     100100   200  04   RRL     RRL     RRL     RRL     RRL    Bits 3-0 encode shift
206
140
     100200   200  10   MPY     MPY     MPY     MPY     MPY
207
141
     100400   201  xx   DIV     DIV     DIV     DIV     DIV
212
146
     104400   211  xx   DST     DST     DST     DST     DST
213
147
 
214
148
   The remaining codes for bits 7-4 are undefined and will cause a simulator
215
 
   stop if enabled.  On a real 21MX-M, all undefined instructions in the 200
 
149
   stop if enabled.  On a real 1000-M, all undefined instructions in the 200
216
150
   group decode as MPY, and all in the 202 group decode as NOP.  On a real
217
 
   21MX-E, instruction patterns 200/05 through 200/07 and 202/03 decode as NOP;
 
151
   1000-E, instruction patterns 200/05 through 200/07 and 202/03 decode as NOP;
218
152
   all others cause erroneous execution.
219
153
 
220
 
   EAU instruction decoding on the 21MX M-series is convoluted.  The JEAU
 
154
   EAU instruction decoding on the 1000 M-series is convoluted.  The JEAU
221
155
   microorder maps IR bits 11, 9-7 and 5-4 to bits 2-0 of the microcode jump
222
156
   address.  The map is detailed on page IC-84 of the ERD.
223
 
        
224
 
   The 21MX E/F-series add two undocumented instructions to the 200 group:
225
 
   TIMER and DIAG.  These are described in the ERD on page IA 5-5, paragraph
226
 
   5-7.  The M-series executes these as MPY and RRL, respectively.  A third
227
 
   instruction, EXECUTE (100120), is also described but was never implemented,
228
 
   and the E/F-series microcode execute a NOP for this instruction code.
229
 
 
230
 
   Under simulation, TIMER, DIAG, and EXECUTE cause undefined instruction stops
231
 
   if the CPU is set to 2100 or 2116.  DIAG and EXECUTE also cause stops on the
232
 
   21MX-M.  TIMER does not, because it is used by several HP programs to
233
 
   differentiate between M- and E/F-series machines.
 
157
 
 
158
   The 1000 E/F-series add two undocumented instructions to the 200 group: TIMER
 
159
   and DIAG.  These are described in the ERD on page IA 5-5, paragraph 5-7.  The
 
160
   M-series executes these as MPY and RRL, respectively.  A third instruction,
 
161
   EXECUTE (100120), is also described but was never implemented, and the
 
162
   E/F-series microcode execute a NOP for this instruction code.
 
163
 
 
164
   Notes:
 
165
 
 
166
     1. Under simulation, TIMER, DIAG, and EXECUTE cause undefined instruction
 
167
        stops if the CPU is set to 21xx.  DIAG and EXECUTE also cause stops on
 
168
        the 1000-M.  TIMER does not, because it is used by several HP programs
 
169
        to differentiate between M- and E/F-series machines.
 
170
 
 
171
     2. DIAG is not implemented under simulation.  On the E/F, it performs a
 
172
        destructive test of all installed memory.  Because of this, it is only
 
173
        functional if the machine is halted, i.e., if the instruction is
 
174
        executed with the INSTR STEP button.  If it is executed in a program,
 
175
        the result is NOP.
 
176
 
 
177
     3. RRR is permitted and executed as NOP if the CPU is a 2114, as the
 
178
        presence of the EAU is tested by the diagnostic configurator to
 
179
        differentiate between 2114 and 2100/1000 CPUs.
234
180
*/
235
181
 
236
182
t_stat cpu_eau (uint32 IR, uint32 intrq)
240
186
uint32 rs, qs, sc, v1, v2, t;
241
187
int32 sop1, sop2;
242
188
 
243
 
if ((cpu_unit.flags & UNIT_EAU) == 0) return stop_inst; /* implemented? */
 
189
if ((cpu_unit.flags & UNIT_EAU) == 0)                   /* option installed? */
 
190
    if ((UNIT_CPU_MODEL == UNIT_2114) && (IR == 0101100))   /* 2114 and RRR 16? */
 
191
        return SCPE_OK;                                 /* allowed as NOP */
 
192
    else
 
193
        return stop_inst;                               /* fail */
244
194
 
245
195
switch ((IR >> 8) & 0377) {                             /* decode IR<15:8> */
246
196
 
248
198
        switch ((IR >> 4) & 017) {                      /* decode IR<7:4> */
249
199
 
250
200
        case 000:                                       /* DIAG 100000 */
251
 
            if (UNIT_CPU_MODEL != UNIT_21MX_E)          /* must be 21MX-E */
 
201
            if (UNIT_CPU_MODEL != UNIT_1000_E)          /* must be 1000-E */
252
202
                return stop_inst;                       /* trap if not */
253
203
            break;                                      /* DIAG is NOP unless halted */
254
204
 
270
220
            break;
271
221
 
272
222
        case 003:                                       /* TIMER 100060 */
273
 
            if (UNIT_CPU_TYPE != UNIT_TYPE_21MX)        /* must be 21MX */
 
223
            if (UNIT_CPU_TYPE != UNIT_TYPE_1000)        /* must be 1000 */
274
224
                return stop_inst;                       /* trap if not */
275
 
            if (UNIT_CPU_MODEL == UNIT_21MX_M)          /* 21MX M-series? */
 
225
            if (UNIT_CPU_MODEL == UNIT_1000_M)          /* 1000 M-series? */
276
226
                goto MPY;                               /* decode as MPY */
277
227
            BR = (BR + 1) & DMASK;                      /* increment B */
278
228
            if (BR) PC = err_PC;                        /* if !=0, repeat */
285
235
            AR = ((AR << sc) | (t >> (16 - sc))) & DMASK;
286
236
            break;
287
237
 
288
 
        case 010:                                       /* MPY 100200 */
 
238
        case 010:                                       /* MPY 100200 (OP_K) */
289
239
        MPY:
290
 
            if (reason = get_ops (OP_K, op, intrq))     /* get operand */
 
240
            if (reason = cpu_ops (OP_K, op, intrq))     /* get operand */
291
241
                break;
292
242
            sop1 = SEXT (AR);                           /* sext AR */
293
 
            sop2 = SEXT (op[0]);                        /* sext mem */
 
243
            sop2 = SEXT (op[0].word);                   /* sext mem */
294
244
            sop1 = sop1 * sop2;                         /* signed mpy */
295
245
            BR = (sop1 >> 16) & DMASK;                  /* to BR'AR */
296
246
            AR = sop1 & DMASK;
300
250
        default:                                        /* others undefined */
301
251
            return stop_inst;
302
252
            }
303
 
        
 
253
 
304
254
        break;
305
255
 
306
 
    case 0201:                                          /* DIV 100400 */
307
 
        if (reason = get_ops (OP_K, op, intrq))         /* get operand */
 
256
    case 0201:                                          /* DIV 100400 (OP_K) */
 
257
        if (reason = cpu_ops (OP_K, op, intrq))         /* get operand */
308
258
            break;
309
259
        if (rs = qs = BR & SIGN) {                      /* save divd sign, neg? */
310
260
            AR = (~AR + 1) & DMASK;                     /* make B'A pos */
311
261
            BR = (~BR + (AR == 0)) & DMASK;             /* make divd pos */
312
262
            }
313
 
        v2 = op[0];                                     /* divr = mem */
 
263
        v2 = op[0].word;                                /* divr = mem */
314
264
        if (v2 & SIGN) {                                /* neg? */
315
265
            v2 = (~v2 + 1) & DMASK;                     /* make divr pos */
316
266
            qs = qs ^ SIGN;                             /* sign of quotient */
338
288
            BR = (SEXT (BR) >> sc) & DMASK;             /* BR'AR ash right */
339
289
            O = 0;
340
290
            break;
341
 
        
 
291
 
342
292
        case 002:                                       /* LSR 101040-101057 */
343
293
            sc = (IR & 017)? (IR & 017): 16;            /* get sc */
344
294
            AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK;
345
295
            BR = BR >> sc;                              /* BR'AR log right */
346
296
            break;
347
 
        
 
297
 
348
298
        case 004:                                       /* RRR 101100-101117 */
349
299
            sc = (IR & 017)? (IR & 017): 16;            /* get sc */
350
300
            t = AR;                                     /* BR'AR rot right */
351
301
            AR = ((AR >> sc) | (BR << (16 - sc))) & DMASK;
352
302
            BR = ((BR >> sc) | (t << (16 - sc))) & DMASK;
353
303
            break;
354
 
        
 
304
 
355
305
        default:                                        /* others undefined */
356
306
            return stop_inst;
357
307
            }
358
 
        
359
 
        break;
360
 
 
361
 
    case 0210:                                          /* DLD 104200 */
362
 
        if (reason = get_ops (OP_F, op, intrq))         /* get operand */
363
 
            break;
364
 
        AR = (op[0] >> 16) & DMASK;                     /* load AR */
365
 
        BR = op[0] & DMASK;                             /* load BR */
366
 
        break;
367
 
 
368
 
    case 0211:                                          /* DST 104400 */
369
 
        if (reason = get_ops (OP_A, op, intrq))         /* get operand */
370
 
            break;
371
 
        WriteW (op[0], AR);                             /* store AR */
372
 
        op[0] = (op[0] + 1) & VAMASK;
373
 
        WriteW (op[0], BR);                             /* store BR */
 
308
 
 
309
        break;
 
310
 
 
311
    case 0210:                                          /* DLD 104200 (OP_D) */
 
312
        if (reason = cpu_ops (OP_D, op, intrq))         /* get operand */
 
313
            break;
 
314
        AR = (op[0].dword >> 16) & DMASK;               /* load AR */
 
315
        BR = op[0].dword & DMASK;                       /* load BR */
 
316
        break;
 
317
 
 
318
    case 0211:                                          /* DST 104400 (OP_A) */
 
319
        if (reason = cpu_ops (OP_A, op, intrq))         /* get operand */
 
320
            break;
 
321
        WriteW (op[0].word, AR);                        /* store AR */
 
322
        WriteW ((op[0].word + 1) & VAMASK, BR);         /* store BR */
374
323
        break;
375
324
 
376
325
    default:                                            /* should never get here */
377
 
        return SCPE_IERR;
378
 
        }
 
326
        return SCPE_IERR;                               /* bad call from cpu_instr */
 
327
    }
379
328
 
380
329
return reason;
381
330
}
383
332
/* UIG 0
384
333
 
385
334
   The first User Instruction Group (UIG) encodes firmware options for the 2100
386
 
   and 21MX.  Instruction codes 105000-105377 are assigned to microcode options
 
335
   and 1000.  Instruction codes 105000-105377 are assigned to microcode options
387
336
   as follows:
388
337
 
389
 
     Instructions   Option Name                 2100   21MX-M  21MX-E  21MX-F
390
 
     -------------  -------------------------  ------  ------  ------  ------
391
 
     105000-105362  2000 I/O Processor          opt      -       -       -
392
 
     105000-105120  Floating Point              opt     std     std     std
393
 
     105200-105237  Fast FORTRAN Processor      opt     opt     opt     std
394
 
     105240-105257  RTE-IVA/B EMA                -       -      opt     opt
395
 
     105240-105257  RTE-6/VMA                    -       -      opt     opt
396
 
     105300-105317  Distributed System           -       -      opt     opt
397
 
     105340-105357  RTE-6/VM Operating System    -       -      opt     opt
 
338
     Instructions   Option Name                  2100   1000-M  1000-E  1000-F
 
339
     -------------  --------------------------  ------  ------  ------  ------
 
340
     105000-105362  2000 I/O Processor           opt      -       -       -
 
341
     105000-105137  Floating Point               opt     std     std     std
 
342
     105200-105237  Fast FORTRAN Processor       opt     opt     opt     std
 
343
     105240-105257  RTE-IVA/B Extended Memory     -       -      opt     opt
 
344
     105240-105257  RTE-6/VM Virtual Memory       -       -      opt     opt
 
345
     105300-105317  Distributed System            -       -      opt     opt
 
346
     105320-105337  Double Integer                -       -      opt      -
 
347
     105320-105337  Scientific Instruction Set    -       -       -      std
 
348
     105340-105357  RTE-6/VM Operating System     -       -      opt     opt
398
349
 
399
350
   Because the 2100 IOP microcode uses the same instruction range as the 2100 FP
400
351
   and FFP options, it cannot coexist with them.  To simplify simulation, the
401
 
   2100 IOP instructions are remapped to the equivalent 21MX instructions and
 
352
   2100 IOP instructions are remapped to the equivalent 1000 instructions and
402
353
   dispatched to the UIG 1 module.
403
354
 
404
355
   Note that if the 2100 IOP is installed, the only valid UIG instructions are
405
356
   IOP instructions, as the IOP used the full 2100 microcode addressing space.
 
357
 
 
358
   The F-Series moved the three-word extended real instructions from the FFP
 
359
   range to the base floating-point range and added four-word double real and
 
360
   two-word double integer instructions.  The double integer instructions
 
361
   occupied some of the vacated extended real instruction codes in the FFP, with
 
362
   the rest assigned to the floating-point range.  Consequently, many
 
363
   instruction codes for the F-Series are different from the E-Series.
 
364
 
 
365
   Notes:
 
366
 
 
367
     1. Product 93585A, available from the "Specials" group, added double
 
368
        integer microcode to the E-Series.  The instruction codes were different
 
369
        from those in the F-Series to avoid conflicting with the E-Series FFP.
 
370
        HP manual number 93585-90007 documents the double integer instructions,
 
371
        but no copy of this manual has been found.  The Macro/1000 manual
 
372
        (92059-090001) lists E-Series double integer instructions as occupying
 
373
        the code points of the F-Series Scientific Instruction Set.
 
374
 
 
375
     2. To run the double-integer instructions diagnostic in the absence of
 
376
        64-bit integer support (and therefore of F-Series simulation), a special
 
377
        DBI dispatcher may be enabled by defining ENABLE_DIAG during
 
378
        compilation.  This dispatcher will remap the F-Series DBI instructions
 
379
        to the E-Series codes, so that the F-Series diagnostic may be run.
 
380
        Because several of the F-Series DBI instruction codes replace M/E-Series
 
381
        FFP codes, this dispatcher will only operate if FFP is disabled.
 
382
 
 
383
        Note that enabling the dispatcher will produce non-standard FP behavior.
 
384
        For example, any code in the range 105000-105017 normally would execute
 
385
        a FAD instruction.  With the dispatcher enabled, 105014 would execute a
 
386
        .DAD, while the other codes would execute a FAD.  Therefore, ENABLE_DIAG
 
387
        should only be used to run the diagnostic and is not intended for
 
388
        general use.
406
389
*/
407
390
 
408
 
t_stat cpu_uig_0 (uint32 IR, uint32 intrq)
 
391
t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap)
409
392
{
410
 
if ((cpu_unit.flags & UNIT_IOP) && (UNIT_CPU_TYPE == UNIT_TYPE_2100)) {
411
 
    if ((IR >= 0105020) && (IR <= 0105057))             /* remap LAI */
412
 
        IR = 0105400 | (IR - 0105020);
413
 
    else if ((IR >= 0105060) && (IR <= 0105117))        /* remap SAI */
414
 
        IR = 0101400 | (IR - 0105060);
415
 
    else {
416
 
        switch (IR) {                                   /* remap others */
417
 
        case 0105000:  IR = 0105470;  break;            /* ILIST */
418
 
        case 0105120:  IR = 0105765;  break;            /* MBYTE (maps to MBT) */
419
 
        case 0105150:  IR = 0105460;  break;            /* CRC   */
420
 
        case 0105160:  IR = 0105467;  break;            /* TRSLT */
421
 
        case 0105200:  IR = 0105777;  break;            /* MWORD (maps to MVW) */
422
 
        case 0105220:  IR = 0105462;  break;            /* READF */
423
 
        case 0105221:  IR = 0105473;  break;            /* PRFIO */
424
 
        case 0105222:  IR = 0105471;  break;            /* PRFEI */
425
 
        case 0105223:  IR = 0105472;  break;            /* PRFEX */
426
 
        case 0105240:  IR = 0105464;  break;            /* ENQ   */
427
 
        case 0105257:  IR = 0105465;  break;            /* PENQ  */
428
 
        case 0105260:  IR = 0105466;  break;            /* DEQ   */
429
 
        case 0105300:  IR = 0105764;  break;            /* SBYTE (maps to SBT) */
430
 
        case 0105320:  IR = 0105763;  break;            /* LBYTE (maps to LBT) */
431
 
        case 0105340:  IR = 0105461;  break;            /* REST  */
432
 
        case 0105362:  IR = 0105474;  break;            /* SAVE  */
433
 
 
434
 
        default:                                        /* all others invalid */
435
 
            return stop_inst;
436
 
            }
437
 
        }
438
 
    if (IR >= 0105700) return cpu_eig (IR, intrq);      /* dispatch to 21MX EIG */
439
 
    else return cpu_iop (IR, intrq);                    /* or to 21MX IOP */
440
 
    }
 
393
if ((cpu_unit.flags & UNIT_IOP) &&                      /* I/O Processor? */
 
394
    (UNIT_CPU_TYPE == UNIT_TYPE_2100))                  /* 2100 CPU? */
 
395
    return cpu_iop (IR, intrq);                         /* dispatch to IOP */
 
396
 
 
397
 
 
398
#if !defined (HAVE_INT64) && defined (ENABLE_DIAG)      /* DBI diagnostic dispatcher wanted */
 
399
 
 
400
if ((cpu_unit.flags & UNIT_FFP) == 0)
 
401
    switch (IR & 0377) {
 
402
        case 0014:                                      /* .DAD 105014 */
 
403
            return cpu_dbi (0105321, intrq);
 
404
 
 
405
        case 0034:                                      /* .DSB 105034 */
 
406
            return cpu_dbi (0105327, intrq);
 
407
 
 
408
        case 0054:                                      /* .DMP 105054 */
 
409
            return cpu_dbi (0105322, intrq);
 
410
 
 
411
        case 0074:                                      /* .DDI 105074 */
 
412
            return cpu_dbi (0105325, intrq);
 
413
 
 
414
        case 0114:                                      /* .DSBR 105114 */
 
415
            return cpu_dbi (0105334, intrq);
 
416
 
 
417
        case 0134:                                      /* .DDIR 105134 */
 
418
            return cpu_dbi (0105326, intrq);
 
419
 
 
420
        case 0203:                                      /* .DNG 105203 */
 
421
            return cpu_dbi (0105323, intrq);
 
422
 
 
423
        case 0204:                                      /* .DCO 105204 */
 
424
            return cpu_dbi (0105324, intrq);
 
425
 
 
426
        case 0210:                                      /* .DIN 105210 */
 
427
            return cpu_dbi (0105330, intrq);
 
428
 
 
429
        case 0211:                                      /* .DDE 105211 */
 
430
            return cpu_dbi (0105331, intrq);
 
431
 
 
432
        case 0212:                                      /* .DIS 105212 */
 
433
            return cpu_dbi (0105332, intrq);
 
434
 
 
435
        case 0213:                                      /* .DDS 105213 */
 
436
            return cpu_dbi (0105333, intrq);
 
437
        }                                               /* otherwise, continue */
 
438
 
 
439
#endif                                                  /* end of DBI dispatcher */
 
440
 
441
441
 
442
442
switch ((IR >> 4) & 017) {                              /* decode IR<7:4> */
443
443
 
447
447
    case 003:                                           /* 105060-105077 */
448
448
    case 004:                                           /* 105100-105117 */
449
449
    case 005:                                           /* 105120-105137 */
450
 
        return cpu_fp (IR, intrq);                      /* Floating Point */
 
450
#if defined (HAVE_INT64)                                /* int64 support available */
 
451
        return cpu_fpp (IR, intrq);                     /* Floating Point Processor */
 
452
#else                                                   /* int64 support unavailable */
 
453
        return cpu_fp (IR, intrq);                      /* Firmware Floating Point */
 
454
#endif                                                  /* end of int64 support */
451
455
 
452
456
    case 010:                                           /* 105200-105217 */
453
457
    case 011:                                           /* 105220-105237 */
454
458
        return cpu_ffp (IR, intrq);                     /* Fast FORTRAN Processor */
455
 
        }
 
459
 
 
460
    case 012:                                           /* 105240-105257 */
 
461
        return cpu_rte_vma (IR, intrq);                 /* RTE-4/6 EMA/VMA */
 
462
 
 
463
    case 014:                                           /* 105300-105317 */
 
464
        return cpu_ds (IR, intrq);                      /* Distributed System */
 
465
 
 
466
    case 015:                                           /* 105320-105337 */
 
467
#if defined (HAVE_INT64)                                /* int64 support available */
 
468
        if (UNIT_CPU_MODEL == UNIT_1000_F)              /* F-series? */
 
469
            return cpu_sis (IR, intrq);                 /* Scientific Instruction */
 
470
        else                                            /* M/E-series */
 
471
#endif                                                  /* end of int64 support */
 
472
            return cpu_dbi (IR, intrq);                 /* Double integer */
 
473
 
 
474
    case 016:                                           /* 105340-105357 */
 
475
        return cpu_rte_os (IR, intrq, iotrap);          /* RTE-6 OS */
 
476
    }
456
477
 
457
478
return stop_inst;                                       /* others undefined */
458
479
}
460
481
/* UIG 1
461
482
 
462
483
   The second User Instruction Group (UIG) encodes firmware options for the
463
 
   21MX.  Instruction codes 101400-101777 and 105400-105777 are assigned to
 
484
   1000.  Instruction codes 101400-101777 and 105400-105777 are assigned to
464
485
   microcode options as follows ("x" is "1" or "5" below):
465
486
 
466
 
     Instructions   Option Name                 21MX-M  21MX-E  21MX-F
467
 
     -------------  --------------------------  ------  ------  ------
468
 
     10x400-10x437  2000 IOP                     opt     opt      -
469
 
     10x460-10x477  2000 IOP                     opt     opt      -
470
 
     10x700-10x737  Dynamic Mapping System       opt     opt     std
471
 
     10x740-10x777  Extended Instruction Group   std     std     std
 
487
     Instructions   Option Name                   1000-M  1000-E  1000-F
 
488
     -------------  ----------------------------  ------  ------  ------
 
489
     10x400-10x437  2000 IOP                       opt     opt      -
 
490
     10x460-10x477  2000 IOP                       opt     opt      -
 
491
     10x460-10x477  Vector Instruction Set          -       -      opt
 
492
     105520-105537  Distributed System             opt      -       -
 
493
     105600-105617  SIGNAL/1000 Instruction Set     -       -      opt
 
494
     10x700-10x737  Dynamic Mapping System         opt     opt     std
 
495
     10x740-10x777  Extended Instruction Group     std     std     std
472
496
 
473
 
   Only 21MX systems execute these instructions.
 
497
   Only 1000 systems execute these instructions.
474
498
*/
475
499
 
476
 
t_stat cpu_uig_1 (uint32 IR, uint32 intrq)
 
500
t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap)
477
501
{
478
 
if (UNIT_CPU_TYPE != UNIT_TYPE_21MX)                    /* 21MX execution? */
 
502
if (UNIT_CPU_TYPE != UNIT_TYPE_1000)                    /* 1000 execution? */
479
503
    return stop_inst;                                   /* no, so trap */
480
504
 
481
505
switch ((IR >> 4) & 017) {                              /* decode IR<7:4> */
482
506
 
483
507
    case 000:                                           /* 105400-105417 */
484
508
    case 001:                                           /* 105420-105437 */
 
509
        return cpu_iop (IR, intrq);                     /* 2000 I/O Processor */
 
510
 
485
511
    case 003:                                           /* 105460-105477 */
486
 
        return cpu_iop (IR, intrq);                     /* 2000 I/O Processor */
 
512
        if (UNIT_CPU_MODEL == UNIT_1000_F)              /* F-series? */
 
513
            return cpu_vis (IR, intrq);                 /* Vector Instruction Set */
 
514
        else                                            /* M/E-series */
 
515
            return cpu_iop (IR, intrq);                 /* 2000 I/O Processor */
 
516
 
 
517
    case 005:                                           /* 105520-105537 */
 
518
        IR = IR ^ 0000620;                              /* remap to 105300-105317 */
 
519
        return cpu_ds (IR, intrq);                      /* Distributed System */
 
520
 
 
521
    case 010:                                           /* 105600-105617 */
 
522
        return cpu_signal (IR, intrq);                  /* SIGNAL/1000 Instructions */
487
523
 
488
524
    case 014:                                           /* 105700-105717 */
489
525
    case 015:                                           /* 105720-105737 */
492
528
    case 016:                                           /* 105740-105737 */
493
529
    case 017:                                           /* 105760-105777 */
494
530
        return cpu_eig (IR, intrq);                     /* Extended Instruction Group */
495
 
        }
 
531
    }
496
532
 
497
533
return stop_inst;                                       /* others undefined */
498
534
}
499
535
 
500
 
/* Floating Point
501
 
 
502
 
   The 2100 and 21MX CPUs share the single-precision (two word) floating point
503
 
   instruction codes.  Option implementation by CPU was as follows:
504
 
 
505
 
      2116    2100   21MX-M  21MX-E  21MX-F
506
 
     ------  ------  ------  ------  ------
507
 
      N/A    12901A   std     std     std
508
 
 
509
 
   The instruction codes are mapped to routines as follows:
510
 
 
511
 
     Instr.  2100/21MX-M/E/F
512
 
     ------  ---------------
513
 
     105000       FAD
514
 
     105020       FSB
515
 
     105040       FMP
516
 
     105060       FDV
517
 
     105100       FIX
518
 
     105120       FLT
519
 
 
520
 
   Bits 3-0 are not decoded by these instructions, so FAD (e.g.) would be
521
 
   executed by any instruction in the range 105000-105017.
522
 
*/
523
 
 
524
 
static const OP_PAT op_fp[6] = {
525
 
  OP_F,    OP_F,    OP_F,    OP_F,                      /*  FAD    FSB    FMP    FDV  */
526
 
  OP_N,    OP_N                                         /*  FIX    FLT    ---    ---  */
527
 
  };
528
 
 
529
 
static t_stat cpu_fp (uint32 IR, uint32 intrq)
530
 
{
531
 
t_stat reason = SCPE_OK;
532
 
OPS op;
533
 
uint32 entry;
534
 
 
535
 
if ((cpu_unit.flags & UNIT_FP) == 0)                    /* FP option installed? */
536
 
    return stop_inst;
537
 
 
538
 
entry = (IR >> 4) & 017;                                /* mask to entry point */
539
 
 
540
 
if (op_fp[entry] != OP_N) {
541
 
    if (reason = get_ops (op_fp[entry], op, intrq))     /* get instruction operands */
542
 
        return reason;
543
 
    }
544
 
 
545
 
switch (entry) {                                        /* decode IR<7:4> */
546
 
 
547
 
    case 000:                                           /* FMP 105000 */
548
 
        O = f_as (op[0], 0);                            /* add, upd ovflo */
549
 
        break;
550
 
 
551
 
    case 001:                                           /* FMP 105020 */
552
 
        O = f_as (op[0], 1);                            /* sub, upd ovflo */
553
 
        break;
554
 
 
555
 
    case 002:                                           /* FMP 105040 */
556
 
        O = f_mul (op[0]);                              /* mul, upd ovflo */
557
 
        break;
558
 
 
559
 
    case 003:                                           /* FDV 105060 */
560
 
        O = f_div (op[0]);                              /* div, upd ovflo */
561
 
        break;
562
 
 
563
 
    case 004:                                           /* FIX 105100 */
564
 
        O = f_fix ();                                   /* fix, upd ovflo */
565
 
        break;
566
 
 
567
 
    case 005:                                           /* FLT 105120 */
568
 
        O = f_flt ();                                   /* float, upd ovflo */
569
 
        break;
570
 
 
571
 
    default:                                            /* should be impossible */
572
 
        return SCPE_IERR;
573
 
        }
574
 
 
575
 
return reason;
576
 
}
577
 
 
578
 
/* Fast FORTRAN Processor
579
 
 
580
 
   The Fast FORTRAN Processor (FFP) is a set of FORTRAN language accelerators
581
 
   and extended-precision (three-word) floating point routines.  Although the
582
 
   FFP is an option for the 2100 and later CPUs, each implements the FFP in a
583
 
   slightly different form.
584
 
 
585
 
   Option implementation by CPU was as follows:
586
 
 
587
 
      2116    2100   21MX-M  21MX-E  21MX-F
588
 
     ------  ------  ------  ------  ------
589
 
      N/A    12907A  12977B  13306B   std
590
 
 
591
 
   The instruction codes are mapped to routines as follows:
592
 
 
593
 
     Instr.   2100  21MX-M 21MX-E 21MX-F    Instr.   2100  21MX-M 21MX-E 21MX-F
594
 
     ------  ------ ------ ------ ------    ------  ------ ------ ------ ------
595
 
     105200    --     --     --   [test]    105220  .XFER  .XFER  .XFER  .XFER
596
 
     105201   DBLE   DBLE   DBLE   DBLE     105221  .GOTO  .GOTO  .GOTO  .GOTO
597
 
     105202   SNGL   SNGL   SNGL   SNGL     105222  ..MAP  ..MAP  ..MAP  ..MAP
598
 
     105203  .XMPY  .XMPY  .XMPY    --      105223  .ENTR  .ENTR  .ENTR  .ENTR
599
 
     105204  .XDIV  .XDIV  .XDIV    --      105224  .ENTP  .ENTP  .ENTP  .ENTP
600
 
     105205  .DFER  .DFER  .DFER  .DFER     105225    --   .PWR2  .PWR2  .PWR2
601
 
     105206    --   .XPAK  .XPAK  .XPAK     105226    --   .FLUN  .FLUN  .FLUN
602
 
     105207    --    XADD   XADD  .BLE      105227  $SETP  $SETP  $SETP  $SETP
603
 
 
604
 
     105210    --    XSUB   XSUB    --      105230    --   .PACK  .PACK  .PACK
605
 
     105211    --    XMPY   XMPY    --      105231    --     --   .CFER  .CFER
606
 
     105212    --    XDIV   XDIV    --      105232    --     --     --   ..FCM
607
 
     105213  .XADD  .XADD  .XADD    --      105233    --     --     --   ..TCM
608
 
     105214  .XSUB  .XSUB  .XSUB  .NGL      105234    --     --     --     --
609
 
     105215    --   .XCOM  .XCOM  .XCOM     105235    --     --     --     --
610
 
     105216    --   ..DCM  ..DCM  ..DCM     105236    --     --     --     --
611
 
     105217    --   DDINT  DDINT  DDINT     105237    --     --     --     --
612
 
 
613
 
   Notes:
614
 
 
615
 
     1. The "$SETP" instruction is sometimes listed as ".SETP" in the
616
 
        documentation.
617
 
 
618
 
     2. Extended-precision arithmetic routines (e.g., .XMPY) exist on the
619
 
        21MX-F, but they are assigned instruction codes in the single-precision
620
 
        floating-point module.
621
 
 
622
 
     3. The software implementation of ..MAP supports 1-, 2-, or 3-dimensional
623
 
        arrays, designated by setting A = -1, 0, and +1, respectively.  The
624
 
        firmware implementation supports only 2- and 3-dimensional access.
625
 
        
626
 
     4. The documentation for ..MAP for the 2100 FFP shows A = 0 or -1 for two
627
 
        or three dimensions, respectively, but the 21MX FFP shows A = 0 or +1.
628
 
        The firmware actually only checks the LSB of A.
629
 
 
630
 
     5. The .DFER and .XFER implementations for the 2100 FFP return X+4 and Y+4
631
 
        in the A and B registers, whereas the 21MX FFP returns X+3 and Y+3.
632
 
 
633
 
     6. The .XFER implementation for the 2100 FFP returns to P+2, whereas the
634
 
        21MX implementation returns to P+1.
635
 
 
636
 
   Additional references:
637
 
    - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981)
638
 
    - Implementing the HP 2100 Fast FORTRAN Processor (12907-90010, Nov-1974)
639
 
*/
640
 
 
641
 
static const OP_PAT op_ffp[32] = {
642
 
  OP_N,    OP_AAF,  OP_AX,   OP_AXX,                    /*  ---   DBLE   SNGL   .XMPY */
643
 
  OP_AXX,  OP_AA,   OP_A,    OP_AAXX,                   /* .XDIV  .DFER  .XPAK  XADD  */
644
 
  OP_AAXX, OP_AAXX, OP_AAXX, OP_AXX,                    /* XSUB   XMPY   XDIV   .XADD */
645
 
  OP_AXX,  OP_A,    OP_A,    OP_AAX,                    /* .XSUB  .XCOM  ..DCM  DDINT */
646
 
  OP_N,    OP_AK,   OP_KKKK, OP_A,                      /* .XFER  .GOTO  ..MAP  .ENTR */
647
 
  OP_A,    OP_K,    OP_N,    OP_K,                      /* .ENTP  .PWR2  .FLUN  $SETP */
648
 
  OP_C,    OP_AA,   OP_N,    OP_N,                      /* .PACK  .CFER   ---    ---  */
649
 
  OP_N,    OP_N,    OP_N,    OP_N                       /*  ---    ---    ---    ---  */
650
 
  };
651
 
 
652
 
static t_stat cpu_ffp (uint32 IR, uint32 intrq)
653
 
{
654
 
t_stat reason = SCPE_OK;
655
 
OPS op, op2;
656
 
uint32 entry;
657
 
uint32 j, sa, sb, sc, da, dc, ra, MA;
658
 
int32 i;
659
 
XPN xop;
660
 
 
661
 
if ((cpu_unit.flags & UNIT_FFP) == 0)                   /* FFP option installed? */
662
 
    return stop_inst;
663
 
 
664
 
entry = IR & 037;                                       /* mask to entry point */
665
 
 
666
 
if (op_ffp[entry] != OP_N) {
667
 
    if (reason = get_ops (op_ffp[entry], op, intrq))    /* get instruction operands */
668
 
        return reason;
669
 
    }
670
 
 
671
 
switch (entry) {                                        /* decode IR<3:0> */
672
 
 
673
 
/* FFP module 1 */
674
 
 
675
 
    case 001:                                           /* DBLE 105201 (OP_AAF) */
676
 
        WriteW (op[1]++, (op[2] >> 16) & DMASK);        /* transfer high mantissa */
677
 
        WriteW (op[1]++, op[2] & 0177400);              /* convert low mantissa */
678
 
        WriteW (op[1], op[2] & 0377);                   /* convert exponent */
679
 
        break;
680
 
 
681
 
    case 002:                                           /* SNGL 105202 (OP_AX) */
682
 
        BR = op[2] >> 16;                               /* move LSB and expon to B */
683
 
        f_unpack ();                                    /* unpack B into A/B */
684
 
        sa = AR;                                        /* save exponent */
685
 
        AR = (op[1] >> 16) & DMASK;                     /* move MSB to A */
686
 
        BR = (op[1] & DMASK) | (BR != 0);               /* move mid to B with carry */
687
 
        O = f_pack (SEXT (sa));                         /* pack into A/B */
688
 
        break;
689
 
 
690
 
#if defined (HAVE_INT64)
691
 
 
692
 
    case 003:                                           /* .XMPY 105203 (OP_AXX) */
693
 
        i = 0;                                          /* params start at op[0] */
694
 
        goto XMPY;                                      /* process as XMPY */
695
 
 
696
 
    case 004:                                           /* .XDIV 105204 (OP_AXX) */
697
 
        i = 0;                                          /* params start at op[0] */
698
 
        goto XDIV;                                      /* process as XDIV */
699
 
 
700
 
#endif
701
 
 
702
 
    case 005:                                           /* .DFER 105205 (OP_AA) */
703
 
        BR = op[0];                                     /* get destination address */
704
 
        AR = op[1];                                     /* get source address */
705
 
        goto XFER;                                      /* do transfer */
706
 
 
707
 
#if defined (HAVE_INT64)
708
 
 
709
 
    case 006:                                           /* .XPAK 105206 (OP_A) */
710
 
        if (UNIT_CPU_TYPE != UNIT_TYPE_21MX)            /* must be 21MX */
711
 
            return stop_inst;                           /* trap if not */
712
 
        if (intrq) {                                    /* interrupt pending? */
713
 
            PC = err_PC;                                /* restart instruction */
714
 
            break;
715
 
            }
716
 
        xop = ReadX (op[0]);                            /* read unpacked */
717
 
        O = x_pak (&xop, xop, SEXT (AR));               /* pack mantissa, exponent */
718
 
        WriteX (op[0], xop);                            /* write back */
719
 
        break;
720
 
 
721
 
    case 007:                                           /* XADD 105207 (OP_AAXX) */
722
 
        i = 1;                                          /* params start at op[1] */
723
 
    XADD:                                               /* enter here from .XADD */
724
 
        if (intrq) {                                    /* interrupt pending? */
725
 
            PC = err_PC;                                /* restart instruction */
726
 
            break;
727
 
            }
728
 
        O = x_add (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3]));  /* add ops */
729
 
        WriteX (op[i], xop);                            /* write sum */
730
 
        break;
731
 
 
732
 
    case 010:                                           /* XSUB 105210 (OP_AAXX) */
733
 
        i = 1;                                          /* params start at op[1] */
734
 
    XSUB:                                               /* enter here from .XSUB */
735
 
        if (intrq) {                                    /* interrupt pending? */
736
 
            PC = err_PC;                                /* restart instruction */
737
 
            break;
738
 
            }
739
 
        O = x_sub (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3]));  /* subtract */
740
 
        WriteX (op[i], xop);                            /* write difference */
741
 
        break;
742
 
 
743
 
    case 011:                                           /* XMPY 105211 (OP_AAXX) */
744
 
        i = 1;                                          /* params start at op[1] */
745
 
    XMPY:                                               /* enter here from .XMPY */
746
 
        if (intrq) {                                    /* interrupt pending? */
747
 
            PC = err_PC;                                /* restart instruction */
748
 
            break;
749
 
            }
750
 
        O = x_mpy (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3]));  /* multiply */
751
 
        WriteX (op[i], xop);                            /* write product */
752
 
        break;
753
 
 
754
 
    case 012:                                           /* XDIV 105212 (OP_AAXX) */
755
 
        i = 1;                                          /* params start at op[1] */
756
 
     XDIV:                                              /* enter here from .XDIV */
757
 
        if (intrq) {                                    /* interrupt pending? */
758
 
            PC = err_PC;                                /* restart instruction */
759
 
            break;
760
 
            }
761
 
        O = x_div (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3]));  /* divide */
762
 
        WriteX (op[i], xop);                            /* write quotient */
763
 
        break;
764
 
 
765
 
    case 013:                                           /* .XADD 105213 (OP_AXX) */
766
 
        i = 0;                                          /* params start at op[0] */
767
 
        goto XADD;                                      /* process as XADD */
768
 
 
769
 
    case 014:                                           /* .XSUB 105214 (OP_AXX) */
770
 
        i = 0;                                          /* params start at op[0] */
771
 
        goto XSUB;                                      /* process as XSUB */
772
 
 
773
 
    case 015:                                           /* .XCOM 105215 (OP_A) */
774
 
        if (UNIT_CPU_TYPE != UNIT_TYPE_21MX)            /* must be 21MX */
775
 
            return stop_inst;                           /* trap if not */
776
 
        xop = ReadX (op[0]);                            /* read operand */
777
 
        AR = x_com (&xop);                              /* neg and rtn exp adj */
778
 
        WriteX (op[0], xop);                            /* write result */
779
 
        break;
780
 
 
781
 
    case 016:                                           /* ..DCM 105216 (OP_A) */
782
 
        if (UNIT_CPU_TYPE != UNIT_TYPE_21MX)            /* must be 21MX */
783
 
            return stop_inst;                           /* trap if not */
784
 
        if (intrq) {                                    /* interrupt pending? */
785
 
            PC = err_PC;                                /* restart instruction */
786
 
            break;
787
 
            }
788
 
        xop = ReadX (op[0]);                            /* read operand */
789
 
        O = x_dcm (&xop);                               /* negate */
790
 
        WriteX (op[0], xop);                            /* write result */
791
 
        break;
792
 
 
793
 
    case 017:                                           /* DDINT 105217 (OP_AAX) */
794
 
        if (UNIT_CPU_TYPE != UNIT_TYPE_21MX)            /* must be 21MX */
795
 
            return stop_inst;                           /* trap if not */
796
 
        if (intrq) {                                    /* interrupt pending? */
797
 
            PC = err_PC;                                /* restart instruction */
798
 
            break;
799
 
            }
800
 
        x_trun (&xop, AS_XPN (op [2]));                 /* truncate operand */
801
 
        WriteX (op[1], xop);                            /* write result */
802
 
        break;
803
 
 
804
 
#endif
805
 
 
806
 
/* FFP module 2 */
807
 
 
808
 
    case 020:                                           /* .XFER 105220 (OP_N) */
809
 
        if (UNIT_CPU_TYPE == UNIT_TYPE_2100)
810
 
            PC = (PC + 1) & VAMASK;                     /* 2100 .XFER returns to P+2 */
811
 
    XFER:                                               /* enter here from .DFER */
812
 
        sc = 3;                                         /* set count for 3-wd xfer */
813
 
        goto CFER;                                      /* do transfer */
814
 
 
815
 
    case 021:                                           /* .GOTO 105221 (OP_AK) */
816
 
        if ((op[1] == 0) || (op[1] & SIGN))             /* index < 1? */
817
 
            op[1] = 1;                                  /* reset min */
818
 
        sa = PC + op[1] - 1;                            /* point to jump target */
819
 
        if (sa >= op[0])                                /* must be <= last target */
820
 
            sa = op[0] - 1;
821
 
        da = ReadW (sa);                                /* get jump target */
822
 
        if (reason = resolve (da, &MA, intrq)) {        /* resolve indirects */
823
 
            PC = err_PC;                                /* irq restarts instruction */
824
 
            break;
825
 
            }
826
 
        mp_dms_jmp (MA);                                /* validate jump addr */
827
 
        PCQ_ENTRY;                                      /* record last PC */
828
 
        PC = MA;                                        /* jump */
829
 
        BR = op[0];                                     /* (for 2100 FFP compat) */
830
 
        break;
831
 
 
832
 
    case 022:                                           /* ..MAP 105222 (OP_KKKK) */
833
 
        op[1] = op[1] - 1;                              /* decrement 1st subscr */
834
 
        if ((AR & 1) == 0)                              /* 2-dim access? */
835
 
            op[1] = op[1] + (op[2] - 1) * op[3];        /* compute element offset */
836
 
        else {                                          /* 3-dim access */
837
 
            if (reason = get_ops (OP_KK, op2, intrq)) { /* get 1st, 2nd ranges */
838
 
                PC = err_PC;                            /* irq restarts instruction */
839
 
                break;
840
 
                }
841
 
            op[1] = op[1] + ((op[3] - 1) * op2[1] + op[2] - 1) * op2[0];  /* offset */
842
 
            }
843
 
        AR = (op[0] + op[1] * BR) & DMASK;              /* return element address */
844
 
        break;
845
 
 
846
 
    case 023:                                           /* .ENTR 105223 (OP_A) */
847
 
        MA = PC - 3;                                    /* get addr of entry point */
848
 
    ENTR:                                               /* enter here from .ENTP */
849
 
        da = op[0];                                     /* get addr of 1st formal */
850
 
        dc = MA - da;                                   /* get count of formals */
851
 
        sa = ReadW (MA);                                /* get addr of return point */
852
 
        ra = ReadW (sa++);                              /* get rtn, ptr to 1st actual */
853
 
        WriteW (MA, ra);                                /* stuff rtn into caller's ent */
854
 
        sc = ra - sa;                                   /* get count of actuals */
855
 
        if (sc > dc) sc = dc;                           /* use min (actuals, formals) */
856
 
        for (j = 0; j < sc; j++) {
857
 
            MA = ReadW (sa++);                          /* get addr of actual */
858
 
            if (reason = resolve (MA, &MA, intrq)) {    /* resolve indirect */
859
 
                PC = err_PC;                            /* irq restarts instruction */
860
 
                break;
861
 
                }
862
 
            WriteW (da++, MA);                          /* put addr into formal */
863
 
            }
864
 
        AR = ra;                                        /* return address */
865
 
        BR = da;                                        /* addr of 1st unused formal */
866
 
        break;
867
 
 
868
 
    case 024:                                           /* .ENTP 105224 (OP_A) */
869
 
        MA = PC - 5;                                    /* get addr of entry point */
870
 
        goto ENTR;
871
 
 
872
 
    case 025:                                           /* .PWR2 105225 (OP_K) */
873
 
        if (UNIT_CPU_TYPE != UNIT_TYPE_21MX)            /* must be 21MX */
874
 
            return stop_inst;                           /* trap if not */
875
 
        f_pwr2 (SEXT (op[0]));                          /* calc result into A/B */
876
 
        break;
877
 
 
878
 
    case 026:                                           /* .FLUN 105226 (OP_N) */
879
 
        if (UNIT_CPU_TYPE != UNIT_TYPE_21MX)            /* must be 21MX */
880
 
            return stop_inst;                           /* trap if not */
881
 
        f_unpack ();                                    /* unpack into A/B */
882
 
        break;
883
 
 
884
 
    case 027:                                           /* $SETP 105227 (OP_K) */
885
 
        j = sa = AR;                                    /* save initial value */
886
 
        sb = BR;                                        /* save initial address */
887
 
        AR = 0;                                         /* AR will return = 0 */
888
 
        BR = BR & VAMASK;                               /* addr must be direct */
889
 
        do {
890
 
            WriteW (BR, j);                             /* write value to address */
891
 
            j = (j + 1) & DMASK;                        /* incr value */
892
 
            BR = (BR + 1) & VAMASK;                     /* incr address */
893
 
            op[0] = op[0] - 1;                          /* decr count */
894
 
            if (op[0] && intrq) {                       /* more and intr? */
895
 
                AR = sa;                                /* restore A */
896
 
                BR = sb;                                /* restore B */
897
 
                PC = err_PC;                            /* restart instruction */
898
 
                break;
899
 
                }
900
 
            }
901
 
        while (op[0] != 0);                             /* loop until count exhausted */
902
 
        break;
903
 
 
904
 
    case 030:                                           /* .PACK 105230 (OP_C) */
905
 
        if (UNIT_CPU_TYPE != UNIT_TYPE_21MX)            /* must be 21MX */
906
 
            return stop_inst;                           /* trap if not */
907
 
        O = f_pack (SEXT (op[0]));                      /* calc A/B and overflow */
908
 
        break;
909
 
 
910
 
    case 031:                                           /* .CFER 105231 (OP_AA) */
911
 
        if (UNIT_CPU_MODEL != UNIT_21MX_E)              /* must be 21MX E-series */
912
 
            return stop_inst;                           /* trap if not */
913
 
        BR = op[0];                                     /* get destination address */
914
 
        AR = op[1];                                     /* get source address */
915
 
        sc = 4;                                         /* set for 4-wd xfer */
916
 
    CFER:                                               /* enter here from .XFER */
917
 
        for (j = 0; j < sc; j++) {                      /* xfer loop */
918
 
            WriteW (BR, ReadW (AR));                    /* transfer word */
919
 
            AR = (AR + 1) & VAMASK;                     /* bump source addr */
920
 
            BR = (BR + 1) & VAMASK;                     /* bump destination addr */
921
 
            }
922
 
        E = 0;                                          /* routine clears E */
923
 
        if (UNIT_CPU_TYPE == UNIT_TYPE_2100) {          /* 2100 (and .DFER/.XFER)? */
924
 
            AR = (AR + 1) & VAMASK;                     /* 2100 FFP returns X+4, Y+4 */
925
 
            BR = (BR + 1) & VAMASK;
926
 
            }
927
 
        break;
928
 
 
929
 
    default:                                            /* others undefined */
930
 
        reason = stop_inst;
931
 
        }
932
 
 
933
 
return reason;
934
 
}
935
 
 
936
 
/* 2000 I/O Processor
937
 
 
938
 
   The IOP accelerates certain operations of the HP 2000 Time-Share BASIC system
939
 
   I/O processor.  Most 2000 systems were delivered with 2100 CPUs, although IOP
940
 
   microcode was developed for the 21MX-M and 21MX-E.  As the I/O processors
941
 
   were specific to the 2000 system, general compatibility with other CPU
942
 
   microcode options was unnecessary, and indeed no other options were possible
943
 
   for the 2100.
944
 
 
945
 
   Option implementation by CPU was as follows:
946
 
 
947
 
      2116    2100   21MX-M  21MX-E  21MX-F
948
 
     ------  ------  ------  ------  ------
949
 
      N/A    13206A  13207A  22702A   N/A
950
 
 
951
 
   The routines are mapped to instruction codes as follows:
952
 
 
953
 
     Instr.     2100      21MX-M/E   Description
954
 
     ------  ----------  ----------  --------------------------------------------
955
 
     SAI     105060-117  101400-037  Store A indexed by B (+/- offset in IR<4:0>)
956
 
     LAI     105020-057  105400-037  Load A indexed by B (+/- offset in IR<4:0>)
957
 
     CRC     105150      105460      Generate CRC
958
 
     REST    105340      105461      Restore registers from stack
959
 
     READF   105220      105462      Read F register (stack pointer)
960
 
     INS       --        105463      Initialize F register (stack pointer)
961
 
     ENQ     105240      105464      Enqueue
962
 
     PENQ    105257      105465      Priority enqueue
963
 
     DEQ     105260      105466      Dequeue
964
 
     TRSLT   105160      105467      Translate character
965
 
     ILIST   105000      105470      Indirect address list (similar to $SETP)
966
 
     PRFEI   105222      105471      Power fail exit with I/O
967
 
     PRFEX   105223      105472      Power fail exit
968
 
     PRFIO   105221      105473      Power fail I/O
969
 
     SAVE    105362      105474      Save registers to stack
970
 
 
971
 
     MBYTE   105120      105765      Move bytes (MBT)
972
 
     MWORD   105200      105777      Move words (MVW)
973
 
     SBYTE   105300      105764      Store byte (SBT)
974
 
     LBYTE   105320      105763      Load byte (LBT)
975
 
 
976
 
   The INS instruction was not required in the 2100 implementation because the
977
 
   stack pointer was actually the memory protect fence register and so could be
978
 
   loaded directly with an OTA/B 05.  Also, the 21MX implementation did not
979
 
   offer the MBYTE, MWORD, SBYTE, and LBYTE instructions because the equivalent
980
 
   instructions from the standard Extended Instruction Group were used instead.
981
 
 
982
 
   Additional reference:
983
 
   - HP 2000 Computer System Sources and Listings Documentation
984
 
        (22687-90020, undated), section 3, pages 2-74 through 2-91.
985
 
*/
986
 
 
987
 
static const OP_PAT op_iop[16] = {
988
 
  OP_V,    OP_N,    OP_N,    OP_N,                      /* CRC    RESTR  READF  INS   */
989
 
  OP_N,    OP_N,    OP_N,    OP_V,                      /* ENQ    PENQ   DEQ    TRSLT */
990
 
  OP_AC,   OP_CVA,  OP_A,    OP_CV,                     /* ILIST  PRFEI  PRFEX  PRFIO */
991
 
  OP_N,    OP_N,    OP_N,    OP_N                       /* SAVE    ---    ---    ---  */
992
 
  };
993
 
 
994
 
static t_stat cpu_iop (uint32 IR, uint32 intrq)
995
 
{
996
 
t_stat reason = SCPE_OK;
997
 
OPS op;
998
 
uint32 entry;
999
 
uint32 hp, tp, i, t, wc, MA;
1000
 
 
1001
 
if ((cpu_unit.flags & UNIT_IOP) == 0)                   /* IOP option installed? */
1002
 
    return stop_inst;
1003
 
 
1004
 
entry = IR & 077;                                       /* mask to entry point */
1005
 
 
1006
 
if (entry <= 037) {                                     /* LAI/SAI 10x400-437 */
1007
 
    MA = ((entry - 020) + BR) & VAMASK;                 /* +/- offset */
1008
 
    if (IR & I_AB) AR = ReadW (MA);                     /* AB = 1 -> LAI */
1009
 
    else WriteW (MA, AR);                               /* AB = 0 -> SAI */
1010
 
    return reason;
1011
 
    }
1012
 
else if (entry <= 057)                                  /* IR = 10x440-457? */
1013
 
    return stop_inst;                                   /* not part of IOP */
1014
 
 
1015
 
entry = entry - 060;                                    /* offset 10x460-477 */
1016
 
 
1017
 
if (op_iop[entry] != OP_N) {
1018
 
    if (reason = get_ops (op_iop[entry], op, intrq))    /* get instruction operands */
1019
 
        return reason;
1020
 
    }
1021
 
 
1022
 
switch (entry) {                                        /* decode IR<5:0> */
1023
 
 
1024
 
    case 000:                                           /* CRC 105460 (OP_V) */
1025
 
        t = ReadW (op[0]) ^ (AR & 0377);                /* xor prev CRC and char */
1026
 
        for (i = 0; i < 8; i++) {                       /* apply polynomial */
1027
 
            t = (t >> 1) | ((t & 1) << 15);             /* rotate right */
1028
 
            if (t & SIGN) t = t ^ 020001;               /* old t<0>? xor */
1029
 
            }
1030
 
        WriteW (op[0], t);                              /* rewrite CRC */
1031
 
        break;
1032
 
 
1033
 
    case 001:                                           /* RESTR 105461 (OP_N) */
1034
 
        iop_sp = (iop_sp - 1) & VAMASK;                 /* decr stack ptr */
1035
 
        t = ReadW (iop_sp);                             /* get E and O */
1036
 
        O = ((t >> 1) ^ 1) & 1;                         /* restore O */
1037
 
        E = t & 1;                                      /* restore E */
1038
 
        iop_sp = (iop_sp - 1) & VAMASK;                 /* decr sp */
1039
 
        BR = ReadW (iop_sp);                            /* restore B */
1040
 
        iop_sp = (iop_sp - 1) & VAMASK;                 /* decr sp */
1041
 
        AR = ReadW (iop_sp);                            /* restore A */
1042
 
        if (UNIT_CPU_MODEL == UNIT_2100)
1043
 
            mp_fence = iop_sp;                          /* 2100 keeps sp in MP FR */
1044
 
        break;
1045
 
 
1046
 
    case 002:                                           /* READF 105462 (OP_N) */
1047
 
        AR = iop_sp;                                    /* copy stk ptr */
1048
 
        break;
1049
 
 
1050
 
    case 003:                                           /* INS 105463 (OP_N) */
1051
 
        iop_sp = AR;                                    /* init stk ptr */
1052
 
        break;
1053
 
 
1054
 
    case 004:                                           /* ENQ 105464 (OP_N) */
1055
 
        hp = ReadW (AR & VAMASK);                       /* addr of head */
1056
 
        tp = ReadW ((AR + 1) & VAMASK);                 /* addr of tail */
1057
 
        WriteW ((BR - 1) & VAMASK, 0);                  /* entry link */
1058
 
        WriteW ((tp - 1) & VAMASK, BR);                 /* tail link */
1059
 
        WriteW ((AR + 1) & VAMASK, BR);                 /* queue tail */
1060
 
        if (hp != 0) PC = (PC + 1) & VAMASK;            /* q not empty? skip */
1061
 
        break;
1062
 
 
1063
 
    case 005:                                           /* PENQ 105465 (OP_N) */
1064
 
        hp = ReadW (AR & VAMASK);                       /* addr of head */
1065
 
        WriteW ((BR - 1) & VAMASK, hp);                 /* becomes entry link */
1066
 
        WriteW (AR & VAMASK, BR);                       /* queue head */
1067
 
        if (hp == 0)                                    /* q empty? */
1068
 
            WriteW ((AR + 1) & VAMASK, BR);             /* queue tail */
1069
 
        else PC = (PC + 1) & VAMASK;                    /* skip */
1070
 
        break;
1071
 
 
1072
 
    case 006:                                           /* DEQ 105466 (OP_N) */
1073
 
        BR = ReadW (AR & VAMASK);                       /* addr of head */
1074
 
        if (BR) {                                       /* queue not empty? */
1075
 
            hp = ReadW ((BR - 1) & VAMASK);             /* read hd entry link */
1076
 
            WriteW (AR & VAMASK, hp);                   /* becomes queue head */
1077
 
            if (hp == 0)                                /* q now empty? */
1078
 
                WriteW ((AR + 1) & VAMASK, (AR + 1) & DMASK);
1079
 
            PC = (PC + 1) & VAMASK;                     /* skip */
1080
 
            }
1081
 
        break;
1082
 
 
1083
 
    case 007:                                           /* TRSLT 105467 (OP_V) */
1084
 
        wc = ReadW (op[0]);                             /* get count */
1085
 
        if (wc & SIGN) break;                           /* cnt < 0? */
1086
 
        while (wc != 0) {                               /* loop */
1087
 
            MA = (AR + AR + ReadB (BR)) & VAMASK;
1088
 
            t = ReadB (MA);                             /* xlate */
1089
 
            WriteB (BR, t);                             /* store char */
1090
 
            BR = (BR + 1) & DMASK;                      /* incr ptr */
1091
 
            wc = (wc - 1) & DMASK;                      /* decr cnt */
1092
 
            if (wc && intrq) {                          /* more and intr? */
1093
 
                WriteW (op[0], wc);                     /* save count */
1094
 
                PC = err_PC;                            /* stop for now */
1095
 
                break;
1096
 
                }
1097
 
            }
1098
 
        break;
1099
 
 
1100
 
    case 010:                                           /* ILIST 105470 (OP_AC) */
1101
 
        do {                                            /* for count */
1102
 
            WriteW (op[0], AR);                         /* write AR to mem */
1103
 
            AR = (AR + 1) & DMASK;                      /* incr AR */
1104
 
            op[0] = (op[0] + 1) & VAMASK;               /* incr MA */
1105
 
            op[1] = (op[1] - 1) & DMASK;                /* decr count */
1106
 
            }
1107
 
        while (op[1] != 0);
1108
 
        break;
1109
 
 
1110
 
    case 011:                                           /* PRFEI 105471 (OP_CVA) */
1111
 
        WriteW (op[1], 1);                              /* set flag */
1112
 
        reason = iogrp (op[0], 0);                      /* execute I/O instr */
1113
 
        op[0] = op[2];                                  /* set rtn and fall through */
1114
 
 
1115
 
    case 012:                                           /* PRFEX 105472 (OP_A) */
1116
 
        PCQ_ENTRY;
1117
 
        PC = ReadW (op[0]) & VAMASK;                    /* jump indirect */
1118
 
        WriteW (op[0], 0);                              /* clear exit */
1119
 
        break;
1120
 
 
1121
 
    case 013:                                           /* PRFIO 105473 (OP_CV) */
1122
 
        WriteW (op[1], 1);                              /* set flag */
1123
 
        reason = iogrp (op[0], 0);                      /* execute instr */
1124
 
        break;
1125
 
 
1126
 
    case 014:                                           /* SAVE 105474 (OP_N) */
1127
 
        WriteW (iop_sp, AR);                            /* save A */
1128
 
        iop_sp = (iop_sp + 1) & VAMASK;                 /* incr stack ptr */
1129
 
        WriteW (iop_sp, BR);                            /* save B */
1130
 
        iop_sp = (iop_sp + 1) & VAMASK;                 /* incr stack ptr */
1131
 
        t = ((O ^ 1) << 1) | E;                         /* merge E and O */
1132
 
        WriteW (iop_sp, t);                             /* save E and O */
1133
 
        iop_sp = (iop_sp + 1) & VAMASK;                 /* incr stack ptr */
1134
 
        if (UNIT_CPU_TYPE == UNIT_TYPE_2100)
1135
 
            mp_fence = iop_sp;                          /* 2100 keeps sp in MP FR */
1136
 
        break;
1137
 
 
1138
 
    default:                                            /* instruction undefined */
1139
 
        return stop_inst;
1140
 
        }
1141
 
 
1142
 
return reason;
1143
 
}
1144
 
 
1145
 
/* Dynamic Mapping System
1146
 
 
1147
 
   The 21MX Dynamic Mapping System (DMS) consisted of the 12731A Memory
1148
 
   Expansion Module (MEM) card and 38 instructions to expand the basic 32K
1149
 
   logical address space to a 1024K physical space.  The MEM provided four maps
1150
 
   of 32 mapping registers each: a system map, a user map, and two DCPC maps.
1151
 
   DMS worked in conjunction with memory protect to provide a "protected mode"
1152
 
   in which memory read and write violations could be trapped, and that
1153
 
   inhibited "privileged" instruction execution that attempted to alter the
1154
 
   memory mapping.
1155
 
 
1156
 
   Option implementation by CPU was as follows:
1157
 
 
1158
 
      2116    2100   21MX-M  21MX-E  21MX-F
1159
 
     ------  ------  ------  ------  ------
1160
 
      N/A     N/A    12976B  13307B   std
1161
 
 
1162
 
   The instruction codes are mapped to routines as follows:
1163
 
 
1164
 
     Instr.  21MX-M  21MX-E/F   Instr.   21MX-M  21MX-E/F
1165
 
     ------  ------  --------   ------   ------  --------
1166
 
     10x700  [xmm]    [xmm]     10x720    XMM      XMM
1167
 
     10x701  [nop]    [test]    10x721    XMS      XMS
1168
 
     10x702   MBI      MBI      10x722    XM*      XM*
1169
 
     10x703   MBF      MBF      10x723   [nop]    [nop]
1170
 
     10x704   MBW      MBW      10x724    XL*      XL*
1171
 
     10x705   MWI      MWI      10x725    XS*      XS*
1172
 
     10x706   MWF      MWF      10x726    XC*      XC*
1173
 
     10x707   MWW      MWW      10x727    LF*      LF*
1174
 
     10x710   SY*      SY*      10x730    RS*      RS*
1175
 
 
1176
 
     10x711   US*      US*      10x731    RV*      RV*
1177
 
     10x712   PA*      PA*      10x732    DJP      DJP
1178
 
     10x713   PB*      PB*      10x733    DJS      DJS
1179
 
     10x714   SSM      SSM      10x734    SJP      SJP
1180
 
     10x715   JRS      JRS      10x735    SJS      SJS
1181
 
     10x716  [nop]    [nop]     10x736    UJP      UJP
1182
 
     10x717  [nop]    [nop]     10x737    UJS      UJS
1183
 
 
1184
 
   Instructions that use IR bit 9 to select the A or B register are designated
1185
 
   with a * above (e.g., 101710 is SYA, and 105710 is SYB).  For those that do
1186
 
   not use this feature, either the 101xxx or 105xxx code will execute the
1187
 
   corresponding instruction, although the 105xxx form is the documented
1188
 
   instruction code.
1189
 
 
1190
 
   Notes:
1191
 
 
1192
 
     1. Instruction code 10x700 will execute the XMM instruction, although
1193
 
        10x720 is the documented instruction value.
1194
 
 
1195
 
     2. The DMS privilege violation rules are:
1196
 
        - load map and CTL5 set (XMM, XMS, XM*, SY*, US*, PA*, PB*)
1197
 
        - load state or fence and UMAP set (JRS, DJP, DJS, SJP, SJS, UJP, UJS, LF*)
1198
 
 
1199
 
     3. The 21MX manual is incorrect in stating that M*I, M*W, XS* are
1200
 
        privileged.
1201
 
*/
1202
 
 
1203
 
static const OP_PAT op_dms[32] = {
1204
 
  OP_N,    OP_N,    OP_N,    OP_N,                      /* xmm    test   MBI    MBF   */
1205
 
  OP_N,    OP_N,    OP_N,    OP_N,                      /* MBW    MWI    MWF    MWW   */
1206
 
  OP_N,    OP_N,    OP_N,    OP_N,                      /* SYA/B  USA/B  PAA/B  PBA/B */
1207
 
  OP_A,    OP_KA,   OP_N,    OP_N,                      /* SSM    JRS    nop    nop   */
1208
 
  OP_N,    OP_N,    OP_N,    OP_N,                      /* XMM    XMS    XMA/B  nop   */
1209
 
  OP_A,    OP_A,    OP_A,    OP_N,                      /* XLA/B  XSA/B  XCA/B  LFA/B */
1210
 
  OP_N,    OP_N,    OP_A,    OP_A,                      /* RSA/B  RVA/B  DJP    DJS   */
1211
 
  OP_A,    OP_A,    OP_A,    OP_A                       /* SJP    SJS    UJP    UJS   */
1212
 
  };
1213
 
 
1214
 
static t_stat cpu_dms (uint32 IR, uint32 intrq)
1215
 
{
1216
 
t_stat reason = SCPE_OK;
1217
 
OPS op;
1218
 
uint32 entry, absel;
1219
 
uint32 i, t, mapi, mapj;
1220
 
 
1221
 
if ((cpu_unit.flags & UNIT_DMS) == 0)                   /* DMS option installed? */
1222
 
    return stop_inst;
1223
 
 
1224
 
absel = (IR & I_AB)? 1: 0;                              /* get A/B select */
1225
 
entry = IR & 037;                                       /* mask to entry point */
1226
 
 
1227
 
if (op_dms[entry] != OP_N) {
1228
 
    if (reason = get_ops (op_dms[entry], op, intrq))    /* get instruction operands */
1229
 
        return reason;
1230
 
    }
1231
 
 
1232
 
switch (entry) {                                        /* decode IR<3:0> */
1233
 
 
1234
 
/* DMS module 1 */
1235
 
 
1236
 
    case 000:                                           /* [undefined] 105700 (OP_N) */
1237
 
        goto XMM;                                       /* decodes as XMM */
1238
 
 
1239
 
    case 001:                                           /* [self test] 105701 (OP_N) */
1240
 
        ABREG[absel] = ABREG[absel] ^ DMASK;            /* CMA or CMB */
1241
 
        break;
1242
 
 
1243
 
    case 002:                                           /* MBI 105702 (OP_N) */
1244
 
        AR = AR & ~1;                                   /* force A, B even */
1245
 
        BR = BR & ~1;
1246
 
        while (XR != 0) {                               /* loop */
1247
 
            t = ReadB (AR);                             /* read curr */
1248
 
            WriteBA (BR, t);                            /* write alt */
1249
 
            AR = (AR + 1) & DMASK;                      /* incr ptrs */
1250
 
            BR = (BR + 1) & DMASK;
1251
 
            XR = (XR - 1) & DMASK;
1252
 
            if (XR && intrq && !(AR & 1)) {             /* more, int, even? */
1253
 
                PC = err_PC;                            /* stop for now */
1254
 
                break;
1255
 
                }
1256
 
            }
1257
 
        break;
1258
 
 
1259
 
    case 003:                                           /* MBF 105703 (OP_N) */
1260
 
        AR = AR & ~1;                                   /* force A, B even */
1261
 
        BR = BR & ~1;
1262
 
        while (XR != 0) {                               /* loop */
1263
 
            t = ReadBA (AR);                            /* read alt */
1264
 
            WriteB (BR, t);                             /* write curr */
1265
 
            AR = (AR + 1) & DMASK;                      /* incr ptrs */
1266
 
            BR = (BR + 1) & DMASK;
1267
 
            XR = (XR - 1) & DMASK;
1268
 
            if (XR && intrq && !(AR & 1)) {             /* more, int, even? */
1269
 
                PC = err_PC;                            /* stop for now */
1270
 
                break;
1271
 
                }
1272
 
            }
1273
 
        break;
1274
 
 
1275
 
    case 004:                                           /* MBW 105704 (OP_N) */
1276
 
        AR = AR & ~1;                                   /* force A, B even */
1277
 
        BR = BR & ~1;
1278
 
        while (XR != 0) {                               /* loop */
1279
 
            t = ReadBA (AR);                            /* read alt */
1280
 
            WriteBA (BR, t);                            /* write alt */
1281
 
            AR = (AR + 1) & DMASK;                      /* incr ptrs */
1282
 
            BR = (BR + 1) & DMASK;
1283
 
            XR = (XR - 1) & DMASK;
1284
 
            if (XR && intrq && !(AR & 1)) {             /* more, int, even? */
1285
 
                PC = err_PC;                            /* stop for now */
1286
 
                break;
1287
 
                }
1288
 
            }
1289
 
        break;
1290
 
 
1291
 
    case 005:                                           /* MWI 105705 (OP_N) */
1292
 
        while (XR != 0) {                               /* loop */
1293
 
            t = ReadW (AR & VAMASK);                    /* read curr */
1294
 
            WriteWA (BR & VAMASK, t);                   /* write alt */
1295
 
            AR = (AR + 1) & DMASK;                      /* incr ptrs */
1296
 
            BR = (BR + 1) & DMASK;
1297
 
            XR = (XR - 1) & DMASK;
1298
 
            if (XR && intrq) {                          /* more and intr? */
1299
 
                PC = err_PC;                            /* stop for now */
1300
 
                break;
1301
 
                }
1302
 
            }
1303
 
        break;
1304
 
 
1305
 
    case 006:                                           /* MWF 105706 (OP_N) */
1306
 
        while (XR != 0) {                               /* loop */
1307
 
            t = ReadWA (AR & VAMASK);                   /* read alt */
1308
 
            WriteW (BR & VAMASK, t);                    /* write curr */
1309
 
            AR = (AR + 1) & DMASK;                      /* incr ptrs */
1310
 
            BR = (BR + 1) & DMASK;
1311
 
            XR = (XR - 1) & DMASK;
1312
 
            if (XR && intrq) {                          /* more and intr? */
1313
 
                PC = err_PC;                            /* stop for now */
1314
 
                break;
1315
 
                }
1316
 
            }
1317
 
        break;
1318
 
 
1319
 
    case 007:                                           /* MWW 105707 (OP_N) */
1320
 
        while (XR != 0) {                               /* loop */
1321
 
            t = ReadWA (AR & VAMASK);                   /* read alt */
1322
 
            WriteWA (BR & VAMASK, t);                   /* write alt */
1323
 
            AR = (AR + 1) & DMASK;                      /* incr ptrs */
1324
 
            BR = (BR + 1) & DMASK;
1325
 
            XR = (XR - 1) & DMASK;
1326
 
            if (XR && intrq) {                          /* more and intr? */
1327
 
                PC = err_PC;                            /* stop for now */
1328
 
                break;
1329
 
                }
1330
 
            }
1331
 
        break;
1332
 
 
1333
 
    case 010:                                           /* SYA, SYB 10x710 (OP_N) */
1334
 
    case 011:                                           /* USA, USB 10x711 (OP_N) */
1335
 
    case 012:                                           /* PAA, PAB 10x712 (OP_N) */
1336
 
    case 013:                                           /* PBA, PBB 10x713 (OP_N) */
1337
 
        mapi = (IR & 03) << VA_N_PAG;                   /* map base */
1338
 
        if (ABREG[absel] & SIGN) {                      /* store? */
1339
 
            for (i = 0; i < MAP_LNT; i++) {
1340
 
                t = dms_rmap (mapi + i);                /* map to memory */
1341
 
                WriteW ((ABREG[absel] + i) & VAMASK, t);
1342
 
                }
1343
 
            }
1344
 
        else {                                          /* load */
1345
 
            dms_viol (err_PC, MVI_PRV);                 /* priv if PRO */
1346
 
            for (i = 0; i < MAP_LNT; i++) {
1347
 
                t = ReadW ((ABREG[absel] + i) & VAMASK);
1348
 
                dms_wmap (mapi + i, t);                 /* mem to map */
1349
 
                }
1350
 
            }
1351
 
        ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK;
1352
 
        break;
1353
 
 
1354
 
    case 014:                                           /* SSM 105714 (OP_A) */
1355
 
        WriteW (op[0], dms_upd_sr ());                  /* store stat */
1356
 
        break;
1357
 
 
1358
 
    case 015:                                           /* JRS 105715 (OP_KA) */
1359
 
        if (dms_ump) dms_viol (err_PC, MVI_PRV);        /* priv viol if prot */
1360
 
        dms_enb = 0;                                    /* assume off */
1361
 
        dms_ump = SMAP;
1362
 
        if (op[0] & 0100000) {                          /* set enable? */
1363
 
            dms_enb = 1;
1364
 
            if (op[0] & 0040000) dms_ump = UMAP;        /* set/clr usr */
1365
 
            }
1366
 
        mp_dms_jmp (op[1]);                             /* mpck jmp target */
1367
 
        PCQ_ENTRY;                                      /* save old PC */
1368
 
        PC = op[1];                                     /* jump */
1369
 
        ion_defer = 1;                                  /* defer intr */
1370
 
        break;
1371
 
 
1372
 
/* DMS module 2 */
1373
 
 
1374
 
    case 020:                                           /* XMM 105720 (OP_N) */
1375
 
    XMM:
1376
 
        if (XR == 0) break;                             /* nop? */
1377
 
        while (XR != 0) {                               /* loop */
1378
 
            if (XR & SIGN) {                            /* store? */
1379
 
                t = dms_rmap (AR);                      /* map to mem */
1380
 
                WriteW (BR & VAMASK, t);
1381
 
                XR = (XR + 1) & DMASK;
1382
 
                }
1383
 
            else {                                      /* load */
1384
 
                dms_viol (err_PC, MVI_PRV);             /* priv viol if prot */
1385
 
                t = ReadW (BR & VAMASK);                /* mem to map */
1386
 
                dms_wmap (AR, t);
1387
 
                XR = (XR - 1) & DMASK;
1388
 
                }
1389
 
            AR = (AR + 1) & DMASK;
1390
 
            BR = (BR + 1) & DMASK;
1391
 
            if (intrq && ((XR & 017) == 017)) {         /* intr, grp of 16? */
1392
 
                PC = err_PC;                            /* stop for now */
1393
 
                break;
1394
 
                }
1395
 
            }
1396
 
        break;
1397
 
 
1398
 
    case 021:                                           /* XMS 105721 (OP_N) */
1399
 
        if ((XR & SIGN) || (XR == 0)) break;            /* nop? */
1400
 
        dms_viol (err_PC, MVI_PRV);                     /* priv viol if prot */
1401
 
        while (XR != 0) {
1402
 
            dms_wmap (AR, BR);                          /* AR to map */
1403
 
            XR = (XR - 1) & DMASK;
1404
 
            AR = (AR + 1) & DMASK;
1405
 
            BR = (BR + 1) & DMASK;
1406
 
            if (intrq && ((XR & 017) == 017)) {         /* intr, grp of 16? */
1407
 
                PC = err_PC;
1408
 
                break;
1409
 
                }
1410
 
            }
1411
 
        break;
1412
 
 
1413
 
    case 022:                                           /* XMA, XMB 10x722 (OP_N) */
1414
 
        dms_viol (err_PC, MVI_PRV);                     /* priv viol if prot */
1415
 
        if (ABREG[absel] & 0100000) mapi = UMAP;
1416
 
        else mapi = SMAP;
1417
 
        if (ABREG[absel] & 0000001) mapj = PBMAP;
1418
 
        else mapj = PAMAP;
1419
 
        for (i = 0; i < MAP_LNT; i++) {
1420
 
            t = dms_rmap (mapi + i);                    /* read map */
1421
 
            dms_wmap (mapj + i, t);                     /* write map */
1422
 
            }
1423
 
        break;
1424
 
 
1425
 
    case 024:                                           /* XLA, XLB 10x724 (OP_A) */
1426
 
        ABREG[absel] = ReadWA (op[0]);                  /* load alt */
1427
 
        break;
1428
 
 
1429
 
    case 025:                                           /* XSA, XSB 10x725 (OP_A) */
1430
 
        WriteWA (op[0], ABREG[absel]);                  /* store alt */
1431
 
        break;
1432
 
 
1433
 
    case 026:                                           /* XCA, XCB 10x726 (OP_A) */
1434
 
        if (ABREG[absel] != ReadWA (op[0]))             /* compare alt */
1435
 
            PC = (PC + 1) & VAMASK;
1436
 
        break;
1437
 
 
1438
 
    case 027:                                           /* LFA, LFB 10x727 (OP_N) */
1439
 
        if (dms_ump) dms_viol (err_PC, MVI_PRV);        /* priv viol if prot */
1440
 
        dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) |
1441
 
            (ABREG[absel] & (MST_FLT | MST_FENCE));
1442
 
        break;
1443
 
 
1444
 
    case 030:                                           /* RSA, RSB 10x730 (OP_N) */
1445
 
        ABREG[absel] = dms_upd_sr ();                   /* save stat */
1446
 
        break;
1447
 
 
1448
 
    case 031:                                           /* RVA, RVB 10x731 (OP_N) */
1449
 
        ABREG[absel] = dms_vr;                          /* save viol */
1450
 
        break;
1451
 
 
1452
 
    case 032:                                           /* DJP 105732 (OP_A) */
1453
 
        if (dms_ump) dms_viol (err_PC, MVI_PRV);        /* priv viol if prot */
1454
 
        mp_dms_jmp (op[0]);                             /* validate jump addr */
1455
 
        PCQ_ENTRY;                                      /* save curr PC */
1456
 
        PC = op[0];                                     /* new PC */
1457
 
        dms_enb = 0;                                    /* disable map */
1458
 
        dms_ump = SMAP;
1459
 
        ion_defer = 1;
1460
 
        break;
1461
 
 
1462
 
    case 033:                                           /* DJS 105733 (OP_A) */
1463
 
        if (dms_ump) dms_viol (err_PC, MVI_PRV);        /* priv viol if prot */
1464
 
        WriteW (op[0], PC);                             /* store ret addr */
1465
 
        PCQ_ENTRY;                                      /* save curr PC */
1466
 
        PC = (op[0] + 1) & VAMASK;                      /* new PC */
1467
 
        dms_enb = 0;                                    /* disable map */
1468
 
        dms_ump = SMAP;
1469
 
        ion_defer = 1;                                  /* defer intr */
1470
 
        break;
1471
 
 
1472
 
    case 034:                                           /* SJP 105734 (OP_A) */
1473
 
        if (dms_ump) dms_viol (err_PC, MVI_PRV);        /* priv viol if prot */
1474
 
        mp_dms_jmp (op[0]);                             /* validate jump addr */
1475
 
        PCQ_ENTRY;                                      /* save curr PC */
1476
 
        PC = op[0];                                     /* jump */
1477
 
        dms_enb = 1;                                    /* enable system */
1478
 
        dms_ump = SMAP;
1479
 
        ion_defer = 1;                                  /* defer intr */
1480
 
        break;
1481
 
 
1482
 
    case 035:                                           /* SJS 105735 (OP_A) */
1483
 
        if (dms_ump) dms_viol (err_PC, MVI_PRV);        /* priv viol if prot */
1484
 
        t = PC;                                         /* save retn addr */
1485
 
        PCQ_ENTRY;                                      /* save curr PC */
1486
 
        PC = (op[0] + 1) & VAMASK;                      /* new PC */
1487
 
        dms_enb = 1;                                    /* enable system */
1488
 
        dms_ump = SMAP;
1489
 
        WriteW (op[0], t);                              /* store ret addr */
1490
 
        ion_defer = 1;                                  /* defer intr */
1491
 
        break;
1492
 
 
1493
 
    case 036:                                           /* UJP 105736 (OP_A) */
1494
 
        if (dms_ump) dms_viol (err_PC, MVI_PRV);        /* priv viol if prot */
1495
 
        mp_dms_jmp (op[0]);                             /* validate jump addr */
1496
 
        PCQ_ENTRY;                                      /* save curr PC */
1497
 
        PC = op[0];                                     /* jump */
1498
 
        dms_enb = 1;                                    /* enable user */
1499
 
        dms_ump = UMAP;
1500
 
        ion_defer = 1;                                  /* defer intr */
1501
 
        break;
1502
 
 
1503
 
    case 037:                                           /* UJS 105737 (OP_A) */
1504
 
        if (dms_ump) dms_viol (err_PC, MVI_PRV);        /* priv viol if prot */
1505
 
        t = PC;                                         /* save retn addr */
1506
 
        PCQ_ENTRY;                                      /* save curr PC */
1507
 
        PC = (op[0] + 1) & VAMASK;                      /* new PC */
1508
 
        dms_enb = 1;                                    /* enable user */
1509
 
        dms_ump = UMAP;
1510
 
        WriteW (op[0], t);                              /* store ret addr */
1511
 
        ion_defer = 1;                                  /* defer intr */
1512
 
        break;
1513
 
 
1514
 
    default:                                            /* others NOP */
1515
 
        break;
1516
 
        }
1517
 
 
1518
 
return reason;
1519
 
}
1520
 
 
1521
 
/* Extended Instruction Group
1522
 
 
1523
 
   The Extended Instruction Group (EIG) adds 32 index and 10 bit/byte/word
1524
 
   manipulation instructions to the 21MX base set.  These instructions
1525
 
   use the new X and Y index registers that were added to the 21MX.
1526
 
 
1527
 
   Option implementation by CPU was as follows:
1528
 
 
1529
 
      2116    2100   21MX-M  21MX-E  21MX-F
1530
 
     ------  ------  ------  ------  ------
1531
 
      N/A     N/A     std     std     std
1532
 
 
1533
 
   The instruction codes are mapped to routines as follows:
1534
 
 
1535
 
     Instr.  21MX-M/E/F   Instr.   21MX-M/E/F
1536
 
     ------  ----------   ------   ----------
1537
 
     10x740     S*X       10x760      ISX
1538
 
     10x741     C*X       10x761      DSX
1539
 
     10x742     L*X       10x762      JLY
1540
 
     10x743     STX       10x763      LBT
1541
 
     10x744     CX*       10x764      SBT
1542
 
     10x745     LDX       10x765      MBT
1543
 
     10x746     ADX       10x766      CBT
1544
 
     10x747     X*X       10x767      SFB
1545
 
 
1546
 
     10x750     S*Y       10x770      ISY
1547
 
     10x751     C*Y       10x771      DSY
1548
 
     10x752     L*Y       10x772      JPY
1549
 
     10x753     STY       10x773      SBS
1550
 
     10x754     CY*       10x774      CBS
1551
 
     10x755     LDY       10x775      TBS
1552
 
     10x756     ADY       10x776      CMW
1553
 
     10x757     X*Y       10x777      MVW
1554
 
 
1555
 
   Instructions that use IR bit 9 to select the A or B register are designated
1556
 
   with a * above (e.g., 101740 is SAX, and 105740 is SBX).  For those that do
1557
 
   not use this feature, either the 101xxx or 105xxx code will execute the
1558
 
   corresponding instruction, although the 105xxx form is the documented
1559
 
   instruction code.
1560
 
 
1561
 
   Notes:
1562
 
 
1563
 
     1. The LBT, SBT, MBT, and MVW instructions are used as part of the 2100 IOP
1564
 
        implementation.  When so called, the MBT and MVW instructions have the
1565
 
        additional restriction that the count must be positive.
1566
 
*/
1567
 
 
1568
 
static const OP_PAT op_eig[32] = {
1569
 
  OP_A,    OP_N,    OP_A,    OP_A,                      /* S*X    C*X    L*X    STX   */
1570
 
  OP_N,    OP_K,    OP_K,    OP_N,                      /* CX*    LDX    ADX    X*X   */
1571
 
  OP_A,    OP_N,    OP_A,    OP_A,                      /* S*Y    C*Y    L*Y    STY   */
1572
 
  OP_N,    OP_K,    OP_K,    OP_N,                      /* CY*    LDY    ADY    X*Y   */
1573
 
  OP_N,    OP_N,    OP_A,    OP_N,                      /* ISX    DSX    JLY    LBT   */
1574
 
  OP_N,    OP_KV,   OP_KV,   OP_N,                      /* SBT    MBT    CBT    SFB   */
1575
 
  OP_N,    OP_N,    OP_C,    OP_KA,                     /* ISY    DSY    JPY    SBS   */
1576
 
  OP_KA,   OP_KK,   OP_KV,   OP_KV                      /* CBS    TBS    CMW    MVW   */
1577
 
  };
1578
 
 
1579
 
static t_stat cpu_eig (uint32 IR, uint32 intrq)
1580
 
{
1581
 
t_stat reason = SCPE_OK;
1582
 
OPS op;
1583
 
uint32 entry, absel;
1584
 
uint32 t, v1, v2, wc;
1585
 
int32 sop1, sop2;
1586
 
 
1587
 
absel = (IR & I_AB)? 1: 0;                              /* get A/B select */
1588
 
entry = IR & 037;                                       /* mask to entry point */
1589
 
 
1590
 
if (op_eig[entry] != OP_N) {
1591
 
    if (reason = get_ops (op_eig[entry], op, intrq))    /* get instruction operands */
1592
 
        return reason;
1593
 
    }
1594
 
 
1595
 
switch (entry) {                                        /* decode IR<4:0> */
1596
 
 
1597
 
/* EIG module 1 */
1598
 
 
1599
 
    case 000:                                           /* SAX, SBX 10x740 (OP_A) */
1600
 
        op[0] = (op[0] + XR) & VAMASK;                  /* indexed addr */
1601
 
        WriteW (op[0], ABREG[absel]);                   /* store */
1602
 
        break;
1603
 
 
1604
 
    case 001:                                           /* CAX, CBX 10x741 (OP_N) */
1605
 
        XR = ABREG[absel];                              /* copy to XR */
1606
 
        break;
1607
 
 
1608
 
    case 002:                                           /* LAX, LBX 10x742 (OP_A) */
1609
 
        op[0] = (op[0] + XR) & VAMASK;                  /* indexed addr */
1610
 
        ABREG[absel] = ReadW (op[0]);                   /* load */
1611
 
        break;
1612
 
 
1613
 
    case 003:                                           /* STX 105743 (OP_A) */
1614
 
        WriteW (op[0], XR);                             /* store XR */
1615
 
        break;
1616
 
 
1617
 
    case 004:                                           /* CXA, CXB 10x744 (OP_N) */
1618
 
        ABREG[absel] = XR;                              /* copy from XR */
1619
 
        break;
1620
 
 
1621
 
    case 005:                                           /* LDX 105745 (OP_K)*/
1622
 
        XR = op[0];                                     /* load XR */
1623
 
        break;
1624
 
 
1625
 
    case 006:                                           /* ADX 105746 (OP_K) */
1626
 
        t = XR + op[0];                                 /* add to XR */
1627
 
        if (t > DMASK) E = 1;                           /* set E, O */
1628
 
        if (((~XR ^ op[0]) & (XR ^ t)) & SIGN) O = 1;
1629
 
        XR = t & DMASK;
1630
 
        break;
1631
 
 
1632
 
    case 007:                                           /* XAX, XBX 10x747 (OP_N) */
1633
 
        t = XR;                                         /* exchange XR */
1634
 
        XR = ABREG[absel];
1635
 
        ABREG[absel] = t;
1636
 
        break;
1637
 
 
1638
 
    case 010:                                           /* SAY, SBY 10x750 (OP_A) */
1639
 
        op[0] = (op[0] + YR) & VAMASK;                  /* indexed addr */
1640
 
        WriteW (op[0], ABREG[absel]);                   /* store */
1641
 
        break;
1642
 
 
1643
 
    case 011:                                           /* CAY, CBY 10x751 (OP_N) */
1644
 
        YR = ABREG[absel];                              /* copy to YR */
1645
 
        break;
1646
 
 
1647
 
    case 012:                                           /* LAY, LBY 10x752 (OP_A) */
1648
 
        op[0] = (op[0] + YR) & VAMASK;                  /* indexed addr */
1649
 
        ABREG[absel] = ReadW (op[0]);                   /* load */
1650
 
        break;
1651
 
 
1652
 
    case 013:                                           /* STY 105753 (OP_A) */
1653
 
        WriteW (op[0], YR);                             /* store YR */
1654
 
        break;
1655
 
 
1656
 
    case 014:                                           /* CYA, CYB 10x754 (OP_N) */
1657
 
        ABREG[absel] = YR;                              /* copy from YR */
1658
 
        break;
1659
 
 
1660
 
    case 015:                                           /* LDY 105755 (OP_K) */
1661
 
        YR = op[0];                                     /* load YR */
1662
 
        break;
1663
 
 
1664
 
    case 016:                                           /* ADY 105756 (OP_K) */
1665
 
        t = YR + op[0];                                 /* add to YR */
1666
 
        if (t > DMASK) E = 1;                           /* set E, O */
1667
 
        if (((~YR ^ op[0]) & (YR ^ t)) & SIGN) O = 1;
1668
 
        YR = t & DMASK;
1669
 
        break;
1670
 
 
1671
 
    case 017:                                           /* XAY, XBY 10x757 (OP_N) */
1672
 
        t = YR;                                         /* exchange YR */
1673
 
        YR = ABREG[absel];
1674
 
        ABREG[absel] = t;
1675
 
        break;
1676
 
 
1677
 
/* EIG module 2 */
1678
 
 
1679
 
    case 020:                                           /* ISX 105760 (OP_N) */
1680
 
        XR = (XR + 1) & DMASK;                          /* incr XR */
1681
 
        if (XR == 0) PC = (PC + 1) & VAMASK;            /* skip if zero */
1682
 
        break;
1683
 
 
1684
 
    case 021:                                           /* DSX 105761 (OP_N) */
1685
 
        XR = (XR - 1) & DMASK;                          /* decr XR */
1686
 
        if (XR == 0) PC = (PC + 1) & VAMASK;            /* skip if zero */
1687
 
        break;
1688
 
 
1689
 
    case 022:                                           /* JLY 105762 (OP_A) */
1690
 
        mp_dms_jmp (op[0]);                             /* validate jump addr */
1691
 
        PCQ_ENTRY;
1692
 
        YR = PC;                                        /* ret addr to YR */
1693
 
        PC = op[0];                                     /* jump */
1694
 
        break;
1695
 
 
1696
 
    case 023:                                           /* LBT 105763 (OP_N) */
1697
 
        AR = ReadB (BR);                                /* load byte */
1698
 
        BR = (BR + 1) & DMASK;                          /* incr ptr */
1699
 
        break;
1700
 
 
1701
 
    case 024:                                           /* SBT 105764 (OP_N) */
1702
 
        WriteB (BR, AR);                                /* store byte */
1703
 
        BR = (BR + 1) & DMASK;                          /* incr ptr */
1704
 
        break;
1705
 
 
1706
 
    case 025:                                           /* MBT 105765 (OP_KV) */
1707
 
        wc = ReadW (op[1]);                             /* get continuation count */
1708
 
        if (wc == 0) wc = op[0];                        /* none? get initiation count */
1709
 
        if ((wc & SIGN) && (UNIT_CPU_TYPE == UNIT_TYPE_2100))
1710
 
            break;                                      /* < 0 is NOP for 2100 IOP */
1711
 
        while (wc != 0) {                               /* while count */
1712
 
            WriteW (op[1], wc);                         /* for MP abort */
1713
 
            t = ReadB (AR);                             /* move byte */
1714
 
            WriteB (BR, t);
1715
 
            AR = (AR + 1) & DMASK;                      /* incr src */
1716
 
            BR = (BR + 1) & DMASK;                      /* incr dst */
1717
 
            wc = (wc - 1) & DMASK;                      /* decr cnt */
1718
 
            if (intrq && wc) {                          /* intr, more to do? */
1719
 
                PC = err_PC;                            /* back up PC */
1720
 
                break;
1721
 
                }
1722
 
            }
1723
 
        WriteW (op[1], wc);                             /* clean up inline */
1724
 
        break;
1725
 
 
1726
 
    case 026:                                           /* CBT 105766 (OP_KV) */
1727
 
        wc = ReadW (op[1]);                             /* get continuation count */
1728
 
        if (wc == 0) wc = op[0];                        /* none? get initiation count */
1729
 
        while (wc != 0) {                               /* while count */
1730
 
            WriteW (op[1], wc);                         /* for MP abort */
1731
 
            v1 = ReadB (AR);                            /* get src1 */
1732
 
            v2 = ReadB (BR);                            /* get src2 */
1733
 
            if (v1 != v2) {                             /* compare */
1734
 
                PC = (PC + 1 + (v1 > v2)) & VAMASK;
1735
 
                BR = (BR + wc) & DMASK;                 /* update BR */
1736
 
                wc = 0;                                 /* clr interim */
1737
 
                break;
1738
 
                }
1739
 
            AR = (AR + 1) & DMASK;                      /* incr src1 */
1740
 
            BR = (BR + 1) & DMASK;                      /* incr src2 */
1741
 
            wc = (wc - 1) & DMASK;                      /* decr cnt */
1742
 
            if (intrq && wc) {                          /* intr, more to do? */
1743
 
                PC = err_PC;                            /* back up PC */
1744
 
                break;
1745
 
                }
1746
 
            }
1747
 
        WriteW (op[1], wc);                             /* clean up inline */
1748
 
        break;
1749
 
 
1750
 
    case 027:                                           /* SFB 105767 (OP_N) */
1751
 
        v1 = AR & 0377;                                 /* test byte */
1752
 
        v2 = (AR >> 8) & 0377;                          /* term byte */
1753
 
        for (;;) {                                      /* scan */
1754
 
            t = ReadB (BR);                             /* read byte */
1755
 
            if (t == v1) break;                         /* test match? */
1756
 
            BR = (BR + 1) & DMASK;
1757
 
            if (t == v2) {                              /* term match? */
1758
 
                PC = (PC + 1) & VAMASK;
1759
 
                break;
1760
 
                                }
1761
 
            if (intrq) {                                /* int pending? */
1762
 
                PC = err_PC;                            /* back up PC */
1763
 
                break;
1764
 
                }
1765
 
            }
1766
 
        break;
1767
 
 
1768
 
    case 030:                                           /* ISY 105770 (OP_N) */
1769
 
        YR = (YR + 1) & DMASK;                          /* incr YR */
1770
 
        if (YR == 0) PC = (PC + 1) & VAMASK;            /* skip if zero */
1771
 
        break;
1772
 
 
1773
 
    case 031:                                           /* DSY 105771 (OP_N) */
1774
 
        YR = (YR - 1) & DMASK;                          /* decr YR */
1775
 
        if (YR == 0) PC = (PC + 1) & VAMASK;            /* skip if zero */
1776
 
        break;
1777
 
 
1778
 
    case 032:                                           /* JPY 105772 (OP_C) */
1779
 
        op[0] = (op[0] + YR) & VAMASK;                  /* index, no indir */
1780
 
        mp_dms_jmp (op[0]);                             /* validate jump addr */
1781
 
        PCQ_ENTRY;
1782
 
        PC = op[0];                                     /* jump */
1783
 
        break;
1784
 
 
1785
 
    case 033:                                           /* SBS 105773 (OP_KA) */
1786
 
        WriteW (op[1], ReadW (op[1]) | op[0]);          /* set bits */
1787
 
        break;
1788
 
 
1789
 
    case 034:                                           /* CBS 105774 (OP_KA) */
1790
 
        WriteW (op[1], ReadW (op[1]) & ~op[0]);         /* clear bits */
1791
 
        break;
1792
 
 
1793
 
    case 035:                                           /* TBS 105775 (OP_KK) */
1794
 
        if ((op[1] & op[0]) != op[0])                   /* test bits */
1795
 
            PC = (PC + 1) & VAMASK;
1796
 
        break;
1797
 
 
1798
 
    case 036:                                           /* CMW 105776 (OP_KV) */
1799
 
        wc = ReadW (op[1]);                             /* get continuation count */
1800
 
        if (wc == 0) wc = op[0];                        /* none? get initiation count */
1801
 
        while (wc != 0) {                               /* while count */
1802
 
            WriteW (op[1], wc);                         /* for abort */
1803
 
            v1 = ReadW (AR & VAMASK);                   /* first op */
1804
 
            v2 = ReadW (BR & VAMASK);                   /* second op */
1805
 
            sop1 = (int32) SEXT (v1);                   /* signed */
1806
 
            sop2 = (int32) SEXT (v2);
1807
 
            if (sop1 != sop2) {                         /* compare */
1808
 
                PC = (PC + 1 + (sop1 > sop2)) & VAMASK;
1809
 
                BR = (BR + wc) & DMASK;                 /* update BR */
1810
 
                wc = 0;                                 /* clr interim */
1811
 
                break;
1812
 
                }
1813
 
            AR = (AR + 1) & DMASK;                      /* incr src1 */
1814
 
            BR = (BR + 1) & DMASK;                      /* incr src2 */
1815
 
            wc = (wc - 1) & DMASK;                      /* decr cnt */
1816
 
            if (intrq && wc) {                          /* intr, more to do? */
1817
 
                PC = err_PC;                            /* back up PC */
1818
 
                break;
1819
 
                }
1820
 
            }
1821
 
        WriteW (op[1], wc);                             /* clean up inline */
1822
 
        break;
1823
 
 
1824
 
    case 037:                                           /* MVW 105777 (OP_KV) */
1825
 
        wc = ReadW (op[1]);                             /* get continuation count */
1826
 
        if (wc == 0) wc = op[0];                        /* none? get initiation count */
1827
 
        if ((wc & SIGN) && (UNIT_CPU_TYPE == UNIT_TYPE_2100))
1828
 
            break;                                      /* < 0 is NOP for 2100 IOP */
1829
 
        while (wc != 0) {                               /* while count */
1830
 
            WriteW (op[1], wc);                         /* for abort */
1831
 
            t = ReadW (AR & VAMASK);                    /* move word */
1832
 
            WriteW (BR & VAMASK, t);
1833
 
            AR = (AR + 1) & DMASK;                      /* incr src */
1834
 
            BR = (BR + 1) & DMASK;                      /* incr dst */
1835
 
            wc = (wc - 1) & DMASK;                      /* decr cnt */
1836
 
            if (intrq && wc) {                          /* intr, more to do? */
1837
 
                PC = err_PC;                            /* back up PC */
1838
 
                break;
1839
 
                }
1840
 
            }
1841
 
        WriteW (op[1], wc);                             /* clean up inline */
1842
 
        break;
1843
 
 
1844
 
    default:                                            /* all others NOP */
1845
 
        break;
1846
 
        }
1847
 
 
1848
 
return reason;
1849
 
}
1850
 
 
1851
 
/* Get instruction operands
 
536
 
 
537
/* Read a multiple-precision operand value. */
 
538
 
 
539
OP ReadOp (uint32 va, OPSIZE precision)
 
540
{
 
541
OP operand;
 
542
uint32 i;
 
543
 
 
544
if (precision == in_s)
 
545
    operand.word = ReadW (va);                          /* read single integer */
 
546
 
 
547
else if (precision == in_d)
 
548
    operand.dword = ReadW (va) << 16 |                  /* read double integer */
 
549
                    ReadW ((va + 1) & VAMASK);          /* merge high and low words */
 
550
 
 
551
else
 
552
    for (i = 0; i < (uint32) precision; i++) {          /* read fp 2 to 5 words */
 
553
        operand.fpk[i] = ReadW (va);
 
554
        va = (va + 1) & VAMASK;
 
555
        }
 
556
return operand;
 
557
}
 
558
 
 
559
/* Write a multiple-precision operand value. */
 
560
 
 
561
void WriteOp (uint32 va, OP operand, OPSIZE precision)
 
562
{
 
563
uint32 i;
 
564
 
 
565
if (precision == in_s)
 
566
    WriteW (va, operand.word);                          /* write single integer */
 
567
 
 
568
else if (precision == in_d) {
 
569
    WriteW (va, (operand.dword >> 16) & DMASK);         /* write double integer */
 
570
    WriteW ((va + 1) & VAMASK, operand.dword & DMASK);  /* high word, then low word */
 
571
    }
 
572
 
 
573
else
 
574
    for (i = 0; i < (uint32) precision; i++) {          /* write fp 2 to 5 words */
 
575
        WriteW (va, operand.fpk[i]);
 
576
        va = (va + 1) & VAMASK;
 
577
        }
 
578
return;
 
579
}
 
580
 
 
581
 
 
582
/* Get instruction operands.
1852
583
 
1853
584
   Operands for a given instruction are specifed by an "operand pattern"
1854
585
   consisting of flags indicating the types and storage methods.  The pattern
1855
586
   directs how each operand is to be retrieved and whether the operand value or
1856
587
   address is returned in the operand array.
1857
588
 
1858
 
   Eight operand encodings are defined:
1859
 
 
1860
 
      Code   Operand Description              Example    Return
1861
 
     ------  -----------------------------  -----------  ------------
1862
 
     OP_NUL  No operand present                 [inst]   None
1863
 
 
1864
 
     OP_CON  Inline constant                    [inst]   Value of C
1865
 
                                             C  DEC 0
1866
 
 
1867
 
     OP_VAR  Inline variable                    [inst]   Address of V
1868
 
                                             V  BSS 1
1869
 
 
1870
 
     OP_ADR  Address                            [inst]   Address of A
1871
 
                                                DEF A
1872
 
                                                ...
1873
 
                                             A  EQU *
1874
 
        
1875
 
     OP_ADK  Address of a 1-word constant       [instr]  Value of K
1876
 
                                                DEF K
1877
 
                                                ...
1878
 
                                             K  DEC 0
1879
 
 
1880
 
     OP_ADF  Address of a 2-word constant       [inst]   Value of F
1881
 
                                                DEF F
1882
 
                                                ...
1883
 
                                             F  DEC 0.0
1884
 
 
1885
 
     OP_ADX  Address of a 3-word constant       [inst]   Value of X
1886
 
                                                DEF X
1887
 
                                                ...
1888
 
                                             X  DEX 0.0
1889
 
 
1890
 
     OP_ADT  Address of a 4-word constant       [inst]   Value of T
1891
 
                                                DEF T
1892
 
                                                ...
1893
 
                                             T  DEY 0.0
 
589
   Typically, a microcode simulation handler will define an OP_PAT array, with
 
590
   each element containing an operand pattern corresponding to the simulated
 
591
   instruction.  Operand patterns are defined in the header file accompanying
 
592
   this source file.  After calling this function with the appropriate operand
 
593
   pattern and a pointer to an array of OPs, operands are decoded and stored
 
594
   sequentially in the array.
 
595
 
 
596
   The following operand encodings are defined:
 
597
 
 
598
      Code   Operand Description                         Example    Return
 
599
     ------  ----------------------------------------  -----------  ------------
 
600
     OP_NUL  No operand present                           [inst]    None
 
601
 
 
602
     OP_IAR  Integer constant in A register                LDA I    Value of I
 
603
                                                          [inst]
 
604
                                                           ...
 
605
                                                        I  DEC 0
 
606
 
 
607
     OP_DAB  Double integer constant in A/B registers      DLD J    Value of J
 
608
                                                          [inst]
 
609
                                                           ...
 
610
                                                        J  DEC 0,0
 
611
 
 
612
     OP_FAB  2-word FP constant in A/B registers           DLD F    Value of F
 
613
                                                          [inst]
 
614
                                                           ...
 
615
                                                        F  DEC 0.0
 
616
 
 
617
     OP_CON  Inline 1-word constant                       [inst]    Value of C
 
618
                                                        C  DEC 0
 
619
                                                           ...
 
620
 
 
621
     OP_VAR  Inline 1-word variable                       [inst]    Address of V
 
622
                                                        V  BSS 1
 
623
                                                           ...
 
624
 
 
625
     OP_ADR  Inline address                               [inst]    Address of A
 
626
                                                           DEF A
 
627
                                                           ...
 
628
                                                        A  EQU *
 
629
 
 
630
     OP_ADK  Address of integer constant                  [inst]    Value of K
 
631
                                                           DEF K
 
632
                                                           ...
 
633
                                                        K  DEC 0
 
634
 
 
635
     OP_ADD  Address of double integer constant           [inst]    Value of D
 
636
                                                           DEF D
 
637
                                                           ...
 
638
                                                        D  DEC 0,0
 
639
 
 
640
     OP_ADF  Address of 2-word FP constant                [inst]    Value of F
 
641
                                                           DEF F
 
642
                                                           ...
 
643
                                                        F  DEC 0.0
 
644
 
 
645
     OP_ADX  Address of 3-word FP constant                [inst]    Value of X
 
646
                                                           DEF X
 
647
                                                           ...
 
648
                                                        X  DEX 0.0
 
649
 
 
650
     OP_ADT  Address of 4-word FP constant                [inst]    Value of T
 
651
                                                           DEF T
 
652
                                                           ...
 
653
                                                        T  DEY 0.0
 
654
 
 
655
     OP_ADE  Address of 5-word FP constant                [inst]    Value of E
 
656
                                                           DEF E
 
657
                                                           ...
 
658
                                                        E  DEC 0,0,0,0,0
1894
659
 
1895
660
   Address operands, i.e., those having a DEF to the operand, will be resolved
1896
661
   to direct addresses.  If an interrupt is pending and more than three levels
1900
665
 
1901
666
   An operand pattern consists of one or more operand encodings, corresponding
1902
667
   to the operands required by a given instruction.  Values are returned in
1903
 
   sequence to the operand array.  Addresses and one-word values are returned in
1904
 
   the lower half of the 32-bit array element.  Two-word values are packed into
1905
 
   one array element, with the first word in the upper 16 bits.  Three- and
1906
 
   four-word values are packed into two consecutive elements, with the last word
1907
 
   of a three-word value in the upper 16 bits of of the second element.
1908
 
 
1909
 
   IMPLEMENTATION NOTE: OP_ADT is not currently supported.
 
668
   sequence to the operand array.
1910
669
*/
1911
670
 
1912
 
static t_stat get_ops (OP_PAT pattern, OPS op, uint32 irq)
 
671
t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq)
1913
672
{
1914
673
t_stat reason = SCPE_OK;
1915
674
OP_PAT flags;
1916
675
uint32 i, MA;
1917
 
XPN xop;
1918
676
 
1919
677
for (i = 0; i < OP_N_F; i++) {
1920
678
    flags = pattern & OP_M_FLAGS;                       /* get operand pattern */
1927
685
        case OP_NUL:                                    /* null operand */
1928
686
            return reason;                              /* no more, so quit */
1929
687
 
1930
 
        case OP_CON:                                    /* constant operand */
1931
 
            *op++ = ReadW (PC);                         /* get value */
1932
 
            break;
1933
 
 
1934
 
        case OP_VAR:                                    /* variable operand */
1935
 
            *op++ = PC;                                 /* get pointer to variable */
1936
 
            break;
1937
 
 
1938
 
        case OP_ADR:                                    /* address operand */
1939
 
            *op++ = MA;                                 /* get address */
1940
 
            break;
1941
 
 
1942
 
        case OP_ADK:                                    /* address of 1-word constant */
1943
 
            *op++ = ReadW (MA);                         /* get value */
1944
 
            break;
1945
 
 
1946
 
        case OP_ADF:                                    /* address of 2-word constant */
1947
 
            *op++ = ReadF (MA);                         /* get value */
1948
 
            break;
1949
 
 
1950
 
        case OP_ADX:                                    /* address of 3-word constant */
1951
 
            xop = ReadX (MA);
1952
 
            *op++ = xop.high;                           /* get first two words of value */
1953
 
            *op++ = xop.low;                            /* get third word of value */
1954
 
            break;
1955
 
 
1956
 
        case OP_ADT:                                    /* address of 4-word constant */
 
688
        case OP_IAR:                                    /* int in A */
 
689
            (*op++).word = AR;                          /* get one-word value */
 
690
            break;
 
691
 
 
692
        case OP_JAB:                                    /* dbl-int in A/B */
 
693
            (*op++).dword = (AR << 16) | BR;            /* get two-word value */
 
694
            break;
 
695
 
 
696
        case OP_FAB:                                    /* 2-word FP in A/B */
 
697
            (*op).fpk[0] = AR;                          /* get high FP word */
 
698
            (*op++).fpk[1] = BR;                        /* get low FP word */
 
699
            break;
 
700
 
 
701
        case OP_CON:                                    /* inline constant operand */
 
702
            *op++ = ReadOp (PC, in_s);                  /* get value */
 
703
            break;
 
704
 
 
705
        case OP_VAR:                                    /* inline variable operand */
 
706
            (*op++).word = PC;                          /* get pointer to variable */
 
707
            break;
 
708
 
 
709
        case OP_ADR:                                    /* inline address operand */
 
710
            (*op++).word = MA;                          /* get address */
 
711
            break;
 
712
 
 
713
        case OP_ADK:                                    /* address of int constant */
 
714
            *op++ = ReadOp (MA, in_s);                  /* get value */
 
715
            break;
 
716
 
 
717
        case OP_ADD:                                    /* address of dbl-int constant */
 
718
            *op++ = ReadOp (MA, in_d);                  /* get value */
 
719
            break;
 
720
 
 
721
        case OP_ADF:                                    /* address of 2-word FP const */
 
722
            *op++ = ReadOp (MA, fp_f);                  /* get value */
 
723
            break;
 
724
 
 
725
        case OP_ADX:                                    /* address of 3-word FP const */
 
726
            *op++ = ReadOp (MA, fp_x);                  /* get value */
 
727
            break;
 
728
 
 
729
        case OP_ADT:                                    /* address of 4-word FP const */
 
730
            *op++ = ReadOp (MA, fp_t);                  /* get value */
 
731
            break;
 
732
 
 
733
        case OP_ADE:                                    /* address of 5-word FP const */
 
734
            *op++ = ReadOp (MA, fp_e);                  /* get value */
 
735
            break;
1957
736
 
1958
737
        default:
1959
738
            return SCPE_IERR;                           /* not implemented */
1960
739
        }
1961
740
 
1962
 
    PC = (PC + 1) & VAMASK;
 
741
    if (flags >= OP_CON)                                /* operand after instruction? */
 
742
        PC = (PC + 1) & VAMASK;                         /* yes, so bump to next */
1963
743
    pattern = pattern >> OP_N_FLAGS;                    /* move next pattern into place */
1964
744
    }
1965
745
return reason;