| 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 |