~ubuntu-branches/ubuntu/vivid/simh/vivid

« back to all changes in this revision

Viewing changes to HP2100/hp2100_cpu1.c

  • Committer: Bazaar Package Importer
  • Author(s): Vince Mulhollon
  • Date: 2005-05-30 19:25:10 UTC
  • mfrom: (1.1.3 upstream) (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20050530192510-npcvtltga170kziw
Tags: 3.4.0-1
New upstream

Show diffs side-by-side

added added

removed removed

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