1 /* hp3000_cpu.c: HP 3000 Central Processing Unit simulator
2 
3    Copyright (c) 2016-2021, J. David Bryan
4 
5    Permission is hereby granted, free of charge, to any person obtaining a copy
6    of this software and associated documentation files (the "Software"), to deal
7    in the Software without restriction, including without limitation the rights
8    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9    copies of the Software, and to permit persons to whom the Software is
10    furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be included in
13    all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18    AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22    Except as contained in this notice, the name of the author shall not be used
23    in advertising or otherwise to promote the sale, use or other dealings in
24    this Software without prior written authorization from the author.
25 
26    CPU          HP 3000 Series III Central Processing Unit
27 
28    07-Apr-21    JDB     Added "Series III+" machine
29                         Expanded bank register widths from 4 to 6 bits
30    01-Apr-21    JDB     Removed REG_FIT from register definitions (obsolete)
31    11-Oct-20    JDB     Moved UNIT_OPTS to hp3000_cpu.h for updating ease
32    24-Sep-20    JDB     Traps now trace the register set
33    05-Sep-20    JDB     Enabled EIS option
34    26-Aug-20    JDB     Corrected line ends for trace to stdout
35    04-Jul-20    JDB     Postlude trace now calls "sim_error_text" unconditionally
36    09-Dec-19    JDB     Replaced debugging macros with tracing macros
37    20-Jun-19    JDB     Added wait time to process clock trace
38    08-Apr-19    JDB     Suppress stop messages for step and breakpoints in DO files
39    07-Apr-19    JDB     Moved breakpoint test before run/halt-mode test
40    21-Feb-19    JDB     Resuming into PAUS with pending IRQ now sets P correctly
41                         Moved "debug_save" from global to "sim_instr" local
42    06-Feb-19    JDB     Corrected trace report for simulation stop
43    27-Dec-18    JDB     Revised fall through comments to comply with gcc 7
44    05-Sep-17    JDB     Removed the -B (binary display) option; use -2 instead
45                         Changed REG_A (permit any symbolic override) to REG_X
46    19-Jan-17    JDB     Added comments describing the OPND and EXEC trace options
47    29_Dec-16    JDB     Changed the status mnemonic flag from REG_S to REG_T
48    07-Nov-16    JDB     Renamed cpu_byte_to_word_ea to cpu_byte_ea
49    03-Nov-16    JDB     Added zero offsets to the cpu_call_procedure calls
50    01-Nov-16    JDB     Added per-instruction trace capability
51    24-Oct-16    JDB     Renamed SEXT macro to SEXT16
52    22-Sep-16    JDB     Moved byte_to_word_address from hp3000_cpu_base.c
53    21-Sep-16    JDB     Added CIS/NOCIS option
54    01-Sep-16    JDB     Add power fail/power restore support
55    23-Aug-16    JDB     Add module interrupt support
56    14-Jul-16    JDB     Implemented the cold dump process
57                         Changed "loading" EXEC_STATE to "waiting"
58    11-Jul-16    JDB     Change "cpu_unit" from a UNIT to an array of one UNIT
59    08-Jun-16    JDB     Corrected %d format to %u for unsigned values
60    16-May-16    JDB     ACCESS_PROPERTIES.name is now a pointer-to-constant
61    13-May-16    JDB     Modified for revised SCP API function parameter types
62    24-Mar-16    JDB     Changed memory word type from uint16 to MEMORY_WORD
63    21-Mar-16    JDB     Changed cpu_ccb_table type from uint16 to HP_WORD
64    11-Mar-16    JDB     Fixed byte EA calculations with negative indexes
65    22-Dec-15    JDB     First release version
66    01-Apr-15    JDB     First successful run of MPE-V/R through account login
67    11-Dec-12    JDB     Created
68 
69    References:
70      - HP 3000 Series II System Microprogram Listing
71          (30000-90023, August 1976)
72      - HP 3000 Series II/III System Reference Manual
73          (30000-90020, July 1978)
74      - Machine Instruction Set Reference Manual
75          (30000-90022, June 1984)
76 
77 
78    The HP 3000 is a family of general-purpose business computers that were sold
79    by Hewlett-Packard from 1972 through 2001.  There are two major divisions
80    within this family: the "classic" 16-bit, stack-oriented CISC machines, and
81    the "Precision Architecture" 32-bit, register-oriented RISC machines that
82    succeeded them.  All machines run versions of MPE, the "Multiprogramming
83    Executive" operating system.
84 
85    Within the "classic" division, there are two additional subdivisions, based
86    on the method used for peripheral connections: the original "SIO" machines,
87    and the later "HP-IB" machines.  The I/O interfacing hardware differs between
88    the two types of machines, as do the privileged I/O machine instructions.
89    The user instruction sets are identical, as are the register sets visible to
90    the programmer.  The I/O drivers are different to account for the hardware
91    differences, and therefore they run slightly different versions of MPE.
92 
93    This implementation is a simulator for the classic SIO machines.  This group
94    consists of the 3000 CX, the Series I, Series II, and Series III; the last is
95    simulated here.  The CX and Series I, which is a repackaged CX, are
96    essentially subsets of the Series II/III -- a smaller instruction set,
97    limited memory size, and lower-precision floating-point instructions.
98    Simulation of these machines may be added in the future.  Future simulation
99    of the HP-IB machines (the Series 30 through 70) is desirable, as the latest
100    MPE versions run only on these machines, but documentation on the internals
101    of the HP-IB hardware controllers is nonexistent.
102 
103    The CX and Series I support 64K 16-bit words of memory.  The Series II
104    supports up to 256K, divided into four banks of 64K words each, and the
105    Series III extends this to 1024K words using 16 banks (although MPE-V/R can
106    accommodate bank numbers up to six bits in length).  Memory is divided into
107    variable-length code and data segments, with the latter containing a
108    program's global data area and stack.
109 
110    Memory protection is accomplished by checking program, data, and stack
111    accesses against segment base and limit registers, which can be set only by
112    MPE.  Bounds violations cause automatic hardware traps to a handler routine
113    within MPE.  Some violations may be permitted; for example, a Stack Overflow
114    trap may cause MPE to allocate a larger stack and then restart the
115    interrupted instruction.  Almost all memory references are position-
116    independent, so moving segments to accommodate expansion requires only
117    resetting of the segment registers to point at the new locations.  Code
118    segments are fully reentrant and shareable, and both code and data are
119    virtual, as the hardware supports absent code and data segment traps.
120 
121    The classic 3000s are stack machines.  Most of the instructions operate on
122    the value on the top of the stack (TOS) or on the TOS and the next-to-the-top
123    of the stack (NOS).  To improve execution speed, the 3000 has a set of
124    hardware registers that are accessed as the first four locations at the top
125    of the stack, while the remainder of the stack locations reside in main
126    memory.  A hardware register renamer provides fast stack pushes and pops
127    without physically copying values between registers.
128 
129    In hardware, the stack registers are referenced internally as TR0-TR3 and
130    externally as RA-RD.  An access to the RA (TOS) register is translated by the
131    renamer to access TR0, TR1, etc. depending on which internal register is
132    designated as the current top of the stack.  For example, assume that RA
133    corresponds to TR0.  To push a new value onto the top of the stack, the
134    renamer is adjusted so that RA corresponds to TR1, and the new value is
135    stored there.  In this state, RB corresponds to TR0, the previous TOS (and
136    current NOS) value.  Additional pushes rename RA as TR2 and then TR3, with RB
137    being renamed to TR1 and then TR2, and similarly for RC and RD.  The number
138    of valid TOS registers is given by the value in the SR register, and the
139    first stack location in memory is given by the value in the SM register.
140    Pops reverse the sequence: a pop with RA corresponding to TR3 renames RA to
141    TR2, RB to TR1, etc.  When all four stack registers are in use, a push will
142    copy the value in RD to the top of the memory stack (SM + 1) before the
143    registers are renamed and the new value stored into RA.  Similarly, when all
144    four stack registers are empty, a pop simply decrements the SM register,
145    effectively deleting the top of the memory stack.
146 
147    Because of the renamer, the microcode can always use RA to refer to the top
148    of the stack, regardless of which internal TR register is being used, and
149    similarly for RB-RD.  Execution of each stack instruction begins with a
150    preadjustment, if needed, that loads the TOS registers that will be used by
151    the instruction from the top of the memory stack.  For example, if only RA
152    contains a value (i.e., the SR register value is 1), the ADD instruction,
153    which adds the values in RA and RB, will load RB with the value on the top of
154    the memory stack, the SR count will be incremented, and the SM register will
155    be decremented.  On the other hand, if both RA and RB contained values (SR >=
156    2), then no preadjustment would be required before the ADD instruction
157    microcode manipulated RA and RB.
158 
159    In simulation, the renamer is implemented by physically copying the values
160    between registers, as this is much faster than mapping via array index
161    values, as the hardware does.  A set of functions provides the support to
162    implement the hardware stack operations:
163 
164      cpu_push       - empty the TOS register (SR++, caller stores into RA)
165      cpu_pop        - delete the TOS register (SR--)
166      cpu_queue_up   - move from memory to the lowest TOS register (SR++, SM--)
167      cpu_queue_down - move from the lowest TOS register to memory (SR--, SM++)
168      cpu_flush      - move all stack registers to memory (SR = 0 on return)
169      cpu_adjust_sr  - queue up until the required SR count is reached
170      cpu_mark_stack - write a stack marker to memory
171 
172    The renamer is described in US Patent 3,737,871 (Katzman, "Stack Register
173    Renamer", June 1973).
174 
175    The MPE operating system is supported by special microcode features that
176    perform code and data segment mapping, segment access bounds checking,
177    privilege checking, etc.  The layout of certain in-memory tables is known to
178    both the OS and the microcode and is used to validate execution of
179    instructions.  For instance, every stack instruction is checked for a valid
180    access within the stack segment boundaries, which are set up by the OS
181    before program dispatch.  For this reason, the 3000 cannot be operated as a
182    "bare" machine, because these tables would not have been initialized.
183    Similarly, the "cold load" process by which the OS is loaded from storage
184    media into memory is entirely in microcode, as machine instructions cannot be
185    executed until the required tables are loaded into memory.
186 
187    This OS/microcode integration means that the microcode may detect conditions
188    that make continued execution impossible.  An example would be a not-present
189    segment fault for the segment containing the disc I/O driver.  If such a
190    condition is detected, the CPU does a "system halt."  This fatal microcode
191    error, distinct from a regular programmed halt, causes operation to cease
192    until the CPU is reset.
193 
194    The CPU hardware includes a free-running 16-bit process clock that increments
195    once per millisecond whenever a user program is executing.  MPE uses the
196    process clock to charge CPU usage to programs, and thereby to users, groups,
197    and accounts.  Instructions are provided to read (RCLK) and set (SCLK) the
198    process clock.
199 
200 
201    The data types supported by the instruction set are:
202 
203      - 8-bit unsigned byte
204      - 16-bit unsigned integer ("logical" format)
205      - 16-bit two's-complement integer
206      - 32-bit two's-complement integer
207      - 32-bit sign-magnitude floating point
208      - 64-bit sign-magnitude floating point
209 
210    Multi-word values are stored in memory with the most-significant words in the
211    lowest addresses.  The stack is organized in memory from lower to higher
212    addresses, so a value on the stack has its least-significant word on the top
213    of the stack.
214 
215    Machine instructions are initially decoded by a sub-opcode contained in the
216    four highest bits, as follows (note that the HP 3000 numbers bits from
217    left-to-right, i.e., bit 0 is the MSB and bit 15 is the LSB):
218 
219        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
220      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
221      | 0   0   0   0 |   1st stack opcode    |   2nd stack opcode    |  Stack
222      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
223 
224 
225        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
226      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
227      | 0   0   0   1 | X |   shift opcode    |      shift count      |  Shift
228      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
229 
230      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
231      | 0   0   0   1 | I |   branch opcode   |+/-|  P displacement   |  Branch
232      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
233 
234      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
235      | 0   0   0   1 | X |  bit test opcode  |     bit position      |  Bit Test
236      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
237 
238 
239        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
240      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
241      | 0   0   1   0 | 0   0   0   0 |  move op  | opts/S decrement  |  Move
242      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
243 
244      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
245      | 0   0   1   0 | 0   0   0   0 |  special op   | 0   0 | sp op |  Special
246      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
247 
248      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
249      | 0   0   1   0 | 0   0   0   1 |  option set   | option subset |  Firmware
250      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
251 
252      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
253      | 0   0   1   0 |  imm opcode   |       immediate operand       |  Immediate
254      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
255 
256      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
257      | 0   0   1   0 | field opcode  |    J field    |    K field    |  Field
258      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
259 
260      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
261      | 0   0   1   0 |  register op  | SK| DB| DL| Z |STA| X | Q | S |  Register
262      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
263 
264 
265        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
266      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
267      | 0   0   1   1 | 0   0   0   0 |  I/O opcode   |    K field    |  I/O
268      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
269 
270      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
271      | 0   0   1   1 | 0   0   0   0 |  cntl opcode  | 0   0 | cn op |  Control
272      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
273 
274      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
275      | 0   0   1   1 |  program op   |            N field            |  Program
276      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
277 
278      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
279      | 0   0   1   1 | immediate op  |       immediate operand       |  Immediate
280      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
281 
282      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
283      | 0   0   1   1 |   memory op   |        P displacement         |  Memory
284      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
285 
286      The memory, loop, and branch instructions occupy the remainder of the
287      sub-opcodes (04-17):
288 
289        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
290      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
291      |   memory op   | X | I |         mode and displacement         |  Memory
292      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
293                              | 0 | 0 |     P+ displacement 0-255     |
294                              +---+---+---+---+---+---+---+---+---+---+
295                              | 0 | 1 |     P- displacement 0-255     |
296                              +---+---+---+---+---+---+---+---+---+---+
297                              | 1 | 0 |    DB+ displacement 0-255     |
298                              +---+---+---+---+---+---+---+---+---+---+
299                              | 1 | 1 | 0 |   Q+ displacement 0-127   |
300                              +---+---+---+---+---+---+---+---+---+---+
301                              | 1 | 1 | 1 | 0 | Q- displacement 0-63  |
302                              +---+---+---+---+---+---+---+---+---+---+
303                              | 1 | 1 | 1 | 1 | S- displacement 0-63  |
304                              +---+---+---+---+---+---+---+---+---+---+
305 
306      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
307      |   memory op   | X | I | s |     mode and displacement         |   Memory
308      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
309                                  | 0 |    DB+ displacement 0-255     |
310                                  +---+---+---+---+---+---+---+---+---+
311                                  | 1 | 0 |   Q+ displacement 0-127   |
312                                  +---+---+---+---+---+---+---+---+---+
313                                  | 1 | 1 | 0 | Q- displacement 0-63  |
314                                  +---+---+---+---+---+---+---+---+---+
315                                  | 1 | 1 | 1 | S- displacement 0-63  |
316                                  +---+---+---+---+---+---+---+---+---+
317 
318      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
319      | 0   1   0   1 |loop op| 0 |+/-|    P-relative displacement    |  Loop
320      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
321 
322      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
323      | 1   1   0   0 | I | 0   1 | > | = | < | P+- displacement 0-31 |  Branch
324      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
325 
326    Optional firmware extension instruction sets occupy instruction codes
327    020400-020777, except for the DMUL (020570) and DDIV (020571) instructions
328    that are part of the base set, as follows:
329 
330        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
331      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
332      | 0   0   1   0 | 0   0   0   1 | 0   1   1   1 | 1   0   0 | x |  DMUL/DDIV
333      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
334 
335      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
336      | 0   0   1   0 | 0   0   0   1 | 0   0   0   0 | 1 | ext fp op |  Extended FP
337      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
338 
339      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
340      | 0   0   1   0 | 0   0   0   1 | 0   0   0   1 |    APL op     |  APL
341      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
342 
343      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
344      | 0   0   1   0 | 0   0   0   1 | 0   0   1   1 |   COBOL op    |  COBOL
345      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
346 
347      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
348      | 0   0   1   0 | 0   0   0   1 | 1 |  options  |  decimal op   |  Decimal
349      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
350 
351    Most instructions are defined by unique 16-bit codes that specify the
352    operations, operands, addressing modes, shift counts, etc.  For each of these
353    instructions, there is only one canonical form that encodes a given
354    instruction (or instruction pair, in the case of stack instructions).  For
355    example, the octal value 140003 is the only value that encodes the "BR P+3"
356    instruction.
357 
358    There are also instruction codes that contain one or more bits designated as
359    "reserved" in the Machine Instruction Set Reference Manual.  For some of
360    these instructions, the reserved bits do not affect instruction decoding.
361    Each instruction of this type has a defined canonical form -- typically with
362    the reserved bits set to zero -- but will execute identically if one of the
363    undefined forms is used.  For example, the "MOVE" instructions define bits
364    12-13 as 00, but the bits are not decoded, so values of 01, 10, and 11 for
365    these bits will result in identical execution.  Specifically, "MOVE 0" is
366    encoded canonically as octal value 020020, but the undefined codes 020024,
367    020030, and 020034 execute "MOVE 0" as well.
368 
369    For the rest of these instructions, the reserved bits are decoded and will
370    affect the instruction interpretation.  An example of this is the "IXIT"
371    instruction.  It also defines bits 12-13 as 00 (canonical encoding 020360),
372    but in this case the bits must be 00 for the instruction to execute; any
373    other value (e.g., undefined codes 020364, 020370, or 020374) executes as a
374    "PCN" instruction, whose canonical encoding is 020362.
375 
376    Finally, some codes are not assigned to any instructions, or they are
377    assigned to instructions that are supplied by optional firmware that is not
378    present in the machine.  These instruction codes are designated as
379    "unimplemented" and will cause Unimplemented Instruction traps if they are
380    executed.  Examples are the stack operation code 072 in either the left-hand
381    or right-hand position (i.e., instruction codes 0072xx and 00xx72), codes
382    020410-020415 if the Extended Instruction Set firmware option is not
383    installed, and codes 036000-036777.
384 
385    When the simulator examines the bit patterns of instructions to execute, each
386    will fall into one of four categories:
387 
388     1. Defined (canonical) instruction encodings.
389 
390     2. Undefined (non-canonical) instruction encodings, where reserved fields
391        are "don't care" bits (e.g., MOVE).
392 
393     3. Undefined (non-canonical) instruction encodings, where reserved fields
394        are decoded (e.g., IXIT).
395 
396     4. Unimplemented instruction encodings (e.g., stack opcode 072 or EADD with
397        no EIS installed).
398 
399    When examining memory or register values in instruction-mnemonic form, the
400    names of the canonical instructions in category 1 are displayed in uppercase,
401    as are the names of the non-canonical instructions in category 2.  The
402    non-canonical instruction names in category 3 are displayed in lowercase.
403    This is to indicate to the user that the instructions that will be executed
404    may not be the ones expected from the decoding.  Instruction names in
405    category 4 that correspond to supported firmware options are displayed in
406    uppercase, regardless of whether or not the option is enabled.  Category 4
407    encodings that do not correspond to instructions are displayed in octal.
408 
409    All of the base set instructions are one word in length.  Most of the
410    firmware extension instructions occupy one word as well, although some are
411    two words long.  If the first word of a two-word instruction is valid but the
412    second is not, an Unimplemented Instruction trap will occur, with P pointing
413    to the location after the second word.
414 
415 
416    The simulator provides four stop conditions related to instruction execution
417    that may be enabled with a SET CPU STOP=<stop> command:
418 
419      <stop>  Action
420      ------  ------------------------------------
421      LOOP    stop on an infinite loop
422      PAUSE   stop on a PAUS instruction
423      UNDEF   stop on an undefined instruction
424      UNIMPL  stop on an unimplemented instruction
425 
426    If an enabled stop condition is detected, execution ceases with the
427    instruction pending, and control returns to the SCP prompt.  When simulation
428    stops, execution may be resumed in two ways.  If the cause of the stop has
429    not been remedied and the stop has not been disabled, resuming execution with
430    CONTINUE, STEP, GO, or RUN will cause the stop to occur again.  Alternately,
431    specifying the "-B" switch with any of the preceding commands will resume
432    execution while bypassing the stop for the current instruction.
433 
434    The LOOP option stops the simulator if it attempts to execute an instruction
435    that enters an infinite loop (e.g., BR P+0).  The branch instructions TBA,
436    TBX, BCC, BR, BCY, BNCY, BOV, and BNOV result in an infinite loop if the
437    branch displacement is zero and the branch condition is true.  The remaining
438    branch instructions cannot result in an infinite loop, as they all modify the
439    CPU state and so eventually reach a point where they drop out of the loop.
440 
441    The PAUSE option stops the simulator if execution of a PAUS instruction is
442    attempted.  This instruction normally suspends instruction fetching until an
443    interrupt occurs.  Clearing the stop and resuming execution suspends the
444    fetch/execute process until an external interrupt occurs.  Resuming with the
445    stop bypassed continues execution with the instruction following the PAUS;
446    this is the same action that occurs when pressing the HALT button and then
447    the RUN button in hardware.
448 
449    The UNDEF option stops the simulator if execution of a non-canonical
450    instruction from decoding category 3 (i.e., an instruction containing a
451    decoded reserved bit pattern other than that defined in the Machine
452    Instruction Set manual) is attempted.  The intent is to catch instructions
453    containing reserved fields with values that change the meaning of those
454    instructions.  Bypassing the stop will decode and execute the instruction in
455    the same manner as the HP 3000 microcode.
456 
457    The UNIMPL option stops the simulator if execution of an instruction from
458    decoding category 4 is attempted.  Bypassing the stop will cause an
459    Unimplemented Instruction trap.  Instructions that depend on the presence of
460    firmware options are implemented if the option is present and unimplemented
461    if the option is absent.  For example, instruction code 020410 executes as
462    the EADD instruction if the Extended Instruction Set is enabled but is
463    unimplemented if the EIS is disabled.  It is displayed as EADD in either
464    case.
465 
466    The instructions in category 2 whose non-canonical forms do not cause an
467    UNDEF stop are:
468 
469            Canonical  Reserved
470      Inst  Encoding     Bits    Defined As    Decoded As
471      ----  ---------  --------  -----------   -----------
472      SCAN   010600     10-15    0 0 0 0 0 0   x x x x x x
473      TNSL   011600     10-15    0 0 0 0 0 0   x x x x x x
474      MOVE   020000     12-13        0 0           x x
475      MVB    020040     12-13        0 0           x x
476      MVBL   020100        13          0             x
477      SCW    020120        13          0             x
478      MVLB   020140        13          0             x
479      SCU    020160        13          0             x
480      CMPB   020240     12-13        0 0           x x
481      RSW    020300     12-14        0 0 0         x x x
482      LLSH   020301     12-14        0 0 0         x x x
483      PLDA   020320     12-14        0 0 0         x x x
484      PSTA   020321     12-14        0 0 0         x x x
485      LSEA   020340     12-13        0 0           x x
486      SSEA   020341     12-13        0 0           x x
487      LDEA   020342     12-13        0 0           x x
488      SDEA   020343     12-13        0 0           x x
489      PAUS   030020     12-15        0 0 0 0       x x x x
490 
491    The instructions in category 3 whose non-canonical forms cause an UNDEF stop
492    are:
493 
494            Canonical  Reserved
495      Inst  Encoding     Bits    Defined As  Decoded As
496      ----  ---------  --------  ----------  ----------
497      IXIT   020360     12-15     0 0 0 0     0 0 0 0
498      LOCK   020361     12-15     0 0 0 1     n n 0 1
499      PCN    020362     12-15     0 0 1 0     n n n 0
500      UNLK   020363     12-15     0 0 1 1     n n 1 1
501 
502      SED    030040     12-15     0 0 0 x     n n n x
503 
504      XCHD   030060     12-15     0 0 0 0     0 0 0 0
505      PSDB   030061     12-15     0 0 0 1     n n 0 1
506      DISP   030062     12-15     0 0 1 0     n n n 0
507      PSEB   030063     12-15     0 0 1 1     n n 1 1
508 
509      SMSK   030100     12-15     0 0 0 0     0 0 0 0
510      SCLK   030101     12-15     0 0 0 1     n n n n
511      RMSK   030120     12-15     0 0 0 0     0 0 0 0
512      RCLK   030121     12-15     0 0 0 1     n n n n
513 
514    Where:
515 
516      x = 0 or 1
517      n = any collective value other than 0
518 
519    In hardware, the SED instruction works correctly only if opcodes 030040 and
520    030041 are used.  Opcodes 030042-030057 also decode as SED, but the status
521    register is set improperly (the I bit is cleared, bits 12-15 are rotated
522    right twice and then ORed into the status register).  In simulation, opcodes
523    030042-030057 work correctly but will cause an UNDEF simulation stop if
524    enabled.
525 
526 
527    The CPU simulator provides extensive tracing capabilities that may be enabled
528    with the SET CONSOLE DEBUG=<filename> and SET CPU DEBUG=<trace> commands.
529    The trace options that may be specified are:
530 
531      Trace  Action
532      -----  -------------------------------------------
533      INSTR  trace instructions executed
534      DATA   trace memory data accesses
535      FETCH  trace memory instruction fetches
536      REG    trace registers
537      OPND   trace memory operands
538      EXEC   trace matching instruction execution states
539      PSERV  trace process clock service events
540 
541    A section of an example trace is:
542 
543      >>CPU fetch: 00.010342  020320    instruction fetch
544      >>CPU instr: 00.010341  000300  ZROX,NOP
545      >>CPU   reg: 00.006500  000000    X 000000, M i t r o c CCG
546      >>CPU fetch: 00.010343  041100    instruction fetch
547      >>CPU instr: 00.010342  020320  PLDA
548      >>CPU  data: 00.000000  001340    absolute read
549      >>CPU   reg: 00.006500  000001    A 001340, X 000000, M i t r o c CCG
550      >>CPU fetch: 00.010344  037777    instruction fetch
551      >>CPU instr: 00.010343  041100  LOAD DB+100
552      >>CPU  data: 00.002100  123003    data read
553      >>CPU   reg: 00.006500  000002    A 123003, B 001340, X 000000, M i t r o c CCL
554      >>CPU fetch: 00.010345  023404    instruction fetch
555      >>CPU instr: 00.010344  037777  ANDI 377
556      >>CPU   reg: 00.006500  000002    A 000003, B 001340, X 000000, M i t r o c CCG
557      >>CPU fetch: 00.010346  002043    instruction fetch
558      >>CPU instr: 00.010345  023404  MPYI 4
559      >>CPU   reg: 00.006500  000002    A 000014, B 001340, X 000000, M i t r o c CCG
560      >>CPU fetch: 00.010347  020320    instruction fetch
561 
562    The INSTR option traces instruction executions.  Each instruction is printed
563    before it is executed.  The two opcodes of a stack instruction are printed
564    together before the left-hand opcode is executed.  If the right-hand opcode
565    is not NOP, it is reprinted before execution, with dashes replacing the
566    just-executed left-hand opcode.
567 
568    The DATA option traces reads from and writes to memory.  Each access is
569    classified by the memory bank register that is paired with the specified
570    offset; they are: dma, absolute, program, data, and stack.  DMA accesses
571    derive their bank addresses from the banks specified in Set Bank I/O program
572    orders.  Absolute accesses always use bank 0.  Program, data, and stack
573    accesses use the bank addresses in the PBANK, DBANK, and SBANK registers,
574    respectively.
575 
576    The FETCH option traces instruction fetches from memory.  These accesses are
577    separated from those traced by the DATA option because fetches usually are of
578    little interest except when debugging the fetch/execute sequence.  Because
579    the HP 3000 has a two-stage pipeline, fetches load the NIR (Next Instruction
580    Register) with the instruction after the instruction to be executed from the
581    CIR (Current Instruction Register).
582 
583    The REG option traces register values.  Two sets of registers are printed.
584    After executing each instruction, the currently active TOS registers, the
585    index register, and the status register are printed.  After executing an
586    instruction that may alter the base registers, the program, data, and stack
587    segment base registers are printed.
588 
589    The OPND option traces memory byte operand values.  Some instructions take
590    memory and register operands that are difficult to decode from DATA or REG
591    traces.  This option presents these operands in a higher-level format.  The
592    memory bank and address values are always those of the operands.  The operand
593    data and values printed are specific to the instruction.  For example, the
594    ALGN instruction prints its source and target operands, digit counts, and
595    fraction counts, and the EDIT instruction displays its subprogram operations.
596 
597    The EXEC option traces the execution of instructions that match
598    user-specified criteria.  When a match occurs, all CPU trace options are
599    turned on for the duration of the execution of the matched instruction.  The
600    prior trace settings are restored when a match fails.  This option allows
601    detailed tracing of specified instructions while minimizing the log file size
602    compared to a full instruction trace.
603 
604    The PSERV option traces process clock event service entries.  Each trace
605    reports whether or not the CPU was executing on the Interrupt Control Stack
606    when the process clock ticked.  Execution on the ICS implies that the
607    operating system is executing.  As the process clock ticks every millisecond,
608    enabling PSERV tracing can quickly produce a large number of trace lines.
609 
610    The various trace formats are interpreted as follows:
611 
612      >>CPU instr: 00.010341  000300  ZROX,NOP
613                   ~~ ~~~~~~  ~~~~~~  ~~~~~~~~
614                   |    |       |       |
615                   |    |       |       +-- instruction mnemonic(s)
616                   |    |       +---------- octal data (instruction opcode)
617                   |    +------------------ octal address (P)
618                   +----------------------- octal bank (PBANK)
619 
620      >>CPU instr: 00.001240  000006  external interrupt
621      >>CPU instr: 00.023736  000000  unimplemented instruction trap
622                   ~~ ~~~~~~  ~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
623                   |    |       |       |
624                   |    |       |       +-- interrupt classification
625                   |    |       +---------- parameter
626                   |    +------------------ octal address (P) at interrupt
627                   +----------------------- octal bank (PBANK) at interrupt
628 
629 
630      >>CPU  data: 00.000000  001340    absolute read
631      >>CPU  data: 00.002100  123003    data read
632                   ~~ ~~~~~~  ~~~~~~    ~~~~~~~~~~~~~
633                   |    |       |         |
634                   |    |       |         +-- memory access classification
635                   |    |       +------------ octal data (memory contents)
636                   |    +-------------------- octal address (effective address)
637                   +------------------------- octal bank (PBANK, DBANK, or SBANK)
638 
639 
640      >>CPU fetch: 00.010342  020320    instruction fetch
641                   ~~ ~~~~~~  ~~~~~~    ~~~~~~~~~~~~~~~~~
642                   |    |       |         |
643                   |    |       |         +-- memory access classification
644                   |    |       +------------ octal data (instruction opcode)
645                   |    +-------------------- octal address (P + 1)
646                   +------------------------- octal bank (PBANK)
647 
648 
649      >>CPU   reg: 00.006500  000002    A 123003, B 001340, X 000000, M i t r o c CCL
650                   ~~ ~~~~~~  ~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
651                   |    |       |         |
652                   |    |       |         +-- register values (from 0-4 TOS registers, X, STA)
653                   |    |       +------------ octal stack register count (SR)
654                   |    +-------------------- octal stack memory address (SM)
655                   +------------------------- octal bank (SBANK)
656 
657      >>CPU   reg: 00.000000  000001    PB 010000, PL 025227, DL 001770, DB 002000, Q 006510, Z 007000
658                   ~~ ~~~~~~  ~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
659                   |    |       |         |
660                   |    |       |         +-- base register values
661                   |    |       +------------ current code segment number (from STA)
662                   |    +-------------------- zero
663                   +------------------------- octal bank (DBANK)
664 
665      >>CPU  opnd: 00.135771  000000    DFLC '+','!'
666      >>CPU  opnd: 00.045071  000252    target fraction 3 length 6,"002222"
667                   ~~ ~~~~~~  ~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
668                   |    |       |         |
669                   |    |       |         +-- operand-specific value
670                   |    |       +------------ operand-specific data
671                   |    +-------------------- octal address (effective address)
672                   +------------------------- octal bank (PBANK, DBANK, or SBANK)
673 
674      >>CPU pserv: Process clock delay 3970 service entered on the user stack
675 
676    The process clock offers a user-selectable choice of calibrated or realistic
677    timing.  Calibrated timing adjusts the clock to match actual elapsed time
678    (i.e., wall-clock time).  Realistic timing bases the process-clock interval
679    on machine instructions executed, using a mean instruction time of 2.5
680    microseconds.  Running on a typical host platform, the simulator is one or
681    two orders of magnitude faster than a real HP 3000, so the number of machine
682    instructions executed for a given calibrated time interval will be
683    correspondingly greater.  When the process clock is calibrated, the current
684    simulation speed, expressed as a multiple of the speed of a real HP 3000
685    Series III, may be obtained with the SHOW CPU SPEED command.  The speed
686    reported will not be representative if the machine was executing a PAUS
687    instruction when the simulator was stopped.
688 
689    When enabled by a SET CPU IDLE command, execution of a PAUS instruction will
690    idle the simulator.  While idle, the simulator does not use any host system
691    processor time.  Idle detection requires that the process clock and system
692    clock be set to calibrated timing.  Idling is disabled by default.
693 
694 
695    Implementation notes:
696 
697     1. Three timing sources in the simulator may be calibrated to wall-clock
698        time.  These are the process clock, the system clock, and the ATC poll
699        timer.  The process clock is always enabled and running, although the
700        PCLK register only increments if the CPU is not executing on the ICS.
701        The system clock and poll timer run continuously if their respective
702        devices are enabled.  If the ATC is disabled, then the process clock
703        takes over polling for the simulation console.
704 
705        The three sources must be synchronized to allow efficient simulator
706        idling.  This is accomplished by designating the process clock as the
707        master device, which calls the SCP timer calibration routines, and
708        setting the system clock and ATC poll timer to the process clock wait.
709        All three devices will then enter their respective service routines
710        concurrently.
711 
712     2. In hardware, the process clock period is fixed at one millisecond, and
713        the system clock period, while potentially variable, is set by MPE to one
714        millisecond with an interrupt every 100 ticks.  These periods are too
715        short to allow the simulator to idle, as the host OS clock resolution is
716        typically also one millisecond.
717 
718        Therefore, the process and system clock simulators are scheduled with
719        ten-millisecond service times, and the PCLK and counter registers are
720        incremented by ten for each event service.  To present the correct values
721        when the registers are read, the counts are incremented by amounts
722        proportional to the fractions of the service intervals that have elapsed
723        when the reads occur.
724 
725     3. In simulation, the TOS renamer is implemented by permanently assigning
726        the register names RA-RD to TR [0]-TR [3], respectively, and copying the
727        contents between registers to pop and push values.  An alternate
728        implementation approach is to use a renaming register, RN, that tracks
729        the correspondence between registers and array entries, and to assign the
730        register names dynamically using modular indices, e.g., RA is TR [RN], RB
731        is TR [(RN + 1) & 3], etc.  In lieu of copying, incrementing and
732        decrementing RN is done to pop and push values.
733 
734        Both implementations were mocked up and timing measurements made.  The
735        results were that copying values is much faster than mapping via array
736        index values, so this is the implementation chosen.
737 */
738 
739 
740 
741 #include "hp3000_defs.h"
742 #include "hp3000_cpu.h"
743 #include "hp3000_cpu_ims.h"
744 #include "hp3000_mem.h"
745 #include "hp3000_io.h"
746 
747 
748 
749 /* Program constants */
750 
751 #define PCLK_PERIOD         mS (1)                      /* 1 millisecond process clock period */
752 
753 #define PCLK_MULTIPLIER     10                          /* number of hardware process clock ticks per service */
754 #define PCLK_RATE           (1000 / PCLK_MULTIPLIER)    /* process clock rate in ticks per second */
755 
756 #define CPU_IO_RESET        0                           /* reset CPU and all I/O devices */
757 #define IO_RESET            1                           /* reset just the I/O devices */
758 
759 #define CNTL_BASE           8                           /* the radix for the cold dump control byte */
760 #define CNTL_MAX            0377                        /* the maximum cold dump control byte value */
761 #define DUMP_BANK_MASK      0017                        /* cold dump supports only 4-bit bank widths */
762 
763 #define SIO_JUMP            0000000u                    /* Jump unconditionally */
764 #define SIO_SBANK           0014000u                    /* Set bank */
765 #define SIO_ENDIN           0034000u                    /* End with interrupt */
766 #define SIO_CNTL            0040000u                    /* Control */
767 #define SIO_WRITE           0060000u                    /* Write 4096 words */
768 #define SIO_READ            0077760u                    /* Read 16 words */
769 
770 #define MS_CN_GAP           0000005u                    /* Write Gap */
771 #define MS_CN_WRR           0000004u                    /* Write Record */
772 #define MS_CN_RST           0000011u                    /* Rewind and Reset */
773 #define MS_CN_BSR           0000012u                    /* Backspace Record */
774 #define MS_CN_WFM           0000015u                    /* Write File Mark */
775 
776 #define MS_ST_PROTECTED     0001000u                    /* write protected */
777 #define MS_ST_READY         0000400u                    /* unit ready */
778 
779 #define MS_ST_MASK          (MS_ST_PROTECTED | MS_ST_READY)
780 
781 
782 /* CPU global SCP data definitions */
783 
784 DEVICE cpu_dev;                                 /* incomplete device structure */
785 
786 REG *sim_PC = NULL;                             /* the pointer to the P register */
787 
788 
789 /* CPU global data structures */
790 
791 
792 /* CPU registers */
793 
794 HP_WORD CIR    = 0;                             /* current instruction register */
795 HP_WORD NIR    = 0;                             /* next instruction register */
796 HP_WORD PB     = 0;                             /* program base register */
797 HP_WORD P      = 0;                             /* program counter register */
798 HP_WORD PL     = 0;                             /* program limit register */
799 HP_WORD PBANK  = 0;                             /* program segment bank register */
800 HP_WORD DL     = 0;                             /* data limit register */
801 HP_WORD DB     = 0;                             /* data base register */
802 HP_WORD DBANK  = 0;                             /* data segment bank register */
803 HP_WORD Q      = 0;                             /* stack marker register */
804 HP_WORD SM     = 0;                             /* stack memory register */
805 HP_WORD SR     = 0;                             /* stack register counter */
806 HP_WORD Z      = 0;                             /* stack limit register */
807 HP_WORD SBANK  = 0;                             /* stack segment bank register */
808 HP_WORD TR [4] = { 0, 0, 0, 0 };                /* top of stack registers */
809 HP_WORD X      = 0;                             /* index register */
810 HP_WORD STA    = 0;                             /* status register */
811 HP_WORD SWCH   = 0;                             /* switch register */
812 HP_WORD CPX1   = 0;                             /* run-mode interrupt flags register */
813 HP_WORD CPX2   = 0;                             /* halt-mode interrupt flags register */
814 HP_WORD MOD    = 0;                             /* module control register */
815 HP_WORD PCLK   = 0;                             /* process clock register */
816 HP_WORD CNTR   = 0;                             /* microcode counter */
817 
818 
819 /* Condition Code B lookup table.
820 
821    Byte-oriented instructions set the condition code in the status word using
822    Pattern B (CCB).  For this encoding:
823 
824      CCG = ASCII numeric character
825      CCE = ASCII alphabetic character
826      CCL = ASCII special character
827 
828    The simplest implementation of this pattern is a 256-way lookup table using
829    disjoint condition code flags.  The SET_CCB macro uses this table to set the
830    condition code appropriate for the supplied operand into the status word.
831 */
832 
833 const HP_WORD cpu_ccb_table [256] = {
834     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* NUL SOH STX ETX EOT ENQ ACK BEL */
835     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* BS  HT  LF  VT  FF  CR  SO  SI  */
836     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
837     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* CAN EM  SUB ESC FS  GS  RS  US  */
838     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* spa  !   "   #   $   %   &   '  */
839     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /*  (   )   *   +   ,   -   .   /  */
840     CFG, CFG, CFG, CFG, CFG, CFG, CFG, CFG,     /*  0   1   2   3   4   5   6   7  */
841     CFG, CFG, CFL, CFL, CFL, CFL, CFL, CFL,     /*  8   9   :   ;   <   =   >   ?  */
842     CFL, CFE, CFE, CFE, CFE, CFE, CFE, CFE,     /*  @   A   B   C   D   E   F   G  */
843     CFE, CFE, CFE, CFE, CFE, CFE, CFE, CFE,     /*  H   I   J   K   L   M   N   O  */
844     CFE, CFE, CFE, CFE, CFE, CFE, CFE, CFE,     /*  P   Q   R   S   T   U   V   W  */
845     CFE, CFE, CFE, CFL, CFL, CFL, CFL, CFL,     /*  X   Y   Z   [   \   ]   ^   _  */
846     CFL, CFE, CFE, CFE, CFE, CFE, CFE, CFE,     /*  `   a   b   c   d   e   f   g  */
847     CFE, CFE, CFE, CFE, CFE, CFE, CFE, CFE,     /*  h   i   j   k   l   m   n   o  */
848     CFE, CFE, CFE, CFE, CFE, CFE, CFE, CFE,     /*  p   q   r   s   t   u   v   w  */
849     CFE, CFE, CFE, CFL, CFL, CFL, CFL, CFL,     /*  x   y   z   {   |   }   ~  DEL */
850     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 200 - 207 */
851     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 210 - 217 */
852     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 220 - 227 */
853     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 230 - 237 */
854     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 240 - 247 */
855     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 250 - 257 */
856     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 260 - 267 */
857     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 270 - 277 */
858     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 300 - 307 */
859     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 310 - 317 */
860     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 320 - 327 */
861     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 330 - 337 */
862     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 340 - 347 */
863     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 350 - 357 */
864     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL,     /* 360 - 367 */
865     CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL      /* 370 - 377 */
866     };
867 
868 
869 /* CPU global state */
870 
871 jmp_buf     cpu_save_env;                       /* the saved environment for microcode aborts */
872 uint32      cpu_stop_flags;                     /* the simulation stop flag set */
873 
874 POWER_STATE cpu_power_state   = power_on;       /* the power supply state */
875 EXEC_STATE  cpu_micro_state   = halted;         /* the microcode execution state */
876 t_bool      cpu_base_changed  = FALSE;          /* TRUE if any base register is changed */
877 t_bool      cpu_is_calibrated = TRUE;           /* TRUE if the process clock is calibrated */
878 UNIT       *cpu_pclk_uptr     = &cpu_unit [0];  /* a (constant) pointer to the process clock unit */
879 
880 
881 /* CPU local state */
882 
883 static uint32  sim_stops      = 0;              /* the current simulation stop flag settings */
884 static uint32  cpu_speed      = 1;              /* the CPU speed, expressed as a multiplier of a real machine */
885 static uint32  pclk_increment = 1;              /* the process clock increment per event service */
886 static uint32  dump_control   = 0002006u;       /* the cold dump control word (default CNTL = 4, DEVNO = 6 */
887 static HP_WORD exec_mask      = 0;              /* the current instruction execution trace mask */
888 static HP_WORD exec_match     = D16_UMAX;       /* the current instruction execution trace matching value */
889 
890 
891 /* CPU local data structures */
892 
893 
894 /* Interrupt classification names */
895 
896 static const char *const interrupt_name [] = {  /* class names, indexed by IRQ_CLASS */
897     "integer overflow",                         /*   000 irq_Integer_Overflow */
898     "bounds violation",                         /*   001 irq_Bounds_Violation */
899     "illegal memory address error",             /*   002 irq_Illegal_Address  */
900     "non-responding module error",              /*   003 irq_Timeout          */
901     "system parity error",                      /*   004 irq_System_Parity    */
902     "address parity error",                     /*   005 irq_Address_Parity   */
903     "data parity error",                        /*   006 irq_Data_Parity      */
904     "module",                                   /*   007 irq_Module           */
905     "external",                                 /*   010 irq_External         */
906     "power fail",                               /*   011 irq_Power_Fail       */
907     "ICS trap",                                 /*   012 irq_Trap             */
908     "dispatch",                                 /*   013 irq_Dispatch         */
909     "exit"                                      /*   014 irq_IXIT             */
910     };
911 
912 
913 /* Trap classification names */
914 
915 static const char *const trap_name [] = {       /* trap names, indexed by TRAP_CLASS */
916     "no",                                       /*   000 trap_None                */
917     "bounds violation",                         /*   001 trap_Bounds_Violation    */
918     NULL,                                       /*   002 (unused)                 */
919     NULL,                                       /*   003 (unused)                 */
920     NULL,                                       /*   004 (unused)                 */
921     NULL,                                       /*   005 (unused)                 */
922     NULL,                                       /*   006 (unused)                 */
923     NULL,                                       /*   007 (unused)                 */
924     NULL,                                       /*   010 (unused)                 */
925     NULL,                                       /*   011 (unused)                 */
926     NULL,                                       /*   012 (unused)                 */
927     NULL,                                       /*   013 (unused)                 */
928     NULL,                                       /*   014 (unused)                 */
929     NULL,                                       /*   015 (unused)                 */
930     NULL,                                       /*   016 (unused)                 */
931     NULL,                                       /*   017 (unused)                 */
932     "unimplemented instruction",                /*   020 trap_Unimplemented       */
933     "STT violation",                            /*   021 trap_STT_Violation       */
934     "CST violation",                            /*   022 trap_CST_Violation       */
935     "DST violation",                            /*   023 trap_DST_Violation       */
936     "stack underflow",                          /*   024 trap_Stack_Underflow     */
937     "privileged mode violation",                /*   025 trap_Privilege_Violation */
938     NULL,                                       /*   026 (unused)                 */
939     NULL,                                       /*   027 (unused)                 */
940     "stack overflow",                           /*   030 trap_Stack_Overflow      */
941     "user",                                     /*   031 trap_User                */
942     NULL,                                       /*   032 (unused)                 */
943     NULL,                                       /*   033 (unused)                 */
944     NULL,                                       /*   034 (unused)                 */
945     NULL,                                       /*   035 (unused)                 */
946     NULL,                                       /*   036 (unused)                 */
947     "absent code segment",                      /*   037 trap_CS_Absent           */
948     "trace",                                    /*   040 trap_Trace               */
949     "STT entry uncallable",                     /*   041 trap_Uncallable          */
950     "absent data segment",                      /*   042 trap_DS_Absent           */
951     "power on",                                 /*   043 trap_Power_On            */
952     "cold load",                                /*   044 trap_Cold_Load           */
953     "system halt"                               /*   045 trap_System_Halt         */
954     };
955 
956 
957 /* CPU features table.
958 
959    The feature table is used to validate CPU feature changes within the subset
960    of features supported by a given CPU.  Features in the typical list are
961    enabled when the CPU model is selected.  If a feature appears in the typical
962    list but NOT in the optional list, then it is standard equipment and cannot
963    be disabled.  If a feature appears in the optional list, then it may be
964    enabled or disabled as desired by the user.
965 
966 
967    Implementation notes:
968 
969     1. The EIS was standard equipment for the Series II and III, althought it
970        was an option on the 3000 CX and Series I.
971 
972     2. The "Series III+" did not exist.  It is provided as an option to exercise
973        the full memory range of MPE-V/R, which can accommodate 6-bit bank
974        numbers.
975 */
976 
977 struct FEATURE_TABLE {
978     uint32      typ;                            /* standard features plus typically configured options */
979     uint32      opt;                            /* complete list of optional features */
980     uint32      maxmem;                         /* maximum configurable memory in 16-bit words */
981     uint32      bank_mask;                      /* memory bank register width mask */
982     };
983 
984 static const struct FEATURE_TABLE cpu_features [] = {   /* features indexed by CPU_MODEL */
985 /*  Standard       Optional          Maximum    Bank */
986 /*  Features       Features          Memory     Mask */
987 /*  --------  -------------------  -----------  ---- */
988   { UNIT_EIS, UNIT_EIS,             256 * 1024, 003 },  /* UNIT_SERIES_II */
989   { UNIT_EIS, UNIT_EIS | UNIT_CIS, 1024 * 1024, 017 },  /* UNIT_SERIES_III */
990   { UNIT_EIS, UNIT_EIS | UNIT_CIS, 4096 * 1024, 077 }   /* UNIT_SERIES_IIIX */
991   };
992 
993 
994 /* CPU local SCP support routine declarations */
995 
996 static t_stat cpu_service (UNIT   *uptr);
997 static t_stat cpu_reset   (DEVICE *dptr);
998 
999 static t_stat set_stops  (UNIT *uptr, int32 option,     char *cptr, void *desc);
1000 static t_stat set_exec   (UNIT *uptr, int32 option,     char *cptr, void *desc);
1001 static t_stat set_dump   (UNIT *uptr, int32 option,     char *cptr, void *desc);
1002 static t_stat set_size   (UNIT *uptr, int32 new_size,   char *cptr, void *desc);
1003 static t_stat set_model  (UNIT *uptr, int32 new_model,  char *cptr, void *desc);
1004 static t_stat set_option (UNIT *uptr, int32 new_option, char *cptr, void *desc);
1005 static t_stat set_pfars  (UNIT *uptr, int32 setting,    char *cptr, void *desc);
1006 
1007 static t_stat show_stops (FILE *st, UNIT *uptr, int32 val, void *desc);
1008 static t_stat show_exec  (FILE *st, UNIT *uptr, int32 val, void *desc);
1009 static t_stat show_dump  (FILE *st, UNIT *uptr, int32 val, void *desc);
1010 static t_stat show_speed (FILE *st, UNIT *uptr, int32 val, void *desc);
1011 
1012 
1013 /* CPU local utility routine declarations */
1014 
1015 static t_stat halt_mode_interrupt (HP_WORD device_number);
1016 static t_stat machine_instruction (void);
1017 static void   trace_registers     (void);
1018 
1019 
1020 /* CPU SCP data structures */
1021 
1022 
1023 /* Unit list.
1024 
1025    The CPU unit holds the main memory capacity and is used to schedule the
1026    process clock events.
1027 
1028 
1029    Implementation notes:
1030 
1031     1. The unit structure must be global for other modules to obtain the memory
1032        size via the MEMSIZE macro, which references the "capac" field.
1033 
1034     2. The initial CPU model must be present in the unit flags, because the
1035        "set_model" routine, which is called initially from "cpu_reset", depends
1036        on SCP to set the model flag when it is called to validate a SET CPU
1037        command.
1038 */
1039 
1040 #define UNIT_FLAGS          (UNIT_PFARS | UNIT_CALTIME | UNIT_SERIES_III)
1041 
1042 UNIT cpu_unit [] = {
1043     { UDATA (&cpu_service, UNIT_FLAGS | UNIT_FIX | UNIT_BINK | UNIT_IDLE, 0), PCLK_PERIOD * PCLK_MULTIPLIER }
1044     };
1045 
1046 
1047 /* Register list.
1048 
1049    The CPU register list exposes the machine registers for user inspection and
1050    modification.  User flags describe the permitted and default display formats,
1051    as follows:
1052 
1053      - REG_X  permits any symbolic display
1054      - REG_M  defaults to CPU instruction mnemonic display
1055      - REG_T  defaults to CPU status mnemonic display
1056 
1057 
1058    Implementation notes:
1059 
1060     1. The CNTR register is set to the value of the SR register when the
1061        micromachine halts or pauses.  This allows the SR value to be accessed by
1062        the diagnostics.  The top-of-stack registers are flushed to main memory
1063        when the machine halts or pauses, which alters SR.
1064 */
1065 
1066 static REG cpu_reg [] = {
1067 /*    Macro   Name     Location      Radix  Width  Offset       Flags      */
1068 /*    ------  -------  ------------  -----  -----  ------  --------------- */
1069     { ORDATA (CIR,     CIR,                  16),          REG_M | REG_RO  },  /* current instruction register */
1070     { ORDATA (NIR,     NIR,                  16),          REG_M | REG_RO  },  /* next instruction register */
1071     { ORDATA (PB,      PB,                   16),                          },  /* program base register */
1072     { ORDATA (P,       P,                    16),                          },  /* program counter register */
1073     { ORDATA (PL,      PL,                   16),                          },  /* program limit register */
1074     { ORDATA (PBANK,   PBANK,                 6),                          },  /* 6-bit program segment bank register */
1075     { ORDATA (DL,      DL,                   16),                          },  /* data limit register */
1076     { ORDATA (DB,      DB,                   16),                          },  /* data base register */
1077     { ORDATA (DBANK,   DBANK,                 6),                          },  /* 6-bit data segment bank register */
1078     { ORDATA (Q,       Q,                    16),                          },  /* stack marker register */
1079     { ORDATA (SM,      SM,                   16),                          },  /* stack memory register */
1080     { ORDATA (SR,      SR,                    3),                          },  /* stack register counter */
1081     { ORDATA (Z,       Z,                    16),                          },  /* stack limit register */
1082     { ORDATA (SBANK,   SBANK,                 6),                          },  /* 6-bit stack segment bank register */
1083     { ORDATA (RA,      TR [0],               16),          REG_X           },  /* top of stack register */
1084     { ORDATA (RB,      TR [1],               16),          REG_X           },  /* top of stack - 1 register */
1085     { ORDATA (RC,      TR [2],               16),          REG_X           },  /* top of stack - 2 register */
1086     { ORDATA (RD,      TR [3],               16),          REG_X           },  /* top of stack - 3 register */
1087     { ORDATA (X,       X,                    16),          REG_X           },  /* index register */
1088     { ORDATA (STA,     STA,                  16),          REG_T           },  /* status register */
1089     { ORDATA (SWCH,    SWCH,                 16),          REG_X           },  /* switch register */
1090     { ORDATA (CPX1,    CPX1,                 16),                          },  /* run-mode interrupt flags */
1091     { ORDATA (CPX2,    CPX2,                 16),                          },  /* halt-mode interrupt flags */
1092     { ORDATA (PCLK,    PCLK,                 16),                          },  /* process clock register */
1093     { ORDATA (CNTR,    CNTR,                  6),                 REG_HRO  },  /* microcode counter */
1094     { ORDATA (MOD,     MOD,                  16),                 REG_HRO  },  /* module control register */
1095 
1096     { DRDATA (POWER,   cpu_power_state,       2),                 REG_HRO  },  /* system power supply state */
1097     { ORDATA (WRU,     sim_int_char,          8),                 REG_HRO  },  /* SCP interrupt character */
1098     { ORDATA (BRK,     sim_brk_char,          8),                 REG_HRO  },  /* SCP break character */
1099     { ORDATA (DEL,     sim_del_char,          8),                 REG_HRO  },  /* SCP delete character */
1100 
1101     { NULL }
1102     };
1103 
1104 
1105 /* Modifier list */
1106 
1107 static MTAB cpu_mod [] = {
1108 /*    Mask Value    Match Value       Print String         Match String  Validation   Display  Descriptor */
1109 /*    ------------  ---------------   -------------------  ------------  -----------  -------  ---------- */
1110     { UNIT_MODEL,   UNIT_SERIES_II,   "Series II",         NULL,         &set_model,  NULL,    NULL       },
1111     { UNIT_MODEL,   UNIT_SERIES_III,  "Series III",        "III",        &set_model,  NULL,    NULL       },
1112     { UNIT_MODEL,   UNIT_SERIES_IIIX, "Series III+",       "III+",       &set_model,  NULL,    NULL       },
1113 
1114     { UNIT_EIS,     UNIT_EIS,         "EIS",               "EIS",        &set_option, NULL,    NULL       },
1115     { UNIT_EIS,     0,                "no EIS",            "NOEIS",      NULL,        NULL,    NULL       },
1116 
1117     { UNIT_CIS,     UNIT_CIS,         "CIS",               "CIS",        &set_option, NULL,    NULL       },
1118     { UNIT_CIS,     0,                "no CIS",            "NOCIS",      NULL,        NULL,    NULL       },
1119 
1120     { UNIT_PFARS,   UNIT_PFARS,       "auto-restart",      "ARS",        &set_pfars,  NULL,    NULL       },
1121     { UNIT_PFARS,   0,                "no auto-restart",   "NOARS",      &set_pfars,  NULL,    NULL       },
1122 
1123     { UNIT_CALTIME, UNIT_CALTIME,     "calibrated timing", "CALTIME",    NULL,        NULL,    NULL       },
1124     { UNIT_CALTIME, 0,                "realistic timing",  "REALTIME",   NULL,        NULL,    NULL       },
1125 
1126 /*    Entry Flags             Value     Print String  Match String  Validation     Display         Descriptor */
1127 /*    -------------------  -----------  ------------  ------------  -------------  --------------  ---------- */
1128     { MTAB_XDV,             128 * 1024, NULL,         "128K",       &set_size,     NULL,           NULL       },
1129     { MTAB_XDV,             256 * 1024, NULL,         "256K",       &set_size,     NULL,           NULL       },
1130     { MTAB_XDV,             384 * 1024, NULL,         "384K",       &set_size,     NULL,           NULL       },
1131     { MTAB_XDV,             512 * 1024, NULL,         "512K",       &set_size,     NULL,           NULL       },
1132     { MTAB_XDV,             768 * 1024, NULL,         "768K",       &set_size,     NULL,           NULL       },
1133     { MTAB_XDV,            1024 * 1024, NULL,         "1024K",      &set_size,     NULL,           NULL       },
1134     { MTAB_XDV,            2048 * 1024, NULL,         "2048K",      &set_size,     NULL,           NULL       },
1135     { MTAB_XDV,            4096 * 1024, NULL,         "4096K",      &set_size,     NULL,           NULL       },
1136 
1137     { MTAB_XDV,                 0,      "IDLE",       "IDLE",       &sim_set_idle, &sim_show_idle, NULL       },
1138     { MTAB_XDV,                 0,      NULL,         "NOIDLE",     &sim_clr_idle, NULL,           NULL       },
1139 
1140     { MTAB_XDV | MTAB_NMO,      0,      "DUMP",       "DUMPDEV",    &set_dump,     &show_dump,     NULL       },
1141     { MTAB_XDV,                 1,      NULL,         "DUMPCTL",    &set_dump,     NULL,           NULL       },
1142 
1143     { MTAB_XDV | MTAB_NMO,      1,      "STOPS",      "STOP",       &set_stops,    &show_stops,    NULL       },
1144     { MTAB_XDV,                 0,      NULL,         "NOSTOP",     &set_stops,    NULL,           NULL       },
1145 
1146     { MTAB_XDV | MTAB_NMO,      1,      "EXEC",       "EXEC",       &set_exec,     &show_exec,     NULL       },
1147     { MTAB_XDV,                 0,      NULL,         "NOEXEC",     &set_exec,     NULL,           NULL       },
1148 
1149     { MTAB_XDV | MTAB_NMO,      0,      "SPEED",      NULL,         NULL,          &show_speed,    NULL       },
1150 
1151     { 0 }
1152     };
1153 
1154 
1155 /* Debugging trace list */
1156 
1157 static DEBTAB cpu_deb [] = {
1158     { "INSTR", DEB_INSTR  },                    /* instructions */
1159     { "DATA",  DEB_MDATA  },                    /* memory data accesses */
1160     { "FETCH", DEB_MFETCH },                    /* memory instruction fetches */
1161     { "REG",   DEB_REG    },                    /* register values */
1162     { "OPND",  DEB_MOPND  },                    /* memory operand values */
1163     { "EXEC",  DEB_EXEC   },                    /* instruction execution states */
1164     { "PSERV", DEB_PSERV  },                    /* process clock service events */
1165     { NULL,    0          }
1166     };
1167 
1168 /* Debugging stop list */
1169 
1170 static DEBTAB cpu_stop [] = {
1171     { "LOOP",   SS_LOOP   },                    /* stop on an infinite loop */
1172     { "PAUSE",  SS_PAUSE  },                    /* stop on a PAUS instruction */
1173     { "UNDEF",  SS_UNDEF  },                    /* stop on an undefined instruction */
1174     { "UNIMPL", SS_UNIMPL },                    /* stop on an unimplemented instruction */
1175     { NULL,     0         }
1176     };
1177 
1178 
1179 /* Device descriptor */
1180 
1181 DEVICE cpu_dev = {
1182     "CPU",                                      /* device name */
1183     cpu_unit,                                   /* unit array */
1184     cpu_reg,                                    /* register array */
1185     cpu_mod,                                    /* modifier array */
1186     1,                                          /* number of units */
1187     8,                                          /* address radix */
1188     PA_WIDTH,                                   /* address width */
1189     1,                                          /* address increment */
1190     8,                                          /* data radix */
1191     16,                                         /* data width */
1192     &mem_examine,                               /* examine routine */
1193     &mem_deposit,                               /* deposit routine */
1194     &cpu_reset,                                 /* reset routine */
1195     NULL,                                       /* boot routine */
1196     NULL,                                       /* attach routine */
1197     NULL,                                       /* detach routine */
1198     NULL,                                       /* device information block pointer */
1199     DEV_DEBUG,                                  /* device flags */
1200     0,                                          /* debug control flags */
1201     cpu_deb,                                    /* debug flag name array */
1202     NULL,                                       /* memory size change routine */
1203     NULL                                        /* logical device name */
1204     };
1205 
1206 
1207 
1208 /* CPU global SCP support routines */
1209 
1210 
1211 /* Execute CPU instructions.
1212 
1213    This is the instruction decode routine for the HP 3000.  It is called from
1214    the simulator control program to execute instructions in simulated memory,
1215    starting at the simulated program counter.  It runs until the status to be
1216    returned is set to a value other than SCPE_OK.
1217 
1218    On entry, P points to the instruction to execute, and the "sim_switches"
1219    global contains any command-line switches included with the run command.  On
1220    exit, P points at the next instruction to execute (or the current
1221    instruction, in the case of a simulator stop during a PAUS instruction or
1222    after the first of two stack operations).
1223 
1224    Execution is divided into four phases.
1225 
1226    First, the instruction prelude configures the simulation state to resume
1227    execution.  This involves verifying that system power is on and there are no
1228    device conflicts (e.g., two devices with the same device number),
1229    initializing the I/O processor and channels, and setting the RUN switch if no
1230    other front panel switches are pressed.  These actions accommodate
1231    reconfiguration of the I/O device settings and program counter while the
1232    simulator was stopped.  The prelude also responds to one command-line switch:
1233    if "-B" is specified, the current set of simulation stop conditions is
1234    bypassed for the first instruction executed.  This allows, e.g., a PAUS
1235    instruction to be bypassed or an unimplemented instruction trap to be taken.
1236 
1237    Second, the microcode abort mechanism is set up.  Microcode aborts utilize
1238    the "setjmp/longjmp" mechanism to transfer control out of the instruction
1239    executors without returning through the call stack.  This allows an
1240    instruction to be aborted part-way through execution when continuation is
1241    impossible, e.g., due to a memory access violation.  It corresponds to direct
1242    microcode jumps out of the execution sequence and to the appropriate trap
1243    handlers.
1244 
1245    Third, the instruction execution loop decodes instructions and calls the
1246    individual executors in turn until a condition occurs that prevents further
1247    execution.  Examples of such conditions includes execution of a HALT
1248    instruction, a user stop request (CTRL+E) from the simulation console, a
1249    recoverable device error (such as an improperly formatted tape image), a
1250    user-specified breakpoint, and a simulation stop condition (such as execution
1251    of an unimplemented instruction).  The execution loop also polls for I/O
1252    events and device interrupts, and runs I/O channel cycles.  During
1253    instruction execution, the CIR register contains the currently executing
1254    instruction, the NIR register contains the next instruction to execute, and
1255    the P register points to the memory location two instructions ahead of the
1256    current instruction.
1257 
1258    Fourth, the instruction postlude updates the simulation state in preparation
1259    for returning to the SCP command prompt.  Devices that maintain an internal
1260    state different from their external state, such as the CPU process clock, are
1261    updated so that their internal and external states are fully consistent.
1262    This ensures that the state visible to the user during the simulation stop is
1263    correct.  It also ensures that the program counter points correctly at the
1264    next instruction to execute upon resumption.
1265 
1266    If enabled, the simulator is idled when a PAUS instruction has been executed
1267    and no service requests for the multiplexer or selector channels are active.
1268    Execution of a PAUS instruction suspends the fetch-and-execute process until
1269    an interrupt occurs or the simulator is stopped and then resumed with a GO -B
1270    or RUN -B command.
1271 
1272    The HP 3000 is a microcoded machine.  In hardware, the micromachine is always
1273    executing microinstructions, even when the CPU is "halted."  The halt/run
1274    state is simply a flip-flop setting, reflected in bit 15 of the CPX2
1275    register and the RUN light on the front panel, that determines whether the
1276    "halt-mode" or "run-mode" microprogram is currently executing.
1277 
1278    In simulation, the "cpu_micro_state" variable indicates the state of the
1279    micromachine, i.e., which section of the microcode it is executing, while
1280    CPX2 bit 15 indicates whether the macromachine is halted or running.  The
1281    micromachine may be in one of four states:
1282 
1283      - running : the run-mode fetch-and-execute microcode is executing
1284      - paused  : the run-mode PAUS instruction microcode is executing
1285      - waiting : the halt-mode cold load or dump microcode is executing
1286      - halted  : the halt-mode front panel microcode is executing
1287 
1288    Simulation provides a variety of stop conditions that break instruction
1289    execution and return to the SCP prompt with the CPU still in run mode.  These
1290    have no analog in hardware; the only way to stop the CPU is to press the HALT
1291    button on the front panel, which shifts the micromachine into halt-mode
1292    microcode execution.  When any of these conditions occur, the micromachine
1293    state is set to "halted," but the CPX2 run flag is remains set unless the
1294    stop was caused by execution of a HALT instruction.  Resuming execution with
1295    a STEP, CONT, GO, or RUN command proceeds as though the hardware RUN switch
1296    was pressed after a programmed halt.  This provides the proper semantics for
1297    seamlessly stopping and restarting instruction execution.
1298 
1299    A microcode abort is performed by executing a "longjmp" to the abort handler,
1300    which is outside of and precedes the instruction execution loop.  The value
1301    passed to "longjmp" is a 32-bit integer containing the Segment Transfer Table
1302    index of the trap handler in the lower word and an optional parameter in the
1303    upper word.  Aborts are invoked by the MICRO_ABORT macro, which takes as its
1304    parameter a trap classification value, e.g.:
1305 
1306      MICRO_ABORT (trap_Privilege_Violation);
1307      MICRO_ABORT (trap_Integer_Zero_Divide);
1308 
1309    Some aborts require an additional parameter and must be invoked by the
1310    MICRO_ABORTP macro, which takes a trap classification value and a
1311    trap-specific value as parameters.  The traps that require additional
1312    parameters are:
1313 
1314      MICRO_ABORTP (trap_CST_Violation, segment_number);
1315      MICRO_ABORTP (trap_STT_Violation, segment_number);
1316      MICRO_ABORTP (trap_CS_Absent,     label/n/0);
1317      MICRO_ABORTP (trap_DS_Absent,     DST_number);
1318      MICRO_ABORTP (trap_Uncallable,    label);
1319      MICRO_ABORTP (trap_Trace,         label/n/0);
1320      MICRO_ABORTP (trap_User,          trap_number);
1321 
1322    trap_User is not usually called explicitly via MICRO_ABORTP; rather,
1323    MICRO_ABORT is used with one of the specific user-trap identifiers, e.g.,
1324    trap_Integer_Overflow, trap_Float_Overflow, trap_Decimal_Overflow, etc., that
1325    supplies both the trap classification and the trap parameter value.
1326 
1327    In addition, user traps must be enabled by setting the T-bit in the status
1328    word.  If the T bit is not set, a user trap sets the O-bit (overflow) in the
1329    status word and resumes execution with the next instruction instead of
1330    invoking the user trap handler.
1331 
1332    When an abort occurs, an equivalent PCAL to the appropriate STT entry is set
1333    up.  Then execution drops into the instruction loop to execute the first
1334    instruction of the trap handler.
1335 
1336    When the instruction loop is exited, the CPU process clock and system clock
1337    registers are updated, the micromachine is halted, and control returns to
1338    SCP.  Upon return, P points at the next instruction to execute, i.e., the
1339    instruction that will execute when the instruction loop is reentered.
1340 
1341    If the micromachine is paused, then P is reset to point to the PAUS
1342    instruction, which will be reexecuted when the routine is reentered.  If it
1343    is running, then P is reset to point to the current instruction if the stop
1344    allows it to be rerun, or at the next instruction.
1345 
1346 
1347    Implementation notes:
1348 
1349     1. While the Microsoft VC++ "setjmp" documentation says, "All variables
1350        (except register variables) accessible to the routine receiving control
1351        contain the values they had when longjmp was called," the ISO C99
1352        standard says, "All accessible objects have values...as of the time the
1353        longjmp function was called, except that the values of objects of
1354        automatic storage duration that are local to the function containing the
1355        invocation of the corresponding setjmp macro that do not have
1356        volatile-qualified type and have been changed between the setjmp
1357        invocation and longjmp call are indeterminate."
1358 
1359        Therefore, the "device" and "status" variables are marked volatile to
1360        ensure that they are reloaded after a longjmp caused by a micrcode abort.
1361 
1362     2. In hardware, the NEXT microcode order present at the end of each
1363        instruction transfers the NIR content to the CIR, reads the memory word
1364        at P into the NIR, and increments P.  However, if an interrupt is
1365        present, then this action is omitted, and a microcode jump is performed
1366        to control store location 3, which then jumps to the microcoded interrupt
1367        handler.  In simulation, the CIR/NIR/P update is performed before the
1368        next instruction is executed, rather than after the last instruction
1369        completes, so that interrupts are handled before updating.
1370 
1371        In addition, the NEXT action is modified in hardware if the NIR contains
1372        a stack instruction with a non-NOP B stackop.  In this case, NEXT
1373        transfers the NIR content to the CIR, reads the memory word at P into the
1374        NIR, but does not increment P.  Instead, the R bit of the status register
1375        is set to indicate that a B stackop is pending.  When the NEXT at the
1376        completion of the A stackop is executed, the NIR and CIR are untouched,
1377        but P is incremented, and the R bit is cleared.  This ensures that if an
1378        interrupt or trap occurs between the stackops, P will point correctly at
1379        the next instruction to be executed.
1380 
1381        In simulation, following the hardware would require testing the NIR for a
1382        non-NOP B stackop at every pass through the instruction execution loop.
1383        To avoid this, the NEXT simulation unilaterally increments P, rather than
1384        only when a B stackop is not present, and the stack instruction executor
1385        tests for the B stackop and sets the R bit there.  However, by that time,
1386        P has already been incremented, so we decrement it there to return it to
1387        the correct value.
1388 
1389     3. The System Halt trap has no handler.  Instead, the simulator is halted,
1390        and control returns to the SCP prompt.
1391 
1392     4. The trace display for a trap reports the parameter value supplied with
1393        the microcode abort.  This is not necessarily the same as the parameter
1394        that is pushed on the stack for the trap handler.  As some traps, e.g.,
1395        trap_CST_Violation, can cause a System Halt, the placement of the trace
1396        call is dictated by the desire to report both the original trap and the
1397        System Halt trap, even though the placement results in the display of the
1398        incoming parameter value, rather than the stacked parameter value.
1399 
1400     5. The execution trace (DEB_EXEC) match test is performed in two parts to
1401        display the register values both before and after the instruction
1402        execution.  Consequently, the enable test is done before the register
1403        trace, and the disable test is done after.
1404 
1405     6. The execution test (exec_test) is set FALSE even though execution tracing
1406        is not specified.  This is done solely to reassure the compiler that the
1407        value is not clobbered by a longjmp call.
1408 
1409     7. The set of debug trace flags is restored in the postlude (and therefore
1410        also saved in the instruction prelude) to ensure that a simulation stop
1411        that occurs while an execution trace is in progress does not exit with
1412        the flags set improperly.
1413 
1414     8. The breakpoint test must be executed even when the CPU pauses to permit
1415        string breakpoint delays to expire.
1416 */
1417 
sim_instr(void)1418 t_stat sim_instr (void)
1419 {
1420 int        abortval;
1421 HP_WORD    label, parameter;
1422 TRAP_CLASS trap;
1423 t_bool     exec_test;
1424 volatile   uint32  debug_save;
1425 volatile   HP_WORD device;
1426 volatile   t_stat  status = SCPE_OK;
1427 
1428 
1429 /* Instruction prelude */
1430 
1431 debug_save = cpu_dev.dctrl;                             /* save the current set of debug flags for later restoration */
1432 
1433 if (sim_switches & SWMASK ('B'))                        /* if a simulation stop bypass was requested */
1434     cpu_stop_flags = SS_BYPASSED;                       /*   then clear the stop flags for the first instruction */
1435 else                                                    /* otherwise */
1436     cpu_stop_flags = sim_stops;                         /*   set the stops as indicated */
1437 
1438 if (cpu_power_state == power_off)                       /* if system power is off */
1439     status = STOP_POWER;                                /*   then execution is not possible until restoration */
1440 
1441 else if (hp_device_conflict ())                         /* otherwise if device assignment is inconsistent */
1442     status = SCPE_STOP;                                 /*   then inhibit execution */
1443 
1444 else {                                                  /* otherwise */
1445     device = iop_initialize ();                         /*   initialize the IOP */
1446     mpx_initialize ();                                  /*     and the multiplexer channel */
1447     sel_initialize ();                                  /*       and the selector channel */
1448 
1449     if ((CPX2 & CPX2_IRQ_SET) == 0)                     /* if no halt-mode interrupt is present */
1450         CPX2 |= cpx2_RUNSWCH;                           /*   then assume a RUN command via STEP/CONT */
1451     }
1452 
1453 
1454 /* Microcode abort processor */
1455 
1456 abortval = setjmp (cpu_save_env);                       /* set the microcode abort handler */
1457 
1458 if (abortval) {                                         /* if a microcode abort occurred */
1459     trap = TRAP (abortval);                             /*   then get the trap classification */
1460     parameter = PARAM (abortval);                       /*     and the optional parameter */
1461 
1462     label = TO_LABEL (LABEL_IRQ, trap);                 /* form the label from the STT number */
1463 
1464     if (cpu_dev.dctrl & DEB_REG)                        /* if register tracing is enabled */
1465         trace_registers ();                             /*   then show the registers just before the trap */
1466 
1467     tprintf (cpu_dev, DEB_INSTR, BOV_FORMAT "%s trap%s\n",
1468              PBANK, P - 1 & R_MASK, parameter, trap_name [trap],
1469              (trap == trap_User && !(STA & STATUS_T) ? " (disabled)" : ""));
1470 
1471     switch (trap) {                                     /* dispatch on the trap classification */
1472 
1473         case trap_None:                                 /* trap_None should never occur */
1474         case trap_System_Halt:
1475             CNTR = SR;                                  /* copy the stack register to the counter */
1476             cpu_flush ();                               /*   and flush the TOS registers to memory */
1477 
1478             RA = parameter;                             /* set RA to the parameter (system halt condition) */
1479 
1480             CPX2 = CPX2 & ~cpx2_RUN | cpx2_SYSHALT;     /* halt the CPU and set the system halt flag */
1481             status = STOP_SYSHALT;                      /*   and report the system halt condition */
1482 
1483             label = 0;                                  /* there is no trap handler for a system halt */
1484             break;
1485 
1486 
1487         case trap_CST_Violation:
1488             if (STT_SEGMENT (parameter) <= ISR_SEGMENT) /* if the trap occurred in segment 1 */
1489                 MICRO_ABORT (trap_SysHalt_CSTV_1);      /*   then the failure is fatal */
1490 
1491         /* fall through into the next trap handler */
1492 
1493         case trap_STT_Violation:
1494             if (STT_SEGMENT (parameter) <= ISR_SEGMENT) /* if the trap occurred in segment 1 */
1495                 MICRO_ABORT (trap_SysHalt_STTV_1);      /*   then the failure is fatal */
1496 
1497         /* fall through into the next trap handler */
1498 
1499         case trap_Unimplemented:
1500         case trap_DST_Violation:
1501         case trap_Stack_Underflow:
1502         case trap_Privilege_Violation:
1503         case trap_Bounds_Violation:
1504             parameter = label;                          /* the label is the parameter for these traps */
1505 
1506         /* fall through into the next trap handler */
1507 
1508         case trap_DS_Absent:
1509             cpu_flush ();                               /* flush the TOS registers to memory */
1510             cpu_mark_stack ();                          /*   and then write a stack marker */
1511 
1512         /* fall through into the next trap handler */
1513 
1514         case trap_Uncallable:
1515             break;                                      /* set up the trap handler */
1516 
1517 
1518         case trap_User:
1519             if (STA & STATUS_T) {                       /* if user traps are enabled */
1520                 STA &= ~STATUS_O;                       /*   then clear overflow status */
1521                 cpu_flush ();                           /*     and flush the TOS registers to memory */
1522                 cpu_mark_stack ();                      /*       and write a stack marker */
1523                 }                                       /*         and set up the trap handler */
1524 
1525             else {                                      /* otherwise in lieu of trapping */
1526                 STA |= STATUS_O;                        /*   set overflow status */
1527                 label = 0;                              /*     and continue execution with the next instruction */
1528                 }
1529             break;
1530 
1531 
1532         case trap_CS_Absent:
1533             if (CPX1 & cpx1_ICSFLAG)                    /* if the trap occurred while on the ICS */
1534                 MICRO_ABORT (trap_SysHalt_Absent_ICS);  /*   then the failure is fatal */
1535 
1536             else if (STT_SEGMENT (STA) <= ISR_SEGMENT)  /* otherwise if the trap occurred in segment 1 */
1537                 MICRO_ABORT (trap_SysHalt_Absent_1);    /*   then the failure is fatal */
1538             break;                                      /* otherwise set up the trap handler */
1539 
1540 
1541         case trap_Trace:
1542             if (STT_SEGMENT (STA) <= ISR_SEGMENT)       /* if the trap occurred in segment 1 */
1543                 MICRO_ABORT (trap_SysHalt_Trace_1);     /*   then the failure is fatal */
1544             break;                                      /* otherwise set up the trap handler */
1545 
1546 
1547         case trap_Cold_Load:                            /* this trap executes on the ICS */
1548             status = STOP_CLOAD;                        /* report that the cold load is complete */
1549 
1550         /* fall through into trap_Stack_Overflow */
1551 
1552         case trap_Stack_Overflow:                           /* this trap executes on the ICS */
1553             if (CPX1 & cpx1_ICSFLAG)                        /*   so if the trap occurred while on the ICS */
1554                 MICRO_ABORT (trap_SysHalt_Overflow_ICS);    /*     then the failure is fatal */
1555 
1556             cpu_setup_ics_irq (irq_Trap, trap);             /* otherwise, set up the ICS */
1557             break;                                          /*   and then the trap handler */
1558 
1559 
1560         case trap_Power_On:                             /* this trap executes on the ICS */
1561             cpu_setup_ics_irq (irq_Trap, trap);         /*   so set it up */
1562             cpu_power_state = power_on;                 /*     and return to the power-on state */
1563 
1564             if (CPX2 & cpx2_INHPFARS)                   /* if auto-restart is inhibited */
1565                 status = STOP_ARSINH;                   /*   then exit and wait for a manual restart */
1566             break;
1567         }                                               /* all cases are handled */
1568 
1569 
1570     if (label != 0) {                                   /* if the trap handler is to be called */
1571         STA = STATUS_M;                                 /*   then clear the status and enter privileged mode */
1572 
1573         SM = SM + 1 & R_MASK;                           /* increment the stack pointer */
1574         cpu_write_memory (stack, SM, parameter);        /*   and push the parameter on the stack */
1575 
1576         X = CIR;                                        /* save the current instruction for restarting */
1577 
1578         cpu_call_procedure (label, 0);                  /* set up PB, P, PL, and STA to call the procedure */
1579 
1580         cpu_base_changed = TRUE;                        /* one or more base registers have changed */
1581         }
1582 
1583     sim_interval = sim_interval - 1;                    /* count the execution cycle that aborted */
1584     }
1585 
1586 
1587 /* Instruction loop */
1588 
1589 while (status == SCPE_OK) {                             /* execute until simulator status prevents continuation */
1590 
1591     if (sim_interval <= 0) {                            /* if an event timeout has expired */
1592         status = sim_process_event ();                  /*   then call the event service */
1593 
1594         if (status != SCPE_OK)                          /* if the service failed */
1595             break;                                      /*   then abort execution and report the failure */
1596         }
1597 
1598     if (sel_request)                                    /* if a selector channel request is pending */
1599         sel_service (1);                                /*   then service it */
1600 
1601     if (mpx_request_set)                                /* if a multiplexer channel request is pending */
1602         mpx_service (1);                                /*   then service it */
1603 
1604     if (iop_interrupt_request_set                       /* if a hardware interrupt request is pending */
1605       && STA & STATUS_I                                 /*   and interrupts are enabled */
1606       && CIR != SED_1)                                  /*     and not deferred by a SED 1 instruction */
1607         device = iop_poll ();                           /*       then poll to acknowledge the request */
1608 
1609     if (cpu_micro_state != halted                       /* if the micromachine is not halted */
1610       && sim_brk_summ != 0                              /*   and a breakpoint exists */
1611       && sim_brk_test (TO_PA (PBANK, P - 1 & LA_MASK),  /*     at the next location */
1612                        BP_EXEC)) {                      /*       to be executed */
1613         status = STOP_BRKPNT;                           /*         then stop the simulation */
1614         sim_interval = sim_interval + 1;                /*           and don't count the cycle */
1615         }
1616 
1617     else if (cpu_micro_state == running)                /* otherwise if the micromachine is running */
1618         if (CPX1 & CPX1_IRQ_SET                         /*   then if a run-mode interrupt is pending */
1619           && cpu_power_state != power_failing)          /*     and power is not currently failing */
1620             cpu_run_mode_interrupt (device);            /*       then service it */
1621 
1622         else {                                              /* otherwise execute the next instruction */
1623             if (TRACING (cpu_dev, DEB_EXEC | DEB_REG)) {    /* if execution or register tracing is enabled */
1624                 if (cpu_dev.dctrl & DEB_EXEC)               /*   then if tracing execution */
1625                     if (STA & STATUS_R)                     /*     then if the right-hand stack op is pending */
1626                         exec_test =                         /*       then the execution test succeeds if */
1627                            (CIR << STACKOP_A_SHIFT          /*         the right-hand stack op */
1628                              & STACKOP_A_MASK               /*           matches the test criteria */
1629                              & exec_mask) == exec_match;    /*             for the left-hand stack op value */
1630                     else                                    /*     otherwise */
1631                         exec_test =                         /*       then the execution test succeeds if */
1632                            (NIR & exec_mask) == exec_match; /*         the next instruction matches the test criteria */
1633                 else                                        /*   otherwise */
1634                     exec_test = FALSE;                      /*     there is no execution test */
1635 
1636                 if (cpu_dev.dctrl & DEB_EXEC                /* if execution tracing is enabled */
1637                   && cpu_dev.dctrl != DEB_ALL               /*   and is currently inactive */
1638                   && exec_test) {                           /*     and the matching test succeeds */
1639                     debug_save = cpu_dev.dctrl;             /*       then save the current trace flag set */
1640                     cpu_dev.dctrl = DEB_ALL;                /*         and turn on full tracing */
1641                     }
1642 
1643                 if (cpu_dev.dctrl & DEB_REG)                /* if register tracing is enabled */
1644                     trace_registers ();                     /*   then print the registers */
1645 
1646                 if (cpu_dev.dctrl & DEB_EXEC                /* if execution tracing is enabled */
1647                   && cpu_dev.dctrl == DEB_ALL               /*   and is currently active */
1648                   && ! exec_test) {                         /*     and the matching test fails */
1649                     cpu_dev.dctrl = debug_save;             /*       then restore the saved debug flag set */
1650                     hp_trace (&cpu_dev, DEB_EXEC,           /*         and add a separator to the trace log */
1651                               "*****************\n");
1652                     }
1653                 }
1654 
1655             if (!(STA & STATUS_R)) {                    /* (NEXT) if the right-hand stack op is not pending */
1656                 CIR = NIR;                              /*   then update the current instruction */
1657                 cpu_read_memory (fetch, P, &NIR);       /*     and load the next instruction */
1658                 }
1659 
1660             P = P + 1 & R_MASK;                         /* point to the following instruction */
1661 
1662             if (TRACING (cpu_dev, DEB_INSTR)) {             /* if instruction tracing is enabled */
1663                 sim_eval [0] = CIR;                         /*   then save the instruction that will be executed */
1664                 sim_eval [1] = NIR;                         /*     and the following word for evaluation */
1665 
1666                 hp_trace (&cpu_dev, DEB_INSTR, BOV_FORMAT,  /* print the address and the instruction opcode */
1667                           PBANK, P - 2 & R_MASK, CIR);      /*   as an octal value */
1668 
1669                 if (fprint_cpu (sim_deb, sim_eval, 0, SIM_SW_STOP) == SCPE_ARG) /* print the mnemonic; if that fails */
1670                     fprint_val (sim_deb, sim_eval [0], cpu_dev.dradix,          /*   then print the numeric */
1671                                 cpu_dev.dwidth, PV_RZRO);                       /*     value again */
1672 
1673                 if (sim_deb == stdout)                      /* if debug output is to the (raw) console */
1674                     fputc ('\r', sim_deb);                  /*   then insert a carriage return */
1675 
1676                 fputc ('\n', sim_deb);                      /* end the trace with a newline */
1677                 }
1678 
1679             status = machine_instruction ();            /* execute one machine instruction */
1680 
1681             cpu_stop_flags = sim_stops;                 /* reset the stop flags as indicated */
1682             }
1683 
1684     else if (cpu_micro_state == paused) {               /* otherwise if the micromachine is paused */
1685         if (CPX1 & CPX1_IRQ_SET)                        /*   then if a run-mode interrupt is pending */
1686             cpu_run_mode_interrupt (device);            /*     then service it */
1687 
1688         else if (sim_idle_enab                          /*   otherwise if idling is enabled */
1689           && ! sel_request && mpx_request_set == 0)     /*     and there are no channel requests pending */
1690             sim_idle (TMR_PCLK, FALSE);                 /*       then idle the simulator */
1691         }
1692 
1693     else if (CPX2 & CPX2_IRQ_SET)                       /* otherwise if a halt-mode interrupt is pending */
1694         status = halt_mode_interrupt (device);          /*   then service it */
1695 
1696     sim_interval = sim_interval - 1;                    /* count the execution cycle */
1697     }                                                   /*   and continue with the instruction loop */
1698 
1699 
1700 /* Instruction postlude */
1701 
1702 cpu_dev.dctrl = debug_save;                             /* restore the flag set */
1703 
1704 cpu_update_pclk ();                                     /* update the process clock */
1705 clk_update_counter ();                                  /*   and system clock counters */
1706 
1707 if (cpu_micro_state == paused)                          /* if the micromachine is paused */
1708     P = P - 2 & R_MASK;                                 /*   then set P to point to the PAUS instruction */
1709 
1710 else if (cpu_micro_state == running)                    /* otherwise if it is running */
1711     if (status <= STOP_RERUN)                           /*   then if the instruction will be rerun when resumed */
1712         P = P - 2 & R_MASK;                             /*     then set P to point to it */
1713     else                                                /*   otherwise */
1714         P = P - 1 & R_MASK;                             /*     set P to point to the next instruction */
1715 
1716 cpu_micro_state = halted;                               /* halt the micromachine */
1717 
1718 if (cpu_power_state == power_failing                    /* if power is failing */
1719   && status == STOP_HALT)                               /*   and we executed a HALT instruction */
1720     cpu_power_state = power_off;                        /*     then power will be off when we return */
1721 
1722 if (TRACING (cpu_dev, cpu_dev.dctrl)                    /* if instruction tracing is enabled */
1723   && status <= SCPE_LAST)                               /*   and the status is valid */
1724     hp_trace (&cpu_dev, cpu_dev.dctrl,                  /*     then output the simulation stop reason */
1725               BOV_FORMAT "simulation stop: %s\n",
1726               PBANK, P, STA,
1727               sim_error_text (status));
1728 
1729 if (sim_switches & SIM_SW_HIDE                          /* if executing in a non-echoing command file */
1730   && (status == SCPE_STEP || status == STOP_BRKPNT))    /*   and a step or breakpoint stop occurs */
1731     return SCPE_OK;                                     /*     then do not report the stop reason */
1732 else                                                    /* otherwise */
1733     return status;                                      /*   return the status code that caused the stop */
1734 }
1735 
1736 
1737 /* Execute the LOAD and DUMP commands.
1738 
1739    This command processing routine implements the cold load and cold dump
1740    commands.  The syntax is:
1741 
1742      LOAD { <control/devno> }
1743      DUMP { <control/devno> }
1744 
1745    The <control/devno> is a number that is deposited into the SWCH register
1746    before invoking the CPU cold load or cold dump facility.  The CPU radix is
1747    used to interpret the number; it defaults to octal.  If the number is
1748    omitted, the SWCH register value is not altered before loading or dumping.
1749 
1750    On entry, the "arg" parameter is "Cold_Load" for a LOAD command and
1751    "Cold_Dump" for a DUMP command, and "buf" points at the remainder of the
1752    command line.  If characters exist on the command line, they are parsed,
1753    converted to a numeric value, and stored in the SWCH register.  Then the
1754    CPU's cold load/dump routine is called to set up the CPU state.  Finally, the
1755    CPU is started to begin the requested action.
1756 
1757 
1758    Implementation notes:
1759 
1760     1. The RUN command uses the RU_CONT argument instead of RU_RUN so that the
1761        run_cmd SCP routine will not reset all devices before entering the
1762        instruction executor.  The halt mode interrupt handlers for cold load and
1763        cold dump reset the simulator as appropriate for their commands (i.e.,
1764        the CPU and all I/O devices, or just the I/O devices, respectively).
1765 */
1766 
cpu_cold_cmd(int32 arg,char * buf)1767 t_stat cpu_cold_cmd (int32 arg, char *buf)
1768 {
1769 const char *cptr;
1770 char       gbuf [CBUFSIZE];
1771 t_stat     status;
1772 HP_WORD    value;
1773 
1774 if (*buf != '\0') {                                     /* if more command line characters exist */
1775     cptr = get_glyph (buf, gbuf, 0);                    /*   then get the next glyph */
1776 
1777     if (*cptr != '\0')                                  /* if that does not exhaust the input */
1778         return SCPE_2MARG;                              /*   then report that there are too many arguments */
1779 
1780     value = (HP_WORD) get_uint (gbuf, cpu_dev.dradix,   /* get the parameter value */
1781                                 D16_UMAX, &status);
1782 
1783     if (status == SCPE_OK)                              /* if a valid number was present */
1784         SWCH = value;                                   /*   then set it into the switch register */
1785     else                                                /* otherwise */
1786         return status;                                  /*   return the error status */
1787     }
1788 
1789 else if (arg == Cold_Dump)                              /* otherwise if no dump value was given */
1790     SWCH = dump_control;                                /*   then use the system control panel presets */
1791 
1792 cpu_front_panel (SWCH, (PANEL_TYPE) arg);               /* set up the cold load or dump microcode */
1793 
1794 return run_cmd (RU_CONT, buf);                          /* execute the halt-mode routine */
1795 }
1796 
1797 
1798 /* Execute the POWER commands.
1799 
1800    This command processing routine is called to initiate a power failure or
1801    power restoration.  The "cptr" parameter points to the power option keyword;
1802    the "arg" parameter is not used.
1803 
1804    The routine processes commands of the form:
1805 
1806      POWER { FAIL | OFF | DOWN }
1807      POWER { RESTORE | ON | UP }
1808 
1809    In simulation, the "cpu_power_state" global variable indicates the current
1810    state of system power.  The simulator starts in the power_on state.  The
1811    POWER FAIL command moves from the power_on to the power_failing state if the
1812    CPU is running, or to the power_off state if it is not.  Execution of a HALT
1813    in the power_failing state moves to the power_off state.  The POWER RESTORE
1814    command moves from the power_off to the power_returning state if the CPU is
1815    running, or to the power_on state if it is not.  Execution of the power-on
1816    trap moves from the power_returning to the power_on state.
1817 
1818    The POWER FAIL and POWER RESTORE commands are only valid in the power_on and
1819    power_off states, respectively; otherwise, they print "Command not allowed."
1820 
1821    The four enumeration values model the states of the PON (power on) and PFW
1822    (power-fail warning) hardware signals, as follows:
1823 
1824      PON  PFW  State            Simulator Action
1825      ---  ---  ---------------  ----------------------------
1826       1    0   power on         executing normally
1827       1    1   power failing    executing with cpx1_PFINTR
1828       0    1   power off        will not execute
1829       0    0   power returning  executing with trap_Power_On
1830 
1831    In microcode, the power-fail routine writes the current value of the CPX2
1832    register to the word following the last word of the ICS.  This value is used
1833    by the power-on routine to decide if the CPU was running (cpx2_RUN bit is
1834    set) or halted at the time of the power failure.  A power failure is
1835    indicated by setting the cpx1_PFINTR bit in the CPX1 register; this causes an
1836    interrupt to the power-failure routine in the operating system, which
1837    performs an orderly shutdown followed by a programmed HALT to wait for power
1838    to die.  When power is restored, the power-on trap (trap_Power_On) is set up,
1839    and then, if the PF/ARS switch is in the "enable" position, the trap is
1840    taken, which restarts the operating system and any I/O that was in progress
1841    when power failed.  If the switch is in the "disable" position, the CPU
1842    remains halted, and the trap is taken when the RUN button is pressed.
1843 
1844    The POWER commands are entered at the SCP prompt.  If the machine was running
1845    at the time of power failure, execution is resumed automatically to execute
1846    the power-fail or power-restore OS routines.  If the machine was halted when
1847    the POWER commands were entered, the machine remains halted -- just the power
1848    state changes.
1849 
1850 
1851    Implementation notes:
1852 
1853     1. In hardware, when the power fail interrupt is serviced, the microcode
1854        sets the PWR INH flip-flop, which locks out the RUN switch and inhibits
1855        all other halt-mode (CPX2) and run-mode (CPX1) interrupts until the CPU
1856        is reset.  This ensures that the software power-fail interrupt handler
1857        executes unimpeded.  In simulation, a POWER FAIL command with the CPU
1858        running sets the power-fail interrupt bit in the CPX1 register and
1859        resumes execution in the power_on state.  When the interrupt is detected
1860        by the "cpu_run_mode_interrupt" routine, the state is changed to
1861        power_failing.  In this state, run-mode interrupts are not recognized.
1862        Halt-mode interrupts need no special handling, as the power state is
1863        changed to power_off when the CPU halts.  Therefore, the CPU is never in
1864        a "halted-and-waiting-for-power-to-fade-away" state.
1865 
1866     2. The RUN command uses the RU_CONT argument instead of RU_RUN so that the
1867        run_cmd SCP routine will not reset all devices before entering the
1868        instruction executor.  The halt-mode interrupt handlers for cold load and
1869        cold dump reset the simulator as appropriate for their commands (i.e.,
1870        the CPU and all I/O devices, or just the I/O devices, respectively).
1871 
1872     3. In order to set up the power-on trap, this routine presses the RUN button
1873        and continues the simulation.  After the trap is set up in the
1874        "sim_instr" routine, the halt-mode interrupt handler checks the PF/ARS
1875        switch and stops simulation if auto-restart is disabled.
1876 */
1877 
cpu_power_cmd(int32 arg,char * cptr)1878 t_stat cpu_power_cmd (int32 arg, char *cptr)
1879 {
1880 static CTAB options [] = {
1881     { "FAIL",    NULL, power_failing   },
1882     { "RESTORE", NULL, power_returning },
1883     { "OFF",     NULL, power_failing   },
1884     { "ON",      NULL, power_returning },
1885     { "DOWN",    NULL, power_failing   },
1886     { "UP",      NULL, power_returning },
1887     { NULL }
1888     };
1889 
1890 char    gbuf [CBUFSIZE];
1891 CTAB    *ctptr;
1892 HP_WORD zi, failure_cpx2;
1893 t_stat  status;
1894 
1895 if (cptr == NULL || *cptr == '\0')                      /* if there is no option word */
1896     return SCPE_2FARG;                                  /*   then report a missing argument */
1897 
1898 cptr  = get_glyph (cptr, gbuf, 0);                      /* parse (and upshift) the option specified */
1899 ctptr = find_ctab (options, gbuf);                      /*   and look it up in the option table */
1900 
1901 if (ctptr == NULL)                                      /* if the option is not valid */
1902     status = SCPE_ARG;                                  /*   then report a bad argument */
1903 
1904 else if (*cptr != '\0')                                 /* otherwise if something follows the option */
1905     return SCPE_2MARG;                                  /*   then report too many arguments */
1906 
1907 else if (ctptr->arg == power_failing)                   /* otherwise if a power-fail option was given */
1908     if (cpu_power_state != power_on)                    /*   but the CPU power is not on */
1909         status = SCPE_NOFNC;                            /*     then the command is not allowed */
1910 
1911     else {                                              /* otherwise the failure is valid */
1912         iop_assert_PFWARN ();                           /*   so send a power-fail warning to all devices */
1913 
1914         cpu_read_memory (absolute, ICS_Z, &zi);         /* get the ICS stack limit */
1915         cpu_write_memory (absolute, zi + 1, CPX2);      /*   and save the CPX2 value in the following word */
1916 
1917         if (CPX2 & cpx2_RUN) {                          /* if the CPU is currently running */
1918             CPX1 |= cpx1_PFINTR;                        /*   then set the power-fail interrupt */
1919             CPX2 |= cpx2_RUNSWCH;                       /*     and assume a RUN command */
1920             status = run_cmd (RU_CONT, cptr);           /*       and continue execution */
1921             }
1922 
1923         else {                                          /* otherwise the CPU is currently halted */
1924             cpu_power_state = power_off;                /*   so remain halted in the "power is off" state */
1925             status = SCPE_OK;                           /*     and return command success */
1926             }
1927         }
1928 
1929 else if (ctptr->arg == power_returning)                 /* otherwise if a power-restoration option was given */
1930     if (cpu_power_state != power_off)                   /*   but the CPU power is not off */
1931         status = SCPE_NOFNC;                            /*     then the command is not allowed */
1932 
1933     else {                                              /* otherwise the restoration is valid */
1934         reset_all_p (0);                                /*   so reset all devices to their power on states */
1935 
1936         cpu_read_memory (absolute, ICS_Z, &zi);             /* get the ICS stack limit */
1937         cpu_read_memory (absolute, zi + 1, &failure_cpx2);  /*   and get the value of CPX2 at the time of failure */
1938         cpu_write_memory (absolute, zi + 1, CPX2);          /*     and replace it with the current CPX2 value */
1939 
1940         if (failure_cpx2 & cpx2_RUN) {                  /* if the CPU was running at the time of power failure */
1941             cpu_power_state = power_returning;          /*   then move to the "power is returning" state */
1942             CPX2 |= cpx2_RUNSWCH;                       /*     and assume a RUN command */
1943             status = run_cmd (RU_CONT, cptr);           /*       and continue execution */
1944             }
1945 
1946         else {                                          /* otherwise the CPU was halted when power failed */
1947             cpu_power_state = power_on;                 /*   so remain halted in the "power is on" state */
1948             status = SCPE_OK;                           /*     and return command success */
1949             }
1950         }
1951 
1952 else                                                    /* otherwise a valid option has no handler */
1953     status = SCPE_IERR;                                 /*   so report an internal error */
1954 
1955 return status;                                          /* return the operation status */
1956 }
1957 
1958 
1959 
1960 /* CPU global utility routines */
1961 
1962 
1963 /* Process a run-mode interrupt.
1964 
1965    This routine is called when one or more of the interrupt request bits are set
1966    in the CPX1 register.  The highest-priority request is identified and
1967    cleared, the interrupt classification and parameter are established, and the
1968    associated interrupt handler is set up for execution.  On return, the CPU has
1969    been configured and is ready to execute the first instruction in the handler.
1970 
1971    On entry, the routine first checks for an external interrupt alone; this is
1972    done to improve performance, as this is the most common case.  If some other
1973    interrupt is requested, or if multiple interrupts are requested, the CPX1
1974    register is scanned from MSB to LSB to identify the request.
1975 
1976 
1977    Implementation notes:
1978 
1979     1. In hardware, halting the CPU while a PAUS instruction is executing leaves
1980        P pointing to the following instruction, which is executed when the RUN
1981        button is pressed.  In simulation, this action occurs only when execution
1982        is resumed with the "-B" option to bypass the pause.  Otherwise, resuming
1983        (or stepping) continues with the PAUS instruction.
1984 
1985        If an interrupt occurs while PAUS is executing, the interrupt handler
1986        will return to the instruction following the PAUS, as though HALT and RUN
1987        had been pressed.  This occurs because the P register normally points two
1988        instructions past the instruction currently executing.  When an interrupt
1989        occurs, P is decremented to point at the instruction after the current
1990        instruction, which is the correct point of return after the interrupt
1991        service routine completes.
1992 
1993        When the simulator is stopped, P is backed up to point at the next
1994        instruction to execute.  In the case of a PAUS instruction, the "next
1995        instruction" is the same PAUS instruction.  When simulation resumes, the
1996        PAUS instruction is fetched into the NIR, and P is incremented.  If no
1997        interrupt is pending, the main instruction execution loop copies the NIR
1998        into the CIR, prefetches the instruction following the PAUS into the NIR,
1999        and increments P again, so that it points two instructions beyond the
2000        current instruction.  At this point, everything is set up properly as
2001        before the simulation stop.
2002 
2003        However, if an interrupt is pending when simulation resumes, this routine
2004        is called before the NIR-to-CIR operation is performed, so P still points
2005        one instruction beyond the PAUS.  Stacking the usual P - 1 value would
2006        cause the interrupt handler to return to the PAUS instruction instead of
2007        to the instruction following, as would have occurred had a simulation
2008        stop not been involved.
2009 
2010        Therefore, when resuming from a simulator stop, the SS_PAUSE_RESUMED flag
2011        is set in the "cpu_stop_flags" variable by the "halt_mode_interrupt"
2012        routine if a PAUS instruction is in the NIR after reloading.  If an
2013        interrupt is pending, this routine will be entered with the flag set, and
2014        we then increment P so that it is correctly set to point two instructions
2015        beyond the PAUS before handling the interrupt.  If an interrupt is not
2016        pending on resumption, the P adjustment is performed as described above,
2017        and P will be set properly when the next interrupt occurs.
2018 
2019        A special case occurs when resuming into a PAUS from a simulator stop if
2020        a higher-priority interrupt occurs immediately after handling a pending
2021        lower-priority interrupt.  In this case, this routine will be entered a
2022        second time before the instruction execution loop performs the NIR-to-CIR
2023        operation.  Although the PAUS is still in the CIR, we must not increment
2024        P a second time, because the instruction now being interrupted is not the
2025        PAUS but is the first instruction of the lower-priority interrupt routine
2026        that never had a chance to execute.  Wo do this by clearing the
2027        SS_PAUSE_RESUMED flag after the first increment.
2028 */
2029 
cpu_run_mode_interrupt(HP_WORD device_number)2030 void cpu_run_mode_interrupt (HP_WORD device_number)
2031 {
2032 HP_WORD   request_set, request_count, parameter;
2033 IRQ_CLASS class;
2034 
2035 if (cpu_stop_flags & SS_PAUSE_RESUMED) {                /* if we are resuming into a PAUS instruction */
2036     P = P + 1 & R_MASK;                                 /*   then set the return to the instruction following */
2037     cpu_stop_flags &= ~SS_PAUSE_RESUMED;                /*     and clear the flag in case of back-to-back interrupts */
2038     }
2039 
2040 cpu_micro_state = running;                              /* the micromachine may be paused but is no longer */
2041 
2042 request_set = CPX1 & CPX1_IRQ_SET;                      /* get the set of active interrupt requests */
2043 
2044 if (request_set == cpx1_EXTINTR) {                      /* if only an external request is present */
2045     class = irq_External;                               /*   (the most common case) then set the class */
2046     parameter = device_number;                          /*     and set the parameter to the device number */
2047     }
2048 
2049 else {                                                  /* otherwise scan for the class */
2050     request_count = 0;                                  /*   where CPX1.1 through CPX1.9 */
2051     request_set = D16_SIGN;                             /*     correspond to IRQ classes 1-9 */
2052 
2053     while ((CPX1 & request_set) == 0) {                 /* scan from left to right for the first request */
2054         request_count = request_count + 1;              /*   while incrementing the request number */
2055         request_set = request_set >> 1;                 /*     and shifting the current request bit */
2056         }
2057 
2058     class = (IRQ_CLASS) request_count;                  /* set the class from the request count */
2059 
2060     if (class == irq_Integer_Overflow) {                /* if an integer overflow occurred */
2061         parameter = 1;                                  /*   then set the parameter to 1 */
2062         STA &= ~STATUS_O;                               /*     and clear the overflow flag */
2063         }
2064 
2065     else if (class == irq_External)                     /* otherwise if an external interrupt occurred */
2066         parameter = device_number;                      /*   then set the parameter to the device number */
2067 
2068     else if (class == irq_Module) {                     /* otherwise if the class is a module interrupt */
2069         parameter = UPPER_BYTE (MOD);                   /*   then the parameter is the module number */
2070         MOD = 0;                                        /* clear the register to prevent a second interrupt */
2071         }
2072 
2073     else if (class == irq_Power_Fail) {                 /* otherwise if a power fail interrupt occurred */
2074         parameter = TO_LABEL (LABEL_IRQ, class);        /*   then the parameter is the label */
2075         cpu_power_state = power_failing;                /*     and system power is now failing */
2076         }
2077 
2078     else                                                /* otherwise the parameter */
2079         parameter = TO_LABEL (LABEL_IRQ, class);        /*   is the label */
2080     }
2081 
2082 CPX1 &= ~request_set;                                   /* clear the associated CPX request bit */
2083 
2084 tprintf (cpu_dev, DEB_INSTR, BOV_FORMAT "%s interrupt\n",
2085          PBANK, P - 1 & R_MASK, parameter, interrupt_name [class]);
2086 
2087 cpu_setup_irq_handler (class, parameter);               /* set up the entry into the interrupt handler */
2088 
2089 return;
2090 }
2091 
2092 
2093 /* Set up a front panel operation.
2094 
2095    This routine sets the SWCH register to the supplied value and then sets the
2096    appropriate bit in the CPX2 register.  This will cause a halt-mode interrupt
2097    when simulated execution is resumed.
2098 
2099 
2100    Implementation notes:
2101 
2102     1. We do this here to avoid having to export the registers and CPX values
2103        globally.
2104 */
2105 
cpu_front_panel(HP_WORD switch_reg,PANEL_TYPE request)2106 void cpu_front_panel (HP_WORD switch_reg, PANEL_TYPE request)
2107 {
2108 SWCH = switch_reg;                                      /* set the SWCH register value */
2109 
2110 switch (request) {                                      /* dispatch on the request type */
2111 
2112     case Run:                                           /* a run request */
2113         CPX2 |= cpx2_RUNSWCH;                           /* set the RUN switch */
2114         break;
2115 
2116     case Cold_Load:                                     /* a cold load request */
2117         CPX2 |= cpx2_LOADSWCH;                          /* set the LOAD switch */
2118         break;
2119 
2120     case Cold_Dump:                                     /* a cold dump request */
2121         CPX2 |= cpx2_DUMPSWCH;                          /* set the DUMP switch */
2122         break;
2123     }                                                   /* all cases are handled */
2124 
2125 return;
2126 }
2127 
2128 
2129 /* Update the process clock.
2130 
2131    If the process clock is currently calibrated, then the service interval is
2132    actually ten times the hardware period of 1 millisecond.  This provides
2133    sufficient event service call spacing to allow idling to work.
2134 
2135    To present the correct value when the process clock is read, this routine is
2136    called to increment the count by an amount proportional to the fraction of
2137    the service interval that has elapsed.  In addition, it is called by the CPU
2138    instruction postlude, so that the PCLK register will have the correct value
2139    if it is examined from the SCP command prompt.
2140 */
2141 
cpu_update_pclk(void)2142 void cpu_update_pclk (void)
2143 {
2144 int32 elapsed, ticks;
2145 
2146 if (cpu_is_calibrated) {                                /* if the process clock is calibrated */
2147     elapsed = cpu_unit [0].wait                         /*   then the elapsed time is the original wait time */
2148                 - sim_activate_time (&cpu_unit [0]);    /*     less the time remaining before the next service */
2149 
2150     ticks =                                             /* the adjustment is */
2151        (elapsed * PCLK_MULTIPLIER) / cpu_unit [0].wait  /*   the elapsed fraction of the multiplier */
2152          - (PCLK_MULTIPLIER - pclk_increment);          /*     less the amount of any adjustment already made */
2153 
2154     PCLK = PCLK + ticks & R_MASK;                       /* update the process clock counter with rollover */
2155     pclk_increment = pclk_increment - ticks;            /*   and reduce the amount remaining to add at service */
2156     }
2157 
2158 return;
2159 }
2160 
2161 
2162 
2163 /* CPU global instruction execution routines */
2164 
2165 
2166 /* Push the stack down.
2167 
2168    This routine implements the PUSH micro-order to create space on the stack for
2169    a new value.  On return, the new value may be stored in the RA register.
2170 
2171    If the SR register indicates that all of the TOS registers are in use, then
2172    the RD register is freed by performing a queue down.  Then the values in the
2173    TOS registers are shifted down, freeing the RA register.  Finally, SR is
2174    incremented in preparation for the store.
2175 */
2176 
cpu_push(void)2177 void cpu_push (void)
2178 {
2179 if (SR == 4)                                            /* if all TOS registers are full */
2180     cpu_queue_down ();                                  /*   then move the RD value to memory */
2181 
2182 RD = RC;                                                /* shift */
2183 RC = RB;                                                /*   the register */
2184 RB = RA;                                                /*     values down */
2185 
2186 SR = SR + 1;                                            /* increment the register-in-use count */
2187 
2188 return;
2189 }
2190 
2191 
2192 /* Pop the stack up.
2193 
2194    This routine implements the POP micro-order to delete the top-of-stack value.
2195 
2196    On entry, if the SR register indicates that all of the TOS registers are
2197    empty, then if decrementing the SM register would move it below the DB
2198    register value, and the CPU is not in privileged mode, then a Stack Underflow
2199    trap is taken.  Otherwise, the stack memory pointer is decremented.
2200 
2201    If one or more values exist in the TOS registers, the values are shifted up,
2202    deleting the previous value in the RA register, and SR is decremented.
2203 */
2204 
cpu_pop(void)2205 void cpu_pop (void)
2206 {
2207 if (SR == 0) {                                          /* if the TOS registers are empty */
2208     if (SM <= DB && NPRV)                               /*   then if SM isn't above DB and the mode is non-privileged */
2209         MICRO_ABORT (trap_Stack_Underflow);             /*     then trap with a Stack Underflow */
2210 
2211     SM = SM - 1 & R_MASK;                               /* decrement the stack memory register */
2212     }
2213 
2214 else {                                                  /* otherwise at least one TOS register is occupied */
2215     RA = RB;                                            /*   so shift */
2216     RB = RC;                                            /*     the register */
2217     RC = RD;                                            /*       values up */
2218 
2219     SR = SR - 1;                                        /* decrement the register-in-use count */
2220     }
2221 
2222 return;
2223 }
2224 
2225 
2226 /* Queue a value from memory up to the register file.
2227 
2228    This routine implements the QUP micro-order to move the value at the top of
2229    the memory stack into the bottom of the TOS register file.  There must be a
2230    free TOS register when this routine is called.
2231 
2232    On entry, if decrementing the SM register would move it below the DB register
2233    value, and the CPU is not in privileged mode, then a Stack Underflow trap is
2234    taken.  Otherwise, the value pointed to by SM is read into the first unused
2235    TOS register, SM is decremented to account for the removed value, and SR is
2236    incremented to account for the new TOS register in use.
2237 
2238 
2239    Implementation notes:
2240 
2241     1. SR must be less than 4 on entry, so that TR [SR] is the first unused TOS
2242        register.
2243 
2244     2. SM and SR must not be modified within the call to cpu_read_memory.  For
2245        example, SR++ cannot be passed as a parameter.
2246 */
2247 
cpu_queue_up(void)2248 void cpu_queue_up (void)
2249 {
2250 if (SM <= DB && NPRV)                                   /* if SM isn't above DB and the mode is non-privileged */
2251     MICRO_ABORT (trap_Stack_Underflow);                 /*   then trap with a Stack Underflow */
2252 
2253 else {                                                  /* otherwise */
2254     cpu_read_memory (stack, SM, &TR [SR]);              /*   read the value from memory into a TOS register */
2255 
2256     SM = SM - 1 & R_MASK;                               /* decrement the stack memory register */
2257     SR = SR + 1;                                        /*   and increment the register-in-use count */
2258     }
2259 
2260 return;
2261 }
2262 
2263 
2264 /* Queue a value from the register file down to memory.
2265 
2266    This routine implements the QDWN micro-order to move the value at the bottom
2267    of the TOS register file into the top of the memory stack.  There must be a
2268    TOS register in use when this routine is called.
2269 
2270    On entry, if incrementing the SM register would move it above the Z register
2271    value, then a Stack Overflow trap is taken.  Otherwise, SM is incremented to
2272    account for the new value written, SR is decremented to account for the TOS
2273    register removed from use, and the value in that TOS register is written into
2274    memory at the top of the memory stack.
2275 
2276 
2277    Implementation notes:
2278 
2279     1. SR must be greater than 0 on entry, so that TR [SR - 1] is the last TOS
2280        register in use.
2281 
2282     2. SM and SR must not be modified within the call to cpu_write_memory.  For
2283        example, SR-- cannot be passed as a parameter.
2284 */
2285 
cpu_queue_down(void)2286 void cpu_queue_down (void)
2287 {
2288 if (SM >= Z)                                            /* if SM isn't below Z */
2289     MICRO_ABORT (trap_Stack_Overflow);                  /*   then trap with a Stack Overflow */
2290 
2291 SM = SM + 1 & R_MASK;                                   /* increment the stack memory register */
2292 SR = SR - 1;                                            /*   and decrement the register-in-use count */
2293 
2294 cpu_write_memory (stack, SM, TR [SR]);                  /* write the value from a TOS register to memory */
2295 
2296 return;
2297 }
2298 
2299 
2300 /* Flush the register file.
2301 
2302    This routine implements the PSHA microcode subroutine that writes the values
2303    of all TOS registers in use to the memory stack.  As each value is written,
2304    the SM register is incremented and the SR register is decremented.  On
2305    return, the SR register value will be zero.
2306 
2307    The routine does not check for stack overflow.
2308 */
2309 
cpu_flush(void)2310 void cpu_flush (void)
2311 {
2312 while (SR > 0) {                                        /* while one or more registers are in use */
2313     SM = SM + 1 & R_MASK;                               /*   increment the stack memory register */
2314     SR = SR - 1;                                        /*     and decrement the register-in-use count */
2315 
2316     cpu_write_memory (stack, SM, TR [SR]);              /* write the value from a TOS register to memory */
2317     }
2318 
2319 return;
2320 }
2321 
2322 
2323 /* Adjust SR until it reaches a specified value.
2324 
2325    This routine implements the SRP1-SRP4 microcode subroutines that adjust the
2326    stack until the prescribed number (1-4) of TOS registers are occupied.  It
2327    performs queue ups, i.e., moves values from the top of the memory stack to
2328    the bottom of the register file, until the specified SR value is reached.
2329    Stack underflow is checked after the all of the values have been moved.  The
2330    routine assumes that at least one value must be moved.
2331 
2332 
2333    Implementation notes:
2334 
2335     1. SR must be greater than 0 on entry, so that TR [SR - 1] is the last TOS
2336        register in use.
2337 
2338     2. SM and SR must not be modified within the call to cpu_read_memory.  For
2339        example, SR++ cannot be passed as a parameter.
2340 
2341     3. The cpu_queue_up routine isn't used, as that routine checks for a stack
2342        underflow after each word is moved rather than only after the last word.
2343 */
2344 
cpu_adjust_sr(uint32 target)2345 void cpu_adjust_sr (uint32 target)
2346 {
2347 do {
2348     cpu_read_memory (stack, SM, &TR [SR]);              /* read the value from memory into a TOS register */
2349 
2350     SM = SM - 1 & R_MASK;                               /* decrement the stack memory register */
2351     SR = SR + 1;                                        /*   and increment the register-in-use count */
2352     }
2353 while (SR < target);                                    /* queue up until the requested number of registers are in use */
2354 
2355 if (SM <= DB && NPRV)                                   /* if SM isn't above DB, or the mode is non-privileged */
2356     MICRO_ABORT (trap_Stack_Underflow);                 /*   then trap with a Stack Underflow */
2357 
2358 return;
2359 }
2360 
2361 
2362 /* Write a stack marker to memory.
2363 
2364    This routine implements the STMK microcode subroutine that writes a four-word
2365    marker to the stack.  The format of the marker is as follows:
2366 
2367        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
2368      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2369      |                       X register value                        |  [Q - 3]  X
2370      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2371      |                  PB-relative return address                   |  [Q - 2]  P + 1 - PB
2372      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2373      |                     Status register value                     |  [Q - 1]  STA
2374      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2375      |                         Delta Q value                         |  [Q - 0]  S - Q
2376      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2377 
2378    After the values are written, the Q register is set to point to the marker.
2379 
2380    This routine is always entered with SR = 0, i.e., with the TOS registers
2381    flushed to the memory stack.  It does not check for stack overflow.
2382 
2383 
2384    Implementation notes:
2385 
2386     1. The PB-relative return address points to the instruction after the point
2387        of the call.  Conceptually, this is location P + 1, but because the CPU
2388        uses a two-instruction prefetch, the location is actually P - 1.
2389 */
2390 
cpu_mark_stack(void)2391 void cpu_mark_stack (void)
2392 {
2393 SM = SM + 4 & R_MASK;                                   /* adjust the stack pointer */
2394 
2395 cpu_write_memory (stack, SM - 3, X);                    /* push the index register */
2396 cpu_write_memory (stack, SM - 2, P - 1 - PB & LA_MASK); /*   and delta P */
2397 cpu_write_memory (stack, SM - 1, STA);                  /*     and the status register */
2398 cpu_write_memory (stack, SM - 0, SM - Q & LA_MASK);     /*       and delta Q */
2399 
2400 Q = SM;                                                 /* set Q to point to the new stack marker */
2401 
2402 return;
2403 }
2404 
2405 
2406 /* Calculate an effective memory address.
2407 
2408    This routine calculates the effective address for a memory reference or
2409    branch instruction.  On entry, "mode_disp" contains the mode, displacement,
2410    index, and indirect fields of the instruction, "classification" and "offset"
2411    point to variables to receive the corresponding values, and "selector" points
2412    to a variable to receive the byte selection ("upper" or "lower") for byte-
2413    addressable instructions or is NULL for word-addressable instructions.  On
2414    exit, "classification" is set to the memory access classification, "offset"
2415    is set to the address offset within the memory bank implied by the
2416    classification, and "selector" is set to indicate the byte referenced if the
2417    pointer is non-NULL.
2418 
2419    The mode and displacement fields of the instruction encode an address
2420    relative to one of the base registers P, DB, Q, or S, as follows:
2421 
2422        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
2423      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2424      |   memory op   | X | I |         mode and displacement         |
2425      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2426                              | 0 | 0 |     P+ displacement 0-255     |
2427                              +---+---+---+---+---+---+---+---+---+---+
2428                              | 0 | 1 |     P- displacement 0-255     |
2429                              +---+---+---+---+---+---+---+---+---+---+
2430                              | 1 | 0 |    DB+ displacement 0-255     |
2431                              +---+---+---+---+---+---+---+---+---+---+
2432                              | 1 | 1 | 0 |   Q+ displacement 0-127   |
2433                              +---+---+---+---+---+---+---+---+---+---+
2434                              | 1 | 1 | 1 | 0 | Q- displacement 0-63  |
2435                              +---+---+---+---+---+---+---+---+---+---+
2436                              | 1 | 1 | 1 | 1 | S- displacement 0-63  |
2437                              +---+---+---+---+---+---+---+---+---+---+
2438 
2439    The displacement encoded in the instruction is an unsigned value that is
2440    added to or subtracted from the indicated base register.
2441 
2442    If the X and I fields are both 0, the addressing is direct.  If the X field
2443    is 1, the addressing is indexed.  If the I field is 1, the addressing is
2444    indirect.  If both fields are 1, the addressing is indirect indexed, with
2445    indirection performed before indexing.
2446 
2447    To improve execution speed in hardware, a preadder is implemented that sums
2448    the offset contained in certain bits of the CIR with the index register (if
2449    enabled).  The primary use is to save a microinstruction cycle during memory
2450    reference instructions, which must add a base register, the offset in the
2451    CIR, and potentially the X register (either directly or shifted left or right
2452    by one place for LDD/STD or LDB/STB, respectively).  The preadder also serves
2453    to hold other counts obtained from the CIR, e.g., shift counts, although in
2454    these cases, the addition function is not used.
2455 
2456    This routine simulates the preadder as part of the effective address
2457    calculation.  The calculations employed for word addressing are:
2458 
2459      Direct word addressing:
2460        ea = PBANK.(P + displacement)
2461        ea = DBANK.(DB + displacement)
2462        ea = SBANK.(Q,S + displacement)
2463 
2464      Direct indexed word addressing:
2465        ea = PBANK.(P + displacement + X)
2466        ea = DBANK.(DB + displacement + X)
2467        ea = SBANK.(Q,S + displacement + X)
2468 
2469      Indirect word addressing:
2470        ea = PBANK.(P + displacement + M [PBANK.(P + displacement)])
2471        ea = DBANK.(DB + M [DBANK.(DB + displacement)])
2472        ea = DBANK.(DB + M [SBANK.(Q,S + displacement)])
2473 
2474      Indirect indexed word addressing:
2475        ea = PBANK.(P + displacement + M [PBANK.(P + displacement)] + X)
2476        ea = DBANK.(DB + M [DBANK.(DB + displacement)] + X)
2477        ea = DBANK.(DB + M [SBANK.(Q,S + displacement)] + X)
2478 
2479    The indirect cell contains either a self-relative, P-relative address or a
2480    DB-relative address, even for S or Q-relative modes.  Indirect branches with
2481    DB/Q/S-relative mode are offsets from PB, not DB.
2482 
2483    The effective address calculations employed for byte addressing are:
2484 
2485      Direct byte addressing:
2486        ea = DBANK.(DB + displacement).byte [0]
2487        ea = SBANK.(Q,S + displacement).byte [0]
2488 
2489      Direct indexed byte addressing:
2490        ea = DBANK.(DB + displacement + X / 2).byte [X & 1]
2491        ea = SBANK.(Q,S + displacement + X / 2).byte [X & 1]
2492 
2493      Indirect byte addressing:
2494        ea,I = DBANK.(DB + M [DBANK.(DB + displacement)] / 2).byte [cell & 1]
2495        ea,I = DBANK.(DB + M [SBANK.(Q,S + displacement)] / 2).byte [cell & 1]
2496 
2497      Indirect indexed byte addressing:
2498        ea,I = DBANK.(DB + (M [DBANK.(DB + displacement)] + X) / 2).byte [cell + X & 1]
2499        ea,I = DBANK.(DB + (M [SBANK.(Q,S + displacement)] + X) / 2).byte [cell + X & 1]
2500 
2501    For all modes, the displacement is a word address, whereas the indirect cell
2502    and index register contain byte offsets.  For direct addressing, the byte
2503    selected is byte 0.  For all other modes, the byte selected is the byte at
2504    (offset & 1), where the offset is the index register value, the indirect cell
2505    value, or the sum of the two.
2506 
2507    Byte offsets into data segments present problems, in that negative offsets
2508    are permitted (to access the DL-to-DB area), but there are not enough bits to
2509    represent all locations unambiguously in the potential -32K to +32K word
2510    offset range.  Therefore, a byte offset with bit 0 = 1 can represent either a
2511    positive or negative word offset from DB, depending on the interpretation.
2512    The HP 3000 adopts the convention that if the address resulting from a
2513    positive-offset interpretation does not fall within the DL-to-S range, then
2514    32K is added to the address, effectively changing the interpretation from a
2515    positive to a negative offset.  If this new address does not fall within the
2516    DL-to-S range, a Bounds Violation trap occurs if the mode is non-privileged.
2517 
2518    The reinterpretation as a negative offset is performed only if the CPU is not
2519    in split-stack mode (where either DBANK is different from SBANK, or DB does
2520    not lie between DL and Z), as extra data segments do not permit negative-DB
2521    addressing.  Reinterpretation is also not used for code segments, as negative
2522    offsets from PB are not permitted.
2523 
2524 
2525    Implementation notes:
2526 
2527     1. On entry, the program counter points to the instruction following the
2528        next instruction (i.e., the NIR location + 1).  However, P-relative
2529        offsets are calculated from the current instruction (CIR location).
2530        Therefore, we decrement P by two before adding the offset.
2531 
2532        In hardware, P-relative addresses obtained from the preadder are offset
2533        from P + 1, whereas P-relative addresses obtained by summing with
2534        P-register values obtained directly from the S-Bus are offset from P + 2.
2535        This is because the P-register increment that occurs as part of a NEXT
2536        micro-order is coincident with the R-Bus and S-Bus register loads; both
2537        operations occur when the NXT+1 signal asserts.  Therefore, the microcode
2538        handling P-relative memory reference address resolution subtracts one to
2539        get the P value corresponding to the CIR, whereas branches on overflow,
2540        carry, etc. subtract two.
2541 
2542     2. If the mode is indirect, this routine handles bounds checks and TOS
2543        register accesses on the initial address.
2544 
2545     3. The System Reference Manual states that byte offsets are interpreted as
2546        negative if the effective address does not lie between DL and Z.
2547        However, the Series II microcode actually uses DL and S for the limits.
2548 
2549     4. This routine calculates the effective address for the memory address
2550        instructions.  These instructions always bounds-check their accesses, and
2551        data and stack accesses are mapped to the TOS registers if the effective
2552        address lies between SM and SM + SR within the stack bank.
2553 */
2554 
cpu_ea(HP_WORD mode_disp,ACCESS_CLASS * classification,HP_WORD * offset,BYTE_SELECTOR * selector)2555 void cpu_ea (HP_WORD mode_disp, ACCESS_CLASS *classification, HP_WORD *offset, BYTE_SELECTOR *selector)
2556 {
2557 HP_WORD      base, displacement;
2558 ACCESS_CLASS class;
2559 
2560 switch ((mode_disp & MODE_MASK) >> MODE_SHIFT) {        /* dispatch on the addressing mode */
2561 
2562     case 000:
2563     case 001:
2564     case 002:
2565     case 003:                                           /* positive P-relative displacement */
2566         base = P - 2 + (mode_disp & DISPL_255_MASK);    /* add the displacement to the base */
2567         class = program_checked;                        /*   and classify as a program reference */
2568         break;
2569 
2570     case 004:
2571     case 005:
2572     case 006:
2573     case 007:                                           /* negative P-relative displacement */
2574         base = P - 2 - (mode_disp & DISPL_255_MASK);    /* subtract the displacement from the base */
2575         class = program_checked;                        /*   and classify as a program reference */
2576         break;
2577 
2578     case 010:
2579     case 011:
2580     case 012:
2581     case 013:                                           /* positive DB-relative displacement */
2582         base = DB + (mode_disp & DISPL_255_MASK);       /* add the displacement to the base */
2583         class = data_mapped_checked;                    /*   and classify as a data reference */
2584         break;
2585 
2586     case 014:
2587     case 015:                                           /* positive Q-relative displacement */
2588         base = Q + (mode_disp & DISPL_127_MASK);        /* add the displacement to the base */
2589         class = stack_checked;                          /*   and classify as a stack reference */
2590         break;
2591 
2592     case 016:                                           /* negative Q-relative displacement */
2593         base = Q - (mode_disp & DISPL_63_MASK);         /* subtract the displacement from the base */
2594         class = stack_checked;                          /*   and classify as a stack reference */
2595         break;
2596 
2597     case 017:                                           /* negative S-relative displacement */
2598         base = SM + SR - (mode_disp & DISPL_63_MASK);   /* subtract the displacement from the base */
2599         class = stack_checked;                          /*   and classify as a stack reference */
2600         break;
2601     }                                                   /* all cases are handled */
2602 
2603 
2604 if (!(mode_disp & I_FLAG_BIT_5))                            /* if the mode is direct */
2605     displacement = 0;                                       /*   then there's no displacement */
2606 
2607 else {                                                      /* otherwise the mode is indirect */
2608     cpu_read_memory (class, base & LA_MASK, &displacement); /*   so get the displacement value */
2609 
2610     if ((CIR & BR_MASK) == BR_DBQS_I) {                     /* if this a DB/Q/S-relative indirect BR instruction */
2611         base = PB;                                          /*   then PB is the base for the displacement */
2612         class = program_checked;                            /* reclassify as a program reference */
2613         }
2614 
2615     else if (class != program_checked) {                    /* otherwise if it is a data or stack reference */
2616         base = DB;                                          /*   then DB is the base for the displacement */
2617         class = data_mapped_checked;                        /* reclassify as a data reference */
2618         }
2619                                                         /* otherwise, this is a program reference */
2620     }                                                   /*   which is self-referential */
2621 
2622 if ((CIR & LSDX_MASK) == LDD_X                          /* if the mode */
2623   || (CIR & LSDX_MASK) == STD_X)                        /*   is double-word indexed */
2624     displacement = displacement + X * 2 & DV_MASK;      /*     then add the doubled index to the displacement */
2625 
2626 else if (mode_disp & X_FLAG)                            /* otherwise if the mode is indexed */
2627     displacement = displacement + X & DV_MASK;          /*   then add the index to the displacement */
2628 
2629 if (selector == NULL)                                   /* if a word address is requested */
2630     base = base + displacement;                         /*   then add in the word displacement */
2631 
2632 else if ((mode_disp & (X_FLAG | I_FLAG_BIT_5)) == 0)    /* otherwise if a direct byte address is requested */
2633     *selector = upper;                                  /*   then it references the upper byte */
2634 
2635 else {                                                  /* otherwise an indexed or indirect byte address is requested */
2636     if (displacement & 1)                               /*   so if the byte displacement is odd */
2637         *selector = lower;                              /*     then the lower byte was requested */
2638     else                                                /*   otherwise it is even */
2639         *selector = upper;                              /*     and the upper byte was requested */
2640 
2641     base = base + (displacement >> 1) & LA_MASK;        /* convert the displacement from byte to word and add */
2642 
2643     if (DBANK == SBANK && DL <= DB && DB <= Z           /* if not in split-stack mode */
2644      && (base < DL || base > SM + SR))                  /*   and the word address is out of range */
2645         base = base ^ D16_SIGN;                         /*     then add 32K to swap the offset polarity */
2646     }
2647 
2648 *offset = base & LA_MASK;                               /* set the */
2649 *classification = class;                                /*   return values */
2650 
2651 return;
2652 }
2653 
2654 
2655 /* Convert a data- or program-relative byte address to a word effective address.
2656 
2657    The supplied byte offset from DB or PB is converted to a memory address,
2658    bounds-checked if requested, and returned.  If the supplied block length is
2659    not zero, the converted address is assumed to be the starting address of a
2660    block, and an ending address, based on the block length, is calculated and
2661    bounds-checked if requested.  If either address lies outside of the segment
2662    associated with the access class, a Bounds Violation trap occurs, unless a
2663    privileged data access is requested.
2664 
2665    The "class" parameter indicates whether the offset is from DB or PB and
2666    must be "data", "data_checked", "program", or "program_checked".  No other
2667    access classes are supported.  In particular, "data_mapped" and
2668    "data_mapped_checked" are not allowed, as callers of this routine never map
2669    accesses to the TOS registers.
2670 
2671    Byte offsets into data segments present problems, in that negative offsets
2672    are permitted (to access the DL-to-DB area), but there are not enough bits to
2673    represent all locations unambiguously in the potential -32K to +32K word
2674    offset range.  Therefore, a byte offset with bit 0 = 1 can represent either a
2675    positive or negative word offset from DB, depending on the interpretation.
2676    The HP 3000 adopts the convention that if the address resulting from a
2677    positive-offset interpretation does not fall within the DL-to-S range, then
2678    32K is added to the address, effectively changing the interpretation from a
2679    positive to a negative offset.  If this new address does not fall within the
2680    DL-to-S range, a Bounds Violation trap occurs if the mode is non-privileged.
2681 
2682    The reinterpretation as a negative offset is performed only if the CPU is not
2683    in split-stack mode (where either DBANK is different from SBANK, or DB does
2684    not lie between DL and Z), as extra data segments do not permit negative-DB
2685    addressing.  Reinterpretation is also not used for code segments, as negative
2686    offsets from PB are not permitted.
2687 
2688 
2689    Implementation notes:
2690 
2691     1. This routine implements the DBBC microcode subroutine.
2692 */
2693 
cpu_byte_ea(ACCESS_CLASS class,uint32 byte_offset,uint32 block_length)2694 uint32 cpu_byte_ea (ACCESS_CLASS class, uint32 byte_offset, uint32 block_length)
2695 {
2696 uint32 starting_word, ending_word, increment;
2697 
2698 if (block_length & D16_SIGN)                            /* if the block length is negative */
2699     increment = 0177777;                                /*   then the memory increment is negative also */
2700 else                                                    /* otherwise */
2701     increment = 1;                                      /*   the increment is positive */
2702 
2703 if (class == program || class == program_checked) {     /* if this is a program access */
2704     starting_word = PB + (byte_offset >> 1) & LA_MASK;  /*   then determine the starting word address */
2705 
2706     if (class == program_checked                        /* if checking is requested */
2707       && starting_word < PB || starting_word > PL)      /*   and the starting address is out of range */
2708         MICRO_ABORT (trap_Bounds_Violation);            /*     then trap for a bounds violation */
2709 
2710     if (block_length != 0) {                            /* if a block length was supplied */
2711         ending_word =                                   /*   then determine the ending address */
2712            starting_word + ((block_length - increment + (byte_offset & 1)) >> 1) & LA_MASK;
2713 
2714         if (class == program_checked                    /* if checking is requested */
2715           && ending_word < PB || ending_word > PL)      /*   and the ending address is out of range */
2716             MICRO_ABORT (trap_Bounds_Violation);        /*     then trap for a bounds violation */
2717         }
2718     }
2719 
2720 else {                                                  /* otherwise this is a data address */
2721     starting_word = DB + (byte_offset >> 1) & LA_MASK;  /*   so determine the starting word address */
2722 
2723     if (DBANK == SBANK && DL <= DB && DB <= Z           /* if not in split-stack mode */
2724       && (starting_word < DL || starting_word > SM)) {  /*   and the word address is out of range */
2725         starting_word = starting_word ^ D16_SIGN;       /*     then add 32K and try again */
2726 
2727         if (class == data_checked && NPRV                   /* if checking is requested and non-privileged */
2728           && (starting_word < DL || starting_word > SM))    /*   and still out of range */
2729             MICRO_ABORT (trap_Bounds_Violation);            /*     then trap for a bounds violation */
2730         }
2731 
2732     if (block_length != 0) {                            /* if a block length was supplied */
2733         ending_word =                                   /*   then determine the ending word address */
2734            starting_word + ((block_length - increment + (byte_offset & 1)) >> 1) & LA_MASK;
2735 
2736         if (class == data_checked && NPRV               /* if checking is requested and non-privileged */
2737           && (ending_word < DL || ending_word > SM))    /*   and the address is out of range */
2738             MICRO_ABORT (trap_Bounds_Violation);        /*     then trap for a bounds violation */
2739         }
2740     }
2741 
2742 
2743 return starting_word;                                   /* return the starting word address */
2744 }
2745 
2746 
2747 /* Set up the entry into an interrupt handler.
2748 
2749    This routine prepares the CPU state to execute an interrupt handling
2750    procedure.  On entry, "class" is the classification of the current interrupt,
2751    and "parameter" is the parameter associated with the interrupt.  On exit, the
2752    stack has been set up correctly, and the PB, P, PL, and status registers have
2753    been set up for entry into the interrupt procedure.
2754 
2755    Run-mode interrupts are classified as external or internal and ICS or
2756    non-ICS.  External interrupts are those originating with the device
2757    controllers, and internal interrupts are conditions detected by the microcode
2758    (e.g., a bounds violation or arithmetic overflow).  ICS interrupts execute
2759    their handlers on the system's Interrupt Control Stack.  Non-ICS interrupts
2760    execute on the user's stack.
2761 
2762    Of the run-mode interrupts, the External, System Parity Error, Address
2763    Parity Error, Data Parity Error, and Module interrupts execute on the ICS.
2764    All other interrupts execute on the user's stack.  The routine begins by
2765    determining whether an ICS or non-ICS interrupt is indicated.  The
2766    appropriate stack is established, and the stack marker is written to preserve
2767    the state of the interrupted routine.  The label of the handler procedure is
2768    obtained, and then the procedure designated by the label is set up.  On
2769    return, the first instruction of the handler is ready to execute.
2770 
2771 
2772    Implementation notes:
2773 
2774     1. This routine implements various execution paths through the microcode
2775        labeled as INT0 through INT7.
2776 
2777     2. This routine is also called directly by the IXIT instruction executor if
2778        an external interrupt is pending.  This is handled as an external
2779        interrupt but is classified differently so that the teardown and rebuild
2780        of the stack may be avoided to improve performance.
2781 */
2782 
cpu_setup_irq_handler(IRQ_CLASS class,HP_WORD parameter)2783 void cpu_setup_irq_handler (IRQ_CLASS class, HP_WORD parameter)
2784 {
2785 HP_WORD label;
2786 
2787 if (class == irq_External || class == irq_IXIT) {       /* if entry is for an external interrupt */
2788     if (class == irq_External)                          /*   then if it was detected during normal execution */
2789         cpu_setup_ics_irq (class, 0);                   /*     then set it up on the ICS */
2790     else                                                /*   otherwise it was detected during IXIT */
2791         SM = Q + 2 & R_MASK;                            /*     so the ICS is already set up */
2792 
2793     DBANK = 0;                                          /* all handlers are in bank 0 */
2794     STA = STATUS_M | STATUS_I;                          /* enter privileged mode with interrupts enabled */
2795 
2796     cpu_read_memory (stack, parameter * 4 + 2, &DB);    /* read the DB value */
2797     cpu_read_memory (stack, parameter * 4 + 1, &label); /*   and the procedure label from the DRT */
2798     }
2799 
2800 else if (class >= irq_System_Parity                     /* otherwise if entry is for */
2801   && class <= irq_Power_Fail) {                         /*   another ICS interrupt */
2802     cpu_setup_ics_irq (class, 0);                       /*     then set it up on the ICS */
2803 
2804     label = TO_LABEL (LABEL_IRQ, class);                /* form the label for the specified classification */
2805 
2806     STA = STATUS_M;                                     /* clear status and enter privileged mode */
2807     }
2808 
2809 else {                                                  /* otherwise entry is for a non-ICS interrupt */
2810     if (class == irq_Integer_Overflow)                  /* if this is an integer overflow interrupt */
2811         label = TO_LABEL (LABEL_IRQ, trap_User);        /*   then form the label for a user trap */
2812     else                                                /* otherwise form the label */
2813         label = TO_LABEL (LABEL_IRQ, class);            /*   for the specified classification */
2814 
2815     cpu_flush ();                                       /* flush the TOS registers to memory */
2816     cpu_mark_stack ();                                  /*   and write a stack marker */
2817 
2818     STA = STATUS_M;                                     /* clear status and enter privileged mode */
2819     }
2820 
2821 SM = SM + 1 & R_MASK;                                   /* increment the stack pointer */
2822 cpu_write_memory (stack, SM, parameter);                /*   and push the parameter on the stack */
2823 
2824 X = CIR;                                                /* save the CIR in the index register */
2825 
2826 cpu_call_procedure (label, 0);                          /* set up to call the interrupt handling procedure */
2827 
2828 return;
2829 }
2830 
2831 
2832 /* Set up an interrupt on the Interrupt Control Stack.
2833 
2834    This routine prepares the Interrupt Control Stack (ICS) to support interrupt
2835    processing.  It is called from the run-time interrupt routine for ICS
2836    interrupts, the microcode abort routine for ICS traps, and from the DISP and
2837    PSEB instruction executors before entering the dispatcher.  On entry, "class"
2838    is the interrupt classification, and, if the class is "irq_Trap", then "trap"
2839    is the trap classification.  The trap classification is ignored for
2840    interrupts, including the dispatcher start interrupt.
2841 
2842    Unless entry is for a Cold Load trap, the routine begins by writing a
2843    six-word stack marker.  This special ICS marker extends the standard marker
2844    by adding the DBANK and DB values as follows:
2845 
2846        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
2847      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2848      |                       X register value                        |  [Q - 3]  X
2849      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2850      |                  PB-relative return address                   |  [Q - 2]  P + 1 - PB
2851      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2852      |                     Status register value                     |  [Q - 1]  STA
2853      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2854      | D |                     Delta Q value                         |  [Q - 0]  S - Q
2855      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2856      |                         DB-Bank value                         |  [Q + 1]  DBANK
2857      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2858      |                           DB value                            |  [Q + 2]  DB
2859      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2860 
2861    Where:
2862 
2863      D = the dispatcher was interrupted
2864 
2865    After the values are written, the Q register is set to point to the marker.
2866    The stack bank register is then cleared, as the ICS is always located in
2867    memory bank 0.
2868 
2869    If the interrupt or trap occurred while executing on the ICS, and the
2870    dispatcher was running at the time, the "dispatcher running" bit in the CPX1
2871    register is cleared, and the D-bit is set in the delta-Q value word of the
2872    stack marker.  This bit will be used during interrupt exit to decide whether
2873    to restart the dispatcher.
2874 
2875    If the CPU was executing on the user's stack, the "ICS flag" bit in CPX1 is
2876    set, the Q register is reset to point at the permanent dispatcher stack
2877    marker established by the operating system, and the Z register is reset to
2878    the stack limit established by the OS for the ICS; the values are obtained
2879    from reserved memory locations 5 and 6, respectively.  The ICS DB value is
2880    read from the ICS global area that precedes the dispatcher stack marker and
2881    is used to write the stack-DB-relative S value back to the global area.
2882 
2883    Finally, the stack pointer is set to point just above the stack marker.
2884 
2885 
2886    Implementation notes:
2887 
2888     1. This routine implements various execution paths through the microcode
2889        labeled as INT1 through INT5.
2890 */
2891 
cpu_setup_ics_irq(IRQ_CLASS class,TRAP_CLASS trap)2892 void cpu_setup_ics_irq (IRQ_CLASS class, TRAP_CLASS trap)
2893 {
2894 HP_WORD delta_q, stack_db;
2895 
2896 if (class != irq_Trap                                   /* if this is not */
2897   || trap != trap_Cold_Load && trap != trap_Power_On) { /*   a cold load or power on trap entry */
2898     cpu_flush ();                                       /*     then flush the TOS registers to memory */
2899     cpu_mark_stack ();                                  /*       and write a four-word stack marker */
2900 
2901     cpu_write_memory (stack, SM + 1 & LA_MASK, DBANK);  /* add DBANK and DB to the stack */
2902     cpu_write_memory (stack, SM + 2 & LA_MASK, DB);     /*   to form a six-word ICS marker */
2903     }
2904 
2905 SBANK = 0;                                              /* the ICS is always located in bank 0 */
2906 
2907 if (CPX1 & cpx1_ICSFLAG) {                              /* if execution is currently on the ICS */
2908     if (CPX1 & cpx1_DISPFLAG) {                         /*   then if the dispatcher was interrupted */
2909         CPX1 &= ~cpx1_DISPFLAG;                         /*     then clear the dispatcher flag */
2910 
2911         cpu_read_memory (stack, Q, &delta_q);           /* get the delta Q value from the stack marker */
2912         cpu_write_memory (stack, Q, delta_q | STMK_D);  /*   and set the dispatcher-interrupted flag */
2913         }
2914     }
2915 
2916 else {                                                  /* otherwise execution is on the user's stack */
2917     CPX1 |= cpx1_ICSFLAG;                               /*   so set the ICS flag */
2918 
2919     cpu_read_memory (stack, ICS_Q, &Q);                 /* set Q = QI */
2920     cpu_read_memory (stack, ICS_Z, &Z);                 /* set Z = ZI */
2921 
2922     cpu_read_memory (stack, Q - 4 & LA_MASK,            /* read the stack DB value */
2923                      &stack_db);
2924 
2925     cpu_write_memory (stack, Q - 6 & LA_MASK,           /* write the stack-DB-relative S value */
2926                       SM + 2 - stack_db & DV_MASK);     /*   which is meaningless for a cold load or power on */
2927 
2928     SR = 0;                                             /* invalidate the stack registers for a cold load */
2929     DL = D16_UMAX;                                      /*   and set the data limit */
2930     }
2931 
2932 SM = Q + 2 & R_MASK;                                    /* set S above the stack marker */
2933 
2934 return;
2935 }
2936 
2937 
2938 /* Set up a code segment.
2939 
2940    This routine is called to set up a code segment in preparation for calling or
2941    exiting a procedure located in a segment different from the currently
2942    executing segment.  On entry, "label" indicates the segment number containing
2943    the procedure.  On exit, the new status register value and the first word of
2944    the Code Segment Table entry are returned to the variables pointed to by
2945    "status" and "entry_0", respectively.
2946 
2947    The routine begins by reading the CST pointer.  The CST is split into two
2948    parts: a base table, and an extension table.  The table to use is determined
2949    by the requested segment number.  Segment numbers 0 and 192, corresponding to
2950    the first entries of the two tables, are reserved and cause a CST Violation
2951    trap if specified.
2952 
2953    The CST entry corresponding to the segment number is examined to set the
2954    program bank, base, and limit registers (the segment length stored in the
2955    table is number of quad-words, which must be multiplied by four to get the
2956    size in words).  The new status register value is set up and returned, along
2957    with the first word of the CST entry.
2958 
2959 
2960    Implementation notes:
2961 
2962     1. This routine implements the microcode SSEG subroutine.
2963 
2964     2. Passing -1 as a parameter to trap_CST_Violation ensures that the segment
2965        number >= 2 check will pass and the trap handler will be invoked.
2966 
2967     3. The Series II microcode sets PBANK and PB unilaterally but sets PL only
2968        if the code segment is not absent.  An absent segment entry contains the
2969        disc address in words 3 and 4 instead of the bank address and base
2970        address, so PBANK and PB will contain invalid values in this case.  It is
2971        not clear why the microcode avoids setting PL; the microinstruction in
2972        question also sets Flag 2, so conditioning PL may be just a side effect.
2973        In any case, we duplicate the firmware behavior here.
2974 
2975     4. This routine is only used locally, but we leave it as a global entry to
2976        support future firmware extensions that may need to call it.
2977 */
2978 
cpu_setup_code_segment(HP_WORD label,HP_WORD * status,HP_WORD * entry_0)2979 void cpu_setup_code_segment (HP_WORD label, HP_WORD *status, HP_WORD *entry_0)
2980 {
2981 HP_WORD cst_pointer, cst_size, cst_entry, cst_bank, segment_number, entry_number;
2982 
2983 segment_number = STT_SEGMENT (label);                       /* isolate the segment number from the label */
2984 
2985 if (segment_number < CST_RESERVED) {                        /* if the target segment is in the base table */
2986     cpu_read_memory (absolute, CSTB_POINTER, &cst_pointer); /*   then read the CST base pointer */
2987     entry_number = segment_number;                          /*     and set the entry number */
2988     }
2989 
2990 else {                                                      /* otherwise it is in the extension table */
2991     cpu_read_memory (absolute, CSTX_POINTER, &cst_pointer); /*   so read the CST extension pointer */
2992     entry_number = segment_number - CST_RESERVED;           /*     and set the entry number */
2993     }
2994 
2995 if (entry_number == 0)                                  /* segment numbers 0 and 192 do not exist */
2996     MICRO_ABORTP (trap_CST_Violation, -1);              /*   so trap for a violation if either is specified */
2997 
2998 cpu_read_memory (absolute, cst_pointer, &cst_size);     /* read the table size */
2999 
3000 if (entry_number > cst_size)                            /* if the entry is outside of the table */
3001     MICRO_ABORTP (trap_CST_Violation, entry_number);    /*   then trap for a violation */
3002 
3003 cst_entry = cst_pointer + entry_number * 4;             /* get the address of the target CST entry */
3004 
3005 cpu_read_memory  (absolute, cst_entry, entry_0);                /* get the first word of the entry */
3006 cpu_write_memory (absolute, cst_entry, *entry_0 | CST_R_BIT);   /*   and set the segment reference bit */
3007 
3008 cpu_read_memory (absolute, cst_entry + 2, &cst_bank);   /* read the bank address word */
3009 PBANK = cst_bank & CST_BANK_MASK;                       /*   and mask to just the bank number */
3010 
3011 cpu_read_memory (absolute, cst_entry + 3, &PB);         /* read the segment's base address */
3012 
3013 PL = (*entry_0 & CST_SEGLEN_MASK) * 4 - 1;              /* set PL to the segment length - 1 */
3014 
3015 *status = STA & ~LABEL_SEGMENT_MASK | segment_number;   /* set the segment number in the new status word */
3016 
3017 if (*entry_0 & CST_M_BIT)                               /* if the segment executes in privileged mode */
3018     *status |= STATUS_M;                                /*   then set up to enter privileged mode */
3019 
3020 if (! (*entry_0 & CST_A_BIT))                           /* if the segment is not absent */
3021     PL = PL + PB;                                       /*   then set the segment limit */
3022 
3023 return;
3024 }
3025 
3026 
3027 /* Set up a data segment.
3028 
3029    This routine is called to set up a data segment for access.  It is called by
3030    the MDS, MFDS, and MTDS instruction executors to obtain the bank and offset
3031    of specified segments from the Data Segment Table.  On entry,
3032    "segment_number" indicates the number of the desired data segment.  On exit,
3033    the memory bank number and offset of the data segment base are returned to
3034    the variables pointed to by "bank" and "address", respectively.
3035 
3036    The routine begins by reading the DST pointer.  Segment number 0,
3037    corresponding to the first entry of the table, is reserved and causes a DST
3038    Violation trap if specified.
3039 
3040    The DST entry corresponding to the segment number is examined to obtain the
3041    bank and base address.  If the segment is absent, a Data Segment Absent trap
3042    is taken.  Otherwise, the bank and address values are returned.
3043 
3044 
3045    Implementation notes:
3046 
3047     1. This routine implements the microcode DSEG subroutine.
3048 */
3049 
cpu_setup_data_segment(HP_WORD segment_number,HP_WORD * bank,HP_WORD * address)3050 void cpu_setup_data_segment (HP_WORD segment_number, HP_WORD *bank, HP_WORD *address)
3051 {
3052 HP_WORD dst_pointer, dst_size, dst_entry, entry_0;
3053 
3054 cpu_read_memory (absolute, DST_POINTER, &dst_pointer);  /* read the DST base pointer */
3055 
3056 if (segment_number == 0)                                /* segment number 0 does not exist */
3057     MICRO_ABORT (trap_DST_Violation);                   /*   so trap for a violation if it is specified */
3058 
3059 cpu_read_memory (absolute, dst_pointer, &dst_size);     /* read the table size */
3060 
3061 if (segment_number > dst_size)                          /* if the entry is outside of the table */
3062     MICRO_ABORT (trap_DST_Violation);                   /*   then trap for a violation */
3063 
3064 dst_entry = dst_pointer + segment_number * 4;           /* get the address of the target DST entry */
3065 
3066 cpu_read_memory (absolute, dst_entry, &entry_0);                /* get the first word of the entry */
3067 cpu_write_memory (absolute, dst_entry, entry_0 | DST_R_BIT);    /*   and set the segment reference bit */
3068 
3069 if (entry_0 & DST_A_BIT)                                /* if the segment is absent */
3070     MICRO_ABORTP (trap_DS_Absent, segment_number);      /*   then trap for an absentee violation */
3071 
3072 cpu_read_memory (absolute, dst_entry + 2, bank);        /* read the segment bank number */
3073 cpu_read_memory (absolute, dst_entry + 3, address);     /*   and base address */
3074 
3075 *bank = *bank & DST_BANK_MASK;                          /* mask off the reserved bits */
3076 
3077 return;                                                 /*   before returning to the caller */
3078 }
3079 
3080 
3081 /* Call a procedure.
3082 
3083    This routine sets up the PB, P, PL, and status registers to enter a
3084    procedure.  It is called by the PCAL instruction executor and by the
3085    interrupt and trap routines to set up the handler procedures.  On entry,
3086    "label" contains an external program label indicating the segment number and
3087    Segment Transfer Table entry number describing the procedure, or a local
3088    program label indicating the starting address of the procedure, and "offset"
3089    contains an offset to be added to the starting address.  On exit, the
3090    registers are set up for execution to resume with the first instruction of
3091    the procedure.
3092 
3093    If the label is a local label, the PB-relative address is obtained from the
3094    label and stored in the P register, and the Next Instruction Register is
3095    loaded with the first instruction of the procedure.
3096 
3097    If the label is external, the code segment referenced by the label is set up.
3098    If the "trace" or "absent" bits are set, the corresponding trap is taken.
3099    Otherwise, the Segment Transfer Table length is read, and the STT entry
3100    number is validated; if it references a location outside of the table, a STT
3101    violation trap is taken.
3102 
3103    Otherwise, the valid STT entry is examined.  If the target procedure is not
3104    in the designated code segment or is uncallable if not in privileged mode,
3105    the appropriate traps are taken.  If the STT entry contains a local label, it
3106    is used to set up the P register and NIR as above.
3107 
3108    The "offset" parameter is used only by the XBR instruction executor.  The
3109    PCAL executor and the interrupt handlers pass an offset of zero to begin
3110    execution at the first instruction of the designated procedure.
3111 
3112 
3113    Implementation notes:
3114 
3115     1. This routine implements the microcode PCL3 and PCL5 subroutines.
3116 */
3117 
cpu_call_procedure(HP_WORD label,HP_WORD offset)3118 void cpu_call_procedure (HP_WORD label, HP_WORD offset)
3119 {
3120 HP_WORD new_status, new_label, new_p, cst_entry, stt_size, stt_entry;
3121 
3122 new_status = STA;                                       /* save the status for a local label */
3123 
3124 if (label & LABEL_EXTERNAL) {                                   /* if the label is non-local */
3125     cpu_setup_code_segment (label, &new_status, &cst_entry);    /*   then set up the corresponding code segment */
3126 
3127     stt_entry = STT_NUMBER (label);                     /* get the STT entry number from the label */
3128 
3129     if (cst_entry & (CST_A_BIT | CST_T_BIT)) {          /* if the code segment is absent or being traced */
3130         STA = new_status;                               /*   then set the new status before trapping */
3131         cpu_mark_stack ();                              /*     and write a stack marker to memory */
3132 
3133         if (cst_entry & CST_A_BIT)                      /* if the code segment is absent */
3134             MICRO_ABORTP (trap_CS_Absent, label);       /*   then trap to load it */
3135         else                                            /* otherwise */
3136             MICRO_ABORTP (trap_Trace, label);           /*   trap to trace it */
3137         }
3138 
3139     cpu_read_memory (program_checked, PL, &stt_size);   /* read the table size */
3140 
3141     if (stt_entry > STT_LENGTH (stt_size))              /* if the entry is outside of the table */
3142         MICRO_ABORTP (trap_STT_Violation, new_status);  /*   then trap for a violation */
3143 
3144     cpu_read_memory (program_checked, PL - stt_entry, &new_label);  /* read the label from the STT */
3145 
3146     if (new_label & LABEL_EXTERNAL)                     /* if the procedure is not in the target segment */
3147         MICRO_ABORTP (trap_STT_Violation, new_status);  /*   then trap for a violation */
3148 
3149     if ((new_label & LABEL_UNCALLABLE) && NPRV)         /* if the procedure is uncallable in the current mode */
3150         MICRO_ABORTP (trap_Uncallable, label);          /*   then trap for a violation */
3151 
3152     if (stt_entry == 0)                                 /* if the STT number is zero in an external label */
3153         label = 0;                                      /*   then the starting address is PB */
3154     else                                                /* otherwise */
3155         label = new_label;                              /*   the PB offset is contained in the new label */
3156 
3157     cpu_base_changed = TRUE;                            /* the program base registers have changed for tracing */
3158     }
3159 
3160 new_p = PB + (label + offset & LABEL_ADDRESS_MASK);     /* get the procedure starting address */
3161 
3162 cpu_read_memory (fetch_checked, new_p, &NIR);           /* check the bounds and get the next instruction */
3163 P = new_p + 1 & R_MASK;                                 /* the bounds are valid, so set the new P value */
3164 
3165 STA = new_status;                                       /* set the new status value */
3166 
3167 return;
3168 }
3169 
3170 
3171 /* Return from a procedure.
3172 
3173    This routine sets up the P, Q, SM, and status registers to return from a
3174    procedure.  It is called by the EXIT and IXIT instruction executors and by
3175    the cpu_start_dispatcher routine to enter the dispatcher.  On entry, "new_q"
3176    and "new_sm" contain the new values for the Q and SM registers that unwind
3177    the stack.  The "parameter" value is used only if a Trace or Code Segment
3178    Absent trap is taken.  For EXIT, the parameter is the stack adjustment value
3179    (the N field).  For IXIT, the parameter is zero.  On exit, the registers are
3180    set up for execution to resume with the first instruction after the procedure
3181    call or interrupt.
3182 
3183    The routine begins by reloading register values from the stack marker.  The
3184    stack marker format is:
3185 
3186        0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
3187      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3188      |                       X register value                        |  [Q - 3]  X
3189      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3190      | T | M |          PB-relative return address                   |  [Q - 2]  P + 1 - PB
3191      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3192      |                     Status register value                     |  [Q - 1]  STA
3193      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3194      |                         Delta Q value                         |  [Q - 0]  S - Q
3195      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
3196 
3197    Where:
3198 
3199      T = a trace or control-Y interrupt is pending
3200      M = the code segment is physically mapped
3201 
3202    The T and M bits are set by the operating system, if applicable, after the
3203    stack marker was originally written.
3204 
3205    Stack underflow and overflow are checked, and privilege changes are
3206    validated.  If the return will be to a different code segment, it is set up.
3207    Finally, the new P, Q, SM, and status register values are loaded, and NIR is
3208    loaded with the first instruction after the return.
3209 
3210 
3211    Implementation notes:
3212 
3213     1. This routine implements the microcode EXI1 subroutine.
3214 
3215     2. We pass a temporary status to cpu_setup_code_segment because it forms the
3216        returned new status from the current STA register value.  But for EXIT
3217        and IXIT, the new status comes from the stack marker, which already has
3218        the segment number to which we're returning, and which must not be
3219        altered.
3220 
3221     3. The NEXT action is modified when the R-bit is set in the status word
3222        being restored.  This occurs when an interrupt occurred between the two
3223        stackops of a stack instruction.  The main instruction loop does not
3224        alter CIR in this case, so we must set it up here.
3225 */
3226 
cpu_exit_procedure(HP_WORD new_q,HP_WORD new_sm,HP_WORD parameter)3227 void cpu_exit_procedure (HP_WORD new_q, HP_WORD new_sm, HP_WORD parameter)
3228 {
3229 HP_WORD temp_status, new_status, new_p, cst_entry;
3230 
3231 SM = Q;                                                 /* delete any local values from the stack */
3232 
3233 if (new_q > Z || new_sm > Z)                            /* if either the new Q or SM exceed the stack limit */
3234     MICRO_ABORT (trap_Stack_Overflow);                  /*   then trap with a stack overflow */
3235 
3236 cpu_read_memory (stack, Q - 1, &new_status);            /* read the new status value from the stack marker */
3237 
3238 if ((CIR & EXIT_MASK) == EXIT                           /* if an EXIT instruction is executing */
3239   && (new_q < DB || new_sm < DB)                        /*   and either new Q or new S are below the data base */
3240   && (new_status & STATUS_M) == 0)                      /*     and the new mode is non-privileged */
3241     MICRO_ABORT (trap_Stack_Underflow);                 /*       then trap with a stack underflow */
3242 
3243 cpu_read_memory (stack, Q - 2, &new_p);                 /* read the PB-relative return value from the stack marker */
3244 
3245 if (NPRV                                                /* if currently in user mode */
3246   && ((new_status & STATUS_M)                           /*   and returning to privileged mode */
3247   || (new_status & STATUS_I) != (STA & STATUS_I)))      /*   or attempting to change interrupt state */
3248     MICRO_ABORT (trap_Privilege_Violation);             /*     then trap with a privilege violation */
3249 
3250 STA &= ~STATUS_I;                                       /* turn off external interrupts */
3251 
3252 cpu_read_memory (stack, Q - 3, &X);                     /* read the new X value from the stack marker */
3253 
3254 if (STATUS_CS (new_status) != STATUS_CS (STA)) {                    /* if returning to a different segment */
3255     cpu_setup_code_segment (new_status, &temp_status, &cst_entry);  /*   then set up the new segment */
3256 
3257     if (NPRV && (temp_status & STATUS_M))               /* if in user mode now and returning to a privileged segment */
3258         MICRO_ABORT (trap_Privilege_Violation);         /*   then trap with a privilege violation */
3259 
3260     if (new_p & STMK_T)                                 /* if the new code segment is being traced */
3261         MICRO_ABORTP (trap_Trace, parameter);           /*   then trap to trace it */
3262 
3263     if (cst_entry & CST_A_BIT)                          /* if the code segment is absent */
3264         MICRO_ABORTP (trap_CS_Absent, parameter);       /*   then trap to load it */
3265     }
3266 
3267 new_p = PB + (new_p & STMK_RTN_ADDR);                   /* convert the relative address to absolute */
3268 
3269 cpu_read_memory (fetch_checked, new_p, &NIR);           /* check the bounds and get the next instruction */
3270 P = new_p + 1 & R_MASK;                                 /* the bounds are valid, so set the new P value */
3271 
3272 STA = new_status;                                       /* set the new status value */
3273 Q   = new_q;                                            /*   and the stack marker */
3274 SM  = new_sm;                                           /*     and the stack pointer */
3275 
3276 if (STA & STATUS_R) {                                   /* if a right-hand stack op is pending */
3277     CIR = NIR;                                          /*   then set the current instruction */
3278     cpu_read_memory (fetch, P, &NIR);                   /*     and load the next instruction */
3279     }
3280 
3281 cpu_base_changed = TRUE;                                /* one or more base registers have changed for tracing */
3282 
3283 return;
3284 }
3285 
3286 
3287 /* Start the dispatcher.
3288 
3289    This routine is called by the DISP and PSEB instruction executors to start
3290    the dispatcher and by the IXIT executor to restart the dispatcher if it was
3291    interrupted.
3292 
3293    On entry, the ICS has been set up.  The "dispatcher running" bit in the CPX1
3294    register is set, Q is set to point at the permanent dispatcher stack marker
3295    on the ICS, the dispatcher's DBANK and DB registers are loaded, and an "exit
3296    procedure" is performed to return to the dispatcher.
3297 */
3298 
cpu_start_dispatcher(void)3299 void cpu_start_dispatcher (void)
3300 {
3301 tprintf (cpu_dev, DEB_INSTR, BOV_FORMAT "%s interrupt\n",
3302          PBANK, P - 1 & R_MASK, 0, interrupt_name [irq_Dispatch]);
3303 
3304 CPX1 |= cpx1_DISPFLAG;                                  /* set the "dispatcher is running" flag */
3305 
3306 cpu_read_memory (absolute, ICS_Q, &Q);                  /* set Q to point to the dispatcher's stack marker */
3307 cpu_write_memory (absolute, Q, 0);                      /*   and clear the stack marker delta Q value */
3308 
3309 cpu_read_memory (stack, Q + 1 & LA_MASK, &DBANK);       /* load the dispatcher's data bank */
3310 cpu_read_memory (stack, Q + 2 & LA_MASK, &DB);          /*   and data base registers */
3311 
3312 cpu_exit_procedure (Q, Q + 2, 0);                       /* return to the dispatcher */
3313 
3314 return;
3315 }
3316 
3317 
3318 
3319 /* CPU local SCP support routines */
3320 
3321 
3322 /* Service the CPU process clock.
3323 
3324    The process clock is used by the operating system to time per-process CPU
3325    usage.  It is always enabled and running, although the PCLK register only
3326    increments if the CPU is not executing on the ICS.
3327 
3328    The process clock may be calibrated to wall-clock time or set to real time.
3329    In hardware, the process clock has a one-millisecond period.  Setting the
3330    mode to real time schedules clock events based on the number of event ticks
3331    equivalent to one millisecond.  Because the simulator is an order of
3332    magnitude faster than the hardware, this short period precludes idling.
3333 
3334    In the calibrated mode, the short period would still preclude idling.
3335    Therefore, in this mode, the clock is scheduled with a ten-millisecond
3336    service time, and the PCLK register is incremented by ten for each event
3337    service.  To present the correct value when PCLK is read, the
3338    "cpu_update_pclk" routine is called by the RCLK instruction executor to
3339    increment the count by an amount proportional to the fraction of the service
3340    interval that has elapsed.  In addition, that routine is called by the CPU
3341    instruction postlude, so that PCLK will have the correct value if it is
3342    examined from the SCP command prompt.
3343 
3344    The simulation console is normally hosted by, and therefore polled by, the
3345    ATC on channel 0.  If the console is not hosted by the ATC, due to a SET ATC
3346    DISABLED command, the process clock assumes polling control over the console.
3347 
3348 
3349    Implementation notes:
3350 
3351     1. If the process clock is calibrated, the system clock and ATC poll
3352        services are synchronized with the process clock service to improve
3353        idling.
3354 
3355     2. The current CPU speed, expressed as a multiple of the hardware speed, is
3356        calculated for each service entry.  It may be displayed at the SCP prompt
3357        with the SHOW CPU SPEED command.  The speed is only representative when
3358        the process clock is calibrated, and the CPU is not executing a PAUS
3359        instruction (which suspends the normal fetch/execute instruction cycle).
3360 */
3361 
cpu_service(UNIT * uptr)3362 static t_stat cpu_service (UNIT *uptr)
3363 {
3364 const t_bool ics_exec = (CPX1 & cpx1_ICSFLAG) != 0;     /* TRUE if the CPU is executing on the ICS */
3365 static uint32 last_cpu_speed = 0;                       /* last CPU execution rate multiple */
3366 t_stat status;
3367 
3368 tprintf (cpu_dev, DEB_PSERV, "Process clock delay %d service entered on the %s\n",
3369          uptr->wait, (ics_exec ? "ICS" : "user stack"));
3370 
3371 if (!ics_exec)                                          /* if the CPU is not executing on the ICS */
3372     PCLK = PCLK + pclk_increment & R_MASK;              /*   then increment the process clock */
3373 
3374 cpu_is_calibrated = (uptr->flags & UNIT_CALTIME) != 0;  /* TRUE if the process clock is calibrated */
3375 
3376 if (cpu_is_calibrated) {                                /* if the process clock is tracking wall-clock time */
3377     uptr->wait = sim_rtcn_calb (PCLK_RATE, TMR_PCLK);   /*   then calibrate it */
3378     pclk_increment = PCLK_MULTIPLIER;                   /*     and set the increment to the multiplier */
3379     }
3380 
3381 else {                                                  /* otherwise */
3382     uptr->wait = PCLK_PERIOD;                           /*   set the delay as an event tick count */
3383     pclk_increment = 1;                                 /*     and set the increment without multiplying */
3384     }
3385 
3386 sim_activate (uptr, uptr->wait);                        /* reschedule the timer */
3387 
3388 cpu_speed = uptr->wait / (PCLK_PERIOD * pclk_increment);    /* calculate the current CPU speed multiplier */
3389 
3390 if (TRACING (cpu_dev, DEB_PSERV))
3391     if (last_cpu_speed != cpu_speed) {
3392         hp_trace (&cpu_dev, DEB_PSERV, "Simulation rate %ux\n", cpu_speed);
3393         last_cpu_speed = cpu_speed;
3394         }
3395 
3396 if (atc_is_polling == FALSE) {                          /* if the ATC is not polling for the simulation console */
3397     status = sim_poll_kbd ();                           /*   then we must poll for a console interrupt */
3398 
3399     if (status < SCPE_KFLAG)                            /* if the result is not a character */
3400         return status;                                  /*   then return the resulting status */
3401     }
3402 
3403 return SCPE_OK;                                         /* return the success of the service */
3404 }
3405 
3406 
3407 /* Reset the CPU.
3408 
3409    This routine is called for a RESET, RESET CPU, or BOOT CPU command.  It is the
3410    simulation equivalent of the CPURESET signal, which is asserted by the front
3411    panel LOAD switch.  In hardware, this causes a microcode restart in addition
3412    to clearing certain registers.
3413 
3414    If this is the first call after simulator startup, the initial memory array
3415    is allocated, the default CPU and memory size configuration is set, and the
3416    SCP-required program counter pointer is set to point to the REG array element
3417    corresponding to the P register.
3418 
3419    If this is a power-on reset ("RESET -P"), the process clock calibrated timer
3420    is initialized, and any LOAD or DUMP request in progress is cleared.
3421 
3422    The micromachine is halted, the process clock is scheduled, and several
3423    registers are cleared.
3424 
3425 
3426    Implementation notes:
3427 
3428     1. Setting the sim_PC value at run time accommodates changes in the register
3429        order automatically.  A fixed setting runs the risk of it not being
3430        updated if a change in the register order is made.
3431 */
3432 
cpu_reset(DEVICE * dptr)3433 static t_stat cpu_reset (DEVICE *dptr)
3434 {
3435 if (sim_PC == NULL) {                                   /* if this is the first call after simulator start */
3436     if (mem_initialize (PA_MAX)) {                      /*   then if memory allocation succeeds */
3437         set_model (&cpu_unit [0], UNIT_CPU_MODEL,       /*     then establish the default CPU model */
3438                    NULL, NULL);
3439 
3440         for (sim_PC = dptr->registers;                      /* find the P register entry */
3441              sim_PC->loc != &P && sim_PC->loc != NULL;      /*   in the register array */
3442              sim_PC++);                                     /*     for the SCP interface */
3443 
3444         if (sim_PC == NULL)                                 /* if the P register entry is not present */
3445             return SCPE_NXREG;                              /*   then there is a serious problem! */
3446         }
3447 
3448     else                                                /* otherwise memory initialization failed */
3449         return SCPE_MEM;                                /*   so report the error and abort the simulation */
3450     }
3451 
3452 if (sim_switches & SWMASK ('P')) {                      /* if this is a power-on reset */
3453     sim_rtcn_init (cpu_unit [0].wait, TMR_PCLK);        /*   then initialize the process clock timer */
3454     CPX2 &= ~(cpx2_LOADSWCH | cpx2_DUMPSWCH);           /*     and clear any cold load or dump request */
3455     }
3456 
3457 cpu_micro_state = halted;                               /* halt the micromachine */
3458 sim_activate_abs (&cpu_unit [0], cpu_unit [0].wait);    /*   and schedule the process clock */
3459 
3460 PCLK = 0;                                               /* clear the process clock counter */
3461 CPX1 = 0;                                               /*   and all run-mode signals */
3462 CPX2 &= ~(cpx2_RUN | cpx2_SYSHALT);                     /*     and the run and system halt flip-flops */
3463 
3464 if (cpu_unit [0].flags & UNIT_PFARS)                    /* if the PF/ARS switch position is ENBL */
3465     CPX2 &= ~cpx2_INHPFARS;                             /*   then clear the auto-restart inhibit flag */
3466 else                                                    /* otherwise the position is DSBL */
3467     CPX2 |= cpx2_INHPFARS;                              /*   so set the auto-restart inhibit flag */
3468 
3469 CNTR = SR;                                              /* copy the stack register to the counter */
3470 cpu_flush ();                                           /*   and flush the TOS registers to memory */
3471 
3472 return SCPE_OK;                                         /* indicate that the reset succeeded */
3473 }
3474 
3475 
3476 /* Set the CPU simulation stop conditions.
3477 
3478    This validation routine is called to configure the set of CPU stop
3479    conditions.  The "option" parameter is 0 to clear the stops and 1 to set
3480    them, and "cptr" points to the first character of the name of the stop to be
3481    cleared or set.  The unit and description pointers are not used.
3482 
3483    The routine processes commands of the form:
3484 
3485      SET CPU STOP
3486      SET CPU STOP=<stopname>[;<stopname>...]
3487      SET CPU NOSTOP
3488      SET CPU NOSTOP=<stopname>[;<stopname>...]
3489 
3490    The valid <stopname>s are contained in the debug table "cpu_stop".  If names
3491    are not specified, all stop conditions are enabled or disabled.
3492 
3493 
3494    Implementation notes:
3495 
3496     1. The CPU simulator maintains a private and a public set of simulator
3497        stops.  This routine sets the private set.  The private set is copied to
3498        the public set as part of the instruction execution prelude, unless the
3499        "-B" ("bypass") command-line switch is used with the run command.  This
3500        allows the stops to be bypassed conveniently for the first instruction
3501        execution only.
3502 */
3503 
set_stops(UNIT * uptr,int32 option,char * cptr,void * desc)3504 static t_stat set_stops (UNIT *uptr, int32 option, char *cptr, void *desc)
3505 {
3506 char gbuf [CBUFSIZE];
3507 uint32 stop;
3508 
3509 if (cptr == NULL) {                                     /* if there are no arguments */
3510     sim_stops = 0;                                      /*   then clear all of the stop flags */
3511 
3512     if (option == 1)                                            /* if we're setting the stops */
3513         for (stop = 0; cpu_stop [stop].name != NULL; stop++)    /*   then loop through the flags */
3514             sim_stops |= cpu_stop [stop].mask;                  /*     and add each one to the set */
3515     }
3516 
3517 else if (*cptr == '\0')                                 /* otherwise if the argument is empty */
3518     return SCPE_MISVAL;                                 /*   then report the missing value */
3519 
3520 else                                                    /* otherwise at least one argument is present */
3521     while (*cptr) {                                     /* loop through the arguments */
3522         cptr = get_glyph (cptr, gbuf, ';');             /* get the next argument */
3523 
3524         for (stop = 0; cpu_stop [stop].name != NULL; stop++)    /* loop through the flags */
3525             if (strcmp (cpu_stop [stop].name, gbuf) == 0) {     /*   and if the argument matches */
3526                 if (option == 1)                                /*     then if it's a STOP argument */
3527                     sim_stops |= cpu_stop [stop].mask;          /*       then add the stop flag */
3528                 else                                            /*     otherwise it's a NOSTOP argument */
3529                     sim_stops &= ~cpu_stop [stop].mask;         /*       so remove the flag */
3530 
3531                 break;                                          /* this argument has been processed */
3532                 }
3533 
3534         if (cpu_stop [stop].name == NULL)               /* if the argument was not found */
3535             return SCPE_ARG;                            /*   then report it */
3536         }
3537 
3538 return SCPE_OK;                                         /* the stops were successfully processed */
3539 }
3540 
3541 
3542 /* Change the instruction execution trace criteria.
3543 
3544    This validation routine is called to configure the criteria that select
3545    instruction execution tracing.  The "option" parameter is 0 to clear and 1 to
3546    set the criteria, and "cptr" points to the first character of the match value
3547    to be set.  The unit and description pointers are not used.
3548 
3549    The routine processes commands of the form:
3550 
3551      SET CPU EXEC=<match>[;<mask>]
3552      SET CPU NOEXEC
3553 
3554    If the <mask> value is not supplied, a mask of 177777 octal is used.  The
3555    values are entered in the current CPU data radix, which defaults to octal,
3556    unless an override switch is present on the command line.
3557 */
3558 
set_exec(UNIT * uptr,int32 option,char * cptr,void * desc)3559 static t_stat set_exec (UNIT *uptr, int32 option, char *cptr, void *desc)
3560 {
3561 char   gbuf [CBUFSIZE];
3562 uint32 match, mask, radix;
3563 t_stat status;
3564 
3565 if (option == 0)                                        /* if this is a NOEXEC request */
3566     if (cptr == NULL) {                                 /*   then if there are no arguments */
3567         exec_match = D16_UMAX;                          /*     then set the match and mask values */
3568         exec_mask  = 0;                                 /*       to prevent matching */
3569         return SCPE_OK;                                 /*         and return success */
3570         }
3571 
3572     else                                                /*   otherwise there are extraneous characters */
3573         return SCPE_2MARG;                              /*     so report that there are too many arguments */
3574 
3575 else if (cptr == NULL || *cptr == '\0')                 /* otherwise if the EXEC request supplies no arguments */
3576     return SCPE_MISVAL;                                 /*   then report a missing value */
3577 
3578 else {                                                  /* otherwise at least one argument is present */
3579     cptr = get_glyph (cptr, gbuf, ';');                 /*   so get the match argument */
3580 
3581     if (sim_switches & SWMASK ('O'))                    /* if an octal override is present */
3582         radix = 8;                                      /*   then parse the value in base 8 */
3583     else if (sim_switches & SWMASK ('D'))               /* otherwise if a decimal override is present */
3584         radix = 10;                                     /*   then parse the value in base 10 */
3585     else if (sim_switches & SWMASK ('H'))               /* otherwise if a hex override is present */
3586         radix = 16;                                     /*   then parse the value in base 16 */
3587     else                                                /* otherwise */
3588         radix = cpu_dev.dradix;                         /*   use the current CPU data radix */
3589 
3590     match = (uint32) get_uint (gbuf, radix, D16_UMAX, &status); /* parse the match value */
3591 
3592     if (status != SCPE_OK)                              /* if a parsing error occurred */
3593         return status;                                  /*   then return the error status */
3594 
3595     else if (*cptr == '\0') {                           /* otherwise if no more characters are present */
3596         exec_match = match;                             /*   then set the match value */
3597         exec_mask  = D16_MASK;                          /*     and default the mask value */
3598         return SCPE_OK;                                 /*       and return success */
3599         }
3600 
3601     else {                                              /* otherwise another argument is present */
3602         cptr = get_glyph (cptr, gbuf, ';');             /*   so get the mask argument */
3603 
3604         mask = (uint32) get_uint (gbuf, radix, D16_UMAX, &status);  /* parse the mask value */
3605 
3606         if (status != SCPE_OK)                          /* if a parsing error occurred */
3607             return status;                              /*   then return the error status */
3608 
3609         else if (*cptr == '\0')                         /* if no more characters are present */
3610             if (mask == 0)                              /*   then if the mask value is zero */
3611                 return SCPE_ARG;                        /*     then the match will never succeed */
3612 
3613             else {                                      /*   otherwise */
3614                 exec_match = match;                     /*     set the match value */
3615                 exec_mask  = mask;                      /*       and the mask value */
3616                 return SCPE_OK;                         /*         and return success */
3617                 }
3618 
3619         else                                            /* otherwise extraneous characters are present */
3620             return SCPE_2MARG;                          /*   so report that there are too many arguments */
3621         }
3622     }
3623 }
3624 
3625 
3626 /* Set the CPU cold dump configuration jumpers.
3627 
3628    This validation routine is called to configure the set of jumpers on the
3629    system control panel that preset the device number and control value for the
3630    cold dump process.  The "option" parameter is 0 to set the device number
3631    and 1 to set the control value.  The "cptr" parameter points to the first
3632    character of the value to be set.  The unit and description pointers are not
3633    used.
3634 
3635    The routine processes commands of the form:
3636 
3637      SET CPU DUMPDEV=<devno>
3638      SET CPU DUMPCTL=<cntlval>
3639 
3640    The device number is a decimal value between 3 and 127, and the control value
3641    is an octal number between 0 and 377.  Values outside of these ranges are
3642    rejected.
3643 */
3644 
set_dump(UNIT * uptr,int32 option,char * cptr,void * desc)3645 static t_stat set_dump (UNIT *uptr, int32 option, char *cptr, void *desc)
3646 {
3647 t_value value;
3648 t_stat  status = SCPE_OK;
3649 
3650 if (cptr == NULL || *cptr == '\0')                      /* if the expected value is missing */
3651     status = SCPE_MISVAL;                               /*   then report the error */
3652 
3653 else if (option == 0) {                                 /* otherwise if a device number is present */
3654     value = get_uint (cptr, DEVNO_BASE,                 /*   then parse the supplied value */
3655                       DEVNO_MAX, &status);
3656 
3657     if (status == SCPE_OK)                                  /* if it is valid */
3658         if (value >= 3)                                     /*   and in the proper range */
3659             dump_control = REPLACE_LOWER (dump_control,     /*     then set the new device number */
3660                                           (uint32) value);  /*       into the dump control word */
3661         else                                                /*   otherwise the device number */
3662             status = SCPE_ARG;                              /*     is invalid */
3663     }
3664 
3665 else {                                                  /* otherwise a control byte is present */
3666     value = get_uint (cptr, CNTL_BASE,                  /*   so parse the supplied value */
3667                       CNTL_MAX, &status);
3668 
3669     if (status == SCPE_OK)                              /* if it is valid */
3670         dump_control = REPLACE_UPPER (dump_control,     /*   then set the new control value */
3671                                       (uint32) value);  /*     into the dump control word */
3672     }
3673 
3674 return status;                                          /* return the operation status */
3675 }
3676 
3677 
3678 /* Change the CPU memory size.
3679 
3680    This validation routine is called to configure the CPU memory size.  The
3681    "new_size" parameter is set to the size desired and will be one of the
3682    discrete sizes supported by the machine.  The "uptr" parameter points to the
3683    CPU unit and is used to obtain the CPU model.  The other parameters are not
3684    used.
3685 
3686    The routine processes commands of the form:
3687 
3688      SET [-F] CPU <memsize>
3689 
3690    If the new memory size is larger than the supported size for the CPU model
3691    currently selected, the routine returns an error.  If the new size is smaller
3692    than the previous size, and if the area that would be lost contains non-zero
3693    data, the user is prompted to confirm that memory should be truncated.  If
3694    the user denies the request, the change is rejected.  Otherwise, the new size
3695    is set.  The user may omit the confirmation request and force truncation by
3696    specifying the "-F" switch on the command line.
3697 
3698 
3699    Implementation notes:
3700 
3701     1. The memory access routines return a zero value for locations beyond the
3702        currently defined memory size.  Therefore, the unused area need not be
3703        explicitly zeroed.
3704 */
3705 
set_size(UNIT * uptr,int32 new_size,char * cptr,void * desc)3706 static t_stat set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc)
3707 {
3708 static char confirm [] = "Really truncate memory [N]?";
3709 
3710 const uint32 model = CPU_MODEL (uptr->flags);           /* the current CPU model index */
3711 
3712 if ((uint32) new_size > cpu_features [model].maxmem)    /* if the new memory size is not supported on current model */
3713     return SCPE_NOFNC;                                  /*   then report the error */
3714 
3715 if (!(sim_switches & SWMASK ('F'))                      /* if truncation is not explicitly forced */
3716   && ! mem_is_empty (new_size)                          /*   and the truncated part is not empty */
3717   && get_yn (confirm, FALSE) == FALSE)                  /*     and the user denies confirmation */
3718     return SCPE_INCOMP;                                 /*       then abort the command */
3719 
3720 MEMSIZE = new_size;                                     /* set the new memory size */
3721 
3722 return SCPE_OK;                                         /* confirm that the change is OK */
3723 }
3724 
3725 
3726 /* Change the CPU model.
3727 
3728    This validation routine is called to configure the CPU model.  The
3729    "new_model" parameter is set to the model desired and will be one of the unit
3730    model flags.  The other parameters are not used.
3731 
3732    The routine processes commands of the form:
3733 
3734      SET [-F] CPU <model>
3735 
3736    Setting the model establishes a set of typical hardware features.  It also
3737    verifies that the current memory size is supported by the new model.  If it
3738    is not, the size is reduced to the maximum supported memory configuration.
3739    If the area that would be lost contains non-zero data, the user is prompted
3740    to confirm that memory should be truncated.  If the user denies the request,
3741    the change is rejected.  Otherwise, the new size is set.  The user may omit
3742    the confirmation request and force truncation by specifying the "-F" switch
3743    on the command line.
3744 
3745    This routine is also called once from the CPU reset routine to establish the
3746    initial CPU model.  The current memory size will be 0 when this call is made.
3747 */
3748 
set_model(UNIT * uptr,int32 new_model,char * cptr,void * desc)3749 static t_stat set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc)
3750 {
3751 const uint32 new_index = CPU_MODEL (new_model);         /* the new index into the CPU features table */
3752 uint32 new_memsize, index;
3753 t_stat status;
3754 
3755 if (MEMSIZE == 0                                        /* if this is the initial establishing call */
3756   || MEMSIZE > cpu_features [new_index].maxmem)         /*   or if the current memory size is unsupported */
3757     new_memsize = cpu_features [new_index].maxmem;      /*     then set the new size to the maximum supported size */
3758 else                                                    /* otherwise the current size is valid for the new model */
3759     new_memsize = (uint32) MEMSIZE;                     /*   so leave it unchanged */
3760 
3761 status = set_size (uptr, new_memsize, NULL, NULL);      /* set the new memory size */
3762 
3763 if (status == SCPE_OK) {                                /* if the change succeeded */
3764     uptr->flags = uptr->flags & ~UNIT_OPTS              /*   then set the typical features */
3765                     | cpu_features [new_index].typ;     /*     for the new model */
3766 
3767     mem_bank_mask = cpu_features [new_index].bank_mask; /* set the new memory bank register mask */
3768 
3769     for (index = 0; cpu_reg [index].loc != NULL; index++)   /* scan the CPU register list */
3770         if (cpu_reg [index].loc == &PBANK                   /*   and set the maximum allowed value */
3771           || cpu_reg [index].loc == &DBANK                  /*     for the three bank registers */
3772           || cpu_reg [index].loc == &SBANK)                 /*       to the highest bank number */
3773             cpu_reg [index].maxval = mem_bank_mask;         /*         for the new CPU model */
3774     }
3775 
3776 return status;                                          /* return the validation result */
3777 }
3778 
3779 
3780 /* Change a CPU option.
3781 
3782    This validation routine is called to configure the option set for the current
3783    CPU model.  The "new_option" parameter is set to the option desired and will
3784    be one of the unit option flags.  The "uptr" parameter points to the CPU unit
3785    and is used to obtain the CPU model.  The other parameters are not used.
3786 
3787    The routine processes commands of the form:
3788 
3789      SET CPU <option>[,<option>...]
3790 
3791    The option must be valid for the current CPU model, or the command is
3792    rejected.
3793 */
3794 
set_option(UNIT * uptr,int32 new_option,char * cptr,void * desc)3795 static t_stat set_option (UNIT *uptr, int32 new_option, char *cptr, void *desc)
3796 {
3797 const uint32 model = CPU_MODEL (uptr->flags);           /* the current CPU model index */
3798 
3799 if ((cpu_features [model].opt & new_option) != 0)       /* if the option is supported on the current model */
3800     return SCPE_OK;                                     /*   then confirm the change */
3801 else                                                    /* otherwise */
3802     return SCPE_NOFNC;                                  /*   reject the change */
3803 }
3804 
3805 
3806 /* Change the power-fail auto-restart switch setting.
3807 
3808    This validation routine is called to configure the PF/ARS switch that is
3809    located behind the system control panel.  If set to the ENBL (enable)
3810    position, the CPU will perform an auto-restart when power is restored after a
3811    failure.  In the DSBL (disable) position, the CPU will remain halted after
3812    power restoration; execution may be continued by pressing the RUN button.
3813 
3814    In simulation, a SET CPU ARS command enables auto-restart, and SET CPU NOARS
3815    disables auto-restart.  The "setting" parameter is set to the UNIT_ARS flag
3816    in the former cast and to zero in the latter case.  The other parameters are
3817    not used.  The routine reflects the ARS setting in "inhibit auto-restart" bit
3818    of the CPX2 register.
3819 */
3820 
set_pfars(UNIT * uptr,int32 setting,char * cptr,void * desc)3821 static t_stat set_pfars (UNIT *uptr, int32 setting, char *cptr, void *desc)
3822 {
3823 if (setting == UNIT_PFARS)                              /* if the option is ARS */
3824     CPX2 &= ~cpx2_INHPFARS;                             /*   then clear the auto-restart inhibit flag */
3825 else                                                    /* otherwise the option is NOARS */
3826     CPX2 |= cpx2_INHPFARS;                              /*   so set the auto-restart inhibit flag */
3827 
3828 return SCPE_OK;                                         /* confirm the change */
3829 }
3830 
3831 
3832 /* Show the CPU simulation stop conditions.
3833 
3834    This display routine is called to show the set of CPU stop conditions.  The
3835    "st" parameter is the open output stream.  The other parameters are not used.
3836 
3837    If at least one stop condition is enabled, the routine searches through the
3838    stop table for flag bits that are set in the stop set.  For each one it
3839    finds, the routine prints the corresponding stop name.
3840 
3841    This routine services an extended modifier entry, so it must add the trailing
3842    newline to the output before returning.
3843 */
3844 
show_stops(FILE * st,UNIT * uptr,int32 val,void * desc)3845 static t_stat show_stops (FILE *st, UNIT *uptr, int32 val, void *desc)
3846 {
3847 uint32 stop;
3848 t_bool need_spacer = FALSE;
3849 
3850 if (sim_stops == 0)                                     /* if no simulation stops are set */
3851     fputs ("Stops disabled", st);                       /*   then report that all are disabled */
3852 
3853 else {                                                  /* otherwise at least one stop is valid */
3854     fputs ("Stop=", st);                                /*   so prepare to report the list of conditions */
3855 
3856     for (stop = 0; cpu_stop [stop].name != NULL; stop++)    /* loop through the set of stops in the table */
3857         if (cpu_stop [stop].mask & sim_stops) {             /* if the current stop is enabled */
3858             if (need_spacer)                                /*   then if a spacer is needed */
3859                 fputc (';', st);                            /*     then add it first */
3860 
3861             fputs (cpu_stop [stop].name, st);               /* report the stop name */
3862 
3863             need_spacer = TRUE;                             /* a spacer will be needed next time */
3864             }
3865         }
3866 
3867 fputc ('\n', st);                                       /* add the trailing newline */
3868 
3869 return SCPE_OK;                                         /* report the success of the display */
3870 }
3871 
3872 
3873 /* Show the instruction execution trace criteria.
3874 
3875    This display routine is called to show the criteria that select instruction
3876    execution tracing.  The "st" parameter is the open output stream.  The other
3877    parameters are not used.
3878 
3879    This routine services an extended modifier entry, so it must add the trailing
3880    newline to the output before returning.
3881 */
3882 
show_exec(FILE * st,UNIT * uptr,int32 val,void * desc)3883 static t_stat show_exec (FILE *st, UNIT *uptr, int32 val, void *desc)
3884 {
3885 uint32 radix;
3886 
3887 if (exec_mask == 0)                                     /* if the instruction is entirely masked */
3888     fputs ("Execution trace disabled\n", st);           /*   then report that matching is disabled */
3889 
3890 else {                                                  /* otherwise */
3891     if (sim_switches & SWMASK ('O'))                    /*   if an octal override is present */
3892         radix = 8;                                      /*     then print the value in base 8 */
3893     else if (sim_switches & SWMASK ('D'))               /*   otherwise if a decimal override is present */
3894         radix = 10;                                     /*     then print the value in base 10 */
3895     else if (sim_switches & SWMASK ('H'))               /*   otherwise if a hex override is present */
3896         radix = 16;                                     /*     then print the value in base 16 */
3897     else                                                /*   otherwise */
3898         radix = cpu_dev.dradix;                         /*     use the current CPU data radix */
3899 
3900     fputs ("Execution trace match = ", st);                         /* print the label */
3901     fprint_val (st, exec_match, radix, cpu_dev.dwidth, PV_RZRO);    /*   and the match value */
3902 
3903     fputs (", mask = ", st);                                        /* print a separator */
3904     fprint_val (st, exec_mask, radix, cpu_dev.dwidth, PV_RZRO);     /*   and the mask value */
3905 
3906     fputc ('\n', st);                                               /* tie off the line */
3907     }
3908 
3909 return SCPE_OK;                                         /* report the success of the display */
3910 }
3911 
3912 
3913 /* Show the CPU cold dump configuration jumpers.
3914 
3915    This display routine is called to show the device number and control byte
3916    that are preset on the rear of the system control panel for the cold dump
3917    process.  The "st" parameter is the open output stream.  The other parameters
3918    are not used.
3919 */
3920 
show_dump(FILE * st,UNIT * uptr,int32 val,void * desc)3921 static t_stat show_dump (FILE *st, UNIT *uptr, int32 val, void *desc)
3922 {
3923 fprintf (st, "Dump device = %u, dump control = %03o\n",
3924          LOWER_BYTE (dump_control), UPPER_BYTE (dump_control));
3925 
3926 return SCPE_OK;
3927 }
3928 
3929 
3930 /* Show the current CPU simulation speed.
3931 
3932    This display routine is called to show the current simulation speed.  The
3933    "st" parameter is the open output stream.  The other parameters are not used.
3934 
3935    The CPU speed, expressed as a multiple of the hardware speed, is calculated
3936    by the process clock service routine.  It is only representative when the
3937    process clock is calibrated, and the CPU is not executing a PAUS instruction
3938    (which suspends the normal fetch/execute instruction cycle).
3939 */
3940 
show_speed(FILE * st,UNIT * uptr,int32 val,void * desc)3941 static t_stat show_speed (FILE *st, UNIT *uptr, int32 val, void *desc)
3942 {
3943 fprintf (st, "Simulation speed = %ux\n", cpu_speed);    /* display the current CPU speed */
3944 return SCPE_OK;                                         /*   and report success */
3945 }
3946 
3947 
3948 
3949 /* CPU local utility routines */
3950 
3951 
3952 /* Process a halt-mode interrupt.
3953 
3954    This routine is called when one or more of the interrupt request bits are set
3955    in the CPX2 register.  These bits represent switch closures on the CPU front
3956    panel or on the optional maintenance display panel.  The specific switch
3957    closure is identified, and the corresponding microcode routine is executed.
3958    If multiple bits are set in CPX2, the microcode recognizes them in order from
3959    MSB to LSB.
3960 
3961    If the RUN switch is set, a test is made for a System Halt, which inhibits
3962    recognition of the switch.  If the System Halt flag is set, the CPU must be
3963    reset before execution may be resumed.  Otherwise, the NIR is reloaded in
3964    case P was changed during the simulation stop.  If the R-bit (right stack op
3965    pending) flag in the status register is set, but the NIR no longer contains a
3966    stack instruction, R is cleared.  If a stack instruction is present, and the
3967    R-bit is set, then the CIR is set, and the following instruction is fetched.
3968    The micromachine state is set to "running", and one event tick is added back
3969    to the accumulator to ensure that a single step won't complete without
3970    executing an instruction.
3971 
3972    If the DUMP switch is pressed, an I/O Reset is performed on all devices
3973    except the CPU, which is skipped to preserve the register state.  The dump
3974    device number is obtained from the SWCH register and tested to ensure that a
3975    tape is mounted with a write ring and the unit is online.  Then the contents
3976    of the CPU registers are written to the reserved memory area starting at
3977    address 1400 octal in bank 0.  This is followed by two SIO programs.  The
3978    main program at addresses 1430-1437 write 4K-word blocks of memory to the
3979    dump device.  The error recovery program at addresses 1422-1427 is invoked
3980    when a write fails.  It does a Backspace Record followed by a Write Gap to
3981    skip the bad spot on the tape, and then the write is retried.
3982 
3983    The DUMP switch remains set, so after each pass through the main execution
3984    loop to run a channel cycle, this routine is reentered.  The "waiting" state
3985    causes the second part of the process to check for device completion.  When
3986    it occurs, the expected external interrupt is cleared, and if the dump is
3987    complete, the DUMP switch is reset, the original SIO pointer in the DRT is
3988    restored, and the micromachine is halted.  Otherwise, the SIO pointer is
3989    read.  If it points at the end of the program, then the operation completed
3990    normally.  In this case, the dump address is advanced, and, if all of memory
3991    has been dumped, the SIO pointer is reset to the recovery program, and that
3992    program is changed to finish up with Write File Mark and Rewind/Offline
3993    commands.  Otherwise, the pointer is reset to the main program in preparation
3994    for the next 4K write.  The SIO program is then restarted.
3995 
3996    If SIO pointer failed to complete, the pointer is reset to point at the error
3997    recovery program, and the memory address is unchanged; the same 4K write will
3998    be performed once the recovery program runs.  If the recovery program fails,
3999    the dump is terminated at that point with a failure indication.
4000 
4001    During the dump operation, the CIR register is continually updated with the
4002    current memory bank number.  If the dump runs to completion, CIR will contain
4003    the number of 64K memory banks installed in the machine.  A value less than
4004    the installed memory value indicates a dump failure.  Except for the CIR, the
4005    machine state is restored, so that another dump may be attempted.
4006 
4007    If the LOAD switch is pressed, the cold load process begins by filling memory
4008    with HALT 10 instructions if SWCH register bit 8 is clear.  The cold load
4009    device number is obtained from the lower byte of the SWCH register.
4010 
4011    The first part of the cold load process clears the TOS and STA registers,
4012    stores the initial channel program in memory, and executes an SIO instruction
4013    to start the channel.  Once the device starts, interrupts are enabled, and
4014    the micromachine state is set to "waiting" in preparation for executing the
4015    second part of the cold load process once the channel program ends.  The
4016    routine then exits to begin channel execution.
4017 
4018    The LOAD switch remains set, so after each pass through the main execution
4019    loop to run a channel cycle, this routine is reentered.  The "waiting" state
4020    causes the second part of the process to check for device completion.  The
4021    expected external interrupt is cleared, the LOAD switch is cleared, the
4022    micromachine state is set to "running", and the Cold Load trap is taken to
4023    complete the process.
4024 
4025 
4026    Implementation notes:
4027 
4028     1. After processing the RUN switch and returning to the instruction loop, if
4029        no interrupt is present, and the R-bit in the status register is clear,
4030        then CIR will be set from NIR, and NIR will be reloaded.  If the R-bit is
4031        set, then CIR and NIR will not be changed, i.e., the NEXT action will be
4032        skipped, so we perform it here.  If an interrupt is pending, then the
4033        interrupt will be processed using the old value of the CIR, and the
4034        instruction in the NIR will become the first instruction executed after
4035        the interrupt handler completes.
4036 
4037     2. The cold load microcode is shared with the cold dump process.  The Series
4038        II dump process saves memory locations DRT + 0 through DRT + 3 in the TOS
4039        registers.  The load process uses the same microcode but does not perform
4040        the memory read, so the TOS registers are loaded with the previous
4041        contents of the OPND register, which is effectively a random value.  In
4042        simulation, the TOS registers are cleared.
4043 
4044     3. The cold load and dump microcode waits forever for an interrupt from the
4045        cold load device.  If it doesn't occur, the microcode hangs until a
4046        system reset is performed (it tests CPX1 bit 8 and does a JMP *-1 if the
4047        bit is not set).  The simulation follows the microcode behavior.
4048 
4049     4. Front panel diagnostics and direct I/O cold loading is not implemented.
4050 */
4051 
halt_mode_interrupt(HP_WORD device_number)4052 static t_stat halt_mode_interrupt (HP_WORD device_number)
4053 {
4054 static HP_WORD cold_device, sio_pointer, status, offset, pointer;
4055 static uint32  address;
4056 static t_bool  error_recovery;
4057 
4058 if (CPX2 & cpx2_RUNSWCH) {                              /* if the RUN switch is pressed */
4059     if (CPX2 & cpx2_SYSHALT) {                          /*   then if the System Halt flip-flop is set */
4060         CPX2 &= ~CPX2_IRQ_SET;                          /*     then clear all switches */
4061         return STOP_SYSHALT;                            /*       as the CPU cannot run until it is reset */
4062         }
4063 
4064     else                                                /*   otherwise */
4065         CPX2 = CPX2 & ~cpx2_RUNSWCH | cpx2_RUN;         /*     clear the switch and set the Run flip-flop */
4066 
4067     cpu_read_memory (fetch, P, &NIR);                   /* load the next instruction to execute */
4068     P = P + 1 & R_MASK;                                 /*   and point to the following instruction */
4069 
4070     if ((NIR & PAUS_MASK) == PAUS)                      /* if resuming into a PAUS instruction */
4071         cpu_stop_flags |= SS_PAUSE_RESUMED;             /*   then defer any interrupt until after PAUS is executed */
4072 
4073     if ((NIR & SUBOP_MASK) != 0)                        /* if the instruction is not a stack instruction */
4074         STA &= ~STATUS_R;                               /*   then clear the R-bit in case it had been set */
4075 
4076     else if (STA & STATUS_R) {                          /* otherwise if a right-hand stack op is pending */
4077         CIR = NIR;                                      /*   then set the current instruction */
4078         cpu_read_memory (fetch, P, &NIR);               /*     and load the next instruction */
4079         }
4080 
4081     cpu_micro_state = running;                          /* start the micromachine */
4082     sim_interval = sim_interval + 1;                    /* don't count this cycle against a STEP count */
4083 
4084     if (cpu_power_state == power_returning) {           /* if power is returning after a failure */
4085         if (CPX2 & cpx2_INHPFARS)                       /*   then if auto-restart is inhibited */
4086             CPX2 &= ~cpx2_RUN;                          /*     then clear the Run flip-flop */
4087 
4088         MICRO_ABORT (trap_Power_On);                    /* set up the trap to the power-on routine */
4089         }
4090     }
4091 
4092 
4093 else if (CPX2 & cpx2_DUMPSWCH) {                        /* otherwise if the DUMP switch is pressed */
4094     if (cpu_micro_state != waiting) {                   /*   then if the dump is not in progress */
4095         reset_all (IO_RESET);                           /*     then reset all I/O devices */
4096 
4097         cold_device = LOWER_BYTE (SWCH) & DEVNO_MASK;   /* get the device number from the lower SWCH byte */
4098 
4099         status = iop_direct_io (cold_device, ioTIO, 0); /* get the device status */
4100 
4101         if ((status & MS_ST_MASK) != MS_ST_READY) {     /* if the tape is not ready and unprotected */
4102             CPX2 &= ~cpx2_DUMPSWCH;                     /*   then clear the dump switch */
4103 
4104             CIR = 0;                                    /* clear CIR to indicate a failure */
4105             return STOP_CDUMP;                          /*   and terminate the dump */
4106             }
4107 
4108         if (DBANK > DUMP_BANK_MASK                      /* if any of the bank register values */
4109           || PBANK > DUMP_BANK_MASK                     /*   are larger than the cold dump format permits */
4110           || SBANK > DUMP_BANK_MASK)                    /*     then warn the user of the truncation */
4111             cprintf ("%s cold dump warning: bank register values truncated\n",
4112                      sim_name);
4113 
4114         cpu_read_memory (absolute, cold_device * 4,     /* get the original DRT pointer */
4115                          &sio_pointer);
4116 
4117         cpu_write_memory (absolute, 01400, 1);              /* set the machine ID to 1 for the Series III */
4118         cpu_write_memory (absolute, 01401, sio_pointer);    /* store the original DRT pointer */
4119         cpu_write_memory (absolute, 01402, SM);             /* store the stack pointer */
4120         cpu_write_memory (absolute, 01403, 0);              /* store zeros for the scratch pad 1 */
4121         cpu_write_memory (absolute, 01404, 0);              /*   and scratch pad 2 register values */
4122         cpu_write_memory (absolute, 01405, DB);             /* store the data base */
4123         cpu_write_memory (absolute, 01406, (DBANK & DUMP_BANK_MASK) << 12   /* store DBANK in 0:4 */
4124                                          | (PBANK & DUMP_BANK_MASK) << 8    /*   and PBANK in 4:4 */
4125                                          | (SBANK & DUMP_BANK_MASK));       /*     and SBANK in 12:4 */
4126         cpu_write_memory (absolute, 01407, Z);              /* store the stack limit */
4127         cpu_write_memory (absolute, 01410, DL);             /*   and the data limit */
4128         cpu_write_memory (absolute, 01411, X);              /*   and the index register */
4129         cpu_write_memory (absolute, 01412, Q);              /*   and the frame pointer */
4130         cpu_write_memory (absolute, 01413, CIR);            /*   and the current instruction */
4131         cpu_write_memory (absolute, 01414, PB);             /*   and the program base */
4132         cpu_write_memory (absolute, 01415, PL);             /*   and the program limit */
4133         cpu_write_memory (absolute, 01416, P);              /*   and the program counter */
4134         cpu_write_memory (absolute, 01417, CPX1);           /* store the CPX1 register */
4135         cpu_write_memory (absolute, 01420, STA);            /*   and the status register */
4136         cpu_write_memory (absolute, 01421,                  /* store the lower byte of the CPX2 register */
4137                           LOWER_WORD (CPX2 << 8             /*   in the upper byte of memory */
4138                             | MEMSIZE / 65536));            /*     and the memory bank count in the lower byte */
4139 
4140         cpu_write_memory (absolute, 01422, SIO_CNTL);           /* CONTRL 0,BSR */
4141         cpu_write_memory (absolute, 01423, MS_CN_BSR);
4142         cpu_write_memory (absolute, 01424, SIO_CNTL);           /* CONTRL 0,GAP */
4143         cpu_write_memory (absolute, 01425, MS_CN_GAP);
4144         cpu_write_memory (absolute, 01426, SIO_JUMP);           /* JUMP   001436 */
4145         cpu_write_memory (absolute, 01427, 001436);
4146 
4147         cpu_write_memory (absolute, 01430, SIO_SBANK);          /* SETBNK 0 */
4148         cpu_write_memory (absolute, 01431, 000000);
4149         cpu_write_memory (absolute, 01432, SIO_CNTL);           /* CONTRL 0,<SWCH-upper> */
4150         cpu_write_memory (absolute, 01433, UPPER_BYTE (SWCH));
4151         cpu_write_memory (absolute, 01434, SIO_WRITE);          /* WRITE  #4096,000000 */
4152         cpu_write_memory (absolute, 01435, 000000);
4153         cpu_write_memory (absolute, 01436, SIO_ENDIN);          /* ENDINT */
4154         cpu_write_memory (absolute, 01437, 000000);
4155 
4156         address = 0;                                    /* clear the address */
4157         offset = 0;                                     /*   and memory offset counters */
4158 
4159         CIR = 0;                                        /* clear the memory bank counter */
4160 
4161         cpu_write_memory (absolute, cold_device * 4, 01430);    /* point the DRT at the cold dump program */
4162         error_recovery = FALSE;
4163 
4164         iop_direct_io (cold_device, ioSIO, 0);          /* start the device */
4165 
4166         if (CPX1 & cpx1_IOTIMER)                        /* if the device did not respond */
4167             MICRO_ABORT (trap_SysHalt_IO_Timeout);      /*   then a System Halt occurs */
4168 
4169         else {                                          /* otherwise the device has started */
4170             status = STA;                               /*   so save the original status register value */
4171 
4172             STA = STATUS_I | STATUS_O;                  /* enable interrupts and set overflow */
4173             cpu_micro_state = waiting;                  /*   and set the load-in-progress state */
4174             }
4175         }
4176 
4177     else if (CPX1 & cpx1_EXTINTR) {                     /* otherwise if an external interrupt is pending */
4178         CPX1 &= ~cpx1_EXTINTR;                          /*   then clear it */
4179 
4180         iop_direct_io (device_number, ioRIN, 0);        /* reset the device interrupt */
4181 
4182         if (device_number == cold_device)               /* if the expected device interrupted */
4183             if (address >= MEMSIZE) {                   /*   then if all of memory has been dumped */
4184                 CPX2 &= ~cpx2_DUMPSWCH;                 /*   then reset the DUMP switch */
4185 
4186                 STA = status;                           /* restore the original status register value */
4187 
4188                 cpu_write_memory (absolute,             /* restore the */
4189                                   cold_device * 4,      /*   original SIO pointer */
4190                                   sio_pointer);         /*     to the DRT */
4191 
4192                 cpu_micro_state = halted;               /* clear the dump-in-progress state */
4193                 return STOP_CDUMP;                      /*   and report dump completion */
4194                 }
4195 
4196             else {                                      /* otherwise the dump continues */
4197                 cpu_read_memory (absolute,              /* read the */
4198                                  cold_device * 4,       /*   current SIO pointer address */
4199                                  &pointer);             /*     from the DRT */
4200 
4201                 if (pointer == 01440) {                 /* if the SIO program completed normally */
4202                     cpu_write_memory (absolute,         /*   then reset the pointer */
4203                                       cold_device * 4,  /*     to the start */
4204                                       001430);          /*       of the program */
4205 
4206                     if (error_recovery)                 /* if this was a successful error recovery */
4207                         error_recovery = FALSE;         /*   then clear the flag and keep the current address */
4208 
4209                     else {                                  /* otherwise this was a successful write */
4210                         address = address + 4096;           /*   so bump the memory address */
4211                         offset = offset + 4096 & LA_MASK;   /*     and offset to the next 4K block */
4212 
4213                         cpu_write_memory (absolute,         /* store the new write buffer address */
4214                                           001435, offset);
4215 
4216                         if (offset == 0) {                  /* if the offset wrapped around */
4217                             CIR = CIR + 1;                  /*   then increment the bank number */
4218                             cpu_write_memory (absolute,     /*     and store it as the SET BANK target */
4219                                               001431, CIR);
4220 
4221                             if (address >= MEMSIZE) {               /* if all of memory has been dumped */
4222                                 cpu_write_memory (absolute, 001423, /*   then change the error recovery program */
4223                                                   MS_CN_WFM);       /*     to write a file mark */
4224                                 cpu_write_memory (absolute, 001425, /*       followed by */
4225                                                   MS_CN_RST);       /*         a rewind/offline request */
4226 
4227                                 cpu_write_memory (absolute,         /* point at the recovery program */
4228                                                   cold_device * 4,
4229                                                   001422);
4230                                 }
4231                             }
4232                         }
4233                     }
4234 
4235                 else if (error_recovery) {              /* otherwise if the recover program failed */
4236                     CPX2 &= ~cpx2_DUMPSWCH;             /*   then reset the DUMP switch */
4237 
4238                     STA = status;                       /* restore the original status register value */
4239 
4240                     cpu_write_memory (absolute,         /* restore the */
4241                                       cold_device * 4,  /*   original SIO pointer */
4242                                       sio_pointer);     /*     to the DRT */
4243 
4244                     cpu_micro_state = halted;           /* clear the dump-in-progress state */
4245                     return STOP_CDUMP;                  /*   and report dump failure */
4246                     }
4247 
4248                 else {                                  /* otherwise attempt error recovery */
4249                     cpu_write_memory (absolute,         /*   by setting the SIO pointer */
4250                                       cold_device * 4,  /*     to the backspace/write gap */
4251                                       001422);          /*       program */
4252 
4253                     error_recovery = TRUE;              /* indicate that recovery is in progress */
4254                     }
4255 
4256                 iop_direct_io (cold_device, ioSIO, 0);  /* start the device */
4257                 }
4258         }                                               /* otherwise wait for the cold dump device to interrupt */
4259     }
4260 
4261 else if (CPX2 & cpx2_LOADSWCH)                          /* otherwise if the LOAD switch is pressed */
4262     if (cpu_micro_state != waiting) {                   /*   then if the load is not in progress */
4263         reset_all (CPU_IO_RESET);                       /*     then reset the CPU and all I/O devices */
4264 
4265         if ((SWCH & 000200) == 0)                       /* if switch register bit 8 is clear */
4266             mem_fill (0, HALT_10);                      /*   then fill all of memory with HALT 10 instructions */
4267 
4268         SBANK = 0;                                      /* set the stack bank to bank 0 */
4269 
4270         cold_device = LOWER_BYTE (SWCH) & DEVNO_MASK;   /* get the device number from the lower SWCH byte */
4271 
4272         if (cold_device < 3) {                          /* if the device number is between 0 and 2 */
4273             CPX2 &= ~cpx2_LOADSWCH;                     /*   then reset the LOAD switch */
4274             return SCPE_INCOMP;                         /*     and execute a front panel diagnostic */
4275             }
4276 
4277         else if (cold_device > 63) {                    /* otherwise if the device number is > 63 */
4278             CPX2 &= ~cpx2_LOADSWCH;                     /*   then reset the LOAD switch */
4279             return SCPE_INCOMP;                         /*     and execute a direct I/O cold load */
4280             }
4281 
4282         else {                                          /* otherwise the device number is in the channel I/O range */
4283             RA = 0;                                     /* set the */
4284             RB = 0;                                     /*   TOS registers */
4285             RC = 0;                                     /*     to the same */
4286             RD = 0;                                     /*       (random) value */
4287 
4288             SR = 4;                                     /* mark the TOS registers as valid */
4289             STA = 0;                                    /*   and clear the status register */
4290 
4291             cpu_write_memory (absolute, 01430, SIO_SBANK);          /* SETBNK 0 */
4292             cpu_write_memory (absolute, 01431, 000000);
4293             cpu_write_memory (absolute, 01432, SIO_CNTL);           /* CONTRL 0,<SWCH-upper> */
4294             cpu_write_memory (absolute, 01433, UPPER_BYTE (SWCH));
4295             cpu_write_memory (absolute, 01434, SIO_READ);           /* READ   #16,001400 */
4296             cpu_write_memory (absolute, 01435, 001400);
4297             cpu_write_memory (absolute, 01436, SIO_JUMP);           /* JUMP   001400 */
4298             cpu_write_memory (absolute, 01437, 001400);
4299 
4300             cpu_write_memory (absolute, cold_device * 4, 01430);    /* point the DRT to the cold load program */
4301 
4302             iop_direct_io (cold_device, ioSIO, 0);      /* start the device */
4303 
4304             if (CPX1 & cpx1_IOTIMER)                    /* if the device did not respond */
4305                 MICRO_ABORT (trap_SysHalt_IO_Timeout);  /*   then a System Halt occurs */
4306 
4307             else {                                      /* otherwise the device has started */
4308                 STA = STATUS_I | STATUS_O;              /*   so enable interrupts and set overflow */
4309                 cpu_micro_state = waiting;              /*     and set the load-in-progress state */
4310                 }
4311             }
4312         }
4313 
4314     else                                                /* otherwise the load is in progress */
4315         if (CPX1 & cpx1_EXTINTR) {                      /* if an external interrupt is pending */
4316             CPX1 &= ~cpx1_EXTINTR;                      /*   then clear it */
4317 
4318             iop_direct_io (device_number, ioRIN, 0);    /* reset the device interrupt */
4319 
4320             if (device_number == cold_device) {         /* if the expected device interrupted */
4321                 CPX2 &= ~cpx2_LOADSWCH;                 /*   then reset the LOAD switch */
4322 
4323                 cpu_micro_state = running;              /* clear the load-in-progress state */
4324                 MICRO_ABORT (trap_Cold_Load);           /*   and execute the cold load trap handler */
4325                 }
4326             }                                           /* otherwise wait for the cold load device to interrupt */
4327 
4328 return SCPE_OK;
4329 }
4330 
4331 
4332 /* Execute one machine instruction.
4333 
4334    This routine executes the CPU instruction present in the CIR.  The CPU state
4335    (registers, memory, interrupt status) is modified as necessary, and the
4336    routine return SCPE_OK if the instruction executed successfully.  Any other
4337    status indicates that execution should cease, and control should return to
4338    the simulator console.  For example, a programmed HALT instruction returns
4339    STOP_HALT status.
4340 
4341    Unimplemented instructions are detected by those decoding branches that
4342    result from bit patterns not corresponding to legal instructions or
4343    corresponding to optional instructions not currently enabled.  Normally,
4344    execution of an unimplemented instruction would result in an Unimplemented
4345    Instruction trap.  However, for debugging purposes, a simulator stop may be
4346    requested instead by returning STOP_UNIMPL status if the SS_UNIMPL simulation
4347    stop flag is set.
4348 
4349    This routine implements the main instruction dispatcher, as well as memory
4350    address instructions (subopcodes 04-17).  Instructions corresponding to
4351    subopcodes 00-03 are executed by routines in the base instruction set module.
4352 
4353 
4354    Implementation notes:
4355 
4356     1. Each instruction executor begins with a comment listing the instruction
4357        mnemonic and, following in parentheses, the condition code setting, or
4358        "none" if the condition code is not altered, and a list of any traps that
4359        might be generated.
4360 
4361     2. Stack preadjusts are simpler if performed explicitly due to overlapping
4362        requirements that reduce the number of static preadjusts to 4 of the 16
4363        entries.
4364 
4365     3. The order of operations for each instruction follows the microcode.  For
4366        example, the LOAD instruction performs the bounds check on the effective
4367        address and reads the operand before pushing the stack down and storing
4368        it in the RA registrer.  Pushing the stack down first and then reading
4369        the value directly into the RA register would leave the stack in a
4370        different state if the memory access caused a Bounds Violation trap.
4371 
4372     4. The TBA, MTBA, TBX, and MTBX instructions take longer to execute than the
4373        nominal 2.5 microseconds assumed for the average instruction execution
4374        time.  Consequently, the 7905 disc diagnostic fails Step 66 (the retry
4375        counter test) if the DS device is set for REALTIME operation.  The
4376        diagnostic uses the MTBA P+0 instruction in a timing loop, which expires
4377        before the disc operations complete.
4378 
4379        A workaround for this diagnostic is to decrement sim_interval twice for
4380        these instructions.  However, doing so causes the 7970 tape diagnostic to
4381        fail Step 532 (the timing error test) for the opposite reason: a wait
4382        loop of MTBA P+0 instructions causes the tape data transfer service event
4383        time to count down twice as fast, while the multiplexer channel data
4384        transfer polls occur at the usual one per instruction.  This could be
4385        remedied by having the channel polls execute twice as many I/O cycles for
4386        these instructions, although the general solution would be to recast
4387        sim_intervals as microseconds and to decrement sim_interval by differing
4388        amounts appropriate for each instruction.
4389 */
4390 
machine_instruction(void)4391 static t_stat machine_instruction (void)
4392 {
4393 HP_WORD       displacement, opcode, offset, operand, operand_1, operand_2, result;
4394 int32         control, limit;
4395 ACCESS_CLASS  class;
4396 BYTE_SELECTOR selector;
4397 t_bool        branch;
4398 t_stat        status = SCPE_OK;
4399 
4400 switch (SUBOP (CIR)) {                                  /* dispatch on bits 0-3 of the instruction */
4401 
4402     case 000:                                           /* stack operations */
4403         status = cpu_stack_op ();                       /* set the status from the instruction executor */
4404         break;
4405 
4406 
4407     case 001:                                           /* shift, branch, and bit test operations */
4408         status = cpu_shift_branch_bit_op ();            /* set the status from the instruction executor */
4409         break;
4410 
4411 
4412     case 002:                                           /* move, special, firmware, immediate, field, and register operations */
4413         status = cpu_move_spec_fw_imm_field_reg_op ();  /* set the status from the instruction executor */
4414         break;
4415 
4416 
4417     case 003:                                           /* I/O, control, program, immediate, and memory operations */
4418         status = cpu_io_cntl_prog_imm_mem_op ();        /* set the status from the instruction executor */
4419         break;
4420 
4421 
4422     case 004:                                           /* LOAD (CCA; STOV, BNDV) */
4423         cpu_ea (CIR, &class, &offset, NULL);            /* get the effective address */
4424         cpu_read_memory (class, offset, &operand);      /*   and read the operand */
4425 
4426         cpu_push ();                                    /* push the operand */
4427         RA = operand;                                   /*   onto the stack */
4428 
4429         SET_CCA (RA, 0);                                /* set the condition code */
4430         break;
4431 
4432 
4433     case 005:                                           /* TBA, MTBA, TBX, MTBX, and STOR */
4434         if (CIR & M_FLAG) {                             /* STOR (none; STUN, BNDV) */
4435             cpu_ea (CIR, &class, &offset, NULL);        /* get the effective address */
4436 
4437             PREADJUST_SR (1);                           /* ensure that at least one TOS register is loaded */
4438 
4439             cpu_write_memory (class, offset, RA);       /* write the TOS to memory */
4440             cpu_pop ();                                 /*   and pop the stack */
4441             }
4442 
4443         else {                                          /* TBA, MTBA, TBX, or MTBX */
4444             opcode = CIR & TBR_MASK;                    /* get the test and branch operation */
4445 
4446             if (opcode == TBA || opcode == MTBA) {      /* TBA or MTBA (none; STUN, STOV, BNDV) */
4447                 PREADJUST_SR (3);                       /* ensure that at least three TOS registers are loaded */
4448 
4449                 while (SR > 3)                          /* if more than three TOS register are loaded */
4450                     cpu_queue_down ();                  /*   queue them down until exactly three are left */
4451 
4452                 offset = DB + RC & LA_MASK;             /* get the address of the control value */
4453 
4454                 if (DL <= offset && offset <= SM || PRIV)       /* if the address is within the segment */
4455                     cpu_read_memory (data, offset, &operand);   /*   then read the value */
4456 
4457                 else                                            /* otherwise */
4458                     MICRO_ABORT (trap_Bounds_Violation);        /*   trap with a bounds violation if not privileged */
4459 
4460                 if (opcode == MTBA) {                           /* if the instruction is MTBA */
4461                     operand = operand + RB & DV_MASK;           /*   then add the step size */
4462                     cpu_write_memory (data, offset, operand);   /*     to the control variable */
4463                     }
4464 
4465                 control = SEXT16 (operand);             /* sign-extend the control value */
4466                 }
4467 
4468             else {                                      /* TBX or MTBX (none; STUN, BNDV) */
4469                 PREADJUST_SR (2);                       /* ensure that at least two TOS registers are loaded */
4470 
4471                 if (opcode == MTBX)                     /* if the instruction is MTBX */
4472                     X = X + RB & R_MASK;                /*   then add the step size to the control variable */
4473 
4474                 control = SEXT16 (X);                   /* sign-extend the control value */
4475                 }
4476 
4477             limit = SEXT16 (RA);                        /* sign-extend the limit value */
4478 
4479             if (RB & D16_SIGN)                          /* if the step size is negative */
4480                 branch = control >= limit;              /*   then branch if the value is not below the limit */
4481             else                                        /* otherwise */
4482                 branch = control <= limit;              /*   branch if the value is not above the limit */
4483 
4484             if (branch) {                                       /* if the test succeeded */
4485                 displacement = CIR & DISPL_255_MASK;            /*   then get the branch displacement */
4486 
4487                 if (CIR & DISPL_255_SIGN)                       /* if the displacement is negative */
4488                     offset = P - 2 - displacement & LA_MASK;    /*   then subtract the displacement from the base */
4489                 else                                            /* otherwise */
4490                     offset = P - 2 + displacement & LA_MASK;    /*   add the displacement to the base */
4491 
4492                 if (cpu_stop_flags & SS_LOOP                    /* if the infinite loop stop is active */
4493                   && displacement == 0                          /*   and the target is the current instruction */
4494                   && (opcode == TBA || opcode == TBX))          /*     and the instruction must be checked */
4495                     status = STOP_INFLOOP;                      /*       then stop the simulator */
4496                 else                                            /* otherwise */
4497                     status = SCPE_OK;                           /*   continue */
4498 
4499                 cpu_read_memory (fetch_checked, offset, &NIR);  /* load the next instruction register */
4500                 P = offset + 1 & R_MASK;                        /*   and increment the program counter */
4501                 }
4502 
4503             else {                                      /* otherwise the test failed */
4504                 cpu_pop ();                             /*   so pop the limit */
4505                 cpu_pop ();                             /*     and the step size from the stack */
4506 
4507                 if (opcode == TBA || opcode == MTBA)    /* if the instruction is TBA or MTBA */
4508                     cpu_pop ();                         /*   then pop the variable address too */
4509                 }                                       /*     and continue execution at P + 1 */
4510             }
4511         break;
4512 
4513 
4514     case 006:                                           /* CMPM (CCC; STUN) */
4515         cpu_ea (CIR, &class, &offset, NULL);            /* get the effective address */
4516         cpu_read_memory (class, offset, &operand);      /*   and read the operand */
4517 
4518         PREADJUST_SR (1);                               /* ensure that at least one TOS register is loaded */
4519 
4520         SET_CCC (RA, 0, operand, 0);                    /* set the condition code from the TOS value */
4521         cpu_pop ();                                     /*   and then pop the value from the stack */
4522         break;
4523 
4524 
4525     case 007:                                           /* ADDM (CCA, C, O; STUN, BNDV, ARITH) */
4526         cpu_ea (CIR, &class, &offset, NULL);            /* get the effective address */
4527         cpu_read_memory (class, offset, &operand);      /*   and read the operand */
4528 
4529         PREADJUST_SR (1);                               /* ensure that at least one TOS register is loaded */
4530 
4531         RA = cpu_add_16 (RA, operand);                  /* add the operands */
4532         SET_CCA (RA, 0);                                /*   and set the condition code */
4533         break;
4534 
4535 
4536     case 010:                                           /* SUBM (CCA, C, O; STUN, BNDV, ARITH) */
4537         cpu_ea (CIR, &class, &offset, NULL);            /* get the effective address */
4538         cpu_read_memory (class, offset, &operand);      /*   and read the operand */
4539 
4540         PREADJUST_SR (1);                               /* ensure that at least one TOS register is loaded */
4541 
4542         RA = cpu_sub_16 (RA, operand);                  /* subtract the operands */
4543         SET_CCA (RA, 0);                                /*   and set the condition code */
4544         break;
4545 
4546 
4547     case 011:                                           /* MPYM (CCA, O; STUN, STOV, BNDV, ARITH) */
4548         cpu_ea (CIR, &class, &offset, NULL);            /* get the effective address */
4549         cpu_read_memory (class, offset, &operand);      /*   and read the operand */
4550 
4551         PREADJUST_SR (1);                               /* ensure that at least one TOS register is loaded */
4552 
4553         RA = cpu_mpy_16 (RA, operand);                  /* multiply the operands */
4554         SET_CCA (RA, 0);                                /*   and set the condition code */
4555         break;
4556 
4557 
4558     case 012:                                           /* INCM, DECM */
4559         cpu_ea (CIR | M_FLAG, &class, &offset, NULL);   /* get the effective address (forced to data-relative) */
4560         cpu_read_memory (class, offset, &operand);      /*   and read the operand */
4561 
4562         if (CIR & M_FLAG)                               /* DECM (CCA, C, O; BNDV, ARITH) */
4563             result = cpu_sub_16 (operand, 1);           /* decrement the operand and set C and O as necessary */
4564         else                                            /* INCM (CCA, C, O; BNDV, ARITH) */
4565             result = cpu_add_16 (operand, 1);           /* increment the operand and set C and O as necessary */
4566 
4567         cpu_write_memory (class, offset, result);       /* write the operand back to memory */
4568         SET_CCA (result, 0);                            /*   and set the condition code */
4569         break;
4570 
4571 
4572     case 013:                                           /* LDX (CCA; BNDV) */
4573         cpu_ea (CIR, &class, &offset, NULL);            /* get the effective address */
4574         cpu_read_memory (class, offset, &X);            /*   and read the operand into the X register */
4575 
4576         SET_CCA (X, 0);                                 /* set the condition code */
4577         break;
4578 
4579 
4580     case 014:                                           /* BR (none; BNDV), BCC (none; BNDV) */
4581         if ((CIR & BR_MASK) != BCC) {                   /* if the instruction is BR */
4582             cpu_ea (CIR, &class, &offset, NULL);        /*   then get the effective address of the branch */
4583 
4584             if (cpu_stop_flags & SS_LOOP                /* if the infinite loop stop is active */
4585               && offset == (P - 2 & LA_MASK))           /*   and the target is the current instruction */
4586                 status = STOP_INFLOOP;                  /*     then stop the simulator */
4587             else                                        /* otherwise */
4588                 status = SCPE_OK;                       /*   continue */
4589 
4590             cpu_read_memory (fetch_checked, offset, &NIR);  /* load the next instruction register */
4591             P = offset + 1 & R_MASK;                        /*   and increment the program counter */
4592             }
4593 
4594         else if (TO_CCF (STA) & CIR << BCC_CCF_SHIFT)   /* otherwise if the BCC test succeeds */
4595             status = cpu_branch_short (TRUE);           /*   then branch to the target address */
4596         break;                                          /* otherwise continue execution at P + 1 */
4597 
4598 
4599     case 015:                                           /* LDD (CCA; STOV, BNDV), LDB (CCB; STOV, BNDV) */
4600         if (CIR & M_FLAG) {                             /* if the instruction is LDD */
4601             cpu_ea (CIR, &class, &offset, NULL);        /*   then get the effective address of the double-word */
4602 
4603             cpu_read_memory (class, offset, &operand_1);                /* read the MSW */
4604             cpu_read_memory (class, offset + 1 & LA_MASK, &operand_2);  /*   and the LSW of the operand */
4605 
4606             cpu_push ();                                /* push the MSW  */
4607             cpu_push ();                                /*   and the LSW  */
4608             RB = operand_1;                             /*     of the operand */
4609             RA = operand_2;                             /*       onto the stack */
4610 
4611             SET_CCA (RB, RA);                           /* set the condition code */
4612             }
4613 
4614         else {                                                  /* otherwise the instruction is LDB */
4615             cpu_ea (CIR | M_FLAG, &class,  &offset, &selector); /*   so get the effective word address of the byte */
4616             cpu_read_memory (class, offset, &operand);          /*     and read the operand */
4617 
4618             cpu_push ();                                /* push the stack down */
4619 
4620             if (selector == upper)                      /* if the upper byte is selected */
4621                 RA = UPPER_BYTE (operand);              /*   then store it in the TOS */
4622             else                                        /* otherwise */
4623                 RA = LOWER_BYTE (operand);              /*   store the lower byte in the TOS */
4624 
4625             SET_CCB (RA);                               /* set the condition code */
4626             }
4627         break;
4628 
4629 
4630     case 016:                                           /* STD (none; STUN, BNDV), STB (none; STUN, BNDV) */
4631         if (CIR & M_FLAG) {                             /* if the instruction is STD */
4632             cpu_ea (CIR, &class, &offset, NULL);        /*   then get the effective address of the double-word */
4633 
4634             PREADJUST_SR (2);                           /* ensure that at least two TOS registers are loaded */
4635 
4636             cpu_write_memory (class, offset + 1 & LA_MASK, RA); /* write the LSW first to follow the microcode */
4637             cpu_write_memory (class, offset, RB);               /*   and then write the MSW */
4638 
4639             cpu_pop ();                                 /* pop the TOS */
4640             cpu_pop ();                                 /*   and the NOS */
4641             }
4642 
4643         else {                                                  /* otherwise the instruction is STB */
4644             cpu_ea (CIR | M_FLAG, &class, &offset, &selector);  /*   so get the effective word address of the byte */
4645 
4646             PREADJUST_SR (1);                           /* ensure that at least one TOS register is loaded */
4647 
4648             cpu_read_memory (class, offset, &operand);  /* read the word containing the target byte */
4649 
4650             if (selector == upper)                      /* if the upper byte is targeted */
4651                 operand = REPLACE_UPPER (operand, RA);  /*   then store the TOS into it */
4652             else                                        /* otherwise */
4653                 operand = REPLACE_LOWER (operand, RA);  /*   store the TOS into the lower byte */
4654 
4655             cpu_write_memory (class, offset, operand);  /* write the word back */
4656             cpu_pop ();                                 /*   and pop the TOS */
4657             }
4658         break;
4659 
4660 
4661     case 017:                                           /* LRA (none; STOV, BNDV) */
4662         cpu_ea (CIR, &class, &offset, NULL);            /* get the effective address */
4663 
4664         if (class == program_checked)                   /* if this a program reference */
4665             offset = offset - PB;                       /*   then subtract PB to get the relative address */
4666         else                                            /* otherwise it is a data or stack reference */
4667             offset = offset - DB;                       /*   so subtract DB to get the address */
4668 
4669         cpu_push ();                                    /* push the relative address */
4670         RA = offset & R_MASK;                           /*   onto the stack */
4671         break;
4672 
4673     }                                                   /* all cases are handled */
4674 
4675 if (status == STOP_UNIMPL                               /* if the instruction is unimplemented */
4676   && (cpu_stop_flags & SS_UNIMPL) == 0)                 /*   and the unimplemented instruction stop is inactive */
4677     MICRO_ABORT (trap_Unimplemented);                   /*     then trap to handle it */
4678 
4679 return status;
4680 }
4681 
4682 
4683 /* Trace the register set.
4684 
4685    This routine outputs the current values of the machine registers to the
4686    debug log.  The first output line consists of the SBANK, SM, SR, TOS, index,
4687    and status register values.  If the "cpu_base_changed" flag is set, a second
4688    line consisting of the DBANK register, code segment number, and code, data,
4689    and stack base and limit registers is also output.
4690 
4691    The routine must not be called unless the debug log is defined, and should
4692    not be called unless the register trace flag is set.
4693 */
4694 
trace_registers(void)4695 static void trace_registers (void)
4696 {
4697 static const char *const stack_formats [] = {           /* stack register display formats, indexed by SR */
4698     BOV_FORMAT "  ",                                    /*   SR = 0 format */
4699     BOV_FORMAT "  A %06o, ",                            /*   SR = 1 format */
4700     BOV_FORMAT "  A %06o, B %06o, ",                    /*   SR = 2 format */
4701     BOV_FORMAT "  A %06o, B %06o, C %06o, ",            /*   SR = 3 format */
4702     BOV_FORMAT "  A %06o, B %06o, C %06o, D %06o, "     /*   SR = 4 format */
4703     };
4704 
4705 hp_trace (&cpu_dev, DEB_REG, stack_formats [SR],        /* output the active TOS registers */
4706           SBANK, SM, SR, RA, RB, RC, RD);
4707 
4708 fprintf (sim_deb, "X %06o, %s\n", X, fmt_status (STA)); /* output the index and status registers */
4709 
4710 if (cpu_base_changed) {                                 /* if the base registers have been altered */
4711     hp_trace (&cpu_dev, DEB_REG,                        /*   then output the base register values */
4712               BOV_FORMAT "  PB %06o, PL %06o, DL %06o, DB %06o, Q %06o, Z %06o\n",
4713               DBANK, 0, STATUS_CS (STA), PB, PL, DL, DB, Q, Z);
4714 
4715     cpu_base_changed = FALSE;                           /* clear the base registers changed flag */
4716     }
4717 
4718 return;
4719 }
4720