First Commit of my working state
[simh.git] / HP2100 / hp2100_cpu2.c
CommitLineData
196ba1fc
PH
1/* hp2100_cpu2.c: HP 2100/1000 FP/DMS/EIG/IOP instructions\r
2\r
3 Copyright (c) 2005-2006, Robert M. Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 CPU2 Floating-point, dynamic mapping, extended, and I/O processor\r
27 instructions\r
28\r
29 19-Dec-06 JDB DMS self-test now executes as NOP on 1000-M\r
30 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64\r
31 26-Sep-06 JDB Moved from hp2100_cpu1.c to simplify extensions\r
32 22-Feb-05 JDB Fixed missing MPCK on JRS target\r
33 21-Jan-05 JDB Reorganized CPU option and operand processing flags\r
34 Split code along microcode modules\r
35 15-Jan-05 RMS Cloned from hp2100_cpu.c\r
36\r
37 Primary references:\r
38 - HP 1000 M/E/F-Series Computers Technical Reference Handbook\r
39 (5955-0282, Mar-1980)\r
40 - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation\r
41 (92851-90001, Mar-1981)\r
42 - Macro/1000 Reference Manual (92059-90001, Dec-1992)\r
43\r
44 Additional references are listed with the associated firmware\r
45 implementations, as are the HP option model numbers pertaining to the\r
46 applicable CPUs.\r
47*/\r
48\r
49#include "hp2100_defs.h"\r
50#include "hp2100_cpu.h"\r
51#include "hp2100_cpu1.h"\r
52\r
53#if !defined (HAVE_INT64) /* int64 support unavailable */\r
54\r
55#include "hp2100_fp.h"\r
56\r
57t_stat cpu_fp (uint32 IR, uint32 intrq); /* Firmware Floating Point */\r
58\r
59#endif /* int64 support unavailable */\r
60\r
61t_stat cpu_dms (uint32 IR, uint32 intrq); /* Dynamic mapping system */\r
62t_stat cpu_eig (uint32 IR, uint32 intrq); /* Extended instruction group */\r
63t_stat cpu_iop (uint32 IR, uint32 intrq); /* 2000 I/O Processor */\r
64\r
65\r
66#if !defined (HAVE_INT64) /* int64 support unavailable */\r
67\r
68/* Single-Precision Floating Point Instructions\r
69\r
70 The 2100 and 1000 CPUs share the single-precision (two word) floating-point\r
71 instruction codes. Floating-point firmware was an option on the 2100 and was\r
72 standard on the 1000-M and E. The 1000-F had a standard hardware Floating\r
73 Point Processor that executed these six instructions and added extended- and\r
74 double-precision floating- point instructions, as well as double-integer\r
75 instructions (the FPP is simulated separately).\r
76\r
77 Option implementation by CPU was as follows:\r
78\r
79 2114 2115 2116 2100 1000-M 1000-E 1000-F\r
80 ------ ------ ------ ------ ------ ------ ------\r
81 N/A N/A N/A 12901A std std N/A\r
82\r
83 The instruction codes for the 2100 and 1000-M/E systems are mapped to\r
84 routines as follows:\r
85\r
86 Instr. 2100/1000-M/E Description\r
87 ------ ------------- -----------------------------------\r
88 105000 FAD Single real add\r
89 105020 FSB Single real subtract\r
90 105040 FMP Single real multiply\r
91 105060 FDV Single real divide\r
92 105100 FIX Single integer to single real fix\r
93 105120 FLT Single real to single integer float\r
94\r
95 Bits 3-0 are not decoded by these instructions, so FAD (e.g.) would be\r
96 executed by any instruction in the range 105000-105017.\r
97\r
98 Implementation note: rather than have two simulators that each executes the\r
99 single-precision FP instruction set, we compile conditionally, based on the\r
100 availability of 64-bit integer support in the host compiler. 64-bit integers\r
101 are required for the FPP, so if they are available, then the FPP is used to\r
102 handle the six single-precision instructions for the 2100 and M/E-Series, and\r
103 this function is omitted. If support is unavailable, this function is used\r
104 instead.\r
105\r
106 Implementation note: the operands to FAD, etc. are floating-point values, so\r
107 OP_F would normally be used. However, the firmware FP support routines want\r
108 floating-point operands as 32-bit integer values, so OP_D is used to achieve\r
109 this.\r
110*/\r
111\r
112static const OP_PAT op_fp[8] = {\r
113 OP_D, OP_D, OP_D, OP_D, /* FAD FSB FMP FDV */\r
114 OP_N, OP_N, OP_N, OP_N /* FIX FLT --- --- */\r
115 };\r
116\r
117t_stat cpu_fp (uint32 IR, uint32 intrq)\r
118{\r
119t_stat reason = SCPE_OK;\r
120OPS op;\r
121uint32 entry;\r
122\r
123if ((cpu_unit.flags & UNIT_FP) == 0) /* FP option installed? */\r
124 return stop_inst;\r
125\r
126entry = (IR >> 4) & 017; /* mask to entry point */\r
127\r
128if (op_fp[entry] != OP_N)\r
129 if (reason = cpu_ops (op_fp[entry], op, intrq)) /* get instruction operands */\r
130 return reason;\r
131\r
132switch (entry) { /* decode IR<7:4> */\r
133\r
134 case 000: /* FAD 105000 (OP_D) */\r
135 O = f_as (op[0].dword, 0); /* add, upd ovflo */\r
136 break;\r
137\r
138 case 001: /* FSB 105020 (OP_D) */\r
139 O = f_as (op[0].dword, 1); /* sub, upd ovflo */\r
140 break;\r
141\r
142 case 002: /* FMP 105040 (OP_D) */\r
143 O = f_mul (op[0].dword); /* mul, upd ovflo */\r
144 break;\r
145\r
146 case 003: /* FDV 105060 (OP_D) */\r
147 O = f_div (op[0].dword); /* div, upd ovflo */\r
148 break;\r
149\r
150 case 004: /* FIX 105100 (OP_N) */\r
151 O = f_fix (); /* fix, upd ovflo */\r
152 break;\r
153\r
154 case 005: /* FLT 105120 (OP_N) */\r
155 O = f_flt (); /* float, upd ovflo */\r
156 break;\r
157\r
158 default: /* should be impossible */\r
159 return SCPE_IERR;\r
160 }\r
161\r
162return reason;\r
163}\r
164\r
165#endif /* int64 support unavailable */\r
166\r
167\r
168/* Dynamic Mapping System\r
169\r
170 The 1000 Dynamic Mapping System (DMS) consisted of the 12731A Memory\r
171 Expansion Module (MEM) card and 38 instructions to expand the basic 32K\r
172 logical address space to a 1024K physical space. The MEM provided four maps\r
173 of 32 mapping registers each: a system map, a user map, and two DCPC maps.\r
174 DMS worked in conjunction with memory protect to provide a "protected mode"\r
175 in which memory read and write violations could be trapped, and that\r
176 inhibited "privileged" instruction execution that attempted to alter the\r
177 memory mapping.\r
178\r
179 Option implementation by CPU was as follows:\r
180\r
181 2114 2115 2116 2100 1000-M 1000-E 1000-F\r
182 ------ ------ ------ ------ ------ ------ ------\r
183 N/A N/A N/A N/A 12976B 13307B std\r
184\r
185 The instruction codes are mapped to routines as follows:\r
186\r
187 Instr. 1000-M 1000-E/F Instr. 1000-M 1000-E/F\r
188 ------ ------ -------- ------ ------ --------\r
189 10x700 [xmm] [xmm] 10x720 XMM XMM\r
190 10x701 [nop] [test] 10x721 XMS XMS\r
191 10x702 MBI MBI 10x722 XM* XM*\r
192 10x703 MBF MBF 10x723 [nop] [nop]\r
193 10x704 MBW MBW 10x724 XL* XL*\r
194 10x705 MWI MWI 10x725 XS* XS*\r
195 10x706 MWF MWF 10x726 XC* XC*\r
196 10x707 MWW MWW 10x727 LF* LF*\r
197 10x710 SY* SY* 10x730 RS* RS*\r
198\r
199 10x711 US* US* 10x731 RV* RV*\r
200 10x712 PA* PA* 10x732 DJP DJP\r
201 10x713 PB* PB* 10x733 DJS DJS\r
202 10x714 SSM SSM 10x734 SJP SJP\r
203 10x715 JRS JRS 10x735 SJS SJS\r
204 10x716 [nop] [nop] 10x736 UJP UJP\r
205 10x717 [nop] [nop] 10x737 UJS UJS\r
206\r
207 Instructions that use IR bit 9 to select the A or B register are designated\r
208 with a * above (e.g., 101710 is SYA, and 105710 is SYB). For those that do\r
209 not use this feature, either the 101xxx or 105xxx code will execute the\r
210 corresponding instruction, although the 105xxx form is the documented\r
211 instruction code.\r
212\r
213 Notes:\r
214\r
215 1. Instruction code 10x700 will execute the XMM instruction, although\r
216 10x720 is the documented instruction value.\r
217\r
218 2. Instruction code 10x701 will complement the A or B register, as\r
219 indicated, on 1000-E and F-Series machines. This instruction is a NOP\r
220 on M-Series machines.\r
221\r
222 3. The DMS privilege violation rules are:\r
223 - load map and CTL5 set (XMM, XMS, XM*, SY*, US*, PA*, PB*)\r
224 - load state or fence and UMAP set (JRS, DJP, DJS, SJP, SJS, UJP, UJS, LF*)\r
225\r
226 4. The 1000 manual is incorrect in stating that M*I, M*W, XS* are\r
227 privileged.\r
228*/\r
229\r
230static const OP_PAT op_dms[32] = {\r
231 OP_N, OP_N, OP_N, OP_N, /* [xmm] [test] MBI MBF */\r
232 OP_N, OP_N, OP_N, OP_N, /* MBW MWI MWF MWW */\r
233 OP_N, OP_N, OP_N, OP_N, /* SYA/B USA/B PAA/B PBA/B */\r
234 OP_A, OP_KA, OP_N, OP_N, /* SSM JRS nop nop */\r
235 OP_N, OP_N, OP_N, OP_N, /* XMM XMS XMA/B nop */\r
236 OP_A, OP_A, OP_A, OP_N, /* XLA/B XSA/B XCA/B LFA/B */\r
237 OP_N, OP_N, OP_A, OP_A, /* RSA/B RVA/B DJP DJS */\r
238 OP_A, OP_A, OP_A, OP_A /* SJP SJS UJP UJS */\r
239 };\r
240\r
241t_stat cpu_dms (uint32 IR, uint32 intrq)\r
242{\r
243t_stat reason = SCPE_OK;\r
244OPS op;\r
245uint32 entry, absel;\r
246uint32 i, t, mapi, mapj;\r
247\r
248if ((cpu_unit.flags & UNIT_DMS) == 0) /* DMS option installed? */\r
249 return stop_inst;\r
250\r
251absel = (IR & I_AB)? 1: 0; /* get A/B select */\r
252entry = IR & 037; /* mask to entry point */\r
253\r
254if (op_dms[entry] != OP_N)\r
255 if (reason = cpu_ops (op_dms[entry], op, intrq)) /* get instruction operands */\r
256 return reason;\r
257\r
258switch (entry) { /* decode IR<3:0> */\r
259\r
260/* DMS module 1 */\r
261\r
262 case 000: /* [undefined] 105700 (OP_N) */\r
263 goto XMM; /* decodes as XMM */\r
264\r
265 case 001: /* [self test] 105701 (OP_N) */\r
266 if (UNIT_CPU_MODEL != UNIT_1000_M) /* executes as NOP on 1000-M */\r
267 ABREG[absel] = ~ABREG[absel]; /* CMA or CMB */\r
268 break;\r
269\r
270 case 002: /* MBI 105702 (OP_N) */\r
271 AR = AR & ~1; /* force A, B even */\r
272 BR = BR & ~1;\r
273 while (XR != 0) { /* loop */\r
274 t = ReadB (AR); /* read curr */\r
275 WriteBA (BR, t); /* write alt */\r
276 AR = (AR + 1) & DMASK; /* incr ptrs */\r
277 BR = (BR + 1) & DMASK;\r
278 XR = (XR - 1) & DMASK;\r
279 if (XR && intrq && !(AR & 1)) { /* more, int, even? */\r
280 PC = err_PC; /* stop for now */\r
281 break;\r
282 }\r
283 }\r
284 break;\r
285\r
286 case 003: /* MBF 105703 (OP_N) */\r
287 AR = AR & ~1; /* force A, B even */\r
288 BR = BR & ~1;\r
289 while (XR != 0) { /* loop */\r
290 t = ReadBA (AR); /* read alt */\r
291 WriteB (BR, t); /* write curr */\r
292 AR = (AR + 1) & DMASK; /* incr ptrs */\r
293 BR = (BR + 1) & DMASK;\r
294 XR = (XR - 1) & DMASK;\r
295 if (XR && intrq && !(AR & 1)) { /* more, int, even? */\r
296 PC = err_PC; /* stop for now */\r
297 break;\r
298 }\r
299 }\r
300 break;\r
301\r
302 case 004: /* MBW 105704 (OP_N) */\r
303 AR = AR & ~1; /* force A, B even */\r
304 BR = BR & ~1;\r
305 while (XR != 0) { /* loop */\r
306 t = ReadBA (AR); /* read alt */\r
307 WriteBA (BR, t); /* write alt */\r
308 AR = (AR + 1) & DMASK; /* incr ptrs */\r
309 BR = (BR + 1) & DMASK;\r
310 XR = (XR - 1) & DMASK;\r
311 if (XR && intrq && !(AR & 1)) { /* more, int, even? */\r
312 PC = err_PC; /* stop for now */\r
313 break;\r
314 }\r
315 }\r
316 break;\r
317\r
318 case 005: /* MWI 105705 (OP_N) */\r
319 while (XR != 0) { /* loop */\r
320 t = ReadW (AR & VAMASK); /* read curr */\r
321 WriteWA (BR & VAMASK, t); /* write alt */\r
322 AR = (AR + 1) & DMASK; /* incr ptrs */\r
323 BR = (BR + 1) & DMASK;\r
324 XR = (XR - 1) & DMASK;\r
325 if (XR && intrq) { /* more and intr? */\r
326 PC = err_PC; /* stop for now */\r
327 break;\r
328 }\r
329 }\r
330 break;\r
331\r
332 case 006: /* MWF 105706 (OP_N) */\r
333 while (XR != 0) { /* loop */\r
334 t = ReadWA (AR & VAMASK); /* read alt */\r
335 WriteW (BR & VAMASK, t); /* write curr */\r
336 AR = (AR + 1) & DMASK; /* incr ptrs */\r
337 BR = (BR + 1) & DMASK;\r
338 XR = (XR - 1) & DMASK;\r
339 if (XR && intrq) { /* more and intr? */\r
340 PC = err_PC; /* stop for now */\r
341 break;\r
342 }\r
343 }\r
344 break;\r
345\r
346 case 007: /* MWW 105707 (OP_N) */\r
347 while (XR != 0) { /* loop */\r
348 t = ReadWA (AR & VAMASK); /* read alt */\r
349 WriteWA (BR & VAMASK, t); /* write alt */\r
350 AR = (AR + 1) & DMASK; /* incr ptrs */\r
351 BR = (BR + 1) & DMASK;\r
352 XR = (XR - 1) & DMASK;\r
353 if (XR && intrq) { /* more and intr? */\r
354 PC = err_PC; /* stop for now */\r
355 break;\r
356 }\r
357 }\r
358 break;\r
359\r
360 case 010: /* SYA, SYB 10x710 (OP_N) */\r
361 case 011: /* USA, USB 10x711 (OP_N) */\r
362 case 012: /* PAA, PAB 10x712 (OP_N) */\r
363 case 013: /* PBA, PBB 10x713 (OP_N) */\r
364 mapi = (IR & 03) << VA_N_PAG; /* map base */\r
365 if (ABREG[absel] & SIGN) { /* store? */\r
366 for (i = 0; i < MAP_LNT; i++) {\r
367 t = dms_rmap (mapi + i); /* map to memory */\r
368 WriteW ((ABREG[absel] + i) & VAMASK, t);\r
369 }\r
370 }\r
371 else { /* load */\r
372 dms_viol (err_PC, MVI_PRV); /* priv if PRO */\r
373 for (i = 0; i < MAP_LNT; i++) {\r
374 t = ReadW ((ABREG[absel] + i) & VAMASK);\r
375 dms_wmap (mapi + i, t); /* mem to map */\r
376 }\r
377 }\r
378 ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK;\r
379 break;\r
380\r
381 case 014: /* SSM 105714 (OP_A) */\r
382 WriteW (op[0].word, dms_upd_sr ()); /* store stat */\r
383 break;\r
384\r
385 case 015: /* JRS 105715 (OP_KA) */\r
386 if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
387 dms_enb = 0; /* assume off */\r
388 dms_ump = SMAP;\r
389 if (op[0].word & 0100000) { /* set enable? */\r
390 dms_enb = 1;\r
391 if (op[0].word & 0040000) dms_ump = UMAP; /* set/clr usr */\r
392 }\r
393 mp_dms_jmp (op[1].word); /* mpck jmp target */\r
394 PCQ_ENTRY; /* save old PC */\r
395 PC = op[1].word; /* jump */\r
396 ion_defer = 1; /* defer intr */\r
397 break;\r
398\r
399/* DMS module 2 */\r
400\r
401 case 020: /* XMM 105720 (OP_N) */\r
402 XMM:\r
403 if (XR == 0) break; /* nop? */\r
404 while (XR != 0) { /* loop */\r
405 if (XR & SIGN) { /* store? */\r
406 t = dms_rmap (AR); /* map to mem */\r
407 WriteW (BR & VAMASK, t);\r
408 XR = (XR + 1) & DMASK;\r
409 }\r
410 else { /* load */\r
411 dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
412 t = ReadW (BR & VAMASK); /* mem to map */\r
413 dms_wmap (AR, t);\r
414 XR = (XR - 1) & DMASK;\r
415 }\r
416 AR = (AR + 1) & DMASK;\r
417 BR = (BR + 1) & DMASK;\r
418 if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */\r
419 PC = err_PC; /* stop for now */\r
420 break;\r
421 }\r
422 }\r
423 break;\r
424\r
425 case 021: /* XMS 105721 (OP_N) */\r
426 if ((XR & SIGN) || (XR == 0)) break; /* nop? */\r
427 dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
428 while (XR != 0) {\r
429 dms_wmap (AR, BR); /* AR to map */\r
430 XR = (XR - 1) & DMASK;\r
431 AR = (AR + 1) & DMASK;\r
432 BR = (BR + 1) & DMASK;\r
433 if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */\r
434 PC = err_PC;\r
435 break;\r
436 }\r
437 }\r
438 break;\r
439\r
440 case 022: /* XMA, XMB 10x722 (OP_N) */\r
441 dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
442 if (ABREG[absel] & 0100000) mapi = UMAP;\r
443 else mapi = SMAP;\r
444 if (ABREG[absel] & 0000001) mapj = PBMAP;\r
445 else mapj = PAMAP;\r
446 for (i = 0; i < MAP_LNT; i++) {\r
447 t = dms_rmap (mapi + i); /* read map */\r
448 dms_wmap (mapj + i, t); /* write map */\r
449 }\r
450 break;\r
451\r
452 case 024: /* XLA, XLB 10x724 (OP_A) */\r
453 ABREG[absel] = ReadWA (op[0].word); /* load alt */\r
454 break;\r
455\r
456 case 025: /* XSA, XSB 10x725 (OP_A) */\r
457 WriteWA (op[0].word, ABREG[absel]); /* store alt */\r
458 break;\r
459\r
460 case 026: /* XCA, XCB 10x726 (OP_A) */\r
461 if (ABREG[absel] != ReadWA (op[0].word)) /* compare alt */\r
462 PC = (PC + 1) & VAMASK;\r
463 break;\r
464\r
465 case 027: /* LFA, LFB 10x727 (OP_N) */\r
466 if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
467 dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) |\r
468 (ABREG[absel] & (MST_FLT | MST_FENCE));\r
469 break;\r
470\r
471 case 030: /* RSA, RSB 10x730 (OP_N) */\r
472 ABREG[absel] = dms_upd_sr (); /* save stat */\r
473 break;\r
474\r
475 case 031: /* RVA, RVB 10x731 (OP_N) */\r
476 ABREG[absel] = dms_vr; /* save viol */\r
477 break;\r
478\r
479 case 032: /* DJP 105732 (OP_A) */\r
480 if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
481 mp_dms_jmp (op[0].word); /* validate jump addr */\r
482 PCQ_ENTRY; /* save curr PC */\r
483 PC = op[0].word; /* new PC */\r
484 dms_enb = 0; /* disable map */\r
485 dms_ump = SMAP;\r
486 ion_defer = 1;\r
487 break;\r
488\r
489 case 033: /* DJS 105733 (OP_A) */\r
490 if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
491 WriteW (op[0].word, PC); /* store ret addr */\r
492 PCQ_ENTRY; /* save curr PC */\r
493 PC = (op[0].word + 1) & VAMASK; /* new PC */\r
494 dms_enb = 0; /* disable map */\r
495 dms_ump = SMAP;\r
496 ion_defer = 1; /* defer intr */\r
497 break;\r
498\r
499 case 034: /* SJP 105734 (OP_A) */\r
500 if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
501 mp_dms_jmp (op[0].word); /* validate jump addr */\r
502 PCQ_ENTRY; /* save curr PC */\r
503 PC = op[0].word; /* jump */\r
504 dms_enb = 1; /* enable system */\r
505 dms_ump = SMAP;\r
506 ion_defer = 1; /* defer intr */\r
507 break;\r
508\r
509 case 035: /* SJS 105735 (OP_A) */\r
510 if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
511 t = PC; /* save retn addr */\r
512 PCQ_ENTRY; /* save curr PC */\r
513 PC = (op[0].word + 1) & VAMASK; /* new PC */\r
514 dms_enb = 1; /* enable system */\r
515 dms_ump = SMAP;\r
516 WriteW (op[0].word, t); /* store ret addr */\r
517 ion_defer = 1; /* defer intr */\r
518 break;\r
519\r
520 case 036: /* UJP 105736 (OP_A) */\r
521 if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
522 mp_dms_jmp (op[0].word); /* validate jump addr */\r
523 PCQ_ENTRY; /* save curr PC */\r
524 PC = op[0].word; /* jump */\r
525 dms_enb = 1; /* enable user */\r
526 dms_ump = UMAP;\r
527 ion_defer = 1; /* defer intr */\r
528 break;\r
529\r
530 case 037: /* UJS 105737 (OP_A) */\r
531 if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */\r
532 t = PC; /* save retn addr */\r
533 PCQ_ENTRY; /* save curr PC */\r
534 PC = (op[0].word + 1) & VAMASK; /* new PC */\r
535 dms_enb = 1; /* enable user */\r
536 dms_ump = UMAP;\r
537 WriteW (op[0].word, t); /* store ret addr */\r
538 ion_defer = 1; /* defer intr */\r
539 break;\r
540\r
541 default: /* others NOP */\r
542 break;\r
543 }\r
544\r
545return reason;\r
546}\r
547\r
548\r
549/* Extended Instruction Group\r
550\r
551 The Extended Instruction Group (EIG) adds 32 index and 10 bit/byte/word\r
552 manipulation instructions to the 1000 base set. These instructions\r
553 use the new X and Y index registers that were added to the 1000.\r
554\r
555 Option implementation by CPU was as follows:\r
556\r
557 2114 2115 2116 2100 1000-M 1000-E 1000-F\r
558 ------ ------ ------ ------ ------ ------ ------\r
559 N/A N/A N/A N/A std std std\r
560\r
561 The instruction codes are mapped to routines as follows:\r
562\r
563 Instr. 1000-M/E/F Instr. 1000-M/E/F\r
564 ------ ---------- ------ ----------\r
565 10x740 S*X 10x760 ISX\r
566 10x741 C*X 10x761 DSX\r
567 10x742 L*X 10x762 JLY\r
568 10x743 STX 10x763 LBT\r
569 10x744 CX* 10x764 SBT\r
570 10x745 LDX 10x765 MBT\r
571 10x746 ADX 10x766 CBT\r
572 10x747 X*X 10x767 SFB\r
573\r
574 10x750 S*Y 10x770 ISY\r
575 10x751 C*Y 10x771 DSY\r
576 10x752 L*Y 10x772 JPY\r
577 10x753 STY 10x773 SBS\r
578 10x754 CY* 10x774 CBS\r
579 10x755 LDY 10x775 TBS\r
580 10x756 ADY 10x776 CMW\r
581 10x757 X*Y 10x777 MVW\r
582\r
583 Instructions that use IR bit 9 to select the A or B register are designated\r
584 with a * above (e.g., 101740 is SAX, and 105740 is SBX). For those that do\r
585 not use this feature, either the 101xxx or 105xxx code will execute the\r
586 corresponding instruction, although the 105xxx form is the documented\r
587 instruction code.\r
588\r
589 Notes:\r
590\r
591 1. The LBT, SBT, MBT, and MVW instructions are used as part of the 2100 IOP\r
592 implementation. When so called, the MBT and MVW instructions have the\r
593 additional restriction that the count must be positive.\r
594*/\r
595\r
596static const OP_PAT op_eig[32] = {\r
597 OP_A, OP_N, OP_A, OP_A, /* S*X C*X L*X STX */\r
598 OP_N, OP_K, OP_K, OP_N, /* CX* LDX ADX X*X */\r
599 OP_A, OP_N, OP_A, OP_A, /* S*Y C*Y L*Y STY */\r
600 OP_N, OP_K, OP_K, OP_N, /* CY* LDY ADY X*Y */\r
601 OP_N, OP_N, OP_A, OP_N, /* ISX DSX JLY LBT */\r
602 OP_N, OP_KV, OP_KV, OP_N, /* SBT MBT CBT SFB */\r
603 OP_N, OP_N, OP_C, OP_KA, /* ISY DSY JPY SBS */\r
604 OP_KA, OP_KK, OP_KV, OP_KV /* CBS TBS CMW MVW */\r
605 };\r
606\r
607t_stat cpu_eig (uint32 IR, uint32 intrq)\r
608{\r
609t_stat reason = SCPE_OK;\r
610OPS op;\r
611uint32 entry, absel;\r
612uint32 t, v1, v2, wc;\r
613int32 sop1, sop2;\r
614\r
615absel = (IR & I_AB)? 1: 0; /* get A/B select */\r
616entry = IR & 037; /* mask to entry point */\r
617\r
618if (op_eig[entry] != OP_N)\r
619 if (reason = cpu_ops (op_eig[entry], op, intrq)) /* get instruction operands */\r
620 return reason;\r
621\r
622switch (entry) { /* decode IR<4:0> */\r
623\r
624/* EIG module 1 */\r
625\r
626 case 000: /* SAX, SBX 10x740 (OP_A) */\r
627 op[0].word = (op[0].word + XR) & VAMASK; /* indexed addr */\r
628 WriteW (op[0].word, ABREG[absel]); /* store */\r
629 break;\r
630\r
631 case 001: /* CAX, CBX 10x741 (OP_N) */\r
632 XR = ABREG[absel]; /* copy to XR */\r
633 break;\r
634\r
635 case 002: /* LAX, LBX 10x742 (OP_A) */\r
636 op[0].word = (op[0].word + XR) & VAMASK; /* indexed addr */\r
637 ABREG[absel] = ReadW (op[0].word); /* load */\r
638 break;\r
639\r
640 case 003: /* STX 105743 (OP_A) */\r
641 WriteW (op[0].word, XR); /* store XR */\r
642 break;\r
643\r
644 case 004: /* CXA, CXB 10x744 (OP_N) */\r
645 ABREG[absel] = XR; /* copy from XR */\r
646 break;\r
647\r
648 case 005: /* LDX 105745 (OP_K)*/\r
649 XR = op[0].word; /* load XR */\r
650 break;\r
651\r
652 case 006: /* ADX 105746 (OP_K) */\r
653 t = XR + op[0].word; /* add to XR */\r
654 if (t > DMASK) E = 1; /* set E, O */\r
655 if (((~XR ^ op[0].word) & (XR ^ t)) & SIGN) O = 1;\r
656 XR = t & DMASK;\r
657 break;\r
658\r
659 case 007: /* XAX, XBX 10x747 (OP_N) */\r
660 t = XR; /* exchange XR */\r
661 XR = ABREG[absel];\r
662 ABREG[absel] = t;\r
663 break;\r
664\r
665 case 010: /* SAY, SBY 10x750 (OP_A) */\r
666 op[0].word = (op[0].word + YR) & VAMASK; /* indexed addr */\r
667 WriteW (op[0].word, ABREG[absel]); /* store */\r
668 break;\r
669\r
670 case 011: /* CAY, CBY 10x751 (OP_N) */\r
671 YR = ABREG[absel]; /* copy to YR */\r
672 break;\r
673\r
674 case 012: /* LAY, LBY 10x752 (OP_A) */\r
675 op[0].word = (op[0].word + YR) & VAMASK; /* indexed addr */\r
676 ABREG[absel] = ReadW (op[0].word); /* load */\r
677 break;\r
678\r
679 case 013: /* STY 105753 (OP_A) */\r
680 WriteW (op[0].word, YR); /* store YR */\r
681 break;\r
682\r
683 case 014: /* CYA, CYB 10x754 (OP_N) */\r
684 ABREG[absel] = YR; /* copy from YR */\r
685 break;\r
686\r
687 case 015: /* LDY 105755 (OP_K) */\r
688 YR = op[0].word; /* load YR */\r
689 break;\r
690\r
691 case 016: /* ADY 105756 (OP_K) */\r
692 t = YR + op[0].word; /* add to YR */\r
693 if (t > DMASK) E = 1; /* set E, O */\r
694 if (((~YR ^ op[0].word) & (YR ^ t)) & SIGN) O = 1;\r
695 YR = t & DMASK;\r
696 break;\r
697\r
698 case 017: /* XAY, XBY 10x757 (OP_N) */\r
699 t = YR; /* exchange YR */\r
700 YR = ABREG[absel];\r
701 ABREG[absel] = t;\r
702 break;\r
703\r
704/* EIG module 2 */\r
705\r
706 case 020: /* ISX 105760 (OP_N) */\r
707 XR = (XR + 1) & DMASK; /* incr XR */\r
708 if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */\r
709 break;\r
710\r
711 case 021: /* DSX 105761 (OP_N) */\r
712 XR = (XR - 1) & DMASK; /* decr XR */\r
713 if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */\r
714 break;\r
715\r
716 case 022: /* JLY 105762 (OP_A) */\r
717 mp_dms_jmp (op[0].word); /* validate jump addr */\r
718 PCQ_ENTRY;\r
719 YR = PC; /* ret addr to YR */\r
720 PC = op[0].word; /* jump */\r
721 break;\r
722\r
723 case 023: /* LBT 105763 (OP_N) */\r
724 AR = ReadB (BR); /* load byte */\r
725 BR = (BR + 1) & DMASK; /* incr ptr */\r
726 break;\r
727\r
728 case 024: /* SBT 105764 (OP_N) */\r
729 WriteB (BR, AR); /* store byte */\r
730 BR = (BR + 1) & DMASK; /* incr ptr */\r
731 break;\r
732\r
733 case 025: /* MBT 105765 (OP_KV) */\r
734 wc = ReadW (op[1].word); /* get continuation count */\r
735 if (wc == 0) wc = op[0].word; /* none? get initiation count */\r
736 if ((wc & SIGN) &&\r
737 (UNIT_CPU_TYPE == UNIT_TYPE_2100))\r
738 break; /* < 0 is NOP for 2100 IOP */\r
739 while (wc != 0) { /* while count */\r
740 WriteW (op[1].word, wc); /* for MP abort */\r
741 t = ReadB (AR); /* move byte */\r
742 WriteB (BR, t);\r
743 AR = (AR + 1) & DMASK; /* incr src */\r
744 BR = (BR + 1) & DMASK; /* incr dst */\r
745 wc = (wc - 1) & DMASK; /* decr cnt */\r
746 if (intrq && wc) { /* intr, more to do? */\r
747 PC = err_PC; /* back up PC */\r
748 break;\r
749 }\r
750 }\r
751 WriteW (op[1].word, wc); /* clean up inline */\r
752 break;\r
753\r
754 case 026: /* CBT 105766 (OP_KV) */\r
755 wc = ReadW (op[1].word); /* get continuation count */\r
756 if (wc == 0) wc = op[0].word; /* none? get initiation count */\r
757 while (wc != 0) { /* while count */\r
758 WriteW (op[1].word, wc); /* for MP abort */\r
759 v1 = ReadB (AR); /* get src1 */\r
760 v2 = ReadB (BR); /* get src2 */\r
761 if (v1 != v2) { /* compare */\r
762 PC = (PC + 1 + (v1 > v2)) & VAMASK;\r
763 BR = (BR + wc) & DMASK; /* update BR */\r
764 wc = 0; /* clr interim */\r
765 break;\r
766 }\r
767 AR = (AR + 1) & DMASK; /* incr src1 */\r
768 BR = (BR + 1) & DMASK; /* incr src2 */\r
769 wc = (wc - 1) & DMASK; /* decr cnt */\r
770 if (intrq && wc) { /* intr, more to do? */\r
771 PC = err_PC; /* back up PC */\r
772 break;\r
773 }\r
774 }\r
775 WriteW (op[1].word, wc); /* clean up inline */\r
776 break;\r
777\r
778 case 027: /* SFB 105767 (OP_N) */\r
779 v1 = AR & 0377; /* test byte */\r
780 v2 = (AR >> 8) & 0377; /* term byte */\r
781 for (;;) { /* scan */\r
782 t = ReadB (BR); /* read byte */\r
783 if (t == v1) break; /* test match? */\r
784 BR = (BR + 1) & DMASK;\r
785 if (t == v2) { /* term match? */\r
786 PC = (PC + 1) & VAMASK;\r
787 break;\r
788 }\r
789 if (intrq) { /* int pending? */\r
790 PC = err_PC; /* back up PC */\r
791 break;\r
792 }\r
793 }\r
794 break;\r
795\r
796 case 030: /* ISY 105770 (OP_N) */\r
797 YR = (YR + 1) & DMASK; /* incr YR */\r
798 if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */\r
799 break;\r
800\r
801 case 031: /* DSY 105771 (OP_N) */\r
802 YR = (YR - 1) & DMASK; /* decr YR */\r
803 if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */\r
804 break;\r
805\r
806 case 032: /* JPY 105772 (OP_C) */\r
807 op[0].word = (op[0].word + YR) & VAMASK; /* index, no indir */\r
808 mp_dms_jmp (op[0].word); /* validate jump addr */\r
809 PCQ_ENTRY;\r
810 PC = op[0].word; /* jump */\r
811 break;\r
812\r
813 case 033: /* SBS 105773 (OP_KA) */\r
814 WriteW (op[1].word, /* set bits */\r
815 ReadW (op[1].word) | op[0].word);\r
816 break;\r
817\r
818 case 034: /* CBS 105774 (OP_KA) */\r
819 WriteW (op[1].word, /* clear bits */\r
820 ReadW (op[1].word) & ~op[0].word);\r
821 break;\r
822\r
823 case 035: /* TBS 105775 (OP_KK) */\r
824 if ((op[1].word & op[0].word) != op[0].word) /* test bits */\r
825 PC = (PC + 1) & VAMASK;\r
826 break;\r
827\r
828 case 036: /* CMW 105776 (OP_KV) */\r
829 wc = ReadW (op[1].word); /* get continuation count */\r
830 if (wc == 0) wc = op[0].word; /* none? get initiation count */\r
831 while (wc != 0) { /* while count */\r
832 WriteW (op[1].word, wc); /* for abort */\r
833 v1 = ReadW (AR & VAMASK); /* first op */\r
834 v2 = ReadW (BR & VAMASK); /* second op */\r
835 sop1 = (int32) SEXT (v1); /* signed */\r
836 sop2 = (int32) SEXT (v2);\r
837 if (sop1 != sop2) { /* compare */\r
838 PC = (PC + 1 + (sop1 > sop2)) & VAMASK;\r
839 BR = (BR + wc) & DMASK; /* update BR */\r
840 wc = 0; /* clr interim */\r
841 break;\r
842 }\r
843 AR = (AR + 1) & DMASK; /* incr src1 */\r
844 BR = (BR + 1) & DMASK; /* incr src2 */\r
845 wc = (wc - 1) & DMASK; /* decr cnt */\r
846 if (intrq && wc) { /* intr, more to do? */\r
847 PC = err_PC; /* back up PC */\r
848 break;\r
849 }\r
850 }\r
851 WriteW (op[1].word, wc); /* clean up inline */\r
852 break;\r
853\r
854 case 037: /* MVW 105777 (OP_KV) */\r
855 wc = ReadW (op[1].word); /* get continuation count */\r
856 if (wc == 0) wc = op[0].word; /* none? get initiation count */\r
857 if ((wc & SIGN) &&\r
858 (UNIT_CPU_TYPE == UNIT_TYPE_2100))\r
859 break; /* < 0 is NOP for 2100 IOP */\r
860 while (wc != 0) { /* while count */\r
861 WriteW (op[1].word, wc); /* for abort */\r
862 t = ReadW (AR & VAMASK); /* move word */\r
863 WriteW (BR & VAMASK, t);\r
864 AR = (AR + 1) & DMASK; /* incr src */\r
865 BR = (BR + 1) & DMASK; /* incr dst */\r
866 wc = (wc - 1) & DMASK; /* decr cnt */\r
867 if (intrq && wc) { /* intr, more to do? */\r
868 PC = err_PC; /* back up PC */\r
869 break;\r
870 }\r
871 }\r
872 WriteW (op[1].word, wc); /* clean up inline */\r
873 break;\r
874\r
875 }\r
876\r
877return reason;\r
878}\r
879\r
880\r
881/* 2000 I/O Processor\r
882\r
883 The IOP accelerates certain operations of the HP 2000 Time-Share BASIC system\r
884 I/O processor. Most 2000 systems were delivered with 2100 CPUs, although IOP\r
885 microcode was developed for the 1000-M and 1000-E. As the I/O processors\r
886 were specific to the 2000 system, general compatibility with other CPU\r
887 microcode options was unnecessary, and indeed no other options were possible\r
888 for the 2100.\r
889\r
890 Option implementation by CPU was as follows:\r
891\r
892 2114 2115 2116 2100 1000-M 1000-E 1000-F\r
893 ------ ------ ------ ------ ------ ------ ------\r
894 N/A N/A N/A 13206A 13207A 22702A N/A\r
895\r
896 The routines are mapped to instruction codes as follows:\r
897\r
898 Instr. 2100 1000-M/E Description\r
899 ------ ---------- ---------- --------------------------------------------\r
900 SAI 105060-117 101400-037 Store A indexed by B (+/- offset in IR<4:0>)\r
901 LAI 105020-057 105400-037 Load A indexed by B (+/- offset in IR<4:0>)\r
902 CRC 105150 105460 Generate CRC\r
903 REST 105340 105461 Restore registers from stack\r
904 READF 105220 105462 Read F register (stack pointer)\r
905 INS -- 105463 Initialize F register (stack pointer)\r
906 ENQ 105240 105464 Enqueue\r
907 PENQ 105257 105465 Priority enqueue\r
908 DEQ 105260 105466 Dequeue\r
909 TRSLT 105160 105467 Translate character\r
910 ILIST 105000 105470 Indirect address list (similar to $SETP)\r
911 PRFEI 105222 105471 Power fail exit with I/O\r
912 PRFEX 105223 105472 Power fail exit\r
913 PRFIO 105221 105473 Power fail I/O\r
914 SAVE 105362 105474 Save registers to stack\r
915\r
916 MBYTE 105120 105765 Move bytes (MBT)\r
917 MWORD 105200 105777 Move words (MVW)\r
918 SBYTE 105300 105764 Store byte (SBT)\r
919 LBYTE 105320 105763 Load byte (LBT)\r
920\r
921 The INS instruction was not required in the 2100 implementation because the\r
922 stack pointer was actually the memory protect fence register and so could be\r
923 loaded directly with an OTA/B 05. Also, the 1000 implementation did not\r
924 offer the MBYTE, MWORD, SBYTE, and LBYTE instructions because the equivalent\r
925 instructions from the standard Extended Instruction Group were used instead.\r
926 Note that the 2100 MBYTE and MWORD instructions operate slightly differently\r
927 from the 1000 MBT and MVW instructions. Specifically, the move count is\r
928 signed on the 2100 and unsigned on the 1000. A negative count on the 2100\r
929 results in a NOP.\r
930\r
931 The simulator remaps the 2100 instructions to the 1000 codes. The four EIG equivalents\r
932 are dispatched to the EIG simulator. The rest are handled here. Note that the MBT and\r
933 MVW instructions operate slightly differently on the 2100; they are\r
934\r
935 Additional reference:\r
936 - HP 2000 Computer System Sources and Listings Documentation\r
937 (22687-90020, undated), section 3, pages 2-74 through 2-91.\r
938*/\r
939\r
940static const OP_PAT op_iop[16] = {\r
941 OP_V, OP_N, OP_N, OP_N, /* CRC RESTR READF INS */\r
942 OP_N, OP_N, OP_N, OP_V, /* ENQ PENQ DEQ TRSLT */\r
943 OP_AC, OP_CVA, OP_A, OP_CV, /* ILIST PRFEI PRFEX PRFIO */\r
944 OP_N, OP_N, OP_N, OP_N /* SAVE --- --- --- */\r
945 };\r
946\r
947t_stat cpu_iop (uint32 IR, uint32 intrq)\r
948{\r
949t_stat reason = SCPE_OK;\r
950OPS op;\r
951uint32 entry;\r
952uint32 hp, tp, i, t, wc, MA;\r
953\r
954if ((cpu_unit.flags & UNIT_IOP) == 0) /* IOP option installed? */\r
955 return stop_inst;\r
956\r
957if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 IOP? */\r
958 if ((IR >= 0105020) && (IR <= 0105057)) /* remap LAI */\r
959 IR = 0105400 | (IR - 0105020);\r
960 else if ((IR >= 0105060) && (IR <= 0105117)) /* remap SAI */\r
961 IR = 0101400 | (IR - 0105060);\r
962 else {\r
963 switch (IR) { /* remap others */\r
964 case 0105000: IR = 0105470; break; /* ILIST */\r
965 case 0105120: return cpu_eig (0105765, intrq); /* MBYTE (maps to MBT) */\r
966 case 0105150: IR = 0105460; break; /* CRC */\r
967 case 0105160: IR = 0105467; break; /* TRSLT */\r
968 case 0105200: return cpu_eig (0105777, intrq); /* MWORD (maps to MVW) */\r
969 case 0105220: IR = 0105462; break; /* READF */\r
970 case 0105221: IR = 0105473; break; /* PRFIO */\r
971 case 0105222: IR = 0105471; break; /* PRFEI */\r
972 case 0105223: IR = 0105472; break; /* PRFEX */\r
973 case 0105240: IR = 0105464; break; /* ENQ */\r
974 case 0105257: IR = 0105465; break; /* PENQ */\r
975 case 0105260: IR = 0105466; break; /* DEQ */\r
976 case 0105300: return cpu_eig (0105764, intrq); /* SBYTE (maps to SBT) */\r
977 case 0105320: return cpu_eig (0105763, intrq); /* LBYTE (maps to LBT) */\r
978 case 0105340: IR = 0105461; break; /* REST */\r
979 case 0105362: IR = 0105474; break; /* SAVE */\r
980\r
981 default: /* all others invalid */\r
982 return stop_inst;\r
983 }\r
984 }\r
985 }\r
986\r
987entry = IR & 077; /* mask to entry point */\r
988\r
989if (entry <= 037) { /* LAI/SAI 10x400-437 */\r
990 MA = ((entry - 020) + BR) & VAMASK; /* +/- offset */\r
991 if (IR & I_AB) AR = ReadW (MA); /* AB = 1 -> LAI */\r
992 else WriteW (MA, AR); /* AB = 0 -> SAI */\r
993 return reason;\r
994 }\r
995else if (entry <= 057) /* IR = 10x440-457? */\r
996 return stop_inst; /* not part of IOP */\r
997\r
998entry = entry - 060; /* offset 10x460-477 */\r
999\r
1000if (op_iop[entry] != OP_N)\r
1001 if (reason = cpu_ops (op_iop[entry], op, intrq)) /* get instruction operands */\r
1002 return reason;\r
1003\r
1004switch (entry) { /* decode IR<5:0> */\r
1005\r
1006 case 000: /* CRC 105460 (OP_V) */\r
1007 t = ReadW (op[0].word) ^ (AR & 0377); /* xor prev CRC and char */\r
1008 for (i = 0; i < 8; i++) { /* apply polynomial */\r
1009 t = (t >> 1) | ((t & 1) << 15); /* rotate right */\r
1010 if (t & SIGN) t = t ^ 020001; /* old t<0>? xor */\r
1011 }\r
1012 WriteW (op[0].word, t); /* rewrite CRC */\r
1013 break;\r
1014\r
1015 case 001: /* RESTR 105461 (OP_N) */\r
1016 iop_sp = (iop_sp - 1) & VAMASK; /* decr stack ptr */\r
1017 t = ReadW (iop_sp); /* get E and O */\r
1018 O = ((t >> 1) ^ 1) & 1; /* restore O */\r
1019 E = t & 1; /* restore E */\r
1020 iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */\r
1021 BR = ReadW (iop_sp); /* restore B */\r
1022 iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */\r
1023 AR = ReadW (iop_sp); /* restore A */\r
1024 if (UNIT_CPU_MODEL == UNIT_2100)\r
1025 mp_fence = iop_sp; /* 2100 keeps sp in MP FR */\r
1026 break;\r
1027\r
1028 case 002: /* READF 105462 (OP_N) */\r
1029 AR = iop_sp; /* copy stk ptr */\r
1030 break;\r
1031\r
1032 case 003: /* INS 105463 (OP_N) */\r
1033 iop_sp = AR; /* init stk ptr */\r
1034 break;\r
1035\r
1036 case 004: /* ENQ 105464 (OP_N) */\r
1037 hp = ReadW (AR & VAMASK); /* addr of head */\r
1038 tp = ReadW ((AR + 1) & VAMASK); /* addr of tail */\r
1039 WriteW ((BR - 1) & VAMASK, 0); /* entry link */\r
1040 WriteW ((tp - 1) & VAMASK, BR); /* tail link */\r
1041 WriteW ((AR + 1) & VAMASK, BR); /* queue tail */\r
1042 if (hp != 0) PC = (PC + 1) & VAMASK; /* q not empty? skip */\r
1043 break;\r
1044\r
1045 case 005: /* PENQ 105465 (OP_N) */\r
1046 hp = ReadW (AR & VAMASK); /* addr of head */\r
1047 WriteW ((BR - 1) & VAMASK, hp); /* becomes entry link */\r
1048 WriteW (AR & VAMASK, BR); /* queue head */\r
1049 if (hp == 0) /* q empty? */\r
1050 WriteW ((AR + 1) & VAMASK, BR); /* queue tail */\r
1051 else PC = (PC + 1) & VAMASK; /* skip */\r
1052 break;\r
1053\r
1054 case 006: /* DEQ 105466 (OP_N) */\r
1055 BR = ReadW (AR & VAMASK); /* addr of head */\r
1056 if (BR) { /* queue not empty? */\r
1057 hp = ReadW ((BR - 1) & VAMASK); /* read hd entry link */\r
1058 WriteW (AR & VAMASK, hp); /* becomes queue head */\r
1059 if (hp == 0) /* q now empty? */\r
1060 WriteW ((AR + 1) & VAMASK, (AR + 1) & DMASK);\r
1061 PC = (PC + 1) & VAMASK; /* skip */\r
1062 }\r
1063 break;\r
1064\r
1065 case 007: /* TRSLT 105467 (OP_V) */\r
1066 wc = ReadW (op[0].word); /* get count */\r
1067 if (wc & SIGN) break; /* cnt < 0? */\r
1068 while (wc != 0) { /* loop */\r
1069 MA = (AR + AR + ReadB (BR)) & VAMASK;\r
1070 t = ReadB (MA); /* xlate */\r
1071 WriteB (BR, t); /* store char */\r
1072 BR = (BR + 1) & DMASK; /* incr ptr */\r
1073 wc = (wc - 1) & DMASK; /* decr cnt */\r
1074 if (wc && intrq) { /* more and intr? */\r
1075 WriteW (op[0].word, wc); /* save count */\r
1076 PC = err_PC; /* stop for now */\r
1077 break;\r
1078 }\r
1079 }\r
1080 break;\r
1081\r
1082 case 010: /* ILIST 105470 (OP_AC) */\r
1083 do { /* for count */\r
1084 WriteW (op[0].word, AR); /* write AR to mem */\r
1085 AR = (AR + 1) & DMASK; /* incr AR */\r
1086 op[0].word = (op[0].word + 1) & VAMASK; /* incr MA */\r
1087 op[1].word = (op[1].word - 1) & DMASK; /* decr count */\r
1088 }\r
1089 while (op[1].word != 0);\r
1090 break;\r
1091\r
1092 case 011: /* PRFEI 105471 (OP_CVA) */\r
1093 WriteW (op[1].word, 1); /* set flag */\r
1094 reason = iogrp (op[0].word, 0); /* execute I/O instr */\r
1095 op[0].word = op[2].word; /* set rtn and fall through */\r
1096\r
1097 case 012: /* PRFEX 105472 (OP_A) */\r
1098 PCQ_ENTRY;\r
1099 PC = ReadW (op[0].word) & VAMASK; /* jump indirect */\r
1100 WriteW (op[0].word, 0); /* clear exit */\r
1101 break;\r
1102\r
1103 case 013: /* PRFIO 105473 (OP_CV) */\r
1104 WriteW (op[1].word, 1); /* set flag */\r
1105 reason = iogrp (op[0].word, 0); /* execute instr */\r
1106 break;\r
1107\r
1108 case 014: /* SAVE 105474 (OP_N) */\r
1109 WriteW (iop_sp, AR); /* save A */\r
1110 iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */\r
1111 WriteW (iop_sp, BR); /* save B */\r
1112 iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */\r
1113 t = ((O ^ 1) << 1) | E; /* merge E and O */\r
1114 WriteW (iop_sp, t); /* save E and O */\r
1115 iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */\r
1116 if (UNIT_CPU_TYPE == UNIT_TYPE_2100)\r
1117 mp_fence = iop_sp; /* 2100 keeps sp in MP FR */\r
1118 break;\r
1119\r
1120 default: /* instruction undefined */\r
1121 return stop_inst;\r
1122 }\r
1123\r
1124return reason;\r
1125}\r