First Commit of my working state
[simh.git] / HP2100 / hp2100_cpu.c
1 /* hp2100_cpu.c: HP 21xx CPU simulator
2
3 Copyright (c) 1993-2008, Robert M. Supnik
4
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:
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
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.
21
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.
25
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
30
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
128
129 References:
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)
142
143 The register state for the HP 2116 CPU is:
144
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)
148 SR<15:0> S register
149 MR<14:0> M register - memory address
150 TR<15:0> T register - memory data
151 E extend flag (carry out)
152 O overflow flag
153
154 The 2100 adds memory protection logic:
155
156 mp_fence<14:0> memory fence register
157 mp_viol<15:0> memory protection violation register (F register)
158
159 The 21MX adds a pair of index registers and memory expansion logic:
160
161 XR<15:0> X register
162 YR<15:0> Y register
163 dms_sr<15:0> dynamic memory system status register
164 dms_vr<15:0> dynamic memory system violation register
165
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.
170
171 The memory reference format is:
172
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
177
178 <14:11> mnemonic action
179
180 0010 AND A = A & M[MA]
181 0011 JSB M[MA] = P, P = MA + 1
182 0100 XOR A = A ^ M[MA]
183 0101 JMP P = 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]
190 1100 LDA A = M[MA]
191 1101 LDB B = M[MA]
192 1110 STA M[MA] = A
193 1111 STB M[MA] = B
194
195 <15,10> mode action
196
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>]
201
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.
206
207 The shift format is:
208
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 | | \---+---/ | | | \---+---/
214 | | | | | | |
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
222
223 The alter/skip format is:
224
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
239
240 The I/O transfer format is:
241
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 | | \---+---/\-------+-------/
247 | | | |
248 | | | +--------- device select
249 | | +---------------------- opcode
250 | +---------------------------- hold/clear flag
251 +---------------------------------- A/B select
252
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.
256
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.
262
263
264 The extended memory reference format (HP 2100) is:
265
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
272
273 The extended arithmetic format (HP 2100) is:
274
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
279
280 The extended operate format (HP 21MX) is:
281
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
286
287 The extended byte and word format (HP 21MX) is:
288
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
297
298 The extended bit operate format (HP 21MX) is:
299
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
308
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.
313
314 General notes:
315
316 1. Reasons to stop. The simulator can be stopped by:
317
318 HALT instruction
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
324
325 2. Interrupts. I/O devices are modelled as five parallel arrays:
326
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]
332
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.
340
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.
345
346 Service requests are used to trigger the DMA service logic.
347
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.
352
353 On the 21xx machines, doing SET CPU LOADERDISABLE decreases available
354 memory size by 64 words.
355
356 4. Adding I/O devices. These modules must be modified:
357
358 hp2100_defs.h add interrupt request definition
359 hp2100_sys.c add sim_devices table entry
360
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).
370
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.
376
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
381 deferral criteria.
382 */
383
384 #include "hp2100_defs.h"
385 #include <setjmp.h>
386 #include "hp2100_cpu.h"
387
388 /* Memory protect constants */
389
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 */
396
397 #define ABORT(val) longjmp (save_env, (val))
398
399 #define DMAR0 1
400 #define DMAR1 2
401
402 #define ALL_BKPTS (SWMASK('E')|SWMASK('N')|SWMASK('S')|SWMASK('U'))
403 #define ALL_MAPMODES (SWMASK('S')|SWMASK('U')|SWMASK('P')|SWMASK('Q'))
404
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 */
446
447 /* Table of CPU features by model.
448
449 Fields:
450 - typ: standard features plus typically configured options.
451 - opt: complete list of optional features.
452 - maxmem: maximum configurable memory in 16-bit words.
453
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
458 user.
459 */
460
461 struct FEATURE_TABLE { /* CPU model feature table: */
462 uint32 typ; /* - typical features */
463 uint32 opt; /* - optional features */
464 uint32 maxmem; /* - maximum memory */
465 };
466
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,
470 32768 },
471 { UNIT_DMA, /* UNIT_2115 */
472 UNIT_PFAIL | UNIT_DMA | UNIT_EAU,
473 8192 },
474 { UNIT_DMA, /* UNIT_2114 */
475 UNIT_PFAIL | UNIT_DMA,
476 16384 },
477 { 0, 0, 0 },
478 { UNIT_PFAIL | UNIT_MP | UNIT_DMA | UNIT_EAU, /* UNIT_2100 */
479 UNIT_DMA | UNIT_FP | UNIT_IOP | UNIT_FFP,
480 32768 },
481 { 0, 0, 0 },
482 { 0, 0, 0 },
483 { 0, 0, 0 },
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,
487 1048576 },
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,
491 1048576 },
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,
496 1048576 }
497 };
498
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[];
508
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);
537
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);
542
543 /* CPU data structures
544
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
550 */
551
552 UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 0) };
553
554 REG cpu_reg[] = {
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 },
593 { NULL }
594 };
595
596 /* CPU modifier table.
597
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. */
601
602 MTAB cpu_mod[] = {
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" },
611
612 #if defined (HAVE_INT64)
613 { UNIT_MODEL_MASK, UNIT_1000_F, "", "1000-F", &cpu_set_model, &cpu_show_model, "1000-F" },
614 #endif
615
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 },
618
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 },
622
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 },
626
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 },
630
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 },
634
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 },
638
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 },
642
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 },
645
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 },
648
649 { UNIT_EMA_VMA, 0, "no EMA/VMA", NULL, &cpu_set_opt, NULL, NULL },
650
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 },
655
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 },
659 #endif
660
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 },
665 */
666
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 },
678 { 0 }
679 };
680
681 DEBTAB cpu_deb[] = {
682 { "OS", DEB_OS },
683 { "OSTBG", DEB_OSTBG },
684 { "VMA", DEB_VMA },
685 { "EMA", DEB_EMA },
686 { "VIS", DEB_VIS },
687 { "SIG", DEB_SIG },
688 { NULL, 0 }
689 };
690
691 DEVICE cpu_dev = {
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,
696 NULL, DEV_DEBUG,
697 0, cpu_deb, NULL, NULL
698 };
699
700 /* Memory protect data structures
701
702 mp_dev MP device descriptor
703 mp_unit MP unit descriptor
704 mp_reg MP register list
705 mp_mod MP modifiers list
706 */
707
708 UNIT mp_unit = { UDATA (NULL, UNIT_MP_SEL1, 0) }; /* default is JSB in, INT in, SEL1 out */
709
710 REG mp_reg[] = {
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) },
718 { NULL }
719 };
720
721 MTAB mp_mod[] = {
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 },
728 { 0 }
729 };
730
731 DEVICE mp_dev = {
732 "MP", &mp_unit, mp_reg, mp_mod,
733 1, 8, 1, 1, 8, 16,
734 NULL, NULL, &mp_reset,
735 NULL, NULL, NULL,
736 NULL, DEV_DISABLE | DEV_DIS
737 };
738
739 /* DMA controller data structures
740
741 dmax_dev DMAx device descriptor
742 dmax_reg DMAx register list
743 */
744
745 UNIT dma0_unit = { UDATA (NULL, 0, 0) };
746
747 REG dma0_reg[] = {
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) },
759 { NULL }
760 };
761
762 DEVICE dma0_dev = {
763 "DMA0", &dma0_unit, dma0_reg, NULL,
764 1, 8, 1, 1, 8, 16,
765 NULL, NULL, &dma0_reset,
766 NULL, NULL, NULL,
767 NULL, DEV_DISABLE
768 };
769
770 UNIT dma1_unit = { UDATA (NULL, 0, 0) };
771
772 REG dma1_reg[] = {
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) },
784 { NULL }
785 };
786
787 DEVICE dma1_dev = {
788 "DMA1", &dma1_unit, dma1_reg, NULL,
789 1, 8, 1, 1, 8, 16,
790 NULL, NULL, &dma1_reset,
791 NULL, NULL, NULL,
792 NULL, DEV_DISABLE
793 };
794
795 /* Interrupt defer table (1000 version) */
796
797 static int32 defer_tab[] = { 0, 1, 1, 1, 0, 0, 0, 1 };
798
799 /* Device dispatch table */
800
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);
809
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
819 };
820
821 t_stat sim_instr (void)
822 {
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 */
829 int abortval;
830
831 /* Restore register state */
832
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 */
837 reason = 0;
838
839 /* Restore I/O state */
840
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;
844 else {
845 dtab[DMA0] = &dmpio; /* set up DMA0 dispatch */
846 dtab[DMALT0] = &dmsio;
847 }
848 if (dma1_dev.flags & DEV_DIS) dtab[DMA1] = dtab[DMALT1] = NULL;
849 else {
850 dtab[DMA1] = &dmpio; /* set up DMA1 dispatch */
851 dtab[DMALT1] = &dmsio;
852 }
853
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 */
872 }
873 }
874
875 /* Configure interrupt deferral table */
876
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 */
881
882 /* Abort handling
883
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.
889 */
890
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 */
895 }
896 dmarq = calc_dma (); /* recalc DMA masks */
897 intrq = calc_int (); /* recalc interrupts */
898
899 /* Main instruction fetch/decode loop */
900
901 while (reason == 0) { /* loop until halted */
902 uint32 IR, MA, absel, v1, t, skip;
903
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 */
908 }
909
910 if (dmarq) {
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 */
915 }
916
917 if (intrq && ion_defer) /* interrupt pending but deferred? */
918 ion_defer = calc_defer (); /* confirm deferral */
919
920 /* (From Dave Bryan)
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
926 92851-90001) says:
927
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."
930 */
931
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 */
942 }
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 */
952 }
953
954 else { /* normal instruction */
955 iotrap = 0;
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 */
962 break;
963 }
964 if (mp_evrff) mp_viol = PC; /* if ok, upd mp_viol */
965 IR = ReadW (PC); /* fetch instr */
966 PC = (PC + 1) & VAMASK;
967 ion_defer = 0;
968 }
969
970 sim_interval = sim_interval - 1; /* count instruction */
971
972 /* Instruction decode. The 21MX does a 256-way decode on IR<15:8>
973
974 15 14 13 12 11 10 09 08 instruction
975
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
979 1 0 0 0 x 1 x x IO
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) */
986
987 absel = (IR & I_AB)? 1: 0; /* get A/B select */
988 switch ((IR >> 8) & 0377) { /* decode IR<15:8> */
989
990 /* Memory reference instructions */
991
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);
998 break;
999
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).
1005
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.
1013
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.
1019 */
1020
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 */
1024
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 */
1028
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 */
1032
1033 WriteW (MA, PC); /* store PC */
1034 PCQ_ENTRY;
1035 PC = (MA + 1) & VAMASK; /* jump */
1036 break;
1037
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);
1044 break;
1045
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 */
1049
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 */
1054 PCQ_ENTRY;
1055 PC = MA; /* jump */
1056 break;
1057
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);
1064 break;
1065
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;
1072 WriteW (MA, t);
1073 if (t == 0) PC = (PC + 1) & VAMASK;
1074 break;
1075
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 */
1081 v1 = ReadW (MA);
1082 t = AR + v1;
1083 if (t > DMASK) E = 1;
1084 if (((~AR ^ v1) & (AR ^ t)) & SIGN) O = 1;
1085 AR = t & DMASK;
1086 break;
1087
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 */
1093 v1 = ReadW (MA);
1094 t = BR + v1;
1095 if (t > DMASK) E = 1;
1096 if (((~BR ^ v1) & (BR ^ t)) & SIGN) O = 1;
1097 BR = t & DMASK;
1098 break;
1099
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;
1106 break;
1107
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;
1114 break;
1115
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 */
1121 AR = ReadW (MA);
1122 break;
1123
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 */
1129 BR = ReadW (MA);
1130 break;
1131
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 */
1137 WriteW (MA, AR);
1138 break;
1139
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 */
1145 WriteW (MA, BR);
1146 break;
1147
1148 /* Alter/skip instructions */
1149
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;
1168 if (t == 0) E = 1;
1169 if (t == SIGN) O = 1;
1170 }
1171 if ((IR & 000002) && (t != 0)) skip = 1; /* SZx,RSS */
1172 if ((IR & 000072) == 0) skip = 1; /* RSS */
1173 } /* end if RSS */
1174 else {
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;
1184 if (t == 0) E = 1;
1185 if (t == SIGN) O = 1;
1186 }
1187 if ((IR & 000002) && (t == 0)) skip = 1; /* SZx */
1188 } /* end if ~RSS */
1189 ABREG[absel] = t; /* store result */
1190 PC = (PC + skip) & VAMASK; /* add in skip */
1191 break; /* end if alter/skip */
1192
1193 /* Shift instructions */
1194
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 */
1203
1204 /* I/O instructions */
1205
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 */
1210
1211 /* Extended arithmetic */
1212
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 */
1219 break;
1220
1221 /* Extended instructions */
1222
1223 case 0212: /* UIG 0 extension */
1224 reason = cpu_uig_0 (IR, intrq, iotrap); /* extended opcode */
1225 break;
1226
1227 case 0203: /* UIG 1 extension */
1228 case 0213:
1229 reason = cpu_uig_1 (IR, intrq, iotrap); /* extended opcode */
1230 break;
1231 } /* end case IR */
1232
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 */
1237 }
1238
1239 else if (reason == NOTE_INDINT) { /* intr pend during indir? */
1240 PC = err_PC; /* back out of inst */
1241 reason = 0; /* continue */
1242 }
1243 } /* end while */
1244
1245 /* Simulation halted */
1246
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? */
1261 dev = dibp->devno;
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);
1267 }
1268 }
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');
1274 return reason;
1275 }
1276
1277 /* Resolve indirect addresses.
1278
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.
1282
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.
1289 */
1290
1291 t_stat resolve (uint32 MA, uint32 *addr, uint32 irq)
1292 {
1293 uint32 i;
1294 t_bool pending = (irq && !(mp_unit.flags & DEV_DIS));
1295 t_bool int_enable = ((mp_unit.flags & UNIT_MP_INT) && CTL(PRO));
1296
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 */
1303 }
1304 MA = ReadW (MA & VAMASK); /* follow address chain */
1305 }
1306 if (MA & I_IA) return STOP_IND; /* indirect loop? */
1307 *addr = MA;
1308 return SCPE_OK;
1309 }
1310
1311 /* Get effective address from IR */
1312
1313 t_stat Ea (uint32 IR, uint32 *addr, uint32 irq)
1314 {
1315 uint32 MA;
1316
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 */
1320 }
1321
1322 /* Shift micro operation */
1323
1324 uint32 shift (uint32 t, uint32 flag, uint32 op)
1325 {
1326 uint32 oldE;
1327
1328 op = op & 07; /* get shift op */
1329 if (flag) { /* enabled? */
1330 switch (op) { /* case on operation */
1331
1332 case 00: /* signed left shift */
1333 return ((t & SIGN) | ((t << 1) & 077777));
1334
1335 case 01: /* signed right shift */
1336 return ((t & SIGN) | (t >> 1));
1337
1338 case 02: /* rotate left */
1339 return (((t << 1) | (t >> 15)) & DMASK);
1340
1341 case 03: /* rotate right */
1342 return (((t >> 1) | (t << 15)) & DMASK);
1343
1344 case 04: /* left shift, 0 sign */
1345 return ((t << 1) & 077777);
1346
1347 case 05: /* ext right rotate */
1348 oldE = E;
1349 E = t & 1;
1350 return ((t >> 1) | (oldE << 15));
1351
1352 case 06: /* ext left rotate */
1353 oldE = E;
1354 E = (t >> 15) & 1;
1355 return (((t << 1) | oldE) & DMASK);
1356
1357 case 07: /* rotate left four */
1358 return (((t << 4) | (t >> 12)) & DMASK);
1359 } /* end case */
1360 } /* end if */
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 */
1364 }
1365
1366 /* I/O instruction decode.
1367
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.
1372
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).
1376 */
1377
1378 t_stat iogrp (uint32 ir, uint32 iotrap)
1379 {
1380 uint32 dev, sop, iodata, iostat, ab;
1381
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 */
1389 ABORT (ABORT_PRO);
1390 }
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 */
1398 return STOP_HALT;
1399 }
1400 iostat = iodata >> IOT_V_REASON;
1401 if (iostat == SCPE_OK) return NOTE_IOG; /* normal status */
1402 else return iostat; /* abnormal status */
1403 }
1404
1405 /* Device dispatch */
1406
1407 uint32 devdisp (uint32 devno, uint32 inst, uint32 IR, uint32 dat)
1408 {
1409 if (dtab[devno]) return dtab[devno] (inst, IR, dat);
1410 else return nulio (inst, IR, dat);
1411 }
1412
1413 /* Calculate DMA requests */
1414
1415 uint32 calc_dma (void)
1416 {
1417 uint32 r = 0;
1418
1419 if (CMD (DMA0) && SRQ (dmac[0].cw1 & I_DEVMASK)) /* check DMA0 cycle */
1420 r = r | DMAR0;
1421 if (CMD (DMA1) && SRQ (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */
1422 r = r | DMAR1;
1423 return r;
1424 }
1425
1426 /* Determine whether a pending interrupt deferral should be inhibited.
1427
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.
1431
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.
1436
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.
1441 */
1442
1443 uint32 calc_defer (void)
1444 {
1445 uint16 IR;
1446
1447 if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx series? */
1448 IR = ReadW (PC); /* prefetch next instr */
1449
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 */
1454 else
1455 return 1; /* no, so allow deferral */
1456 }
1457 else
1458 return 1; /* 1000 always allows deferral */
1459 }
1460
1461 /* Calculate interrupt requests
1462
1463 This routine takes into account all the relevant state of the
1464 interrupt system: ion, dev_flg, dev_fbf, and dev_ctl.
1465
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,
1478 if any.
1479 */
1480
1481 uint32 calc_int (void)
1482 {
1483 int32 j, lomask, mask[2], req[2];
1484
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];
1497 }
1498 else req[1] = 0;
1499 }
1500 else {
1501 req[0] = req[0] & (INT_M (PWR) | INT_M (PRO));
1502 req[1] = 0;
1503 }
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;
1507 }
1508 }
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);
1512 }
1513 }
1514 return 0;
1515 }
1516
1517 /* Memory access routines */
1518
1519 uint8 ReadB (uint32 va)
1520 {
1521 int32 pa;
1522
1523 if (dms_enb) pa = dms (va >> 1, dms_ump, RD);
1524 else pa = va >> 1;
1525 if (va & 1) return (ReadPW (pa) & 0377);
1526 else return ((ReadPW (pa) >> 8) & 0377);
1527 }
1528
1529 uint8 ReadBA (uint32 va)
1530 {
1531 uint32 pa;
1532
1533 if (dms_enb) pa = dms (va >> 1, dms_ump ^ MAP_LNT, RD);
1534 else pa = va >> 1;
1535 if (va & 1) return (ReadPW (pa) & 0377);
1536 else return ((ReadPW (pa) >> 8) & 0377);
1537 }
1538
1539 uint16 ReadW (uint32 va)
1540 {
1541 uint32 pa;
1542
1543 if (dms_enb) pa = dms (va, dms_ump, RD);
1544 else pa = va;
1545 return ReadPW (pa);
1546 }
1547
1548 uint16 ReadWA (uint32 va)
1549 {
1550 uint32 pa;
1551
1552 if (dms_enb) pa = dms (va, dms_ump ^ MAP_LNT, RD);
1553 else pa = va;
1554 return ReadPW (pa);
1555 }
1556
1557 uint16 ReadIO (uint32 va, uint32 map)
1558 {
1559 uint32 pa;
1560
1561 if (dms_enb) pa = dms_io (va, map);
1562 else pa = va;
1563 return M[pa];
1564 }
1565
1566 uint16 ReadPW (uint32 pa)
1567 {
1568 if (pa <= 1) return ABREG[pa];
1569 return M[pa];
1570 }
1571
1572 uint16 ReadTAB (uint32 addr)
1573 {
1574 if (addr == 0) return saved_AR;
1575 else if (addr == 1) return saved_BR;
1576 else return ReadIO (addr, dms_ump);
1577 }
1578
1579 /* Memory protection test for writes
1580
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).
1587 */
1588
1589 #define MP_TEST(x) (CTL (PRO) && ((x) > 1) && ((x) < mp_fence))
1590
1591 void WriteB (uint32 va, uint32 dat)
1592 {
1593 uint32 pa, t;
1594
1595 if (dms_enb) pa = dms (va >> 1, dms_ump, WR);
1596 else pa = va >> 1;
1597 if (MP_TEST (va >> 1)) ABORT (ABORT_PRO);
1598 if (MEM_ADDR_OK (pa)) {
1599 t = ReadPW (pa);
1600 if (va & 1) t = (t & 0177400) | (dat & 0377);
1601 else t = (t & 0377) | ((dat & 0377) << 8);
1602 WritePW (pa, t);
1603 }
1604 return;
1605 }
1606
1607 void WriteBA (uint32 va, uint32 dat)
1608 {
1609 uint32 pa, t;
1610
1611 if (dms_enb) {
1612 dms_viol (va >> 1, MVI_WPR); /* viol if prot */
1613 pa = dms (va >> 1, dms_ump ^ MAP_LNT, WR);
1614 }
1615 else pa = va >> 1;
1616 if (MP_TEST (va >> 1)) ABORT (ABORT_PRO);
1617 if (MEM_ADDR_OK (pa)) {
1618 t = ReadPW (pa);
1619 if (va & 1) t = (t & 0177400) | (dat & 0377);
1620 else t = (t & 0377) | ((dat & 0377) << 8);
1621 WritePW (pa, t);
1622 }
1623 return;
1624 }
1625
1626 void WriteW (uint32 va, uint32 dat)
1627 {
1628 uint32 pa;
1629
1630 if (dms_enb) pa = dms (va, dms_ump, WR);
1631 else pa = va;
1632 if (MP_TEST (va)) ABORT (ABORT_PRO);
1633 if (MEM_ADDR_OK (pa)) WritePW (pa, dat);
1634 return;
1635 }
1636
1637 void WriteWA (uint32 va, uint32 dat)
1638 {
1639 int32 pa;
1640
1641 if (dms_enb) {
1642 dms_viol (va, MVI_WPR); /* viol if prot */
1643 pa = dms (va, dms_ump ^ MAP_LNT, WR);
1644 }
1645 else pa = va;
1646 if (MP_TEST (va)) ABORT (ABORT_PRO);
1647 if (MEM_ADDR_OK (pa)) WritePW (pa, dat);
1648 return;
1649 }
1650
1651 void WriteIO (uint32 va, uint32 dat, uint32 map)
1652 {
1653 uint32 pa;
1654
1655 if (dms_enb) pa = dms_io (va, map);
1656 else pa = va;
1657 if (MEM_ADDR_OK (pa)) M[pa] = dat & DMASK;
1658 return;
1659 }
1660
1661 void WritePW (uint32 pa, uint32 dat)
1662 {
1663 if (pa <= 1) ABREG[pa] = dat & DMASK;
1664 else M[pa] = dat & DMASK;
1665 return;
1666 }
1667
1668 /* DMS relocation for CPU access */
1669
1670 uint32 dms (uint32 va, uint32 map, uint32 prot)
1671 {
1672 uint32 pgn, mpr;
1673
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 */
1683 }
1684 }
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));
1688 }
1689
1690 /* DMS relocation for IO access */
1691
1692 uint32 dms_io (uint32 va, uint32 map)
1693 {
1694 uint32 pgn, mpr;
1695
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 */
1704 }
1705 }
1706 mpr = dms_map[map + pgn]; /* get map reg */
1707 return (MAP_GETPAG (mpr) | VA_GETOFF (va));
1708 }
1709
1710 /* DMS relocation for console access */
1711
1712 uint32 dms_cons (uint32 va, int32 sw)
1713 {
1714 uint32 map_sel;
1715
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 */
1727 }
1728
1729 /* Mem protect and DMS validation for jumps */
1730
1731 void mp_dms_jmp (uint32 va)
1732 {
1733 uint32 pgn = VA_GETPAG (va); /* get page num */
1734
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 */
1742 }
1743 }
1744 if (CTL (PRO) && (va < mp_fence)) ABORT (ABORT_PRO); /* base page MPR */
1745 return;
1746 }
1747
1748 /* DMS read and write maps */
1749
1750 uint16 dms_rmap (uint32 mapi)
1751 {
1752 mapi = mapi & MAP_MASK;
1753 return (dms_map[mapi] & ~MAP_MBZ);
1754 }
1755
1756 void dms_wmap (uint32 mapi, uint32 dat)
1757 {
1758 mapi = mapi & MAP_MASK;
1759 dms_map[mapi] = (uint16) (dat & ~MAP_MBZ);
1760 return;
1761 }
1762
1763 /* DMS violation */
1764
1765 void dms_viol (uint32 va, uint32 st)
1766 {
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 */
1774 }
1775 return;
1776 }
1777
1778 /* DMS update status */
1779
1780 uint32 dms_upd_sr (void)
1781 {
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;
1786 return dms_sr;
1787 }
1788
1789 /* Device 0 (CPU) I/O routine
1790
1791 NOTE: LIx/MIx reads floating I/O bus (0 on all machines).
1792
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).
1796
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":
1801
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)."
1804
1805 ...and in section 5.8, "Parity Error Detection":
1806
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
1812 turn it off."
1813 */
1814
1815 int32 cpuio (int32 inst, int32 IR, int32 dat)
1816 {
1817 int i;
1818
1819 switch (inst) { /* case on opcode */
1820
1821 case ioFLG: /* flag */
1822 ion = (IR & I_HC)? 0: 1; /* interrupts off/on */
1823 return dat;
1824
1825 case ioSFC: /* skip flag clear */
1826 if (!ion) PC = (PC + 1) & VAMASK;
1827 break;
1828
1829 case ioSFS: /* skip flag set */
1830 if (ion) PC = (PC + 1) & VAMASK;
1831 break;
1832
1833 case ioLIX: /* load */
1834 dat = 0; /* returns 0 */
1835 break;
1836
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 */
1841 break;
1842
1843 default:
1844 break;
1845 }
1846
1847 if (IR & I_HC) ion = 0; /* HC option */
1848 return dat;
1849 }
1850
1851 /* Device 1 (overflow/S-register) I/O routine
1852
1853 NOTE: The S register is read-only on the 2115/2116. It is read/write on
1854 the 2114, 2100, and 1000.
1855 */
1856
1857 int32 ovfio (int32 inst, int32 IR, int32 dat)
1858 {
1859 switch (inst) { /* case on opcode */
1860
1861 case ioFLG: /* flag */
1862 O = (IR & I_HC)? 0: 1; /* clear/set overflow */
1863 return dat;
1864
1865 case ioSFC: /* skip flag clear */
1866 if (!O) PC = (PC + 1) & VAMASK;
1867 break; /* can clear flag */
1868
1869 case ioSFS: /* skip flag set */
1870 if (O) PC = (PC + 1) & VAMASK;
1871 break; /* can clear flag */
1872
1873 case ioMIX: /* merge */
1874 dat = dat | SR;
1875 break;
1876
1877 case ioLIX: /* load */
1878 dat = SR;
1879 break;
1880
1881 case ioOTX: /* output */
1882 if ((UNIT_CPU_MODEL != UNIT_2116) &&
1883 (UNIT_CPU_MODEL != UNIT_2115))
1884 SR = dat;
1885 break;
1886
1887 default:
1888 break;
1889 }
1890
1891 if (IR & I_HC) O = 0; /* HC option */
1892 return dat;
1893 }
1894
1895 /* Device 4 (power fail) I/O routine */
1896
1897 int32 pwrio (int32 inst, int32 IR, int32 dat)
1898 {
1899 switch (inst) { /* case on opcode */
1900
1901 case ioMIX: /* merge */
1902 dat = dat | intaddr;
1903 break;
1904
1905 case ioLIX: /* load */
1906 dat = intaddr;
1907 break;
1908
1909 default:
1910 break;
1911 }
1912
1913 return dat;
1914 }
1915
1916 /* Device 5 (memory protect) I/O routine
1917
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.
1921
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.
1926 */
1927
1928 int32 proio (int32 inst, int32 IR, int32 dat)
1929 {
1930 switch (inst) { /* case on opcode */
1931
1932 case ioSFC: /* skip flag clear */
1933 if (!mp_mevff) PC = (PC + 1) & VAMASK; /* skip if mem prot */
1934 break;
1935
1936 case ioSFS: /* skip flag set */
1937 if (mp_mevff) PC = (PC + 1) & VAMASK; /* skip if DMS */
1938 break;
1939
1940 case ioMIX: /* merge */
1941 dat = dat | mp_viol;
1942 break;
1943
1944 case ioLIX: /* load */
1945 dat = mp_viol;
1946 break;
1947
1948 case ioOTX: /* output */
1949 mp_fence = dat & VAMASK;
1950 if (cpu_unit.flags & UNIT_2100) iop_sp = mp_fence;
1951 break;
1952
1953 case ioCRS: /* control reset */
1954 case ioCTL: /* control clear/set */
1955 if ((IR & I_CTL) == 0) { /* STC */
1956 setCTL (PRO);
1957 dms_vr = 0;
1958 mp_evrff = 1; /* allow mp_viol upd */
1959 mp_mevff = 0; /* clear DMS flag */
1960 }
1961 break;
1962
1963 default:
1964 break;
1965 }
1966
1967 if (IR & I_HC) { clrFLG (PRO); } /* HC option */
1968 return dat;
1969 }
1970
1971 /* Devices 2,3 (secondary DMA) I/O routine.
1972
1973 Implements control word 2 (memory address) and control word 3 (word count).
1974
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
1978 counts.
1979
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.
1983 */
1984
1985 int32 dmsio (int32 inst, int32 IR, int32 dat)
1986 {
1987 int32 ch;
1988
1989 ch = IR & 1; /* get channel num */
1990 switch (inst) { /* case on opcode */
1991
1992 case ioLIX: /* load remaining word count */
1993 dat = 0;
1994
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 */
2000 else
2001 dat = dat | dmac[ch].cw3; /* rest use full value */
2002 break;
2003
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 */
2010 else
2011 dmac[ch].cw2 = dat; /* full address stored */
2012 break;
2013
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 */
2018 break;
2019
2020 default:
2021 break;
2022 }
2023
2024 return dat;
2025 }
2026
2027 /* Devices 6,7 (primary DMA) I/O routine
2028
2029 Implements control word 1 (device address) and DMA control.
2030
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.
2034
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.
2037
2038 NOTE: LIx/MIx reads floating S-bus (1 on 21MX, 0 on 211x/2100).
2039
2040 NOTE: CRS clears control and command flip-flops, whereas CLC clears only
2041 control.
2042 */
2043
2044 int32 dmpio (int32 inst, int32 IR, int32 dat)
2045 {
2046 int32 ch;
2047
2048 ch = IR & 1; /* get channel number */
2049
2050 switch (inst) { /* case on opcode */
2051
2052 case ioFLG: /* flag */
2053 if ((IR & I_HC) == 0) { /* set->abort */
2054 setFLG (DMA0 + ch); /* set flag */
2055 clrCMD (DMA0 + ch); /* clr cmd */
2056 }
2057 break;
2058
2059 case ioSFC: /* skip flag clear */
2060 if (FLG (DMA0 + ch) == 0) PC = (PC + 1) & VAMASK;
2061 break;
2062
2063 case ioSFS: /* skip flag set */
2064 if (FLG (DMA0 + ch) != 0) PC = (PC + 1) & VAMASK;
2065 break;
2066
2067 case ioLIX: /* load */
2068 dat = 0;
2069
2070 case ioMIX: /* merge */
2071 if (UNIT_CPU_TYPE == UNIT_TYPE_1000)
2072 dat = DMASK;
2073 break;
2074
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 */
2082 break;
2083
2084 case ioCRS: /* control reset */
2085 clrCMD (DMA0 + ch); /* clear command flip-flop */
2086
2087 case ioCTL: /* control */
2088 if (IR & I_CTL) { clrCTL (DMA0 + ch); } /* CLC: cmd unchgd */
2089 else { /* STC */
2090 if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* slow DMA card? */
2091 dmac[ch].latency = 1; /* needs startup latency */
2092 else
2093 dmac[ch].latency = 0; /* DCPC starts immediately */
2094
2095 dmac[ch].packer = 0; /* clear packing register */
2096 setCTL (DMA0 + ch); /* set ctl, cmd */
2097 setCMD (DMA0 + ch);
2098 }
2099 break;
2100
2101 default:
2102 break;
2103 }
2104
2105 if (IR & I_HC) { clrFLG (DMA0 + ch); } /* HC option */
2106 return dat;
2107 }
2108
2109 /* DMA cycle routine
2110
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.
2114
2115 The last cycle (word count reaches 0) logic is quite tricky.
2116 Input cases:
2117 - CLC requested: issue CLC
2118 Output cases:
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)
2124 */
2125
2126 void dma_cycle (uint32 ch, uint32 map)
2127 {
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 */
2131
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 */
2135 }
2136
2137 dev = dmac[ch].cw1 & I_DEVMASK; /* get device */
2138 MA = dmac[ch].cw2 & VAMASK; /* get mem addr */
2139
2140 if (inp) { /* input cycle? */
2141 temp = devdisp (dev, ioLIX, dev, 0); /* do LIA dev */
2142
2143 if (byt) { /* byte packing? */
2144 if (dmac[ch].packer & DMA_OE) { /* second byte? */
2145 temp = (dmac[ch].packer << 8) | /* merge stored byte */
2146 (temp & DMASK8);
2147 WriteIO (MA, temp, map); /* store word data */
2148 }
2149 else /* first byte */
2150 dmac[ch].packer = (temp & DMASK8); /* save it */
2151
2152 dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */
2153 }
2154 else /* no byte packing */
2155 WriteIO (MA, temp, map); /* store word data */
2156 }
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 */
2161
2162 else { /* first byte */
2163 dmac[ch].packer = ReadIO (MA, map); /* read word data */
2164 temp = (dmac[ch].packer >> 8) & DMASK8; /* get high byte */
2165 }
2166
2167 dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */
2168 }
2169 else /* no byte packing */
2170 temp = ReadIO (MA, map); /* read word data */
2171
2172 devdisp (dev, ioOTX, dev, temp); /* do OTA dev */
2173 }
2174
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 */
2179 }
2180
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 */
2185 }
2186 else {
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 */
2190 } /* end input */
2191 else { /* output */
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 */
2198 } /* end output */
2199 setFLG (DMA0 + ch); /* set DMA flg */
2200 clrCMD (DMA0 + ch); /* clr DMA cmd */
2201 devdisp (dev, ioEDT, dev, inp | ch); /* do EDT */
2202 }
2203 return;
2204 }
2205
2206 /* Unimplemented device routine
2207
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).
2210 */
2211
2212 int32 nulio (int32 inst, int32 IR, int32 dat)
2213 {
2214 int32 devd;
2215
2216 devd = IR & I_DEVMASK; /* get device no */
2217 switch (inst) { /* case on opcode */
2218
2219 case ioSFC: /* skip flag clear */
2220 PC = (PC + 1) & VAMASK;
2221 break;
2222
2223 case ioLIX: /* load */
2224 dat = 0;
2225
2226 case ioMIX: /* merge */
2227 if ((devd < VARDEV) && (UNIT_CPU_TYPE == UNIT_TYPE_1000))
2228 dat = DMASK;
2229 break;
2230
2231 default:
2232 break;
2233 }
2234
2235 return (stop_dev << IOT_V_REASON) | dat;
2236 }
2237
2238 /* Reset routines */
2239
2240 t_stat cpu_reset (DEVICE *dptr)
2241 {
2242 E = 0;
2243 O = 0;
2244 ion = ion_defer = 0;
2245 clrCMD (PWR);
2246 clrCTL (PWR);
2247 clrFLG (PWR);
2248 clrFBF (PWR);
2249 dev_srq[0] = dev_srq[0] & ~M_FXDEV;
2250 dms_enb = dms_ump = 0; /* init DMS */
2251 dms_sr = 0;
2252 dms_vr = 0;
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 */
2256
2257 if (M == NULL) { /* initial call? */
2258 M = calloc (PASIZE, sizeof (uint16)); /* alloc mem */
2259
2260 if (M == NULL) /* alloc fail? */
2261 return SCPE_MEM;
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 */
2270 }
2271 }
2272
2273 if (pcq_r) pcq_r->qptr = 0;
2274 else return SCPE_IERR;
2275 return SCPE_OK;
2276 }
2277
2278 t_stat mp_reset (DEVICE *dptr)
2279 {
2280 clrCTL (PRO);
2281 clrFLG (PRO);
2282 clrFBF (PRO);
2283 mp_fence = 0; /* init mprot */
2284 mp_viol = 0;
2285 mp_mevff = 0;
2286 mp_evrff = 1;
2287 return SCPE_OK;
2288 }
2289
2290 t_stat dma0_reset (DEVICE *tptr)
2291 {
2292 if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */
2293 hp_enbdis_pair (&dma0_dev, &dma1_dev); /* make pair cons */
2294 clrCMD (DMA0);
2295 clrCTL (DMA0);
2296 setFLG (DMA0);
2297 clrSRQ (DMA0);
2298 clrCTL (DMALT0);
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;
2302 return SCPE_OK;
2303 }
2304
2305 t_stat dma1_reset (DEVICE *tptr)
2306 {
2307 if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */
2308 hp_enbdis_pair (&dma1_dev, &dma0_dev); /* make pair cons */
2309 clrCMD (DMA1);
2310 clrCTL (DMA1);
2311 setFLG (DMA1);
2312 clrSRQ (DMA1);
2313 clrCTL (DMALT1);
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;
2317 return SCPE_OK;
2318 }
2319
2320 /* Memory examine */
2321
2322 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
2323 {
2324 int32 d;
2325
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;
2332 else d = M[addr];
2333 if (vptr != NULL) *vptr = d & DMASK;
2334 return SCPE_OK;
2335 }
2336
2337 /* Memory deposit */
2338
2339 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
2340 {
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;
2348 return SCPE_OK;
2349 }
2350
2351 /* Set device number */
2352
2353 t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc)
2354 {
2355 DEVICE *dptr = (DEVICE *) desc;
2356 DIB *dibp;
2357 int32 i, newdev;
2358 t_stat r;
2359
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;
2368 return SCPE_OK;
2369 }
2370
2371 /* Show device number */
2372
2373 t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc)
2374 {
2375 DEVICE *dptr = (DEVICE *) desc;
2376 DIB *dibp;
2377 int32 i;
2378
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);
2384 return SCPE_OK;
2385 }
2386
2387 /* Make a pair of devices consistent */
2388
2389 void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp)
2390 {
2391 if (ccp->flags & DEV_DIS) dcp->flags = dcp->flags | DEV_DIS;
2392 else dcp->flags = dcp->flags & ~DEV_DIS;
2393 return;
2394 }
2395
2396 /* VM command post-processor
2397
2398 Update T register to contents of memory addressed by M register
2399 if M register has changed. */
2400
2401 void hp_post_cmd (t_bool from_scp)
2402 {
2403 if (MR != saved_MR) { /* M changed since last update? */
2404 saved_MR = MR;
2405 TR = ReadTAB (MR); /* sync T with new M */
2406 }
2407 return;
2408 }
2409
2410 /* Test for device conflict */
2411
2412 t_bool dev_conflict (void)
2413 {
2414 DEVICE *dptr;
2415 DIB *dibp;
2416 uint32 i, j, k;
2417 t_bool is_conflict = FALSE;
2418 uint32 conflicts[I_DEVMASK + 1] = { 0 };
2419
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)
2424 is_conflict = TRUE;
2425 }
2426
2427 if (is_conflict) {
2428 sim_ttcmd();
2429 for (i = 0; i <= I_DEVMASK; i++) {
2430 if (conflicts[i] > 1) {
2431 k = conflicts[i];
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]) {
2438 printf (" and");
2439 if (sim_log) fputs (" and", sim_log);
2440 }
2441 printf (" %s", sim_dname (dptr));
2442 if (sim_log) fprintf (sim_log, " %s", sim_dname (dptr));
2443 k = k - 1;
2444 if (k == 0) {
2445 putchar ('\n');
2446 if (sim_log) fputc ('\n', sim_log);
2447 break;
2448 }
2449 }
2450 }
2451 }
2452 }
2453 }
2454 return is_conflict;
2455 }
2456
2457 /* Change CPU memory size.
2458
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.
2461
2462 Validation:
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.
2466 */
2467
2468 t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc)
2469 {
2470 int32 mc = 0;
2471 uint32 i;
2472 uint32 model = CPU_MODEL_INDEX; /* current CPU model index */
2473 uint32 old_size = MEMSIZE; /* current memory size */
2474
2475 if ((uint32) new_size > cpu_features[model].maxmem)
2476 return SCPE_NOFNC; /* mem size unsupported */
2477
2478 if ((new_size <= 0) || (new_size > PASIZE) || ((new_size & 07777) != 0))
2479 return SCPE_NXM; /* invalid size (prog err) */
2480
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)))
2484 return SCPE_INCOMP;
2485 }
2486
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 */
2491 }
2492 else /* loader unsupported */
2493 fwanxm = MEMSIZE = new_size; /* set new memory size */
2494
2495 for (i = fwanxm; i < old_size; i++) M[i] = 0; /* zero non-existent memory */
2496 return SCPE_OK;
2497 }
2498
2499 /* Change CPU models.
2500
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.
2504
2505 Validation:
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.
2510 */
2511
2512 t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc)
2513 {
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 */
2517 uint32 new_memsize;
2518 t_stat result;
2519
2520 cpu_unit.flags = cpu_unit.flags & ~UNIT_OPTS | /* set typical features */
2521 cpu_features[new_index].typ & UNIT_OPTS; /* mask pseudo-opts */
2522
2523
2524 if (cpu_features[new_index].typ & UNIT_MP) /* MP in typ config? */
2525 mp_dev.flags = mp_dev.flags & ~DEV_DIS; /* enable it */
2526 else
2527 mp_dev.flags = mp_dev.flags | DEV_DIS; /* disable it */
2528
2529 if (cpu_features[new_index].opt & UNIT_MP) /* MP an option? */
2530 mp_dev.flags = mp_dev.flags | DEV_DISABLE; /* make it alterable */
2531 else
2532 mp_dev.flags = mp_dev.flags & ~DEV_DISABLE; /* make it unalterable */
2533
2534
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 */
2537
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 */
2542 }
2543 else {
2544 dma0_dev.flags = dma0_dev.flags | DEV_DIS; /* disable channel 0 */
2545 dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */
2546 }
2547
2548 if (cpu_features[new_index].opt & UNIT_DMA) { /* DMA an option? */
2549 dma0_dev.flags = dma0_dev.flags | DEV_DISABLE; /* make it alterable */
2550
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 */
2555 }
2556 else {
2557 dma0_dev.flags = dma0_dev.flags & ~DEV_DISABLE; /* make it unalterable */
2558 dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */
2559 }
2560
2561
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);
2566 }
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 */
2571 }
2572
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 */
2576 else
2577 new_memsize = MEMSIZE; /* or leave it unchanged */
2578
2579 result = cpu_set_size (uptr, new_memsize, NULL, NULL); /* set memory size */
2580
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 */
2584 else
2585 fwanxm = MEMSIZE; /* loader reserved only for 21xx */
2586
2587 return result;
2588 }
2589
2590 /* Display the CPU model and optional loader status.
2591
2592 Loader status is displayed for 21xx models and suppressed for 1000 models.
2593 */
2594
2595 t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc)
2596 {
2597 fputs ((char *) desc, st); /* write model name */
2598
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 */
2602 else
2603 fputs (", loader enabled", st); /* no, so access enabled */
2604 return SCPE_OK;
2605 }
2606
2607 /* Set a CPU option.
2608
2609 Validation:
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).
2614 */
2615
2616 t_stat cpu_set_opt (UNIT *uptr, int32 option, char *cptr, void *desc)
2617 {
2618 uint32 model = CPU_MODEL_INDEX; /* current CPU model index */
2619
2620 if ((cpu_features[model].opt & option) == 0) /* option supported? */
2621 return SCPE_NOFNC; /* no */
2622
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);
2628
2629 if (option == UNIT_FFP) /* 2100 FFP option requires FP */
2630 uptr->flags = uptr->flags | UNIT_FP;
2631 }
2632
2633 return SCPE_OK;
2634 }
2635
2636 /* Clear a CPU option.
2637
2638 Validation:
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).
2643 */
2644
2645 t_bool cpu_clr_opt (UNIT *uptr, int32 option, char *cptr, void *desc)
2646 {
2647 uint32 model = CPU_MODEL_INDEX; /* current CPU model index */
2648
2649 if ((cpu_features[model].opt & option) == 0) /* option supported? */
2650 return SCPE_NOFNC; /* no */
2651
2652 uptr->flags = uptr->flags & ~option; /* disable option */
2653
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 */
2657
2658 return SCPE_OK;
2659 }
2660
2661 /* 21xx loader enable/disable function.
2662
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
2668 off.
2669
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
2672 switch.
2673
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.
2678
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.
2682
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.
2688 */
2689
2690 t_stat cpu_set_ldr (UNIT *uptr, int32 enable, char *cptr, void *desc)
2691 {
2692 static uint16 loader[IBL_LNT];
2693 int32 i;
2694 t_bool is_enabled = (fwanxm == MEMSIZE);
2695
2696 if ((UNIT_CPU_FAMILY != UNIT_FAMILY_21XX) || /* valid only for 21xx */
2697 (MEMSIZE == 0)) /* and for initialized memory */
2698 return SCPE_NOFNC;
2699
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 */
2705 }
2706 }
2707
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 */
2712 }
2713
2714 return SCPE_OK;
2715 }
2716
2717 /* IBL routine (CPU boot) */
2718
2719 t_stat cpu_boot (int32 unitno, DEVICE *dptr)
2720 {
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;
2725
2726 if (dev < 010) return SCPE_NOFNC;
2727 switch (sel) {
2728
2729 case 0: /* PTR boot */
2730 ibl_copy (ptr_rom, dev);
2731 break;
2732
2733 case 1: /* DP/DQ boot */
2734 ibl_copy (dq_rom, dev);
2735 break;
2736
2737 case 2: /* MS boot */
2738 ibl_copy (ms_rom, dev);
2739 break;
2740
2741 case 3: /* DS boot */
2742 ibl_copy (ds_rom,dev);
2743 break;
2744 }
2745
2746 return SCPE_OK;
2747 }
2748
2749 /* IBL boot ROM copy
2750
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
2754
2755 Notes:
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)
2759 */
2760
2761 t_stat ibl_copy (const uint16 pboot[IBL_LNT], int32 dev)
2762 {
2763 int32 i;
2764 uint16 wd;
2765
2766 cpu_set_ldr (NULL, TRUE, NULL, NULL); /* enable loader (ignore errors) */
2767
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 */
2777 }
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 */
2780 return SCPE_OK;
2781 }