First Commit of my working state
[simh.git] / HP2100 / hp2100_cpu1.c
CommitLineData
196ba1fc
PH
1/* hp2100_cpu1.c: HP 2100/1000 EAU simulator and UIG dispatcher\r
2\r
3 Copyright (c) 2005-2008, 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 CPU1 Extended arithmetic and optional microcode dispatchers\r
27\r
28 20-Apr-08 JDB Fixed VIS and SIGNAL to depend on the FPP and HAVE_INT64\r
29 28-Nov-07 JDB Added fprint_ops, fprint_regs for debug printouts\r
30 17-Nov-07 JDB Enabled DIAG as NOP on 1000 F-Series\r
31 04-Jan-07 JDB Added special DBI dispatcher for non-INT64 diagnostic\r
32 29-Dec-06 JDB Allows RRR as NOP if 2114 (diag config test)\r
33 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64\r
34 16-Oct-06 JDB Generalized operands for F-Series FP types\r
35 26-Sep-06 JDB Split hp2100_cpu1.c into multiple modules to simplify extensions\r
36 Added iotrap parameter to UIG dispatchers for RTE microcode\r
37 22-Feb-05 JDB Removed EXECUTE instruction (is NOP in actual microcode)\r
38 21-Jan-05 JDB Reorganized CPU option and operand processing flags\r
39 Split code along microcode modules\r
40 15-Jan-05 RMS Cloned from hp2100_cpu.c\r
41\r
42 Primary references:\r
43 - HP 1000 M/E/F-Series Computers Technical Reference Handbook\r
44 (5955-0282, Mar-1980)\r
45 - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation\r
46 (92851-90001, Mar-1981)\r
47 - Macro/1000 Reference Manual (92059-90001, Dec-1992)\r
48\r
49 Additional references are listed with the associated firmware\r
50 implementations, as are the HP option model numbers pertaining to the\r
51 applicable CPUs.\r
52\r
53 This source file contains the Extended Arithmetic Unit simulator and the User\r
54 Instruction Group (a.k.a. "Macro") dispatcher for the 2100 and 1000 (21MX)\r
55 CPUs. The UIG simulators reside in separate source files, due to the large\r
56 number of firmware options available for the 1000 machines. Unit flags\r
57 indicate which options are present in the current system.\r
58\r
59 This module also provides generalized instruction operand processing.\r
60\r
61 The microcode address space of the 2100 encompassed four modules of 256 words\r
62 each. The 1000 M-series expanded that to sixteen modules, and the 1000\r
63 E/F-series expanded that still further to sixty-four modules. Each CPU had\r
64 its own microinstruction set, although the micromachines of the various 1000\r
65 models were similar internally.\r
66\r
67 Regarding option instruction sets, there was some commonality across CPU\r
68 types. EAU instructions were identical across all models, and the floating\r
69 point set was the same on the 2100 and 1000. Other options implemented\r
70 proper instruction supersets (e.g., the Fast FORTRAN Processor from 2100 to\r
71 1000-M to 1000-E to 1000-F) or functional equivalence with differing code\r
72 points (the 2000 I/O Processor from 2100 to 1000 and extended-precision\r
73 floating-point instructions from 1000-E to 1000-F).\r
74\r
75 The 2100 decoded the EAU and UIG sets separately in hardware and supported\r
76 only the UIG 0 code points. Bits 7-4 of a UIG instruction decoded one of\r
77 sixteen entry points in the lowest-numbered module after module 0. Those\r
78 entry points could be used directly (as for the floating-point instructions),\r
79 or additional decoding based on bits 3-0 could be implemented.\r
80\r
81 The 1000 generalized the instruction decoding to a series of microcoded\r
82 jumps, based on the bits in the instruction. Bits 15-8 indicated the group\r
83 of the current instruction: EAU (200, 201, 202, 210, and 211), UIG 0 (212),\r
84 or UIG 1 (203 and 213). UIG 0, UIG 1, and some EAU instructions were decoded\r
85 further by selecting one of sixteen modules within the group via bits 7-4.\r
86 Finally, each UIG module decoded up to sixteen instruction entry points via\r
87 bits 3-0. Jump tables for all firmware options were contained in the base\r
88 set, so modules needed only to be concerned with decoding their individual\r
89 entry points within the module.\r
90\r
91 While the 2100 and 1000 hardware decoded these instruction sets differently,\r
92 the decoding mechanism of the simulation follows that of the 1000 E/F-series.\r
93 Where needed, CPU type- or model-specific behavior is simulated.\r
94\r
95 The design of the 1000 microinstruction set was such that executing an\r
96 instruction for which no microcode was present (e.g., executing a FFP\r
97 instruction when the FFP firmware was not installed) resulted in a NOP.\r
98 Under simulation, such execution causes an undefined instruction stop.\r
99*/\r
100\r
101#include "hp2100_defs.h"\r
102#include "hp2100_cpu.h"\r
103#include "hp2100_cpu1.h"\r
104\r
105#if defined (HAVE_INT64) /* int64 support available */\r
106extern t_stat cpu_fpp (uint32 IR, uint32 intrq); /* Floating Point Processor */\r
107extern t_stat cpu_sis (uint32 IR, uint32 intrq); /* Scientific Instruction Set */\r
108extern t_stat cpu_vis (uint32 IR, uint32 intrq); /* Vector Instruction Set */\r
109extern t_stat cpu_signal (uint32 IR, uint32 intrq); /* SIGNAL/1000 */\r
110#else /* int64 support unavailable */\r
111extern t_stat cpu_fp (uint32 IR, uint32 intrq); /* Firmware Floating Point */\r
112#endif /* end of int64 support */\r
113\r
114extern t_stat cpu_ffp (uint32 IR, uint32 intrq); /* Fast FORTRAN Processor */\r
115extern t_stat cpu_ds (uint32 IR, uint32 intrq); /* Distributed Systems */\r
116extern t_stat cpu_dbi (uint32 IR, uint32 intrq); /* Double integer */\r
117extern t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-4/6 EMA/VMA */\r
118extern t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* RTE-6 OS */\r
119extern t_stat cpu_iop (uint32 IR, uint32 intrq); /* 2000 I/O Processor */\r
120extern t_stat cpu_dms (uint32 IR, uint32 intrq); /* Dynamic mapping system */\r
121extern t_stat cpu_eig (uint32 IR, uint32 intrq); /* Extended instruction group */\r
122\r
123/* EAU\r
124\r
125 The Extended Arithmetic Unit (EAU) adds ten instructions with double-word\r
126 operands, including multiply, divide, shifts, and rotates. Option\r
127 implementation by CPU was as follows:\r
128\r
129 2114 2115 2116 2100 1000-M 1000-E 1000-F\r
130 ------ ------ ------ ------ ------ ------ ------\r
131 N/A 12579A 12579A std std std std\r
132\r
133 The instruction codes are mapped to routines as follows:\r
134\r
135 Instr. Bits\r
136 Code 15-8 7-4 2116 2100 1000-M 1000-E 1000-F Note\r
137 ------ ---- --- ------ ------ ------ ------ ------ ---------------------\r
138 100000 200 00 [diag] [diag] [self test]\r
139 100020 200 01 ASL ASL ASL ASL ASL Bits 3-0 encode shift\r
140 100040 200 02 LSL LSL LSL LSL LSL Bits 3-0 encode shift\r
141 100060 200 03 TIMER TIMER [deterministic delay]\r
142 100100 200 04 RRL RRL RRL RRL RRL Bits 3-0 encode shift\r
143 100200 200 10 MPY MPY MPY MPY MPY\r
144 100400 201 xx DIV DIV DIV DIV DIV\r
145 101020 202 01 ASR ASR ASR ASR ASR Bits 3-0 encode shift\r
146 101040 202 02 LSR LSR LSR LSR LSR Bits 3-0 encode shift\r
147 101100 202 04 RRR RRR RRR RRR RRR Bits 3-0 encode shift\r
148 104200 210 xx DLD DLD DLD DLD DLD\r
149 104400 211 xx DST DST DST DST DST\r
150\r
151 The remaining codes for bits 7-4 are undefined and will cause a simulator\r
152 stop if enabled. On a real 1000-M, all undefined instructions in the 200\r
153 group decode as MPY, and all in the 202 group decode as NOP. On a real\r
154 1000-E, instruction patterns 200/05 through 200/07 and 202/03 decode as NOP;\r
155 all others cause erroneous execution.\r
156\r
157 EAU instruction decoding on the 1000 M-series is convoluted. The JEAU\r
158 microorder maps IR bits 11, 9-7 and 5-4 to bits 2-0 of the microcode jump\r
159 address. The map is detailed on page IC-84 of the ERD.\r
160\r
161 The 1000 E/F-series add two undocumented instructions to the 200 group: TIMER\r
162 and DIAG. These are described in the ERD on page IA 5-5, paragraph 5-7. The\r
163 M-series executes these as MPY and RRL, respectively. A third instruction,\r
164 EXECUTE (100120), is also described but was never implemented, and the\r
165 E/F-series microcode execute a NOP for this instruction code.\r
166\r
167 Notes:\r
168\r
169 1. Under simulation, TIMER, DIAG, and EXECUTE cause undefined instruction\r
170 stops if the CPU is set to 21xx. DIAG and EXECUTE also cause stops on\r
171 the 1000-M. TIMER does not, because it is used by several HP programs\r
172 to differentiate between M- and E/F-series machines.\r
173\r
174 2. DIAG is not implemented under simulation. On the E/F, it performs a\r
175 destructive test of all installed memory. Because of this, it is only\r
176 functional if the machine is halted, i.e., if the instruction is\r
177 executed with the INSTR STEP button. If it is executed in a program,\r
178 the result is NOP.\r
179\r
180 3. RRR is permitted and executed as NOP if the CPU is a 2114, as the\r
181 presence of the EAU is tested by the diagnostic configurator to\r
182 differentiate between 2114 and 2100/1000 CPUs.\r
183*/\r
184\r
185t_stat cpu_eau (uint32 IR, uint32 intrq)\r
186{\r
187t_stat reason = SCPE_OK;\r
188OPS op;\r
189uint32 rs, qs, sc, v1, v2, t;\r
190int32 sop1, sop2;\r
191\r
192if ((cpu_unit.flags & UNIT_EAU) == 0) /* option installed? */\r
193 if ((UNIT_CPU_MODEL == UNIT_2114) && (IR == 0101100)) /* 2114 and RRR 16? */\r
194 return SCPE_OK; /* allowed as NOP */\r
195 else\r
196 return stop_inst; /* fail */\r
197\r
198switch ((IR >> 8) & 0377) { /* decode IR<15:8> */\r
199\r
200 case 0200: /* EAU group 0 */\r
201 switch ((IR >> 4) & 017) { /* decode IR<7:4> */\r
202\r
203 case 000: /* DIAG 100000 */\r
204 if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */\r
205 (UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */\r
206 return stop_inst; /* trap if not */\r
207 break; /* DIAG is NOP unless halted */\r
208\r
209 case 001: /* ASL 100020-100037 */\r
210 sc = (IR & 017)? (IR & 017): 16; /* get sc */\r
211 O = 0; /* clear ovflo */\r
212 while (sc-- != 0) { /* bit by bit */\r
213 t = BR << 1; /* shift B */\r
214 BR = (BR & SIGN) | (t & 077777) | (AR >> 15);\r
215 AR = (AR << 1) & DMASK;\r
216 if ((BR ^ t) & SIGN) O = 1;\r
217 }\r
218 break;\r
219\r
220 case 002: /* LSL 100040-100057 */\r
221 sc = (IR & 017)? (IR & 017): 16; /* get sc */\r
222 BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK;\r
223 AR = (AR << sc) & DMASK; /* BR'AR lsh left */\r
224 break;\r
225\r
226 case 003: /* TIMER 100060 */\r
227 if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */\r
228 return stop_inst; /* trap if not */\r
229 if (UNIT_CPU_MODEL == UNIT_1000_M) /* 1000 M-series? */\r
230 goto MPY; /* decode as MPY */\r
231 BR = (BR + 1) & DMASK; /* increment B */\r
232 if (BR) PC = err_PC; /* if !=0, repeat */\r
233 break;\r
234\r
235 case 004: /* RRL 100100-100117 */\r
236 sc = (IR & 017)? (IR & 017): 16; /* get sc */\r
237 t = BR; /* BR'AR rot left */\r
238 BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK;\r
239 AR = ((AR << sc) | (t >> (16 - sc))) & DMASK;\r
240 break;\r
241\r
242 case 010: /* MPY 100200 (OP_K) */\r
243 MPY:\r
244 if (reason = cpu_ops (OP_K, op, intrq)) /* get operand */\r
245 break;\r
246 sop1 = SEXT (AR); /* sext AR */\r
247 sop2 = SEXT (op[0].word); /* sext mem */\r
248 sop1 = sop1 * sop2; /* signed mpy */\r
249 BR = (sop1 >> 16) & DMASK; /* to BR'AR */\r
250 AR = sop1 & DMASK;\r
251 O = 0; /* no overflow */\r
252 break;\r
253\r
254 default: /* others undefined */\r
255 return stop_inst;\r
256 }\r
257\r
258 break;\r
259\r
260 case 0201: /* DIV 100400 (OP_K) */\r
261 if (reason = cpu_ops (OP_K, op, intrq)) /* get operand */\r
262 break;\r
263 if (rs = qs = BR & SIGN) { /* save divd sign, neg? */\r
264 AR = (~AR + 1) & DMASK; /* make B'A pos */\r
265 BR = (~BR + (AR == 0)) & DMASK; /* make divd pos */\r
266 }\r
267 v2 = op[0].word; /* divr = mem */\r
268 if (v2 & SIGN) { /* neg? */\r
269 v2 = (~v2 + 1) & DMASK; /* make divr pos */\r
270 qs = qs ^ SIGN; /* sign of quotient */\r
271 }\r
272 if (BR >= v2) O = 1; /* divide work? */\r
273 else { /* maybe... */\r
274 O = 0; /* assume ok */\r
275 v1 = (BR << 16) | AR; /* 32b divd */\r
276 AR = (v1 / v2) & DMASK; /* quotient */\r
277 BR = (v1 % v2) & DMASK; /* remainder */\r
278 if (AR) { /* quotient > 0? */\r
279 if (qs) AR = (~AR + 1) & DMASK; /* apply quo sign */\r
280 if ((AR ^ qs) & SIGN) O = 1; /* still wrong? ovflo */\r
281 }\r
282 if (rs) BR = (~BR + 1) & DMASK; /* apply rem sign */\r
283 }\r
284 break;\r
285\r
286 case 0202: /* EAU group 2 */\r
287 switch ((IR >> 4) & 017) { /* decode IR<7:4> */\r
288\r
289 case 001: /* ASR 101020-101037 */\r
290 sc = (IR & 017)? (IR & 017): 16; /* get sc */\r
291 AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK;\r
292 BR = (SEXT (BR) >> sc) & DMASK; /* BR'AR ash right */\r
293 O = 0;\r
294 break;\r
295\r
296 case 002: /* LSR 101040-101057 */\r
297 sc = (IR & 017)? (IR & 017): 16; /* get sc */\r
298 AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK;\r
299 BR = BR >> sc; /* BR'AR log right */\r
300 break;\r
301\r
302 case 004: /* RRR 101100-101117 */\r
303 sc = (IR & 017)? (IR & 017): 16; /* get sc */\r
304 t = AR; /* BR'AR rot right */\r
305 AR = ((AR >> sc) | (BR << (16 - sc))) & DMASK;\r
306 BR = ((BR >> sc) | (t << (16 - sc))) & DMASK;\r
307 break;\r
308\r
309 default: /* others undefined */\r
310 return stop_inst;\r
311 }\r
312\r
313 break;\r
314\r
315 case 0210: /* DLD 104200 (OP_D) */\r
316 if (reason = cpu_ops (OP_D, op, intrq)) /* get operand */\r
317 break;\r
318 AR = (op[0].dword >> 16) & DMASK; /* load AR */\r
319 BR = op[0].dword & DMASK; /* load BR */\r
320 break;\r
321\r
322 case 0211: /* DST 104400 (OP_A) */\r
323 if (reason = cpu_ops (OP_A, op, intrq)) /* get operand */\r
324 break;\r
325 WriteW (op[0].word, AR); /* store AR */\r
326 WriteW ((op[0].word + 1) & VAMASK, BR); /* store BR */\r
327 break;\r
328\r
329 default: /* should never get here */\r
330 return SCPE_IERR; /* bad call from cpu_instr */\r
331 }\r
332\r
333return reason;\r
334}\r
335\r
336/* UIG 0\r
337\r
338 The first User Instruction Group (UIG) encodes firmware options for the 2100\r
339 and 1000. Instruction codes 105000-105377 are assigned to microcode options\r
340 as follows:\r
341\r
342 Instructions Option Name 2100 1000-M 1000-E 1000-F\r
343 ------------- -------------------------- ------ ------ ------ ------\r
344 105000-105362 2000 I/O Processor opt - - -\r
345 105000-105137 Floating Point opt std std std\r
346 105200-105237 Fast FORTRAN Processor opt opt opt std\r
347 105240-105257 RTE-IVA/B Extended Memory - - opt opt\r
348 105240-105257 RTE-6/VM Virtual Memory - - opt opt\r
349 105300-105317 Distributed System - - opt opt\r
350 105320-105337 Double Integer - - opt -\r
351 105320-105337 Scientific Instruction Set - - - std\r
352 105340-105357 RTE-6/VM Operating System - - opt opt\r
353\r
354 Because the 2100 IOP microcode uses the same instruction range as the 2100 FP\r
355 and FFP options, it cannot coexist with them. To simplify simulation, the\r
356 2100 IOP instructions are remapped to the equivalent 1000 instructions and\r
357 dispatched to the UIG 1 module.\r
358\r
359 Note that if the 2100 IOP is installed, the only valid UIG instructions are\r
360 IOP instructions, as the IOP used the full 2100 microcode addressing space.\r
361\r
362 The F-Series moved the three-word extended real instructions from the FFP\r
363 range to the base floating-point range and added four-word double real and\r
364 two-word double integer instructions. The double integer instructions\r
365 occupied some of the vacated extended real instruction codes in the FFP, with\r
366 the rest assigned to the floating-point range. Consequently, many\r
367 instruction codes for the F-Series are different from the E-Series.\r
368\r
369 Notes:\r
370\r
371 1. Product 93585A, available from the "Specials" group, added double\r
372 integer microcode to the E-Series. The instruction codes were different\r
373 from those in the F-Series to avoid conflicting with the E-Series FFP.\r
374 HP manual number 93585-90007 documents the double integer instructions,\r
375 but no copy of this manual has been found. The Macro/1000 manual\r
376 (92059-090001) lists E-Series double integer instructions as occupying\r
377 the code points of the F-Series Scientific Instruction Set.\r
378\r
379 2. To run the double-integer instructions diagnostic in the absence of\r
380 64-bit integer support (and therefore of F-Series simulation), a special\r
381 DBI dispatcher may be enabled by defining ENABLE_DIAG during\r
382 compilation. This dispatcher will remap the F-Series DBI instructions\r
383 to the E-Series codes, so that the F-Series diagnostic may be run.\r
384 Because several of the F-Series DBI instruction codes replace M/E-Series\r
385 FFP codes, this dispatcher will only operate if FFP is disabled.\r
386\r
387 Note that enabling the dispatcher will produce non-standard FP behavior.\r
388 For example, any code in the range 105000-105017 normally would execute\r
389 a FAD instruction. With the dispatcher enabled, 105014 would execute a\r
390 .DAD, while the other codes would execute a FAD. Therefore, ENABLE_DIAG\r
391 should only be used to run the diagnostic and is not intended for\r
392 general use.\r
393*/\r
394\r
395t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap)\r
396{\r
397if ((cpu_unit.flags & UNIT_IOP) && /* I/O Processor? */\r
398 (UNIT_CPU_TYPE == UNIT_TYPE_2100)) /* 2100 CPU? */\r
399 return cpu_iop (IR, intrq); /* dispatch to IOP */\r
400\r
401\r
402#if !defined (HAVE_INT64) && defined (ENABLE_DIAG) /* DBI diagnostic dispatcher wanted */\r
403\r
404if ((cpu_unit.flags & UNIT_FFP) == 0)\r
405 switch (IR & 0377) {\r
406 case 0014: /* .DAD 105014 */\r
407 return cpu_dbi (0105321, intrq);\r
408\r
409 case 0034: /* .DSB 105034 */\r
410 return cpu_dbi (0105327, intrq);\r
411\r
412 case 0054: /* .DMP 105054 */\r
413 return cpu_dbi (0105322, intrq);\r
414\r
415 case 0074: /* .DDI 105074 */\r
416 return cpu_dbi (0105325, intrq);\r
417\r
418 case 0114: /* .DSBR 105114 */\r
419 return cpu_dbi (0105334, intrq);\r
420\r
421 case 0134: /* .DDIR 105134 */\r
422 return cpu_dbi (0105326, intrq);\r
423\r
424 case 0203: /* .DNG 105203 */\r
425 return cpu_dbi (0105323, intrq);\r
426\r
427 case 0204: /* .DCO 105204 */\r
428 return cpu_dbi (0105324, intrq);\r
429\r
430 case 0210: /* .DIN 105210 */\r
431 return cpu_dbi (0105330, intrq);\r
432\r
433 case 0211: /* .DDE 105211 */\r
434 return cpu_dbi (0105331, intrq);\r
435\r
436 case 0212: /* .DIS 105212 */\r
437 return cpu_dbi (0105332, intrq);\r
438\r
439 case 0213: /* .DDS 105213 */\r
440 return cpu_dbi (0105333, intrq);\r
441 } /* otherwise, continue */\r
442\r
443#endif /* end of DBI dispatcher */\r
444\r
445\r
446switch ((IR >> 4) & 017) { /* decode IR<7:4> */\r
447\r
448 case 000: /* 105000-105017 */\r
449 case 001: /* 105020-105037 */\r
450 case 002: /* 105040-105057 */\r
451 case 003: /* 105060-105077 */\r
452 case 004: /* 105100-105117 */\r
453 case 005: /* 105120-105137 */\r
454#if defined (HAVE_INT64) /* int64 support available */\r
455 return cpu_fpp (IR, intrq); /* Floating Point Processor */\r
456#else /* int64 support unavailable */\r
457 return cpu_fp (IR, intrq); /* Firmware Floating Point */\r
458#endif /* end of int64 support */\r
459\r
460 case 010: /* 105200-105217 */\r
461 case 011: /* 105220-105237 */\r
462 return cpu_ffp (IR, intrq); /* Fast FORTRAN Processor */\r
463\r
464 case 012: /* 105240-105257 */\r
465 return cpu_rte_vma (IR, intrq); /* RTE-4/6 EMA/VMA */\r
466\r
467 case 014: /* 105300-105317 */\r
468 return cpu_ds (IR, intrq); /* Distributed System */\r
469\r
470 case 015: /* 105320-105337 */\r
471#if defined (HAVE_INT64) /* int64 support available */\r
472 if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-series? */\r
473 return cpu_sis (IR, intrq); /* Scientific Instruction */\r
474 else /* M/E-series */\r
475#endif /* end of int64 support */\r
476 return cpu_dbi (IR, intrq); /* Double integer */\r
477\r
478 case 016: /* 105340-105357 */\r
479 return cpu_rte_os (IR, intrq, iotrap); /* RTE-6 OS */\r
480 }\r
481\r
482return stop_inst; /* others undefined */\r
483}\r
484\r
485/* UIG 1\r
486\r
487 The second User Instruction Group (UIG) encodes firmware options for the\r
488 1000. Instruction codes 101400-101777 and 105400-105777 are assigned to\r
489 microcode options as follows ("x" is "1" or "5" below):\r
490\r
491 Instructions Option Name 1000-M 1000-E 1000-F\r
492 ------------- ---------------------------- ------ ------ ------\r
493 10x400-10x437 2000 IOP opt opt -\r
494 10x460-10x477 2000 IOP opt opt -\r
495 10x460-10x477 Vector Instruction Set - - opt\r
496 105520-105537 Distributed System opt - -\r
497 105600-105617 SIGNAL/1000 Instruction Set - - opt\r
498 10x700-10x737 Dynamic Mapping System opt opt std\r
499 10x740-10x777 Extended Instruction Group std std std\r
500\r
501 Only 1000 systems execute these instructions.\r
502*/\r
503\r
504t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap)\r
505{\r
506if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* 1000 execution? */\r
507 return stop_inst; /* no, so trap */\r
508\r
509switch ((IR >> 4) & 017) { /* decode IR<7:4> */\r
510\r
511 case 000: /* 105400-105417 */\r
512 case 001: /* 105420-105437 */\r
513 return cpu_iop (IR, intrq); /* 2000 I/O Processor */\r
514\r
515 case 003: /* 105460-105477 */\r
516#if defined (HAVE_INT64) /* int64 support available */\r
517 if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-series? */\r
518 return cpu_vis (IR, intrq); /* Vector Instruction Set */\r
519 else /* M/E-series */\r
520#endif /* end of int64 support */\r
521 return cpu_iop (IR, intrq); /* 2000 I/O Processor */\r
522\r
523 case 005: /* 105520-105537 */\r
524 IR = IR ^ 0000620; /* remap to 105300-105317 */\r
525 return cpu_ds (IR, intrq); /* Distributed System */\r
526\r
527#if defined (HAVE_INT64) /* int64 support available */\r
528 case 010: /* 105600-105617 */\r
529 return cpu_signal (IR, intrq); /* SIGNAL/1000 Instructions */\r
530#endif /* end of int64 support */\r
531\r
532 case 014: /* 105700-105717 */\r
533 case 015: /* 105720-105737 */\r
534 return cpu_dms (IR, intrq); /* Dynamic Mapping System */\r
535\r
536 case 016: /* 105740-105737 */\r
537 case 017: /* 105760-105777 */\r
538 return cpu_eig (IR, intrq); /* Extended Instruction Group */\r
539 }\r
540\r
541return stop_inst; /* others undefined */\r
542}\r
543\r
544\r
545/* Read a multiple-precision operand value. */\r
546\r
547OP ReadOp (uint32 va, OPSIZE precision)\r
548{\r
549OP operand;\r
550uint32 i;\r
551\r
552if (precision == in_s)\r
553 operand.word = ReadW (va); /* read single integer */\r
554\r
555else if (precision == in_d)\r
556 operand.dword = ReadW (va) << 16 | /* read double integer */\r
557 ReadW ((va + 1) & VAMASK); /* merge high and low words */\r
558\r
559else\r
560 for (i = 0; i < (uint32) precision; i++) { /* read fp 2 to 5 words */\r
561 operand.fpk[i] = ReadW (va);\r
562 va = (va + 1) & VAMASK;\r
563 }\r
564return operand;\r
565}\r
566\r
567/* Write a multiple-precision operand value. */\r
568\r
569void WriteOp (uint32 va, OP operand, OPSIZE precision)\r
570{\r
571uint32 i;\r
572\r
573if (precision == in_s)\r
574 WriteW (va, operand.word); /* write single integer */\r
575\r
576else if (precision == in_d) {\r
577 WriteW (va, (operand.dword >> 16) & DMASK); /* write double integer */\r
578 WriteW ((va + 1) & VAMASK, operand.dword & DMASK); /* high word, then low word */\r
579 }\r
580\r
581else\r
582 for (i = 0; i < (uint32) precision; i++) { /* write fp 2 to 5 words */\r
583 WriteW (va, operand.fpk[i]);\r
584 va = (va + 1) & VAMASK;\r
585 }\r
586return;\r
587}\r
588\r
589\r
590/* Get instruction operands.\r
591\r
592 Operands for a given instruction are specifed by an "operand pattern"\r
593 consisting of flags indicating the types and storage methods. The pattern\r
594 directs how each operand is to be retrieved and whether the operand value or\r
595 address is returned in the operand array.\r
596\r
597 Typically, a microcode simulation handler will define an OP_PAT array, with\r
598 each element containing an operand pattern corresponding to the simulated\r
599 instruction. Operand patterns are defined in the header file accompanying\r
600 this source file. After calling this function with the appropriate operand\r
601 pattern and a pointer to an array of OPs, operands are decoded and stored\r
602 sequentially in the array.\r
603\r
604 The following operand encodings are defined:\r
605\r
606 Code Operand Description Example Return\r
607 ------ ---------------------------------------- ----------- ------------\r
608 OP_NUL No operand present [inst] None\r
609\r
610 OP_IAR Integer constant in A register LDA I Value of I\r
611 [inst]\r
612 ...\r
613 I DEC 0\r
614\r
615 OP_DAB Double integer constant in A/B registers DLD J Value of J\r
616 [inst]\r
617 ...\r
618 J DEC 0,0\r
619\r
620 OP_FAB 2-word FP constant in A/B registers DLD F Value of F\r
621 [inst]\r
622 ...\r
623 F DEC 0.0\r
624\r
625 OP_CON Inline 1-word constant [inst] Value of C\r
626 C DEC 0\r
627 ...\r
628\r
629 OP_VAR Inline 1-word variable [inst] Address of V\r
630 V BSS 1\r
631 ...\r
632\r
633 OP_ADR Inline address [inst] Address of A\r
634 DEF A\r
635 ...\r
636 A EQU *\r
637\r
638 OP_ADK Address of integer constant [inst] Value of K\r
639 DEF K\r
640 ...\r
641 K DEC 0\r
642\r
643 OP_ADD Address of double integer constant [inst] Value of D\r
644 DEF D\r
645 ...\r
646 D DEC 0,0\r
647\r
648 OP_ADF Address of 2-word FP constant [inst] Value of F\r
649 DEF F\r
650 ...\r
651 F DEC 0.0\r
652\r
653 OP_ADX Address of 3-word FP constant [inst] Value of X\r
654 DEF X\r
655 ...\r
656 X DEX 0.0\r
657\r
658 OP_ADT Address of 4-word FP constant [inst] Value of T\r
659 DEF T\r
660 ...\r
661 T DEY 0.0\r
662\r
663 OP_ADE Address of 5-word FP constant [inst] Value of E\r
664 DEF E\r
665 ...\r
666 E DEC 0,0,0,0,0\r
667\r
668 Address operands, i.e., those having a DEF to the operand, will be resolved\r
669 to direct addresses. If an interrupt is pending and more than three levels\r
670 of indirection are used, the routine returns without completing operand\r
671 retrieval (the instruction will be retried after interrupt servicing).\r
672 Addresses are always resolved in the current DMS map.\r
673\r
674 An operand pattern consists of one or more operand encodings, corresponding\r
675 to the operands required by a given instruction. Values are returned in\r
676 sequence to the operand array.\r
677*/\r
678\r
679t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq)\r
680{\r
681t_stat reason = SCPE_OK;\r
682OP_PAT flags;\r
683uint32 i, MA;\r
684\r
685for (i = 0; i < OP_N_F; i++) {\r
686 flags = pattern & OP_M_FLAGS; /* get operand pattern */\r
687\r
688 if (flags >= OP_ADR) /* address operand? */\r
689 if (reason = resolve (ReadW (PC), &MA, irq)) /* resolve indirects */\r
690 return reason;\r
691\r
692 switch (flags) {\r
693 case OP_NUL: /* null operand */\r
694 return reason; /* no more, so quit */\r
695\r
696 case OP_IAR: /* int in A */\r
697 (*op++).word = AR; /* get one-word value */\r
698 break;\r
699\r
700 case OP_JAB: /* dbl-int in A/B */\r
701 (*op++).dword = (AR << 16) | BR; /* get two-word value */\r
702 break;\r
703\r
704 case OP_FAB: /* 2-word FP in A/B */\r
705 (*op).fpk[0] = AR; /* get high FP word */\r
706 (*op++).fpk[1] = BR; /* get low FP word */\r
707 break;\r
708\r
709 case OP_CON: /* inline constant operand */\r
710 *op++ = ReadOp (PC, in_s); /* get value */\r
711 break;\r
712\r
713 case OP_VAR: /* inline variable operand */\r
714 (*op++).word = PC; /* get pointer to variable */\r
715 break;\r
716\r
717 case OP_ADR: /* inline address operand */\r
718 (*op++).word = MA; /* get address */\r
719 break;\r
720\r
721 case OP_ADK: /* address of int constant */\r
722 *op++ = ReadOp (MA, in_s); /* get value */\r
723 break;\r
724\r
725 case OP_ADD: /* address of dbl-int constant */\r
726 *op++ = ReadOp (MA, in_d); /* get value */\r
727 break;\r
728\r
729 case OP_ADF: /* address of 2-word FP const */\r
730 *op++ = ReadOp (MA, fp_f); /* get value */\r
731 break;\r
732\r
733 case OP_ADX: /* address of 3-word FP const */\r
734 *op++ = ReadOp (MA, fp_x); /* get value */\r
735 break;\r
736\r
737 case OP_ADT: /* address of 4-word FP const */\r
738 *op++ = ReadOp (MA, fp_t); /* get value */\r
739 break;\r
740\r
741 case OP_ADE: /* address of 5-word FP const */\r
742 *op++ = ReadOp (MA, fp_e); /* get value */\r
743 break;\r
744\r
745 default:\r
746 return SCPE_IERR; /* not implemented */\r
747 }\r
748\r
749 if (flags >= OP_CON) /* operand after instruction? */\r
750 PC = (PC + 1) & VAMASK; /* yes, so bump to next */\r
751 pattern = pattern >> OP_N_FLAGS; /* move next pattern into place */\r
752 }\r
753return reason;\r
754}\r
755\r
756\r
757/* Print operands to the debug device.\r
758\r
759 The values of an operand array are printed to the debug device. The types of\r
760 the operands are specified by an operand pattern. Typically, the operand\r
761 pattern is the same one that was used to fill the array originally.\r
762*/\r
763\r
764void fprint_ops (OP_PAT pattern, OPS op)\r
765{\r
766OP_PAT flags;\r
767uint32 i;\r
768\r
769for (i = 0; i < OP_N_F; i++) {\r
770 flags = pattern & OP_M_FLAGS; /* get operand pattern */\r
771\r
772 switch (flags) {\r
773 case OP_NUL: /* null operand */\r
774 return; /* no more, so quit */\r
775\r
776 case OP_IAR: /* int in A */\r
777 case OP_CON: /* inline constant operand */\r
778 case OP_VAR: /* inline variable operand */\r
779 case OP_ADR: /* inline address operand */\r
780 case OP_ADK: /* address of int constant */\r
781 fprintf (sim_deb,\r
782 ", op[%d] = %06o",\r
783 i, op[i].word);\r
784 break;\r
785\r
786 case OP_JAB: /* dbl-int in A/B */\r
787 case OP_ADD: /* address of dbl-int constant */\r
788 fprintf (sim_deb,\r
789 ", op[%d] = %011o",\r
790 i, op[i].dword);\r
791 break;\r
792\r
793 case OP_FAB: /* 2-word FP in A/B */\r
794 case OP_ADF: /* address of 2-word FP const */\r
795 fprintf (sim_deb,\r
796 ", op[%d] = (%06o, %06o)",\r
797 i, op[i].fpk[0], op[i].fpk[1]);\r
798 break;\r
799\r
800 case OP_ADX: /* address of 3-word FP const */\r
801 fprintf (sim_deb,\r
802 ", op[%d] = (%06o, %06o, %06o)",\r
803 i, op[i].fpk[0], op[i].fpk[1],\r
804 op[i].fpk[2]);\r
805 break;\r
806\r
807 case OP_ADT: /* address of 4-word FP const */\r
808 fprintf (sim_deb,\r
809 ", op[%d] = (%06o, %06o, %06o, %06o)",\r
810 i, op[i].fpk[0], op[i].fpk[1],\r
811 op[i].fpk[2], op[i].fpk[3]);\r
812 break;\r
813\r
814 case OP_ADE: /* address of 5-word FP const */\r
815 fprintf (sim_deb,\r
816 ", op[%d] = (%06o, %06o, %06o, %06o, %06o)",\r
817 i, op[i].fpk[0], op[i].fpk[1],\r
818 op[i].fpk[2], op[i].fpk[3], op[i].fpk[4]);\r
819 break;\r
820\r
821 default:\r
822 fprintf (sim_deb, "UNKNOWN OPERAND TYPE"); /* not implemented */\r
823 }\r
824\r
825 pattern = pattern >> OP_N_FLAGS; /* move next pattern into place */\r
826 }\r
827}\r
828\r
829\r
830/* Print CPU registers to the debug device.\r
831\r
832 One or more CPU registers may be printed to the debug output device, which\r
833 must be valid before calling.\r
834*/\r
835\r
836void fprint_regs (char *caption, uint32 regs, uint32 base)\r
837{\r
838static uint32 ARX, BRX, PRL; /* static so addresses are constant */\r
839\r
840static const char *reg_names[] = { "CIR", "A", "B", "E", "X", "Y", "O", "P", "return" };\r
841static const uint32 *reg_ptrs[] = { &intaddr, &ARX, &BRX, &E, &XR, &YR, &O, &PC, &PRL };\r
842static const char *formats[] = { "%02o", "%06o", "%06o", "%01o", "%06o", "%06o", "%01o", "%06o", "P+%d" };\r
843\r
844static char format[20] = " %s = "; /* base format string */\r
845static const int eos = 6; /* length of base format string */\r
846\r
847uint32 i;\r
848t_bool first = TRUE; /* first-time through flag */\r
849\r
850ARX = AR; /* copy 16-bit value to static variable */\r
851BRX = BR; /* copy 16-bit value to static variable */\r
852PRL = PC - base; /* compute value in static variable */\r
853\r
854for (i = 0; i < REG_COUNT; i++) {\r
855 if (regs & 1) { /* register requested? */\r
856 if (first) /* first time? */\r
857 fputs (caption, sim_deb); /* print caption */\r
858 else\r
859 fputc (',', sim_deb); /* print separator */\r
860\r
861 strcpy (&format[eos], formats[i]); /* copy format specifier */\r
862 fprintf (sim_deb, format, reg_names[i], *reg_ptrs[i]);\r
863\r
864 first = FALSE;\r
865 }\r
866\r
867 regs = regs >> 1; /* align next register flag */\r
868 }\r
869return;\r
870}\r