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