/* hp2100_cpu.c: HP 21xx/1000 Central Processing Unit simulator Copyright (c) 1993-2016, Robert M. Supnik Copyright (c) 2017-2019, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the names of the authors shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. CPU 2114C/2115A/2116C/2100A/1000-M/E/F Central Processing Unit I/O subsystem Power Fail Recovery System 12-Feb-19 JDB Worked around idle problem (SIMH issue 622) 06-Feb-19 JDB Corrected trace report for simulation stop 05-Feb-19 JDB sim_dname now takes a const pointer 13-Aug-18 JDB Renamed "ion_defer" to "cpu_interrupt_enable" and flipped sense 24-Jul-18 JDB Removed unneeded "iotrap" parameter from "cpu_iog" routine 20-Jul-18 JDB Moved memory/MEM/MP and DMA into separate source files 29-Jun-18 JDB Fixed "clear_option" return type definition 14-Jun-18 JDB Renamed PRO device to MPPE 05-Jun-18 JDB Revised I/O model 21-May-18 JDB Changed "access" to "mem_access" to avoid clashing 07-May-18 JDB Modified "io_dispatch" to display outbound signals 01-May-18 JDB Multiple consecutive CLC 0 operations are now omitted 02-Apr-18 JDB SET CPU 21MX now configures an M-Series model 22-Feb-18 JDB Reworked "cpu_ibl" into "cpu_copy_loader" 11-Aug-17 JDB MEM must be disabled when DMS is disabled 01-Aug-17 JDB Changed SET/SHOW CPU [NO]IDLE to use sim_*_idle routines 22-Jul-17 JDB Renamed "intaddr" to CIR; added IR 18-Jul-17 JDB Added CPU stops 11-Jul-17 JDB Moved "hp_enbdis_pair" to hp2100_sys.c Renamed "ibl_copy" to "cpu_ibl" 10-Jul-17 JDB Renamed the global routine "iogrp" to "cpu_iog" 07-Jul-17 JDB Changed "iotrap" from uint32 to t_bool 26-Jun-17 JDB Moved I/O instruction subopcode constants from hp2100_defs.h 16-May-17 JDB Changed REG_A, REG_B to REG_X 19-Apr-17 JDB SET CPU IDLE now omits idle loop tracing 04-Apr-17 JDB Added "cpu_configuration" for symbolic ex/dep validation Rejected model change no longer changes options 21-Mar-17 JDB IOP is now illegal on the 1000 F-Series 27-Feb-17 JDB Added BBL load for 21xx machines ibl_copy no longer returns a status code 22-Feb-17 JDB Added DMA tracing 21-Feb-17 JDB Added bus tracing to the I/O dispatcher 19-Jan-17 JDB Added CPU tracing Consolidated the memory read and write routines 05-Aug-16 JDB Renamed the P register from "PC" to "PR" 13-May-16 JDB Modified for revised SCP API function parameter types 31-Dec-14 JDB Corrected devdisp data parameters 30-Dec-14 JDB Added S-register parameters to ibl_copy 24-Dec-14 JDB Added casts for explicit downward conversions 18-Mar-13 JDB Removed redundant extern declarations 05-Feb-13 JDB HLT instruction handler now relies on sim_vm_fprint_stopped 09-May-12 JDB Separated assignments from conditional expressions 13-Jan-12 JDB Minor speedup in "is_mapped" Added casts to cpu_mod, dmasio, dmapio, cpu_reset, dma_reset 07-Apr-11 JDB Fixed I/O return status bug for DMA cycles Failed I/O cycles now stop on failing instruction 28-Mar-11 JDB Tidied up signal handling 29-Oct-10 JDB Revised DMA for new multi-card paradigm Consolidated DMA reset routines DMA channels renamed from 0,1 to 1,2 to match documentation 27-Oct-10 JDB Changed I/O instructions, handlers, and DMA for revised signal model Changed I/O dispatch table to use DIB pointers 19-Oct-10 JDB Removed DMA latency counter 13-Oct-10 JDB Fixed DMA requests to enable stealing every cycle Fixed DMA priority for channel 1 over channel 2 Corrected comments for "cpu_set_idle" 30-Sep-08 JDB Breakpoints on interrupt trap cells now work 05-Sep-08 JDB VIS and IOP are now mutually exclusive on 1000-F 11-Aug-08 JDB Removed A/B shadow register variables 07-Aug-08 JDB Moved hp_setdev, hp_showdev to hp2100_sys.c Moved non-existent memory checks to WritePW 05-Aug-08 JDB Fixed mp_dms_jmp to accept lower bound, check write protection 30-Jul-08 JDB Corrected DMS violation register set conditions Refefined ABORT to pass address, moved def to hp2100_cpu.h Combined dms and dms_io routines 29-Jul-08 JDB JSB to 0/1 with W5 out and fence = 0 erroneously causes MP abort 11-Jul-08 JDB Unified I/O slot dispatch by adding DIBs for CPU, MP, and DMA 26-Jun-08 JDB Rewrote device I/O to model backplane signals EDT no longer passes DMA channel 30-Apr-08 JDB Enabled SIGNAL instructions, SIG debug flag 28-Apr-08 JDB Added SET CPU IDLE/NOIDLE, idle detection for DOS/RTE 24-Apr-08 JDB Fixed single stepping through interrupts 20-Apr-08 JDB Enabled EMA and VIS, added EMA, VIS, and SIGNAL debug flags 03-Dec-07 JDB Memory ex/dep and bkpt type default to current map mode 26-Nov-07 JDB Added SET CPU DEBUG and OS/VMA flags, enabled OS/VMA 15-Nov-07 JDB Corrected MP W5 (JSB) jumper action, SET/SHOW reversal, mp_mevff clear on interrupt with I/O instruction in trap cell 04-Nov-07 JDB Removed DBI support from 1000-M (was temporary for RTE-6/VM) 28-Apr-07 RMS Removed clock initialization 02-Mar-07 JDB EDT passes input flag and DMA channel in dat parameter 11-Jan-07 JDB Added 12578A DMA byte packing 28-Dec-06 JDB CLC 0 now sends CRS instead of CLC to devices 26-Dec-06 JDB Fixed improper IRQ deferral for 21xx CPUs Fixed improper interrupt servicing in resolve 21-Dec-06 JDB Added 21xx loader enable/disable support 16-Dec-06 JDB Added 2114 and 2115 CPU options. Added support for 12607B (2114) and 12578A (2115/6) DMA 01-Dec-06 JDB Added 1000-F CPU option (requires HAVE_INT64) SHOW CPU displays 1000-M/E instead of 21MX-M/E 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c 12-Oct-06 JDB Fixed INDMAX off-by-one error in resolve 26-Sep-06 JDB Added iotrap parameter to UIG dispatchers for RTE microcode 12-Sep-06 JDB iogrp returns NOTE_IOG to recalc interrupts resolve returns NOTE_INDINT to service held-off interrupt 16-Aug-06 JDB Added support for future microcode options, future F-Series 09-Aug-06 JDB Added double integer microcode, 1000-M/E synonyms Enhanced CPU option validity checking Added DCPC as a synonym for DMA for 21MX simulations 26-Dec-05 JDB Improved reporting in dev_conflict 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 21-Jan-05 JDB Reorganized CPU option flags 15-Jan-05 RMS Split out EAU and MAC instructions 26-Dec-04 RMS DMA reset doesn't clear alternate CTL flop (from Dave Bryan) DMA reset shouldn't clear control words (from Dave Bryan) Alternate CTL flop not visible as register (from Dave Bryan) Fixed CBS, SBS, TBS to perform virtual reads Separated A/B from M[0/1] for DMA IO (from Dave Bryan) Fixed bug in JPY (from Dave Bryan) 25-Dec-04 JDB Added SET CPU 21MX-M, 21MX-E (21MX defaults to MX-E) TIMER/EXECUTE/DIAG instructions disabled for 21MX-M T-register reflects changes in M-register when halted 25-Sep-04 JDB Moved MP into its own device; added MP option jumpers Modified DMA to allow disabling Modified SET CPU 2100/2116 to truncate memory > 32K Added -F switch to SET CPU to force memory truncation Fixed S-register behavior on 2116 Fixed LIx/MIx behavior for DMA on 2116 and 2100 Fixed LIx/MIx behavior for empty I/O card slots Modified WRU to be REG_HRO Added BRK and DEL to save console settings Fixed use of "unsigned int16" in cpu_reset Modified memory size routine to return SCPE_INCOMP if memory size truncation declined 20-Jul-04 RMS Fixed bug in breakpoint test (reported by Dave Bryan) Back up PC on instruction errors (from Dave Bryan) 14-May-04 RMS Fixed bugs and added features from Dave Bryan - SBT increments B after store - DMS console map must check dms_enb - SFS x,C and SFC x,C work - MP violation clears automatically on interrupt - SFS/SFC 5 is not gated by protection enabled - DMS enable does not disable mem prot checks - DMS status inconsistent at simulator halt - Examine/deposit are checking wrong addresses - Physical addresses are 20b not 15b - Revised DMS to use memory rather than internal format - Added instruction printout to HALT message - Added M and T internal registers - Added N, S, and U breakpoints Revised IBL facility to conform to microcode Added DMA EDT I/O pseudo-opcode Separated DMA SRQ (service request) from FLG 12-Mar-03 RMS Added logical name support 02-Feb-03 RMS Fixed last cycle bug in DMA output (found by Mike Gemeny) 22-Nov-02 RMS Added 21MX IOP support 24-Oct-02 RMS Fixed bugs in IOP and extended instructions Fixed bugs in memory protection and DMS Added clock calibration 25-Sep-02 RMS Fixed bug in DMS decode (found by Robert Alan Byer) 26-Jul-02 RMS Restructured extended instructions, added IOP support 22-Mar-02 RMS Changed to allocate memory array dynamically 11-Mar-02 RMS Cleaned up setjmp/auto variable interaction 17-Feb-02 RMS Added DMS support Fixed bugs in extended instructions 03-Feb-02 RMS Added terminal multiplexor support Changed PCQ macro to use unmodified PC Fixed flop restore logic (found by Bill McDermith) Fixed SZx,SLx,RSS bug (found by Bill McDermith) Added floating point support 16-Jan-02 RMS Added additional device support 07-Jan-02 RMS Fixed DMA register tables (found by Bill McDermith) 07-Dec-01 RMS Revised to use breakpoint package 03-Dec-01 RMS Added extended SET/SHOW support 10-Aug-01 RMS Removed register in declarations 26-Nov-00 RMS Fixed bug in dual device number routine 21-Nov-00 RMS Fixed bug in reset routine 15-Oct-00 RMS Added dynamic device number support References: - 2100A Computer Reference Manual (02100-90001, December 1971) - Model 2100A Computer Installation and Maintenance Manual (02100-90002, August 1972) - HP 1000 M/E/F-Series Computers Technical Reference Handbook (5955-0282, March 1980) - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation (92851-90001, March 1981) - HP 1000 Computer Real-Time Systems (5091-4479, August 1992) Hewlett-Packard sold the HP 21xx/1000 family of real-time computers from 1966 through 2000. There are three major divisions within this family: the 21xx core-memory machines, the 1000 (originally 21MX) M/E/F-Series semiconductor- memory machines, and the 1000 L/A-Series machines. All machines are 16-bit accumulator-oriented CISC machines running the same base instruction set. A wide range of operating systems run on these machines, from a simple 4K word paper-tape-based monitor to a megaword multi-user, multiprogramming disc- based system and a multi-user time-shared BASIC system. This implementation is a simulator for the 2114, 2115, 2116, 2100, and 1000 M/E/F-Series machines. A large variety of CPU options, device interface cards, and peripherals are provided. High-speed I/O transfers are performed by Direct Memory Access and Dual-Channel Port Controller options. This simulator does not model the 1000 L/A-Series machines. All of the machines support a 15-bit logical address space, addressing a maximum of 32K words, divided into 1K-word pages. Memory-referencing instructions in the base set can directly address the 1024 words of the base page (page 0) or the 1024 words of the current page (the page containing the instruction). The instructions in the extended set directly address the 32768 words in the full logical address space. The A and B accumulators may be addressed as logical memory addresses 0 and 1, respectively. Peripheral devices are connected to the CPU by interface cards installed in the I/O card cages present in the CPU and optional I/O extender chassis. Each slot in the card cage is assigned an address, called a select code, that may be referenced by I/O instructions in the base set. Select codes range from 0 to 77 octal, with the first eight select codes reserved for the system, providing connections for 56 possible interfaces. The 211x machines use a hardwired processor providing 70 basic instructions and up to 32K of core memory. The base instruction set is divided into the Memory Reference Group, the Shift-Rotate Group, the Alter-Skip Group, and the I/O Group. SRG instruction words may contain from one to four suboperation codes that are executed from left-to-right, and ASG instruction words may contain from one to eight suboperations. An optional Extended Arithmetic Unit may be added to the 2115 and 2116 that provides hardware multiply and divide, double-load and -store, and double-word shift and rotate instructions. The 2100 machine uses a microprogrammed processor that provides the 80 instructions of the base set and the EAU as standard equipment. Optional floating-point microcode adds six two-word (single-precision) instructions. User microprogramming is also supported. When used as part of an HP 2000 Time-Shared BASIC system, the CPU designated as the I/O processor may be equipped with microcode implementing 18 additional OS accelerator instructions. The 1000 M/E-Series machines also use microprogrammed processors and extend the 2100 instruction set with two new index registers, X and Y, and a new Extended Instruction Group consisting of 32 index-register instructions and 10 word-and-byte-manipulation instructions. The six 2100 floating-point instructions are also standard. The 1000 F-Series adds a hardware floating-point processor with 18 new triple- and quad-word instructions. A number of optional microcode extensions are available with the M/E/F-Series. 1000 CPUs offer the optional Dynamic Mapping System, which provides memory mapping on a page-by-page basis. The 5-bit page number of a logical memory address selects one of 32 ten-bit map registers containing physical page numbers. The ten-bit page number combined with the ten-bit page offset yields a 20-bit physical address capable of accessing a location in a one-megaword memory. DMS provides separate maps for system and user programs, as well as for the two DCPC channels, and includes microcode that implements the 38 Dynamic Mapping Instructions used to manipulate the mapping system. Optional memory protection is accomplished by dividing the logical address space into protected and unprotected parts. When protection is enabled, any attempt to write or jump below the fence separating the two parts is inhibited, and an interrupt to the operating system occurs, which aborts the offending user program. If the DMS option is enabled as well, protection is enhanced by specifying read and write permissions on a page-by-page basis. A note on terminology: the 1000 series of computers was originally called the 21MX at introduction. The 21MX (occasionally, 21MXM) corresponds to the 1000 M-Series, and the 21MXE (occasionally, 21XE) corresponds to the 1000 E-Series. The model numbers were changed before the introduction of the 1000 F-Series, although some internal HP documentation refers to this machine as the 21MXF. The terms MEM (Memory Expansion Module), MEU (Memory Expansion Unit), DMI (Dynamic Mapping Instructions), and DMS (Dynamic Mapping System) are used somewhat interchangeably to refer to the logical-to-physical memory address translation option provided on the 1000-Series. DMS consists of the MEM card (12731A) and the DMI firmware (13307A). However, MEM and MEU have been used interchangeably to refer to the mapping card, as have DMI and DMS to refer to the firmware instructions. These CPU hardware registers are present in all machines: Name Width Description ---- ----- ---------------------------------------------- A 16 Accumulator (addressable as memory location 0) B 16 Accumulator (addressable as memory location 1) P 15 Program counter S 16 Switch and display register M 15 Memory address register T 16 Memory data register E 1 Extend flag (arithmetic carry out) O 1 Overflow flag (arithmetic overflow) In addition, there are two internal registers that are not visible to the programmer but are used by the hardware: Name Width Description ---- ----- ---------------------------------------------- IR 16 Instruction register CIR 6 Central interrupt register The Instruction Register holds the current instruction, while the Central Interrupt Register holds the select code identifying an interrupting device. The 1000 Series adds these CPU hardware registers: Name Width Description ---- ----- ---------------------------------------------- X 16 index register Y 16 index register The data types supported by the base instruction set are: - 8-bit unsigned byte - 16-bit unsigned integer - 16-bit two's-complement integer - 32-bit two's-complement integer - 32-bit two's-complement floating point Multi-word values are stored in memory with the most-significant words in the lowest addresses. Bytes are stored in memory with the most-significant byte in the upper half of the 16-bit word and the least-significant byte in the lower half. The instruction set is fairly irregular -- a legacy of its original implementation in hardware in the 2116 and the accretion of microprogrammed instructions in the 2100 and 1000 CPUs. Initially, there were five base-set instruction groups: 1. Memory-Reference Group (MRG) 2. Shift-Rotate Group (SRG) 3. Alter-Skip Group (ASG) 4. I/O Group (IOG) 5. Macroinstruction Group (MAC) All of the instructions added after the 2116 are in the Macroinstruction Group. The 2116 offers two hardware options that extended the instruction set. The first is the 12579A Extended Arithmetic Unit. The second is the 2152A Floating Point Processor, which is interfaced through, and therefore requires, the EAU. The EAU adds 10 instructions including integer multiply and divide and double-word loads, stores, shifts, and rotates. The FPP adds 30 floating-point arithmetic, trigonometric, logarithmic, and exponential instructions. The 2116 EAU is compatible with the 2100 and 1000 EAU implementations and is provided by the simulator. The 2116 FPP is unique to that machine and is not simulated. The base set groups are decoded from bits 15-12 and 10, as follows: 15 14-12 10 Group Address Ranges -- ----- -- ----- ------------------------------- x nnn x MRG 010000-077777 and 110000-177777 0 000 0 SRG 000000-001777 and 004000-005777 0 000 1 ASG 002000-003777 and 006000-007777 1 000 1 IOG 102000-103777 and 106000-107777 1 000 0 MAC 100000-101777 and 104000-105777 Where: x = don't care n = any combination other than all zeros The MAC group is subdivided into the Extended Arithmetic Group (EAG) and the User Instruction Group (UIG), based on bits 11, 9, and 8, as follows: 11 9 8 Group Address Range -- -- -- ----- ------------- 0 0 0 EAG 100000-100377 0 0 1 EAG 100400-100777 0 1 0 EAG 101000-101377 0 1 1 UIG-1 101400-101777 1 0 0 EAG 104000-104377 1 0 1 EAG 104400-104777 1 1 0 UIG-0 105000-105377 1 1 1 UIG-1 105400-105777 All of the 2116 FPP instructions are in the UIG sets: 3 use 10144x opcodes and the rest use 1050xx and 1054xx opcodes. The 2100 decodes only UIG-0 instructions, whereas the 1000s use both UIG sets. In particular, the 105740-105777 range is used by the 1000 Extended Instruction Group (EIG), which is part of the 1000-Series base set. The 21xx and 1000 M/E/F-Series machines do not trap unimplemented instructions. In general, unimplemented EAG instructions cause erroneous execution, and unimplemented UIG instructions execute as NOP. However, there are machine-to-machine variations, and some unimplemented instructions execute as other, defined instructions. The Memory-Reference Group instructions are encoded as follows: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | I | mem op | P | memory address | MRG +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | I | mem op | R | P | memory address | MRG +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Where: I = direct/indirect (0/1) R = A/B register (0/1) P = base/current page (0/1) The "mem ops" are encoded as follows: 14-11 Mnemonic Action ----- -------- --------------------------------------------- 0010 AND A = A & M [MA] 0011 JSB M [MA] = P, P = MA + 1 0100 XOR A = A ^ M [MA] 0101 JMP P = MA 0110 IOR A = A | M [MA] 0111 ISZ M [MA] = M [MA] + 1, P = P + 2 if M [MA] == 0 1000 ADA A = A + M [MA] 1001 ADB B = B + M [MA] 1010 CPA P = P + 2 if A != M [MA] 1011 CPB P = P + 2 if B != M [MA] 1100 LDA A = M [MA] 1101 LDB B = M [MA] 1110 STA M [MA] = A 1111 STB M [MA] = B Bits 15 and 10 encode the type of access, as follows: 15 10 Access Type Action --- --- --------------------- ----------------------------- 0 0 base page direct MA = IR <9:0> 0 1 current page direct MA = P <14:10> | IR <9:0> 1 0 base page indirect MA = M [IR <9:0>] 1 1 current page indirect MA = M [P <14:10> | IR <9:0>] The Shift-Rotate Group instructions are encoded as follows: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 0 | 0 0 0 | R | 0 | E | op 1 | C | E | S | op 2 | SRG +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Where: R = A/B register (0/1) E = disable/enable op C = CLE S = SL* Bits 8-6 and 2-0 each encode one of eight operations, as follows: Op N Operation ---- --------------------------- 000 Arithmetic left shift 001 Arithmetic right shift 010 Rotate left 011 Rotate right 100 Shift left and clear sign 101 Rotate right through Extend 110 Rotate left through Extend 111 Rotate left four bits The Alter-Skip Group instructions are encoded as follows: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 0 | 0 0 0 | R | 1 | r op | e op | E | S | L | I | Z | V | ASG +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Where: R = A/B register (0/1) E = SEZ S = SS* L = SL* I = IN* Z = SZ* V = RSS Bits 9-8 and 7-6 each encode one of three operations, as follows: 9-8 Operation --- ------------------------ 01 Clear A/B 10 Complement A/B 11 Clear and complement A/B 7-6 Operation --- --------------------------- 01 Clear Extend 10 Complement Extend 11 Clear and complement Extend The Input-Output Group instructions are encoded as follows: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 1 | 0 0 0 | R | 1 | H | I/O op | select code | IOG +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Where: R = A/B register (0/1) H = hold/clear flag (0/1) There are ten instructions. Six are encoded directly by bits 8-6, with bits 11 and 9 assuming the definitions above. The other four are encoded with bits 11 and 9 differentiating, as follows: 11 9 8-6 Operation --- --- --- --------------------------- x H 000 Halt x 0 001 Set the flag flip-flop x 1 001 Clear the flag flip-flop x H 010 Skip if the flag is clear x H 011 Skip if the flag is set R H 100 Merge input data into A/B R H 101 Load input data into A/B R H 110 Store output data from A/B 0 H 111 Set the control flip-flop 1 H 111 Clear the control flip-flop An I/O group instruction controls the device specified by the select code. Depending on the opcode, the instruction may set or clear the device flag, start or stop I/O, or read or write data. The Macroinstruction Group instructions are encoded with bits 15-12 and 10 as 1 000 0. Bits 11 and 9-0 determine the specific EAU or UIG instruction. The Extended Arithmetic Group instructions are encoded as follows: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 1 | 0 0 0 | op| 0 | operation | 0 0 0 0 0 0 | EAG +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Operations: 11 9-6 Operation --- ---- ----------------------------------------------------- 0 0010 Multiply 16 x 16 = 32-bit product 0 0100 Divide 32 / 16 = 16-bit quotient and 16-bit remainder 1 0010 Double load A and B registers from memory 1 0100 Double store A and B registers to memory All other encodings are undefined. +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 1 | 0 0 0 | 0 | 0 | shift/rotate op | shift count | EAG +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Operations: 9-4 Operation ------ -------------------------------------------------- 100001 Arithmetic shift right A and B registers 1-16 bits 000001 Arithmetic shift left A and B registers 1-16 bits 100010 Logical shift right A and B registers 1-16 bits 000010 Logical shift left A and B registers 1-16 bits 100100 Rotate right A and B registers 1-16 bits 000100 Rotate left A and B registers 1-16 bits The shift count encodes the number of bits shifted, with a count of zero representing a shift of 16 bits. The User Instruction Group instructions are encoded as follows: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 1 | 0 0 0 | R | 0 1 | module | operation | UIG +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Where: R = A/B register (0/1) Bits 8-4 encode the microcode module containing the instructions, and bits 3-0 encode the specific instructions. See the individual UIG instruction simulator source files for the specific encodings used. I/O device interfaces and their connected devices are simulated by substituting software states for I/O backplane signals. The set of signals generated by I/O instructions and DMA cycles is dispatched to the target interface simulator for action, and the set of signals asserted or denied in response is returned from the call. Backplane signals are processed sequentially. For example, the "STC sc,C" instruction generates the "set control" and the "clear flag" signals that are processed in that order. The HP 21xx/1000 interrupt structure is based on the PRH, PRL, IEN, IRQ, and IAK signals. PRH indicates that no higher-priority device is interrupting. PRL indicates to lower-priority devices that a given device is not interrupting. IEN asserts when the interrupt system is enabled. IRQ indicates that a given device is requesting an interrupt. IAK indicates that the given device's interrupt request is being acknowledged. Typical I/O interfaces have a flag buffer, a flag, and a control flip-flop. If an interface's flag buffer, flag, and control flip-flops are all set, the interrupt system is enabled, and the interface has the highest priority on the interrupt chain, it requests an interrupt by asserting the IRQ signal. When the interrupt is acknowledged with the IAK signal, the flag buffer is cleared, preventing further interrupt requests from that interface. The combination of flag set and control set blocks interrupts from lower priority devices. Service requests are used to trigger the DMA service logic. Setting the interface flag flip-flop typically asserts SRQ, although SRQ may be calculated independently. Most of the I/O signals are generated by execution of IOG instructions or DMA cycles; the target interface simulator is called explicitly to respond to the signal assertions. However, two hardware signals (ENF and SIR) are periodic, and a direct simulation would call each interface simulator with these signals after each machine instruction. Instead, the interface simulator is called only when these signals would have an effect on the state of the interface. Also, two signals (IEN and PRH) are combinatorial, in that changing either potentially affects all interfaces in the system. These are handled efficiently by saving the states of each interface in bit vectors, as described below. PRH and PRL form a hardware priority chain that extends from interface to interface on the backplane. For an interface to generate an interrupt, PRH must be asserted by the next-higher-priority interface. When an interface generates an interrupt, it denies PRL to the next-lower-priority interface. When an interface is not interrupting, it passes PRH to PRL unaltered. This means that a given interface can interrupt only if all higher-priority devices are receiving PRH asserted and are asserting PRL. It also means that clearing the interrupt on a given interface, i.e., reasserting PRL, may affect all lower-priority interfaces. As an example, assume that the interface at select code 10 ("SC 10") has its flag buffer, flag, and control flip-flops set, that IEN and PRH are asserted, and that no other interfaces have their flag flip-flops set. SC 10 will assert IRQ and deny PRL. SC 11 sees its PRH low (because PRL 10 is connected to PRH 11) and so denies PRL, and this action ripples through all of the lower-priority interfaces. Then, while the interrupt for SC 10 is being serviced, the interface at select code 17 sets its flag buffer, flag, and control flip-flops. SC 17 is inhibited from interrupting by PRH denied. When the interrupt service routine clears the interrupt by clearing the flag buffer and flag flip-flops, SC 10 reasserts PRL to SC 11, and that signal ripples through the interfaces at select codes 12-16, arriving at SC 17 as PRH assertion. With PRH asserted, SC 17 generates an interrupt and denies PRL to SC 20 and above. A direct simulation of this hardware behavior would require calling all lower-priority interface simulators in ascending select code (and therefore priority) order with the PRH signal and checking for an asserted IRQ signal or a denied PRL signal. This is inefficient. To avoid making a potentially long sequence of calls, each interface simulator returns a "conditional IRQ" signal and a "conditional PRL" signal in addition to the standard IRQ and PRL signals. The conditional signals are those that would result if the higher-priority interface is asserting PRH and the interrupt system is on. So, for instance, an interface simulator with its flag buffer, flag, and control flip-flops set will assert its conditional IRQ signal and deny its conditional PRL signal. If PRH and IEN are asserted, then its "real" IRQ and PRL signals are also asserted and denied respectively. For fast assertion checking, the conditional IRQ and PRL signal states are kept in bit vectors, which are updated after each interface simulator call. Each vector is represented as a two-element array of 32-bit unsigned integers, forming a 64-bit vector in which bits 0-31 of the first element correspond to select codes 00-37 octal, and bits 0-31 of the second element correspond to select codes 40-77 octal. The "interrupt_request_set" array holds conditional IRQ states, and the "priority_holdoff_set" array holds the complement of the conditional PRL states (the complement is used to simplify the priority calculation). These vectors permit rapid determination of an interrupting interface when a higher-priority interface reasserts PRL or when the interrupt system is reenabled. The simulator provides three stop conditions related to instruction execution that may be enabled with a SET CPU STOP= command: Action ------ ------------------------------------------ UNIMPL stop on an unimplemented instruction UNDEF stop on an undefined instruction UNSC stop on an access to an unused select code IOERR stop on an unreported I/O error If an enabled stop condition is detected, execution ceases with the instruction pending, and control returns to the SCP prompt. When simulation stops, execution may be resumed in two ways. If the cause of the stop has not been remedied and the stop has not been disabled, resuming execution with CONTINUE, STEP, GO, or RUN will cause the stop to occur again. Alternately, specifying the "-B" switch with any of the preceding commands will resume execution while bypassing the stop for the current instruction. The UNIMPL option stops the simulator if execution is attempted of an instruction provided by a firmware option that is not currently installed (e.g., a DAD instruction when the double-integer firmware is not installed) or of an opcode provided by an installed option but not assigned to an instruction (e.g., opcode 105335 from the double-integer firmware). Bypassing the stop will execute the instruction as a NOP (no-operation). The UNDEF option stops the simulator if execution is attempted of an instruction containing a decoded reserved bit pattern other than that defined in the Operating and Reference manual for the CPU. For example, opcodes 101700 and 105700 are not listed as DMS instructions, but they execute as XMM instructions, rather than as NOP. The intent of this stop is to catch instructions containing reserved fields with values that change the meaning of those instructions. Bypassing the stop will decode and execute the instruction in the same manner as the selected CPU. The UNSC option stops the simulator if an I/O instruction addresses a select code that is not assigned to an enabled device (equivalent to an empty hardware I/O backplane slot). Bypassing the stop will read the floating S-bus or I/O-bus for LIA/B and MIA/B instructions or do nothing for all other instructions. The IOERR option stops the simulator if an I/O error condition exists for a device that does not report this status to the CPU. For example, the paper tape reader device (PTR) does not report "no tape loaded" status, and the processor interconnect device (IPL) does not report "cable disconnected." In both cases, I/O to the device will simply hang with no indication of the problem. Enabling the IOERR option will stop the simulator with an error indication for these devices. In addition, a simulation stop will occur if an indirect addressing chain exceeds the maximum length specified by a SET CPU INDIR= command. Memory addresses may be indirect to indicate that the values point to the target addresses rather than contain the target addresses. The target of an indirect address may itself be indirect, and the CPU follows this chain of addresses until it finds a direct address. Indirect addressing is typically only one or two levels deep, but if the chain loops back on itself (e.g., if an indirect address points at itself), then instruction execution will hang. The limit may be set to any number of levels up to 32,768. This is the absolute maximum number of levels that can be created without an infinite loop -- each location in memory points to the next one except for the last, which contains the target value. In practice, anything over a few levels likely represents a programming error. The default setting is 16 levels. The CPU simulator provides extensive tracing capabilities that may be enabled with the SET DEBUG and SET CPU DEBUG= commands. The trace options that may be specified are: Trace Action ----- ------------------------------------------- INSTR trace instructions executed DATA trace memory data accesses FETCH trace memory instruction fetches REG trace registers OPND trace instruction operands EXEC trace matching instruction execution states A section of an example trace is: >>CPU instr: S 0002 05735 103101 CLO >>CPU fetch: S 0002 05736 000036 instruction fetch >>CPU reg: - **** 01011 042200 A 177777, B 000000, X 177777, Y 000000, e o i >>CPU instr: S 0002 05736 000036 SLA,ELA >>CPU fetch: S 0002 05737 102101 instruction fetch >>CPU reg: - **** 01011 042200 A 177776, B 000000, X 177777, Y 000000, E o i >>CPU instr: S 0002 05737 102101 STO >>CPU fetch: S 0002 05740 002400 instruction fetch >>CPU reg: - **** 01011 042200 A 177776, B 000000, X 177777, Y 000000, E O i >>CPU instr: S 0002 05755 102100 STF 0 >>CPU fetch: S 0002 05756 102705 instruction fetch >>CPU reg: - **** 01011 042200 A 177777, B 177777, X 177777, Y 000000, E O I >>CPU instr: S 0002 05756 102705 STC 5 >>CPU fetch: S 0002 05757 105736 instruction fetch >>CPU reg: P **** 01011 042200 A 177777, B 177777, X 177777, Y 000000, E O I >>CPU instr: S 0002 05757 105736 UJP 2111 >>CPU fetch: S 0002 05760 002111 instruction fetch >>CPU fetch: U 0001 02111 026111 instruction fetch >>CPU reg: P **** 01011 042200 A 177777, B 177777, X 177777, Y 000000, E O I >>CPU instr: U 0001 02111 026111 JMP 2111 >>CPU instr: U 0001 02111 000011 interrupt >>CPU fetch: S 0000 00011 115013 instruction fetch >>CPU reg: - **** 01011 042200 A 177777, B 177777, X 177777, Y 000000, E O I >>CPU reg: - **** ***** ****** MPF 000000, MPV 002111, MES 163011, MEV 030000 >>CPU instr: S 0000 00011 115013 JSB 1013,I >>CPU data: S 0000 01013 005557 data read >>CPU data: S 0002 05557 002111 data write >>CPU fetch: S 0002 05560 103100 instruction fetch >>CPU reg: - **** 01011 042200 A 177777, B 177777, X 177777, Y 000000, E O I >>CPU instr: S 0002 05560 103100 CLF 0 >>CPU fetch: S 0002 05561 105714 instruction fetch >>CPU reg: - **** 01011 042200 A 177777, B 177777, X 177777, Y 000000, E O i >>CPU exec: ******************** >>CPU reg: P **** 01567 000000 A 100036, B 000100, X 000100, Y 074000, E o I >>CPU instr: U 0220 07063 105240 .PMAP >>CPU data: U 0000 01776 000227 unprotected read >>CPU data: U 0227 76100 000233 data read >>CPU opnd: * **** 07065 105240 return location is P+2 (no error) >>CPU fetch: U 0220 07065 127055 instruction fetch >>CPU reg: P **** 01567 000000 A 100037, B 000101, X 000100, Y 074000, e o I The INSTR option traces instruction executions and interrupts. Each instruction is printed in symbolic form before it is executed. The DATA option traces reads from and writes to memory. Each access is classified by its usage type as "data" (using the current or alternate map with access protection) or "unprotected" (using a specified map without protection). The FETCH option traces instruction fetches from memory. Reads of the additional words in a multiword instruction, such as the target address of a DLD (double load) instruction, are also classified as fetches. The REG option traces register values. Two sets of registers are printed. After executing each instruction, the working registers (A, B, E, O, S, and, for 1000 CPUs, X and Y) and the state of the interrupt system (on or off) are printed. After executing an instruction that may alter the Memory Protect or Memory Expansion Module state, the MP fence and violation registers, the MEM status and violation registers, and the current protection state are printed. The OPND option traces operand values. Some instructions that take memory and register operands that are difficult to decode from DATA or REG traces present the operand values in a higher-level format. The operand data and value presented are specific to the instruction; see the instruction executor comments for details. The EXEC option traces the execution of instructions that match user-specified criteria. When a match occurs, all CPU trace options are turned on for the duration of the execution of the matched instruction. The prior trace settings are restored when a match fails. This option allows detailed tracing of specified instructions while minimizing the log file size compared to a full instruction trace. The various trace formats are interpreted as follows: >>CPU instr: U 0045 10341 016200 LDA 11200 ~ ~~~~ ~~~~~ ~~~~~~ ~~~~~~~~~ | | | | | | | | | +-- instruction mnemonic | | | +---------- octal data (instruction opcode) | | +------------------ octal logical address (P register) | +----------------------- octal physical page number +--------------------------- memory map (S/U/- system/user/disabled) >>CPU instr: U 0045 10341 000011 interrupt ~ ~~~~ ~~~~~ ~~~~~~ ~~~~~~~~~ | | | | | | | | | +-- interrupt classification | | | +---------- octal device number (CIR register) | | +------------------ octal logical address at interrupt (P register) | +----------------------- octal physical page number at interrupt +--------------------------- memory map (S/U/- system/user/disabled) >>CPU fetch: - 0000 10341 016200 instruction fetch >>CPU data: U 0013 01200 123003 data read >>CPU data: S 0013 01200 017200 unprotected write ~ ~~~~ ~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~ | | | | | | | | | +-- memory access classification | | | +------------ octal data (memory contents) | | +-------------------- octal logical address (effective address) | +------------------------- octal physical page number +----------------------------- memory map (S/U/A/B/- system/user/port A/port B/disabled) >>CPU reg: P **** 01535 040013 A 123003, B 001340, X 000000, Y 000000, e O I ~ ~~~~ ~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | | | +-- A, B, X, Y, E, O, interrupt system registers | | | | (lower/upper case = 0/1 or off/on) | | | +------------ S register | | +-------------------- MEM fence | +------------------------- (place holder) +----------------------------- protection state (P/- protected/unprotected) >>CPU reg: P **** ***** ****** MPF 00000, MPV 000000, MES 000000, MEV 000000 ~ ~~~~ ~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | | | +-- memory protect fence and violation registers | | | | memory expansion status and violation registers | | | +------------ (place holder) | | +-------------------- (place holder) | +------------------------- (place holder) +----------------------------- protection state (P/- protected/unprotected) >>CPU opnd: . **** 36002 101475 return location is P+3 (error EM21) >>CPU opnd: . **** 22067 105355 entry is for a dynamic mapping violation ~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | +-- operand-specific value | +------------ operand-specific octal data +-------------------- octal logical address (P register) Implementation notes: 1. The simulator is fast enough, compared to the run-time of the longest instructions, for interruptibility not to matter. However, the HP diagnostics explicitly test interruptibility in the EIS and DMS instructions and in long indirect address chains. Accordingly, the simulator does "just enough" to pass these tests. In particular, if an interrupt is pending but deferred at the beginning of an interruptible instruction, the interrupt is taken at the appropriate point; but there is no testing for new interrupts during execution (that is, the event timer is not called). 2. The Power Fail option is not currently implemented. 3. Idling with 4.x simulator framework versions after June 14, 2018 (git commit ID d3986466) loses TBG ticks. This causes the DOS/RTE/TSB system clock to run slowly, losing about one second per minute. A workaround is to prevent "sim_interval" from going negative on return from "sim_idle". Issue 622 on the SIMH site describes the problem. */ #include #include "hp2100_defs.h" #include "hp2100_cpu.h" #include "hp2100_cpu_dmm.h" /* Lost time workaround */ #if (SIM_MAJOR >= 4) #define sim_idle(timer,decrement) \ if (sim_idle (timer, decrement) == TRUE /* [workaround] idle the simulator; if idling occurred */ \ && sim_interval < 0) /* [workaround] and the time interval is negative */ \ sim_interval = 0 /* [workaround] then reset it to zero */ #endif /* CPU program constants */ /* Alter-Skip Group instruction register fields */ #define IR_CMx 0001000u /* CMA/B */ #define IR_CLx 0000400u /* CLA/B */ #define IR_CME 0000200u /* CME */ #define IR_CLE 0000100u /* CLE */ #define IR_SEZ 0000040u /* SEZ */ #define IR_SSx 0000020u /* SSA/B */ #define IR_SLx 0000010u /* SLA/B */ #define IR_INx 0000004u /* INA/B */ #define IR_SZx 0000002u /* SZA/B */ #define IR_RSS 0000001u /* RSS */ #define IR_SSx_SLx_RSS (IR_SSx | IR_SLx | IR_RSS) /* a special case */ #define IR_ALL_SKIPS (IR_SEZ | IR_SZx | IR_SSx_SLx_RSS) /* another special case */ /* Shift-Rotate Group instruction register micro-ops */ #define IR_xLS 0000000u /* ALS/BLS */ #define IR_xRS 0000001u /* ARS/BRS */ #define IR_RxL 0000002u /* RAL/RBL */ #define IR_RxR 0000003u /* RAR/RBR */ #define IR_xLR 0000004u /* ALR/BLR */ #define IR_ERx 0000005u /* ERA/ERB */ #define IR_ELx 0000006u /* ELA/ELB */ #define IR_xLF 0000007u /* ALF/BLF */ #define SRG_DIS 0000000u /* micro-op disable */ #define SRG1_EN 0000010u /* micro-op 1 enable */ #define SRG2_EN 0000020u /* micro-op 2 enable */ /* Instruction register masks */ #define IR_MRG (MRG | AB_MASK) /* MRG instructions mask */ #define IR_MRG_I (IR_MRG | IR_IND) /* MRG indirect instructions mask */ #define IR_JSB 0014000u /* JSB instruction */ #define IR_JSB_I (IR_JSB | IR_IND) /* JSB,I instruction */ #define IR_JMP 0024000u /* JMP instruction */ #define IR_HLT_MASK 0172700u /* I/O group mask for HLT[,C] instruction */ #define IR_CLC_MASK 0176700u /* I/O group mask for a CLC[,C] instruction */ #define IR_HLT 0102000u /* HLT instruction */ #define IR_CLC 0106700u /* CLC instruction */ /* CPU unit flags and accessors. 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | r | - | G | V | O | E | D | F | M | I | P | U | CPU model | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Where: r = reserved G = SIGNAL/1000 firmware is present V = Vector Instruction Set firmware is present O = RTE-6/VM VMA and OS firmware is present E = RTE-IV EMA firmware is present D = Double Integer firmware is present F = Fast FORTRAN Processor firmware is present M = Dynamic Mapping System firmware is present I = 2000 I/O Processor firmware is present P = Floating Point hardware or firmware is present U = Extended Arithmetic Unit is present */ #define UNIT_MODEL_SHIFT (UNIT_V_UF + 0) /* bits 0- 3: CPU model (OPTION_ID value) */ #define UNIT_OPTION_SHIFT (UNIT_V_UF + 4) /* bits 4-15: CPU options installed */ #define UNIT_MODEL_MASK 0000017u /* model ID mask */ #define UNIT_OPTION_MASK 0003777u /* option ID mask */ #define UNIT_MODEL_FIELD (UNIT_MODEL_MASK << UNIT_MODEL_SHIFT) #define UNIT_OPTION_FIELD (UNIT_OPTION_MASK << UNIT_OPTION_SHIFT) #define UNIT_MODEL(f) ((f) >> UNIT_MODEL_SHIFT & UNIT_MODEL_MASK) #define UNIT_OPTION(f) ((f) >> UNIT_OPTION_SHIFT & UNIT_OPTION_MASK) #define TO_UNIT_OPTION(id) (1u << UNIT_OPTION_SHIFT + (id) - Option_BASE - 1) /* Unit models */ #define UNIT_2116 (Option_2116 << UNIT_MODEL_SHIFT) #define UNIT_2115 (Option_2115 << UNIT_MODEL_SHIFT) #define UNIT_2114 (Option_2114 << UNIT_MODEL_SHIFT) #define UNIT_2100 (Option_2100 << UNIT_MODEL_SHIFT) #define UNIT_1000_M (Option_1000_M << UNIT_MODEL_SHIFT) #define UNIT_1000_E (Option_1000_E << UNIT_MODEL_SHIFT) #define UNIT_1000_F (Option_1000_F << UNIT_MODEL_SHIFT) /* Unit options */ #define UNIT_EAU TO_UNIT_OPTION (Option_EAU) #define UNIT_FP TO_UNIT_OPTION (Option_FP) #define UNIT_IOP TO_UNIT_OPTION (Option_IOP) #define UNIT_DMS TO_UNIT_OPTION (Option_DMS) #define UNIT_FFP TO_UNIT_OPTION (Option_FFP) #define UNIT_DBI TO_UNIT_OPTION (Option_DBI) #define UNIT_EMA TO_UNIT_OPTION (Option_EMA) #define UNIT_VMAOS TO_UNIT_OPTION (Option_VMAOS) #define UNIT_VIS TO_UNIT_OPTION (Option_VIS) #define UNIT_SIGNAL TO_UNIT_OPTION (Option_SIGNAL) #define UNIT_DS TO_UNIT_OPTION (Option_DS) #define UNIT_EMA_VMA (UNIT_EMA | UNIT_VMAOS) /* Unit conversions to CPU options */ #define TO_CPU_MODEL(f) (CPU_OPTION) (1u << UNIT_MODEL (f)) #define TO_CPU_OPTION(f) (CPU_OPTION) (UNIT_OPTION (f) << CPU_OPTION_SHIFT) /* "Pseudo-option" flags used only for option testing; never set into the UNIT structure */ #define UNIT_V_PFAIL (UNIT_V_UF - 1) /* Power fail is installed */ #define UNIT_V_DMA (UNIT_V_UF - 2) /* DMA is installed */ #define UNIT_V_MP (UNIT_V_UF - 3) /* Memory protect is installed */ #define UNIT_PFAIL (1 << UNIT_V_PFAIL) #define UNIT_DMA (1 << UNIT_V_DMA) #define UNIT_MP (1 << UNIT_V_MP) /* CPU global SCP data definitions */ REG *sim_PC = NULL; /* the pointer to the P register */ /* CPU global data structures */ /* CPU registers */ HP_WORD ABREG [2] = { 0, 0 }; /* A and B registers */ HP_WORD PR = 0; /* P register */ HP_WORD SR = 0; /* S register */ HP_WORD MR = 0; /* M register */ HP_WORD TR = 0; /* T register */ HP_WORD XR = 0; /* X register */ HP_WORD YR = 0; /* Y register */ uint32 E = 0; /* E register */ uint32 O = 0; /* O register */ HP_WORD IR = 0; /* Instruction Register */ HP_WORD CIR = 0; /* Central Interrupt Register */ HP_WORD SPR = 0; /* 1000 Stack Pointer Register / 2100 F Register */ /* CPU global state */ FLIP_FLOP cpu_interrupt_enable = SET; /* interrupt enable flip-flop */ uint32 cpu_pending_interrupt = 0; /* pending interrupt select code or zero if none */ t_stat cpu_ss_unimpl = SCPE_OK; /* status return for unimplemented instruction execution */ t_stat cpu_ss_undef = SCPE_OK; /* status return for undefined instruction execution */ t_stat cpu_ss_unsc = SCPE_OK; /* status return for I/O to an unassigned select code */ t_stat cpu_ss_ioerr = SCPE_OK; /* status return for an unreported I/O error */ t_stat cpu_ss_inhibit = SCPE_OK; /* CPU stop inhibition mask */ UNIT *cpu_ioerr_uptr = NULL; /* pointer to a unit with an unreported I/O error */ HP_WORD err_PR = 0; /* error PC */ uint16 pcq [PCQ_SIZE] = { 0 }; /* PC queue (must be 16-bits wide for REG array entry) */ uint32 pcq_p = 0; /* PC queue pointer */ REG *pcq_r = NULL; /* PC queue register pointer */ CPU_OPTION_SET cpu_configuration; /* the current CPU option set and model */ uint32 cpu_speed = 1; /* the CPU speed, expressed as a multiplier of a real machine */ /* CPU local state. Implementation notes: 1. The "is_1000" variable is used to index into tables where the row selected depends on whether or not the CPU is a 1000 M/E/F-series model. For logical tests that depend on this, it is faster (by one x86 machine instruction) to test the "cpu_configuration" variable for the presence of one of the three 1000 model flags. */ static jmp_buf abort_environment; /* microcode abort environment */ static FLIP_FLOP interrupt_system = CLEAR; /* interrupt system */ static uint32 interrupt_request = 0; /* the currently interrupting select code or zero if none */ static uint32 interrupt_request_set [2] = { 0, 0 }; /* device interrupt request bit vector */ static uint32 priority_holdoff_set [2] = { 0, 0 }; /* device priority holdoff bit vector */ static uint32 exec_mask = 0; /* the current instruction execution trace mask */ static uint32 exec_match = D16_UMAX; /* the current instruction execution trace matching value */ static uint32 indirect_limit = 16; /* the indirect chain length limit */ static t_bool is_1000 = FALSE; /* TRUE if the CPU is a 1000 M/E/F-Series */ static t_bool mp_is_present = FALSE; /* TRUE if Memory Protect is present */ static uint32 last_select_code = 0; /* the last select code sent over the I/O backplane */ static HP_WORD saved_MR = 0; /* the M-register value between SCP commands */ static DEVICE *loader_rom [4] = { NULL }; /* the four boot loader ROM sockets in a 1000 CPU */ /* CPU local data structures */ /* CPU features table. The feature table is used to validate CPU feature changes within the subset of features supported by a given CPU. Features in the typical list are enabled when the CPU model is selected. If a feature appears in the typical list but NOT in the optional list, then it is standard equipment and cannot be disabled. If a feature appears in the optional list, then it may be enabled or disabled as desired by the user. */ typedef struct { /* CPU model feature table */ uint32 typ; /* standard features plus typically configured options */ uint32 opt; /* complete list of optional features */ uint32 maxmem; /* maximum configurable memory in 16-bit words */ } FEATURE_TABLE; static const FEATURE_TABLE cpu_features [] = { /* CPU features indexed by OPTION_ID */ { UNIT_DMA | UNIT_MP, /* Option_2116 */ UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_EAU, 32 * 1024 }, { UNIT_DMA, /* Option_2115 */ UNIT_PFAIL | UNIT_DMA | UNIT_EAU, 8 * 1024 }, { UNIT_DMA, /* Option_2114 */ UNIT_PFAIL | UNIT_DMA, 16 * 1024 }, { UNIT_PFAIL | UNIT_MP | UNIT_DMA | UNIT_EAU, /* Option_2100 */ UNIT_DMA | UNIT_FP | UNIT_IOP | UNIT_FFP, 32 * 1024 }, { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* Option_1000_M */ UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | UNIT_IOP | UNIT_FFP | UNIT_DS, 1024 * 1024 }, { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* Option_1000_E */ UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | UNIT_IOP | UNIT_FFP | UNIT_DBI | UNIT_DS | UNIT_EMA_VMA, 1024 * 1024 }, { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | /* Option_1000_F */ UNIT_FFP | UNIT_DBI | UNIT_DMS, UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | UNIT_VIS | UNIT_DS | UNIT_SIGNAL | UNIT_EMA_VMA, 1024 * 1024 } }; /* CPU local SCP support routine declarations */ static INTERFACE cpu_interface; static INTERFACE ovf_interface; static INTERFACE pwr_interface; static t_stat cpu_examine (t_value *eval, t_addr address, UNIT *uptr, int32 switches); static t_stat cpu_deposit (t_value value, t_addr address, UNIT *uptr, int32 switches); static t_stat cpu_reset (DEVICE *dptr); static t_stat cpu_boot (int32 unitno, DEVICE *dptr); static t_stat set_stops (UNIT *uptr, int32 option, CONST char *cptr, void *desc); static t_stat set_size (UNIT *uptr, int32 new_size, CONST char *cptr, void *desc); static t_stat set_model (UNIT *uptr, int32 new_model, CONST char *cptr, void *desc); static t_stat set_option (UNIT *uptr, int32 option, CONST char *cptr, void *desc); static t_stat clear_option (UNIT *uptr, int32 option, CONST char *cptr, void *desc); static t_stat set_loader (UNIT *uptr, int32 enable, CONST char *cptr, void *desc); static t_stat set_roms (UNIT *uptr, int32 option, CONST char *cptr, void *desc); static t_stat set_exec (UNIT *uptr, int32 option, CONST char *cptr, void *desc); static t_stat show_stops (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat show_model (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat show_roms (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat show_cage (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat show_exec (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat show_speed (FILE *st, UNIT *uptr, int32 val, CONST void *desc); /* CPU local utility routine declarations */ static t_stat mrg_address (void); static HP_WORD srg_uop (HP_WORD value, HP_WORD operation); static t_stat machine_instruction (t_bool int_ack, uint32 *idle_save); static t_bool reenable_interrupts (void); /* CPU SCP data structures */ /* Device information blocks */ static DIB cpu_dib = { /* CPU (select code 0) */ &cpu_interface, /* the device's I/O interface function pointer */ CPU, /* the device's select code (02-77) */ 0, /* the card index */ NULL, /* the card description */ NULL /* the ROM description */ }; static DIB ovfl_dib = { /* Overflow (select code 1) */ &ovf_interface, /* the device's I/O interface function pointer */ OVF, /* the device's select code (02-77) */ 0, /* the card index */ NULL, /* the card description */ NULL /* the ROM description */ }; static DIB pwrf_dib = { /* Power Fail (select code 4) */ &pwr_interface, /* the device's I/O interface function pointer */ PWR, /* the device's select code (02-77) */ 0, /* the card index */ NULL, /* the card description */ NULL /* the ROM description */ }; /* Unit list. The CPU unit "capac" field is set to the current main memory capacity in 16-bit words by the "set_size" utility routine. The CPU does not use a unit event service routine. */ static UNIT cpu_unit [] = { { UDATA (NULL, UNIT_FIX | UNIT_BINK, 0) } }; /* Register list. The CPU register list exposes the machine registers for user inspection and modification. Implementation notes: 1. All registers that reference variables of type HP_WORD must have the REG_FIT flag for proper access if HP_WORD is a 16-bit type. 2. The REG_X flag indicates that the register may be displayed in symbolic form. 3. The T register cannot be modified. To change a memory location value, the DEPOSIT CPU command must be used. */ static REG cpu_reg [] = { /* Macro Name Location Radix Width Offset Depth Flags */ /* ------ ------- ------------------ ----- ----- -------- ----------------- ----------------- */ { ORDATA (P, PR, 15) }, { ORDATA (A, AR, 16), REG_X }, { ORDATA (B, BR, 16), REG_X }, { ORDATA (M, MR, 15) }, { ORDATA (T, TR, 16), REG_RO | REG_X }, { ORDATA (X, XR, 16), REG_X }, { ORDATA (Y, YR, 16), REG_X }, { ORDATA (S, SR, 16), REG_X }, { FLDATA (E, E, 0) }, { FLDATA (O, O, 0) }, { ORDATA (CIR, CIR, 6) }, { FLDATA (INTSYS, interrupt_system, 0) }, { FLDATA (INTEN, cpu_interrupt_enable, 0) }, { ORDATA (IOPSP, SPR, 16) }, { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_CIRC | REG_RO }, { ORDATA (IR, IR, 16), REG_HRO }, { ORDATA (SAVEDMR, saved_MR, 32), REG_HRO }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (EMASK, exec_mask, 16), REG_HRO }, { ORDATA (EMATCH, exec_match, 16), REG_HRO }, { DRDATA (ILIMIT, indirect_limit, 16), REG_HRO }, { ORDATA (FWANXM, mem_end, 32), REG_HRO }, { ORDATA (CONFIG, cpu_configuration, 32), REG_HRO }, { BRDATA (ROMS, loader_rom, 8, 32, 4), REG_HRO }, { FLDATA (IS1000, is_1000, 0), REG_HRO }, { ORDATA (INTREQ, interrupt_request, 6), REG_HRO }, { ORDATA (LASTSC, last_select_code, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8), REG_HRO }, { ORDATA (BRK, sim_brk_char, 8), REG_HRO }, { ORDATA (DEL, sim_del_char, 8), REG_HRO }, { NULL } }; /* Modifier list. Implementation notes: 1. The 21MX monikers are deprecated in favor of the 1000 designations. See the "HP 1000 Series Naming History" on the back inside cover of the Technical Reference Handbook. 2. The string descriptors are used by the "show_model" routine to print the CPU model numbers prior to appending "loader enabled" or "loader disabled" to the report. 3. Each CPU option requires three modifiers. The two regular modifiers control the setting and printing of the option, while the extended modifier controls clearing the option. The latter is necessary because the option must be checked before confirming the change, and so the option value must be passed to the validation routine. */ static MTAB cpu_mod [] = { /* Mask Value Match Value Print String Match String Validation Display Descriptor */ /* ---------------- ----------- ------------ ------------ ------------- ----------- ----------------- */ { UNIT_MODEL_FIELD, UNIT_2116, "", "2116", &set_model, &show_model, (void *) "2116" }, { UNIT_MODEL_FIELD, UNIT_2115, "", "2115", &set_model, &show_model, (void *) "2115" }, { UNIT_MODEL_FIELD, UNIT_2114, "", "2114", &set_model, &show_model, (void *) "2114" }, { UNIT_MODEL_FIELD, UNIT_2100, "", "2100", &set_model, &show_model, (void *) "2100" }, { UNIT_MODEL_FIELD, UNIT_1000_E, "", "1000-E", &set_model, &show_model, (void *) "1000-E" }, { UNIT_MODEL_FIELD, UNIT_1000_M, "", "1000-M", &set_model, &show_model, (void *) "1000-M" }, #if defined (HAVE_INT64) { UNIT_MODEL_FIELD, UNIT_1000_F, "", "1000-F", &set_model, &show_model, (void *) "1000-F" }, #endif { UNIT_MODEL_FIELD, UNIT_1000_M, NULL, "21MX-M", &set_model, &show_model, (void *) "1000-M" }, { UNIT_MODEL_FIELD, UNIT_1000_E, NULL, "21MX-E", &set_model, &show_model, (void *) "1000-E" }, { UNIT_EAU, UNIT_EAU, "EAU", "EAU", &set_option, NULL, NULL }, { UNIT_EAU, 0, "no EAU", NULL, NULL, NULL, NULL }, { MTAB_XDV, UNIT_EAU, NULL, "NOEAU", &clear_option, NULL, NULL }, { UNIT_FP, UNIT_FP, "FP", "FP", &set_option, NULL, NULL }, { UNIT_FP, 0, "no FP", NULL, NULL, NULL, NULL }, { MTAB_XDV, UNIT_FP, NULL, "NOFP", &clear_option, NULL, NULL }, { UNIT_IOP, UNIT_IOP, "IOP", "IOP", &set_option, NULL, NULL }, { UNIT_IOP, 0, "no IOP", NULL, NULL, NULL, NULL }, { MTAB_XDV, UNIT_IOP, NULL, "NOIOP", &clear_option, NULL, NULL }, { UNIT_DMS, UNIT_DMS, "DMS", "DMS", &set_option, NULL, NULL }, { UNIT_DMS, 0, "no DMS", NULL, NULL, NULL, NULL }, { MTAB_XDV, UNIT_DMS, NULL, "NODMS", &clear_option, NULL, NULL }, { UNIT_FFP, UNIT_FFP, "FFP", "FFP", &set_option, NULL, NULL }, { UNIT_FFP, 0, "no FFP", NULL, NULL, NULL, NULL }, { MTAB_XDV, UNIT_FFP, NULL, "NOFFP", &clear_option, NULL, NULL }, { UNIT_DBI, UNIT_DBI, "DBI", "DBI", &set_option, NULL, NULL }, { UNIT_DBI, 0, "no DBI", NULL, NULL, NULL, NULL }, { MTAB_XDV, UNIT_DBI, NULL, "NODBI", &clear_option, NULL, NULL }, { UNIT_EMA_VMA, UNIT_EMA, "EMA", "EMA", &set_option, NULL, NULL }, { MTAB_XDV, UNIT_EMA, NULL, "NOEMA", &clear_option, NULL, NULL }, { UNIT_EMA_VMA, UNIT_VMAOS, "VMA", "VMA", &set_option, NULL, NULL }, { MTAB_XDV, UNIT_VMAOS, NULL, "NOVMA", &clear_option, NULL, NULL }, { UNIT_EMA_VMA, 0, "no EMA/VMA", NULL, &set_option, NULL, NULL }, #if defined (HAVE_INT64) { UNIT_VIS, UNIT_VIS, "VIS", "VIS", &set_option, NULL, NULL }, { UNIT_VIS, 0, "no VIS", NULL, NULL, NULL, NULL }, { MTAB_XDV, UNIT_VIS, NULL, "NOVIS", &clear_option, NULL, NULL }, { UNIT_SIGNAL, UNIT_SIGNAL, "SIGNAL", "SIGNAL", &set_option, NULL, NULL }, { UNIT_SIGNAL, 0, "no SIGNAL", NULL, NULL, NULL, NULL }, { MTAB_XDV, UNIT_SIGNAL, NULL, "NOSIGNAL", &clear_option, NULL, NULL }, #endif /* Future microcode support. { UNIT_DS, UNIT_DS, "DS", "DS", &set_option, NULL, NULL }, { UNIT_DS, 0, "no DS", NULL, NULL, NULL, NULL }, { MTAB_XDV, UNIT_DS, NULL, "NODS", &clear_option, NULL, NULL }, */ /* Entry Flags Value Print String Match String Validation Display Descriptor */ /* ------------------- ----------- ------------ --------------- ------------- -------------- ---------- */ { MTAB_XDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle, NULL }, { MTAB_XDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL, NULL }, { MTAB_XDV, 1, NULL, "LOADERENABLE", &set_loader, NULL, NULL }, { MTAB_XDV, 0, NULL, "LOADERDISABLE", &set_loader, NULL, NULL }, { MTAB_XDV, 4 * 1024, NULL, "4K", &set_size, NULL, NULL }, { MTAB_XDV, 8 * 1024, NULL, "8K", &set_size, NULL, NULL }, { MTAB_XDV, 12 * 1024, NULL, "12K", &set_size, NULL, NULL }, { MTAB_XDV, 16 * 1024, NULL, "16K", &set_size, NULL, NULL }, { MTAB_XDV, 24 * 1024, NULL, "24K", &set_size, NULL, NULL }, { MTAB_XDV, 32 * 1024, NULL, "32K", &set_size, NULL, NULL }, { MTAB_XDV, 64 * 1024, NULL, "64K", &set_size, NULL, NULL }, { MTAB_XDV, 128 * 1024, NULL, "128K", &set_size, NULL, NULL }, { MTAB_XDV, 256 * 1024, NULL, "256K", &set_size, NULL, NULL }, { MTAB_XDV, 512 * 1024, NULL, "512K", &set_size, NULL, NULL }, { MTAB_XDV, 1024 * 1024, NULL, "1024K", &set_size, NULL, NULL }, { MTAB_XDV | MTAB_NMO, 0, "ROMS", "ROMS", &set_roms, &show_roms, NULL }, { MTAB_XDV | MTAB_NMO, 0, "IOCAGE", NULL, NULL, &show_cage, NULL }, { MTAB_XDV | MTAB_NMO, 1, "STOPS", "STOP", &set_stops, &show_stops, NULL }, { MTAB_XDV, 0, NULL, "NOSTOP", &set_stops, NULL, NULL }, { MTAB_XDV | MTAB_NMO, 2, "INDIR", "INDIR", &set_stops, &show_stops, NULL }, { MTAB_XDV | MTAB_NMO, 1, "EXEC", "EXEC", &set_exec, &show_exec, NULL }, { MTAB_XDV, 0, NULL, "NOEXEC", &set_exec, NULL, NULL }, { MTAB_XDV | MTAB_NMO, 0, "SPEED", NULL, NULL, &show_speed, NULL }, { 0 } }; /* Trace list */ static DEBTAB cpu_deb [] = { { "INSTR", TRACE_INSTR }, /* trace instruction executions */ { "DATA", TRACE_DATA }, /* trace memory data accesses */ { "FETCH", TRACE_FETCH }, /* trace memory instruction fetches */ { "REG", TRACE_REG }, /* trace register values */ { "OPND", TRACE_OPND }, /* trace instruction operands */ { "EXEC", TRACE_EXEC }, /* trace matching instruction execution states */ { "NOOS", DEBUG_NOOS }, /* RTE-6/VM will not use OS firmware */ { NULL, 0 } }; /* Simulation stop list. The simulator can be configured to detect certain machine instruction conditions and stop execution when one of them occurs. Stops may be enabled or disabled individually with these commands: SET CPU STOP=