1 /* hp3000_cpu.c: HP 3000 Central Processing Unit simulator
2
3 Copyright (c) 2016-2019, 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 09-Dec-19 JDB Replaced debugging macros with tracing macros
29 20-Jun-19 JDB Added wait time to process clock trace
30 08-Apr-19 JDB Suppress stop messages for step and breakpoints in DO files
31 07-Apr-19 JDB Moved breakpoint test before run/halt-mode test
32 21-Feb-19 JDB Resuming into PAUS with pending IRQ now sets P correctly
33 Moved "debug_save" from global to "sim_instr" local
34 06-Feb-19 JDB Corrected trace report for simulation stop
35 27-Dec-18 JDB Revised fall through comments to comply with gcc 7
36 05-Sep-17 JDB Removed the -B (binary display) option; use -2 instead
37 Changed REG_A (permit any symbolic override) to REG_X
38 19-Jan-17 JDB Added comments describing the OPND and EXEC trace options
39 29_Dec-16 JDB Changed the status mnemonic flag from REG_S to REG_T
40 07-Nov-16 JDB Renamed cpu_byte_to_word_ea to cpu_byte_ea
41 03-Nov-16 JDB Added zero offsets to the cpu_call_procedure calls
42 01-Nov-16 JDB Added per-instruction trace capability
43 24-Oct-16 JDB Renamed SEXT macro to SEXT16
44 22-Sep-16 JDB Moved byte_to_word_address from hp3000_cpu_base.c
45 21-Sep-16 JDB Added CIS/NOCIS option
46 01-Sep-16 JDB Add power fail/power restore support
47 23-Aug-16 JDB Add module interrupt support
48 14-Jul-16 JDB Implemented the cold dump process
49 Changed "loading" EXEC_STATE to "waiting"
50 11-Jul-16 JDB Change "cpu_unit" from a UNIT to an array of one UNIT
51 08-Jun-16 JDB Corrected %d format to %u for unsigned values
52 16-May-16 JDB ACCESS_PROPERTIES.name is now a pointer-to-constant
53 13-May-16 JDB Modified for revised SCP API function parameter types
54 24-Mar-16 JDB Changed memory word type from uint16 to MEMORY_WORD
55 21-Mar-16 JDB Changed cpu_ccb_table type from uint16 to HP_WORD
56 11-Mar-16 JDB Fixed byte EA calculations with negative indexes
57 22-Dec-15 JDB First release version
58 01-Apr-15 JDB First successful run of MPE-V/R through account login
59 11-Dec-12 JDB Created
60
61 References:
62 - HP 3000 Series II System Microprogram Listing
63 (30000-90023, August 1976)
64 - HP 3000 Series II/III System Reference Manual
65 (30000-90020, July 1978)
66 - Machine Instruction Set Reference Manual
67 (30000-90022, June 1984)
68
69
70 The HP 3000 is a family of general-purpose business computers that were sold
71 by Hewlett-Packard from 1972 through 2001. There are two major divisions
72 within this family: the "classic" 16-bit, stack-oriented CISC machines, and
73 the "Precision Architecture" 32-bit, register-oriented RISC machines that
74 succeeded them. All machines run versions of MPE, the "Multiprogramming
75 Executive" operating system.
76
77 Within the "classic" division, there are two additional subdivisions, based
78 on the method used for peripheral connections: the original "SIO" machines,
79 and the later "HP-IB" machines. The I/O interfacing hardware differs between
80 the two types of machines, as do the privileged I/O machine instructions.
81 The user instruction sets are identical, as are the register sets visible to
82 the programmer. The I/O drivers are different to account for the hardware
83 differences, and therefore they run slightly different versions of MPE.
84
85 This implementation is a simulator for the classic SIO machines. This group
86 consists of the 3000 CX, the Series I, Series II, and Series III; the last is
87 simulated here. The CX and Series I, which is a repackaged CX, are
88 essentially subsets of the Series II/III -- a smaller instruction set,
89 limited memory size, and lower-precision floating-point instructions.
90 Simulation of these machines may be added in the future. Future simulation
91 of the HP-IB machines (the Series 30 through 70) is desirable, as the latest
92 MPE versions run only on these machines, but documentation on the internals
93 of the HP-IB hardware controllers is nonexistent.
94
95 The CX and Series I support 64K 16-bit words of memory. The Series II
96 supports up to 256K, divided into four banks of 64K words each, and the
97 Series III extends this to 1024K words using 16 banks. Memory is divided
98 into variable-length code and data segments, with the latter containing a
99 program's global data area and stack.
100
101 Memory protection is accomplished by checking program, data, and stack
102 accesses against segment base and limit registers, which can be set only by
103 MPE. Bounds violations cause automatic hardware traps to a handler routine
104 within MPE. Some violations may be permitted; for example, a Stack Overflow
105 trap may cause MPE to allocate a larger stack and then restart the
106 interrupted instruction. Almost all memory references are position-
107 independent, so moving segments to accommodate expansion requires only
108 resetting of the segment registers to point at the new locations. Code
109 segments are fully reentrant and shareable, and both code and data are
110 virtual, as the hardware supports absent code and data segment traps.
111
112 The classic 3000s are stack machines. Most of the instructions operate on
113 the value on the top of the stack (TOS) or on the TOS and the next-to-the-top
114 of the stack (NOS). To improve execution speed, the 3000 has a set of
115 hardware registers that are accessed as the first four locations at the top
116 of the stack, while the remainder of the stack locations reside in main
117 memory. A hardware register renamer provides fast stack pushes and pops
118 without physically copying values between registers.
119
120 In hardware, the stack registers are referenced internally as TR0-TR3 and
121 externally as RA-RD. An access to the RA (TOS) register is translated by the
122 renamer to access TR0, TR1, etc. depending on which internal register is
123 designated as the current top of the stack. For example, assume that RA
124 corresponds to TR0. To push a new value onto the top of the stack, the
125 renamer is adjusted so that RA corresponds to TR1, and the new value is
126 stored there. In this state, RB corresponds to TR0, the previous TOS (and
127 current NOS) value. Additional pushes rename RA as TR2 and then TR3, with RB
128 being renamed to TR1 and then TR2, and similarly for RC and RD. The number
129 of valid TOS registers is given by the value in the SR register, and the
130 first stack location in memory is given by the value in the SM register.
131 Pops reverse the sequence: a pop with RA corresponding to TR3 renames RA to
132 TR2, RB to TR1, etc. When all four stack registers are in use, a push will
133 copy the value in RD to the top of the memory stack (SM + 1) before the
134 registers are renamed and the new value stored into RA. Similarly, when all
135 four stack registers are empty, a pop simply decrements the SM register,
136 effectively deleting the top of the memory stack.
137
138 Because of the renamer, the microcode can always use RA to refer to the top
139 of the stack, regardless of which internal TR register is being used, and
140 similarly for RB-RD. Execution of each stack instruction begins with a
141 preadjustment, if needed, that loads the TOS registers that will be used by
142 the instruction from the top of the memory stack. For example, if only RA
143 contains a value (i.e., the SR register value is 1), the ADD instruction,
144 which adds the values in RA and RB, will load RB with the value on the top of
145 the memory stack, the SR count will be incremented, and the SM register will
146 be decremented. On the other hand, if both RA and RB contained values (SR >=
147 2), then no preadjustment would be required before the ADD instruction
148 microcode manipulated RA and RB.
149
150 In simulation, the renamer is implemented by physically copying the values
151 between registers, as this is much faster than mapping via array index
152 values, as the hardware does. A set of functions provides the support to
153 implement the hardware stack operations:
154
155 cpu_push - empty the TOS register (SR++, caller stores into RA)
156 cpu_pop - delete the TOS register (SR--)
157 cpu_queue_up - move from memory to the lowest TOS register (SR++, SM--)
158 cpu_queue_down - move from the lowest TOS register to memory (SR--, SM++)
159 cpu_flush - move all stack registers to memory (SR = 0 on return)
160 cpu_adjust_sr - queue up until the required SR count is reached
161 cpu_mark_stack - write a stack marker to memory
162
163 The renamer is described in US Patent 3,737,871 (Katzman, "Stack Register
164 Renamer", June 1973).
165
166 The MPE operating system is supported by special microcode features that
167 perform code and data segment mapping, segment access bounds checking,
168 privilege checking, etc. The layout of certain in-memory tables is known to
169 both the OS and the microcode and is used to validate execution of
170 instructions. For instance, every stack instruction is checked for a valid
171 access within the stack segment boundaries, which are set up by the OS
172 before program dispatch. For this reason, the 3000 cannot be operated as a
173 "bare" machine, because these tables would not have been initialized.
174 Similarly, the "cold load" process by which the OS is loaded from storage
175 media into memory is entirely in microcode, as machine instructions cannot be
176 executed until the required tables are loaded into memory.
177
178 This OS/microcode integration means that the microcode may detect conditions
179 that make continued execution impossible. An example would be a not-present
180 segment fault for the segment containing the disc I/O driver. If such a
181 condition is detected, the CPU does a "system halt." This fatal microcode
182 error, distinct from a regular programmed halt, causes operation to cease
183 until the CPU is reset.
184
185 The CPU hardware includes a free-running 16-bit process clock that increments
186 once per millisecond whenever a user program is executing. MPE uses the
187 process clock to charge CPU usage to programs, and thereby to users, groups,
188 and accounts. Instructions are provided to read (RCLK) and set (SCLK) the
189 process clock.
190
191
192 The data types supported by the instruction set are:
193
194 - 8-bit unsigned byte
195 - 16-bit unsigned integer ("logical" format)
196 - 16-bit two's-complement integer
197 - 32-bit two's-complement integer
198 - 32-bit sign-magnitude floating point
199 - 64-bit sign-magnitude floating point
200
201 Multi-word values are stored in memory with the most-significant words in the
202 lowest addresses. The stack is organized in memory from lower to higher
203 addresses, so a value on the stack has its least-significant word on the top
204 of the stack.
205
206 Machine instructions are initially decoded by a sub-opcode contained in the
207 four highest bits, as follows (note that the HP 3000 numbers bits from
208 left-to-right, i.e., bit 0 is the MSB and bit 15 is the LSB):
209
210 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
211 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
212 | 0 0 0 0 | 1st stack opcode | 2nd stack opcode | Stack
213 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
214
215
216 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
217 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
218 | 0 0 0 1 | X | shift opcode | shift count | Shift
219 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
220
221 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
222 | 0 0 0 1 | I | branch opcode |+/-| P displacement | Branch
223 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
224
225 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
226 | 0 0 0 1 | X | bit test opcode | bit position | Bit Test
227 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
228
229
230 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
231 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
232 | 0 0 1 0 | 0 0 0 0 | move op | opts/S decrement | Move
233 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
234
235 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
236 | 0 0 1 0 | 0 0 0 0 | special op | 0 0 | sp op | Special
237 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
238
239 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
240 | 0 0 1 0 | 0 0 0 1 | option set | option subset | Firmware
241 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
242
243 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
244 | 0 0 1 0 | imm opcode | immediate operand | Immediate
245 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
246
247 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
248 | 0 0 1 0 | field opcode | J field | K field | Field
249 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
250
251 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
252 | 0 0 1 0 | register op | SK| DB| DL| Z |STA| X | Q | S | Register
253 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
254
255
256 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
257 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
258 | 0 0 1 1 | 0 0 0 0 | I/O opcode | K field | I/O
259 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
260
261 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
262 | 0 0 1 1 | 0 0 0 0 | cntl opcode | 0 0 | cn op | Control
263 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
264
265 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
266 | 0 0 1 1 | program op | N field | Program
267 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
268
269 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
270 | 0 0 1 1 | immediate op | immediate operand | Immediate
271 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
272
273 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
274 | 0 0 1 1 | memory op | P displacement | Memory
275 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
276
277 The memory, loop, and branch instructions occupy the remainder of the
278 sub-opcodes (04-17):
279
280 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
281 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
282 | memory op | X | I | mode and displacement | Memory
283 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
284 | 0 | 0 | P+ displacement 0-255 |
285 +---+---+---+---+---+---+---+---+---+---+
286 | 0 | 1 | P- displacement 0-255 |
287 +---+---+---+---+---+---+---+---+---+---+
288 | 1 | 0 | DB+ displacement 0-255 |
289 +---+---+---+---+---+---+---+---+---+---+
290 | 1 | 1 | 0 | Q+ displacement 0-127 |
291 +---+---+---+---+---+---+---+---+---+---+
292 | 1 | 1 | 1 | 0 | Q- displacement 0-63 |
293 +---+---+---+---+---+---+---+---+---+---+
294 | 1 | 1 | 1 | 1 | S- displacement 0-63 |
295 +---+---+---+---+---+---+---+---+---+---+
296
297 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
298 | memory op | X | I | s | mode and displacement | Memory
299 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
300 | 0 | DB+ displacement 0-255 |
301 +---+---+---+---+---+---+---+---+---+
302 | 1 | 0 | Q+ displacement 0-127 |
303 +---+---+---+---+---+---+---+---+---+
304 | 1 | 1 | 0 | Q- displacement 0-63 |
305 +---+---+---+---+---+---+---+---+---+
306 | 1 | 1 | 1 | S- displacement 0-63 |
307 +---+---+---+---+---+---+---+---+---+
308
309 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
310 | 0 1 0 1 |loop op| 0 |+/-| P-relative displacement | Loop
311 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
312
313 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
314 | 1 1 0 0 | I | 0 1 | > | = | < | P+- displacement 0-31 | Branch
315 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
316
317 Optional firmware extension instruction sets occupy instruction codes
318 020400-020777, except for the DMUL (020570) and DDIV (020571) instructions
319 that are part of the base set, as follows:
320
321 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
322 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
323 | 0 0 1 0 | 0 0 0 1 | 0 1 1 1 | 1 0 0 | x | DMUL/DDIV
324 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
325
326 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
327 | 0 0 1 0 | 0 0 0 1 | 0 0 0 0 | 1 | ext fp op | Extended FP
328 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
329
330 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
331 | 0 0 1 0 | 0 0 0 1 | 0 0 0 1 | APL op | APL
332 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
333
334 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
335 | 0 0 1 0 | 0 0 0 1 | 0 0 1 1 | COBOL op | COBOL
336 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
337
338 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
339 | 0 0 1 0 | 0 0 0 1 | 1 | options | decimal op | Decimal
340 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
341
342 Most instructions are defined by unique 16-bit codes that specify the
343 operations, operands, addressing modes, shift counts, etc. For each of these
344 instructions, there is only one canonical form that encodes a given
345 instruction (or instruction pair, in the case of stack instructions). For
346 example, the octal value 140003 is the only value that encodes the "BR P+3"
347 instruction.
348
349 There are also instruction codes that contain one or more bits designated as
350 "reserved" in the Machine Instruction Set Reference Manual. For some of
351 these instructions, the reserved bits do not affect instruction decoding.
352 Each instruction of this type has a defined canonical form -- typically with
353 the reserved bits set to zero -- but will execute identically if one of the
354 undefined forms is used. For example, the "MOVE" instructions define bits
355 12-13 as 00, but the bits are not decoded, so values of 01, 10, and 11 for
356 these bits will result in identical execution. Specifically, "MOVE 0" is
357 encoded canonically as octal value 020020, but the undefined codes 020024,
358 020030, and 020034 execute "MOVE 0" as well.
359
360 For the rest of these instructions, the reserved bits are decoded and will
361 affect the instruction interpretation. An example of this is the "IXIT"
362 instruction. It also defines bits 12-13 as 00 (canonical encoding 020360),
363 but in this case the bits must be 00 for the instruction to execute; any
364 other value (e.g., undefined codes 020364, 020370, or 020374) executes as a
365 "PCN" instruction, whose canonical encoding is 020362.
366
367 Finally, some codes are not assigned to any instructions, or they are
368 assigned to instructions that are supplied by optional firmware that is not
369 present in the machine. These instruction codes are designated as
370 "unimplemented" and will cause Unimplemented Instruction traps if they are
371 executed. Examples are the stack operation code 072 in either the left-hand
372 or right-hand position (i.e., instruction codes 0072xx and 00xx72), codes
373 020410-020415 if the Extended Instruction Set firmware option is not
374 installed, and codes 036000-036777.
375
376 When the simulator examines the bit patterns of instructions to execute, each
377 will fall into one of four categories:
378
379 1. Defined (canonical) instruction encodings.
380
381 2. Undefined (non-canonical) instruction encodings, where reserved fields
382 are "don't care" bits (e.g., MOVE).
383
384 3. Undefined (non-canonical) instruction encodings, where reserved fields
385 are decoded (e.g., IXIT).
386
387 4. Unimplemented instruction encodings (e.g., stack opcode 072 or EADD with
388 no EIS installed).
389
390 When examining memory or register values in instruction-mnemonic form, the
391 names of the canonical instructions in category 1 are displayed in uppercase,
392 as are the names of the non-canonical instructions in category 2. The
393 non-canonical instruction names in category 3 are displayed in lowercase.
394 This is to indicate to the user that the instructions that will be executed
395 may not be the ones expected from the decoding. Instruction names in
396 category 4 that correspond to supported firmware options are displayed in
397 uppercase, regardless of whether or not the option is enabled. Category 4
398 encodings that do not correspond to instructions are displayed in octal.
399
400 All of the base set instructions are one word in length. Most of the
401 firmware extension instructions occupy one word as well, although some are
402 two words long. If the first word of a two-word instruction is valid but the
403 second is not, an Unimplemented Instruction trap will occur, with P pointing
404 to the location after the second word.
405
406
407 The simulator provides four stop conditions related to instruction execution
408 that may be enabled with a SET CPU STOP=<stop> command:
409
410 <stop> Action
411 ------ ------------------------------------
412 LOOP stop on an infinite loop
413 PAUSE stop on a PAUS instruction
414 UNDEF stop on an undefined instruction
415 UNIMPL stop on an unimplemented instruction
416
417 If an enabled stop condition is detected, execution ceases with the
418 instruction pending, and control returns to the SCP prompt. When simulation
419 stops, execution may be resumed in two ways. If the cause of the stop has
420 not been remedied and the stop has not been disabled, resuming execution with
421 CONTINUE, STEP, GO, or RUN will cause the stop to occur again. Alternately,
422 specifying the "-B" switch with any of the preceding commands will resume
423 execution while bypassing the stop for the current instruction.
424
425 The LOOP option stops the simulator if it attempts to execute an instruction
426 that enters an infinite loop (e.g., BR P+0). The branch instructions TBA,
427 TBX, BCC, BR, BCY, BNCY, BOV, and BNOV result in an infinite loop if the
428 branch displacement is zero and the branch condition is true. The remaining
429 branch instructions cannot result in an infinite loop, as they all modify the
430 CPU state and so eventually reach a point where they drop out of the loop.
431
432 The PAUSE option stops the simulator if execution of a PAUS instruction is
433 attempted. This instruction normally suspends instruction fetching until an
434 interrupt occurs. Clearing the stop and resuming execution suspends the
435 fetch/execute process until an external interrupt occurs. Resuming with the
436 stop bypassed continues execution with the instruction following the PAUS;
437 this is the same action that occurs when pressing the HALT button and then
438 the RUN button in hardware.
439
440 The UNDEF option stops the simulator if execution of a non-canonical
441 instruction from decoding category 3 (i.e., an instruction containing a
442 decoded reserved bit pattern other than that defined in the Machine
443 Instruction Set manual) is attempted. The intent is to catch instructions
444 containing reserved fields with values that change the meaning of those
445 instructions. Bypassing the stop will decode and execute the instruction in
446 the same manner as the HP 3000 microcode.
447
448 The UNIMPL option stops the simulator if execution of an instruction from
449 decoding category 4 is attempted. Bypassing the stop will cause an
450 Unimplemented Instruction trap. Instructions that depend on the presence of
451 firmware options are implemented if the option is present and unimplemented
452 if the option is absent. For example, instruction code 020410 executes as
453 the EADD instruction if the Extended Instruction Set is enabled but is
454 unimplemented if the EIS is disabled. It is displayed as EADD in either
455 case.
456
457 The instructions in category 2 whose non-canonical forms do not cause an
458 UNDEF stop are:
459
460 Canonical Reserved
461 Inst Encoding Bits Defined As Decoded As
462 ---- --------- -------- ----------- -----------
463 SCAN 010600 10-15 0 0 0 0 0 0 x x x x x x
464 TNSL 011600 10-15 0 0 0 0 0 0 x x x x x x
465 MOVE 020000 12-13 0 0 x x
466 MVB 020040 12-13 0 0 x x
467 MVBL 020100 13 0 x
468 SCW 020120 13 0 x
469 MVLB 020140 13 0 x
470 SCU 020160 13 0 x
471 CMPB 020240 12-13 0 0 x x
472 RSW 020300 12-14 0 0 0 x x x
473 LLSH 020301 12-14 0 0 0 x x x
474 PLDA 020320 12-14 0 0 0 x x x
475 PSTA 020321 12-14 0 0 0 x x x
476 LSEA 020340 12-13 0 0 x x
477 SSEA 020341 12-13 0 0 x x
478 LDEA 020342 12-13 0 0 x x
479 SDEA 020343 12-13 0 0 x x
480 PAUS 030020 12-15 0 0 0 0 x x x x
481
482 The instructions in category 3 whose non-canonical forms cause an UNDEF stop
483 are:
484
485 Canonical Reserved
486 Inst Encoding Bits Defined As Decoded As
487 ---- --------- -------- ---------- ----------
488 IXIT 020360 12-15 0 0 0 0 0 0 0 0
489 LOCK 020361 12-15 0 0 0 1 n n 0 1
490 PCN 020362 12-15 0 0 1 0 n n n 0
491 UNLK 020363 12-15 0 0 1 1 n n 1 1
492
493 SED 030040 12-15 0 0 0 x n n n x
494
495 XCHD 030060 12-15 0 0 0 0 0 0 0 0
496 PSDB 030061 12-15 0 0 0 1 n n 0 1
497 DISP 030062 12-15 0 0 1 0 n n n 0
498 PSEB 030063 12-15 0 0 1 1 n n 1 1
499
500 SMSK 030100 12-15 0 0 0 0 0 0 0 0
501 SCLK 030101 12-15 0 0 0 1 n n n n
502 RMSK 030120 12-15 0 0 0 0 0 0 0 0
503 RCLK 030121 12-15 0 0 0 1 n n n n
504
505 Where:
506
507 x = 0 or 1
508 n = any collective value other than 0
509
510 In hardware, the SED instruction works correctly only if opcodes 030040 and
511 030041 are used. Opcodes 030042-030057 also decode as SED, but the status
512 register is set improperly (the I bit is cleared, bits 12-15 are rotated
513 right twice and then ORed into the status register). In simulation, opcodes
514 030042-030057 work correctly but will cause an UNDEF simulation stop if
515 enabled.
516
517
518 The CPU simulator provides extensive tracing capabilities that may be enabled
519 with the SET CONSOLE DEBUG=<filename> and SET CPU DEBUG=<trace> commands.
520 The trace options that may be specified are:
521
522 Trace Action
523 ----- -------------------------------------------
524 INSTR trace instructions executed
525 DATA trace memory data accesses
526 FETCH trace memory instruction fetches
527 REG trace registers
528 OPND trace memory operands
529 EXEC trace matching instruction execution states
530 PSERV trace process clock service events
531
532 A section of an example trace is:
533
534 >>CPU fetch: 00.010342 020320 instruction fetch
535 >>CPU instr: 00.010341 000300 ZROX,NOP
536 >>CPU reg: 00.006500 000000 X 000000, M i t r o c CCG
537 >>CPU fetch: 00.010343 041100 instruction fetch
538 >>CPU instr: 00.010342 020320 PLDA
539 >>CPU data: 00.000000 001340 absolute read
540 >>CPU reg: 00.006500 000001 A 001340, X 000000, M i t r o c CCG
541 >>CPU fetch: 00.010344 037777 instruction fetch
542 >>CPU instr: 00.010343 041100 LOAD DB+100
543 >>CPU data: 00.002100 123003 data read
544 >>CPU reg: 00.006500 000002 A 123003, B 001340, X 000000, M i t r o c CCL
545 >>CPU fetch: 00.010345 023404 instruction fetch
546 >>CPU instr: 00.010344 037777 ANDI 377
547 >>CPU reg: 00.006500 000002 A 000003, B 001340, X 000000, M i t r o c CCG
548 >>CPU fetch: 00.010346 002043 instruction fetch
549 >>CPU instr: 00.010345 023404 MPYI 4
550 >>CPU reg: 00.006500 000002 A 000014, B 001340, X 000000, M i t r o c CCG
551 >>CPU fetch: 00.010347 020320 instruction fetch
552
553 The INSTR option traces instruction executions. Each instruction is printed
554 before it is executed. The two opcodes of a stack instruction are printed
555 together before the left-hand opcode is executed. If the right-hand opcode
556 is not NOP, it is reprinted before execution, with dashes replacing the
557 just-executed left-hand opcode.
558
559 The DATA option traces reads from and writes to memory. Each access is
560 classified by the memory bank register that is paired with the specified
561 offset; they are: dma, absolute, program, data, and stack. DMA accesses
562 derive their bank addresses from the banks specified in Set Bank I/O program
563 orders. Absolute accesses always use bank 0. Program, data, and stack
564 accesses use the bank addresses in the PBANK, DBANK, and SBANK registers,
565 respectively.
566
567 The FETCH option traces instruction fetches from memory. These accesses are
568 separated from those traced by the DATA option because fetches usually are of
569 little interest except when debugging the fetch/execute sequence. Because
570 the HP 3000 has a two-stage pipeline, fetches load the NIR (Next Instruction
571 Register) with the instruction after the instruction to be executed from the
572 CIR (Current Instruction Register).
573
574 The REG option traces register values. Two sets of registers are printed.
575 After executing each instruction, the currently active TOS registers, the
576 index register, and the status register are printed. After executing an
577 instruction that may alter the base registers, the program, data, and stack
578 segment base registers are printed.
579
580 The OPND option traces memory byte operand values. Some instructions take
581 memory and register operands that are difficult to decode from DATA or REG
582 traces. This option presents these operands in a higher-level format. The
583 memory bank and address values are always those of the operands. The operand
584 data and values printed are specific to the instruction. For example, the
585 ALGN instruction prints its source and target operands, digit counts, and
586 fraction counts, and the EDIT instruction displays its subprogram operations.
587
588 The EXEC option traces the execution of instructions that match
589 user-specified criteria. When a match occurs, all CPU trace options are
590 turned on for the duration of the execution of the matched instruction. The
591 prior trace settings are restored when a match fails. This option allows
592 detailed tracing of specified instructions while minimizing the log file size
593 compared to a full instruction trace.
594
595 The PSERV option traces process clock event service entries. Each trace
596 reports whether or not the CPU was executing on the Interrupt Control Stack
597 when the process clock ticked. Execution on the ICS implies that the
598 operating system is executing. As the process clock ticks every millisecond,
599 enabling PSERV tracing can quickly produce a large number of trace lines.
600
601 The various trace formats are interpreted as follows:
602
603 >>CPU instr: 00.010341 000300 ZROX,NOP
604 ~~ ~~~~~~ ~~~~~~ ~~~~~~~~
605 | | | |
606 | | | +-- instruction mnemonic(s)
607 | | +---------- octal data (instruction opcode)
608 | +------------------ octal address (P)
609 +----------------------- octal bank (PBANK)
610
611 >>CPU instr: 00.001240 000006 external interrupt
612 >>CPU instr: 00.023736 000000 unimplemented instruction trap
613 ~~ ~~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
614 | | | |
615 | | | +-- interrupt classification
616 | | +---------- parameter
617 | +------------------ octal address (P) at interrupt
618 +----------------------- octal bank (PBANK) at interrupt
619
620
621 >>CPU data: 00.000000 001340 absolute read
622 >>CPU data: 00.002100 123003 data read
623 ~~ ~~~~~~ ~~~~~~ ~~~~~~~~~~~~~
624 | | | |
625 | | | +-- memory access classification
626 | | +------------ octal data (memory contents)
627 | +-------------------- octal address (effective address)
628 +------------------------- octal bank (PBANK, DBANK, or SBANK)
629
630
631 >>CPU fetch: 00.010342 020320 instruction fetch
632 ~~ ~~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~
633 | | | |
634 | | | +-- memory access classification
635 | | +------------ octal data (instruction opcode)
636 | +-------------------- octal address (P + 1)
637 +------------------------- octal bank (PBANK)
638
639
640 >>CPU reg: 00.006500 000002 A 123003, B 001340, X 000000, M i t r o c CCL
641 ~~ ~~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
642 | | | |
643 | | | +-- register values (from 0-4 TOS registers, X, STA)
644 | | +------------ octal stack register count (SR)
645 | +-------------------- octal stack memory address (SM)
646 +------------------------- octal bank (SBANK)
647
648 >>CPU reg: 00.000000 000001 PB 010000, PL 025227, DL 001770, DB 002000, Q 006510, Z 007000
649 ~~ ~~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
650 | | | |
651 | | | +-- base register values
652 | | +------------ current code segment number (from STA)
653 | +-------------------- zero
654 +------------------------- octal bank (DBANK)
655
656 >>CPU opnd: 00.135771 000000 DFLC '+','!'
657 >>CPU opnd: 00.045071 000252 target fraction 3 length 6,"002222"
658 ~~ ~~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
659 | | | |
660 | | | +-- operand-specific value
661 | | +------------ operand-specific data
662 | +-------------------- octal address (effective address)
663 +------------------------- octal bank (PBANK, DBANK, or SBANK)
664
665 >>CPU pserv: Process clock delay 3970 service entered on the user stack
666
667 The process clock offers a user-selectable choice of calibrated or realistic
668 timing. Calibrated timing adjusts the clock to match actual elapsed time
669 (i.e., wall-clock time). Realistic timing bases the process-clock interval
670 on machine instructions executed, using a mean instruction time of 2.5
671 microseconds. Running on a typical host platform, the simulator is one or
672 two orders of magnitude faster than a real HP 3000, so the number of machine
673 instructions executed for a given calibrated time interval will be
674 correspondingly greater. When the process clock is calibrated, the current
675 simulation speed, expressed as a multiple of the speed of a real HP 3000
676 Series III, may be obtained with the SHOW CPU SPEED command. The speed
677 reported will not be representative if the machine was executing a PAUS
678 instruction when the simulator was stopped.
679
680 When enabled by a SET CPU IDLE command, execution of a PAUS instruction will
681 idle the simulator. While idle, the simulator does not use any host system
682 processor time. Idle detection requires that the process clock and system
683 clock be set to calibrated timing. Idling is disabled by default.
684
685
686 Implementation notes:
687
688 1. Three timing sources in the simulator may be calibrated to wall-clock
689 time. These are the process clock, the system clock, and the ATC poll
690 timer. The process clock is always enabled and running, although the
691 PCLK register only increments if the CPU is not executing on the ICS.
692 The system clock and poll timer run continuously if their respective
693 devices are enabled. If the ATC is disabled, then the process clock
694 takes over polling for the simulation console.
695
696 The three sources must be synchronized to allow efficient simulator
697 idling. This is accomplished by designating the process clock as the
698 master device, which calls the SCP timer calibration routines, and
699 setting the system clock and ATC poll timer to the process clock wait.
700 All three devices will then enter their respective service routines
701 concurrently.
702
703 2. In hardware, the process clock period is fixed at one millisecond, and
704 the system clock period, while potentially variable, is set by MPE to one
705 millisecond with an interrupt every 100 ticks. These periods are too
706 short to allow the simulator to idle, as the host OS clock resolution is
707 typically also one millisecond.
708
709 Therefore, the process and system clock simulators are scheduled with
710 ten-millisecond service times, and the PCLK and counter registers are
711 incremented by ten for each event service. To present the correct values
712 when the registers are read, the counts are incremented by amounts
713 proportional to the fractions of the service intervals that have elapsed
714 when the reads occur.
715
716 3. In simulation, the TOS renamer is implemented by permanently assigning
717 the register names RA-RD to TR [0]-TR [3], respectively, and copying the
718 contents between registers to pop and push values. An alternate
719 implementation approach is to use a renaming register, RN, that tracks
720 the correspondence between registers and array entries, and to assign the
721 register names dynamically using modular indices, e.g., RA is TR [RN], RB
722 is TR [(RN + 1) & 3], etc. In lieu of copying, incrementing and
723 decrementing RN is done to pop and push values.
724
725 Both implementations were mocked up and timing measurements made. The
726 results were that copying values is much faster than mapping via array
727 index values, so this is the implementation chosen.
728 */
729
730
731
732 #include "hp3000_defs.h"
733 #include "hp3000_cpu.h"
734 #include "hp3000_cpu_ims.h"
735 #include "hp3000_mem.h"
736 #include "hp3000_io.h"
737
738
739
740 /* Program constants */
741
742 #define PCLK_PERIOD mS (1) /* 1 millisecond process clock period */
743
744 #define PCLK_MULTIPLIER 10 /* number of hardware process clock ticks per service */
745 #define PCLK_RATE (1000 / PCLK_MULTIPLIER) /* process clock rate in ticks per second */
746
747 #define UNIT_OPTS (UNIT_EIS) /* the standard equipment feature set */
748
749 #define CPU_IO_RESET 0 /* reset CPU and all I/O devices */
750 #define IO_RESET 1 /* reset just the I/O devices */
751
752 #define CNTL_BASE 8 /* the radix for the cold dump control byte */
753 #define CNTL_MAX 0377 /* the maximum cold dump control byte value */
754
755 #define SIO_JUMP 0000000u /* Jump unconditionally */
756 #define SIO_SBANK 0014000u /* Set bank */
757 #define SIO_ENDIN 0034000u /* End with interrupt */
758 #define SIO_CNTL 0040000u /* Control */
759 #define SIO_WRITE 0060000u /* Write 4096 words */
760 #define SIO_READ 0077760u /* Read 16 words */
761
762 #define MS_CN_GAP 0000005u /* Write Gap */
763 #define MS_CN_WRR 0000004u /* Write Record */
764 #define MS_CN_RST 0000011u /* Rewind and Reset */
765 #define MS_CN_BSR 0000012u /* Backspace Record */
766 #define MS_CN_WFM 0000015u /* Write File Mark */
767
768 #define MS_ST_PROTECTED 0001000u /* write protected */
769 #define MS_ST_READY 0000400u /* unit ready */
770
771 #define MS_ST_MASK (MS_ST_PROTECTED | MS_ST_READY)
772
773
774 /* CPU global SCP data definitions */
775
776 DEVICE cpu_dev; /* incomplete device structure */
777
778 REG *sim_PC = NULL; /* the pointer to the P register */
779
780
781 /* CPU global data structures */
782
783
784 /* CPU registers */
785
786 HP_WORD CIR = 0; /* current instruction register */
787 HP_WORD NIR = 0; /* next instruction register */
788 HP_WORD PB = 0; /* program base register */
789 HP_WORD P = 0; /* program counter register */
790 HP_WORD PL = 0; /* program limit register */
791 HP_WORD PBANK = 0; /* program segment bank register */
792 HP_WORD DL = 0; /* data limit register */
793 HP_WORD DB = 0; /* data base register */
794 HP_WORD DBANK = 0; /* data segment bank register */
795 HP_WORD Q = 0; /* stack marker register */
796 HP_WORD SM = 0; /* stack memory register */
797 HP_WORD SR = 0; /* stack register counter */
798 HP_WORD Z = 0; /* stack limit register */
799 HP_WORD SBANK = 0; /* stack segment bank register */
800 HP_WORD TR [4] = { 0, 0, 0, 0 }; /* top of stack registers */
801 HP_WORD X = 0; /* index register */
802 HP_WORD STA = 0; /* status register */
803 HP_WORD SWCH = 0; /* switch register */
804 HP_WORD CPX1 = 0; /* run-mode interrupt flags register */
805 HP_WORD CPX2 = 0; /* halt-mode interrupt flags register */
806 HP_WORD MOD = 0; /* module control register */
807 HP_WORD PCLK = 0; /* process clock register */
808 HP_WORD CNTR = 0; /* microcode counter */
809
810
811 /* Condition Code B lookup table.
812
813 Byte-oriented instructions set the condition code in the status word using
814 Pattern B (CCB). For this encoding:
815
816 CCG = ASCII numeric character
817 CCE = ASCII alphabetic character
818 CCL = ASCII special character
819
820 The simplest implementation of this pattern is a 256-way lookup table using
821 disjoint condition code flags. The SET_CCB macro uses this table to set the
822 condition code appropriate for the supplied operand into the status word.
823 */
824
825 const HP_WORD cpu_ccb_table [256] = {
826 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* NUL SOH STX ETX EOT ENQ ACK BEL */
827 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* BS HT LF VT FF CR SO SI */
828 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
829 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* CAN EM SUB ESC FS GS RS US */
830 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* spa ! " # $ % & ' */
831 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* ( ) * + , - . / */
832 CFG, CFG, CFG, CFG, CFG, CFG, CFG, CFG, /* 0 1 2 3 4 5 6 7 */
833 CFG, CFG, CFL, CFL, CFL, CFL, CFL, CFL, /* 8 9 : ; < = > ? */
834 CFL, CFE, CFE, CFE, CFE, CFE, CFE, CFE, /* @ A B C D E F G */
835 CFE, CFE, CFE, CFE, CFE, CFE, CFE, CFE, /* H I J K L M N O */
836 CFE, CFE, CFE, CFE, CFE, CFE, CFE, CFE, /* P Q R S T U V W */
837 CFE, CFE, CFE, CFL, CFL, CFL, CFL, CFL, /* X Y Z [ \ ] ^ _ */
838 CFL, CFE, CFE, CFE, CFE, CFE, CFE, CFE, /* ` a b c d e f g */
839 CFE, CFE, CFE, CFE, CFE, CFE, CFE, CFE, /* h i j k l m n o */
840 CFE, CFE, CFE, CFE, CFE, CFE, CFE, CFE, /* p q r s t u v w */
841 CFE, CFE, CFE, CFL, CFL, CFL, CFL, CFL, /* x y z { | } ~ DEL */
842 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 200 - 207 */
843 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 210 - 217 */
844 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 220 - 227 */
845 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 230 - 237 */
846 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 240 - 247 */
847 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 250 - 257 */
848 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 260 - 267 */
849 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 270 - 277 */
850 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 300 - 307 */
851 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 310 - 317 */
852 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 320 - 327 */
853 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 330 - 337 */
854 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 340 - 347 */
855 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 350 - 357 */
856 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* 360 - 367 */
857 CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL /* 370 - 377 */
858 };
859
860
861 /* CPU global state */
862
863 jmp_buf cpu_save_env; /* the saved environment for microcode aborts */
864 uint32 cpu_stop_flags; /* the simulation stop flag set */
865
866 POWER_STATE cpu_power_state = power_on; /* the power supply state */
867 EXEC_STATE cpu_micro_state = halted; /* the microcode execution state */
868 t_bool cpu_base_changed = FALSE; /* TRUE if any base register is changed */
869 t_bool cpu_is_calibrated = TRUE; /* TRUE if the process clock is calibrated */
870 UNIT *cpu_pclk_uptr = &cpu_unit [0]; /* a (constant) pointer to the process clock unit */
871
872
873 /* CPU local state */
874
875 static uint32 sim_stops = 0; /* the current simulation stop flag settings */
876 static uint32 cpu_speed = 1; /* the CPU speed, expressed as a multiplier of a real machine */
877 static uint32 pclk_increment = 1; /* the process clock increment per event service */
878 static uint32 dump_control = 0002006u; /* the cold dump control word (default CNTL = 4, DEVNO = 6 */
879 static HP_WORD exec_mask = 0; /* the current instruction execution trace mask */
880 static HP_WORD exec_match = D16_UMAX; /* the current instruction execution trace matching value */
881
882
883 /* CPU local data structures */
884
885
886 /* Interrupt classification names */
887
888 static const char *const interrupt_name [] = { /* class names, indexed by IRQ_CLASS */
889 "integer overflow", /* 000 irq_Integer_Overflow */
890 "bounds violation", /* 001 irq_Bounds_Violation */
891 "illegal memory address error", /* 002 irq_Illegal_Address */
892 "non-responding module error", /* 003 irq_Timeout */
893 "system parity error", /* 004 irq_System_Parity */
894 "address parity error", /* 005 irq_Address_Parity */
895 "data parity error", /* 006 irq_Data_Parity */
896 "module", /* 007 irq_Module */
897 "external", /* 010 irq_External */
898 "power fail", /* 011 irq_Power_Fail */
899 "ICS trap", /* 012 irq_Trap */
900 "dispatch", /* 013 irq_Dispatch */
901 "exit" /* 014 irq_IXIT */
902 };
903
904
905 /* Trap classification names */
906
907 static const char *const trap_name [] = { /* trap names, indexed by TRAP_CLASS */
908 "no", /* 000 trap_None */
909 "bounds violation", /* 001 trap_Bounds_Violation */
910 NULL, /* 002 (unused) */
911 NULL, /* 003 (unused) */
912 NULL, /* 004 (unused) */
913 NULL, /* 005 (unused) */
914 NULL, /* 006 (unused) */
915 NULL, /* 007 (unused) */
916 NULL, /* 010 (unused) */
917 NULL, /* 011 (unused) */
918 NULL, /* 012 (unused) */
919 NULL, /* 013 (unused) */
920 NULL, /* 014 (unused) */
921 NULL, /* 015 (unused) */
922 NULL, /* 016 (unused) */
923 NULL, /* 017 (unused) */
924 "unimplemented instruction", /* 020 trap_Unimplemented */
925 "STT violation", /* 021 trap_STT_Violation */
926 "CST violation", /* 022 trap_CST_Violation */
927 "DST violation", /* 023 trap_DST_Violation */
928 "stack underflow", /* 024 trap_Stack_Underflow */
929 "privileged mode violation", /* 025 trap_Privilege_Violation */
930 NULL, /* 026 (unused) */
931 NULL, /* 027 (unused) */
932 "stack overflow", /* 030 trap_Stack_Overflow */
933 "user", /* 031 trap_User */
934 NULL, /* 032 (unused) */
935 NULL, /* 033 (unused) */
936 NULL, /* 034 (unused) */
937 NULL, /* 035 (unused) */
938 NULL, /* 036 (unused) */
939 "absent code segment", /* 037 trap_CS_Absent */
940 "trace", /* 040 trap_Trace */
941 "STT entry uncallable", /* 041 trap_Uncallable */
942 "absent data segment", /* 042 trap_DS_Absent */
943 "power on", /* 043 trap_Power_On */
944 "cold load", /* 044 trap_Cold_Load */
945 "system halt" /* 045 trap_System_Halt */
946 };
947
948
949 /* CPU features table.
950
951 The feature table is used to validate CPU feature changes within the subset
952 of features supported by a given CPU. Features in the typical list are
953 enabled when the CPU model is selected. If a feature appears in the typical
954 list but NOT in the optional list, then it is standard equipment and cannot
955 be disabled. If a feature appears in the optional list, then it may be
956 enabled or disabled as desired by the user.
957
958
959 Implementation notes:
960
961 1. The EIS was standard equipment for the Series II and III, so UNIT_EIS
962 should appear in their "typ" fields. However, the EIS instructions are
963 not currently implemented, so the value is omitted below.
964 */
965
966 struct FEATURE_TABLE {
967 uint32 typ; /* standard features plus typically configured options */
968 uint32 opt; /* complete list of optional features */
969 uint32 maxmem; /* maximum configurable memory in 16-bit words */
970 };
971
972 static const struct FEATURE_TABLE cpu_features [] = { /* features indexed by CPU_MODEL */
973 { 0, /* UNIT_SERIES_III */
974 UNIT_CIS,
975 1024 * 1024 },
976 { 0, /* UNIT_SERIES_II */
977 0,
978 256 * 1024 }
979 };
980
981
982 /* CPU local SCP support routine declarations */
983
984 static t_stat cpu_service (UNIT *uptr);
985 static t_stat cpu_reset (DEVICE *dptr);
986
987 static t_stat set_stops (UNIT *uptr, int32 option, char *cptr, void *desc);
988 static t_stat set_exec (UNIT *uptr, int32 option, char *cptr, void *desc);
989 static t_stat set_dump (UNIT *uptr, int32 option, char *cptr, void *desc);
990 static t_stat set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc);
991 static t_stat set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc);
992 static t_stat set_option (UNIT *uptr, int32 new_option, char *cptr, void *desc);
993 static t_stat set_pfars (UNIT *uptr, int32 setting, char *cptr, void *desc);
994
995 static t_stat show_stops (FILE *st, UNIT *uptr, int32 val, void *desc);
996 static t_stat show_exec (FILE *st, UNIT *uptr, int32 val, void *desc);
997 static t_stat show_dump (FILE *st, UNIT *uptr, int32 val, void *desc);
998 static t_stat show_speed (FILE *st, UNIT *uptr, int32 val, void *desc);
999
1000
1001 /* CPU local utility routine declarations */
1002
1003 static t_stat halt_mode_interrupt (HP_WORD device_number);
1004 static t_stat machine_instruction (void);
1005
1006
1007 /* CPU SCP data structures */
1008
1009
1010 /* Unit list.
1011
1012 The CPU unit holds the main memory capacity and is used to schedule the
1013 process clock events.
1014
1015
1016 Implementation notes:
1017
1018 1. The unit structure must be global for other modules to obtain the memory
1019 size via the MEMSIZE macro, which references the "capac" field.
1020 */
1021
1022 #define UNIT_FLAGS (UNIT_PFARS | UNIT_CALTIME)
1023
1024 UNIT cpu_unit [] = {
1025 { UDATA (&cpu_service, UNIT_FLAGS | UNIT_FIX | UNIT_BINK | UNIT_IDLE, 0), PCLK_PERIOD * PCLK_MULTIPLIER }
1026 };
1027
1028
1029 /* Register list.
1030
1031 The CPU register list exposes the machine registers for user inspection and
1032 modification. User flags describe the permitted and default display formats,
1033 as follows:
1034
1035 - REG_X permits any symbolic display
1036 - REG_M defaults to CPU instruction mnemonic display
1037 - REG_T defaults to CPU status mnemonic display
1038
1039
1040 Implementation notes:
1041
1042 1. All registers that reference variables of type HP_WORD must have the
1043 REG_FIT flag for proper access if HP_WORD is a 16-bit type.
1044
1045 2. The CNTR register is set to the value of the SR register when the
1046 micromachine halts or pauses. This allows the SR value to be accessed by
1047 the diagnostics. The top-of-stack registers are flushed to main memory
1048 when the machine halts or pauses, which alters SR.
1049 */
1050
1051 static REG cpu_reg [] = {
1052 /* Macro Name Location Radix Width Offset Flags */
1053 /* ------ ------- ------------ ----- ----- ------ ------------------------ */
1054 { ORDATA (CIR, CIR, 16), REG_M | REG_RO | REG_FIT }, /* current instruction register */
1055 { ORDATA (NIR, NIR, 16), REG_M | REG_RO | REG_FIT }, /* next instruction register */
1056 { ORDATA (PB, PB, 16), REG_FIT }, /* program base register */
1057 { ORDATA (P, P, 16), REG_FIT }, /* program counter register */
1058 { ORDATA (PL, PL, 16), REG_FIT }, /* program limit register */
1059 { ORDATA (PBANK, PBANK, 4), REG_FIT }, /* program segment bank register */
1060 { ORDATA (DL, DL, 16), REG_FIT }, /* data limit register */
1061 { ORDATA (DB, DB, 16), REG_FIT }, /* data base register */
1062 { ORDATA (DBANK, DBANK, 4), REG_FIT }, /* data segment bank register */
1063 { ORDATA (Q, Q, 16), REG_FIT }, /* stack marker register */
1064 { ORDATA (SM, SM, 16), REG_FIT }, /* stack memory register */
1065 { ORDATA (SR, SR, 3), REG_FIT }, /* stack register counter */
1066 { ORDATA (Z, Z, 16), REG_FIT }, /* stack limit register */
1067 { ORDATA (SBANK, SBANK, 4), REG_FIT }, /* stack segment bank register */
1068 { ORDATA (RA, TR [0], 16), REG_X | REG_FIT }, /* top of stack register */
1069 { ORDATA (RB, TR [1], 16), REG_X | REG_FIT }, /* top of stack - 1 register */
1070 { ORDATA (RC, TR [2], 16), REG_X | REG_FIT }, /* top of stack - 2 register */
1071 { ORDATA (RD, TR [3], 16), REG_X | REG_FIT }, /* top of stack - 3 register */
1072 { ORDATA (X, X, 16), REG_X | REG_FIT }, /* index register */
1073 { ORDATA (STA, STA, 16), REG_T | REG_FIT }, /* status register */
1074 { ORDATA (SWCH, SWCH, 16), REG_X | REG_FIT }, /* switch register */
1075 { ORDATA (CPX1, CPX1, 16), REG_FIT }, /* run-mode interrupt flags */
1076 { ORDATA (CPX2, CPX2, 16), REG_FIT }, /* halt-mode interrupt flags */
1077 { ORDATA (PCLK, PCLK, 16), REG_FIT }, /* process clock register */
1078 { ORDATA (CNTR, CNTR, 6), REG_HRO | REG_FIT }, /* microcode counter */
1079 { ORDATA (MOD, MOD, 16), REG_HRO | REG_FIT }, /* module control register */
1080
1081 { DRDATA (POWER, cpu_power_state, 2), REG_HRO }, /* system power supply state */
1082 { ORDATA (WRU, sim_int_char, 8), REG_HRO }, /* SCP interrupt character */
1083 { ORDATA (BRK, sim_brk_char, 8), REG_HRO }, /* SCP break character */
1084 { ORDATA (DEL, sim_del_char, 8), REG_HRO }, /* SCP delete character */
1085
1086 { NULL }
1087 };
1088
1089
1090 /* Modifier list */
1091
1092 static MTAB cpu_mod [] = {
1093 /* Mask Value Match Value Print String Match String Validation Display Descriptor */
1094 /* ------------ --------------- ------------------- ------------ ----------- ------- ---------- */
1095 { UNIT_MODEL, UNIT_SERIES_II, "Series II", NULL, &set_model, NULL, NULL },
1096 { UNIT_MODEL, UNIT_SERIES_III, "Series III", "III", &set_model, NULL, NULL },
1097
1098 { UNIT_EIS, UNIT_EIS, "EIS", NULL, &set_option, NULL, NULL },
1099 { UNIT_EIS, 0, "no EIS", "NOEIS", NULL, NULL, NULL },
1100
1101 { UNIT_CIS, UNIT_CIS, "CIS", "CIS", &set_option, NULL, NULL },
1102 { UNIT_CIS, 0, "no CIS", "NOCIS", NULL, NULL, NULL },
1103
1104 { UNIT_PFARS, UNIT_PFARS, "auto-restart", "ARS", &set_pfars, NULL, NULL },
1105 { UNIT_PFARS, 0, "no auto-restart", "NOARS", &set_pfars, NULL, NULL },
1106
1107 { UNIT_CALTIME, UNIT_CALTIME, "calibrated timing", "CALTIME", NULL, NULL, NULL },
1108 { UNIT_CALTIME, 0, "realistic timing", "REALTIME", NULL, NULL, NULL },
1109
1110 /* Entry Flags Value Print String Match String Validation Display Descriptor */
1111 /* ------------------- ----------- ------------ ------------ ------------- -------------- ---------- */
1112 { MTAB_XDV, 128 * 1024, NULL, "128K", &set_size, NULL, NULL },
1113 { MTAB_XDV, 256 * 1024, NULL, "256K", &set_size, NULL, NULL },
1114 { MTAB_XDV, 384 * 1024, NULL, "384K", &set_size, NULL, NULL },
1115 { MTAB_XDV, 512 * 1024, NULL, "512K", &set_size, NULL, NULL },
1116 { MTAB_XDV, 768 * 1024, NULL, "768K", &set_size, NULL, NULL },
1117 { MTAB_XDV, 1024 * 1024, NULL, "1024K", &set_size, NULL, NULL },
1118
1119 { MTAB_XDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle, NULL },
1120 { MTAB_XDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL, NULL },
1121
1122 { MTAB_XDV | MTAB_NMO, 0, "DUMP", "DUMPDEV", &set_dump, &show_dump, NULL },
1123 { MTAB_XDV, 1, NULL, "DUMPCTL", &set_dump, NULL, NULL },
1124
1125 { MTAB_XDV | MTAB_NMO, 1, "STOPS", "STOP", &set_stops, &show_stops, NULL },
1126 { MTAB_XDV, 0, NULL, "NOSTOP", &set_stops, NULL, NULL },
1127
1128 { MTAB_XDV | MTAB_NMO, 1, "EXEC", "EXEC", &set_exec, &show_exec, NULL },
1129 { MTAB_XDV, 0, NULL, "NOEXEC", &set_exec, NULL, NULL },
1130
1131 { MTAB_XDV | MTAB_NMO, 0, "SPEED", NULL, NULL, &show_speed, NULL },
1132
1133 { 0 }
1134 };
1135
1136
1137 /* Debugging trace list */
1138
1139 static DEBTAB cpu_deb [] = {
1140 { "INSTR", DEB_INSTR }, /* instructions */
1141 { "DATA", DEB_MDATA }, /* memory data accesses */
1142 { "FETCH", DEB_MFETCH }, /* memory instruction fetches */
1143 { "REG", DEB_REG }, /* register values */
1144 { "OPND", DEB_MOPND }, /* memory operand values */
1145 { "EXEC", DEB_EXEC }, /* instruction execution states */
1146 { "PSERV", DEB_PSERV }, /* process clock service events */
1147 { NULL, 0 }
1148 };
1149
1150 /* Debugging stop list */
1151
1152 static DEBTAB cpu_stop [] = {
1153 { "LOOP", SS_LOOP }, /* stop on an infinite loop */
1154 { "PAUSE", SS_PAUSE }, /* stop on a PAUS instruction */
1155 { "UNDEF", SS_UNDEF }, /* stop on an undefined instruction */
1156 { "UNIMPL", SS_UNIMPL }, /* stop on an unimplemented instruction */
1157 { NULL, 0 }
1158 };
1159
1160
1161 /* Device descriptor */
1162
1163 DEVICE cpu_dev = {
1164 "CPU", /* device name */
1165 cpu_unit, /* unit array */
1166 cpu_reg, /* register array */
1167 cpu_mod, /* modifier array */
1168 1, /* number of units */
1169 8, /* address radix */
1170 PA_WIDTH, /* address width */
1171 1, /* address increment */
1172 8, /* data radix */
1173 16, /* data width */
1174 &mem_examine, /* examine routine */
1175 &mem_deposit, /* deposit routine */
1176 &cpu_reset, /* reset routine */
1177 NULL, /* boot routine */
1178 NULL, /* attach routine */
1179 NULL, /* detach routine */
1180 NULL, /* device information block pointer */
1181 DEV_DEBUG, /* device flags */
1182 0, /* debug control flags */
1183 cpu_deb, /* debug flag name array */
1184 NULL, /* memory size change routine */
1185 NULL /* logical device name */
1186 };
1187
1188
1189
1190 /* CPU global SCP support routines */
1191
1192
1193 /* Execute CPU instructions.
1194
1195 This is the instruction decode routine for the HP 3000. It is called from
1196 the simulator control program to execute instructions in simulated memory,
1197 starting at the simulated program counter. It runs until the status to be
1198 returned is set to a value other than SCPE_OK.
1199
1200 On entry, P points to the instruction to execute, and the "sim_switches"
1201 global contains any command-line switches included with the run command. On
1202 exit, P points at the next instruction to execute (or the current
1203 instruction, in the case of a simulator stop during a PAUS instruction or
1204 after the first of two stack operations).
1205
1206 Execution is divided into four phases.
1207
1208 First, the instruction prelude configures the simulation state to resume
1209 execution. This involves verifying that system power is on and there are no
1210 device conflicts (e.g., two devices with the same device number),
1211 initializing the I/O processor and channels, and setting the RUN switch if no
1212 other front panel switches are pressed. These actions accommodate
1213 reconfiguration of the I/O device settings and program counter while the
1214 simulator was stopped. The prelude also responds to one command-line switch:
1215 if "-B" is specified, the current set of simulation stop conditions is
1216 bypassed for the first instruction executed. This allows, e.g., a PAUS
1217 instruction to be bypassed or an unimplemented instruction trap to be taken.
1218
1219 Second, the microcode abort mechanism is set up. Microcode aborts utilize
1220 the "setjmp/longjmp" mechanism to transfer control out of the instruction
1221 executors without returning through the call stack. This allows an
1222 instruction to be aborted part-way through execution when continuation is
1223 impossible, e.g., due to a memory access violation. It corresponds to direct
1224 microcode jumps out of the execution sequence and to the appropriate trap
1225 handlers.
1226
1227 Third, the instruction execution loop decodes instructions and calls the
1228 individual executors in turn until a condition occurs that prevents further
1229 execution. Examples of such conditions includes execution of a HALT
1230 instruction, a user stop request (CTRL+E) from the simulation console, a
1231 recoverable device error (such as an improperly formatted tape image), a
1232 user-specified breakpoint, and a simulation stop condition (such as execution
1233 of an unimplemented instruction). The execution loop also polls for I/O
1234 events and device interrupts, and runs I/O channel cycles. During
1235 instruction execution, the CIR register contains the currently executing
1236 instruction, the NIR register contains the next instruction to execute, and
1237 the P register points to the memory location two instructions ahead of the
1238 current instruction.
1239
1240 Fourth, the instruction postlude updates the simulation state in preparation
1241 for returning to the SCP command prompt. Devices that maintain an internal
1242 state different from their external state, such as the CPU process clock, are
1243 updated so that their internal and external states are fully consistent.
1244 This ensures that the state visible to the user during the simulation stop is
1245 correct. It also ensures that the program counter points correctly at the
1246 next instruction to execute upon resumption.
1247
1248 If enabled, the simulator is idled when a PAUS instruction has been executed
1249 and no service requests for the multiplexer or selector channels are active.
1250 Execution of a PAUS instruction suspends the fetch-and-execute process until
1251 an interrupt occurs or the simulator is stopped and then resumed with a GO -B
1252 or RUN -B command.
1253
1254 The HP 3000 is a microcoded machine. In hardware, the micromachine is always
1255 executing microinstructions, even when the CPU is "halted." The halt/run
1256 state is simply a flip-flop setting, reflected in bit 15 of the CPX2
1257 register and the RUN light on the front panel, that determines whether the
1258 "halt-mode" or "run-mode" microprogram is currently executing.
1259
1260 In simulation, the "cpu_micro_state" variable indicates the state of the
1261 micromachine, i.e., which section of the microcode it is executing, while
1262 CPX2 bit 15 indicates whether the macromachine is halted or running. The
1263 micromachine may be in one of four states:
1264
1265 - running : the run-mode fetch-and-execute microcode is executing
1266 - paused : the run-mode PAUS instruction microcode is executing
1267 - waiting : the halt-mode cold load or dump microcode is executing
1268 - halted : the halt-mode front panel microcode is executing
1269
1270 Simulation provides a variety of stop conditions that break instruction
1271 execution and return to the SCP prompt with the CPU still in run mode. These
1272 have no analog in hardware; the only way to stop the CPU is to press the HALT
1273 button on the front panel, which shifts the micromachine into halt-mode
1274 microcode execution. When any of these conditions occur, the micromachine
1275 state is set to "halted," but the CPX2 run flag is remains set unless the
1276 stop was caused by execution of a HALT instruction. Resuming execution with
1277 a STEP, CONT, GO, or RUN command proceeds as though the hardware RUN switch
1278 was pressed after a programmed halt. This provides the proper semantics for
1279 seamlessly stopping and restarting instruction execution.
1280
1281 A microcode abort is performed by executing a "longjmp" to the abort handler,
1282 which is outside of and precedes the instruction execution loop. The value
1283 passed to "longjmp" is a 32-bit integer containing the Segment Transfer Table
1284 index of the trap handler in the lower word and an optional parameter in the
1285 upper word. Aborts are invoked by the MICRO_ABORT macro, which takes as its
1286 parameter a trap classification value, e.g.:
1287
1288 MICRO_ABORT (trap_Privilege_Violation);
1289 MICRO_ABORT (trap_Integer_Zero_Divide);
1290
1291 Some aborts require an additional parameter and must be invoked by the
1292 MICRO_ABORTP macro, which takes a trap classification value and a
1293 trap-specific value as parameters. The traps that require additional
1294 parameters are:
1295
1296 MICRO_ABORTP (trap_CST_Violation, segment_number);
1297 MICRO_ABORTP (trap_STT_Violation, segment_number);
1298 MICRO_ABORTP (trap_CS_Absent, label/n/0);
1299 MICRO_ABORTP (trap_DS_Absent, DST_number);
1300 MICRO_ABORTP (trap_Uncallable, label);
1301 MICRO_ABORTP (trap_Trace, label/n/0);
1302 MICRO_ABORTP (trap_User, trap_number);
1303
1304 trap_User is not usually called explicitly via MICRO_ABORTP; rather,
1305 MICRO_ABORT is used with one of the specific user-trap identifiers, e.g.,
1306 trap_Integer_Overflow, trap_Float_Overflow, trap_Decimal_Overflow, etc., that
1307 supplies both the trap classification and the trap parameter value.
1308
1309 In addition, user traps must be enabled by setting the T-bit in the status
1310 word. If the T bit is not set, a user trap sets the O-bit (overflow) in the
1311 status word and resumes execution with the next instruction instead of
1312 invoking the user trap handler.
1313
1314 When an abort occurs, an equivalent PCAL to the appropriate STT entry is set
1315 up. Then execution drops into the instruction loop to execute the first
1316 instruction of the trap handler.
1317
1318 When the instruction loop is exited, the CPU process clock and system clock
1319 registers are updated, the micromachine is halted, and control returns to
1320 SCP. Upon return, P points at the next instruction to execute, i.e., the
1321 instruction that will execute when the instruction loop is reentered.
1322
1323 If the micromachine is paused, then P is reset to point to the PAUS
1324 instruction, which will be reexecuted when the routine is reentered. If it
1325 is running, then P is reset to point to the current instruction if the stop
1326 allows it to be rerun, or at the next instruction.
1327
1328
1329 Implementation notes:
1330
1331 1. While the Microsoft VC++ "setjmp" documentation says, "All variables
1332 (except register variables) accessible to the routine receiving control
1333 contain the values they had when longjmp was called," the ISO C99
1334 standard says, "All accessible objects have values...as of the time the
1335 longjmp function was called, except that the values of objects of
1336 automatic storage duration that are local to the function containing the
1337 invocation of the corresponding setjmp macro that do not have
1338 volatile-qualified type and have been changed between the setjmp
1339 invocation and longjmp call are indeterminate."
1340
1341 Therefore, the "device" and "status" variables are marked volatile to
1342 ensure that they are reloaded after a longjmp caused by a micrcode abort.
1343
1344 2. In hardware, the NEXT microcode order present at the end of each
1345 instruction transfers the NIR content to the CIR, reads the memory word
1346 at P into the NIR, and increments P. However, if an interrupt is
1347 present, then this action is omitted, and a microcode jump is performed
1348 to control store location 3, which then jumps to the microcoded interrupt
1349 handler. In simulation, the CIR/NIR/P update is performed before the
1350 next instruction is executed, rather than after the last instruction
1351 completes, so that interrupts are handled before updating.
1352
1353 In addition, the NEXT action is modified in hardware if the NIR contains
1354 a stack instruction with a non-NOP B stackop. In this case, NEXT
1355 transfers the NIR content to the CIR, reads the memory word at P into the
1356 NIR, but does not increment P. Instead, the R bit of the status register
1357 is set to indicate that a B stackop is pending. When the NEXT at the
1358 completion of the A stackop is executed, the NIR and CIR are untouched,
1359 but P is incremented, and the R bit is cleared. This ensures that if an
1360 interrupt or trap occurs between the stackops, P will point correctly at
1361 the next instruction to be executed.
1362
1363 In simulation, following the hardware would require testing the NIR for a
1364 non-NOP B stackop at every pass through the instruction execution loop.
1365 To avoid this, the NEXT simulation unilaterally increments P, rather than
1366 only when a B stackop is not present, and the stack instruction executor
1367 tests for the B stackop and sets the R bit there. However, by that time,
1368 P has already been incremented, so we decrement it there to return it to
1369 the correct value.
1370
1371 3. The System Halt trap has no handler. Instead, the simulator is halted,
1372 and control returns to the SCP prompt.
1373
1374 4. The trace display for a trap reports the parameter value supplied with
1375 the microcode abort. This is not necessarily the same as the parameter
1376 that is pushed on the stack for the trap handler. As some traps, e.g.,
1377 trap_CST_Violation, can cause a System Halt, the placement of the trace
1378 call is dictated by the desire to report both the original trap and the
1379 System Halt trap, even though the placement results in the display of the
1380 incoming parameter value, rather than the stacked parameter value.
1381
1382 5. The execution trace (DEB_EXEC) match test is performed in two parts to
1383 display the register values both before and after the instruction
1384 execution. Consequently, the enable test is done before the register
1385 trace, and the disable test is done after.
1386
1387 6. The execution test (exec_test) is set FALSE even though execution tracing
1388 is not specified. This is done solely to reassure the compiler that the
1389 value is not clobbered by a longjmp call.
1390
1391 7. The set of debug trace flags is restored in the postlude (and therefore
1392 also saved in the instruction prelude) to ensure that a simulation stop
1393 that occurs while an execution trace is in progress does not exit with
1394 the flags set improperly.
1395
1396 8. The breakpoint test must be executed even when the CPU pauses to permit
1397 string breakpoint delays to expire.
1398 */
1399
sim_instr(void)1400 t_stat sim_instr (void)
1401 {
1402 static const char *const stack_formats [] = { /* stack register display formats, indexed by SR */
1403 BOV_FORMAT " ", /* SR = 0 format */
1404 BOV_FORMAT " A %06o, ", /* SR = 1 format */
1405 BOV_FORMAT " A %06o, B %06o, ", /* SR = 2 format */
1406 BOV_FORMAT " A %06o, B %06o, C %06o, ", /* SR = 3 format */
1407 BOV_FORMAT " A %06o, B %06o, C %06o, D %06o, " /* SR = 4 format */
1408 };
1409
1410 int abortval;
1411 HP_WORD label, parameter;
1412 TRAP_CLASS trap;
1413 t_bool exec_test;
1414 volatile uint32 debug_save;
1415 volatile HP_WORD device;
1416 volatile t_stat status = SCPE_OK;
1417
1418
1419 /* Instruction prelude */
1420
1421 debug_save = cpu_dev.dctrl; /* save the current set of debug flags for later restoration */
1422
1423 if (sim_switches & SWMASK ('B')) /* if a simulation stop bypass was requested */
1424 cpu_stop_flags = SS_BYPASSED; /* then clear the stop flags for the first instruction */
1425 else /* otherwise */
1426 cpu_stop_flags = sim_stops; /* set the stops as indicated */
1427
1428 if (cpu_power_state == power_off) /* if system power is off */
1429 status = STOP_POWER; /* then execution is not possible until restoration */
1430
1431 else if (hp_device_conflict ()) /* otherwise if device assignment is inconsistent */
1432 status = SCPE_STOP; /* then inhibit execution */
1433
1434 else { /* otherwise */
1435 device = iop_initialize (); /* initialize the IOP */
1436 mpx_initialize (); /* and the multiplexer channel */
1437 sel_initialize (); /* and the selector channel */
1438
1439 if ((CPX2 & CPX2_IRQ_SET) == 0) /* if no halt-mode interrupt is present */
1440 CPX2 |= cpx2_RUNSWCH; /* then assume a RUN command via STEP/CONT */
1441 }
1442
1443
1444 /* Microcode abort processor */
1445
1446 abortval = setjmp (cpu_save_env); /* set the microcode abort handler */
1447
1448 if (abortval) { /* if a microcode abort occurred */
1449 trap = TRAP (abortval); /* then get the trap classification */
1450 parameter = PARAM (abortval); /* and the optional parameter */
1451
1452 label = TO_LABEL (LABEL_IRQ, trap); /* form the label from the STT number */
1453
1454 tprintf (cpu_dev, DEB_INSTR, BOV_FORMAT "%s trap%s\n",
1455 PBANK, P - 1 & R_MASK, parameter, trap_name [trap],
1456 (trap == trap_User && !(STA & STATUS_T) ? " (disabled)" : ""));
1457
1458 switch (trap) { /* dispatch on the trap classification */
1459
1460 case trap_None: /* trap_None should never occur */
1461 case trap_System_Halt:
1462 CNTR = SR; /* copy the stack register to the counter */
1463 cpu_flush (); /* and flush the TOS registers to memory */
1464
1465 RA = parameter; /* set RA to the parameter (system halt condition) */
1466
1467 CPX2 = CPX2 & ~cpx2_RUN | cpx2_SYSHALT; /* halt the CPU and set the system halt flag */
1468 status = STOP_SYSHALT; /* and report the system halt condition */
1469
1470 label = 0; /* there is no trap handler for a system halt */
1471 break;
1472
1473
1474 case trap_CST_Violation:
1475 if (STT_SEGMENT (parameter) <= ISR_SEGMENT) /* if the trap occurred in segment 1 */
1476 MICRO_ABORT (trap_SysHalt_CSTV_1); /* then the failure is fatal */
1477
1478 /* fall through into the next trap handler */
1479
1480 case trap_STT_Violation:
1481 if (STT_SEGMENT (parameter) <= ISR_SEGMENT) /* if the trap occurred in segment 1 */
1482 MICRO_ABORT (trap_SysHalt_STTV_1); /* then the failure is fatal */
1483
1484 /* fall through into the next trap handler */
1485
1486 case trap_Unimplemented:
1487 case trap_DST_Violation:
1488 case trap_Stack_Underflow:
1489 case trap_Privilege_Violation:
1490 case trap_Bounds_Violation:
1491 parameter = label; /* the label is the parameter for these traps */
1492
1493 /* fall through into the next trap handler */
1494
1495 case trap_DS_Absent:
1496 cpu_flush (); /* flush the TOS registers to memory */
1497 cpu_mark_stack (); /* and then write a stack marker */
1498
1499 /* fall through into the next trap handler */
1500
1501 case trap_Uncallable:
1502 break; /* set up the trap handler */
1503
1504
1505 case trap_User:
1506 if (STA & STATUS_T) { /* if user traps are enabled */
1507 STA &= ~STATUS_O; /* then clear overflow status */
1508 cpu_flush (); /* and flush the TOS registers to memory */
1509 cpu_mark_stack (); /* and write a stack marker */
1510 } /* and set up the trap handler */
1511
1512 else { /* otherwise in lieu of trapping */
1513 STA |= STATUS_O; /* set overflow status */
1514 label = 0; /* and continue execution with the next instruction */
1515 }
1516 break;
1517
1518
1519 case trap_CS_Absent:
1520 if (CPX1 & cpx1_ICSFLAG) /* if the trap occurred while on the ICS */
1521 MICRO_ABORT (trap_SysHalt_Absent_ICS); /* then the failure is fatal */
1522
1523 else if (STT_SEGMENT (STA) <= ISR_SEGMENT) /* otherwise if the trap occurred in segment 1 */
1524 MICRO_ABORT (trap_SysHalt_Absent_1); /* then the failure is fatal */
1525 break; /* otherwise set up the trap handler */
1526
1527
1528 case trap_Trace:
1529 if (STT_SEGMENT (STA) <= ISR_SEGMENT) /* if the trap occurred in segment 1 */
1530 MICRO_ABORT (trap_SysHalt_Trace_1); /* then the failure is fatal */
1531 break; /* otherwise set up the trap handler */
1532
1533
1534 case trap_Cold_Load: /* this trap executes on the ICS */
1535 status = STOP_CLOAD; /* report that the cold load is complete */
1536
1537 /* fall through into trap_Stack_Overflow */
1538
1539 case trap_Stack_Overflow: /* this trap executes on the ICS */
1540 if (CPX1 & cpx1_ICSFLAG) /* so if the trap occurred while on the ICS */
1541 MICRO_ABORT (trap_SysHalt_Overflow_ICS); /* then the failure is fatal */
1542
1543 cpu_setup_ics_irq (irq_Trap, trap); /* otherwise, set up the ICS */
1544 break; /* and then the trap handler */
1545
1546
1547 case trap_Power_On: /* this trap executes on the ICS */
1548 cpu_setup_ics_irq (irq_Trap, trap); /* so set it up */
1549 cpu_power_state = power_on; /* and return to the power-on state */
1550
1551 if (CPX2 & cpx2_INHPFARS) /* if auto-restart is inhibited */
1552 status = STOP_ARSINH; /* then exit and wait for a manual restart */
1553 break;
1554 } /* all cases are handled */
1555
1556
1557 if (label != 0) { /* if the trap handler is to be called */
1558 STA = STATUS_M; /* then clear the status and enter privileged mode */
1559
1560 SM = SM + 1 & R_MASK; /* increment the stack pointer */
1561 cpu_write_memory (stack, SM, parameter); /* and push the parameter on the stack */
1562
1563 X = CIR; /* save the current instruction for restarting */
1564
1565 cpu_call_procedure (label, 0); /* set up PB, P, PL, and STA to call the procedure */
1566
1567 cpu_base_changed = TRUE; /* one or more base registers have changed */
1568 }
1569
1570 sim_interval = sim_interval - 1; /* count the execution cycle that aborted */
1571 }
1572
1573
1574 /* Instruction loop */
1575
1576 while (status == SCPE_OK) { /* execute until simulator status prevents continuation */
1577
1578 if (sim_interval <= 0) { /* if an event timeout has expired */
1579 status = sim_process_event (); /* then call the event service */
1580
1581 if (status != SCPE_OK) /* if the service failed */
1582 break; /* then abort execution and report the failure */
1583 }
1584
1585 if (sel_request) /* if a selector channel request is pending */
1586 sel_service (1); /* then service it */
1587
1588 if (mpx_request_set) /* if a multiplexer channel request is pending */
1589 mpx_service (1); /* then service it */
1590
1591 if (iop_interrupt_request_set /* if a hardware interrupt request is pending */
1592 && STA & STATUS_I /* and interrupts are enabled */
1593 && CIR != SED_1) /* and not deferred by a SED 1 instruction */
1594 device = iop_poll (); /* then poll to acknowledge the request */
1595
1596 if (cpu_micro_state != halted /* if the micromachine is not halted */
1597 && sim_brk_summ != 0 /* and a breakpoint exists */
1598 && sim_brk_test (TO_PA (PBANK, P - 1 & LA_MASK), /* at the next location */
1599 BP_EXEC)) { /* to be executed */
1600 status = STOP_BRKPNT; /* then stop the simulation */
1601 sim_interval = sim_interval + 1; /* and don't count the cycle */
1602 }
1603
1604 else if (cpu_micro_state == running) /* otherwise if the micromachine is running */
1605 if (CPX1 & CPX1_IRQ_SET /* then if a run-mode interrupt is pending */
1606 && cpu_power_state != power_failing) /* and power is not currently failing */
1607 cpu_run_mode_interrupt (device); /* then service it */
1608
1609 else { /* otherwise execute the next instruction */
1610 if (TRACING (cpu_dev, DEB_EXEC | DEB_REG)) { /* if execution or register tracing is enabled */
1611 if (cpu_dev.dctrl & DEB_EXEC) /* then if tracing execution */
1612 if (STA & STATUS_R) /* then if the right-hand stack op is pending */
1613 exec_test = /* then the execution test succeeds if */
1614 (CIR << STACKOP_A_SHIFT /* the right-hand stack op */
1615 & STACKOP_A_MASK /* matches the test criteria */
1616 & exec_mask) == exec_match; /* for the left-hand stack op value */
1617 else /* otherwise */
1618 exec_test = /* then the execution test succeeds if */
1619 (NIR & exec_mask) == exec_match; /* the next instruction matches the test criteria */
1620 else /* otherwise */
1621 exec_test = FALSE; /* there is no execution test */
1622
1623 if (cpu_dev.dctrl & DEB_EXEC /* if execution tracing is enabled */
1624 && cpu_dev.dctrl != DEB_ALL /* and is currently inactive */
1625 && exec_test) { /* and the matching test succeeds */
1626 debug_save = cpu_dev.dctrl; /* then save the current trace flag set */
1627 cpu_dev.dctrl = DEB_ALL; /* and turn on full tracing */
1628 }
1629
1630 if (cpu_dev.dctrl & DEB_REG) { /* if register tracing is enabled */
1631 hp_trace (&cpu_dev, DEB_REG, /* then output the active TOS registers */
1632 stack_formats [SR],
1633 SBANK, SM, SR, RA, RB, RC, RD);
1634
1635 fprintf (sim_deb, "X %06o, %s\n", /* output the index and status registers */
1636 X, fmt_status (STA));
1637
1638 if (cpu_base_changed) { /* if the base registers have been altered */
1639 hp_trace (&cpu_dev, DEB_REG, /* then output the base register values */
1640 BOV_FORMAT " PB %06o, PL %06o, DL %06o, DB %06o, Q %06o, Z %06o\n",
1641 DBANK, 0, STATUS_CS (STA),
1642 PB, PL, DL, DB, Q, Z);
1643
1644 cpu_base_changed = FALSE; /* clear the base registers changed flag */
1645 }
1646 }
1647
1648 if (cpu_dev.dctrl & DEB_EXEC /* if execution tracing is enabled */
1649 && cpu_dev.dctrl == DEB_ALL /* and is currently active */
1650 && ! exec_test) { /* and the matching test fails */
1651 cpu_dev.dctrl = debug_save; /* then restore the saved debug flag set */
1652 hp_trace (&cpu_dev, DEB_EXEC, /* and add a separator to the trace log */
1653 "*****************\n");
1654 }
1655 }
1656
1657 if (!(STA & STATUS_R)) { /* (NEXT) if the right-hand stack op is not pending */
1658 CIR = NIR; /* then update the current instruction */
1659 cpu_read_memory (fetch, P, &NIR); /* and load the next instruction */
1660 }
1661
1662 P = P + 1 & R_MASK; /* point to the following instruction */
1663
1664 if (TRACING (cpu_dev, DEB_INSTR)) { /* if instruction tracing is enabled */
1665 sim_eval [0] = CIR; /* then save the instruction that will be executed */
1666 sim_eval [1] = NIR; /* and the following word for evaluation */
1667
1668 hp_trace (&cpu_dev, DEB_INSTR, BOV_FORMAT, /* print the address and the instruction opcode */
1669 PBANK, P - 2 & R_MASK, CIR); /* as an octal value */
1670
1671 if (fprint_cpu (sim_deb, sim_eval, 0, SIM_SW_STOP) == SCPE_ARG) /* print the mnemonic; if that fails */
1672 fprint_val (sim_deb, sim_eval [0], cpu_dev.dradix, /* then print the numeric */
1673 cpu_dev.dwidth, PV_RZRO); /* value again */
1674
1675 fputc ('\n', sim_deb); /* end the trace with a newline */
1676 }
1677
1678 status = machine_instruction (); /* execute one machine instruction */
1679
1680 cpu_stop_flags = sim_stops; /* reset the stop flags as indicated */
1681 }
1682
1683 else if (cpu_micro_state == paused) { /* otherwise if the micromachine is paused */
1684 if (CPX1 & CPX1_IRQ_SET) /* then if a run-mode interrupt is pending */
1685 cpu_run_mode_interrupt (device); /* then service it */
1686
1687 else if (sim_idle_enab /* otherwise if idling is enabled */
1688 && ! sel_request && mpx_request_set == 0) /* and there are no channel requests pending */
1689 sim_idle (TMR_PCLK, FALSE); /* then idle the simulator */
1690 }
1691
1692 else if (CPX2 & CPX2_IRQ_SET) /* otherwise if a halt-mode interrupt is pending */
1693 status = halt_mode_interrupt (device); /* then service it */
1694
1695 sim_interval = sim_interval - 1; /* count the execution cycle */
1696 } /* and continue with the instruction loop */
1697
1698
1699 /* Instruction postlude */
1700
1701 cpu_dev.dctrl = debug_save; /* restore the flag set */
1702
1703 cpu_update_pclk (); /* update the process clock */
1704 clk_update_counter (); /* and system clock counters */
1705
1706 if (cpu_micro_state == paused) /* if the micromachine is paused */
1707 P = P - 2 & R_MASK; /* then set P to point to the PAUS instruction */
1708
1709 else if (cpu_micro_state == running) /* otherwise if it is running */
1710 if (status <= STOP_RERUN) /* then if the instruction will be rerun when resumed */
1711 P = P - 2 & R_MASK; /* then set P to point to it */
1712 else /* otherwise */
1713 P = P - 1 & R_MASK; /* set P to point to the next instruction */
1714
1715 cpu_micro_state = halted; /* halt the micromachine */
1716
1717 if (cpu_power_state == power_failing /* if power is failing */
1718 && status == STOP_HALT) /* and we executed a HALT instruction */
1719 cpu_power_state = power_off; /* then power will be off when we return */
1720
1721 if (TRACING (cpu_dev, cpu_dev.dctrl) /* if instruction tracing is enabled */
1722 && status <= SCPE_LAST) /* and the status is valid */
1723 hp_trace (&cpu_dev, cpu_dev.dctrl, /* then output the simulation stop reason */
1724 BOV_FORMAT "simulation stop: %s\n",
1725 PBANK, P, STA,
1726 status >= SCPE_BASE ? sim_error_text (status)
1727 : sim_stop_messages [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 characters exist on the command line */
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)) {
3437 set_model (&cpu_unit [0], UNIT_SERIES_III, /* so establish the initial 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;
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 return status; /* return the validation result */
3768 }
3769
3770
3771 /* Change a CPU option.
3772
3773 This validation routine is called to configure the option set for the current
3774 CPU model. The "new_option" parameter is set to the option desired and will
3775 be one of the unit option flags. The "uptr" parameter points to the CPU unit
3776 and is used to obtain the CPU model. The other parameters are not used.
3777
3778 The routine processes commands of the form:
3779
3780 SET CPU <option>[,<option>...]
3781
3782 The option must be valid for the current CPU model, or the command is
3783 rejected.
3784 */
3785
set_option(UNIT * uptr,int32 new_option,char * cptr,void * desc)3786 static t_stat set_option (UNIT *uptr, int32 new_option, char *cptr, void *desc)
3787 {
3788 const uint32 model = CPU_MODEL (uptr->flags); /* the current CPU model index */
3789
3790 if ((cpu_features [model].opt & new_option) != 0) /* if the option is supported on the current model */
3791 return SCPE_OK; /* then confirm the change */
3792 else /* otherwise */
3793 return SCPE_NOFNC; /* reject the change */
3794 }
3795
3796
3797 /* Change the power-fail auto-restart switch setting.
3798
3799 This validation routine is called to configure the PF/ARS switch that is
3800 located behind the system control panel. If set to the ENBL (enable)
3801 position, the CPU will perform an auto-restart when power is restored after a
3802 failure. In the DSBL (disable) position, the CPU will remain halted after
3803 power restoration; execution may be continued by pressing the RUN button.
3804
3805 In simulation, a SET CPU ARS command enables auto-restart, and SET CPU NOARS
3806 disables auto-restart. The "setting" parameter is set to the UNIT_ARS flag
3807 in the former cast and to zero in the latter case. The other parameters are
3808 not used. The routine reflects the ARS setting in "inhibit auto-restart" bit
3809 of the CPX2 register.
3810 */
3811
set_pfars(UNIT * uptr,int32 setting,char * cptr,void * desc)3812 static t_stat set_pfars (UNIT *uptr, int32 setting, char *cptr, void *desc)
3813 {
3814 if (setting == UNIT_PFARS) /* if the option is ARS */
3815 CPX2 &= ~cpx2_INHPFARS; /* then clear the auto-restart inhibit flag */
3816 else /* otherwise the option is NOARS */
3817 CPX2 |= cpx2_INHPFARS; /* so set the auto-restart inhibit flag */
3818
3819 return SCPE_OK; /* confirm the change */
3820 }
3821
3822
3823 /* Show the CPU simulation stop conditions.
3824
3825 This display routine is called to show the set of CPU stop conditions. The
3826 "st" parameter is the open output stream. The other parameters are not used.
3827
3828 If at least one stop condition is enabled, the routine searches through the
3829 stop table for flag bits that are set in the stop set. For each one it
3830 finds, the routine prints the corresponding stop name.
3831
3832 This routine services an extended modifier entry, so it must add the trailing
3833 newline to the output before returning.
3834 */
3835
show_stops(FILE * st,UNIT * uptr,int32 val,void * desc)3836 static t_stat show_stops (FILE *st, UNIT *uptr, int32 val, void *desc)
3837 {
3838 uint32 stop;
3839 t_bool need_spacer = FALSE;
3840
3841 if (sim_stops == 0) /* if no simulation stops are set */
3842 fputs ("Stops disabled", st); /* then report that all are disabled */
3843
3844 else { /* otherwise at least one stop is valid */
3845 fputs ("Stop=", st); /* so prepare to report the list of conditions */
3846
3847 for (stop = 0; cpu_stop [stop].name != NULL; stop++) /* loop through the set of stops in the table */
3848 if (cpu_stop [stop].mask & sim_stops) { /* if the current stop is enabled */
3849 if (need_spacer) /* then if a spacer is needed */
3850 fputc (';', st); /* then add it first */
3851
3852 fputs (cpu_stop [stop].name, st); /* report the stop name */
3853
3854 need_spacer = TRUE; /* a spacer will be needed next time */
3855 }
3856 }
3857
3858 fputc ('\n', st); /* add the trailing newline */
3859
3860 return SCPE_OK; /* report the success of the display */
3861 }
3862
3863
3864 /* Show the instruction execution trace criteria.
3865
3866 This display routine is called to show the criteria that select instruction
3867 execution tracing. The "st" parameter is the open output stream. The other
3868 parameters are not used.
3869
3870 This routine services an extended modifier entry, so it must add the trailing
3871 newline to the output before returning.
3872 */
3873
show_exec(FILE * st,UNIT * uptr,int32 val,void * desc)3874 static t_stat show_exec (FILE *st, UNIT *uptr, int32 val, void *desc)
3875 {
3876 uint32 radix;
3877
3878 if (exec_mask == 0) /* if the instruction is entirely masked */
3879 fputs ("Execution trace disabled\n", st); /* then report that matching is disabled */
3880
3881 else { /* otherwise */
3882 if (sim_switches & SWMASK ('O')) /* if an octal override is present */
3883 radix = 8; /* then print the value in base 8 */
3884 else if (sim_switches & SWMASK ('D')) /* otherwise if a decimal override is present */
3885 radix = 10; /* then print the value in base 10 */
3886 else if (sim_switches & SWMASK ('H')) /* otherwise if a hex override is present */
3887 radix = 16; /* then print the value in base 16 */
3888 else /* otherwise */
3889 radix = cpu_dev.dradix; /* use the current CPU data radix */
3890
3891 fputs ("Execution trace match = ", st); /* print the label */
3892 fprint_val (st, exec_match, radix, cpu_dev.dwidth, PV_RZRO); /* and the match value */
3893
3894 fputs (", mask = ", st); /* print a separator */
3895 fprint_val (st, exec_mask, radix, cpu_dev.dwidth, PV_RZRO); /* and the mask value */
3896
3897 fputc ('\n', st); /* tie off the line */
3898 }
3899
3900 return SCPE_OK; /* report the success of the display */
3901 }
3902
3903
3904 /* Show the CPU cold dump configuration jumpers.
3905
3906 This display routine is called to show the device number and control byte
3907 that are preset on the rear of the system control panel for the cold dump
3908 process. The "st" parameter is the open output stream. The other parameters
3909 are not used.
3910 */
3911
show_dump(FILE * st,UNIT * uptr,int32 val,void * desc)3912 static t_stat show_dump (FILE *st, UNIT *uptr, int32 val, void *desc)
3913 {
3914 fprintf (st, "Dump device = %u, dump control = %03o\n",
3915 LOWER_BYTE (dump_control), UPPER_BYTE (dump_control));
3916
3917 return SCPE_OK;
3918 }
3919
3920
3921 /* Show the current CPU simulation speed.
3922
3923 This display routine is called to show the current simulation speed. The
3924 "st" parameter is the open output stream. The other parameters are not used.
3925
3926 The CPU speed, expressed as a multiple of the hardware speed, is calculated
3927 by the process clock service routine. It is only representative when the
3928 process clock is calibrated, and the CPU is not executing a PAUS instruction
3929 (which suspends the normal fetch/execute instruction cycle).
3930 */
3931
show_speed(FILE * st,UNIT * uptr,int32 val,void * desc)3932 static t_stat show_speed (FILE *st, UNIT *uptr, int32 val, void *desc)
3933 {
3934 fprintf (st, "Simulation speed = %ux\n", cpu_speed); /* display the current CPU speed */
3935 return SCPE_OK; /* and report success */
3936 }
3937
3938
3939
3940 /* CPU local utility routines */
3941
3942
3943 /* Process a halt-mode interrupt.
3944
3945 This routine is called when one or more of the interrupt request bits are set
3946 in the CPX2 register. These bits represent switch closures on the CPU front
3947 panel or on the optional maintenance display panel. The specific switch
3948 closure is identified, and the corresponding microcode routine is executed.
3949 If multiple bits are set in CPX2, the microcode recognizes them in order from
3950 MSB to LSB.
3951
3952 If the RUN switch is set, a test is made for a System Halt, which inhibits
3953 recognition of the switch. If the System Halt flag is set, the CPU must be
3954 reset before execution may be resumed. Otherwise, the NIR is reloaded in
3955 case P was changed during the simulation stop. If the R-bit (right stack op
3956 pending) flag in the status register is set, but the NIR no longer contains a
3957 stack instruction, R is cleared. If a stack instruction is present, and the
3958 R-bit is set, then the CIR is set, and the following instruction is fetched.
3959 The micromachine state is set to "running", and one event tick is added back
3960 to the accumulator to ensure that a single step won't complete without
3961 executing an instruction.
3962
3963 If the DUMP switch is pressed, an I/O Reset is performed on all devices
3964 except the CPU, which is skipped to preserve the register state. The dump
3965 device number is obtained from the SWCH register and tested to ensure that a
3966 tape is mounted with a write ring and the unit is online. Then the contents
3967 of the CPU registers are written to the reserved memory area starting at
3968 address 1400 octal in bank 0. This is followed by two SIO programs. The
3969 main program at addresses 1430-1437 write 4K-word blocks of memory to the
3970 dump device. The error recovery program at addresses 1422-1427 is invoked
3971 when a write fails. It does a Backspace Record followed by a Write Gap to
3972 skip the bad spot on the tape, and then the write is retried.
3973
3974 The DUMP switch remains set, so after each pass through the main execution
3975 loop to run a channel cycle, this routine is reentered. The "waiting" state
3976 causes the second part of the process to check for device completion. When
3977 it occurs, the expected external interrupt is cleared, and if the dump is
3978 complete, the DUMP switch is reset, the original SIO pointer in the DRT is
3979 restored, and the micromachine is halted. Otherwise, the SIO pointer is
3980 read. If it points at the end of the program, then the operation completed
3981 normally. In this case, the dump address is advanced, and, if all of memory
3982 has been dumped, the SIO pointer is reset to the recovery program, and that
3983 program is changed to finish up with Write File Mark and Rewind/Offline
3984 commands. Otherwise, the pointer is reset to the main program in preparation
3985 for the next 4K write. The SIO program is then restarted.
3986
3987 If SIO pointer failed to complete, the pointer is reset to point at the error
3988 recovery program, and the memory address is unchanged; the same 4K write will
3989 be performed once the recovery program runs. If the recovery program fails,
3990 the dump is terminated at that point with a failure indication.
3991
3992 During the dump operation, the CIR register is continually updated with the
3993 current memory bank number. If the dump runs to completion, CIR will contain
3994 the number of 64K memory banks installed in the machine. A value less than
3995 the installed memory value indicates a dump failure. Except for the CIR, the
3996 machine state is restored, so that another dump may be attempted.
3997
3998 If the LOAD switch is pressed, the cold load process begins by filling memory
3999 with HALT 10 instructions if SWCH register bit 8 is clear. The cold load
4000 device number is obtained from the lower byte of the SWCH register.
4001
4002 The first part of the cold load process clears the TOS and STA registers,
4003 stores the initial channel program in memory, and executes an SIO instruction
4004 to start the channel. Once the device starts, interrupts are enabled, and
4005 the micromachine state is set to "waiting" in preparation for executing the
4006 second part of the cold load process once the channel program ends. The
4007 routine then exits to begin channel execution.
4008
4009 The LOAD switch remains set, so after each pass through the main execution
4010 loop to run a channel cycle, this routine is reentered. The "waiting" state
4011 causes the second part of the process to check for device completion. The
4012 expected external interrupt is cleared, the LOAD switch is cleared, the
4013 micromachine state is set to "running", and the Cold Load trap is taken to
4014 complete the process.
4015
4016
4017 Implementation notes:
4018
4019 1. After processing the RUN switch and returning to the instruction loop, if
4020 no interrupt is present, and the R-bit in the status register is clear,
4021 then CIR will be set from NIR, and NIR will be reloaded. If the R-bit is
4022 set, then CIR and NIR will not be changed, i.e., the NEXT action will be
4023 skipped, so we perform it here. If an interrupt is pending, then the
4024 interrupt will be processed using the old value of the CIR, and the
4025 instruction in the NIR will become the first instruction executed after
4026 the interrupt handler completes.
4027
4028 2. The cold load microcode is shared with the cold dump process. The Series
4029 II dump process saves memory locations DRT + 0 through DRT + 3 in the TOS
4030 registers. The load process uses the same microcode but does not perform
4031 the memory read, so the TOS registers are loaded with the previous
4032 contents of the OPND register, which is effectively a random value. In
4033 simulation, the TOS registers are cleared.
4034
4035 3. The cold load and dump microcode waits forever for an interrupt from the
4036 cold load device. If it doesn't occur, the microcode hangs until a
4037 system reset is performed (it tests CPX1 bit 8 and does a JMP *-1 if the
4038 bit is not set). The simulation follows the microcode behavior.
4039
4040 4. Front panel diagnostics and direct I/O cold loading is not implemented.
4041 */
4042
halt_mode_interrupt(HP_WORD device_number)4043 static t_stat halt_mode_interrupt (HP_WORD device_number)
4044 {
4045 static HP_WORD cold_device, sio_pointer, status, offset, pointer;
4046 static uint32 address;
4047 static t_bool error_recovery;
4048
4049 if (CPX2 & cpx2_RUNSWCH) { /* if the RUN switch is pressed */
4050 if (CPX2 & cpx2_SYSHALT) { /* then if the System Halt flip-flop is set */
4051 CPX2 &= ~CPX2_IRQ_SET; /* then clear all switches */
4052 return STOP_SYSHALT; /* as the CPU cannot run until it is reset */
4053 }
4054
4055 else /* otherwise */
4056 CPX2 = CPX2 & ~cpx2_RUNSWCH | cpx2_RUN; /* clear the switch and set the Run flip-flop */
4057
4058 cpu_read_memory (fetch, P, &NIR); /* load the next instruction to execute */
4059 P = P + 1 & R_MASK; /* and point to the following instruction */
4060
4061 if ((NIR & PAUS_MASK) == PAUS) /* if resuming into a PAUS instruction */
4062 cpu_stop_flags |= SS_PAUSE_RESUMED; /* then defer any interrupt until after PAUS is executed */
4063
4064 if ((NIR & SUBOP_MASK) != 0) /* if the instruction is not a stack instruction */
4065 STA &= ~STATUS_R; /* then clear the R-bit in case it had been set */
4066
4067 else if (STA & STATUS_R) { /* otherwise if a right-hand stack op is pending */
4068 CIR = NIR; /* then set the current instruction */
4069 cpu_read_memory (fetch, P, &NIR); /* and load the next instruction */
4070 }
4071
4072 cpu_micro_state = running; /* start the micromachine */
4073 sim_interval = sim_interval + 1; /* don't count this cycle against a STEP count */
4074
4075 if (cpu_power_state == power_returning) { /* if power is returning after a failure */
4076 if (CPX2 & cpx2_INHPFARS) /* then if auto-restart is inhibited */
4077 CPX2 &= ~cpx2_RUN; /* then clear the Run flip-flop */
4078
4079 MICRO_ABORT (trap_Power_On); /* set up the trap to the power-on routine */
4080 }
4081 }
4082
4083
4084 else if (CPX2 & cpx2_DUMPSWCH) { /* otherwise if the DUMP switch is pressed */
4085 if (cpu_micro_state != waiting) { /* then if the dump is not in progress */
4086 reset_all (IO_RESET); /* then reset all I/O devices */
4087
4088 cold_device = LOWER_BYTE (SWCH) & DEVNO_MASK; /* get the device number from the lower SWCH byte */
4089
4090 status = iop_direct_io (cold_device, ioTIO, 0); /* get the device status */
4091
4092 if ((status & MS_ST_MASK) != MS_ST_READY) { /* if the tape is not ready and unprotected */
4093 CPX2 &= ~cpx2_DUMPSWCH; /* then clear the dump switch */
4094
4095 CIR = 0; /* clear CIR to indicate a failure */
4096 return STOP_CDUMP; /* and terminate the dump */
4097 }
4098
4099 cpu_read_memory (absolute, cold_device * 4, /* get the original DRT pointer */
4100 &sio_pointer);
4101
4102 cpu_write_memory (absolute, 01400, 1); /* set the machine ID to 1 for the Series III */
4103 cpu_write_memory (absolute, 01401, sio_pointer); /* store the original DRT pointer */
4104 cpu_write_memory (absolute, 01402, SM); /* store the stack pointer */
4105 cpu_write_memory (absolute, 01403, 0); /* store zeros for the scratch pad 1 */
4106 cpu_write_memory (absolute, 01404, 0); /* and scratch pad 2 register values */
4107 cpu_write_memory (absolute, 01405, DB); /* store the data base */
4108 cpu_write_memory (absolute, 01406, DBANK << 12 /* store DBANK in 0:4 */
4109 | PBANK << 8 /* and PBANK in 4:4 */
4110 | SBANK); /* and SBANK in 12:4 */
4111 cpu_write_memory (absolute, 01407, Z); /* store the stack limit */
4112 cpu_write_memory (absolute, 01410, DL); /* and the data limit */
4113 cpu_write_memory (absolute, 01411, X); /* and the index register */
4114 cpu_write_memory (absolute, 01412, Q); /* and the frame pointer */
4115 cpu_write_memory (absolute, 01413, CIR); /* and the current instruction */
4116 cpu_write_memory (absolute, 01414, PB); /* and the program base */
4117 cpu_write_memory (absolute, 01415, PL); /* and the program limit */
4118 cpu_write_memory (absolute, 01416, P); /* and the program counter */
4119 cpu_write_memory (absolute, 01417, CPX1); /* store the CPX1 register */
4120 cpu_write_memory (absolute, 01420, STA); /* and the status register */
4121 cpu_write_memory (absolute, 01421, /* store the lower byte of the CPX2 register */
4122 LOWER_WORD (CPX2 << 8 /* in the upper byte of memory */
4123 | MEMSIZE / 65536)); /* and the memory bank count in the lower byte */
4124
4125 cpu_write_memory (absolute, 01422, SIO_CNTL); /* CONTRL 0,BSR */
4126 cpu_write_memory (absolute, 01423, MS_CN_BSR);
4127 cpu_write_memory (absolute, 01424, SIO_CNTL); /* CONTRL 0,GAP */
4128 cpu_write_memory (absolute, 01425, MS_CN_GAP);
4129 cpu_write_memory (absolute, 01426, SIO_JUMP); /* JUMP 001436 */
4130 cpu_write_memory (absolute, 01427, 001436);
4131
4132 cpu_write_memory (absolute, 01430, SIO_SBANK); /* SETBNK 0 */
4133 cpu_write_memory (absolute, 01431, 000000);
4134 cpu_write_memory (absolute, 01432, SIO_CNTL); /* CONTRL 0,<SWCH-upper> */
4135 cpu_write_memory (absolute, 01433, UPPER_BYTE (SWCH));
4136 cpu_write_memory (absolute, 01434, SIO_WRITE); /* WRITE #4096,000000 */
4137 cpu_write_memory (absolute, 01435, 000000);
4138 cpu_write_memory (absolute, 01436, SIO_ENDIN); /* ENDINT */
4139 cpu_write_memory (absolute, 01437, 000000);
4140
4141 address = 0; /* clear the address */
4142 offset = 0; /* and memory offset counters */
4143
4144 CIR = 0; /* clear the memory bank counter */
4145
4146 cpu_write_memory (absolute, cold_device * 4, 01430); /* point the DRT at the cold dump program */
4147 error_recovery = FALSE;
4148
4149 iop_direct_io (cold_device, ioSIO, 0); /* start the device */
4150
4151 if (CPX1 & cpx1_IOTIMER) /* if the device did not respond */
4152 MICRO_ABORT (trap_SysHalt_IO_Timeout); /* then a System Halt occurs */
4153
4154 else { /* otherwise the device has started */
4155 status = STA; /* so save the original status register value */
4156
4157 STA = STATUS_I | STATUS_O; /* enable interrupts and set overflow */
4158 cpu_micro_state = waiting; /* and set the load-in-progress state */
4159 }
4160 }
4161
4162 else if (CPX1 & cpx1_EXTINTR) { /* otherwise if an external interrupt is pending */
4163 CPX1 &= ~cpx1_EXTINTR; /* then clear it */
4164
4165 iop_direct_io (device_number, ioRIN, 0); /* reset the device interrupt */
4166
4167 if (device_number == cold_device) /* if the expected device interrupted */
4168 if (address >= MEMSIZE) { /* then if all of memory has been dumped */
4169 CPX2 &= ~cpx2_DUMPSWCH; /* then reset the DUMP switch */
4170
4171 STA = status; /* restore the original status register value */
4172
4173 cpu_write_memory (absolute, /* restore the */
4174 cold_device * 4, /* original SIO pointer */
4175 sio_pointer); /* to the DRT */
4176
4177 cpu_micro_state = halted; /* clear the dump-in-progress state */
4178 return STOP_CDUMP; /* and report dump completion */
4179 }
4180
4181 else { /* otherwise the dump continues */
4182 cpu_read_memory (absolute, /* read the */
4183 cold_device * 4, /* current SIO pointer address */
4184 &pointer); /* from the DRT */
4185
4186 if (pointer == 01440) { /* if the SIO program completed normally */
4187 cpu_write_memory (absolute, /* then reset the pointer */
4188 cold_device * 4, /* to the start */
4189 001430); /* of the program */
4190
4191 if (error_recovery) /* if this was a successful error recovery */
4192 error_recovery = FALSE; /* then clear the flag and keep the current address */
4193
4194 else { /* otherwise this was a successful write */
4195 address = address + 4096; /* so bump the memory address */
4196 offset = offset + 4096 & LA_MASK; /* and offset to the next 4K block */
4197
4198 cpu_write_memory (absolute, /* store the new write buffer address */
4199 001435, offset);
4200
4201 if (offset == 0) { /* if the offset wrapped around */
4202 CIR = CIR + 1; /* then increment the bank number */
4203 cpu_write_memory (absolute, /* and store it as the SET BANK target */
4204 001431, CIR);
4205
4206 if (address >= MEMSIZE) { /* if all of memory has been dumped */
4207 cpu_write_memory (absolute, 001423, /* then change the error recovery program */
4208 MS_CN_WFM); /* to write a file mark */
4209 cpu_write_memory (absolute, 001425, /* followed by */
4210 MS_CN_RST); /* a rewind/offline request */
4211
4212 cpu_write_memory (absolute, /* point at the recovery program */
4213 cold_device * 4,
4214 001422);
4215 }
4216 }
4217 }
4218 }
4219
4220 else if (error_recovery) { /* otherwise if the recover program failed */
4221 CPX2 &= ~cpx2_DUMPSWCH; /* then reset the DUMP switch */
4222
4223 STA = status; /* restore the original status register value */
4224
4225 cpu_write_memory (absolute, /* restore the */
4226 cold_device * 4, /* original SIO pointer */
4227 sio_pointer); /* to the DRT */
4228
4229 cpu_micro_state = halted; /* clear the dump-in-progress state */
4230 return STOP_CDUMP; /* and report dump failure */
4231 }
4232
4233 else { /* otherwise attempt error recovery */
4234 cpu_write_memory (absolute, /* by setting the SIO pointer */
4235 cold_device * 4, /* to the backspace/write gap */
4236 001422); /* program */
4237
4238 error_recovery = TRUE; /* indicate that recovery is in progress */
4239 }
4240
4241 iop_direct_io (cold_device, ioSIO, 0); /* start the device */
4242 }
4243 } /* otherwise wait for the cold dump device to interrupt */
4244 }
4245
4246 else if (CPX2 & cpx2_LOADSWCH) /* otherwise if the LOAD switch is pressed */
4247 if (cpu_micro_state != waiting) { /* then if the load is not in progress */
4248 reset_all (CPU_IO_RESET); /* then reset the CPU and all I/O devices */
4249
4250 if ((SWCH & 000200) == 0) /* if switch register bit 8 is clear */
4251 mem_fill (0, HALT_10); /* then fill all of memory with HALT 10 instructions */
4252
4253 SBANK = 0; /* set the stack bank to bank 0 */
4254
4255 cold_device = LOWER_BYTE (SWCH) & DEVNO_MASK; /* get the device number from the lower SWCH byte */
4256
4257 if (cold_device < 3) { /* if the device number is between 0 and 2 */
4258 CPX2 &= ~cpx2_LOADSWCH; /* then reset the LOAD switch */
4259 return SCPE_INCOMP; /* and execute a front panel diagnostic */
4260 }
4261
4262 else if (cold_device > 63) { /* otherwise if the device number is > 63 */
4263 CPX2 &= ~cpx2_LOADSWCH; /* then reset the LOAD switch */
4264 return SCPE_INCOMP; /* and execute a direct I/O cold load */
4265 }
4266
4267 else { /* otherwise the device number is in the channel I/O range */
4268 RA = 0; /* set the */
4269 RB = 0; /* TOS registers */
4270 RC = 0; /* to the same */
4271 RD = 0; /* (random) value */
4272
4273 SR = 4; /* mark the TOS registers as valid */
4274 STA = 0; /* and clear the status register */
4275
4276 cpu_write_memory (absolute, 01430, SIO_SBANK); /* SETBNK 0 */
4277 cpu_write_memory (absolute, 01431, 000000);
4278 cpu_write_memory (absolute, 01432, SIO_CNTL); /* CONTRL 0,<SWCH-upper> */
4279 cpu_write_memory (absolute, 01433, UPPER_BYTE (SWCH));
4280 cpu_write_memory (absolute, 01434, SIO_READ); /* READ #16,001400 */
4281 cpu_write_memory (absolute, 01435, 001400);
4282 cpu_write_memory (absolute, 01436, SIO_JUMP); /* JUMP 001400 */
4283 cpu_write_memory (absolute, 01437, 001400);
4284
4285 cpu_write_memory (absolute, cold_device * 4, 01430); /* point the DRT to the cold load program */
4286
4287 iop_direct_io (cold_device, ioSIO, 0); /* start the device */
4288
4289 if (CPX1 & cpx1_IOTIMER) /* if the device did not respond */
4290 MICRO_ABORT (trap_SysHalt_IO_Timeout); /* then a System Halt occurs */
4291
4292 else { /* otherwise the device has started */
4293 STA = STATUS_I | STATUS_O; /* so enable interrupts and set overflow */
4294 cpu_micro_state = waiting; /* and set the load-in-progress state */
4295 }
4296 }
4297 }
4298
4299 else /* otherwise the load is in progress */
4300 if (CPX1 & cpx1_EXTINTR) { /* if an external interrupt is pending */
4301 CPX1 &= ~cpx1_EXTINTR; /* then clear it */
4302
4303 iop_direct_io (device_number, ioRIN, 0); /* reset the device interrupt */
4304
4305 if (device_number == cold_device) { /* if the expected device interrupted */
4306 CPX2 &= ~cpx2_LOADSWCH; /* then reset the LOAD switch */
4307
4308 cpu_micro_state = running; /* clear the load-in-progress state */
4309 MICRO_ABORT (trap_Cold_Load); /* and execute the cold load trap handler */
4310 }
4311 } /* otherwise wait for the cold load device to interrupt */
4312
4313 return SCPE_OK;
4314 }
4315
4316
4317 /* Execute one machine instruction.
4318
4319 This routine executes the CPU instruction present in the CIR. The CPU state
4320 (registers, memory, interrupt status) is modified as necessary, and the
4321 routine return SCPE_OK if the instruction executed successfully. Any other
4322 status indicates that execution should cease, and control should return to
4323 the simulator console. For example, a programmed HALT instruction returns
4324 STOP_HALT status.
4325
4326 Unimplemented instructions are detected by those decoding branches that
4327 result from bit patterns not corresponding to legal instructions or
4328 corresponding to optional instructions not currently enabled. Normally,
4329 execution of an unimplemented instruction would result in an Unimplemented
4330 Instruction trap. However, for debugging purposes, a simulator stop may be
4331 requested instead by returning STOP_UNIMPL status if the SS_UNIMPL simulation
4332 stop flag is set.
4333
4334 This routine implements the main instruction dispatcher, as well as memory
4335 address instructions (subopcodes 04-17). Instructions corresponding to
4336 subopcodes 00-03 are executed by routines in the base instruction set module.
4337
4338
4339 Implementation notes:
4340
4341 1. Each instruction executor begins with a comment listing the instruction
4342 mnemonic and, following in parentheses, the condition code setting, or
4343 "none" if the condition code is not altered, and a list of any traps that
4344 might be generated.
4345
4346 2. Stack preadjusts are simpler if performed explicitly due to overlapping
4347 requirements that reduce the number of static preadjusts to 4 of the 16
4348 entries.
4349
4350 3. The order of operations for each instruction follows the microcode. For
4351 example, the LOAD instruction performs the bounds check on the effective
4352 address and reads the operand before pushing the stack down and storing
4353 it in the RA registrer. Pushing the stack down first and then reading
4354 the value directly into the RA register would leave the stack in a
4355 different state if the memory access caused a Bounds Violation trap.
4356
4357 4. The TBA, MTBA, TBX, and MTBX instructions take longer to execute than the
4358 nominal 2.5 microseconds assumed for the average instruction execution
4359 time. Consequently, the 7905 disc diagnostic fails Step 66 (the retry
4360 counter test) if the DS device is set for REALTIME operation. The
4361 diagnostic uses the MTBA P+0 instruction in a timing loop, which expires
4362 before the disc operations complete.
4363
4364 A workaround for this diagnostic is to decrement sim_interval twice for
4365 these instructions. However, doing so causes the 7970 tape diagnostic to
4366 fail Step 532 (the timing error test) for the opposite reason: a wait
4367 loop of MTBA P+0 instructions causes the tape data transfer service event
4368 time to count down twice as fast, while the multiplexer channel data
4369 transfer polls occur at the usual one per instruction. This could be
4370 remedied by having the channel polls execute twice as many I/O cycles for
4371 these instructions, although the general solution would be to recast
4372 sim_intervals as microseconds and to decrement sim_interval by differing
4373 amounts appropriate for each instruction.
4374 */
4375
machine_instruction(void)4376 static t_stat machine_instruction (void)
4377 {
4378 HP_WORD displacement, opcode, offset, operand, operand_1, operand_2, result;
4379 int32 control, limit;
4380 ACCESS_CLASS class;
4381 BYTE_SELECTOR selector;
4382 t_bool branch;
4383 t_stat status = SCPE_OK;
4384
4385 switch (SUBOP (CIR)) { /* dispatch on bits 0-3 of the instruction */
4386
4387 case 000: /* stack operations */
4388 status = cpu_stack_op (); /* set the status from the instruction executor */
4389 break;
4390
4391
4392 case 001: /* shift, branch, and bit test operations */
4393 status = cpu_shift_branch_bit_op (); /* set the status from the instruction executor */
4394 break;
4395
4396
4397 case 002: /* move, special, firmware, immediate, field, and register operations */
4398 status = cpu_move_spec_fw_imm_field_reg_op (); /* set the status from the instruction executor */
4399 break;
4400
4401
4402 case 003: /* I/O, control, program, immediate, and memory operations */
4403 status = cpu_io_cntl_prog_imm_mem_op (); /* set the status from the instruction executor */
4404 break;
4405
4406
4407 case 004: /* LOAD (CCA; STOV, BNDV) */
4408 cpu_ea (CIR, &class, &offset, NULL); /* get the effective address */
4409 cpu_read_memory (class, offset, &operand); /* and read the operand */
4410
4411 cpu_push (); /* push the operand */
4412 RA = operand; /* onto the stack */
4413
4414 SET_CCA (RA, 0); /* set the condition code */
4415 break;
4416
4417
4418 case 005: /* TBA, MTBA, TBX, MTBX, and STOR */
4419 if (CIR & M_FLAG) { /* STOR (none; STUN, BNDV) */
4420 cpu_ea (CIR, &class, &offset, NULL); /* get the effective address */
4421
4422 PREADJUST_SR (1); /* ensure that at least one TOS register is loaded */
4423
4424 cpu_write_memory (class, offset, RA); /* write the TOS to memory */
4425 cpu_pop (); /* and pop the stack */
4426 }
4427
4428 else { /* TBA, MTBA, TBX, or MTBX */
4429 opcode = CIR & TBR_MASK; /* get the test and branch operation */
4430
4431 if (opcode == TBA || opcode == MTBA) { /* TBA or MTBA (none; STUN, STOV, BNDV) */
4432 PREADJUST_SR (3); /* ensure that at least three TOS registers are loaded */
4433
4434 while (SR > 3) /* if more than three TOS register are loaded */
4435 cpu_queue_down (); /* queue them down until exactly three are left */
4436
4437 offset = DB + RC & LA_MASK; /* get the address of the control value */
4438
4439 if (DL <= offset && offset <= SM || PRIV) /* if the address is within the segment */
4440 cpu_read_memory (data, offset, &operand); /* then read the value */
4441
4442 else /* otherwise */
4443 MICRO_ABORT (trap_Bounds_Violation); /* trap with a bounds violation if not privileged */
4444
4445 if (opcode == MTBA) { /* if the instruction is MTBA */
4446 operand = operand + RB & DV_MASK; /* then add the step size */
4447 cpu_write_memory (data, offset, operand); /* to the control variable */
4448 }
4449
4450 control = SEXT16 (operand); /* sign-extend the control value */
4451 }
4452
4453 else { /* TBX or MTBX (none; STUN, BNDV) */
4454 PREADJUST_SR (2); /* ensure that at least two TOS registers are loaded */
4455
4456 if (opcode == MTBX) /* if the instruction is MTBX */
4457 X = X + RB & R_MASK; /* then add the step size to the control variable */
4458
4459 control = SEXT16 (X); /* sign-extend the control value */
4460 }
4461
4462 limit = SEXT16 (RA); /* sign-extend the limit value */
4463
4464 if (RB & D16_SIGN) /* if the step size is negative */
4465 branch = control >= limit; /* then branch if the value is not below the limit */
4466 else /* otherwise */
4467 branch = control <= limit; /* branch if the value is not above the limit */
4468
4469 if (branch) { /* if the test succeeded */
4470 displacement = CIR & DISPL_255_MASK; /* then get the branch displacement */
4471
4472 if (CIR & DISPL_255_SIGN) /* if the displacement is negative */
4473 offset = P - 2 - displacement & LA_MASK; /* then subtract the displacement from the base */
4474 else /* otherwise */
4475 offset = P - 2 + displacement & LA_MASK; /* add the displacement to the base */
4476
4477 if (cpu_stop_flags & SS_LOOP /* if the infinite loop stop is active */
4478 && displacement == 0 /* and the target is the current instruction */
4479 && (opcode == TBA || opcode == TBX)) /* and the instruction must be checked */
4480 status = STOP_INFLOOP; /* then stop the simulator */
4481 else /* otherwise */
4482 status = SCPE_OK; /* continue */
4483
4484 cpu_read_memory (fetch_checked, offset, &NIR); /* load the next instruction register */
4485 P = offset + 1 & R_MASK; /* and increment the program counter */
4486 }
4487
4488 else { /* otherwise the test failed */
4489 cpu_pop (); /* so pop the limit */
4490 cpu_pop (); /* and the step size from the stack */
4491
4492 if (opcode == TBA || opcode == MTBA) /* if the instruction is TBA or MTBA */
4493 cpu_pop (); /* then pop the variable address too */
4494 } /* and continue execution at P + 1 */
4495 }
4496 break;
4497
4498
4499 case 006: /* CMPM (CCC; STUN) */
4500 cpu_ea (CIR, &class, &offset, NULL); /* get the effective address */
4501 cpu_read_memory (class, offset, &operand); /* and read the operand */
4502
4503 PREADJUST_SR (1); /* ensure that at least one TOS register is loaded */
4504
4505 SET_CCC (RA, 0, operand, 0); /* set the condition code from the TOS value */
4506 cpu_pop (); /* and then pop the value from the stack */
4507 break;
4508
4509
4510 case 007: /* ADDM (CCA, C, O; STUN, BNDV, ARITH) */
4511 cpu_ea (CIR, &class, &offset, NULL); /* get the effective address */
4512 cpu_read_memory (class, offset, &operand); /* and read the operand */
4513
4514 PREADJUST_SR (1); /* ensure that at least one TOS register is loaded */
4515
4516 RA = cpu_add_16 (RA, operand); /* add the operands */
4517 SET_CCA (RA, 0); /* and set the condition code */
4518 break;
4519
4520
4521 case 010: /* SUBM (CCA, C, O; STUN, BNDV, ARITH) */
4522 cpu_ea (CIR, &class, &offset, NULL); /* get the effective address */
4523 cpu_read_memory (class, offset, &operand); /* and read the operand */
4524
4525 PREADJUST_SR (1); /* ensure that at least one TOS register is loaded */
4526
4527 RA = cpu_sub_16 (RA, operand); /* subtract the operands */
4528 SET_CCA (RA, 0); /* and set the condition code */
4529 break;
4530
4531
4532 case 011: /* MPYM (CCA, O; STUN, STOV, BNDV, ARITH) */
4533 cpu_ea (CIR, &class, &offset, NULL); /* get the effective address */
4534 cpu_read_memory (class, offset, &operand); /* and read the operand */
4535
4536 PREADJUST_SR (1); /* ensure that at least one TOS register is loaded */
4537
4538 RA = cpu_mpy_16 (RA, operand); /* multiply the operands */
4539 SET_CCA (RA, 0); /* and set the condition code */
4540 break;
4541
4542
4543 case 012: /* INCM, DECM */
4544 cpu_ea (CIR | M_FLAG, &class, &offset, NULL); /* get the effective address (forced to data-relative) */
4545 cpu_read_memory (class, offset, &operand); /* and read the operand */
4546
4547 if (CIR & M_FLAG) /* DECM (CCA, C, O; BNDV, ARITH) */
4548 result = cpu_sub_16 (operand, 1); /* decrement the operand and set C and O as necessary */
4549 else /* INCM (CCA, C, O; BNDV, ARITH) */
4550 result = cpu_add_16 (operand, 1); /* increment the operand and set C and O as necessary */
4551
4552 cpu_write_memory (class, offset, result); /* write the operand back to memory */
4553 SET_CCA (result, 0); /* and set the condition code */
4554 break;
4555
4556
4557 case 013: /* LDX (CCA; BNDV) */
4558 cpu_ea (CIR, &class, &offset, NULL); /* get the effective address */
4559 cpu_read_memory (class, offset, &X); /* and read the operand into the X register */
4560
4561 SET_CCA (X, 0); /* set the condition code */
4562 break;
4563
4564
4565 case 014: /* BR (none; BNDV), BCC (none; BNDV) */
4566 if ((CIR & BR_MASK) != BCC) { /* if the instruction is BR */
4567 cpu_ea (CIR, &class, &offset, NULL); /* then get the effective address of the branch */
4568
4569 if (cpu_stop_flags & SS_LOOP /* if the infinite loop stop is active */
4570 && offset == (P - 2 & LA_MASK)) /* and the target is the current instruction */
4571 status = STOP_INFLOOP; /* then stop the simulator */
4572 else /* otherwise */
4573 status = SCPE_OK; /* continue */
4574
4575 cpu_read_memory (fetch_checked, offset, &NIR); /* load the next instruction register */
4576 P = offset + 1 & R_MASK; /* and increment the program counter */
4577 }
4578
4579 else if (TO_CCF (STA) & CIR << BCC_CCF_SHIFT) /* otherwise if the BCC test succeeds */
4580 status = cpu_branch_short (TRUE); /* then branch to the target address */
4581 break; /* otherwise continue execution at P + 1 */
4582
4583
4584 case 015: /* LDD (CCA; STOV, BNDV), LDB (CCB; STOV, BNDV) */
4585 if (CIR & M_FLAG) { /* if the instruction is LDD */
4586 cpu_ea (CIR, &class, &offset, NULL); /* then get the effective address of the double-word */
4587
4588 cpu_read_memory (class, offset, &operand_1); /* read the MSW */
4589 cpu_read_memory (class, offset + 1 & LA_MASK, &operand_2); /* and the LSW of the operand */
4590
4591 cpu_push (); /* push the MSW */
4592 cpu_push (); /* and the LSW */
4593 RB = operand_1; /* of the operand */
4594 RA = operand_2; /* onto the stack */
4595
4596 SET_CCA (RB, RA); /* set the condition code */
4597 }
4598
4599 else { /* otherwise the instruction is LDB */
4600 cpu_ea (CIR | M_FLAG, &class, &offset, &selector); /* so get the effective word address of the byte */
4601 cpu_read_memory (class, offset, &operand); /* and read the operand */
4602
4603 cpu_push (); /* push the stack down */
4604
4605 if (selector == upper) /* if the upper byte is selected */
4606 RA = UPPER_BYTE (operand); /* then store it in the TOS */
4607 else /* otherwise */
4608 RA = LOWER_BYTE (operand); /* store the lower byte in the TOS */
4609
4610 SET_CCB (RA); /* set the condition code */
4611 }
4612 break;
4613
4614
4615 case 016: /* STD (none; STUN, BNDV), STB (none; STUN, BNDV) */
4616 if (CIR & M_FLAG) { /* if the instruction is STD */
4617 cpu_ea (CIR, &class, &offset, NULL); /* then get the effective address of the double-word */
4618
4619 PREADJUST_SR (2); /* ensure that at least two TOS registers are loaded */
4620
4621 cpu_write_memory (class, offset + 1 & LA_MASK, RA); /* write the LSW first to follow the microcode */
4622 cpu_write_memory (class, offset, RB); /* and then write the MSW */
4623
4624 cpu_pop (); /* pop the TOS */
4625 cpu_pop (); /* and the NOS */
4626 }
4627
4628 else { /* otherwise the instruction is STB */
4629 cpu_ea (CIR | M_FLAG, &class, &offset, &selector); /* so get the effective word address of the byte */
4630
4631 PREADJUST_SR (1); /* ensure that at least one TOS register is loaded */
4632
4633 cpu_read_memory (class, offset, &operand); /* read the word containing the target byte */
4634
4635 if (selector == upper) /* if the upper byte is targeted */
4636 operand = REPLACE_UPPER (operand, RA); /* then store the TOS into it */
4637 else /* otherwise */
4638 operand = REPLACE_LOWER (operand, RA); /* store the TOS into the lower byte */
4639
4640 cpu_write_memory (class, offset, operand); /* write the word back */
4641 cpu_pop (); /* and pop the TOS */
4642 }
4643 break;
4644
4645
4646 case 017: /* LRA (none; STOV, BNDV) */
4647 cpu_ea (CIR, &class, &offset, NULL); /* get the effective address */
4648
4649 if (class == program_checked) /* if this a program reference */
4650 offset = offset - PB; /* then subtract PB to get the relative address */
4651 else /* otherwise it is a data or stack reference */
4652 offset = offset - DB; /* so subtract DB to get the address */
4653
4654 cpu_push (); /* push the relative address */
4655 RA = offset & R_MASK; /* onto the stack */
4656 break;
4657
4658 } /* all cases are handled */
4659
4660 if (status == STOP_UNIMPL /* if the instruction is unimplemented */
4661 && (cpu_stop_flags & SS_UNIMPL) == 0) /* and the unimplemented instruction stop is inactive */
4662 MICRO_ABORT (trap_Unimplemented); /* then trap to handle it */
4663
4664 return status;
4665 }
4666