1 /* hp2100_cpu.c: HP 21xx CPU simulator
3 Copyright (c) 1993-2008, Robert M. Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
26 CPU 2114C/2115A/2116C/2100A/1000-M/E/F central processing unit
27 MP 12581A/12892B memory protect
28 DMA0,DMA1 12607B/12578A/12895A direct memory access controller
29 DCPC0,DCPC1 12897B dual channel port controller
31 30-Apr-08 JDB Enabled SIGNAL instructions, SIG debug flag
32 24-Apr-08 JDB Fixed single stepping through interrupts
33 20-Apr-08 JDB Enabled EMA and VIS, added EMA, VIS, and SIGNAL debug flags
34 03-Dec-07 JDB Memory ex/dep and bkpt type default to current map mode
35 26-Nov-07 JDB Added SET CPU DEBUG and OS/VMA flags, enabled OS/VMA
36 15-Nov-07 JDB Corrected MP W5 (JSB) jumper action, SET/SHOW reversal,
37 mp_mevff clear on interrupt with I/O instruction in trap cell
38 04-Nov-07 JDB Removed DBI support from 1000-M (was temporary for RTE-6/VM)
39 28-Apr-07 RMS Removed clock initialization
40 02-Mar-07 JDB EDT passes input flag and DMA channel in dat parameter
41 11-Jan-07 JDB Added 12578A DMA byte packing
42 28-Dec-06 JDB CLC 0 now sends CRS instead of CLC to devices
43 26-Dec-06 JDB Fixed improper IRQ deferral for 21xx CPUs
44 Fixed improper interrupt servicing in resolve
45 21-Dec-06 JDB Added 21xx loader enable/disable support
46 16-Dec-06 JDB Added 2114 and 2115 CPU options.
47 Added support for 12607B (2114) and 12578A (2115/6) DMA
48 01-Dec-06 JDB Added 1000-F CPU option (requires HAVE_INT64)
49 SHOW CPU displays 1000-M/E instead of 21MX-M/E
50 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c
51 12-Oct-06 JDB Fixed INDMAX off-by-one error in resolve
52 26-Sep-06 JDB Added iotrap parameter to UIG dispatchers for RTE microcode
53 12-Sep-06 JDB iogrp returns NOTE_IOG to recalc interrupts
54 resolve returns NOTE_INDINT to service held-off interrupt
55 16-Aug-06 JDB Added support for future microcode options, future F-Series
56 09-Aug-06 JDB Added double integer microcode, 1000-M/E synonyms
57 Enhanced CPU option validity checking
58 Added DCPC as a synonym for DMA for 21MX simulations
59 26-Dec-05 JDB Improved reporting in dev_conflict
60 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
61 21-Jan-05 JDB Reorganized CPU option flags
62 15-Jan-05 RMS Split out EAU and MAC instructions
63 26-Dec-04 RMS DMA reset doesn't clear alternate CTL flop (from Dave Bryan)
64 DMA reset shouldn't clear control words (from Dave Bryan)
65 Alternate CTL flop not visible as register (from Dave Bryan)
66 Fixed CBS, SBS, TBS to perform virtual reads
67 Separated A/B from M[0/1] for DMA IO (from Dave Bryan)
68 Fixed bug in JPY (from Dave Bryan)
69 25-Dec-04 JDB Added SET CPU 21MX-M, 21MX-E (21MX defaults to MX-E)
70 TIMER/EXECUTE/DIAG instructions disabled for 21MX-M
71 T-register reflects changes in M-register when halted
72 25-Sep-04 JDB Moved MP into its own device; added MP option jumpers
73 Modified DMA to allow disabling
74 Modified SET CPU 2100/2116 to truncate memory > 32K
75 Added -F switch to SET CPU to force memory truncation
76 Fixed S-register behavior on 2116
77 Fixed LIx/MIx behavior for DMA on 2116 and 2100
78 Fixed LIx/MIx behavior for empty I/O card slots
79 Modified WRU to be REG_HRO
80 Added BRK and DEL to save console settings
81 Fixed use of "unsigned int16" in cpu_reset
82 Modified memory size routine to return SCPE_INCOMP if
83 memory size truncation declined
84 20-Jul-04 RMS Fixed bug in breakpoint test (reported by Dave Bryan)
85 Back up PC on instruction errors (from Dave Bryan)
86 14-May-04 RMS Fixed bugs and added features from Dave Bryan
87 - SBT increments B after store
88 - DMS console map must check dms_enb
89 - SFS x,C and SFC x,C work
90 - MP violation clears automatically on interrupt
91 - SFS/SFC 5 is not gated by protection enabled
92 - DMS enable does not disable mem prot checks
93 - DMS status inconsistent at simulator halt
94 - Examine/deposit are checking wrong addresses
95 - Physical addresses are 20b not 15b
96 - Revised DMS to use memory rather than internal format
97 - Added instruction printout to HALT message
98 - Added M and T internal registers
99 - Added N, S, and U breakpoints
100 Revised IBL facility to conform to microcode
101 Added DMA EDT I/O pseudo-opcode
102 Separated DMA SRQ (service request) from FLG
103 12-Mar-03 RMS Added logical name support
104 02-Feb-03 RMS Fixed last cycle bug in DMA output (found by Mike Gemeny)
105 22-Nov-02 RMS Added 21MX IOP support
106 24-Oct-02 RMS Fixed bugs in IOP and extended instructions
107 Fixed bugs in memory protection and DMS
108 Added clock calibration
109 25-Sep-02 RMS Fixed bug in DMS decode (found by Robert Alan Byer)
110 26-Jul-02 RMS Restructured extended instructions, added IOP support
111 22-Mar-02 RMS Changed to allocate memory array dynamically
112 11-Mar-02 RMS Cleaned up setjmp/auto variable interaction
113 17-Feb-02 RMS Added DMS support
114 Fixed bugs in extended instructions
115 03-Feb-02 RMS Added terminal multiplexor support
116 Changed PCQ macro to use unmodified PC
117 Fixed flop restore logic (found by Bill McDermith)
118 Fixed SZx,SLx,RSS bug (found by Bill McDermith)
119 Added floating point support
120 16-Jan-02 RMS Added additional device support
121 07-Jan-02 RMS Fixed DMA register tables (found by Bill McDermith)
122 07-Dec-01 RMS Revised to use breakpoint package
123 03-Dec-01 RMS Added extended SET/SHOW support
124 10-Aug-01 RMS Removed register in declarations
125 26-Nov-00 RMS Fixed bug in dual device number routine
126 21-Nov-00 RMS Fixed bug in reset routine
127 15-Oct-00 RMS Added dynamic device number support
130 - 2100A Computer Reference Manual (02100-90001, Dec-1971)
131 - Model 2100A Computer Installation and Maintenance Manual
132 (02100-90002, Aug-1972)
133 - HP 1000 M/E/F-Series Computers Technical Reference Handbook
134 (5955-0282, Mar-1980)
135 - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation
136 (92851-90001, Mar-1981)
137 - 12607A Direct Memory Access Operating and Service Manual
138 (12607-90002, Jan-1970)
139 - 12578A/12578A-01 Direct Memory Access Operating and Service Manual
140 (12578-9001, Mar-1972)
141 - 12892B Memory Protect Installation Manual (12892-90007, Jun-1978)
143 The register state for the HP 2116 CPU is:
145 AR<15:0> A register - addressable as location 0
146 BR<15:0> B register - addressable as location 1
147 PC<14:0> P register (program counter)
149 MR<14:0> M register - memory address
150 TR<15:0> T register - memory data
151 E extend flag (carry out)
154 The 2100 adds memory protection logic:
156 mp_fence<14:0> memory fence register
157 mp_viol<15:0> memory protection violation register (F register)
159 The 21MX adds a pair of index registers and memory expansion logic:
163 dms_sr<15:0> dynamic memory system status register
164 dms_vr<15:0> dynamic memory system violation register
166 The original HP 2116 has four instruction formats: memory reference,
167 shift, alter/skip, and I/O. The HP 2100 added extended memory reference
168 and extended arithmetic. The HP21MX added extended byte, bit, and word
169 instructions as well as extended memory.
171 The memory reference format is:
173 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
174 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
175 |in| op |cp| offset | memory reference
176 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
178 <14:11> mnemonic action
180 0010 AND A = A & M[MA]
181 0011 JSB M[MA] = P, P = MA + 1
182 0100 XOR A = A ^ M[MA]
184 0110 IOR A = A | M[MA]
185 0111 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0
186 1000 ADA A = A + M[MA]
187 1001 ADB B = B + M[MA]
188 1010 CPA skip if A != M[MA]
189 1011 CPB skip if B != M[MA]
197 0,0 page zero direct MA = IR<9:0>
198 0,1 current page direct MA = PC<14:0>'IR,9:0>
199 1,0 page zero indirect MA = M[IR<9:0>]
200 1,1 current page indirect MA = M[PC<14:10>'IR<9:0>]
202 Memory reference instructions can access an address space of 32K words.
203 An instruction can directly reference the first 1024 words of memory
204 (called page zero), as well as 1024 words of the current page; it can
205 indirectly access all 32K.
209 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
210 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
211 | 0 0 0 0|ab| 0|s1| op1 |ce|s2|sl| op2 | shift
212 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
213 | | \---+---/ | | | \---+---/
215 | | | | | | +---- shift 2 opcode
216 | | | | | +---------- skip if low bit == 0
217 | | | | +------------- shift 2 enable
218 | | | +---------------- clear Extend
219 | | +---------------------- shift 1 opcode
220 | +---------------------------- shift 1 enable
221 +---------------------------------- A/B select
223 The alter/skip format is:
225 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
226 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
227 | 0 0 0 0|ab| 1|regop| e op|se|ss|sl|in|sz|rs| alter/skip
228 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
229 | \-+-/ \-+-/ | | | | | |
230 | | | | | | | | +- reverse skip sense
231 | | | | | | | +---- skip if register == 0
232 | | | | | | +------- increment register
233 | | | | | +---------- skip if low bit == 0
234 | | | | +------------- skip if sign bit == 0
235 | | | +---------------- skip if Extend == 0
236 | | +--------------------- clr/com/set Extend
237 | +--------------------------- clr/com/set register
238 +---------------------------------- A/B select
240 The I/O transfer format is:
242 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
243 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
244 | 1 0 0 0|ab| 1|hc| opcode | device | I/O transfer
245 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
246 | | \---+---/\-------+-------/
248 | | | +--------- device select
249 | | +---------------------- opcode
250 | +---------------------------- hold/clear flag
251 +---------------------------------- A/B select
253 The IO transfer instruction controls the specified device.
254 Depending on the opcode, the instruction may set or clear
255 the device flag, start or stop I/O, or read or write data.
257 The 2100 added an extended memory reference instruction;
258 the 21MX added extended arithmetic, operate, byte, word,
259 and bit instructions. Note that the HP 21xx is, despite
260 the right-to-left bit numbering, a big endian system.
261 Bits <15:8> are byte 0, and bits <7:0> are byte 1.
264 The extended memory reference format (HP 2100) is:
266 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
267 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
268 | 1| 0 0 0|op| 0| opcode | extended mem ref
269 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
270 |in| operand address |
271 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
273 The extended arithmetic format (HP 2100) is:
275 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
276 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
277 | 1| 0 0 0 0 0|dr| 0 0| opcode |shift count| extended arithmetic
278 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
280 The extended operate format (HP 21MX) is:
282 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
283 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
284 | 1| 0 0 0|op| 0| 1 1 1 1 1| opcode | extended operate
285 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
287 The extended byte and word format (HP 21MX) is:
289 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
290 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
291 | 1| 0 0 0 1 0 1 1 1 1 1 1| opcode | extended byte/word
292 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
293 |in| operand address |
294 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
295 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
296 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
298 The extended bit operate format (HP 21MX) is:
300 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
301 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
302 | 1| 0 0 0 1 0 1 1 1 1 1 1 1| opcode | extended bit operate
303 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
304 |in| operand address |
305 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
306 |in| operand address |
307 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
309 This routine is the instruction decode routine for the HP 2100.
310 It is called from the simulator control program to execute
311 instructions in simulated memory, starting at the simulated PC.
312 It runs until 'reason' is set non-zero.
316 1. Reasons to stop. The simulator can be stopped by:
319 breakpoint encountered
320 infinite indirection loop
321 unimplemented instruction and stop_inst flag set
322 unknown I/O device and stop_dev flag set
323 I/O error in I/O simulator
325 2. Interrupts. I/O devices are modelled as five parallel arrays:
327 device commands as bit array dev_cmd[2][31..0]
328 device flags as bit array dev_flg[2][31..0]
329 device flag buffers as bit array dev_fbf[2][31..0]
330 device controls as bit array dev_ctl[2][31..0]
331 device service requests as bit array dev_srq[3][31..0]
333 The HP 2100 interrupt structure is based on flag, flag buffer,
334 and control. If a device flag is set, the flag buffer is set,
335 the control bit is set, and the device is the highest priority
336 on the interrupt chain, it requests an interrupt. When the
337 interrupt is acknowledged, the flag buffer is cleared, preventing
338 further interrupt requests from that device. The combination of
339 flag and control set blocks interrupts from lower priority devices.
341 Command plays no direct role in interrupts. The command flop
342 tells whether a device is active. It is set by STC and cleared
343 by CLC; it is also cleared when the device flag is set. Simple
344 devices don't need to track command separately from control.
346 Service requests are used to trigger the DMA service logic.
348 3. Non-existent memory. On the HP 2100, reads to non-existent memory
349 return zero, and writes are ignored. In the simulator, the
350 largest possible memory is instantiated and initialized to zero.
351 Thus, only writes need be checked against memory size.
353 On the 21xx machines, doing SET CPU LOADERDISABLE decreases available
354 memory size by 64 words.
356 4. Adding I/O devices. These modules must be modified:
358 hp2100_defs.h add interrupt request definition
359 hp2100_sys.c add sim_devices table entry
361 5. Instruction interruptibility. The simulator is fast enough, compared
362 to the run-time of the longest instructions, for interruptibility not
363 to matter. But the HP diagnostics explicitly test interruptibility in
364 EIS and DMS instructions, and long indirect address chains. Accordingly,
365 the simulator does "just enough" to pass these tests. In particular, if
366 an interrupt is pending but deferred at the beginning of an interruptible
367 instruction, the interrupt is taken at the appropriate point; but there
368 is no testing for new interrupts during execution (that is, the event
369 timer is not called).
371 6. Interrupt deferral. At instruction fetch time, a pending interrupt
372 request will be deferred if the previous instruction was a JMP indirect,
373 JSB indirect, STC, CLC, STF, CLF, or was executing from an interrupt trap
374 cell. In addition, the following instructions will cause deferral on the
375 1000 series: SFS, SFC, JRS, DJP, DJS, SJP, SJS, UJP, and UJS.
377 On the HP 1000, the request is always deferred until after the current
378 instruction completes. On the 21xx, the request is deferred unless the
379 current instruction is an MRG instruction other than JMP or JMP,I or
380 JSB,I. Note that for the 21xx, SFS and SFC are not included in the
384 #include "hp2100_defs.h"
386 #include "hp2100_cpu.h"
388 /* Memory protect constants */
390 #define UNIT_V_MP_JSB (UNIT_V_UF + 0) /* MP jumper W5 */
391 #define UNIT_V_MP_INT (UNIT_V_UF + 1) /* MP jumper W6 */
392 #define UNIT_V_MP_SEL1 (UNIT_V_UF + 2) /* MP jumper W7 */
393 #define UNIT_MP_JSB (1 << UNIT_V_MP_JSB) /* 1 = W5 is out */
394 #define UNIT_MP_INT (1 << UNIT_V_MP_INT) /* 1 = W6 is out */
395 #define UNIT_MP_SEL1 (1 << UNIT_V_MP_SEL1) /* 1 = W7 is out */
397 #define ABORT(val) longjmp (save_env, (val))
402 #define ALL_BKPTS (SWMASK('E')|SWMASK('N')|SWMASK('S')|SWMASK('U'))
403 #define ALL_MAPMODES (SWMASK('S')|SWMASK('U')|SWMASK('P')|SWMASK('Q'))
405 uint16
*M
= NULL
; /* memory */
406 uint32 saved_AR
= 0; /* A register */
407 uint32 saved_BR
= 0; /* B register */
408 uint16 ABREG
[2]; /* during execution */
409 uint32 PC
= 0; /* P register */
410 uint32 SR
= 0; /* S register */
411 uint32 MR
= 0; /* M register */
412 uint32 saved_MR
= 0; /* between executions */
413 uint32 TR
= 0; /* T register */
414 uint32 XR
= 0; /* X register */
415 uint32 YR
= 0; /* Y register */
416 uint32 E
= 0; /* E register */
417 uint32 O
= 0; /* O register */
418 uint32 dev_cmd
[2] = { 0 }; /* device command */
419 uint32 dev_ctl
[2] = { 0 }; /* device control */
420 uint32 dev_flg
[2] = { 0 }; /* device flags */
421 uint32 dev_fbf
[2] = { 0 }; /* device flag bufs */
422 uint32 dev_srq
[2] = { 0 }; /* device svc reqs */
423 struct DMA dmac
[2] = { { 0 }, { 0 } }; /* DMA channels */
424 uint32 ion
= 0; /* interrupt enable */
425 uint32 ion_defer
= 0; /* interrupt defer */
426 uint32 intaddr
= 0; /* interrupt addr */
427 uint32 mp_fence
= 0; /* mem prot fence */
428 uint32 mp_viol
= 0; /* mem prot viol reg */
429 uint32 mp_mevff
= 0; /* mem exp (dms) viol */
430 uint32 mp_evrff
= 1; /* update mp_viol */
431 uint32 err_PC
= 0; /* error PC */
432 uint32 dms_enb
= 0; /* dms enable */
433 uint32 dms_ump
= 0; /* dms user map */
434 uint32 dms_sr
= 0; /* dms status reg */
435 uint32 dms_vr
= 0; /* dms violation reg */
436 uint16 dms_map
[MAP_NUM
* MAP_LNT
] = { 0 }; /* dms maps */
437 uint32 iop_sp
= 0; /* iop stack */
438 uint32 ind_max
= 16; /* iadr nest limit */
439 uint32 stop_inst
= 1; /* stop on ill inst */
440 uint32 stop_dev
= 0; /* stop on ill dev */
441 uint32 fwanxm
= 0; /* first word addr of nx mem */
442 uint16 pcq
[PCQ_SIZE
] = { 0 }; /* PC queue */
443 uint32 pcq_p
= 0; /* PC queue ptr */
444 REG
*pcq_r
= NULL
; /* PC queue reg ptr */
445 jmp_buf save_env
; /* abort handler */
447 /* Table of CPU features by model.
450 - typ: standard features plus typically configured options.
451 - opt: complete list of optional features.
452 - maxmem: maximum configurable memory in 16-bit words.
454 Features in the "typical" list are enabled when the CPU model is selected.
455 If a feature appears in the "typical" list but NOT in the "optional" list,
456 then it is standard equipment and cannot be disabled. If a feature appears
457 in the "optional" list, then it may be enabled or disabled as desired by the
461 struct FEATURE_TABLE
{ /* CPU model feature table: */
462 uint32 typ
; /* - typical features */
463 uint32 opt
; /* - optional features */
464 uint32 maxmem
; /* - maximum memory */
467 static struct FEATURE_TABLE cpu_features
[] = { /* features in UNIT_xxxx order*/
468 { UNIT_DMA
| UNIT_MP
, /* UNIT_2116 */
469 UNIT_PFAIL
| UNIT_DMA
| UNIT_MP
| UNIT_EAU
,
471 { UNIT_DMA
, /* UNIT_2115 */
472 UNIT_PFAIL
| UNIT_DMA
| UNIT_EAU
,
474 { UNIT_DMA
, /* UNIT_2114 */
475 UNIT_PFAIL
| UNIT_DMA
,
478 { UNIT_PFAIL
| UNIT_MP
| UNIT_DMA
| UNIT_EAU
, /* UNIT_2100 */
479 UNIT_DMA
| UNIT_FP
| UNIT_IOP
| UNIT_FFP
,
484 { UNIT_MP
| UNIT_DMA
| UNIT_EAU
| UNIT_FP
| UNIT_DMS
, /* UNIT_1000_M */
485 UNIT_PFAIL
| UNIT_DMA
| UNIT_MP
| UNIT_DMS
|
486 UNIT_IOP
| UNIT_FFP
| UNIT_DS
,
488 { UNIT_MP
| UNIT_DMA
| UNIT_EAU
| UNIT_FP
| UNIT_DMS
, /* UNIT_1000_E */
489 UNIT_PFAIL
| UNIT_DMA
| UNIT_MP
| UNIT_DMS
|
490 UNIT_IOP
| UNIT_FFP
| UNIT_DBI
| UNIT_DS
| UNIT_EMA_VMA
,
492 { UNIT_MP
| UNIT_DMA
| UNIT_EAU
| UNIT_FP
| /* UNIT_1000_F */
493 UNIT_FFP
| UNIT_DBI
| UNIT_DMS
,
494 UNIT_PFAIL
| UNIT_DMA
| UNIT_MP
| UNIT_VIS
|
495 UNIT_IOP
| UNIT_DS
| UNIT_SIGNAL
| UNIT_EMA_VMA
,
499 extern int32 sim_interval
;
500 extern int32 sim_int_char
;
501 extern int32 sim_brk_char
;
502 extern int32 sim_del_char
;
503 extern uint32 sim_brk_types
, sim_brk_dflt
, sim_brk_summ
; /* breakpoint info */
504 extern FILE *sim_log
;
505 extern DEVICE
*sim_devices
[];
506 extern int32 sim_switches
;
507 extern char halt_msg
[];
509 t_stat
Ea (uint32 IR
, uint32
*addr
, uint32 irq
);
510 uint16
ReadIO (uint32 addr
, uint32 map
);
511 uint16
ReadPW (uint32 addr
);
512 uint16
ReadTAB (uint32 addr
);
513 void WriteIO (uint32 addr
, uint32 dat
, uint32 map
);
514 void WritePW (uint32 addr
, uint32 dat
);
515 uint32
dms (uint32 va
, uint32 map
, uint32 prot
);
516 uint32
dms_io (uint32 va
, uint32 map
);
517 uint32
shift (uint32 inval
, uint32 flag
, uint32 oper
);
518 void dma_cycle (uint32 chan
, uint32 map
);
519 uint32
calc_dma (void);
520 uint32
calc_int (void);
521 uint32
calc_defer (void);
522 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
);
523 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
);
524 t_stat
cpu_reset (DEVICE
*dptr
);
525 t_stat
cpu_boot (int32 unitno
, DEVICE
*dptr
);
526 t_stat
mp_reset (DEVICE
*dptr
);
527 t_stat
dma0_reset (DEVICE
*dptr
);
528 t_stat
dma1_reset (DEVICE
*dptr
);
529 t_stat
cpu_set_size (UNIT
*uptr
, int32 new_size
, char *cptr
, void *desc
);
530 t_stat
cpu_set_model (UNIT
*uptr
, int32 new_model
, char *cptr
, void *desc
);
531 t_stat
cpu_show_model (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
532 t_stat
cpu_set_opt (UNIT
*uptr
, int32 option
, char *cptr
, void *desc
);
533 t_stat
cpu_clr_opt (UNIT
*uptr
, int32 option
, char *cptr
, void *desc
);
534 t_stat
cpu_set_ldr (UNIT
*uptr
, int32 enable
, char *cptr
, void *desc
);
535 t_bool
dev_conflict (void);
536 void hp_post_cmd (t_bool from_scp
);
538 extern t_stat
cpu_eau (uint32 IR
, uint32 intrq
);
539 extern t_stat
cpu_uig_0 (uint32 IR
, uint32 intrq
, uint32 iotrap
);
540 extern t_stat
cpu_uig_1 (uint32 IR
, uint32 intrq
, uint32 iotrap
);
541 extern void (*sim_vm_post
) (t_bool from_scp
);
543 /* CPU data structures
545 cpu_dev CPU device descriptor
546 cpu_unit CPU unit descriptor
547 cpu_reg CPU register list
548 cpu_mod CPU modifiers list
549 cpu_deb CPU debug flags
552 UNIT cpu_unit
= { UDATA (NULL
, UNIT_FIX
+ UNIT_BINK
, 0) };
555 { ORDATA (P
, PC
, 15) },
556 { ORDATA (A
, saved_AR
, 16) },
557 { ORDATA (B
, saved_BR
, 16) },
558 { ORDATA (M
, MR
, 15) },
559 { ORDATA (T
, TR
, 16), REG_RO
},
560 { ORDATA (X
, XR
, 16) },
561 { ORDATA (Y
, YR
, 16) },
562 { ORDATA (S
, SR
, 16) },
563 { FLDATA (E
, E
, 0) },
564 { FLDATA (O
, O
, 0) },
565 { FLDATA (ION
, ion
, 0) },
566 { FLDATA (ION_DEFER
, ion_defer
, 0) },
567 { ORDATA (CIR
, intaddr
, 6) },
568 { FLDATA (DMSENB
, dms_enb
, 0) },
569 { FLDATA (DMSCUR
, dms_ump
, VA_N_PAG
) },
570 { ORDATA (DMSSR
, dms_sr
, 16) },
571 { ORDATA (DMSVR
, dms_vr
, 16) },
572 { BRDATA (DMSMAP
, dms_map
, 8, 16, MAP_NUM
* MAP_LNT
) },
573 { ORDATA (IOPSP
, iop_sp
, 16) },
574 { FLDATA (STOP_INST
, stop_inst
, 0) },
575 { FLDATA (STOP_DEV
, stop_dev
, 1) },
576 { DRDATA (INDMAX
, ind_max
, 16), REG_NZ
+ PV_LEFT
},
577 { ORDATA (FWANXM
, fwanxm
, 32), REG_HRO
},
578 { BRDATA (PCQ
, pcq
, 8, 15, PCQ_SIZE
), REG_RO
+REG_CIRC
},
579 { ORDATA (PCQP
, pcq_p
, 6), REG_HRO
},
580 { ORDATA (WRU
, sim_int_char
, 8), REG_HRO
},
581 { ORDATA (BRK
, sim_brk_char
, 8), REG_HRO
},
582 { ORDATA (DEL
, sim_del_char
, 8), REG_HRO
},
583 { ORDATA (HCMD
, dev_cmd
[0], 32), REG_HRO
},
584 { ORDATA (LCMD
, dev_cmd
[1], 32), REG_HRO
},
585 { ORDATA (HCTL
, dev_ctl
[0], 32), REG_HRO
},
586 { ORDATA (LCTL
, dev_ctl
[1], 32), REG_HRO
},
587 { ORDATA (HFLG
, dev_flg
[0], 32), REG_HRO
},
588 { ORDATA (LFLG
, dev_flg
[1], 32), REG_HRO
},
589 { ORDATA (HFBF
, dev_fbf
[0], 32), REG_HRO
},
590 { ORDATA (LFBF
, dev_fbf
[1], 32), REG_HRO
},
591 { ORDATA (HSRQ
, dev_srq
[0], 32), REG_HRO
},
592 { ORDATA (LSRQ
, dev_srq
[1], 32), REG_HRO
},
596 /* CPU modifier table.
598 The 21MX monikers are deprecated in favor of the 1000 designations. See the
599 "HP 1000 Series Naming History" on the back inside cover of the Technical
600 Reference Handbook. */
603 { UNIT_MODEL_MASK
, UNIT_2116
, "", "2116", &cpu_set_model
, &cpu_show_model
, "2116" },
604 { UNIT_MODEL_MASK
, UNIT_2115
, "", "2115", &cpu_set_model
, &cpu_show_model
, "2115" },
605 { UNIT_MODEL_MASK
, UNIT_2114
, "", "2114", &cpu_set_model
, &cpu_show_model
, "2114" },
606 { UNIT_MODEL_MASK
, UNIT_2100
, "", "2100", &cpu_set_model
, &cpu_show_model
, "2100" },
607 { UNIT_MODEL_MASK
, UNIT_1000_E
, "", "1000-E", &cpu_set_model
, &cpu_show_model
, "1000-E" },
608 { UNIT_MODEL_MASK
, UNIT_1000_E
, NULL
, "21MX-E", &cpu_set_model
, &cpu_show_model
, "1000-E" },
609 { UNIT_MODEL_MASK
, UNIT_1000_M
, "", "1000-M", &cpu_set_model
, &cpu_show_model
, "1000-M" },
610 { UNIT_MODEL_MASK
, UNIT_1000_M
, NULL
, "21MX-M", &cpu_set_model
, &cpu_show_model
, "1000-M" },
612 #if defined (HAVE_INT64)
613 { UNIT_MODEL_MASK
, UNIT_1000_F
, "", "1000-F", &cpu_set_model
, &cpu_show_model
, "1000-F" },
616 { MTAB_XTD
| MTAB_VDV
, 1, NULL
, "LOADERENABLE", &cpu_set_ldr
, NULL
, NULL
},
617 { MTAB_XTD
| MTAB_VDV
, 0, NULL
, "LOADERDISABLE", &cpu_set_ldr
, NULL
, NULL
},
619 { UNIT_EAU
, UNIT_EAU
, "EAU", "EAU", &cpu_set_opt
, NULL
, NULL
},
620 { UNIT_EAU
, 0, "no EAU", NULL
, NULL
, NULL
, NULL
},
621 { MTAB_XTD
| MTAB_VDV
, UNIT_EAU
, NULL
, "NOEAU", &cpu_clr_opt
, NULL
, NULL
},
623 { UNIT_FP
, UNIT_FP
, "FP", "FP", &cpu_set_opt
, NULL
, NULL
},
624 { UNIT_FP
, 0, "no FP", NULL
, NULL
, NULL
, NULL
},
625 { MTAB_XTD
| MTAB_VDV
, UNIT_FP
, NULL
, "NOFP", &cpu_clr_opt
, NULL
, NULL
},
627 { UNIT_IOP
, UNIT_IOP
, "IOP", "IOP", &cpu_set_opt
, NULL
, NULL
},
628 { UNIT_IOP
, 0, "no IOP", NULL
, NULL
, NULL
, NULL
},
629 { MTAB_XTD
| MTAB_VDV
, UNIT_IOP
, NULL
, "NOIOP", &cpu_clr_opt
, NULL
, NULL
},
631 { UNIT_DMS
, UNIT_DMS
, "DMS", "DMS", &cpu_set_opt
, NULL
, NULL
},
632 { UNIT_DMS
, 0, "no DMS", NULL
, NULL
, NULL
, NULL
},
633 { MTAB_XTD
| MTAB_VDV
, UNIT_DMS
, NULL
, "NODMS", &cpu_clr_opt
, NULL
, NULL
},
635 { UNIT_FFP
, UNIT_FFP
, "FFP", "FFP", &cpu_set_opt
, NULL
, NULL
},
636 { UNIT_FFP
, 0, "no FFP", NULL
, NULL
, NULL
, NULL
},
637 { MTAB_XTD
| MTAB_VDV
, UNIT_FFP
, NULL
, "NOFFP", &cpu_clr_opt
, NULL
, NULL
},
639 { UNIT_DBI
, UNIT_DBI
, "DBI", "DBI", &cpu_set_opt
, NULL
, NULL
},
640 { UNIT_DBI
, 0, "no DBI", NULL
, NULL
, NULL
, NULL
},
641 { MTAB_XTD
| MTAB_VDV
, UNIT_DBI
, NULL
, "NODBI", &cpu_clr_opt
, NULL
, NULL
},
643 { UNIT_EMA_VMA
, UNIT_EMA
, "EMA", "EMA", &cpu_set_opt
, NULL
, NULL
},
644 { MTAB_XTD
| MTAB_VDV
, UNIT_EMA
, NULL
, "NOEMA", &cpu_clr_opt
, NULL
, NULL
},
646 { UNIT_EMA_VMA
, UNIT_VMAOS
, "VMA", "VMA", &cpu_set_opt
, NULL
, NULL
},
647 { MTAB_XTD
| MTAB_VDV
, UNIT_VMAOS
, NULL
, "NOVMA", &cpu_clr_opt
, NULL
, NULL
},
649 { UNIT_EMA_VMA
, 0, "no EMA/VMA", NULL
, &cpu_set_opt
, NULL
, NULL
},
651 #if defined (HAVE_INT64)
652 { UNIT_VIS
, UNIT_VIS
, "VIS", "VIS", &cpu_set_opt
, NULL
, NULL
},
653 { UNIT_VIS
, 0, "no VIS", NULL
, NULL
, NULL
, NULL
},
654 { MTAB_XTD
| MTAB_VDV
, UNIT_VIS
, NULL
, "NOVIS", &cpu_clr_opt
, NULL
, NULL
},
656 { UNIT_SIGNAL
, UNIT_SIGNAL
,"SIGNAL", "SIGNAL", &cpu_set_opt
, NULL
, NULL
},
657 { UNIT_SIGNAL
, 0, "no SIGNAL", NULL
, NULL
, NULL
, NULL
},
658 { MTAB_XTD
| MTAB_VDV
, UNIT_SIGNAL
, NULL
, "NOSIGNAL", &cpu_clr_opt
, NULL
, NULL
},
661 /* Future microcode support.
662 { UNIT_DS, UNIT_DS, "DS", "DS", &cpu_set_opt, NULL, NULL },
663 { UNIT_DS, 0, "no DS", NULL, NULL, NULL, NULL },
664 { MTAB_XTD | MTAB_VDV, UNIT_DS, NULL, "NODS", &cpu_clr_opt, NULL, NULL },
667 { MTAB_XTD
| MTAB_VDV
, 4096, NULL
, "4K", &cpu_set_size
, NULL
, NULL
},
668 { MTAB_XTD
| MTAB_VDV
, 8192, NULL
, "8K", &cpu_set_size
, NULL
, NULL
},
669 { MTAB_XTD
| MTAB_VDV
, 12288, NULL
, "12K", &cpu_set_size
, NULL
, NULL
},
670 { MTAB_XTD
| MTAB_VDV
, 16384, NULL
, "16K", &cpu_set_size
, NULL
, NULL
},
671 { MTAB_XTD
| MTAB_VDV
, 24576, NULL
, "24K", &cpu_set_size
, NULL
, NULL
},
672 { MTAB_XTD
| MTAB_VDV
, 32768, NULL
, "32K", &cpu_set_size
, NULL
, NULL
},
673 { MTAB_XTD
| MTAB_VDV
, 65536, NULL
, "64K", &cpu_set_size
, NULL
, NULL
},
674 { MTAB_XTD
| MTAB_VDV
, 131072, NULL
, "128K", &cpu_set_size
, NULL
, NULL
},
675 { MTAB_XTD
| MTAB_VDV
, 262144, NULL
, "256K", &cpu_set_size
, NULL
, NULL
},
676 { MTAB_XTD
| MTAB_VDV
, 524288, NULL
, "512K", &cpu_set_size
, NULL
, NULL
},
677 { MTAB_XTD
| MTAB_VDV
, 1048576, NULL
, "1024K", &cpu_set_size
, NULL
, NULL
},
683 { "OSTBG", DEB_OSTBG
},
692 "CPU", &cpu_unit
, cpu_reg
, cpu_mod
,
693 1, 8, PA_N_SIZE
, 1, 8, 16,
694 &cpu_ex
, &cpu_dep
, &cpu_reset
,
695 &cpu_boot
, NULL
, NULL
,
697 0, cpu_deb
, NULL
, NULL
700 /* Memory protect data structures
702 mp_dev MP device descriptor
703 mp_unit MP unit descriptor
704 mp_reg MP register list
705 mp_mod MP modifiers list
708 UNIT mp_unit
= { UDATA (NULL
, UNIT_MP_SEL1
, 0) }; /* default is JSB in, INT in, SEL1 out */
711 { FLDATA (CTL
, dev_ctl
[PRO
/32], INT_V (PRO
)) },
712 { FLDATA (FLG
, dev_flg
[PRO
/32], INT_V (PRO
)) },
713 { FLDATA (FBF
, dev_fbf
[PRO
/32], INT_V (PRO
)) },
714 { ORDATA (FR
, mp_fence
, 15) },
715 { ORDATA (VR
, mp_viol
, 16) },
716 { FLDATA (MEV
, mp_mevff
, 0) },
717 { FLDATA (EVR
, mp_evrff
, 0) },
722 { UNIT_MP_JSB
, UNIT_MP_JSB
, "JSB (W5) out", "JSBOUT", NULL
},
723 { UNIT_MP_JSB
, 0, "JSB (W5) in", "JSBIN", NULL
},
724 { UNIT_MP_INT
, UNIT_MP_INT
, "INT (W6) out", "INTOUT", NULL
},
725 { UNIT_MP_INT
, 0, "INT (W6) in", "INTIN", NULL
},
726 { UNIT_MP_SEL1
, UNIT_MP_SEL1
, "SEL1 (W7) out", "SEL1OUT", NULL
},
727 { UNIT_MP_SEL1
, 0, "SEL1 (W7) in", "SEL1IN", NULL
},
732 "MP", &mp_unit
, mp_reg
, mp_mod
,
734 NULL
, NULL
, &mp_reset
,
736 NULL
, DEV_DISABLE
| DEV_DIS
739 /* DMA controller data structures
741 dmax_dev DMAx device descriptor
742 dmax_reg DMAx register list
745 UNIT dma0_unit
= { UDATA (NULL
, 0, 0) };
748 { FLDATA (CMD
, dev_cmd
[DMA0
/32], INT_V (DMA0
)) },
749 { FLDATA (CTL
, dev_ctl
[DMA0
/32], INT_V (DMA0
)) },
750 { FLDATA (FLG
, dev_flg
[DMA0
/32], INT_V (DMA0
)) },
751 { FLDATA (FBF
, dev_fbf
[DMA0
/32], INT_V (DMA0
)) },
752 { FLDATA (CTLALT
, dev_ctl
[DMALT0
/32], INT_V (DMALT0
)) },
753 { ORDATA (CW1
, dmac
[0].cw1
, 16) },
754 { ORDATA (CW2
, dmac
[0].cw2
, 16) },
755 { ORDATA (CW3
, dmac
[0].cw3
, 16) },
756 { DRDATA (LATENCY
, dmac
[0].latency
, 8) },
757 { FLDATA (BYTE
, dmac
[0].packer
, 31) },
758 { ORDATA (PACKER
, dmac
[0].packer
, 8) },
763 "DMA0", &dma0_unit
, dma0_reg
, NULL
,
765 NULL
, NULL
, &dma0_reset
,
770 UNIT dma1_unit
= { UDATA (NULL
, 0, 0) };
773 { FLDATA (CMD
, dev_cmd
[DMA1
/32], INT_V (DMA1
)) },
774 { FLDATA (CTL
, dev_ctl
[DMA1
/32], INT_V (DMA1
)) },
775 { FLDATA (FLG
, dev_flg
[DMA1
/32], INT_V (DMA1
)) },
776 { FLDATA (FBF
, dev_fbf
[DMA1
/32], INT_V (DMA1
)) },
777 { FLDATA (CTLALT
, dev_ctl
[DMALT1
/32], INT_V (DMALT1
)) },
778 { ORDATA (CW1
, dmac
[1].cw1
, 16) },
779 { ORDATA (CW2
, dmac
[1].cw2
, 16) },
780 { ORDATA (CW3
, dmac
[1].cw3
, 16) },
781 { DRDATA (LATENCY
, dmac
[1].latency
, 8) },
782 { FLDATA (BYTE
, dmac
[1].packer
, 31) },
783 { ORDATA (PACKER
, dmac
[1].packer
, 8) },
788 "DMA1", &dma1_unit
, dma1_reg
, NULL
,
790 NULL
, NULL
, &dma1_reset
,
795 /* Interrupt defer table (1000 version) */
797 static int32 defer_tab
[] = { 0, 1, 1, 1, 0, 0, 0, 1 };
799 /* Device dispatch table */
801 uint32
devdisp (uint32 devno
, uint32 inst
, uint32 IR
, uint32 outdat
);
802 int32
cpuio (int32 op
, int32 IR
, int32 outdat
);
803 int32
ovfio (int32 op
, int32 IR
, int32 outdat
);
804 int32
pwrio (int32 op
, int32 IR
, int32 outdat
);
805 int32
proio (int32 op
, int32 IR
, int32 outdat
);
806 int32
dmsio (int32 op
, int32 IR
, int32 outdat
);
807 int32
dmpio (int32 op
, int32 IR
, int32 outdat
);
808 int32
nulio (int32 op
, int32 IR
, int32 outdat
);
810 int32 (*dtab
[64])() = {
811 &cpuio
, &ovfio
, &dmsio
, &dmsio
, &pwrio
, &proio
, &dmpio
, &dmpio
,
812 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
813 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
814 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
815 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
816 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
817 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
818 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
821 t_stat
sim_instr (void)
823 uint32 intrq
, dmarq
; /* set after setjmp */
824 uint32 iotrap
= 0; /* set after setjmp */
825 t_stat reason
; /* set after setjmp */
826 int32 i
, dev
; /* temp */
827 DEVICE
*dptr
; /* temp */
828 DIB
*dibp
; /* temp */
831 /* Restore register state */
833 if (dev_conflict ()) return SCPE_STOP
; /* check consistency */
834 AR
= saved_AR
& DMASK
; /* restore reg */
835 BR
= saved_BR
& DMASK
;
836 err_PC
= PC
= PC
& VAMASK
; /* load local PC */
839 /* Restore I/O state */
841 if (mp_dev
.flags
& DEV_DIS
) dtab
[PRO
] = NULL
;
842 else dtab
[PRO
] = &proio
; /* set up MP dispatch */
843 if (dma0_dev
.flags
& DEV_DIS
) dtab
[DMA0
] = dtab
[DMALT0
] = NULL
;
845 dtab
[DMA0
] = &dmpio
; /* set up DMA0 dispatch */
846 dtab
[DMALT0
] = &dmsio
;
848 if (dma1_dev
.flags
& DEV_DIS
) dtab
[DMA1
] = dtab
[DMALT1
] = NULL
;
850 dtab
[DMA1
] = &dmpio
; /* set up DMA1 dispatch */
851 dtab
[DMALT1
] = &dmsio
;
854 for (i
= VARDEV
; i
<= I_DEVMASK
; i
++) dtab
[i
] = NULL
; /* clr disp table */
855 dev_cmd
[0] = dev_cmd
[0] & M_FXDEV
; /* clear dynamic info */
856 dev_ctl
[0] = dev_ctl
[0] & M_FXDEV
;
857 dev_flg
[0] = dev_flg
[0] & M_FXDEV
;
858 dev_fbf
[0] = dev_fbf
[0] & M_FXDEV
;
859 dev_srq
[0] = dev_srq
[1] = 0; /* init svc requests */
860 dev_cmd
[1] = dev_ctl
[1] = dev_flg
[1] = dev_fbf
[1] = 0;
861 for (i
= 0; dptr
= sim_devices
[i
]; i
++) { /* loop thru dev */
862 dibp
= (DIB
*) dptr
->ctxt
; /* get DIB */
863 if (dibp
&& !(dptr
->flags
& DEV_DIS
)) { /* exist, enabled? */
864 dev
= dibp
->devno
; /* get dev # */
865 if (dibp
->cmd
) { setCMD (dev
); } /* restore cmd */
866 if (dibp
->ctl
) { setCTL (dev
); } /* restore ctl */
867 if (dibp
->flg
) { setFLG (dev
); } /* restore flg */
868 clrFBF (dev
); /* also sets fbf */
869 if (dibp
->fbf
) { setFBF (dev
); } /* restore fbf */
870 if (dibp
->srq
) { setSRQ (dev
); } /* restore srq */
871 dtab
[dev
] = dibp
->iot
; /* set I/O dispatch */
875 /* Configure interrupt deferral table */
877 if (UNIT_CPU_FAMILY
== UNIT_FAMILY_21XX
) /* 21xx series? */
878 defer_tab
[ioSFC
] = defer_tab
[ioSFS
] = 0; /* SFC/S doesn't defer */
879 else /* 1000 series */
880 defer_tab
[ioSFC
] = defer_tab
[ioSFS
] = 1; /* SFC/S does defer */
884 If an abort occurs in memory protection, the relocation routine
885 executes a longjmp to this area OUTSIDE the main simulation loop.
886 Memory protection errors are the only sources of aborts in the
887 HP 2100. All referenced variables must be globals, and all sim_instr
888 scoped automatics must be set after the setjmp.
891 abortval
= setjmp (save_env
); /* set abort hdlr */
892 if (abortval
!= 0) { /* mem mgt abort? */
893 setFLG (PRO
); /* req interrupt */
894 mp_evrff
= 0; /* block mp_viol upd */
896 dmarq
= calc_dma (); /* recalc DMA masks */
897 intrq
= calc_int (); /* recalc interrupts */
899 /* Main instruction fetch/decode loop */
901 while (reason
== 0) { /* loop until halted */
902 uint32 IR
, MA
, absel
, v1
, t
, skip
;
904 if (sim_interval
<= 0) { /* check clock queue */
905 if (reason
= sim_process_event ()) break;
906 dmarq
= calc_dma (); /* recalc DMA reqs */
907 intrq
= calc_int (); /* recalc interrupts */
911 if (dmarq
& DMAR0
) dma_cycle (0, PAMAP
); /* DMA1 cycle? */
912 if (dmarq
& DMAR1
) dma_cycle (1, PBMAP
); /* DMA2 cycle? */
913 dmarq
= calc_dma (); /* recalc DMA reqs */
914 intrq
= calc_int (); /* recalc interrupts */
917 if (intrq
&& ion_defer
) /* interrupt pending but deferred? */
918 ion_defer
= calc_defer (); /* confirm deferral */
921 Unlike most other I/O devices, the MP flag flip-flop is cleared
922 automatically when the interrupt is acknowledged and not by a programmed
923 instruction (CLF and STF affect the parity error enable FF instead).
924 Section 4.4.3 "Memory Protect and I/O Interrupt Generation" of the "HP 1000
925 M/E/F-Series Computers Engineering and Reference Documentation" (HP
928 "When IAK occurs and IRQ5 is asserted, the FLAGBFF is cleared, FLAGFF
929 clocked off at next T2, and IRQ5 will no longer occur."
932 if (intrq
&& ((intrq
<= PRO
) || !ion_defer
)) { /* interrupt request? */
933 iotrap
= 1; /* I/O trap cell instr */
934 clrFBF (intrq
); /* clear flag buffer */
935 if (intrq
== PRO
) clrFLG (PRO
); /* MP flag follows fbuf */
936 intaddr
= intrq
; /* save int addr */
937 if (dms_enb
) dms_sr
= dms_sr
| MST_ENBI
; /* dms enabled? */
938 else dms_sr
= dms_sr
& ~MST_ENBI
;
939 if (dms_ump
) { /* user map? */
940 dms_sr
= dms_sr
| MST_UMPI
;
941 dms_ump
= SMAP
; /* switch to system */
943 else dms_sr
= dms_sr
& ~MST_UMPI
;
944 IR
= ReadW (intrq
); /* get dispatch instr */
945 ion_defer
= 1; /* defer interrupts */
946 intrq
= 0; /* clear request */
947 if (((IR
& I_NMRMASK
) != I_IO
) || /* if not I/O or */
948 (I_GETIOOP (IR
) == ioHLT
)) /* if halt, */
949 clrCTL (PRO
); /* protection off */
950 else /* I/O instr leaves MP on */
951 mp_mevff
= 0; /* but clears MEV flip-flop */
954 else { /* normal instruction */
956 err_PC
= PC
; /* save PC for error */
957 if (sim_brk_summ
&& /* any breakpoints? */
958 sim_brk_test (PC
, SWMASK ('E') | /* unconditional or */
959 (dms_enb
? (dms_ump
? SWMASK ('U'): SWMASK ('S')):
960 SWMASK ('N')))) { /* or right type for DMS? */
961 reason
= STOP_IBKPT
; /* stop simulation */
964 if (mp_evrff
) mp_viol
= PC
; /* if ok, upd mp_viol */
965 IR
= ReadW (PC
); /* fetch instr */
966 PC
= (PC
+ 1) & VAMASK
;
970 sim_interval
= sim_interval
- 1; /* count instruction */
972 /* Instruction decode. The 21MX does a 256-way decode on IR<15:8>
974 15 14 13 12 11 10 09 08 instruction
976 x <-!= 0-> x x x x memory reference
977 0 0 0 0 x 0 x x shift
978 0 0 0 0 x 0 x x alter-skip
980 1 0 0 0 0 0 x 0 extended arithmetic
981 1 0 0 0 0 0 0 1 divide (decoded as 100400)
982 1 0 0 0 1 0 0 0 double load (decoded as 104000)
983 1 0 0 0 1 0 0 1 double store (decoded as 104400)
984 1 0 0 0 1 0 1 0 extended instr group 0 (A/B must be set)
985 1 0 0 0 x 0 1 1 extended instr group 1 (A/B ignored) */
987 absel
= (IR
& I_AB
)? 1: 0; /* get A/B select */
988 switch ((IR
>> 8) & 0377) { /* decode IR<15:8> */
990 /* Memory reference instructions */
992 case 0020:case 0021:case 0022:case 0023:
993 case 0024:case 0025:case 0026:case 0027:
994 case 0220:case 0221:case 0222:case 0223:
995 case 0224:case 0225:case 0226:case 0227:
996 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* AND */
997 AR
= AR
& ReadW (MA
);
1000 /* JSB is a little tricky. It is possible to generate both an MP and a DM
1001 violation simultaneously. Consider a JSB to a location under the MP fence
1002 and on a write-protected page. This situation must be reported as a DM
1003 violation, because it has priority (SFS 5 and SFC 5 check only the MEVFF,
1004 which sets independently of the MP fence violation).
1006 Under simulation, this means that DM violations must be checked, and the
1007 MEVFF must be set, before an MP abort is taken. This is done for JSB by the
1008 WriteW call to store the return PC. However, WriteW only checks for fence
1009 violations above location 2, as normally JSBs to locations 0 and 1 (i.e., the
1010 A and B register) are allowed. However, if the W5 (JSB) jumper is out, then
1011 JSB 0 and JSB 1 are MP violations as well and must be caught. We do this
1012 with an explicit check before calling WriteW.
1014 This would seem to violate the above requirement for DM checks before MP
1015 checks. However, a DM abort cannot occur on a write to 0/1, even if logical
1016 page 0 is write-protected, because writes to 0/1 do not attempt to access
1017 memory; they are intercepted and affect the A/B registers instead (micro-
1018 order TAB is used in the Store field), so no MEV signal is generated.
1021 case 0230:case 0231:case 0232:case 0233:
1022 case 0234:case 0235:case 0236:case 0237:
1023 ion_defer
= 1; /* defer if JSB,I */
1025 case 0030:case 0031:case 0032:case 0033:
1026 case 0034:case 0035:case 0036:case 0037:
1027 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* JSB */
1029 if ((mp_unit
.flags
& UNIT_MP_JSB
) && /* if W5 (JSB) out */
1030 CTL (PRO
) && (MA
<= 1)) /* and MP on and JSB 0 or JSB 1 */
1031 ABORT (ABORT_PRO
); /* MP violation */
1033 WriteW (MA
, PC
); /* store PC */
1035 PC
= (MA
+ 1) & VAMASK
; /* jump */
1038 case 0040:case 0041:case 0042:case 0043:
1039 case 0044:case 0045:case 0046:case 0047:
1040 case 0240:case 0241:case 0242:case 0243:
1041 case 0244:case 0245:case 0246:case 0247:
1042 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* XOR */
1043 AR
= AR
^ ReadW (MA
);
1046 case 0250:case 0251:case 0252:case 0253:
1047 case 0254:case 0255:case 0256:case 0257:
1048 ion_defer
= 1; /* defer if JMP,I */
1050 case 0050:case 0051:case 0052:case 0053:
1051 case 0054:case 0055:case 0056:case 0057:
1052 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* JMP */
1053 mp_dms_jmp (MA
); /* validate jump addr */
1058 case 0060:case 0061:case 0062:case 0063:
1059 case 0064:case 0065:case 0066:case 0067:
1060 case 0260:case 0261:case 0262:case 0263:
1061 case 0264:case 0265:case 0266:case 0267:
1062 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* IOR */
1063 AR
= AR
| ReadW (MA
);
1066 case 0070:case 0071:case 0072:case 0073:
1067 case 0074:case 0075:case 0076:case 0077:
1068 case 0270:case 0271:case 0272:case 0273:
1069 case 0274:case 0275:case 0276:case 0277:
1070 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* ISZ */
1071 t
= (ReadW (MA
) + 1) & DMASK
;
1073 if (t
== 0) PC
= (PC
+ 1) & VAMASK
;
1076 case 0100:case 0101:case 0102:case 0103:
1077 case 0104:case 0105:case 0106:case 0107:
1078 case 0300:case 0301:case 0302:case 0303:
1079 case 0304:case 0305:case 0306:case 0307:
1080 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* ADA */
1083 if (t
> DMASK
) E
= 1;
1084 if (((~AR
^ v1
) & (AR
^ t
)) & SIGN
) O
= 1;
1088 case 0110:case 0111:case 0112:case 0113:
1089 case 0114:case 0115:case 0116:case 0117:
1090 case 0310:case 0311:case 0312:case 0313:
1091 case 0314:case 0315:case 0316:case 0317:
1092 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* ADB */
1095 if (t
> DMASK
) E
= 1;
1096 if (((~BR
^ v1
) & (BR
^ t
)) & SIGN
) O
= 1;
1100 case 0120:case 0121:case 0122:case 0123:
1101 case 0124:case 0125:case 0126:case 0127:
1102 case 0320:case 0321:case 0322:case 0323:
1103 case 0324:case 0325:case 0326:case 0327:
1104 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* CPA */
1105 if (AR
!= ReadW (MA
)) PC
= (PC
+ 1) & VAMASK
;
1108 case 0130:case 0131:case 0132:case 0133:
1109 case 0134:case 0135:case 0136:case 0137:
1110 case 0330:case 0331:case 0332:case 0333:
1111 case 0334:case 0335:case 0336:case 0337:
1112 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* CPB */
1113 if (BR
!= ReadW (MA
)) PC
= (PC
+ 1) & VAMASK
;
1116 case 0140:case 0141:case 0142:case 0143:
1117 case 0144:case 0145:case 0146:case 0147:
1118 case 0340:case 0341:case 0342:case 0343:
1119 case 0344:case 0345:case 0346:case 0347:
1120 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* LDA */
1124 case 0150:case 0151:case 0152:case 0153:
1125 case 0154:case 0155:case 0156:case 0157:
1126 case 0350:case 0351:case 0352:case 0353:
1127 case 0354:case 0355:case 0356:case 0357:
1128 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* LDB */
1132 case 0160:case 0161:case 0162:case 0163:
1133 case 0164:case 0165:case 0166:case 0167:
1134 case 0360:case 0361:case 0362:case 0363:
1135 case 0364:case 0365:case 0366:case 0367:
1136 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* STA */
1140 case 0170:case 0171:case 0172:case 0173:
1141 case 0174:case 0175:case 0176:case 0177:
1142 case 0370:case 0371:case 0372:case 0373:
1143 case 0374:case 0375:case 0376:case 0377:
1144 if (reason
= Ea (IR
, &MA
, intrq
)) break; /* STB */
1148 /* Alter/skip instructions */
1150 case 0004:case 0005:case 0006:case 0007:
1151 case 0014:case 0015:case 0016:case 0017:
1152 skip
= 0; /* no skip */
1153 if (IR
& 000400) t
= 0; /* CLx */
1154 else t
= ABREG
[absel
];
1155 if (IR
& 001000) t
= t
^ DMASK
; /* CMx */
1156 if (IR
& 000001) { /* RSS? */
1157 if ((IR
& 000040) && (E
!= 0)) skip
= 1; /* SEZ,RSS */
1158 if (IR
& 000100) E
= 0; /* CLE */
1159 if (IR
& 000200) E
= E
^ 1; /* CME */
1160 if (((IR
& 000030) == 000030) && /* SSx,SLx,RSS */
1161 ((t
& 0100001) == 0100001)) skip
= 1;
1162 if (((IR
& 000030) == 000020) && /* SSx,RSS */
1163 ((t
& SIGN
) != 0)) skip
= 1;
1164 if (((IR
& 000030) == 000010) && /* SLx,RSS */
1165 ((t
& 1) != 0)) skip
= 1;
1166 if (IR
& 000004) { /* INx */
1167 t
= (t
+ 1) & DMASK
;
1169 if (t
== SIGN
) O
= 1;
1171 if ((IR
& 000002) && (t
!= 0)) skip
= 1; /* SZx,RSS */
1172 if ((IR
& 000072) == 0) skip
= 1; /* RSS */
1175 if ((IR
& 000040) && (E
== 0)) skip
= 1; /* SEZ */
1176 if (IR
& 000100) E
= 0; /* CLE */
1177 if (IR
& 000200) E
= E
^ 1; /* CME */
1178 if ((IR
& 000020) && /* SSx */
1179 ((t
& SIGN
) == 0)) skip
= 1;
1180 if ((IR
& 000010) && /* SLx */
1181 ((t
& 1) == 0)) skip
= 1;
1182 if (IR
& 000004) { /* INx */
1183 t
= (t
+ 1) & DMASK
;
1185 if (t
== SIGN
) O
= 1;
1187 if ((IR
& 000002) && (t
== 0)) skip
= 1; /* SZx */
1189 ABREG
[absel
] = t
; /* store result */
1190 PC
= (PC
+ skip
) & VAMASK
; /* add in skip */
1191 break; /* end if alter/skip */
1193 /* Shift instructions */
1195 case 0000:case 0001:case 0002:case 0003:
1196 case 0010:case 0011:case 0012:case 0013:
1197 t
= shift (ABREG
[absel
], IR
& 01000, IR
>> 6); /* do first shift */
1198 if (IR
& 000040) E
= 0; /* CLE */
1199 if ((IR
& 000010) && ((t
& 1) == 0)) /* SLx */
1200 PC
= (PC
+ 1) & VAMASK
;
1201 ABREG
[absel
] = shift (t
, IR
& 00020, IR
); /* do second shift */
1202 break; /* end if shift */
1204 /* I/O instructions */
1206 case 0204:case 0205:case 0206:case 0207:
1207 case 0214:case 0215:case 0216:case 0217:
1208 reason
= iogrp (IR
, iotrap
); /* execute instr */
1209 break; /* end if I/O */
1211 /* Extended arithmetic */
1213 case 0200: /* EAU group 0 */
1214 case 0201: /* divide */
1215 case 0202: /* EAU group 2 */
1216 case 0210: /* DLD */
1217 case 0211: /* DST */
1218 reason
= cpu_eau (IR
, intrq
); /* extended arith */
1221 /* Extended instructions */
1223 case 0212: /* UIG 0 extension */
1224 reason
= cpu_uig_0 (IR
, intrq
, iotrap
); /* extended opcode */
1227 case 0203: /* UIG 1 extension */
1229 reason
= cpu_uig_1 (IR
, intrq
, iotrap
); /* extended opcode */
1233 if (reason
== NOTE_IOG
) { /* I/O instr exec? */
1234 dmarq
= calc_dma (); /* recalc DMA masks */
1235 intrq
= calc_int (); /* recalc interrupts */
1236 reason
= 0; /* continue */
1239 else if (reason
== NOTE_INDINT
) { /* intr pend during indir? */
1240 PC
= err_PC
; /* back out of inst */
1241 reason
= 0; /* continue */
1245 /* Simulation halted */
1247 saved_AR
= AR
& DMASK
;
1248 saved_BR
= BR
& DMASK
;
1249 if (iotrap
&& (reason
== STOP_HALT
)) MR
= intaddr
; /* HLT in trap cell? */
1250 else MR
= (PC
- 1) & VAMASK
; /* no, M = P - 1 */
1251 TR
= ReadTAB (MR
); /* last word fetched */
1252 saved_MR
= MR
; /* save for T cmd update */
1253 if ((reason
== STOP_RSRV
) || (reason
== STOP_IODV
) || /* instr error? */
1254 (reason
== STOP_IND
)) PC
= err_PC
; /* back up PC */
1255 dms_upd_sr (); /* update dms_sr */
1256 if (reason
== STOP_HALT
) /* programmed halt? */
1257 cpu_set_ldr (NULL
, FALSE
, NULL
, NULL
); /* disable loader (ignore errors) */
1258 for (i
= 0; dptr
= sim_devices
[i
]; i
++) { /* loop thru dev */
1259 dibp
= (DIB
*) dptr
->ctxt
; /* get DIB */
1260 if (dibp
) { /* exist? */
1262 dibp
->cmd
= CMD (dev
);
1263 dibp
->ctl
= CTL (dev
);
1264 dibp
->flg
= FLG (dev
);
1265 dibp
->fbf
= FBF (dev
);
1266 dibp
->srq
= SRQ (dev
);
1269 pcq_r
->qptr
= pcq_p
; /* update pc q ptr */
1270 if (dms_enb
) /* default breakpoint type */
1271 if (dms_ump
) sim_brk_dflt
= SWMASK ('U'); /* to current map mode */
1272 else sim_brk_dflt
= SWMASK ('S');
1273 else sim_brk_dflt
= SWMASK ('N');
1277 /* Resolve indirect addresses.
1279 An indirect chain is followed until a direct address is obtained. Under
1280 simulation, a maximum number of indirect levels are allowed (typically 16),
1281 after which the instruction will be aborted.
1283 If the memory protect feature is present, an indirect counter is used that
1284 allows a pending interrupt to be serviced if more than three levels of
1285 indirection are encountered. If MP jumper W6 ("INT") is out and MP is
1286 enabled, then pending interrupts are serviced immediately. When employing
1287 the indirect counter, the hardware clears a pending interrupt deferral after
1288 the third indirection and aborts the instruction after the fourth.
1291 t_stat
resolve (uint32 MA
, uint32
*addr
, uint32 irq
)
1294 t_bool pending
= (irq
&& !(mp_unit
.flags
& DEV_DIS
));
1295 t_bool int_enable
= ((mp_unit
.flags
& UNIT_MP_INT
) && CTL(PRO
));
1297 for (i
= 0; (i
< ind_max
) && (MA
& I_IA
); i
++) { /* resolve multilevel */
1298 if (pending
) { /* interrupt pending and MP enabled? */
1299 if ((i
== 2) || int_enable
) /* 3rd level indirect or INT out? */
1300 ion_defer
= 0; /* reenable interrrupts */
1301 if ((i
> 2) || int_enable
) /* 4th or higher or INT out? */
1302 return NOTE_INDINT
; /* break out now */
1304 MA
= ReadW (MA
& VAMASK
); /* follow address chain */
1306 if (MA
& I_IA
) return STOP_IND
; /* indirect loop? */
1311 /* Get effective address from IR */
1313 t_stat
Ea (uint32 IR
, uint32
*addr
, uint32 irq
)
1317 MA
= IR
& (I_IA
| I_DISP
); /* ind + disp */
1318 if (IR
& I_CP
) MA
= ((PC
- 1) & I_PAGENO
) | MA
; /* current page? */
1319 return resolve (MA
, addr
, irq
); /* resolve indirects */
1322 /* Shift micro operation */
1324 uint32
shift (uint32 t
, uint32 flag
, uint32 op
)
1328 op
= op
& 07; /* get shift op */
1329 if (flag
) { /* enabled? */
1330 switch (op
) { /* case on operation */
1332 case 00: /* signed left shift */
1333 return ((t
& SIGN
) | ((t
<< 1) & 077777));
1335 case 01: /* signed right shift */
1336 return ((t
& SIGN
) | (t
>> 1));
1338 case 02: /* rotate left */
1339 return (((t
<< 1) | (t
>> 15)) & DMASK
);
1341 case 03: /* rotate right */
1342 return (((t
>> 1) | (t
<< 15)) & DMASK
);
1344 case 04: /* left shift, 0 sign */
1345 return ((t
<< 1) & 077777);
1347 case 05: /* ext right rotate */
1350 return ((t
>> 1) | (oldE
<< 15));
1352 case 06: /* ext left rotate */
1355 return (((t
<< 1) | oldE
) & DMASK
);
1357 case 07: /* rotate left four */
1358 return (((t
<< 4) | (t
>> 12)) & DMASK
);
1361 if (op
== 05) E
= t
& 1; /* disabled ext rgt rot */
1362 if (op
== 06) E
= (t
>> 15) & 1; /* disabled ext lft rot */
1363 return t
; /* input unchanged */
1366 /* I/O instruction decode.
1368 If memory protect is enabled, and the instruction is not in a trap cell, then
1369 HLT instructions are illegal and will cause a memory protect violation. If
1370 jumper W7 (SEL1) is in, then all other I/O instructions are legal; if W7 is
1371 out, then only I/O instructions to select code 1 are legal.
1373 We return NOTE_IOG for normal status instead of SCPE_OK to request that
1374 interrupts be recalculated at the end of the instruction (execution of the
1375 I/O group instructions can change the interrupt priority chain).
1378 t_stat
iogrp (uint32 ir
, uint32 iotrap
)
1380 uint32 dev
, sop
, iodata
, iostat
, ab
;
1382 ab
= (ir
& I_AB
)? 1: 0; /* get A/B select */
1383 dev
= ir
& I_DEVMASK
; /* get device */
1384 sop
= I_GETIOOP (ir
); /* get subopcode */
1385 if (!iotrap
&& CTL (PRO
) && /* protected? */
1386 ((sop
== ioHLT
) || /* halt or !ovf? */
1387 ((dev
!= OVF
) && (mp_unit
.flags
& UNIT_MP_SEL1
)))) { /* sel code OK? */
1388 if (sop
== ioLIX
) ABREG
[ab
] = 0; /* A/B writes anyway */
1391 iodata
= devdisp (dev
, sop
, ir
, ABREG
[ab
]); /* process I/O */
1392 ion_defer
= defer_tab
[sop
]; /* set defer */
1393 if ((sop
== ioMIX
) || (sop
== ioLIX
)) /* store ret data */
1394 ABREG
[ab
] = iodata
& DMASK
;
1395 if (sop
== ioHLT
) { /* halt? */
1396 int32 len
= strlen (halt_msg
); /* find end msg */
1397 sprintf (&halt_msg
[len
- 6], "%06o", ir
); /* add the halt */
1400 iostat
= iodata
>> IOT_V_REASON
;
1401 if (iostat
== SCPE_OK
) return NOTE_IOG
; /* normal status */
1402 else return iostat
; /* abnormal status */
1405 /* Device dispatch */
1407 uint32
devdisp (uint32 devno
, uint32 inst
, uint32 IR
, uint32 dat
)
1409 if (dtab
[devno
]) return dtab
[devno
] (inst
, IR
, dat
);
1410 else return nulio (inst
, IR
, dat
);
1413 /* Calculate DMA requests */
1415 uint32
calc_dma (void)
1419 if (CMD (DMA0
) && SRQ (dmac
[0].cw1
& I_DEVMASK
)) /* check DMA0 cycle */
1421 if (CMD (DMA1
) && SRQ (dmac
[1].cw1
& I_DEVMASK
)) /* check DMA1 cycle */
1426 /* Determine whether a pending interrupt deferral should be inhibited.
1428 Execution of certain instructions generally causes a pending interrupt to be
1429 deferred until the succeeding instruction completes. However, the interrupt
1430 deferral rules differ on the 21xx vs. the 1000.
1432 The 1000 always defers until the completion of the instruction following a
1433 deferring instruction. The 21xx defers unless the following instruction is
1434 an MRG instruction other than JMP or JMP,I or JSB,I. If it is, then the
1435 deferral is inhibited, i.e., the pending interrupt will be serviced.
1437 See the "Set Phase Logic Flowchart," transition from phase 1A to phase 1B,
1438 and the "Theory of Operation," "Control Section Detailed Theory," "Phase
1439 Control Logic," "Phase 1B" paragraph in the Model 2100A Computer Installation
1440 and Maintenance Manual for details.
1443 uint32
calc_defer (void)
1447 if (UNIT_CPU_FAMILY
== UNIT_FAMILY_21XX
) { /* 21xx series? */
1448 IR
= ReadW (PC
); /* prefetch next instr */
1450 if (((IR
& I_MRG
& ~I_AB
) != 0000000) && /* is MRG instruction? */
1451 ((IR
& I_MRG_I
) != I_JSB_I
) && /* but not JSB,I? */
1452 ((IR
& I_MRG
) != I_JMP
)) /* and not JMP or JMP,I? */
1453 return 0; /* yes, so inhibit deferral */
1455 return 1; /* no, so allow deferral */
1458 return 1; /* 1000 always allows deferral */
1461 /* Calculate interrupt requests
1463 This routine takes into account all the relevant state of the
1464 interrupt system: ion, dev_flg, dev_fbf, and dev_ctl.
1466 1. dev_flg & dev_ctl determines the end of the priority grant.
1467 The break in the chain will occur at the first device for
1468 which dev_flg & dev_ctl is true. This is determined by
1469 AND'ing the set bits with their 2's complement; only the low
1470 order (highest priority) bit will differ. 1 less than
1471 that, or'd with the single set bit itself, is the mask of
1472 possible interrupting devices. If ION is clear, only devices
1473 4 and 5 are eligible to interrupt.
1474 2. dev_flg & dev_ctl & dev_fbf determines the outstanding
1475 interrupt requests. All three bits must be on for a device
1476 to request an interrupt. This is the masked under the
1477 result from #1 to determine the highest priority interrupt,
1481 uint32
calc_int (void)
1483 int32 j
, lomask
, mask
[2], req
[2];
1485 lomask
= dev_flg
[0] & dev_ctl
[0] & ~M_NXDEV
; /* start chain calc */
1486 req
[0] = lomask
& dev_fbf
[0]; /* calc requests */
1487 lomask
= lomask
& (-lomask
); /* chain & -chain */
1488 mask
[0] = lomask
| (lomask
- 1); /* enabled devices */
1489 req
[0] = req
[0] & mask
[0]; /* highest request */
1490 if (ion
) { /* ion? */
1491 if (lomask
== 0) { /* no break in chn? */
1492 mask
[1] = dev_flg
[1] & dev_ctl
[1]; /* do all devices */
1493 req
[1] = mask
[1] & dev_fbf
[1];
1494 mask
[1] = mask
[1] & (-mask
[1]);
1495 mask
[1] = mask
[1] | (mask
[1] - 1);
1496 req
[1] = req
[1] & mask
[1];
1501 req
[0] = req
[0] & (INT_M (PWR
) | INT_M (PRO
));
1504 if (req
[0]) { /* if low request */
1505 for (j
= 0; j
< 32; j
++) { /* find dev # */
1506 if (req
[0] & INT_M (j
)) return j
;
1509 if (req
[1]) { /* if hi request */
1510 for (j
= 0; j
< 32; j
++) { /* find dev # */
1511 if (req
[1] & INT_M (j
)) return (32 + j
);
1517 /* Memory access routines */
1519 uint8
ReadB (uint32 va
)
1523 if (dms_enb
) pa
= dms (va
>> 1, dms_ump
, RD
);
1525 if (va
& 1) return (ReadPW (pa
) & 0377);
1526 else return ((ReadPW (pa
) >> 8) & 0377);
1529 uint8
ReadBA (uint32 va
)
1533 if (dms_enb
) pa
= dms (va
>> 1, dms_ump
^ MAP_LNT
, RD
);
1535 if (va
& 1) return (ReadPW (pa
) & 0377);
1536 else return ((ReadPW (pa
) >> 8) & 0377);
1539 uint16
ReadW (uint32 va
)
1543 if (dms_enb
) pa
= dms (va
, dms_ump
, RD
);
1548 uint16
ReadWA (uint32 va
)
1552 if (dms_enb
) pa
= dms (va
, dms_ump
^ MAP_LNT
, RD
);
1557 uint16
ReadIO (uint32 va
, uint32 map
)
1561 if (dms_enb
) pa
= dms_io (va
, map
);
1566 uint16
ReadPW (uint32 pa
)
1568 if (pa
<= 1) return ABREG
[pa
];
1572 uint16
ReadTAB (uint32 addr
)
1574 if (addr
== 0) return saved_AR
;
1575 else if (addr
== 1) return saved_BR
;
1576 else return ReadIO (addr
, dms_ump
);
1579 /* Memory protection test for writes
1581 From Dave Bryan: The problem is that memory writes aren't being checked for
1582 an MP violation if DMS is enabled, i.e., if DMS is enabled, and the page is
1583 writable, then whether the target is below the MP fence is not checked. [The
1584 simulator must] do MP check on all writes after DMS translation and violation
1585 checks are done (so, to pass, the page must be writable AND the target must
1586 be above the MP fence).
1589 #define MP_TEST(x) (CTL (PRO) && ((x) > 1) && ((x) < mp_fence))
1591 void WriteB (uint32 va
, uint32 dat
)
1595 if (dms_enb
) pa
= dms (va
>> 1, dms_ump
, WR
);
1597 if (MP_TEST (va
>> 1)) ABORT (ABORT_PRO
);
1598 if (MEM_ADDR_OK (pa
)) {
1600 if (va
& 1) t
= (t
& 0177400) | (dat
& 0377);
1601 else t
= (t
& 0377) | ((dat
& 0377) << 8);
1607 void WriteBA (uint32 va
, uint32 dat
)
1612 dms_viol (va
>> 1, MVI_WPR
); /* viol if prot */
1613 pa
= dms (va
>> 1, dms_ump
^ MAP_LNT
, WR
);
1616 if (MP_TEST (va
>> 1)) ABORT (ABORT_PRO
);
1617 if (MEM_ADDR_OK (pa
)) {
1619 if (va
& 1) t
= (t
& 0177400) | (dat
& 0377);
1620 else t
= (t
& 0377) | ((dat
& 0377) << 8);
1626 void WriteW (uint32 va
, uint32 dat
)
1630 if (dms_enb
) pa
= dms (va
, dms_ump
, WR
);
1632 if (MP_TEST (va
)) ABORT (ABORT_PRO
);
1633 if (MEM_ADDR_OK (pa
)) WritePW (pa
, dat
);
1637 void WriteWA (uint32 va
, uint32 dat
)
1642 dms_viol (va
, MVI_WPR
); /* viol if prot */
1643 pa
= dms (va
, dms_ump
^ MAP_LNT
, WR
);
1646 if (MP_TEST (va
)) ABORT (ABORT_PRO
);
1647 if (MEM_ADDR_OK (pa
)) WritePW (pa
, dat
);
1651 void WriteIO (uint32 va
, uint32 dat
, uint32 map
)
1655 if (dms_enb
) pa
= dms_io (va
, map
);
1657 if (MEM_ADDR_OK (pa
)) M
[pa
] = dat
& DMASK
;
1661 void WritePW (uint32 pa
, uint32 dat
)
1663 if (pa
<= 1) ABREG
[pa
] = dat
& DMASK
;
1664 else M
[pa
] = dat
& DMASK
;
1668 /* DMS relocation for CPU access */
1670 uint32
dms (uint32 va
, uint32 map
, uint32 prot
)
1674 if (va
<= 1) return va
; /* A, B */
1675 pgn
= VA_GETPAG (va
); /* get page num */
1676 if (pgn
== 0) { /* base page? */
1677 uint32 dms_fence
= dms_sr
& MST_FENCE
; /* get fence value */
1678 if ((dms_sr
& MST_FLT
)? /* check unmapped */
1679 (va
>= dms_fence
): /* 1B10: >= fence */
1680 (va
< dms_fence
)) { /* 0B10: < fence */
1681 if (prot
== WR
) dms_viol (va
, MVI_BPG
); /* if W, viol */
1682 return va
; /* no mapping */
1685 mpr
= dms_map
[map
+ pgn
]; /* get map reg */
1686 if (mpr
& prot
) dms_viol (va
, prot
); /* prot violation? */
1687 return (MAP_GETPAG (mpr
) | VA_GETOFF (va
));
1690 /* DMS relocation for IO access */
1692 uint32
dms_io (uint32 va
, uint32 map
)
1696 if (va
<= 1) return va
; /* A, B */
1697 pgn
= VA_GETPAG (va
); /* get page num */
1698 if (pgn
== 0) { /* base page? */
1699 uint32 dms_fence
= dms_sr
& MST_FENCE
; /* get fence value */
1700 if ((dms_sr
& MST_FLT
)? /* check unmapped */
1701 (va
>= dms_fence
): /* 1B10: >= fence */
1702 (va
< dms_fence
)) { /* 0B10: < fence */
1703 return va
; /* no mapping */
1706 mpr
= dms_map
[map
+ pgn
]; /* get map reg */
1707 return (MAP_GETPAG (mpr
) | VA_GETOFF (va
));
1710 /* DMS relocation for console access */
1712 uint32
dms_cons (uint32 va
, int32 sw
)
1716 if ((dms_enb
== 0) || /* DMS off? */
1717 (sw
& (SWMASK ('N') | SIM_SW_REST
))) /* no mapping rqst or save/rest? */
1718 return va
; /* use physical address */
1719 else if (sw
& SWMASK ('S')) map_sel
= SMAP
;
1720 else if (sw
& SWMASK ('U')) map_sel
= UMAP
;
1721 else if (sw
& SWMASK ('P')) map_sel
= PAMAP
;
1722 else if (sw
& SWMASK ('Q')) map_sel
= PBMAP
;
1723 else map_sel
= dms_ump
; /* dflt to log addr, cur map */
1724 if (va
>= VASIZE
) return MEMSIZE
; /* virtual, must be 15b */
1725 else if (dms_enb
) return dms_io (va
, map_sel
); /* DMS on? go thru map */
1726 else return va
; /* else return virtual */
1729 /* Mem protect and DMS validation for jumps */
1731 void mp_dms_jmp (uint32 va
)
1733 uint32 pgn
= VA_GETPAG (va
); /* get page num */
1735 if ((pgn
== 0) && (va
> 1)) { /* base page? */
1736 uint32 dms_fence
= dms_sr
& MST_FENCE
; /* get fence value */
1737 if ((dms_sr
& MST_FLT
)? /* check unmapped */
1738 (va
>= dms_fence
): /* 1B10: >= fence */
1739 (va
< dms_fence
)) { /* 0B10: < fence */
1740 dms_viol (va
, MVI_BPG
); /* if W, viol */
1741 return; /* PRO not set */
1744 if (CTL (PRO
) && (va
< mp_fence
)) ABORT (ABORT_PRO
); /* base page MPR */
1748 /* DMS read and write maps */
1750 uint16
dms_rmap (uint32 mapi
)
1752 mapi
= mapi
& MAP_MASK
;
1753 return (dms_map
[mapi
] & ~MAP_MBZ
);
1756 void dms_wmap (uint32 mapi
, uint32 dat
)
1758 mapi
= mapi
& MAP_MASK
;
1759 dms_map
[mapi
] = (uint16
) (dat
& ~MAP_MBZ
);
1765 void dms_viol (uint32 va
, uint32 st
)
1767 dms_vr
= st
| VA_GETPAG (va
) |
1768 ((st
& (MVI_RPR
| MVI_WPR
))? MVI_MEB
: 0) | /* set MEB */
1769 (dms_enb
? MVI_MEM
: 0) | /* set MEM */
1770 (dms_ump
? MVI_UMP
: 0); /* set UMAP */
1771 if (CTL (PRO
)) { /* protected? */
1772 mp_mevff
= 1; /* signal dms */
1773 ABORT (ABORT_PRO
); /* abort */
1778 /* DMS update status */
1780 uint32
dms_upd_sr (void)
1782 dms_sr
= dms_sr
& ~(MST_ENB
| MST_UMP
| MST_PRO
);
1783 if (dms_enb
) dms_sr
= dms_sr
| MST_ENB
;
1784 if (dms_ump
) dms_sr
= dms_sr
| MST_UMP
;
1785 if (CTL (PRO
)) dms_sr
= dms_sr
| MST_PRO
;
1789 /* Device 0 (CPU) I/O routine
1791 NOTE: LIx/MIx reads floating I/O bus (0 on all machines).
1793 NOTE: CLC 0 issues CRS to all devices, not CLC. While most cards react
1794 identically to CRS and CLC, some do not, e.g., the 12566B when used as an
1795 I/O diagnostic target. PRESET also issues CRS (with POPIO).
1797 From Dave Bryan: RTE uses the undocumented instruction "SFS 0,C" to both test
1798 and turn off the interrupt system. This is confirmed in the "RTE-6/VM
1799 Technical Specifications" manual (HP 92084-90015), section 2.3.1 "Process
1800 the Interrupt", subsection "A.1 $CIC":
1802 "Test to see if the interrupt system is on or off. This is done with the
1803 SFS 0,C instruction. In either case, turn it off (the ,C does it)."
1805 ...and in section 5.8, "Parity Error Detection":
1807 "Because parity error interrupts can occur even when the interrupt system
1808 is off, the code at $CIC must be able to save the complete system status.
1809 The major hole in being able to save the complete state is in saving the
1810 interrupt system state. In order to do this in both the 21MX and the 21XE
1811 the instruction 103300 was used to both test the interrupt system and
1815 int32
cpuio (int32 inst
, int32 IR
, int32 dat
)
1819 switch (inst
) { /* case on opcode */
1821 case ioFLG
: /* flag */
1822 ion
= (IR
& I_HC
)? 0: 1; /* interrupts off/on */
1825 case ioSFC
: /* skip flag clear */
1826 if (!ion
) PC
= (PC
+ 1) & VAMASK
;
1829 case ioSFS
: /* skip flag set */
1830 if (ion
) PC
= (PC
+ 1) & VAMASK
;
1833 case ioLIX
: /* load */
1834 dat
= 0; /* returns 0 */
1837 case ioCTL
: /* control */
1838 if (IR
& I_CTL
) /* CLC 0 sends CRS */
1839 for (i
= 0; i
<= I_DEVMASK
; i
++) /* to all devices */
1840 devdisp (i
, ioCRS
, I_CTL
+ i
, 0); /* IR -> "CLC i" for convenience */
1847 if (IR
& I_HC
) ion
= 0; /* HC option */
1851 /* Device 1 (overflow/S-register) I/O routine
1853 NOTE: The S register is read-only on the 2115/2116. It is read/write on
1854 the 2114, 2100, and 1000.
1857 int32
ovfio (int32 inst
, int32 IR
, int32 dat
)
1859 switch (inst
) { /* case on opcode */
1861 case ioFLG
: /* flag */
1862 O
= (IR
& I_HC
)? 0: 1; /* clear/set overflow */
1865 case ioSFC
: /* skip flag clear */
1866 if (!O
) PC
= (PC
+ 1) & VAMASK
;
1867 break; /* can clear flag */
1869 case ioSFS
: /* skip flag set */
1870 if (O
) PC
= (PC
+ 1) & VAMASK
;
1871 break; /* can clear flag */
1873 case ioMIX
: /* merge */
1877 case ioLIX
: /* load */
1881 case ioOTX
: /* output */
1882 if ((UNIT_CPU_MODEL
!= UNIT_2116
) &&
1883 (UNIT_CPU_MODEL
!= UNIT_2115
))
1891 if (IR
& I_HC
) O
= 0; /* HC option */
1895 /* Device 4 (power fail) I/O routine */
1897 int32
pwrio (int32 inst
, int32 IR
, int32 dat
)
1899 switch (inst
) { /* case on opcode */
1901 case ioMIX
: /* merge */
1902 dat
= dat
| intaddr
;
1905 case ioLIX
: /* load */
1916 /* Device 5 (memory protect) I/O routine
1918 From Dave Bryan: Examination of the schematics for the MP card in the
1919 engineering documentation shows that the SFS and SFC I/O backplane signals
1920 gate the output of the MEVFF onto the SKF line unconditionally.
1922 The MEVFF records memory expansion (a.k.a. dynamic mapping) violations. It
1923 is set when an DM violation is encountered. It is cleared on POPIO, STC 5,
1924 and -HLT * IOGSP * INTPT. The latter occurs when an interrupt causes
1925 execution of a non-halt I/O instruction in the interrupt trap cell.
1928 int32
proio (int32 inst
, int32 IR
, int32 dat
)
1930 switch (inst
) { /* case on opcode */
1932 case ioSFC
: /* skip flag clear */
1933 if (!mp_mevff
) PC
= (PC
+ 1) & VAMASK
; /* skip if mem prot */
1936 case ioSFS
: /* skip flag set */
1937 if (mp_mevff
) PC
= (PC
+ 1) & VAMASK
; /* skip if DMS */
1940 case ioMIX
: /* merge */
1941 dat
= dat
| mp_viol
;
1944 case ioLIX
: /* load */
1948 case ioOTX
: /* output */
1949 mp_fence
= dat
& VAMASK
;
1950 if (cpu_unit
.flags
& UNIT_2100
) iop_sp
= mp_fence
;
1953 case ioCRS
: /* control reset */
1954 case ioCTL
: /* control clear/set */
1955 if ((IR
& I_CTL
) == 0) { /* STC */
1958 mp_evrff
= 1; /* allow mp_viol upd */
1959 mp_mevff
= 0; /* clear DMS flag */
1967 if (IR
& I_HC
) { clrFLG (PRO
); } /* HC option */
1971 /* Devices 2,3 (secondary DMA) I/O routine.
1973 Implements control word 2 (memory address) and control word 3 (word count).
1975 The 12607B (2114) supports 14-bit addresses and 13-bit word counts.
1976 The 12578A (2115/6) supports 15-bit addresses and 14-bit word counts.
1977 The 12895A (2100) and 12897B (1000) support 15-bit addresses and 16-bit word
1980 Note: because the I/O bus floats to zero on 211x computers, LIA/MIA (word
1981 count) returns zeros in the unused bit locations, even though the word count
1982 is a negative value.
1985 int32
dmsio (int32 inst
, int32 IR
, int32 dat
)
1989 ch
= IR
& 1; /* get channel num */
1990 switch (inst
) { /* case on opcode */
1992 case ioLIX
: /* load remaining word count */
1995 case ioMIX
: /* merge */
1996 if (UNIT_CPU_MODEL
== UNIT_2114
) /* 2114? */
1997 dat
= dat
| (dmac
[ch
].cw3
& 0017777); /* only 13-bit count */
1998 else if (UNIT_CPU_TYPE
== UNIT_TYPE_211X
) /* 2115/2116? */
1999 dat
= dat
| (dmac
[ch
].cw3
& 0037777); /* only 14-bit count */
2001 dat
= dat
| dmac
[ch
].cw3
; /* rest use full value */
2004 case ioOTX
: /* output */
2005 if (CTL (DMALT0
+ ch
)) /* word count selected? */
2006 dmac
[ch
].cw3
= dat
; /* save count */
2007 else /* memory address selected */
2008 if (UNIT_CPU_MODEL
== UNIT_2114
) /* 2114? */
2009 dmac
[ch
].cw2
= dat
& 0137777; /* 14-bit address */
2011 dmac
[ch
].cw2
= dat
; /* full address stored */
2014 case ioCRS
: /* control reset */
2015 case ioCTL
: /* control clear/set */
2016 if (IR
& I_CTL
) { clrCTL (DMALT0
+ ch
); } /* CLC */
2017 else { setCTL (DMALT0
+ ch
); } /* STC */
2027 /* Devices 6,7 (primary DMA) I/O routine
2029 Implements control word 1 (device address) and DMA control.
2031 The 12607B (2114) stores only bits 2-0 of the select code and interprets them
2032 as select codes 10-16 (SRQ17 is not decoded). The 12578A (2115/6), 12895A
2033 (2100), and 12897B (1000) support the full 10-77 range of select codes.
2035 The 12578A supports byte-sized transfers by setting bit 14. Bit 14 is
2036 ignored by all other DMA cards, which support word transfers only.
2038 NOTE: LIx/MIx reads floating S-bus (1 on 21MX, 0 on 211x/2100).
2040 NOTE: CRS clears control and command flip-flops, whereas CLC clears only
2044 int32
dmpio (int32 inst
, int32 IR
, int32 dat
)
2048 ch
= IR
& 1; /* get channel number */
2050 switch (inst
) { /* case on opcode */
2052 case ioFLG
: /* flag */
2053 if ((IR
& I_HC
) == 0) { /* set->abort */
2054 setFLG (DMA0
+ ch
); /* set flag */
2055 clrCMD (DMA0
+ ch
); /* clr cmd */
2059 case ioSFC
: /* skip flag clear */
2060 if (FLG (DMA0
+ ch
) == 0) PC
= (PC
+ 1) & VAMASK
;
2063 case ioSFS
: /* skip flag set */
2064 if (FLG (DMA0
+ ch
) != 0) PC
= (PC
+ 1) & VAMASK
;
2067 case ioLIX
: /* load */
2070 case ioMIX
: /* merge */
2071 if (UNIT_CPU_TYPE
== UNIT_TYPE_1000
)
2075 case ioOTX
: /* output */
2076 if (UNIT_CPU_MODEL
== UNIT_2114
) /* 12607? */
2077 dmac
[ch
].cw1
= (dat
& 0137707) | 010; /* mask SC, convert to 10-17 */
2078 else if (UNIT_CPU_TYPE
== UNIT_TYPE_211X
) /* 12578? */
2079 dmac
[ch
].cw1
= dat
; /* store full select code, flags */
2080 else /* 12895, 12897 */
2081 dmac
[ch
].cw1
= dat
& ~DMA1_PB
; /* clip byte-packing flag */
2084 case ioCRS
: /* control reset */
2085 clrCMD (DMA0
+ ch
); /* clear command flip-flop */
2087 case ioCTL
: /* control */
2088 if (IR
& I_CTL
) { clrCTL (DMA0
+ ch
); } /* CLC: cmd unchgd */
2090 if (UNIT_CPU_TYPE
== UNIT_TYPE_211X
) /* slow DMA card? */
2091 dmac
[ch
].latency
= 1; /* needs startup latency */
2093 dmac
[ch
].latency
= 0; /* DCPC starts immediately */
2095 dmac
[ch
].packer
= 0; /* clear packing register */
2096 setCTL (DMA0
+ ch
); /* set ctl, cmd */
2105 if (IR
& I_HC
) { clrFLG (DMA0
+ ch
); } /* HC option */
2109 /* DMA cycle routine
2111 The 12578A card supports byte-packing. If bit 14 in control word 1 is set,
2112 each transfer will involve one read/write from memory and two output/input
2113 operations in order to transfer sequential bytes to/from the device.
2115 The last cycle (word count reaches 0) logic is quite tricky.
2117 - CLC requested: issue CLC
2119 - neither STC nor CLC requested: issue CLF
2120 - STC requested but not CLC: issue STC,C
2121 - CLC requested but not STC: issue CLC,C
2122 - STC and CLC both requested: issue STC,C and CLC,C, in that order
2123 Either: issue EDT (pass DMA channel number and I/O flag)
2126 void dma_cycle (uint32 ch
, uint32 map
)
2128 int32 temp
, dev
, MA
;
2129 int32 inp
= dmac
[ch
].cw2
& DMA2_OI
; /* input flag */
2130 int32 byt
= dmac
[ch
].cw1
& DMA1_PB
; /* pack bytes flag */
2132 if (dmac
[ch
].latency
) { /* start-up latency? */
2133 dmac
[ch
].latency
= dmac
[ch
].latency
- 1; /* decrease it */
2134 return; /* that's all this cycle */
2137 dev
= dmac
[ch
].cw1
& I_DEVMASK
; /* get device */
2138 MA
= dmac
[ch
].cw2
& VAMASK
; /* get mem addr */
2140 if (inp
) { /* input cycle? */
2141 temp
= devdisp (dev
, ioLIX
, dev
, 0); /* do LIA dev */
2143 if (byt
) { /* byte packing? */
2144 if (dmac
[ch
].packer
& DMA_OE
) { /* second byte? */
2145 temp
= (dmac
[ch
].packer
<< 8) | /* merge stored byte */
2147 WriteIO (MA
, temp
, map
); /* store word data */
2149 else /* first byte */
2150 dmac
[ch
].packer
= (temp
& DMASK8
); /* save it */
2152 dmac
[ch
].packer
= dmac
[ch
].packer
^ DMA_OE
; /* flip odd/even bit */
2154 else /* no byte packing */
2155 WriteIO (MA
, temp
, map
); /* store word data */
2157 else { /* output cycle */
2158 if (byt
) { /* byte packing? */
2159 if (dmac
[ch
].packer
& DMA_OE
) /* second byte? */
2160 temp
= dmac
[ch
].packer
& DMASK8
; /* retrieve it */
2162 else { /* first byte */
2163 dmac
[ch
].packer
= ReadIO (MA
, map
); /* read word data */
2164 temp
= (dmac
[ch
].packer
>> 8) & DMASK8
; /* get high byte */
2167 dmac
[ch
].packer
= dmac
[ch
].packer
^ DMA_OE
; /* flip odd/even bit */
2169 else /* no byte packing */
2170 temp
= ReadIO (MA
, map
); /* read word data */
2172 devdisp (dev
, ioOTX
, dev
, temp
); /* do OTA dev */
2175 if ((dmac
[ch
].packer
& DMA_OE
) == 0) { /* new byte or no packing? */
2176 dmac
[ch
].cw2
= (dmac
[ch
].cw2
& DMA2_OI
) | /* increment address */
2177 ((dmac
[ch
].cw2
+ 1) & VAMASK
);
2178 dmac
[ch
].cw3
= (dmac
[ch
].cw3
+ 1) & DMASK
; /* increment word count */
2181 if (dmac
[ch
].cw3
) { /* more to do? */
2182 if (dmac
[ch
].cw1
& DMA1_STC
) /* if STC flag, */
2183 devdisp (dev
, ioCTL
, I_HC
+ dev
, 0); /* do STC,C dev */
2184 else devdisp (dev
, ioFLG
, I_HC
+ dev
, 0); /* else CLF dev */
2187 if (inp
) { /* last cycle, input? */
2188 if (dmac
[ch
].cw1
& DMA1_CLC
) /* CLC at end? */
2189 devdisp (dev
, ioCTL
, I_CTL
+ dev
, 0); /* yes */
2192 if ((dmac
[ch
].cw1
& (DMA1_STC
| DMA1_CLC
)) == 0)
2193 devdisp (dev
, ioFLG
, I_HC
+ dev
, 0); /* clear flag */
2194 if (dmac
[ch
].cw1
& DMA1_STC
) /* if STC flag, */
2195 devdisp (dev
, ioCTL
, I_HC
+ dev
, 0); /* do STC,C dev */
2196 if (dmac
[ch
].cw1
& DMA1_CLC
) /* CLC at end? */
2197 devdisp (dev
, ioCTL
, I_HC
+ I_CTL
+ dev
, 0); /* yes */
2199 setFLG (DMA0
+ ch
); /* set DMA flg */
2200 clrCMD (DMA0
+ ch
); /* clr DMA cmd */
2201 devdisp (dev
, ioEDT
, dev
, inp
| ch
); /* do EDT */
2206 /* Unimplemented device routine
2208 NOTE: For SC < 10, LIx/MIx reads floating S-bus (-1 on 21MX, 0 on 211x/2100).
2209 For SC >= 10, LIx/MIx reads floating I/O bus (0 on all machines).
2212 int32
nulio (int32 inst
, int32 IR
, int32 dat
)
2216 devd
= IR
& I_DEVMASK
; /* get device no */
2217 switch (inst
) { /* case on opcode */
2219 case ioSFC
: /* skip flag clear */
2220 PC
= (PC
+ 1) & VAMASK
;
2223 case ioLIX
: /* load */
2226 case ioMIX
: /* merge */
2227 if ((devd
< VARDEV
) && (UNIT_CPU_TYPE
== UNIT_TYPE_1000
))
2235 return (stop_dev
<< IOT_V_REASON
) | dat
;
2238 /* Reset routines */
2240 t_stat
cpu_reset (DEVICE
*dptr
)
2244 ion
= ion_defer
= 0;
2249 dev_srq
[0] = dev_srq
[0] & ~M_FXDEV
;
2250 dms_enb
= dms_ump
= 0; /* init DMS */
2253 pcq_r
= find_reg ("PCQ", NULL
, dptr
);
2254 sim_brk_types
= ALL_BKPTS
;
2255 sim_brk_dflt
= SWMASK ('N'); /* type is nomap as DMS is off */
2257 if (M
== NULL
) { /* initial call? */
2258 M
= calloc (PASIZE
, sizeof (uint16
)); /* alloc mem */
2260 if (M
== NULL
) /* alloc fail? */
2262 else { /* do one-time init */
2263 MEMSIZE
= 32768; /* set initial memory size */
2264 cpu_set_model (NULL
, UNIT_2116
, NULL
, NULL
); /* set initial CPU model */
2265 SR
= 001000; /* select PTR boot ROM at SC 10 */
2266 cpu_boot (0, NULL
); /* install loader for 2116 */
2267 cpu_set_ldr (NULL
, FALSE
, NULL
, NULL
); /* disable loader (was enabled) */
2268 SR
= 0; /* clear S */
2269 sim_vm_post
= &hp_post_cmd
; /* set cmd post proc */
2273 if (pcq_r
) pcq_r
->qptr
= 0;
2274 else return SCPE_IERR
;
2278 t_stat
mp_reset (DEVICE
*dptr
)
2283 mp_fence
= 0; /* init mprot */
2290 t_stat
dma0_reset (DEVICE
*tptr
)
2292 if (UNIT_CPU_MODEL
!= UNIT_2114
) /* 2114 has only one channel */
2293 hp_enbdis_pair (&dma0_dev
, &dma1_dev
); /* make pair cons */
2299 dmac
[0].latency
= dmac
[0].packer
= 0;
2300 if (sim_switches
& SWMASK ('P')) /* power up? */
2301 dmac
[0].cw1
= dmac
[0].cw2
= dmac
[0].cw3
= 0;
2305 t_stat
dma1_reset (DEVICE
*tptr
)
2307 if (UNIT_CPU_MODEL
!= UNIT_2114
) /* 2114 has only one channel */
2308 hp_enbdis_pair (&dma1_dev
, &dma0_dev
); /* make pair cons */
2314 dmac
[1].latency
= dmac
[1].packer
= 0;
2315 if (sim_switches
& SWMASK ('P')) /* power up? */
2316 dmac
[1].cw1
= dmac
[1].cw2
= dmac
[1].cw3
= 0;
2320 /* Memory examine */
2322 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
2326 if ((sw
& ALL_MAPMODES
) && (dms_enb
== 0)) /* req map with DMS off? */
2327 return SCPE_NOFNC
; /* command not allowed */
2328 addr
= dms_cons (addr
, sw
);
2329 if (addr
>= MEMSIZE
) return SCPE_NXM
;
2330 if (!(sw
& SIM_SW_REST
) && (addr
== 0)) d
= saved_AR
;
2331 else if (!(sw
& SIM_SW_REST
) && (addr
== 1)) d
= saved_BR
;
2333 if (vptr
!= NULL
) *vptr
= d
& DMASK
;
2337 /* Memory deposit */
2339 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
2341 if ((sw
& ALL_MAPMODES
) && (dms_enb
== 0)) /* req map with DMS off? */
2342 return SCPE_NOFNC
; /* command not allowed */
2343 addr
= dms_cons (addr
, sw
);
2344 if (addr
>= MEMSIZE
) return SCPE_NXM
;
2345 if (!(sw
& SIM_SW_REST
) && (addr
== 0)) saved_AR
= val
& DMASK
;
2346 else if (!(sw
& SIM_SW_REST
) && (addr
== 1)) saved_BR
= val
& DMASK
;
2347 else M
[addr
] = val
& DMASK
;
2351 /* Set device number */
2353 t_stat
hp_setdev (UNIT
*uptr
, int32 num
, char *cptr
, void *desc
)
2355 DEVICE
*dptr
= (DEVICE
*) desc
;
2360 if (cptr
== NULL
) return SCPE_ARG
;
2361 if ((desc
== NULL
) || (num
> 1)) return SCPE_IERR
;
2362 dibp
= (DIB
*) dptr
->ctxt
;
2363 if (dibp
== NULL
) return SCPE_IERR
;
2364 newdev
= get_uint (cptr
, 8, I_DEVMASK
- num
, &r
);
2365 if (r
!= SCPE_OK
) return r
;
2366 if (newdev
< VARDEV
) return SCPE_ARG
;
2367 for (i
= 0; i
<= num
; i
++, dibp
++) dibp
->devno
= newdev
+ i
;
2371 /* Show device number */
2373 t_stat
hp_showdev (FILE *st
, UNIT
*uptr
, int32 num
, void *desc
)
2375 DEVICE
*dptr
= (DEVICE
*) desc
;
2379 if ((desc
== NULL
) || (num
> 1)) return SCPE_IERR
;
2380 dibp
= (DIB
*) dptr
->ctxt
;
2381 if (dibp
== NULL
) return SCPE_IERR
;
2382 fprintf (st
, "devno=%o", dibp
->devno
);
2383 for (i
= 1; i
<= num
; i
++) fprintf (st
, "/%o", dibp
->devno
+ i
);
2387 /* Make a pair of devices consistent */
2389 void hp_enbdis_pair (DEVICE
*ccp
, DEVICE
*dcp
)
2391 if (ccp
->flags
& DEV_DIS
) dcp
->flags
= dcp
->flags
| DEV_DIS
;
2392 else dcp
->flags
= dcp
->flags
& ~DEV_DIS
;
2396 /* VM command post-processor
2398 Update T register to contents of memory addressed by M register
2399 if M register has changed. */
2401 void hp_post_cmd (t_bool from_scp
)
2403 if (MR
!= saved_MR
) { /* M changed since last update? */
2405 TR
= ReadTAB (MR
); /* sync T with new M */
2410 /* Test for device conflict */
2412 t_bool
dev_conflict (void)
2417 t_bool is_conflict
= FALSE
;
2418 uint32 conflicts
[I_DEVMASK
+ 1] = { 0 };
2420 for (i
= 0; dptr
= sim_devices
[i
]; i
++) {
2421 dibp
= (DIB
*) dptr
->ctxt
;
2422 if (dibp
&& !(dptr
->flags
& DEV_DIS
))
2423 if (++conflicts
[dibp
->devno
] > 1)
2429 for (i
= 0; i
<= I_DEVMASK
; i
++) {
2430 if (conflicts
[i
] > 1) {
2432 printf ("Select code %o conflict:", i
);
2433 if (sim_log
) fprintf (sim_log
, "Select code %o conflict:", i
);
2434 for (j
= 0; dptr
= sim_devices
[j
]; j
++) {
2435 dibp
= (DIB
*) dptr
->ctxt
;
2436 if (dibp
&& !(dptr
->flags
& DEV_DIS
) && (i
== dibp
->devno
)) {
2437 if (k
< conflicts
[i
]) {
2439 if (sim_log
) fputs (" and", sim_log
);
2441 printf (" %s", sim_dname (dptr
));
2442 if (sim_log
) fprintf (sim_log
, " %s", sim_dname (dptr
));
2446 if (sim_log
) fputc ('\n', sim_log
);
2457 /* Change CPU memory size.
2459 On a 21xx, move the current loader to the top of the new memory size. Then
2460 clear "non-existent memory" so that reads return zero, per spec.
2463 - New size <= maximum size for current CPU.
2464 - New size a positive multiple of 4K (progamming error if not).
2465 - If new size < old size, truncation accepted.
2468 t_stat
cpu_set_size (UNIT
*uptr
, int32 new_size
, char *cptr
, void *desc
)
2472 uint32 model
= CPU_MODEL_INDEX
; /* current CPU model index */
2473 uint32 old_size
= MEMSIZE
; /* current memory size */
2475 if ((uint32
) new_size
> cpu_features
[model
].maxmem
)
2476 return SCPE_NOFNC
; /* mem size unsupported */
2478 if ((new_size
<= 0) || (new_size
> PASIZE
) || ((new_size
& 07777) != 0))
2479 return SCPE_NXM
; /* invalid size (prog err) */
2481 if (!(sim_switches
& SWMASK ('F'))) { /* force truncation? */
2482 for (i
= new_size
; i
< MEMSIZE
; i
++) mc
= mc
| M
[i
];
2483 if ((mc
!= 0) && (!get_yn ("Really truncate memory [N]?", FALSE
)))
2487 if (UNIT_CPU_FAMILY
== UNIT_FAMILY_21XX
) { /* 21xx CPU? */
2488 cpu_set_ldr (uptr
, FALSE
, NULL
, NULL
); /* save loader to shadow RAM */
2489 MEMSIZE
= new_size
; /* set new memory size */
2490 fwanxm
= MEMSIZE
- IBL_LNT
; /* reserve memory for loader */
2492 else /* loader unsupported */
2493 fwanxm
= MEMSIZE
= new_size
; /* set new memory size */
2495 for (i
= fwanxm
; i
< old_size
; i
++) M
[i
] = 0; /* zero non-existent memory */
2499 /* Change CPU models.
2501 For convenience, MP and DMA are typically enabled if available; they may be
2502 disabled subsequently if desired. Note that the 2114 supports only one DMA
2503 channel (channel 0). All other models support two channels.
2506 - Sets standard equipment and convenience features.
2507 - Changes DMA device name to DCPC if 1000 is selected.
2508 - Enforces maximum memory allowed (doesn't change otherwise).
2509 - Disables loader on 21xx machines.
2512 t_stat
cpu_set_model (UNIT
*uptr
, int32 new_model
, char *cptr
, void *desc
)
2514 uint32 old_family
= UNIT_CPU_FAMILY
; /* current CPU type */
2515 uint32 new_family
= new_model
& UNIT_FAMILY_MASK
; /* new CPU family */
2516 uint32 new_index
= new_model
>> UNIT_V_CPU
; /* new CPU model index */
2520 cpu_unit
.flags
= cpu_unit
.flags
& ~UNIT_OPTS
| /* set typical features */
2521 cpu_features
[new_index
].typ
& UNIT_OPTS
; /* mask pseudo-opts */
2524 if (cpu_features
[new_index
].typ
& UNIT_MP
) /* MP in typ config? */
2525 mp_dev
.flags
= mp_dev
.flags
& ~DEV_DIS
; /* enable it */
2527 mp_dev
.flags
= mp_dev
.flags
| DEV_DIS
; /* disable it */
2529 if (cpu_features
[new_index
].opt
& UNIT_MP
) /* MP an option? */
2530 mp_dev
.flags
= mp_dev
.flags
| DEV_DISABLE
; /* make it alterable */
2532 mp_dev
.flags
= mp_dev
.flags
& ~DEV_DISABLE
; /* make it unalterable */
2535 if (cpu_features
[new_index
].typ
& UNIT_DMA
) { /* DMA in typ config? */
2536 dma0_dev
.flags
= dma0_dev
.flags
& ~DEV_DIS
; /* enable DMA channel 0 */
2538 if (new_model
== UNIT_2114
) /* 2114 has only one channel */
2539 dma1_dev
.flags
= dma1_dev
.flags
| DEV_DIS
; /* disable channel 1 */
2540 else /* all others have two channels */
2541 dma1_dev
.flags
= dma1_dev
.flags
& ~DEV_DIS
; /* enable it */
2544 dma0_dev
.flags
= dma0_dev
.flags
| DEV_DIS
; /* disable channel 0 */
2545 dma1_dev
.flags
= dma1_dev
.flags
| DEV_DIS
; /* disable channel 1 */
2548 if (cpu_features
[new_index
].opt
& UNIT_DMA
) { /* DMA an option? */
2549 dma0_dev
.flags
= dma0_dev
.flags
| DEV_DISABLE
; /* make it alterable */
2551 if (new_model
== UNIT_2114
) /* 2114 has only one channel */
2552 dma1_dev
.flags
= dma1_dev
.flags
& ~DEV_DISABLE
; /* make it unalterable */
2553 else /* all others have two channels */
2554 dma1_dev
.flags
= dma1_dev
.flags
| DEV_DISABLE
; /* make it alterable */
2557 dma0_dev
.flags
= dma0_dev
.flags
& ~DEV_DISABLE
; /* make it unalterable */
2558 dma1_dev
.flags
= dma1_dev
.flags
& ~DEV_DISABLE
; /* make it unalterable */
2562 if ((old_family
== UNIT_FAMILY_1000
) && /* if current family is 1000 */
2563 (new_family
== UNIT_FAMILY_21XX
)) { /* and new family is 21xx */
2564 deassign_device (&dma0_dev
); /* delete DCPC names */
2565 deassign_device (&dma1_dev
);
2567 else if ((old_family
== UNIT_FAMILY_21XX
) && /* if current family is 21xx */
2568 (new_family
== UNIT_FAMILY_1000
)) { /* and new family is 1000 */
2569 assign_device (&dma0_dev
, "DCPC0"); /* change DMA device name */
2570 assign_device (&dma1_dev
, "DCPC1"); /* to DCPC for familiarity */
2573 if ((MEMSIZE
== 0) || /* current mem size not set? */
2574 (MEMSIZE
> cpu_features
[new_index
].maxmem
)) /* current mem size too large? */
2575 new_memsize
= cpu_features
[new_index
].maxmem
; /* set it to max supported */
2577 new_memsize
= MEMSIZE
; /* or leave it unchanged */
2579 result
= cpu_set_size (uptr
, new_memsize
, NULL
, NULL
); /* set memory size */
2581 if (result
== SCPE_OK
) /* memory change OK? */
2582 if (new_family
== UNIT_FAMILY_21XX
) /* 21xx CPU? */
2583 fwanxm
= MEMSIZE
- IBL_LNT
; /* reserve memory for loader */
2585 fwanxm
= MEMSIZE
; /* loader reserved only for 21xx */
2590 /* Display the CPU model and optional loader status.
2592 Loader status is displayed for 21xx models and suppressed for 1000 models.
2595 t_stat
cpu_show_model (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2597 fputs ((char *) desc
, st
); /* write model name */
2599 if (UNIT_CPU_FAMILY
== UNIT_FAMILY_21XX
) /* valid only for 21xx */
2600 if (fwanxm
< MEMSIZE
) /* loader area non-existent? */
2601 fputs (", loader disabled", st
); /* yes, so access disabled */
2603 fputs (", loader enabled", st
); /* no, so access enabled */
2607 /* Set a CPU option.
2610 - Checks that the current CPU model supports the option selected.
2611 - If CPU is 2100, ensures that FP/FFP and IOP are mutually exclusive.
2612 - If CPU is 2100, ensures that FP is enabled if FFP enabled
2613 (FP is required for FFP installation).
2616 t_stat
cpu_set_opt (UNIT
*uptr
, int32 option
, char *cptr
, void *desc
)
2618 uint32 model
= CPU_MODEL_INDEX
; /* current CPU model index */
2620 if ((cpu_features
[model
].opt
& option
) == 0) /* option supported? */
2621 return SCPE_NOFNC
; /* no */
2623 if (UNIT_CPU_TYPE
== UNIT_TYPE_2100
) {
2624 if ((option
== UNIT_FP
) || (option
== UNIT_FFP
)) /* 2100 IOP and FP/FFP options */
2625 uptr
->flags
= uptr
->flags
& ~UNIT_IOP
; /* are mutually exclusive */
2626 else if (option
== UNIT_IOP
)
2627 uptr
->flags
= uptr
->flags
& ~(UNIT_FP
| UNIT_FFP
);
2629 if (option
== UNIT_FFP
) /* 2100 FFP option requires FP */
2630 uptr
->flags
= uptr
->flags
| UNIT_FP
;
2636 /* Clear a CPU option.
2639 - Checks that the current CPU model supports the option selected.
2640 - Clears flag from unit structure (we are processing MTAB_XTD entries).
2641 - If CPU is 2100, ensures that FFP is disabled if FP disabled
2642 (FP is required for FFP installation).
2645 t_bool
cpu_clr_opt (UNIT
*uptr
, int32 option
, char *cptr
, void *desc
)
2647 uint32 model
= CPU_MODEL_INDEX
; /* current CPU model index */
2649 if ((cpu_features
[model
].opt
& option
) == 0) /* option supported? */
2650 return SCPE_NOFNC
; /* no */
2652 uptr
->flags
= uptr
->flags
& ~option
; /* disable option */
2654 if ((UNIT_CPU_TYPE
== UNIT_TYPE_2100
) && /* disabling 2100 FP? */
2655 (option
== UNIT_FP
))
2656 uptr
->flags
= uptr
->flags
& ~UNIT_FFP
; /* yes, so disable FFP too */
2661 /* 21xx loader enable/disable function.
2663 The 21xx CPUs store their initial binary loaders in the last 64 words of
2664 available memory. This memory is protected by a LOADER ENABLE switch on the
2665 front panel. When the switch is off (disabled), main memory effectively ends
2666 64 locations earlier, i.e., the loader area is treated as non-existent.
2667 Because these are core machines, the loader is retained when system power is
2670 1000 CPUs do not have a protected loader feature. Instead, loaders are
2671 stored in PROMs and are copied into main memory for execution by the IBL
2674 Under simulation, we keep both a total configured memory size (MEMSIZE) and a
2675 current configured memory size (fwanxm = "first word address of non-existent
2676 memory). When the two are equal, the loader is enabled. When the current
2677 size is less than the total size, the loader is disabled.
2679 Disabling the loader copies the last 64 words to a shadow array, zeros the
2680 corresponding memory, and decreases the last word of addressable memory by
2681 64. Enabling the loader reverses this process.
2683 Disabling may be done manually by user command or automatically when a halt
2684 instruction is executed. Enabling occurs only by user command. This differs
2685 slightly from actual machine operation, which additionally disables the
2686 loader when a manual halt is performed. We do not do this to allow
2687 breakpoints within and single-stepping through the loaders.
2690 t_stat
cpu_set_ldr (UNIT
*uptr
, int32 enable
, char *cptr
, void *desc
)
2692 static uint16 loader
[IBL_LNT
];
2694 t_bool is_enabled
= (fwanxm
== MEMSIZE
);
2696 if ((UNIT_CPU_FAMILY
!= UNIT_FAMILY_21XX
) || /* valid only for 21xx */
2697 (MEMSIZE
== 0)) /* and for initialized memory */
2700 if (is_enabled
&& (enable
== 0)) { /* disable loader? */
2701 fwanxm
= MEMSIZE
- IBL_LNT
; /* decrease available memory */
2702 for (i
= 0; i
< IBL_LNT
; i
++) { /* copy loader */
2703 loader
[i
] = M
[fwanxm
+ i
]; /* from memory */
2704 M
[fwanxm
+ i
] = 0; /* and zero location */
2708 else if ((!is_enabled
) && (enable
== 1)) { /* enable loader? */
2709 for (i
= 0; i
< IBL_LNT
; i
++) /* copy loader */
2710 M
[fwanxm
+ i
] = loader
[i
]; /* to memory */
2711 fwanxm
= MEMSIZE
; /* increase available memory */
2717 /* IBL routine (CPU boot) */
2719 t_stat
cpu_boot (int32 unitno
, DEVICE
*dptr
)
2721 extern const uint16 ptr_rom
[IBL_LNT
], dq_rom
[IBL_LNT
];
2722 extern const uint16 ms_rom
[IBL_LNT
], ds_rom
[IBL_LNT
];
2723 int32 dev
= (SR
>> IBL_V_DEV
) & I_DEVMASK
;
2724 int32 sel
= (SR
>> IBL_V_SEL
) & IBL_M_SEL
;
2726 if (dev
< 010) return SCPE_NOFNC
;
2729 case 0: /* PTR boot */
2730 ibl_copy (ptr_rom
, dev
);
2733 case 1: /* DP/DQ boot */
2734 ibl_copy (dq_rom
, dev
);
2737 case 2: /* MS boot */
2738 ibl_copy (ms_rom
, dev
);
2741 case 3: /* DS boot */
2742 ibl_copy (ds_rom
,dev
);
2749 /* IBL boot ROM copy
2751 - Use memory size to set the initial PC and base of the boot area
2752 - Copy boot ROM to memory, updating I/O instructions
2753 - Place 2's complement of boot base in last location
2756 - SR settings are done by the caller
2757 - Boot ROM's must be assembled with a device code of 10 (10 and 11 for
2758 devices requiring two codes)
2761 t_stat
ibl_copy (const uint16 pboot
[IBL_LNT
], int32 dev
)
2766 cpu_set_ldr (NULL
, TRUE
, NULL
, NULL
); /* enable loader (ignore errors) */
2768 if (dev
< 010) return SCPE_ARG
; /* valid device? */
2769 PC
= ((MEMSIZE
- 1) & ~IBL_MASK
) & VAMASK
; /* start at mem top */
2770 for (i
= 0; i
< IBL_LNT
; i
++) { /* copy bootstrap */
2771 wd
= pboot
[i
]; /* get word */
2772 if (((wd
& I_NMRMASK
) == I_IO
) && /* IO instruction? */
2773 ((wd
& I_DEVMASK
) >= 010) && /* dev >= 10? */
2774 (I_GETIOOP (wd
) != ioHLT
)) /* not a HALT? */
2775 M
[PC
+ i
] = (wd
+ (dev
- 010)) & DMASK
; /* change dev code */
2776 else M
[PC
+ i
] = wd
; /* leave unchanged */
2778 M
[PC
+ IBL_DPC
] = (M
[PC
+ IBL_DPC
] + (dev
- 010)) & DMASK
; /* patch DMA ctrl */
2779 M
[PC
+ IBL_END
] = (~PC
+ 1) & DMASK
; /* fill in start of boot */