1
/* hp2100_cpu1.c: HP 2100 EAU and UIG simulator
3
Copyright (c) 2005, Robert M. Supnik
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:
12
The above copyright notice and this permission notice shall be included in
13
all copies or substantial portions of the Software.
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.
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.
26
CPU1 Extended arithmetic and optional microcode instructions
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
36
- HP 1000 M/E/F-Series Computers Technical Reference Handbook
38
- HP 1000 M/E/F-Series Computers Engineering and Reference Documentation
39
(92851-90001, Mar-1981)
41
Additional references are listed with the associated firmware
42
implementations, as are the HP option model numbers pertaining to the
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
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.
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).
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.
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.
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.
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.
90
#include "hp2100_defs.h"
91
#include "hp2100_cpu.h"
92
#include "hp2100_fp1.h"
94
/* Operand processing encoding */
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 */
105
#define OP_N_FLAGS 3 /* number of flag bits */
106
#define OP_M_FLAGS ((1 << OP_N_FLAGS) - 1) /* mask for flag bits */
108
#define OP_N_F 4 /* number of op fields */
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 */
115
/* Operand patterns */
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) | \
133
#define OP_AAF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
135
#define OP_AAX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \
137
#define OP_AXX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2) | \
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))
144
typedef uint32 OP_PAT; /* operand pattern */
145
typedef uint32 OPS[OP_N_F * 2]; /* operand array */
147
extern uint16 ABREG[2];
149
extern uint32 err_PC;
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];
163
extern uint32 stop_inst;
164
extern UNIT cpu_unit;
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 */
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 */
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 */
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:
192
2116 2100 21MX-M 21MX-E 21MX-F
193
------ ------ ------ ------ ------
194
12579A std std std std
196
The instruction codes are mapped to routines as follows:
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
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.
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.
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.
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.
236
t_stat cpu_eau (uint32 IR, uint32 intrq)
238
t_stat reason = SCPE_OK;
240
uint32 rs, qs, sc, v1, v2, t;
243
if ((cpu_unit.flags & UNIT_EAU) == 0) return stop_inst; /* implemented? */
245
switch ((IR >> 8) & 0377) { /* decode IR<15:8> */
247
case 0200: /* EAU group 0 */
248
switch ((IR >> 4) & 017) { /* decode IR<7:4> */
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 */
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; }
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 */
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 */
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;
287
case 010: /* MPY 100200 */
289
if (reason = get_ops (OP_K, op, intrq)) /* get operand */
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 */
296
O = 0; /* no overflow */
299
default: /* others undefined */
305
case 0201: /* DIV 100400 */
306
if (reason = get_ops (OP_K, op, intrq)) /* get operand */
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 */
327
case 0202: /* EAU group 2 */
328
switch ((IR >> 4) & 017) { /* decode IR<7:4> */
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 */
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 */
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;
350
default: /* others undefined */
356
case 0210: /* DLD 104200 */
357
if (reason = get_ops (OP_F, op, intrq)) /* get operand */
359
AR = (op[0] >> 16) & DMASK; /* load AR */
360
BR = op[0] & DMASK; /* load BR */
363
case 0211: /* DST 104400 */
364
if (reason = get_ops (OP_A, op, intrq)) /* get operand */
366
WriteW (op[0], AR); /* store AR */
367
op[0] = (op[0] + 1) & VAMASK;
368
WriteW (op[0], BR); /* store BR */
371
default: /* should never get here */
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
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
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.
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.
403
t_stat cpu_uig_0 (uint32 IR, uint32 intrq)
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);
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 */
429
default: /* all others invalid */
432
if (IR >= 0105700) return cpu_eig (IR, intrq); /* dispatch to 21MX EIG */
433
else return cpu_iop (IR, intrq); } /* or to 21MX IOP */
435
switch ((IR >> 4) & 017) { /* decode IR<7:4> */
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 */
445
case 010: /* 105200-105217 */
446
case 011: /* 105220-105237 */
447
return cpu_ffp (IR, intrq); /* Fast FORTRAN Processor */
450
return stop_inst; /* others undefined */
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):
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
466
Only 21MX systems execute these instructions.
469
t_stat cpu_uig_1 (uint32 IR, uint32 intrq)
471
if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* 21MX execution? */
472
return stop_inst; /* no, so trap */
474
switch ((IR >> 4) & 017) { /* decode IR<7:4> */
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 */
481
case 014: /* 105700-105717 */
482
case 015: /* 105720-105737 */
483
return cpu_dms (IR, intrq); /* Dynamic Mapping System */
485
case 016: /* 105740-105737 */
486
case 017: /* 105760-105777 */
487
return cpu_eig (IR, intrq); /* Extended Instruction Group */
490
return stop_inst; /* others undefined */
495
The 2100 and 21MX CPUs share the single-precision (two word) floating point
496
instruction codes. Option implementation by CPU was as follows:
498
2116 2100 21MX-M 21MX-E 21MX-F
499
------ ------ ------ ------ ------
500
N/A 12901A std std std
502
The instruction codes are mapped to routines as follows:
504
Instr. 2100/21MX-M/E/F
505
------ ---------------
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.
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 --- --- */
521
static t_stat cpu_fp (uint32 IR, uint32 intrq)
523
t_stat reason = SCPE_OK;
527
if ((cpu_unit.flags & UNIT_FP) == 0) /* FP option installed? */
530
entry = (IR >> 4) & 017; /* mask to entry point */
532
if (op_fp[entry] != OP_N)
533
if (reason = get_ops (op_fp[entry], op, intrq)) /* get instruction operands */
536
switch (entry) { /* decode IR<7:4> */
538
case 000: /* FMP 105000 */
539
O = f_as (op[0], 0); /* add, upd ovflo */
542
case 001: /* FMP 105020 */
543
O = f_as (op[0], 1); /* sub, upd ovflo */
546
case 002: /* FMP 105040 */
547
O = f_mul (op[0]); /* mul, upd ovflo */
550
case 003: /* FDV 105060 */
551
O = f_div (op[0]); /* div, upd ovflo */
554
case 004: /* FIX 105100 */
555
O = f_fix (); /* fix, upd ovflo */
558
case 005: /* FLT 105120 */
559
O = f_flt (); /* float, upd ovflo */
562
default: /* should be impossible */
569
/* Fast FORTRAN Processor
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.
576
Option implementation by CPU was as follows:
578
2116 2100 21MX-M 21MX-E 21MX-F
579
------ ------ ------ ------ ------
580
N/A 12907A 12977B 13306B std
582
The instruction codes are mapped to routines as follows:
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
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 -- -- -- --
606
1. The "$SETP" instruction is sometimes listed as ".SETP" in the
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.
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.
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.
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.
624
6. The .XFER implementation for the 2100 FFP returns to P+2, whereas the
625
21MX implementation returns to P+1.
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)
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 }; /* --- --- --- --- */
642
static t_stat cpu_ffp (uint32 IR, uint32 intrq)
644
t_stat reason = SCPE_OK;
647
uint32 j, sa, sb, sc, da, dc, ra, MA;
651
if ((cpu_unit.flags & UNIT_FFP) == 0) /* FFP option installed? */
654
entry = IR & 037; /* mask to entry point */
656
if (op_ffp[entry] != OP_N)
657
if (reason = get_ops (op_ffp[entry], op, intrq))/* get instruction operands */
660
switch (entry) { /* decode IR<3:0> */
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 */
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 */
679
#if defined (HAVE_INT64)
681
case 003: /* .XMPY 105203 (OP_AXX) */
682
i = 0; /* params start at op[0] */
683
goto XMPY; /* process as XMPY */
685
case 004: /* .XDIV 105204 (OP_AXX) */
686
i = 0; /* params start at op[0] */
687
goto XDIV; /* process as XDIV */
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 */
696
#if defined (HAVE_INT64)
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 */
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 */
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 */
715
O = x_add (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* add ops */
716
WriteX (op[i], xop); /* write sum */
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 */
725
O = x_sub (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* subtract */
726
WriteX (op[i], xop); /* write difference */
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 */
735
O = x_mpy (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* multiply */
736
WriteX (op[i], xop); /* write product */
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 */
745
O = x_div (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* divide */
746
WriteX (op[i], xop); /* write quotient */
749
case 013: /* .XADD 105213 (OP_AXX) */
750
i = 0; /* params start at op[0] */
751
goto XADD; /* process as XADD */
753
case 014: /* .XSUB 105214 (OP_AXX) */
754
i = 0; /* params start at op[0] */
755
goto XSUB; /* process as XSUB */
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 */
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 */
771
xop = ReadX (op[0]); /* read operand */
772
O = x_dcm (&xop); /* negate */
773
WriteX (op[0], xop); /* write result */
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 */
782
x_trun (&xop, AS_XPN (op [2])); /* truncate operand */
783
WriteX (op[1], xop); /* write result */
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 */
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 */
803
da = ReadW (sa); /* get jump target */
804
if (reason = resolve (da, &MA, intrq)) { /* resolve indirects */
805
PC = err_PC; /* irq restarts instruction */
807
mp_dms_jmp (MA); /* validate jump addr */
808
PCQ_ENTRY; /* record last PC */
810
BR = op[0]; /* (for 2100 FFP compat) */
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 */
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 */
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 */
840
WriteW (da++, MA); } /* put addr into formal */
841
AR = ra; /* return address */
842
BR = da; /* addr of 1st unused formal */
845
case 024: /* .ENTP 105224 (OP_A) */
846
MA = PC - 5; /* get addr of entry point */
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 */
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 */
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 */
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 */
876
while (op[0] != 0); /* loop until count exhausted */
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 */
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; }
902
default: /* others undefined */
903
reason = stop_inst; }
908
/* 2000 I/O Processor
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
917
Option implementation by CPU was as follows:
919
2116 2100 21MX-M 21MX-E 21MX-F
920
------ ------ ------ ------ ------
921
N/A 13206A 13207A 22702A N/A
923
The routines are mapped to instruction codes as follows:
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
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)
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.
954
Additional reference:
955
- HP 2000 Computer System Sources and Listings Documentation
956
(22687-90020, undated), section 3, pages 2-74 through 2-91.
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 --- --- --- */
965
static t_stat cpu_iop (uint32 IR, uint32 intrq)
967
t_stat reason = SCPE_OK;
970
uint32 hp, tp, i, t, wc, MA;
972
if ((cpu_unit.flags & UNIT_IOP) == 0) /* IOP option installed? */
975
entry = IR & 077; /* mask to entry point */
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 */
982
else if (entry <= 057) /* IR = 10x440-457? */
983
return stop_inst; /* not part of IOP */
985
entry = entry - 060; /* offset 10x460-477 */
987
if (op_iop[entry] != OP_N)
988
if (reason = get_ops (op_iop[entry], op, intrq))/* get instruction operands */
991
switch (entry) { /* decode IR<5:0> */
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 */
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 */
1014
case 002: /* READF 105462 (OP_N) */
1015
AR = iop_sp; /* copy stk ptr */
1018
case 003: /* INS 105463 (OP_N) */
1019
iop_sp = AR; /* init stk ptr */
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 */
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 */
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 */
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 */
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 */
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 */
1079
case 012: /* PRFEX 105472 (OP_A) */
1081
PC = ReadW (op[0]) & VAMASK; /* jump indirect */
1082
WriteW (op[0], 0); /* clear exit */
1085
case 013: /* PRFIO 105473 (OP_CV) */
1086
WriteW (op[1], 1); /* set flag */
1087
reason = iogrp (op[0], 0); /* execute instr */
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 */
1102
default: /* instruction undefined */
1109
/* Dynamic Mapping System
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
1120
Option implementation by CPU was as follows:
1122
2116 2100 21MX-M 21MX-E 21MX-F
1123
------ ------ ------ ------ ------
1124
N/A N/A 12976B 13307B std
1126
The instruction codes are mapped to routines as follows:
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*
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
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
1156
1. Instruction code 10x700 will execute the XMM instruction, although
1157
10x720 is the documented instruction value.
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*)
1163
3. The 21MX manual is incorrect in stating that M*I, M*W, XS* are
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 */
1177
static t_stat cpu_dms (uint32 IR, uint32 intrq)
1179
t_stat reason = SCPE_OK;
1181
uint32 entry, absel;
1182
uint32 i, t, mapi, mapj;
1184
if ((cpu_unit.flags & UNIT_DMS) == 0) /* DMS option installed? */
1187
absel = (IR & I_AB)? 1: 0; /* get A/B select */
1188
entry = IR & 037; /* mask to entry point */
1190
if (op_dms[entry] != OP_N)
1191
if (reason = get_ops (op_dms[entry], op, intrq))/* get instruction operands */
1194
switch (entry) { /* decode IR<3:0> */
1198
case 000: /* [undefined] 105700 (OP_N) */
1199
goto XMM; /* decodes as XMM */
1201
case 001: /* [self test] 105701 (OP_N) */
1202
ABREG[absel] = ABREG[absel] ^ DMASK; /* CMA or CMB */
1205
case 002: /* MBI 105702 (OP_N) */
1206
AR = AR & ~1; /* force A, B even */
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 */
1219
case 003: /* MBF 105703 (OP_N) */
1220
AR = AR & ~1; /* force A, B even */
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 */
1233
case 004: /* MBW 105704 (OP_N) */
1234
AR = AR & ~1; /* force A, B even */
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 */
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 */
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 */
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 */
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); } }
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;
1300
case 014: /* SSM 105714 (OP_A) */
1301
WriteW (op[0], dms_upd_sr ()); /* store stat */
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 */
1308
if (op[0] & 0100000) { /* set enable? */
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 */
1319
case 020: /* XMM 105720 (OP_N) */
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; }
1328
dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
1329
t = ReadW (BR & VAMASK); /* mem to map */
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 */
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 */
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? */
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;
1356
if (ABREG[absel] & 0000001) mapj = PBMAP;
1358
for (i = 0; i < MAP_LNT; i++) {
1359
t = dms_rmap (mapi + i); /* read map */
1360
dms_wmap (mapj + i, t); } /* write map */
1363
case 024: /* XLA, XLB 10x724 (OP_A) */
1364
ABREG[absel] = ReadWA (op[0]); /* load alt */
1367
case 025: /* XSA, XSB 10x725 (OP_A) */
1368
WriteWA (op[0], ABREG[absel]); /* store alt */
1371
case 026: /* XCA, XCB 10x726 (OP_A) */
1372
if (ABREG[absel] != ReadWA (op[0])) /* compare alt */
1373
PC = (PC + 1) & VAMASK;
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));
1382
case 030: /* RSA, RSB 10x730 (OP_N) */
1383
ABREG[absel] = dms_upd_sr (); /* save stat */
1386
case 031: /* RVA, RVB 10x731 (OP_N) */
1387
ABREG[absel] = dms_vr; /* save viol */
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 */
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 */
1407
ion_defer = 1; /* defer intr */
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 */
1417
ion_defer = 1; /* defer intr */
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 */
1427
WriteW (op[0], t); /* store ret addr */
1428
ion_defer = 1; /* defer intr */
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 */
1438
ion_defer = 1; /* defer intr */
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 */
1448
WriteW (op[0], t); /* store ret addr */
1449
ion_defer = 1; /* defer intr */
1452
default: /* others NOP */
1458
/* Extended Instruction Group
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.
1464
Option implementation by CPU was as follows:
1466
2116 2100 21MX-M 21MX-E 21MX-F
1467
------ ------ ------ ------ ------
1470
The instruction codes are mapped to routines as follows:
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
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
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
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.
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 */
1515
static t_stat cpu_eig (uint32 IR, uint32 intrq)
1517
t_stat reason = SCPE_OK;
1519
uint32 entry, absel;
1520
uint32 t, v1, v2, wc;
1523
absel = (IR & I_AB)? 1: 0; /* get A/B select */
1524
entry = IR & 037; /* mask to entry point */
1526
if (op_eig[entry] != OP_N)
1527
if (reason = get_ops (op_eig[entry], op, intrq))/* get instruction operands */
1530
switch (entry) { /* decode IR<4:0> */
1534
case 000: /* SAX, SBX 10x740 (OP_A) */
1535
op[0] = (op[0] + XR) & VAMASK; /* indexed addr */
1536
WriteW (op[0], ABREG[absel]); /* store */
1539
case 001: /* CAX, CBX 10x741 (OP_N) */
1540
XR = ABREG[absel]; /* copy to XR */
1543
case 002: /* LAX, LBX 10x742 (OP_A) */
1544
op[0] = (op[0] + XR) & VAMASK; /* indexed addr */
1545
ABREG[absel] = ReadW (op[0]); /* load */
1548
case 003: /* STX 105743 (OP_A) */
1549
WriteW (op[0], XR); /* store XR */
1552
case 004: /* CXA, CXB 10x744 (OP_N) */
1553
ABREG[absel] = XR; /* copy from XR */
1556
case 005: /* LDX 105745 (OP_K)*/
1557
XR = op[0]; /* load XR */
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;
1567
case 007: /* XAX, XBX 10x747 (OP_N) */
1568
t = XR; /* exchange XR */
1573
case 010: /* SAY, SBY 10x750 (OP_A) */
1574
op[0] = (op[0] + YR) & VAMASK; /* indexed addr */
1575
WriteW (op[0], ABREG[absel]); /* store */
1578
case 011: /* CAY, CBY 10x751 (OP_N) */
1579
YR = ABREG[absel]; /* copy to YR */
1582
case 012: /* LAY, LBY 10x752 (OP_A) */
1583
op[0] = (op[0] + YR) & VAMASK; /* indexed addr */
1584
ABREG[absel] = ReadW (op[0]); /* load */
1587
case 013: /* STY 105753 (OP_A) */
1588
WriteW (op[0], YR); /* store YR */
1591
case 014: /* CYA, CYB 10x754 (OP_N) */
1592
ABREG[absel] = YR; /* copy from YR */
1595
case 015: /* LDY 105755 (OP_K) */
1596
YR = op[0]; /* load YR */
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;
1606
case 017: /* XAY, XBY 10x757 (OP_N) */
1607
t = YR; /* exchange YR */
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 */
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 */
1624
case 022: /* JLY 105762 (OP_A) */
1625
mp_dms_jmp (op[0]); /* validate jump addr */
1627
YR = PC; /* ret addr to YR */
1628
PC = op[0]; /* jump */
1631
case 023: /* LBT 105763 (OP_N) */
1632
AR = ReadB (BR); /* load byte */
1633
BR = (BR + 1) & DMASK; /* incr ptr */
1636
case 024: /* SBT 105764 (OP_N) */
1637
WriteB (BR, AR); /* store byte */
1638
BR = (BR + 1) & DMASK; /* incr ptr */
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 */
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 */
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 */
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 */
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;
1690
if (intrq) { /* int pending? */
1691
PC = err_PC; /* back up PC */
1692
break; } } /* take intr */
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 */
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 */
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 */
1709
PC = op[0]; /* jump */
1712
case 033: /* SBS 105773 (OP_KA) */
1713
WriteW (op[1], ReadW (op[1]) | op[0]); /* set bits */
1716
case 034: /* CBS 105774 (OP_KA) */
1717
WriteW (op[1], ReadW (op[1]) & ~op[0]); /* clear bits */
1720
case 035: /* TBS 105775 (OP_KK) */
1721
if ((op[1] & op[0]) != op[0]) /* test bits */
1722
PC = (PC + 1) & VAMASK;
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 */
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 */
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 */
1766
default: /* all others NOP */
1772
/* Get instruction operands
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.
1779
Eight operand encodings are defined:
1781
Code Operand Description Example Return
1782
------ ----------------------------- ----------- ------------
1783
OP_NUL No operand present [inst] None
1785
OP_CON Inline constant [inst] Value of C
1788
OP_VAR Inline variable [inst] Address of V
1791
OP_ADR Address [inst] Address of A
1796
OP_ADK Address of a 1-word constant [instr] Value of K
1801
OP_ADF Address of a 2-word constant [inst] Value of F
1806
OP_ADX Address of a 3-word constant [inst] Value of X
1811
OP_ADT Address of a 4-word constant [inst] Value of T
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.
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.
1830
IMPLEMENTATION NOTE: OP_ADT is not currently supported.
1833
static t_stat get_ops (OP_PAT pattern, OPS op, uint32 irq)
1835
t_stat reason = SCPE_OK;
1840
for (i = 0; i < OP_N_F; i++) {
1841
flags = pattern & OP_M_FLAGS; /* get operand pattern */
1843
if (flags >= OP_ADR) /* address operand? */
1844
if (reason = resolve (ReadW (PC), &MA, irq))/* resolve indirects */
1848
case OP_NUL: /* null operand */
1849
return reason; /* no more, so quit */
1851
case OP_CON: /* constant operand */
1852
*op++ = ReadW (PC); /* get value */
1855
case OP_VAR: /* variable operand */
1856
*op++ = PC; /* get pointer to variable */
1859
case OP_ADR: /* address operand */
1860
*op++ = MA; /* get address */
1863
case OP_ADK: /* address of 1-word constant */
1864
*op++ = ReadW (MA); /* get value */
1867
case OP_ADF: /* address of 2-word constant */
1868
*op++ = ReadF (MA); /* get value */
1871
case OP_ADX: /* address of 3-word constant */
1873
*op++ = xop.high; /* get first two words of value */
1874
*op++ = xop.low; /* get third word of value */
1877
case OP_ADT: /* address of 4-word constant */
1880
return SCPE_IERR; /* not implemented */
1883
PC = (PC + 1) & VAMASK;
1884
pattern = pattern >> OP_N_FLAGS; } /* move next pattern into place */