Commit | Line | Data |
---|---|---|
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 | |
57 | t_stat cpu_fp (uint32 IR, uint32 intrq); /* Firmware Floating Point */\r | |
58 | \r | |
59 | #endif /* int64 support unavailable */\r | |
60 | \r | |
61 | t_stat cpu_dms (uint32 IR, uint32 intrq); /* Dynamic mapping system */\r | |
62 | t_stat cpu_eig (uint32 IR, uint32 intrq); /* Extended instruction group */\r | |
63 | t_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 | |
112 | static 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 | |
117 | t_stat cpu_fp (uint32 IR, uint32 intrq)\r | |
118 | {\r | |
119 | t_stat reason = SCPE_OK;\r | |
120 | OPS op;\r | |
121 | uint32 entry;\r | |
122 | \r | |
123 | if ((cpu_unit.flags & UNIT_FP) == 0) /* FP option installed? */\r | |
124 | return stop_inst;\r | |
125 | \r | |
126 | entry = (IR >> 4) & 017; /* mask to entry point */\r | |
127 | \r | |
128 | if (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 | |
132 | switch (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 | |
162 | return 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 | |
230 | static 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 | |
241 | t_stat cpu_dms (uint32 IR, uint32 intrq)\r | |
242 | {\r | |
243 | t_stat reason = SCPE_OK;\r | |
244 | OPS op;\r | |
245 | uint32 entry, absel;\r | |
246 | uint32 i, t, mapi, mapj;\r | |
247 | \r | |
248 | if ((cpu_unit.flags & UNIT_DMS) == 0) /* DMS option installed? */\r | |
249 | return stop_inst;\r | |
250 | \r | |
251 | absel = (IR & I_AB)? 1: 0; /* get A/B select */\r | |
252 | entry = IR & 037; /* mask to entry point */\r | |
253 | \r | |
254 | if (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 | |
258 | switch (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 | |
545 | return 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 | |
596 | static 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 | |
607 | t_stat cpu_eig (uint32 IR, uint32 intrq)\r | |
608 | {\r | |
609 | t_stat reason = SCPE_OK;\r | |
610 | OPS op;\r | |
611 | uint32 entry, absel;\r | |
612 | uint32 t, v1, v2, wc;\r | |
613 | int32 sop1, sop2;\r | |
614 | \r | |
615 | absel = (IR & I_AB)? 1: 0; /* get A/B select */\r | |
616 | entry = IR & 037; /* mask to entry point */\r | |
617 | \r | |
618 | if (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 | |
622 | switch (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 | |
877 | return 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 | |
940 | static 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 | |
947 | t_stat cpu_iop (uint32 IR, uint32 intrq)\r | |
948 | {\r | |
949 | t_stat reason = SCPE_OK;\r | |
950 | OPS op;\r | |
951 | uint32 entry;\r | |
952 | uint32 hp, tp, i, t, wc, MA;\r | |
953 | \r | |
954 | if ((cpu_unit.flags & UNIT_IOP) == 0) /* IOP option installed? */\r | |
955 | return stop_inst;\r | |
956 | \r | |
957 | if (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 | |
987 | entry = IR & 077; /* mask to entry point */\r | |
988 | \r | |
989 | if (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 | |
995 | else if (entry <= 057) /* IR = 10x440-457? */\r | |
996 | return stop_inst; /* not part of IOP */\r | |
997 | \r | |
998 | entry = entry - 060; /* offset 10x460-477 */\r | |
999 | \r | |
1000 | if (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 | |
1004 | switch (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 | |
1124 | return reason;\r | |
1125 | }\r |