First Commit of my working state
[simh.git] / HP2100 / hp2100_cpu.c
CommitLineData
196ba1fc
PH
1/* hp2100_cpu.c: HP 21xx CPU simulator\r
2\r
3 Copyright (c) 1993-2008, Robert M. Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 CPU 2114C/2115A/2116C/2100A/1000-M/E/F central processing unit\r
27 MP 12581A/12892B memory protect\r
28 DMA0,DMA1 12607B/12578A/12895A direct memory access controller\r
29 DCPC0,DCPC1 12897B dual channel port controller\r
30\r
31 30-Apr-08 JDB Enabled SIGNAL instructions, SIG debug flag\r
32 24-Apr-08 JDB Fixed single stepping through interrupts\r
33 20-Apr-08 JDB Enabled EMA and VIS, added EMA, VIS, and SIGNAL debug flags\r
34 03-Dec-07 JDB Memory ex/dep and bkpt type default to current map mode\r
35 26-Nov-07 JDB Added SET CPU DEBUG and OS/VMA flags, enabled OS/VMA\r
36 15-Nov-07 JDB Corrected MP W5 (JSB) jumper action, SET/SHOW reversal,\r
37 mp_mevff clear on interrupt with I/O instruction in trap cell\r
38 04-Nov-07 JDB Removed DBI support from 1000-M (was temporary for RTE-6/VM)\r
39 28-Apr-07 RMS Removed clock initialization\r
40 02-Mar-07 JDB EDT passes input flag and DMA channel in dat parameter\r
41 11-Jan-07 JDB Added 12578A DMA byte packing\r
42 28-Dec-06 JDB CLC 0 now sends CRS instead of CLC to devices\r
43 26-Dec-06 JDB Fixed improper IRQ deferral for 21xx CPUs\r
44 Fixed improper interrupt servicing in resolve\r
45 21-Dec-06 JDB Added 21xx loader enable/disable support\r
46 16-Dec-06 JDB Added 2114 and 2115 CPU options.\r
47 Added support for 12607B (2114) and 12578A (2115/6) DMA\r
48 01-Dec-06 JDB Added 1000-F CPU option (requires HAVE_INT64)\r
49 SHOW CPU displays 1000-M/E instead of 21MX-M/E\r
50 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c\r
51 12-Oct-06 JDB Fixed INDMAX off-by-one error in resolve\r
52 26-Sep-06 JDB Added iotrap parameter to UIG dispatchers for RTE microcode\r
53 12-Sep-06 JDB iogrp returns NOTE_IOG to recalc interrupts\r
54 resolve returns NOTE_INDINT to service held-off interrupt\r
55 16-Aug-06 JDB Added support for future microcode options, future F-Series\r
56 09-Aug-06 JDB Added double integer microcode, 1000-M/E synonyms\r
57 Enhanced CPU option validity checking\r
58 Added DCPC as a synonym for DMA for 21MX simulations\r
59 26-Dec-05 JDB Improved reporting in dev_conflict\r
60 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)\r
61 21-Jan-05 JDB Reorganized CPU option flags\r
62 15-Jan-05 RMS Split out EAU and MAC instructions\r
63 26-Dec-04 RMS DMA reset doesn't clear alternate CTL flop (from Dave Bryan)\r
64 DMA reset shouldn't clear control words (from Dave Bryan)\r
65 Alternate CTL flop not visible as register (from Dave Bryan)\r
66 Fixed CBS, SBS, TBS to perform virtual reads\r
67 Separated A/B from M[0/1] for DMA IO (from Dave Bryan)\r
68 Fixed bug in JPY (from Dave Bryan)\r
69 25-Dec-04 JDB Added SET CPU 21MX-M, 21MX-E (21MX defaults to MX-E)\r
70 TIMER/EXECUTE/DIAG instructions disabled for 21MX-M\r
71 T-register reflects changes in M-register when halted\r
72 25-Sep-04 JDB Moved MP into its own device; added MP option jumpers\r
73 Modified DMA to allow disabling\r
74 Modified SET CPU 2100/2116 to truncate memory > 32K\r
75 Added -F switch to SET CPU to force memory truncation\r
76 Fixed S-register behavior on 2116\r
77 Fixed LIx/MIx behavior for DMA on 2116 and 2100\r
78 Fixed LIx/MIx behavior for empty I/O card slots\r
79 Modified WRU to be REG_HRO\r
80 Added BRK and DEL to save console settings\r
81 Fixed use of "unsigned int16" in cpu_reset\r
82 Modified memory size routine to return SCPE_INCOMP if\r
83 memory size truncation declined\r
84 20-Jul-04 RMS Fixed bug in breakpoint test (reported by Dave Bryan)\r
85 Back up PC on instruction errors (from Dave Bryan)\r
86 14-May-04 RMS Fixed bugs and added features from Dave Bryan\r
87 - SBT increments B after store\r
88 - DMS console map must check dms_enb\r
89 - SFS x,C and SFC x,C work\r
90 - MP violation clears automatically on interrupt\r
91 - SFS/SFC 5 is not gated by protection enabled\r
92 - DMS enable does not disable mem prot checks\r
93 - DMS status inconsistent at simulator halt\r
94 - Examine/deposit are checking wrong addresses\r
95 - Physical addresses are 20b not 15b\r
96 - Revised DMS to use memory rather than internal format\r
97 - Added instruction printout to HALT message\r
98 - Added M and T internal registers\r
99 - Added N, S, and U breakpoints\r
100 Revised IBL facility to conform to microcode\r
101 Added DMA EDT I/O pseudo-opcode\r
102 Separated DMA SRQ (service request) from FLG\r
103 12-Mar-03 RMS Added logical name support\r
104 02-Feb-03 RMS Fixed last cycle bug in DMA output (found by Mike Gemeny)\r
105 22-Nov-02 RMS Added 21MX IOP support\r
106 24-Oct-02 RMS Fixed bugs in IOP and extended instructions\r
107 Fixed bugs in memory protection and DMS\r
108 Added clock calibration\r
109 25-Sep-02 RMS Fixed bug in DMS decode (found by Robert Alan Byer)\r
110 26-Jul-02 RMS Restructured extended instructions, added IOP support\r
111 22-Mar-02 RMS Changed to allocate memory array dynamically\r
112 11-Mar-02 RMS Cleaned up setjmp/auto variable interaction\r
113 17-Feb-02 RMS Added DMS support\r
114 Fixed bugs in extended instructions\r
115 03-Feb-02 RMS Added terminal multiplexor support\r
116 Changed PCQ macro to use unmodified PC\r
117 Fixed flop restore logic (found by Bill McDermith)\r
118 Fixed SZx,SLx,RSS bug (found by Bill McDermith)\r
119 Added floating point support\r
120 16-Jan-02 RMS Added additional device support\r
121 07-Jan-02 RMS Fixed DMA register tables (found by Bill McDermith)\r
122 07-Dec-01 RMS Revised to use breakpoint package\r
123 03-Dec-01 RMS Added extended SET/SHOW support\r
124 10-Aug-01 RMS Removed register in declarations\r
125 26-Nov-00 RMS Fixed bug in dual device number routine\r
126 21-Nov-00 RMS Fixed bug in reset routine\r
127 15-Oct-00 RMS Added dynamic device number support\r
128\r
129 References:\r
130 - 2100A Computer Reference Manual (02100-90001, Dec-1971)\r
131 - Model 2100A Computer Installation and Maintenance Manual\r
132 (02100-90002, Aug-1972)\r
133 - HP 1000 M/E/F-Series Computers Technical Reference Handbook\r
134 (5955-0282, Mar-1980)\r
135 - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation\r
136 (92851-90001, Mar-1981)\r
137 - 12607A Direct Memory Access Operating and Service Manual\r
138 (12607-90002, Jan-1970)\r
139 - 12578A/12578A-01 Direct Memory Access Operating and Service Manual\r
140 (12578-9001, Mar-1972)\r
141 - 12892B Memory Protect Installation Manual (12892-90007, Jun-1978)\r
142\r
143 The register state for the HP 2116 CPU is:\r
144\r
145 AR<15:0> A register - addressable as location 0\r
146 BR<15:0> B register - addressable as location 1\r
147 PC<14:0> P register (program counter)\r
148 SR<15:0> S register\r
149 MR<14:0> M register - memory address\r
150 TR<15:0> T register - memory data\r
151 E extend flag (carry out)\r
152 O overflow flag\r
153\r
154 The 2100 adds memory protection logic:\r
155\r
156 mp_fence<14:0> memory fence register\r
157 mp_viol<15:0> memory protection violation register (F register)\r
158\r
159 The 21MX adds a pair of index registers and memory expansion logic:\r
160\r
161 XR<15:0> X register\r
162 YR<15:0> Y register\r
163 dms_sr<15:0> dynamic memory system status register\r
164 dms_vr<15:0> dynamic memory system violation register\r
165\r
166 The original HP 2116 has four instruction formats: memory reference,\r
167 shift, alter/skip, and I/O. The HP 2100 added extended memory reference\r
168 and extended arithmetic. The HP21MX added extended byte, bit, and word\r
169 instructions as well as extended memory.\r
170\r
171 The memory reference format is:\r
172\r
173 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
174 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
175 |in| op |cp| offset | memory reference\r
176 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
177\r
178 <14:11> mnemonic action\r
179\r
180 0010 AND A = A & M[MA]\r
181 0011 JSB M[MA] = P, P = MA + 1\r
182 0100 XOR A = A ^ M[MA]\r
183 0101 JMP P = MA\r
184 0110 IOR A = A | M[MA]\r
185 0111 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0\r
186 1000 ADA A = A + M[MA]\r
187 1001 ADB B = B + M[MA]\r
188 1010 CPA skip if A != M[MA]\r
189 1011 CPB skip if B != M[MA]\r
190 1100 LDA A = M[MA]\r
191 1101 LDB B = M[MA]\r
192 1110 STA M[MA] = A\r
193 1111 STB M[MA] = B\r
194\r
195 <15,10> mode action\r
196\r
197 0,0 page zero direct MA = IR<9:0>\r
198 0,1 current page direct MA = PC<14:0>'IR,9:0>\r
199 1,0 page zero indirect MA = M[IR<9:0>]\r
200 1,1 current page indirect MA = M[PC<14:10>'IR<9:0>]\r
201\r
202 Memory reference instructions can access an address space of 32K words.\r
203 An instruction can directly reference the first 1024 words of memory\r
204 (called page zero), as well as 1024 words of the current page; it can\r
205 indirectly access all 32K.\r
206\r
207 The shift format is:\r
208\r
209 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
210 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
211 | 0 0 0 0|ab| 0|s1| op1 |ce|s2|sl| op2 | shift\r
212 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
213 | | \---+---/ | | | \---+---/\r
214 | | | | | | |\r
215 | | | | | | +---- shift 2 opcode\r
216 | | | | | +---------- skip if low bit == 0\r
217 | | | | +------------- shift 2 enable\r
218 | | | +---------------- clear Extend\r
219 | | +---------------------- shift 1 opcode\r
220 | +---------------------------- shift 1 enable\r
221 +---------------------------------- A/B select\r
222\r
223 The alter/skip format is:\r
224\r
225 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
226 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
227 | 0 0 0 0|ab| 1|regop| e op|se|ss|sl|in|sz|rs| alter/skip\r
228 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
229 | \-+-/ \-+-/ | | | | | |\r
230 | | | | | | | | +- reverse skip sense\r
231 | | | | | | | +---- skip if register == 0\r
232 | | | | | | +------- increment register\r
233 | | | | | +---------- skip if low bit == 0\r
234 | | | | +------------- skip if sign bit == 0\r
235 | | | +---------------- skip if Extend == 0\r
236 | | +--------------------- clr/com/set Extend\r
237 | +--------------------------- clr/com/set register\r
238 +---------------------------------- A/B select\r
239\r
240 The I/O transfer format is:\r
241\r
242 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
243 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
244 | 1 0 0 0|ab| 1|hc| opcode | device | I/O transfer\r
245 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
246 | | \---+---/\-------+-------/\r
247 | | | |\r
248 | | | +--------- device select\r
249 | | +---------------------- opcode\r
250 | +---------------------------- hold/clear flag\r
251 +---------------------------------- A/B select\r
252\r
253 The IO transfer instruction controls the specified device.\r
254 Depending on the opcode, the instruction may set or clear\r
255 the device flag, start or stop I/O, or read or write data.\r
256\r
257 The 2100 added an extended memory reference instruction;\r
258 the 21MX added extended arithmetic, operate, byte, word,\r
259 and bit instructions. Note that the HP 21xx is, despite\r
260 the right-to-left bit numbering, a big endian system.\r
261 Bits <15:8> are byte 0, and bits <7:0> are byte 1.\r
262\r
263\r
264 The extended memory reference format (HP 2100) is:\r
265\r
266 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
267 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
268 | 1| 0 0 0|op| 0| opcode | extended mem ref\r
269 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
270 |in| operand address |\r
271 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
272\r
273 The extended arithmetic format (HP 2100) is:\r
274\r
275 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
276 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
277 | 1| 0 0 0 0 0|dr| 0 0| opcode |shift count| extended arithmetic\r
278 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
279\r
280 The extended operate format (HP 21MX) is:\r
281\r
282 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
283 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
284 | 1| 0 0 0|op| 0| 1 1 1 1 1| opcode | extended operate\r
285 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
286\r
287 The extended byte and word format (HP 21MX) is:\r
288\r
289 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
290 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
291 | 1| 0 0 0 1 0 1 1 1 1 1 1| opcode | extended byte/word\r
292 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
293 |in| operand address |\r
294 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
295 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|\r
296 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
297\r
298 The extended bit operate format (HP 21MX) is:\r
299\r
300 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0\r
301 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
302 | 1| 0 0 0 1 0 1 1 1 1 1 1 1| opcode | extended bit operate\r
303 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
304 |in| operand address |\r
305 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
306 |in| operand address |\r
307 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
308\r
309 This routine is the instruction decode routine for the HP 2100.\r
310 It is called from the simulator control program to execute\r
311 instructions in simulated memory, starting at the simulated PC.\r
312 It runs until 'reason' is set non-zero.\r
313\r
314 General notes:\r
315\r
316 1. Reasons to stop. The simulator can be stopped by:\r
317\r
318 HALT instruction\r
319 breakpoint encountered\r
320 infinite indirection loop\r
321 unimplemented instruction and stop_inst flag set\r
322 unknown I/O device and stop_dev flag set\r
323 I/O error in I/O simulator\r
324\r
325 2. Interrupts. I/O devices are modelled as five parallel arrays:\r
326\r
327 device commands as bit array dev_cmd[2][31..0]\r
328 device flags as bit array dev_flg[2][31..0]\r
329 device flag buffers as bit array dev_fbf[2][31..0]\r
330 device controls as bit array dev_ctl[2][31..0]\r
331 device service requests as bit array dev_srq[3][31..0]\r
332\r
333 The HP 2100 interrupt structure is based on flag, flag buffer,\r
334 and control. If a device flag is set, the flag buffer is set,\r
335 the control bit is set, and the device is the highest priority\r
336 on the interrupt chain, it requests an interrupt. When the\r
337 interrupt is acknowledged, the flag buffer is cleared, preventing\r
338 further interrupt requests from that device. The combination of\r
339 flag and control set blocks interrupts from lower priority devices.\r
340\r
341 Command plays no direct role in interrupts. The command flop\r
342 tells whether a device is active. It is set by STC and cleared\r
343 by CLC; it is also cleared when the device flag is set. Simple\r
344 devices don't need to track command separately from control.\r
345\r
346 Service requests are used to trigger the DMA service logic.\r
347\r
348 3. Non-existent memory. On the HP 2100, reads to non-existent memory\r
349 return zero, and writes are ignored. In the simulator, the\r
350 largest possible memory is instantiated and initialized to zero.\r
351 Thus, only writes need be checked against memory size.\r
352\r
353 On the 21xx machines, doing SET CPU LOADERDISABLE decreases available\r
354 memory size by 64 words.\r
355\r
356 4. Adding I/O devices. These modules must be modified:\r
357\r
358 hp2100_defs.h add interrupt request definition\r
359 hp2100_sys.c add sim_devices table entry\r
360\r
361 5. Instruction interruptibility. The simulator is fast enough, compared\r
362 to the run-time of the longest instructions, for interruptibility not\r
363 to matter. But the HP diagnostics explicitly test interruptibility in\r
364 EIS and DMS instructions, and long indirect address chains. Accordingly,\r
365 the simulator does "just enough" to pass these tests. In particular, if\r
366 an interrupt is pending but deferred at the beginning of an interruptible\r
367 instruction, the interrupt is taken at the appropriate point; but there\r
368 is no testing for new interrupts during execution (that is, the event\r
369 timer is not called).\r
370\r
371 6. Interrupt deferral. At instruction fetch time, a pending interrupt\r
372 request will be deferred if the previous instruction was a JMP indirect,\r
373 JSB indirect, STC, CLC, STF, CLF, or was executing from an interrupt trap\r
374 cell. In addition, the following instructions will cause deferral on the\r
375 1000 series: SFS, SFC, JRS, DJP, DJS, SJP, SJS, UJP, and UJS.\r
376\r
377 On the HP 1000, the request is always deferred until after the current\r
378 instruction completes. On the 21xx, the request is deferred unless the\r
379 current instruction is an MRG instruction other than JMP or JMP,I or\r
380 JSB,I. Note that for the 21xx, SFS and SFC are not included in the\r
381 deferral criteria.\r
382*/\r
383\r
384#include "hp2100_defs.h"\r
385#include <setjmp.h>\r
386#include "hp2100_cpu.h"\r
387\r
388/* Memory protect constants */\r
389\r
390#define UNIT_V_MP_JSB (UNIT_V_UF + 0) /* MP jumper W5 */\r
391#define UNIT_V_MP_INT (UNIT_V_UF + 1) /* MP jumper W6 */\r
392#define UNIT_V_MP_SEL1 (UNIT_V_UF + 2) /* MP jumper W7 */\r
393#define UNIT_MP_JSB (1 << UNIT_V_MP_JSB) /* 1 = W5 is out */\r
394#define UNIT_MP_INT (1 << UNIT_V_MP_INT) /* 1 = W6 is out */\r
395#define UNIT_MP_SEL1 (1 << UNIT_V_MP_SEL1) /* 1 = W7 is out */\r
396\r
397#define ABORT(val) longjmp (save_env, (val))\r
398\r
399#define DMAR0 1\r
400#define DMAR1 2\r
401\r
402#define ALL_BKPTS (SWMASK('E')|SWMASK('N')|SWMASK('S')|SWMASK('U'))\r
403#define ALL_MAPMODES (SWMASK('S')|SWMASK('U')|SWMASK('P')|SWMASK('Q'))\r
404\r
405uint16 *M = NULL; /* memory */\r
406uint32 saved_AR = 0; /* A register */\r
407uint32 saved_BR = 0; /* B register */\r
408uint16 ABREG[2]; /* during execution */\r
409uint32 PC = 0; /* P register */\r
410uint32 SR = 0; /* S register */\r
411uint32 MR = 0; /* M register */\r
412uint32 saved_MR = 0; /* between executions */\r
413uint32 TR = 0; /* T register */\r
414uint32 XR = 0; /* X register */\r
415uint32 YR = 0; /* Y register */\r
416uint32 E = 0; /* E register */\r
417uint32 O = 0; /* O register */\r
418uint32 dev_cmd[2] = { 0 }; /* device command */\r
419uint32 dev_ctl[2] = { 0 }; /* device control */\r
420uint32 dev_flg[2] = { 0 }; /* device flags */\r
421uint32 dev_fbf[2] = { 0 }; /* device flag bufs */\r
422uint32 dev_srq[2] = { 0 }; /* device svc reqs */\r
423struct DMA dmac[2] = { { 0 }, { 0 } }; /* DMA channels */\r
424uint32 ion = 0; /* interrupt enable */\r
425uint32 ion_defer = 0; /* interrupt defer */\r
426uint32 intaddr = 0; /* interrupt addr */\r
427uint32 mp_fence = 0; /* mem prot fence */\r
428uint32 mp_viol = 0; /* mem prot viol reg */\r
429uint32 mp_mevff = 0; /* mem exp (dms) viol */\r
430uint32 mp_evrff = 1; /* update mp_viol */\r
431uint32 err_PC = 0; /* error PC */\r
432uint32 dms_enb = 0; /* dms enable */\r
433uint32 dms_ump = 0; /* dms user map */\r
434uint32 dms_sr = 0; /* dms status reg */\r
435uint32 dms_vr = 0; /* dms violation reg */\r
436uint16 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */\r
437uint32 iop_sp = 0; /* iop stack */\r
438uint32 ind_max = 16; /* iadr nest limit */\r
439uint32 stop_inst = 1; /* stop on ill inst */\r
440uint32 stop_dev = 0; /* stop on ill dev */\r
441uint32 fwanxm = 0; /* first word addr of nx mem */\r
442uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r
443uint32 pcq_p = 0; /* PC queue ptr */\r
444REG *pcq_r = NULL; /* PC queue reg ptr */\r
445jmp_buf save_env; /* abort handler */\r
446\r
447/* Table of CPU features by model.\r
448\r
449 Fields:\r
450 - typ: standard features plus typically configured options.\r
451 - opt: complete list of optional features.\r
452 - maxmem: maximum configurable memory in 16-bit words.\r
453\r
454 Features in the "typical" list are enabled when the CPU model is selected.\r
455 If a feature appears in the "typical" list but NOT in the "optional" list,\r
456 then it is standard equipment and cannot be disabled. If a feature appears\r
457 in the "optional" list, then it may be enabled or disabled as desired by the\r
458 user.\r
459*/\r
460\r
461struct FEATURE_TABLE { /* CPU model feature table: */\r
462 uint32 typ; /* - typical features */\r
463 uint32 opt; /* - optional features */\r
464 uint32 maxmem; /* - maximum memory */\r
465 };\r
466\r
467static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx order*/\r
468 { UNIT_DMA | UNIT_MP, /* UNIT_2116 */\r
469 UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_EAU,\r
470 32768 },\r
471 { UNIT_DMA, /* UNIT_2115 */\r
472 UNIT_PFAIL | UNIT_DMA | UNIT_EAU,\r
473 8192 },\r
474 { UNIT_DMA, /* UNIT_2114 */\r
475 UNIT_PFAIL | UNIT_DMA,\r
476 16384 },\r
477 { 0, 0, 0 },\r
478 { UNIT_PFAIL | UNIT_MP | UNIT_DMA | UNIT_EAU, /* UNIT_2100 */\r
479 UNIT_DMA | UNIT_FP | UNIT_IOP | UNIT_FFP,\r
480 32768 },\r
481 { 0, 0, 0 },\r
482 { 0, 0, 0 },\r
483 { 0, 0, 0 },\r
484 { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_M */\r
485 UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS |\r
486 UNIT_IOP | UNIT_FFP | UNIT_DS,\r
487 1048576 },\r
488 { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_E */\r
489 UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS |\r
490 UNIT_IOP | UNIT_FFP | UNIT_DBI | UNIT_DS | UNIT_EMA_VMA,\r
491 1048576 },\r
492 { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | /* UNIT_1000_F */\r
493 UNIT_FFP | UNIT_DBI | UNIT_DMS,\r
494 UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_VIS |\r
495 UNIT_IOP | UNIT_DS | UNIT_SIGNAL | UNIT_EMA_VMA,\r
496 1048576 }\r
497 };\r
498\r
499extern int32 sim_interval;\r
500extern int32 sim_int_char;\r
501extern int32 sim_brk_char;\r
502extern int32 sim_del_char;\r
503extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r
504extern FILE *sim_log;\r
505extern DEVICE *sim_devices[];\r
506extern int32 sim_switches;\r
507extern char halt_msg[];\r
508\r
509t_stat Ea (uint32 IR, uint32 *addr, uint32 irq);\r
510uint16 ReadIO (uint32 addr, uint32 map);\r
511uint16 ReadPW (uint32 addr);\r
512uint16 ReadTAB (uint32 addr);\r
513void WriteIO (uint32 addr, uint32 dat, uint32 map);\r
514void WritePW (uint32 addr, uint32 dat);\r
515uint32 dms (uint32 va, uint32 map, uint32 prot);\r
516uint32 dms_io (uint32 va, uint32 map);\r
517uint32 shift (uint32 inval, uint32 flag, uint32 oper);\r
518void dma_cycle (uint32 chan, uint32 map);\r
519uint32 calc_dma (void);\r
520uint32 calc_int (void);\r
521uint32 calc_defer (void);\r
522t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
523t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
524t_stat cpu_reset (DEVICE *dptr);\r
525t_stat cpu_boot (int32 unitno, DEVICE *dptr);\r
526t_stat mp_reset (DEVICE *dptr);\r
527t_stat dma0_reset (DEVICE *dptr);\r
528t_stat dma1_reset (DEVICE *dptr);\r
529t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc);\r
530t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc);\r
531t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc);\r
532t_stat cpu_set_opt (UNIT *uptr, int32 option, char *cptr, void *desc);\r
533t_stat cpu_clr_opt (UNIT *uptr, int32 option, char *cptr, void *desc);\r
534t_stat cpu_set_ldr (UNIT *uptr, int32 enable, char *cptr, void *desc);\r
535t_bool dev_conflict (void);\r
536void hp_post_cmd (t_bool from_scp);\r
537\r
538extern t_stat cpu_eau (uint32 IR, uint32 intrq);\r
539extern t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap);\r
540extern t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap);\r
541extern void (*sim_vm_post) (t_bool from_scp);\r
542\r
543/* CPU data structures\r
544\r
545 cpu_dev CPU device descriptor\r
546 cpu_unit CPU unit descriptor\r
547 cpu_reg CPU register list\r
548 cpu_mod CPU modifiers list\r
549 cpu_deb CPU debug flags\r
550*/\r
551\r
552UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 0) };\r
553\r
554REG cpu_reg[] = {\r
555 { ORDATA (P, PC, 15) },\r
556 { ORDATA (A, saved_AR, 16) },\r
557 { ORDATA (B, saved_BR, 16) },\r
558 { ORDATA (M, MR, 15) },\r
559 { ORDATA (T, TR, 16), REG_RO },\r
560 { ORDATA (X, XR, 16) },\r
561 { ORDATA (Y, YR, 16) },\r
562 { ORDATA (S, SR, 16) },\r
563 { FLDATA (E, E, 0) },\r
564 { FLDATA (O, O, 0) },\r
565 { FLDATA (ION, ion, 0) },\r
566 { FLDATA (ION_DEFER, ion_defer, 0) },\r
567 { ORDATA (CIR, intaddr, 6) },\r
568 { FLDATA (DMSENB, dms_enb, 0) },\r
569 { FLDATA (DMSCUR, dms_ump, VA_N_PAG) },\r
570 { ORDATA (DMSSR, dms_sr, 16) },\r
571 { ORDATA (DMSVR, dms_vr, 16) },\r
572 { BRDATA (DMSMAP, dms_map, 8, 16, MAP_NUM * MAP_LNT) },\r
573 { ORDATA (IOPSP, iop_sp, 16) },\r
574 { FLDATA (STOP_INST, stop_inst, 0) },\r
575 { FLDATA (STOP_DEV, stop_dev, 1) },\r
576 { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT },\r
577 { ORDATA (FWANXM, fwanxm, 32), REG_HRO },\r
578 { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC },\r
579 { ORDATA (PCQP, pcq_p, 6), REG_HRO },\r
580 { ORDATA (WRU, sim_int_char, 8), REG_HRO },\r
581 { ORDATA (BRK, sim_brk_char, 8), REG_HRO },\r
582 { ORDATA (DEL, sim_del_char, 8), REG_HRO },\r
583 { ORDATA (HCMD, dev_cmd[0], 32), REG_HRO },\r
584 { ORDATA (LCMD, dev_cmd[1], 32), REG_HRO },\r
585 { ORDATA (HCTL, dev_ctl[0], 32), REG_HRO },\r
586 { ORDATA (LCTL, dev_ctl[1], 32), REG_HRO },\r
587 { ORDATA (HFLG, dev_flg[0], 32), REG_HRO },\r
588 { ORDATA (LFLG, dev_flg[1], 32), REG_HRO },\r
589 { ORDATA (HFBF, dev_fbf[0], 32), REG_HRO },\r
590 { ORDATA (LFBF, dev_fbf[1], 32), REG_HRO },\r
591 { ORDATA (HSRQ, dev_srq[0], 32), REG_HRO },\r
592 { ORDATA (LSRQ, dev_srq[1], 32), REG_HRO },\r
593 { NULL }\r
594 };\r
595\r
596/* CPU modifier table.\r
597\r
598 The 21MX monikers are deprecated in favor of the 1000 designations. See the\r
599 "HP 1000 Series Naming History" on the back inside cover of the Technical\r
600 Reference Handbook. */\r
601\r
602MTAB cpu_mod[] = {\r
603 { UNIT_MODEL_MASK, UNIT_2116, "", "2116", &cpu_set_model, &cpu_show_model, "2116" },\r
604 { UNIT_MODEL_MASK, UNIT_2115, "", "2115", &cpu_set_model, &cpu_show_model, "2115" },\r
605 { UNIT_MODEL_MASK, UNIT_2114, "", "2114", &cpu_set_model, &cpu_show_model, "2114" },\r
606 { UNIT_MODEL_MASK, UNIT_2100, "", "2100", &cpu_set_model, &cpu_show_model, "2100" },\r
607 { UNIT_MODEL_MASK, UNIT_1000_E, "", "1000-E", &cpu_set_model, &cpu_show_model, "1000-E" },\r
608 { UNIT_MODEL_MASK, UNIT_1000_E, NULL, "21MX-E", &cpu_set_model, &cpu_show_model, "1000-E" },\r
609 { UNIT_MODEL_MASK, UNIT_1000_M, "", "1000-M", &cpu_set_model, &cpu_show_model, "1000-M" },\r
610 { UNIT_MODEL_MASK, UNIT_1000_M, NULL, "21MX-M", &cpu_set_model, &cpu_show_model, "1000-M" },\r
611\r
612#if defined (HAVE_INT64)\r
613 { UNIT_MODEL_MASK, UNIT_1000_F, "", "1000-F", &cpu_set_model, &cpu_show_model, "1000-F" },\r
614#endif\r
615\r
616 { MTAB_XTD | MTAB_VDV, 1, NULL, "LOADERENABLE", &cpu_set_ldr, NULL, NULL },\r
617 { MTAB_XTD | MTAB_VDV, 0, NULL, "LOADERDISABLE", &cpu_set_ldr, NULL, NULL },\r
618\r
619 { UNIT_EAU, UNIT_EAU, "EAU", "EAU", &cpu_set_opt, NULL, NULL },\r
620 { UNIT_EAU, 0, "no EAU", NULL, NULL, NULL, NULL },\r
621 { MTAB_XTD | MTAB_VDV, UNIT_EAU, NULL, "NOEAU", &cpu_clr_opt, NULL, NULL },\r
622\r
623 { UNIT_FP, UNIT_FP, "FP", "FP", &cpu_set_opt, NULL, NULL },\r
624 { UNIT_FP, 0, "no FP", NULL, NULL, NULL, NULL },\r
625 { MTAB_XTD | MTAB_VDV, UNIT_FP, NULL, "NOFP", &cpu_clr_opt, NULL, NULL },\r
626\r
627 { UNIT_IOP, UNIT_IOP, "IOP", "IOP", &cpu_set_opt, NULL, NULL },\r
628 { UNIT_IOP, 0, "no IOP", NULL, NULL, NULL, NULL },\r
629 { MTAB_XTD | MTAB_VDV, UNIT_IOP, NULL, "NOIOP", &cpu_clr_opt, NULL, NULL },\r
630\r
631 { UNIT_DMS, UNIT_DMS, "DMS", "DMS", &cpu_set_opt, NULL, NULL },\r
632 { UNIT_DMS, 0, "no DMS", NULL, NULL, NULL, NULL },\r
633 { MTAB_XTD | MTAB_VDV, UNIT_DMS, NULL, "NODMS", &cpu_clr_opt, NULL, NULL },\r
634\r
635 { UNIT_FFP, UNIT_FFP, "FFP", "FFP", &cpu_set_opt, NULL, NULL },\r
636 { UNIT_FFP, 0, "no FFP", NULL, NULL, NULL, NULL },\r
637 { MTAB_XTD | MTAB_VDV, UNIT_FFP, NULL, "NOFFP", &cpu_clr_opt, NULL, NULL },\r
638\r
639 { UNIT_DBI, UNIT_DBI, "DBI", "DBI", &cpu_set_opt, NULL, NULL },\r
640 { UNIT_DBI, 0, "no DBI", NULL, NULL, NULL, NULL },\r
641 { MTAB_XTD | MTAB_VDV, UNIT_DBI, NULL, "NODBI", &cpu_clr_opt, NULL, NULL },\r
642\r
643 { UNIT_EMA_VMA, UNIT_EMA, "EMA", "EMA", &cpu_set_opt, NULL, NULL },\r
644 { MTAB_XTD | MTAB_VDV, UNIT_EMA, NULL, "NOEMA", &cpu_clr_opt, NULL, NULL },\r
645\r
646 { UNIT_EMA_VMA, UNIT_VMAOS, "VMA", "VMA", &cpu_set_opt, NULL, NULL },\r
647 { MTAB_XTD | MTAB_VDV, UNIT_VMAOS, NULL, "NOVMA", &cpu_clr_opt, NULL, NULL },\r
648\r
649 { UNIT_EMA_VMA, 0, "no EMA/VMA", NULL, &cpu_set_opt, NULL, NULL },\r
650\r
651#if defined (HAVE_INT64)\r
652 { UNIT_VIS, UNIT_VIS, "VIS", "VIS", &cpu_set_opt, NULL, NULL },\r
653 { UNIT_VIS, 0, "no VIS", NULL, NULL, NULL, NULL },\r
654 { MTAB_XTD | MTAB_VDV, UNIT_VIS, NULL, "NOVIS", &cpu_clr_opt, NULL, NULL },\r
655\r
656 { UNIT_SIGNAL, UNIT_SIGNAL,"SIGNAL", "SIGNAL", &cpu_set_opt, NULL, NULL },\r
657 { UNIT_SIGNAL, 0, "no SIGNAL", NULL, NULL, NULL, NULL },\r
658 { MTAB_XTD | MTAB_VDV, UNIT_SIGNAL, NULL, "NOSIGNAL", &cpu_clr_opt, NULL, NULL },\r
659#endif\r
660\r
661/* Future microcode support.\r
662 { UNIT_DS, UNIT_DS, "DS", "DS", &cpu_set_opt, NULL, NULL },\r
663 { UNIT_DS, 0, "no DS", NULL, NULL, NULL, NULL },\r
664 { MTAB_XTD | MTAB_VDV, UNIT_DS, NULL, "NODS", &cpu_clr_opt, NULL, NULL },\r
665*/\r
666\r
667 { MTAB_XTD | MTAB_VDV, 4096, NULL, "4K", &cpu_set_size, NULL, NULL },\r
668 { MTAB_XTD | MTAB_VDV, 8192, NULL, "8K", &cpu_set_size, NULL, NULL },\r
669 { MTAB_XTD | MTAB_VDV, 12288, NULL, "12K", &cpu_set_size, NULL, NULL },\r
670 { MTAB_XTD | MTAB_VDV, 16384, NULL, "16K", &cpu_set_size, NULL, NULL },\r
671 { MTAB_XTD | MTAB_VDV, 24576, NULL, "24K", &cpu_set_size, NULL, NULL },\r
672 { MTAB_XTD | MTAB_VDV, 32768, NULL, "32K", &cpu_set_size, NULL, NULL },\r
673 { MTAB_XTD | MTAB_VDV, 65536, NULL, "64K", &cpu_set_size, NULL, NULL },\r
674 { MTAB_XTD | MTAB_VDV, 131072, NULL, "128K", &cpu_set_size, NULL, NULL },\r
675 { MTAB_XTD | MTAB_VDV, 262144, NULL, "256K", &cpu_set_size, NULL, NULL },\r
676 { MTAB_XTD | MTAB_VDV, 524288, NULL, "512K", &cpu_set_size, NULL, NULL },\r
677 { MTAB_XTD | MTAB_VDV, 1048576, NULL, "1024K", &cpu_set_size, NULL, NULL },\r
678 { 0 }\r
679 };\r
680\r
681DEBTAB cpu_deb[] = {\r
682 { "OS", DEB_OS },\r
683 { "OSTBG", DEB_OSTBG },\r
684 { "VMA", DEB_VMA },\r
685 { "EMA", DEB_EMA },\r
686 { "VIS", DEB_VIS },\r
687 { "SIG", DEB_SIG },\r
688 { NULL, 0 }\r
689 };\r
690\r
691DEVICE cpu_dev = {\r
692 "CPU", &cpu_unit, cpu_reg, cpu_mod,\r
693 1, 8, PA_N_SIZE, 1, 8, 16,\r
694 &cpu_ex, &cpu_dep, &cpu_reset,\r
695 &cpu_boot, NULL, NULL,\r
696 NULL, DEV_DEBUG, \r
697 0, cpu_deb, NULL, NULL\r
698 };\r
699\r
700/* Memory protect data structures\r
701\r
702 mp_dev MP device descriptor\r
703 mp_unit MP unit descriptor\r
704 mp_reg MP register list\r
705 mp_mod MP modifiers list\r
706*/\r
707\r
708UNIT mp_unit = { UDATA (NULL, UNIT_MP_SEL1, 0) }; /* default is JSB in, INT in, SEL1 out */\r
709\r
710REG mp_reg[] = {\r
711 { FLDATA (CTL, dev_ctl[PRO/32], INT_V (PRO)) },\r
712 { FLDATA (FLG, dev_flg[PRO/32], INT_V (PRO)) },\r
713 { FLDATA (FBF, dev_fbf[PRO/32], INT_V (PRO)) },\r
714 { ORDATA (FR, mp_fence, 15) },\r
715 { ORDATA (VR, mp_viol, 16) },\r
716 { FLDATA (MEV, mp_mevff, 0) },\r
717 { FLDATA (EVR, mp_evrff, 0) },\r
718 { NULL }\r
719 };\r
720\r
721MTAB mp_mod[] = {\r
722 { UNIT_MP_JSB, UNIT_MP_JSB, "JSB (W5) out", "JSBOUT", NULL },\r
723 { UNIT_MP_JSB, 0, "JSB (W5) in", "JSBIN", NULL },\r
724 { UNIT_MP_INT, UNIT_MP_INT, "INT (W6) out", "INTOUT", NULL },\r
725 { UNIT_MP_INT, 0, "INT (W6) in", "INTIN", NULL },\r
726 { UNIT_MP_SEL1, UNIT_MP_SEL1, "SEL1 (W7) out", "SEL1OUT", NULL },\r
727 { UNIT_MP_SEL1, 0, "SEL1 (W7) in", "SEL1IN", NULL },\r
728 { 0 }\r
729 };\r
730\r
731DEVICE mp_dev = {\r
732 "MP", &mp_unit, mp_reg, mp_mod,\r
733 1, 8, 1, 1, 8, 16,\r
734 NULL, NULL, &mp_reset,\r
735 NULL, NULL, NULL,\r
736 NULL, DEV_DISABLE | DEV_DIS\r
737 };\r
738\r
739/* DMA controller data structures\r
740\r
741 dmax_dev DMAx device descriptor\r
742 dmax_reg DMAx register list\r
743*/\r
744\r
745UNIT dma0_unit = { UDATA (NULL, 0, 0) };\r
746\r
747REG dma0_reg[] = {\r
748 { FLDATA (CMD, dev_cmd[DMA0/32], INT_V (DMA0)) },\r
749 { FLDATA (CTL, dev_ctl[DMA0/32], INT_V (DMA0)) },\r
750 { FLDATA (FLG, dev_flg[DMA0/32], INT_V (DMA0)) },\r
751 { FLDATA (FBF, dev_fbf[DMA0/32], INT_V (DMA0)) },\r
752 { FLDATA (CTLALT, dev_ctl[DMALT0/32], INT_V (DMALT0)) },\r
753 { ORDATA (CW1, dmac[0].cw1, 16) },\r
754 { ORDATA (CW2, dmac[0].cw2, 16) },\r
755 { ORDATA (CW3, dmac[0].cw3, 16) },\r
756 { DRDATA (LATENCY, dmac[0].latency, 8) },\r
757 { FLDATA (BYTE, dmac[0].packer, 31) },\r
758 { ORDATA (PACKER, dmac[0].packer, 8) },\r
759 { NULL }\r
760 };\r
761\r
762DEVICE dma0_dev = {\r
763 "DMA0", &dma0_unit, dma0_reg, NULL,\r
764 1, 8, 1, 1, 8, 16,\r
765 NULL, NULL, &dma0_reset,\r
766 NULL, NULL, NULL,\r
767 NULL, DEV_DISABLE\r
768 };\r
769\r
770UNIT dma1_unit = { UDATA (NULL, 0, 0) };\r
771\r
772REG dma1_reg[] = {\r
773 { FLDATA (CMD, dev_cmd[DMA1/32], INT_V (DMA1)) },\r
774 { FLDATA (CTL, dev_ctl[DMA1/32], INT_V (DMA1)) },\r
775 { FLDATA (FLG, dev_flg[DMA1/32], INT_V (DMA1)) },\r
776 { FLDATA (FBF, dev_fbf[DMA1/32], INT_V (DMA1)) },\r
777 { FLDATA (CTLALT, dev_ctl[DMALT1/32], INT_V (DMALT1)) },\r
778 { ORDATA (CW1, dmac[1].cw1, 16) },\r
779 { ORDATA (CW2, dmac[1].cw2, 16) },\r
780 { ORDATA (CW3, dmac[1].cw3, 16) },\r
781 { DRDATA (LATENCY, dmac[1].latency, 8) },\r
782 { FLDATA (BYTE, dmac[1].packer, 31) },\r
783 { ORDATA (PACKER, dmac[1].packer, 8) },\r
784 { NULL }\r
785 };\r
786\r
787DEVICE dma1_dev = {\r
788 "DMA1", &dma1_unit, dma1_reg, NULL,\r
789 1, 8, 1, 1, 8, 16,\r
790 NULL, NULL, &dma1_reset,\r
791 NULL, NULL, NULL,\r
792 NULL, DEV_DISABLE\r
793 };\r
794\r
795/* Interrupt defer table (1000 version) */\r
796\r
797static int32 defer_tab[] = { 0, 1, 1, 1, 0, 0, 0, 1 };\r
798\r
799/* Device dispatch table */\r
800\r
801uint32 devdisp (uint32 devno, uint32 inst, uint32 IR, uint32 outdat);\r
802int32 cpuio (int32 op, int32 IR, int32 outdat);\r
803int32 ovfio (int32 op, int32 IR, int32 outdat);\r
804int32 pwrio (int32 op, int32 IR, int32 outdat);\r
805int32 proio (int32 op, int32 IR, int32 outdat);\r
806int32 dmsio (int32 op, int32 IR, int32 outdat);\r
807int32 dmpio (int32 op, int32 IR, int32 outdat);\r
808int32 nulio (int32 op, int32 IR, int32 outdat);\r
809\r
810int32 (*dtab[64])() = {\r
811 &cpuio, &ovfio, &dmsio, &dmsio, &pwrio, &proio, &dmpio, &dmpio,\r
812 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\r
813 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\r
814 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\r
815 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\r
816 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\r
817 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\r
818 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL\r
819 };\r
820\r
821t_stat sim_instr (void)\r
822{\r
823uint32 intrq, dmarq; /* set after setjmp */\r
824uint32 iotrap = 0; /* set after setjmp */\r
825t_stat reason; /* set after setjmp */\r
826int32 i, dev; /* temp */\r
827DEVICE *dptr; /* temp */\r
828DIB *dibp; /* temp */\r
829int abortval;\r
830\r
831/* Restore register state */\r
832\r
833if (dev_conflict ()) return SCPE_STOP; /* check consistency */\r
834AR = saved_AR & DMASK; /* restore reg */\r
835BR = saved_BR & DMASK;\r
836err_PC = PC = PC & VAMASK; /* load local PC */\r
837reason = 0;\r
838\r
839/* Restore I/O state */\r
840\r
841if (mp_dev.flags & DEV_DIS) dtab[PRO] = NULL;\r
842else dtab[PRO] = &proio; /* set up MP dispatch */\r
843if (dma0_dev.flags & DEV_DIS) dtab[DMA0] = dtab[DMALT0] = NULL;\r
844else {\r
845 dtab[DMA0] = &dmpio; /* set up DMA0 dispatch */\r
846 dtab[DMALT0] = &dmsio;\r
847 }\r
848if (dma1_dev.flags & DEV_DIS) dtab[DMA1] = dtab[DMALT1] = NULL;\r
849else {\r
850 dtab[DMA1] = &dmpio; /* set up DMA1 dispatch */\r
851 dtab[DMALT1] = &dmsio;\r
852 }\r
853\r
854for (i = VARDEV; i <= I_DEVMASK; i++) dtab[i] = NULL; /* clr disp table */\r
855dev_cmd[0] = dev_cmd[0] & M_FXDEV; /* clear dynamic info */\r
856dev_ctl[0] = dev_ctl[0] & M_FXDEV;\r
857dev_flg[0] = dev_flg[0] & M_FXDEV;\r
858dev_fbf[0] = dev_fbf[0] & M_FXDEV;\r
859dev_srq[0] = dev_srq[1] = 0; /* init svc requests */\r
860dev_cmd[1] = dev_ctl[1] = dev_flg[1] = dev_fbf[1] = 0;\r
861for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */\r
862 dibp = (DIB *) dptr->ctxt; /* get DIB */\r
863 if (dibp && !(dptr->flags & DEV_DIS)) { /* exist, enabled? */\r
864 dev = dibp->devno; /* get dev # */\r
865 if (dibp->cmd) { setCMD (dev); } /* restore cmd */\r
866 if (dibp->ctl) { setCTL (dev); } /* restore ctl */\r
867 if (dibp->flg) { setFLG (dev); } /* restore flg */\r
868 clrFBF (dev); /* also sets fbf */\r
869 if (dibp->fbf) { setFBF (dev); } /* restore fbf */\r
870 if (dibp->srq) { setSRQ (dev); } /* restore srq */\r
871 dtab[dev] = dibp->iot; /* set I/O dispatch */\r
872 }\r
873 }\r
874\r
875/* Configure interrupt deferral table */\r
876\r
877if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) /* 21xx series? */\r
878 defer_tab[ioSFC] = defer_tab[ioSFS] = 0; /* SFC/S doesn't defer */\r
879else /* 1000 series */\r
880 defer_tab[ioSFC] = defer_tab[ioSFS] = 1; /* SFC/S does defer */\r
881\r
882/* Abort handling\r
883\r
884 If an abort occurs in memory protection, the relocation routine\r
885 executes a longjmp to this area OUTSIDE the main simulation loop.\r
886 Memory protection errors are the only sources of aborts in the\r
887 HP 2100. All referenced variables must be globals, and all sim_instr\r
888 scoped automatics must be set after the setjmp.\r
889*/\r
890\r
891abortval = setjmp (save_env); /* set abort hdlr */\r
892if (abortval != 0) { /* mem mgt abort? */\r
893 setFLG (PRO); /* req interrupt */\r
894 mp_evrff = 0; /* block mp_viol upd */\r
895 }\r
896dmarq = calc_dma (); /* recalc DMA masks */\r
897intrq = calc_int (); /* recalc interrupts */\r
898\r
899/* Main instruction fetch/decode loop */\r
900\r
901while (reason == 0) { /* loop until halted */\r
902 uint32 IR, MA, absel, v1, t, skip;\r
903\r
904 if (sim_interval <= 0) { /* check clock queue */\r
905 if (reason = sim_process_event ()) break;\r
906 dmarq = calc_dma (); /* recalc DMA reqs */\r
907 intrq = calc_int (); /* recalc interrupts */\r
908 }\r
909\r
910 if (dmarq) {\r
911 if (dmarq & DMAR0) dma_cycle (0, PAMAP); /* DMA1 cycle? */\r
912 if (dmarq & DMAR1) dma_cycle (1, PBMAP); /* DMA2 cycle? */\r
913 dmarq = calc_dma (); /* recalc DMA reqs */\r
914 intrq = calc_int (); /* recalc interrupts */\r
915 }\r
916\r
917 if (intrq && ion_defer) /* interrupt pending but deferred? */\r
918 ion_defer = calc_defer (); /* confirm deferral */\r
919 \r
920/* (From Dave Bryan)\r
921 Unlike most other I/O devices, the MP flag flip-flop is cleared\r
922 automatically when the interrupt is acknowledged and not by a programmed\r
923 instruction (CLF and STF affect the parity error enable FF instead).\r
924 Section 4.4.3 "Memory Protect and I/O Interrupt Generation" of the "HP 1000\r
925 M/E/F-Series Computers Engineering and Reference Documentation" (HP\r
926 92851-90001) says:\r
927\r
928 "When IAK occurs and IRQ5 is asserted, the FLAGBFF is cleared, FLAGFF\r
929 clocked off at next T2, and IRQ5 will no longer occur."\r
930*/\r
931\r
932 if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */\r
933 iotrap = 1; /* I/O trap cell instr */\r
934 clrFBF (intrq); /* clear flag buffer */\r
935 if (intrq == PRO) clrFLG (PRO); /* MP flag follows fbuf */\r
936 intaddr = intrq; /* save int addr */\r
937 if (dms_enb) dms_sr = dms_sr | MST_ENBI; /* dms enabled? */\r
938 else dms_sr = dms_sr & ~MST_ENBI;\r
939 if (dms_ump) { /* user map? */\r
940 dms_sr = dms_sr | MST_UMPI;\r
941 dms_ump = SMAP; /* switch to system */\r
942 }\r
943 else dms_sr = dms_sr & ~MST_UMPI;\r
944 IR = ReadW (intrq); /* get dispatch instr */\r
945 ion_defer = 1; /* defer interrupts */\r
946 intrq = 0; /* clear request */\r
947 if (((IR & I_NMRMASK) != I_IO) || /* if not I/O or */\r
948 (I_GETIOOP (IR) == ioHLT)) /* if halt, */\r
949 clrCTL (PRO); /* protection off */\r
950 else /* I/O instr leaves MP on */\r
951 mp_mevff = 0; /* but clears MEV flip-flop */\r
952 }\r
953\r
954 else { /* normal instruction */\r
955 iotrap = 0;\r
956 err_PC = PC; /* save PC for error */\r
957 if (sim_brk_summ && /* any breakpoints? */\r
958 sim_brk_test (PC, SWMASK ('E') | /* unconditional or */\r
959 (dms_enb? (dms_ump? SWMASK ('U'): SWMASK ('S')):\r
960 SWMASK ('N')))) { /* or right type for DMS? */\r
961 reason = STOP_IBKPT; /* stop simulation */\r
962 break;\r
963 }\r
964 if (mp_evrff) mp_viol = PC; /* if ok, upd mp_viol */\r
965 IR = ReadW (PC); /* fetch instr */\r
966 PC = (PC + 1) & VAMASK;\r
967 ion_defer = 0;\r
968 }\r
969\r
970 sim_interval = sim_interval - 1; /* count instruction */\r
971\r
972/* Instruction decode. The 21MX does a 256-way decode on IR<15:8>\r
973\r
974 15 14 13 12 11 10 09 08 instruction\r
975\r
976 x <-!= 0-> x x x x memory reference\r
977 0 0 0 0 x 0 x x shift\r
978 0 0 0 0 x 0 x x alter-skip\r
979 1 0 0 0 x 1 x x IO\r
980 1 0 0 0 0 0 x 0 extended arithmetic\r
981 1 0 0 0 0 0 0 1 divide (decoded as 100400)\r
982 1 0 0 0 1 0 0 0 double load (decoded as 104000)\r
983 1 0 0 0 1 0 0 1 double store (decoded as 104400)\r
984 1 0 0 0 1 0 1 0 extended instr group 0 (A/B must be set)\r
985 1 0 0 0 x 0 1 1 extended instr group 1 (A/B ignored) */\r
986\r
987 absel = (IR & I_AB)? 1: 0; /* get A/B select */\r
988 switch ((IR >> 8) & 0377) { /* decode IR<15:8> */\r
989\r
990/* Memory reference instructions */\r
991\r
992 case 0020:case 0021:case 0022:case 0023:\r
993 case 0024:case 0025:case 0026:case 0027:\r
994 case 0220:case 0221:case 0222:case 0223:\r
995 case 0224:case 0225:case 0226:case 0227:\r
996 if (reason = Ea (IR, &MA, intrq)) break; /* AND */\r
997 AR = AR & ReadW (MA);\r
998 break;\r
999\r
1000/* JSB is a little tricky. It is possible to generate both an MP and a DM\r
1001 violation simultaneously. Consider a JSB to a location under the MP fence\r
1002 and on a write-protected page. This situation must be reported as a DM\r
1003 violation, because it has priority (SFS 5 and SFC 5 check only the MEVFF,\r
1004 which sets independently of the MP fence violation).\r
1005\r
1006 Under simulation, this means that DM violations must be checked, and the\r
1007 MEVFF must be set, before an MP abort is taken. This is done for JSB by the\r
1008 WriteW call to store the return PC. However, WriteW only checks for fence\r
1009 violations above location 2, as normally JSBs to locations 0 and 1 (i.e., the\r
1010 A and B register) are allowed. However, if the W5 (JSB) jumper is out, then\r
1011 JSB 0 and JSB 1 are MP violations as well and must be caught. We do this\r
1012 with an explicit check before calling WriteW.\r
1013\r
1014 This would seem to violate the above requirement for DM checks before MP\r
1015 checks. However, a DM abort cannot occur on a write to 0/1, even if logical\r
1016 page 0 is write-protected, because writes to 0/1 do not attempt to access\r
1017 memory; they are intercepted and affect the A/B registers instead (micro-\r
1018 order TAB is used in the Store field), so no MEV signal is generated.\r
1019*/\r
1020\r
1021 case 0230:case 0231:case 0232:case 0233:\r
1022 case 0234:case 0235:case 0236:case 0237:\r
1023 ion_defer = 1; /* defer if JSB,I */\r
1024\r
1025 case 0030:case 0031:case 0032:case 0033:\r
1026 case 0034:case 0035:case 0036:case 0037:\r
1027 if (reason = Ea (IR, &MA, intrq)) break; /* JSB */\r
1028\r
1029 if ((mp_unit.flags & UNIT_MP_JSB) && /* if W5 (JSB) out */\r
1030 CTL (PRO) && (MA <= 1)) /* and MP on and JSB 0 or JSB 1 */\r
1031 ABORT (ABORT_PRO); /* MP violation */\r
1032\r
1033 WriteW (MA, PC); /* store PC */\r
1034 PCQ_ENTRY;\r
1035 PC = (MA + 1) & VAMASK; /* jump */\r
1036 break;\r
1037\r
1038 case 0040:case 0041:case 0042:case 0043:\r
1039 case 0044:case 0045:case 0046:case 0047:\r
1040 case 0240:case 0241:case 0242:case 0243:\r
1041 case 0244:case 0245:case 0246:case 0247:\r
1042 if (reason = Ea (IR, &MA, intrq)) break; /* XOR */\r
1043 AR = AR ^ ReadW (MA);\r
1044 break;\r
1045\r
1046 case 0250:case 0251:case 0252:case 0253:\r
1047 case 0254:case 0255:case 0256:case 0257:\r
1048 ion_defer = 1; /* defer if JMP,I */\r
1049\r
1050 case 0050:case 0051:case 0052:case 0053:\r
1051 case 0054:case 0055:case 0056:case 0057:\r
1052 if (reason = Ea (IR, &MA, intrq)) break; /* JMP */\r
1053 mp_dms_jmp (MA); /* validate jump addr */\r
1054 PCQ_ENTRY;\r
1055 PC = MA; /* jump */\r
1056 break;\r
1057\r
1058 case 0060:case 0061:case 0062:case 0063:\r
1059 case 0064:case 0065:case 0066:case 0067:\r
1060 case 0260:case 0261:case 0262:case 0263:\r
1061 case 0264:case 0265:case 0266:case 0267:\r
1062 if (reason = Ea (IR, &MA, intrq)) break; /* IOR */\r
1063 AR = AR | ReadW (MA);\r
1064 break;\r
1065\r
1066 case 0070:case 0071:case 0072:case 0073:\r
1067 case 0074:case 0075:case 0076:case 0077:\r
1068 case 0270:case 0271:case 0272:case 0273:\r
1069 case 0274:case 0275:case 0276:case 0277:\r
1070 if (reason = Ea (IR, &MA, intrq)) break; /* ISZ */\r
1071 t = (ReadW (MA) + 1) & DMASK;\r
1072 WriteW (MA, t);\r
1073 if (t == 0) PC = (PC + 1) & VAMASK;\r
1074 break;\r
1075\r
1076 case 0100:case 0101:case 0102:case 0103:\r
1077 case 0104:case 0105:case 0106:case 0107:\r
1078 case 0300:case 0301:case 0302:case 0303:\r
1079 case 0304:case 0305:case 0306:case 0307:\r
1080 if (reason = Ea (IR, &MA, intrq)) break; /* ADA */\r
1081 v1 = ReadW (MA);\r
1082 t = AR + v1;\r
1083 if (t > DMASK) E = 1;\r
1084 if (((~AR ^ v1) & (AR ^ t)) & SIGN) O = 1;\r
1085 AR = t & DMASK;\r
1086 break;\r
1087\r
1088 case 0110:case 0111:case 0112:case 0113:\r
1089 case 0114:case 0115:case 0116:case 0117:\r
1090 case 0310:case 0311:case 0312:case 0313:\r
1091 case 0314:case 0315:case 0316:case 0317:\r
1092 if (reason = Ea (IR, &MA, intrq)) break; /* ADB */\r
1093 v1 = ReadW (MA);\r
1094 t = BR + v1;\r
1095 if (t > DMASK) E = 1;\r
1096 if (((~BR ^ v1) & (BR ^ t)) & SIGN) O = 1;\r
1097 BR = t & DMASK;\r
1098 break;\r
1099\r
1100 case 0120:case 0121:case 0122:case 0123:\r
1101 case 0124:case 0125:case 0126:case 0127:\r
1102 case 0320:case 0321:case 0322:case 0323:\r
1103 case 0324:case 0325:case 0326:case 0327:\r
1104 if (reason = Ea (IR, &MA, intrq)) break; /* CPA */\r
1105 if (AR != ReadW (MA)) PC = (PC + 1) & VAMASK;\r
1106 break;\r
1107\r
1108 case 0130:case 0131:case 0132:case 0133:\r
1109 case 0134:case 0135:case 0136:case 0137:\r
1110 case 0330:case 0331:case 0332:case 0333:\r
1111 case 0334:case 0335:case 0336:case 0337:\r
1112 if (reason = Ea (IR, &MA, intrq)) break; /* CPB */\r
1113 if (BR != ReadW (MA)) PC = (PC + 1) & VAMASK;\r
1114 break;\r
1115\r
1116 case 0140:case 0141:case 0142:case 0143:\r
1117 case 0144:case 0145:case 0146:case 0147:\r
1118 case 0340:case 0341:case 0342:case 0343:\r
1119 case 0344:case 0345:case 0346:case 0347:\r
1120 if (reason = Ea (IR, &MA, intrq)) break; /* LDA */\r
1121 AR = ReadW (MA);\r
1122 break;\r
1123\r
1124 case 0150:case 0151:case 0152:case 0153:\r
1125 case 0154:case 0155:case 0156:case 0157:\r
1126 case 0350:case 0351:case 0352:case 0353:\r
1127 case 0354:case 0355:case 0356:case 0357:\r
1128 if (reason = Ea (IR, &MA, intrq)) break; /* LDB */\r
1129 BR = ReadW (MA);\r
1130 break;\r
1131\r
1132 case 0160:case 0161:case 0162:case 0163:\r
1133 case 0164:case 0165:case 0166:case 0167:\r
1134 case 0360:case 0361:case 0362:case 0363:\r
1135 case 0364:case 0365:case 0366:case 0367:\r
1136 if (reason = Ea (IR, &MA, intrq)) break; /* STA */\r
1137 WriteW (MA, AR);\r
1138 break;\r
1139\r
1140 case 0170:case 0171:case 0172:case 0173:\r
1141 case 0174:case 0175:case 0176:case 0177:\r
1142 case 0370:case 0371:case 0372:case 0373:\r
1143 case 0374:case 0375:case 0376:case 0377:\r
1144 if (reason = Ea (IR, &MA, intrq)) break; /* STB */\r
1145 WriteW (MA, BR);\r
1146 break;\r
1147\r
1148/* Alter/skip instructions */\r
1149\r
1150 case 0004:case 0005:case 0006:case 0007:\r
1151 case 0014:case 0015:case 0016:case 0017:\r
1152 skip = 0; /* no skip */\r
1153 if (IR & 000400) t = 0; /* CLx */\r
1154 else t = ABREG[absel];\r
1155 if (IR & 001000) t = t ^ DMASK; /* CMx */\r
1156 if (IR & 000001) { /* RSS? */\r
1157 if ((IR & 000040) && (E != 0)) skip = 1; /* SEZ,RSS */\r
1158 if (IR & 000100) E = 0; /* CLE */\r
1159 if (IR & 000200) E = E ^ 1; /* CME */\r
1160 if (((IR & 000030) == 000030) && /* SSx,SLx,RSS */\r
1161 ((t & 0100001) == 0100001)) skip = 1;\r
1162 if (((IR & 000030) == 000020) && /* SSx,RSS */\r
1163 ((t & SIGN) != 0)) skip = 1;\r
1164 if (((IR & 000030) == 000010) && /* SLx,RSS */\r
1165 ((t & 1) != 0)) skip = 1;\r
1166 if (IR & 000004) { /* INx */\r
1167 t = (t + 1) & DMASK;\r
1168 if (t == 0) E = 1;\r
1169 if (t == SIGN) O = 1;\r
1170 }\r
1171 if ((IR & 000002) && (t != 0)) skip = 1; /* SZx,RSS */\r
1172 if ((IR & 000072) == 0) skip = 1; /* RSS */\r
1173 } /* end if RSS */\r
1174 else {\r
1175 if ((IR & 000040) && (E == 0)) skip = 1; /* SEZ */\r
1176 if (IR & 000100) E = 0; /* CLE */\r
1177 if (IR & 000200) E = E ^ 1; /* CME */\r
1178 if ((IR & 000020) && /* SSx */\r
1179 ((t & SIGN) == 0)) skip = 1;\r
1180 if ((IR & 000010) && /* SLx */\r
1181 ((t & 1) == 0)) skip = 1;\r
1182 if (IR & 000004) { /* INx */\r
1183 t = (t + 1) & DMASK;\r
1184 if (t == 0) E = 1;\r
1185 if (t == SIGN) O = 1;\r
1186 }\r
1187 if ((IR & 000002) && (t == 0)) skip = 1; /* SZx */\r
1188 } /* end if ~RSS */\r
1189 ABREG[absel] = t; /* store result */\r
1190 PC = (PC + skip) & VAMASK; /* add in skip */\r
1191 break; /* end if alter/skip */\r
1192\r
1193/* Shift instructions */\r
1194\r
1195 case 0000:case 0001:case 0002:case 0003:\r
1196 case 0010:case 0011:case 0012:case 0013:\r
1197 t = shift (ABREG[absel], IR & 01000, IR >> 6); /* do first shift */\r
1198 if (IR & 000040) E = 0; /* CLE */\r
1199 if ((IR & 000010) && ((t & 1) == 0)) /* SLx */\r
1200 PC = (PC + 1) & VAMASK;\r
1201 ABREG[absel] = shift (t, IR & 00020, IR); /* do second shift */\r
1202 break; /* end if shift */\r
1203\r
1204/* I/O instructions */\r
1205\r
1206 case 0204:case 0205:case 0206:case 0207:\r
1207 case 0214:case 0215:case 0216:case 0217:\r
1208 reason = iogrp (IR, iotrap); /* execute instr */\r
1209 break; /* end if I/O */\r
1210\r
1211/* Extended arithmetic */\r
1212\r
1213 case 0200: /* EAU group 0 */\r
1214 case 0201: /* divide */\r
1215 case 0202: /* EAU group 2 */\r
1216 case 0210: /* DLD */\r
1217 case 0211: /* DST */\r
1218 reason = cpu_eau (IR, intrq); /* extended arith */\r
1219 break;\r
1220\r
1221/* Extended instructions */\r
1222\r
1223 case 0212: /* UIG 0 extension */\r
1224 reason = cpu_uig_0 (IR, intrq, iotrap); /* extended opcode */\r
1225 break;\r
1226\r
1227 case 0203: /* UIG 1 extension */\r
1228 case 0213:\r
1229 reason = cpu_uig_1 (IR, intrq, iotrap); /* extended opcode */\r
1230 break;\r
1231 } /* end case IR */\r
1232\r
1233 if (reason == NOTE_IOG) { /* I/O instr exec? */\r
1234 dmarq = calc_dma (); /* recalc DMA masks */\r
1235 intrq = calc_int (); /* recalc interrupts */\r
1236 reason = 0; /* continue */\r
1237 }\r
1238\r
1239 else if (reason == NOTE_INDINT) { /* intr pend during indir? */\r
1240 PC = err_PC; /* back out of inst */\r
1241 reason = 0; /* continue */\r
1242 }\r
1243 } /* end while */\r
1244\r
1245/* Simulation halted */\r
1246\r
1247saved_AR = AR & DMASK;\r
1248saved_BR = BR & DMASK;\r
1249if (iotrap && (reason == STOP_HALT)) MR = intaddr; /* HLT in trap cell? */\r
1250else MR = (PC - 1) & VAMASK; /* no, M = P - 1 */\r
1251TR = ReadTAB (MR); /* last word fetched */\r
1252saved_MR = MR; /* save for T cmd update */\r
1253if ((reason == STOP_RSRV) || (reason == STOP_IODV) || /* instr error? */\r
1254 (reason == STOP_IND)) PC = err_PC; /* back up PC */\r
1255dms_upd_sr (); /* update dms_sr */\r
1256if (reason == STOP_HALT) /* programmed halt? */\r
1257 cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (ignore errors) */\r
1258for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */\r
1259 dibp = (DIB *) dptr->ctxt; /* get DIB */\r
1260 if (dibp) { /* exist? */\r
1261 dev = dibp->devno;\r
1262 dibp->cmd = CMD (dev);\r
1263 dibp->ctl = CTL (dev);\r
1264 dibp->flg = FLG (dev);\r
1265 dibp->fbf = FBF (dev);\r
1266 dibp->srq = SRQ (dev);\r
1267 }\r
1268 }\r
1269pcq_r->qptr = pcq_p; /* update pc q ptr */\r
1270if (dms_enb) /* default breakpoint type */\r
1271 if (dms_ump) sim_brk_dflt = SWMASK ('U'); /* to current map mode */\r
1272 else sim_brk_dflt = SWMASK ('S');\r
1273else sim_brk_dflt = SWMASK ('N');\r
1274return reason;\r
1275}\r
1276\r
1277/* Resolve indirect addresses.\r
1278\r
1279 An indirect chain is followed until a direct address is obtained. Under\r
1280 simulation, a maximum number of indirect levels are allowed (typically 16),\r
1281 after which the instruction will be aborted.\r
1282\r
1283 If the memory protect feature is present, an indirect counter is used that\r
1284 allows a pending interrupt to be serviced if more than three levels of\r
1285 indirection are encountered. If MP jumper W6 ("INT") is out and MP is\r
1286 enabled, then pending interrupts are serviced immediately. When employing\r
1287 the indirect counter, the hardware clears a pending interrupt deferral after\r
1288 the third indirection and aborts the instruction after the fourth.\r
1289*/\r
1290\r
1291t_stat resolve (uint32 MA, uint32 *addr, uint32 irq)\r
1292{\r
1293uint32 i;\r
1294t_bool pending = (irq && !(mp_unit.flags & DEV_DIS));\r
1295t_bool int_enable = ((mp_unit.flags & UNIT_MP_INT) && CTL(PRO));\r
1296\r
1297for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */\r
1298 if (pending) { /* interrupt pending and MP enabled? */\r
1299 if ((i == 2) || int_enable) /* 3rd level indirect or INT out? */\r
1300 ion_defer = 0; /* reenable interrrupts */\r
1301 if ((i > 2) || int_enable) /* 4th or higher or INT out? */\r
1302 return NOTE_INDINT; /* break out now */\r
1303 }\r
1304 MA = ReadW (MA & VAMASK); /* follow address chain */\r
1305 }\r
1306if (MA & I_IA) return STOP_IND; /* indirect loop? */\r
1307*addr = MA;\r
1308return SCPE_OK;\r
1309}\r
1310\r
1311/* Get effective address from IR */\r
1312\r
1313t_stat Ea (uint32 IR, uint32 *addr, uint32 irq)\r
1314{\r
1315uint32 MA;\r
1316\r
1317MA = IR & (I_IA | I_DISP); /* ind + disp */\r
1318if (IR & I_CP) MA = ((PC - 1) & I_PAGENO) | MA; /* current page? */\r
1319return resolve (MA, addr, irq); /* resolve indirects */\r
1320}\r
1321\r
1322/* Shift micro operation */\r
1323\r
1324uint32 shift (uint32 t, uint32 flag, uint32 op)\r
1325{\r
1326uint32 oldE;\r
1327\r
1328op = op & 07; /* get shift op */\r
1329if (flag) { /* enabled? */\r
1330 switch (op) { /* case on operation */\r
1331\r
1332 case 00: /* signed left shift */\r
1333 return ((t & SIGN) | ((t << 1) & 077777));\r
1334\r
1335 case 01: /* signed right shift */\r
1336 return ((t & SIGN) | (t >> 1));\r
1337\r
1338 case 02: /* rotate left */\r
1339 return (((t << 1) | (t >> 15)) & DMASK);\r
1340\r
1341 case 03: /* rotate right */\r
1342 return (((t >> 1) | (t << 15)) & DMASK);\r
1343\r
1344 case 04: /* left shift, 0 sign */\r
1345 return ((t << 1) & 077777);\r
1346\r
1347 case 05: /* ext right rotate */\r
1348 oldE = E;\r
1349 E = t & 1;\r
1350 return ((t >> 1) | (oldE << 15));\r
1351\r
1352 case 06: /* ext left rotate */\r
1353 oldE = E;\r
1354 E = (t >> 15) & 1;\r
1355 return (((t << 1) | oldE) & DMASK);\r
1356\r
1357 case 07: /* rotate left four */\r
1358 return (((t << 4) | (t >> 12)) & DMASK);\r
1359 } /* end case */\r
1360 } /* end if */\r
1361if (op == 05) E = t & 1; /* disabled ext rgt rot */\r
1362if (op == 06) E = (t >> 15) & 1; /* disabled ext lft rot */\r
1363return t; /* input unchanged */\r
1364}\r
1365\r
1366/* I/O instruction decode.\r
1367\r
1368 If memory protect is enabled, and the instruction is not in a trap cell, then\r
1369 HLT instructions are illegal and will cause a memory protect violation. If\r
1370 jumper W7 (SEL1) is in, then all other I/O instructions are legal; if W7 is\r
1371 out, then only I/O instructions to select code 1 are legal.\r
1372\r
1373 We return NOTE_IOG for normal status instead of SCPE_OK to request that\r
1374 interrupts be recalculated at the end of the instruction (execution of the\r
1375 I/O group instructions can change the interrupt priority chain).\r
1376*/\r
1377\r
1378t_stat iogrp (uint32 ir, uint32 iotrap)\r
1379{\r
1380uint32 dev, sop, iodata, iostat, ab;\r
1381\r
1382ab = (ir & I_AB)? 1: 0; /* get A/B select */\r
1383dev = ir & I_DEVMASK; /* get device */\r
1384sop = I_GETIOOP (ir); /* get subopcode */\r
1385if (!iotrap && CTL (PRO) && /* protected? */\r
1386 ((sop == ioHLT) || /* halt or !ovf? */\r
1387 ((dev != OVF) && (mp_unit.flags & UNIT_MP_SEL1)))) { /* sel code OK? */\r
1388 if (sop == ioLIX) ABREG[ab] = 0; /* A/B writes anyway */\r
1389 ABORT (ABORT_PRO);\r
1390 }\r
1391iodata = devdisp (dev, sop, ir, ABREG[ab]); /* process I/O */\r
1392ion_defer = defer_tab[sop]; /* set defer */\r
1393if ((sop == ioMIX) || (sop == ioLIX)) /* store ret data */\r
1394 ABREG[ab] = iodata & DMASK;\r
1395if (sop == ioHLT) { /* halt? */\r
1396 int32 len = strlen (halt_msg); /* find end msg */\r
1397 sprintf (&halt_msg[len - 6], "%06o", ir); /* add the halt */\r
1398 return STOP_HALT;\r
1399 }\r
1400iostat = iodata >> IOT_V_REASON;\r
1401if (iostat == SCPE_OK) return NOTE_IOG; /* normal status */\r
1402else return iostat; /* abnormal status */\r
1403}\r
1404\r
1405/* Device dispatch */\r
1406\r
1407uint32 devdisp (uint32 devno, uint32 inst, uint32 IR, uint32 dat)\r
1408{\r
1409if (dtab[devno]) return dtab[devno] (inst, IR, dat);\r
1410else return nulio (inst, IR, dat);\r
1411}\r
1412\r
1413/* Calculate DMA requests */\r
1414\r
1415uint32 calc_dma (void)\r
1416{\r
1417uint32 r = 0;\r
1418\r
1419if (CMD (DMA0) && SRQ (dmac[0].cw1 & I_DEVMASK)) /* check DMA0 cycle */\r
1420 r = r | DMAR0;\r
1421if (CMD (DMA1) && SRQ (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */\r
1422 r = r | DMAR1;\r
1423return r;\r
1424}\r
1425\r
1426/* Determine whether a pending interrupt deferral should be inhibited.\r
1427\r
1428 Execution of certain instructions generally causes a pending interrupt to be\r
1429 deferred until the succeeding instruction completes. However, the interrupt\r
1430 deferral rules differ on the 21xx vs. the 1000.\r
1431 \r
1432 The 1000 always defers until the completion of the instruction following a\r
1433 deferring instruction. The 21xx defers unless the following instruction is\r
1434 an MRG instruction other than JMP or JMP,I or JSB,I. If it is, then the\r
1435 deferral is inhibited, i.e., the pending interrupt will be serviced.\r
1436 \r
1437 See the "Set Phase Logic Flowchart," transition from phase 1A to phase 1B,\r
1438 and the "Theory of Operation," "Control Section Detailed Theory," "Phase\r
1439 Control Logic," "Phase 1B" paragraph in the Model 2100A Computer Installation\r
1440 and Maintenance Manual for details.\r
1441*/\r
1442\r
1443uint32 calc_defer (void)\r
1444{\r
1445uint16 IR;\r
1446\r
1447if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx series? */\r
1448 IR = ReadW (PC); /* prefetch next instr */\r
1449\r
1450 if (((IR & I_MRG & ~I_AB) != 0000000) && /* is MRG instruction? */\r
1451 ((IR & I_MRG_I) != I_JSB_I) && /* but not JSB,I? */\r
1452 ((IR & I_MRG) != I_JMP)) /* and not JMP or JMP,I? */\r
1453 return 0; /* yes, so inhibit deferral */\r
1454 else\r
1455 return 1; /* no, so allow deferral */\r
1456 }\r
1457else\r
1458 return 1; /* 1000 always allows deferral */\r
1459}\r
1460\r
1461/* Calculate interrupt requests\r
1462\r
1463 This routine takes into account all the relevant state of the\r
1464 interrupt system: ion, dev_flg, dev_fbf, and dev_ctl.\r
1465\r
1466 1. dev_flg & dev_ctl determines the end of the priority grant.\r
1467 The break in the chain will occur at the first device for\r
1468 which dev_flg & dev_ctl is true. This is determined by\r
1469 AND'ing the set bits with their 2's complement; only the low\r
1470 order (highest priority) bit will differ. 1 less than\r
1471 that, or'd with the single set bit itself, is the mask of\r
1472 possible interrupting devices. If ION is clear, only devices\r
1473 4 and 5 are eligible to interrupt.\r
1474 2. dev_flg & dev_ctl & dev_fbf determines the outstanding\r
1475 interrupt requests. All three bits must be on for a device\r
1476 to request an interrupt. This is the masked under the\r
1477 result from #1 to determine the highest priority interrupt,\r
1478 if any.\r
1479*/\r
1480\r
1481uint32 calc_int (void)\r
1482{\r
1483int32 j, lomask, mask[2], req[2];\r
1484\r
1485lomask = dev_flg[0] & dev_ctl[0] & ~M_NXDEV; /* start chain calc */\r
1486req[0] = lomask & dev_fbf[0]; /* calc requests */\r
1487lomask = lomask & (-lomask); /* chain & -chain */\r
1488mask[0] = lomask | (lomask - 1); /* enabled devices */\r
1489req[0] = req[0] & mask[0]; /* highest request */\r
1490if (ion) { /* ion? */\r
1491 if (lomask == 0) { /* no break in chn? */\r
1492 mask[1] = dev_flg[1] & dev_ctl[1]; /* do all devices */\r
1493 req[1] = mask[1] & dev_fbf[1];\r
1494 mask[1] = mask[1] & (-mask[1]);\r
1495 mask[1] = mask[1] | (mask[1] - 1);\r
1496 req[1] = req[1] & mask[1];\r
1497 }\r
1498 else req[1] = 0;\r
1499 }\r
1500else {\r
1501 req[0] = req[0] & (INT_M (PWR) | INT_M (PRO));\r
1502 req[1] = 0;\r
1503 }\r
1504if (req[0]) { /* if low request */\r
1505 for (j = 0; j < 32; j++) { /* find dev # */\r
1506 if (req[0] & INT_M (j)) return j;\r
1507 }\r
1508 }\r
1509if (req[1]) { /* if hi request */\r
1510 for (j = 0; j < 32; j++) { /* find dev # */\r
1511 if (req[1] & INT_M (j)) return (32 + j);\r
1512 }\r
1513 }\r
1514return 0;\r
1515}\r
1516\r
1517/* Memory access routines */\r
1518\r
1519uint8 ReadB (uint32 va)\r
1520{\r
1521int32 pa;\r
1522\r
1523if (dms_enb) pa = dms (va >> 1, dms_ump, RD);\r
1524else pa = va >> 1;\r
1525if (va & 1) return (ReadPW (pa) & 0377);\r
1526else return ((ReadPW (pa) >> 8) & 0377);\r
1527}\r
1528\r
1529uint8 ReadBA (uint32 va)\r
1530{\r
1531uint32 pa;\r
1532\r
1533if (dms_enb) pa = dms (va >> 1, dms_ump ^ MAP_LNT, RD);\r
1534else pa = va >> 1;\r
1535if (va & 1) return (ReadPW (pa) & 0377);\r
1536else return ((ReadPW (pa) >> 8) & 0377);\r
1537}\r
1538\r
1539uint16 ReadW (uint32 va)\r
1540{\r
1541uint32 pa;\r
1542\r
1543if (dms_enb) pa = dms (va, dms_ump, RD);\r
1544else pa = va;\r
1545return ReadPW (pa);\r
1546}\r
1547\r
1548uint16 ReadWA (uint32 va)\r
1549{\r
1550uint32 pa;\r
1551\r
1552if (dms_enb) pa = dms (va, dms_ump ^ MAP_LNT, RD);\r
1553else pa = va;\r
1554return ReadPW (pa);\r
1555}\r
1556\r
1557uint16 ReadIO (uint32 va, uint32 map)\r
1558{\r
1559uint32 pa;\r
1560\r
1561if (dms_enb) pa = dms_io (va, map);\r
1562else pa = va;\r
1563return M[pa];\r
1564}\r
1565\r
1566uint16 ReadPW (uint32 pa)\r
1567{\r
1568if (pa <= 1) return ABREG[pa];\r
1569return M[pa];\r
1570}\r
1571\r
1572uint16 ReadTAB (uint32 addr)\r
1573{\r
1574if (addr == 0) return saved_AR;\r
1575else if (addr == 1) return saved_BR;\r
1576else return ReadIO (addr, dms_ump);\r
1577}\r
1578\r
1579/* Memory protection test for writes\r
1580\r
1581 From Dave Bryan: The problem is that memory writes aren't being checked for\r
1582 an MP violation if DMS is enabled, i.e., if DMS is enabled, and the page is\r
1583 writable, then whether the target is below the MP fence is not checked. [The\r
1584 simulator must] do MP check on all writes after DMS translation and violation\r
1585 checks are done (so, to pass, the page must be writable AND the target must\r
1586 be above the MP fence).\r
1587*/\r
1588\r
1589#define MP_TEST(x) (CTL (PRO) && ((x) > 1) && ((x) < mp_fence))\r
1590\r
1591void WriteB (uint32 va, uint32 dat)\r
1592{\r
1593uint32 pa, t;\r
1594\r
1595if (dms_enb) pa = dms (va >> 1, dms_ump, WR);\r
1596else pa = va >> 1;\r
1597if (MP_TEST (va >> 1)) ABORT (ABORT_PRO);\r
1598if (MEM_ADDR_OK (pa)) {\r
1599 t = ReadPW (pa);\r
1600 if (va & 1) t = (t & 0177400) | (dat & 0377);\r
1601 else t = (t & 0377) | ((dat & 0377) << 8);\r
1602 WritePW (pa, t);\r
1603 }\r
1604return;\r
1605}\r
1606\r
1607void WriteBA (uint32 va, uint32 dat)\r
1608{\r
1609uint32 pa, t;\r
1610\r
1611if (dms_enb) {\r
1612 dms_viol (va >> 1, MVI_WPR); /* viol if prot */\r
1613 pa = dms (va >> 1, dms_ump ^ MAP_LNT, WR);\r
1614 }\r
1615else pa = va >> 1;\r
1616if (MP_TEST (va >> 1)) ABORT (ABORT_PRO);\r
1617if (MEM_ADDR_OK (pa)) {\r
1618 t = ReadPW (pa);\r
1619 if (va & 1) t = (t & 0177400) | (dat & 0377);\r
1620 else t = (t & 0377) | ((dat & 0377) << 8);\r
1621 WritePW (pa, t);\r
1622 }\r
1623return;\r
1624}\r
1625\r
1626void WriteW (uint32 va, uint32 dat)\r
1627{\r
1628uint32 pa;\r
1629\r
1630if (dms_enb) pa = dms (va, dms_ump, WR);\r
1631else pa = va;\r
1632if (MP_TEST (va)) ABORT (ABORT_PRO);\r
1633if (MEM_ADDR_OK (pa)) WritePW (pa, dat);\r
1634return;\r
1635}\r
1636\r
1637void WriteWA (uint32 va, uint32 dat)\r
1638{\r
1639int32 pa;\r
1640\r
1641if (dms_enb) {\r
1642 dms_viol (va, MVI_WPR); /* viol if prot */\r
1643 pa = dms (va, dms_ump ^ MAP_LNT, WR);\r
1644 }\r
1645else pa = va;\r
1646if (MP_TEST (va)) ABORT (ABORT_PRO);\r
1647if (MEM_ADDR_OK (pa)) WritePW (pa, dat);\r
1648return;\r
1649}\r
1650\r
1651void WriteIO (uint32 va, uint32 dat, uint32 map)\r
1652{\r
1653uint32 pa;\r
1654\r
1655if (dms_enb) pa = dms_io (va, map);\r
1656else pa = va;\r
1657if (MEM_ADDR_OK (pa)) M[pa] = dat & DMASK;\r
1658return;\r
1659}\r
1660\r
1661void WritePW (uint32 pa, uint32 dat)\r
1662{\r
1663if (pa <= 1) ABREG[pa] = dat & DMASK;\r
1664else M[pa] = dat & DMASK;\r
1665return;\r
1666}\r
1667\r
1668/* DMS relocation for CPU access */\r
1669\r
1670uint32 dms (uint32 va, uint32 map, uint32 prot)\r
1671{\r
1672uint32 pgn, mpr;\r
1673\r
1674if (va <= 1) return va; /* A, B */\r
1675pgn = VA_GETPAG (va); /* get page num */\r
1676if (pgn == 0) { /* base page? */\r
1677 uint32 dms_fence = dms_sr & MST_FENCE; /* get fence value */\r
1678 if ((dms_sr & MST_FLT)? /* check unmapped */\r
1679 (va >= dms_fence): /* 1B10: >= fence */\r
1680 (va < dms_fence)) { /* 0B10: < fence */\r
1681 if (prot == WR) dms_viol (va, MVI_BPG); /* if W, viol */\r
1682 return va; /* no mapping */\r
1683 }\r
1684 }\r
1685mpr = dms_map[map + pgn]; /* get map reg */\r
1686if (mpr & prot) dms_viol (va, prot); /* prot violation? */\r
1687return (MAP_GETPAG (mpr) | VA_GETOFF (va));\r
1688}\r
1689\r
1690/* DMS relocation for IO access */\r
1691\r
1692uint32 dms_io (uint32 va, uint32 map)\r
1693{\r
1694uint32 pgn, mpr;\r
1695\r
1696if (va <= 1) return va; /* A, B */\r
1697pgn = VA_GETPAG (va); /* get page num */\r
1698if (pgn == 0) { /* base page? */\r
1699 uint32 dms_fence = dms_sr & MST_FENCE; /* get fence value */\r
1700 if ((dms_sr & MST_FLT)? /* check unmapped */\r
1701 (va >= dms_fence): /* 1B10: >= fence */\r
1702 (va < dms_fence)) { /* 0B10: < fence */\r
1703 return va; /* no mapping */\r
1704 }\r
1705 }\r
1706mpr = dms_map[map + pgn]; /* get map reg */\r
1707return (MAP_GETPAG (mpr) | VA_GETOFF (va));\r
1708}\r
1709\r
1710/* DMS relocation for console access */\r
1711\r
1712uint32 dms_cons (uint32 va, int32 sw)\r
1713{\r
1714uint32 map_sel;\r
1715\r
1716if ((dms_enb == 0) || /* DMS off? */\r
1717 (sw & (SWMASK ('N') | SIM_SW_REST))) /* no mapping rqst or save/rest? */\r
1718 return va; /* use physical address */\r
1719else if (sw & SWMASK ('S')) map_sel = SMAP;\r
1720else if (sw & SWMASK ('U')) map_sel = UMAP;\r
1721else if (sw & SWMASK ('P')) map_sel = PAMAP;\r
1722else if (sw & SWMASK ('Q')) map_sel = PBMAP;\r
1723else map_sel = dms_ump; /* dflt to log addr, cur map */\r
1724if (va >= VASIZE) return MEMSIZE; /* virtual, must be 15b */\r
1725else if (dms_enb) return dms_io (va, map_sel); /* DMS on? go thru map */\r
1726else return va; /* else return virtual */\r
1727}\r
1728\r
1729/* Mem protect and DMS validation for jumps */\r
1730\r
1731void mp_dms_jmp (uint32 va)\r
1732{\r
1733uint32 pgn = VA_GETPAG (va); /* get page num */\r
1734\r
1735if ((pgn == 0) && (va > 1)) { /* base page? */\r
1736 uint32 dms_fence = dms_sr & MST_FENCE; /* get fence value */\r
1737 if ((dms_sr & MST_FLT)? /* check unmapped */\r
1738 (va >= dms_fence): /* 1B10: >= fence */\r
1739 (va < dms_fence)) { /* 0B10: < fence */\r
1740 dms_viol (va, MVI_BPG); /* if W, viol */\r
1741 return; /* PRO not set */\r
1742 }\r
1743 }\r
1744if (CTL (PRO) && (va < mp_fence)) ABORT (ABORT_PRO); /* base page MPR */\r
1745return;\r
1746}\r
1747\r
1748/* DMS read and write maps */\r
1749\r
1750uint16 dms_rmap (uint32 mapi)\r
1751{\r
1752mapi = mapi & MAP_MASK;\r
1753return (dms_map[mapi] & ~MAP_MBZ);\r
1754}\r
1755\r
1756void dms_wmap (uint32 mapi, uint32 dat)\r
1757{\r
1758mapi = mapi & MAP_MASK;\r
1759dms_map[mapi] = (uint16) (dat & ~MAP_MBZ);\r
1760return;\r
1761}\r
1762\r
1763/* DMS violation */\r
1764\r
1765void dms_viol (uint32 va, uint32 st)\r
1766{\r
1767dms_vr = st | VA_GETPAG (va) |\r
1768 ((st & (MVI_RPR | MVI_WPR))? MVI_MEB: 0) | /* set MEB */\r
1769 (dms_enb? MVI_MEM: 0) | /* set MEM */\r
1770 (dms_ump? MVI_UMP: 0); /* set UMAP */\r
1771if (CTL (PRO)) { /* protected? */\r
1772 mp_mevff = 1; /* signal dms */\r
1773 ABORT (ABORT_PRO); /* abort */\r
1774 }\r
1775return;\r
1776}\r
1777\r
1778/* DMS update status */\r
1779\r
1780uint32 dms_upd_sr (void)\r
1781{\r
1782dms_sr = dms_sr & ~(MST_ENB | MST_UMP | MST_PRO);\r
1783if (dms_enb) dms_sr = dms_sr | MST_ENB;\r
1784if (dms_ump) dms_sr = dms_sr | MST_UMP;\r
1785if (CTL (PRO)) dms_sr = dms_sr | MST_PRO;\r
1786return dms_sr;\r
1787}\r
1788\r
1789/* Device 0 (CPU) I/O routine\r
1790\r
1791 NOTE: LIx/MIx reads floating I/O bus (0 on all machines).\r
1792\r
1793 NOTE: CLC 0 issues CRS to all devices, not CLC. While most cards react\r
1794 identically to CRS and CLC, some do not, e.g., the 12566B when used as an\r
1795 I/O diagnostic target. PRESET also issues CRS (with POPIO).\r
1796\r
1797 From Dave Bryan: RTE uses the undocumented instruction "SFS 0,C" to both test\r
1798 and turn off the interrupt system. This is confirmed in the "RTE-6/VM\r
1799 Technical Specifications" manual (HP 92084-90015), section 2.3.1 "Process\r
1800 the Interrupt", subsection "A.1 $CIC":\r
1801\r
1802 "Test to see if the interrupt system is on or off. This is done with the\r
1803 SFS 0,C instruction. In either case, turn it off (the ,C does it)."\r
1804\r
1805 ...and in section 5.8, "Parity Error Detection":\r
1806\r
1807 "Because parity error interrupts can occur even when the interrupt system\r
1808 is off, the code at $CIC must be able to save the complete system status.\r
1809 The major hole in being able to save the complete state is in saving the\r
1810 interrupt system state. In order to do this in both the 21MX and the 21XE\r
1811 the instruction 103300 was used to both test the interrupt system and\r
1812 turn it off."\r
1813*/\r
1814\r
1815int32 cpuio (int32 inst, int32 IR, int32 dat)\r
1816{\r
1817int i;\r
1818\r
1819switch (inst) { /* case on opcode */\r
1820\r
1821 case ioFLG: /* flag */\r
1822 ion = (IR & I_HC)? 0: 1; /* interrupts off/on */\r
1823 return dat;\r
1824\r
1825 case ioSFC: /* skip flag clear */\r
1826 if (!ion) PC = (PC + 1) & VAMASK;\r
1827 break;\r
1828\r
1829 case ioSFS: /* skip flag set */\r
1830 if (ion) PC = (PC + 1) & VAMASK;\r
1831 break;\r
1832\r
1833 case ioLIX: /* load */\r
1834 dat = 0; /* returns 0 */\r
1835 break;\r
1836\r
1837 case ioCTL: /* control */\r
1838 if (IR & I_CTL) /* CLC 0 sends CRS */\r
1839 for (i = 0; i <= I_DEVMASK; i++) /* to all devices */\r
1840 devdisp (i, ioCRS, I_CTL + i, 0); /* IR -> "CLC i" for convenience */\r
1841 break;\r
1842\r
1843 default:\r
1844 break;\r
1845 }\r
1846\r
1847if (IR & I_HC) ion = 0; /* HC option */\r
1848return dat;\r
1849}\r
1850\r
1851/* Device 1 (overflow/S-register) I/O routine\r
1852\r
1853 NOTE: The S register is read-only on the 2115/2116. It is read/write on\r
1854 the 2114, 2100, and 1000.\r
1855*/\r
1856\r
1857int32 ovfio (int32 inst, int32 IR, int32 dat)\r
1858{\r
1859switch (inst) { /* case on opcode */\r
1860\r
1861 case ioFLG: /* flag */\r
1862 O = (IR & I_HC)? 0: 1; /* clear/set overflow */\r
1863 return dat;\r
1864\r
1865 case ioSFC: /* skip flag clear */\r
1866 if (!O) PC = (PC + 1) & VAMASK;\r
1867 break; /* can clear flag */\r
1868\r
1869 case ioSFS: /* skip flag set */\r
1870 if (O) PC = (PC + 1) & VAMASK;\r
1871 break; /* can clear flag */\r
1872\r
1873 case ioMIX: /* merge */\r
1874 dat = dat | SR;\r
1875 break;\r
1876\r
1877 case ioLIX: /* load */\r
1878 dat = SR;\r
1879 break;\r
1880\r
1881 case ioOTX: /* output */\r
1882 if ((UNIT_CPU_MODEL != UNIT_2116) &&\r
1883 (UNIT_CPU_MODEL != UNIT_2115))\r
1884 SR = dat;\r
1885 break;\r
1886\r
1887 default:\r
1888 break;\r
1889 }\r
1890\r
1891if (IR & I_HC) O = 0; /* HC option */\r
1892return dat;\r
1893}\r
1894\r
1895/* Device 4 (power fail) I/O routine */\r
1896\r
1897int32 pwrio (int32 inst, int32 IR, int32 dat)\r
1898{\r
1899switch (inst) { /* case on opcode */\r
1900\r
1901 case ioMIX: /* merge */\r
1902 dat = dat | intaddr;\r
1903 break;\r
1904\r
1905 case ioLIX: /* load */\r
1906 dat = intaddr;\r
1907 break;\r
1908\r
1909 default:\r
1910 break;\r
1911 }\r
1912\r
1913return dat;\r
1914}\r
1915\r
1916/* Device 5 (memory protect) I/O routine\r
1917\r
1918 From Dave Bryan: Examination of the schematics for the MP card in the\r
1919 engineering documentation shows that the SFS and SFC I/O backplane signals\r
1920 gate the output of the MEVFF onto the SKF line unconditionally.\r
1921\r
1922 The MEVFF records memory expansion (a.k.a. dynamic mapping) violations. It\r
1923 is set when an DM violation is encountered. It is cleared on POPIO, STC 5,\r
1924 and -HLT * IOGSP * INTPT. The latter occurs when an interrupt causes\r
1925 execution of a non-halt I/O instruction in the interrupt trap cell.\r
1926*/\r
1927\r
1928int32 proio (int32 inst, int32 IR, int32 dat)\r
1929{\r
1930switch (inst) { /* case on opcode */\r
1931\r
1932 case ioSFC: /* skip flag clear */\r
1933 if (!mp_mevff) PC = (PC + 1) & VAMASK; /* skip if mem prot */\r
1934 break;\r
1935\r
1936 case ioSFS: /* skip flag set */\r
1937 if (mp_mevff) PC = (PC + 1) & VAMASK; /* skip if DMS */\r
1938 break;\r
1939\r
1940 case ioMIX: /* merge */\r
1941 dat = dat | mp_viol;\r
1942 break;\r
1943\r
1944 case ioLIX: /* load */\r
1945 dat = mp_viol;\r
1946 break;\r
1947\r
1948 case ioOTX: /* output */\r
1949 mp_fence = dat & VAMASK;\r
1950 if (cpu_unit.flags & UNIT_2100) iop_sp = mp_fence;\r
1951 break;\r
1952\r
1953 case ioCRS: /* control reset */\r
1954 case ioCTL: /* control clear/set */\r
1955 if ((IR & I_CTL) == 0) { /* STC */\r
1956 setCTL (PRO);\r
1957 dms_vr = 0;\r
1958 mp_evrff = 1; /* allow mp_viol upd */\r
1959 mp_mevff = 0; /* clear DMS flag */\r
1960 }\r
1961 break;\r
1962\r
1963 default:\r
1964 break;\r
1965 }\r
1966\r
1967if (IR & I_HC) { clrFLG (PRO); } /* HC option */\r
1968return dat;\r
1969}\r
1970\r
1971/* Devices 2,3 (secondary DMA) I/O routine.\r
1972\r
1973 Implements control word 2 (memory address) and control word 3 (word count).\r
1974\r
1975 The 12607B (2114) supports 14-bit addresses and 13-bit word counts.\r
1976 The 12578A (2115/6) supports 15-bit addresses and 14-bit word counts.\r
1977 The 12895A (2100) and 12897B (1000) support 15-bit addresses and 16-bit word\r
1978 counts.\r
1979\r
1980 Note: because the I/O bus floats to zero on 211x computers, LIA/MIA (word\r
1981 count) returns zeros in the unused bit locations, even though the word count\r
1982 is a negative value.\r
1983*/\r
1984\r
1985int32 dmsio (int32 inst, int32 IR, int32 dat)\r
1986{\r
1987int32 ch;\r
1988\r
1989ch = IR & 1; /* get channel num */\r
1990switch (inst) { /* case on opcode */\r
1991\r
1992 case ioLIX: /* load remaining word count */\r
1993 dat = 0;\r
1994\r
1995 case ioMIX: /* merge */\r
1996 if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */\r
1997 dat = dat | (dmac[ch].cw3 & 0017777); /* only 13-bit count */\r
1998 else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2115/2116? */\r
1999 dat = dat | (dmac[ch].cw3 & 0037777); /* only 14-bit count */\r
2000 else\r
2001 dat = dat | dmac[ch].cw3; /* rest use full value */\r
2002 break;\r
2003\r
2004 case ioOTX: /* output */\r
2005 if (CTL (DMALT0 + ch)) /* word count selected? */\r
2006 dmac[ch].cw3 = dat; /* save count */\r
2007 else /* memory address selected */\r
2008 if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */\r
2009 dmac[ch].cw2 = dat & 0137777; /* 14-bit address */\r
2010 else\r
2011 dmac[ch].cw2 = dat; /* full address stored */\r
2012 break;\r
2013\r
2014 case ioCRS: /* control reset */\r
2015 case ioCTL: /* control clear/set */\r
2016 if (IR & I_CTL) { clrCTL (DMALT0 + ch); } /* CLC */\r
2017 else { setCTL (DMALT0 + ch); } /* STC */\r
2018 break;\r
2019\r
2020 default:\r
2021 break;\r
2022 }\r
2023\r
2024return dat;\r
2025}\r
2026\r
2027/* Devices 6,7 (primary DMA) I/O routine\r
2028\r
2029 Implements control word 1 (device address) and DMA control.\r
2030\r
2031 The 12607B (2114) stores only bits 2-0 of the select code and interprets them\r
2032 as select codes 10-16 (SRQ17 is not decoded). The 12578A (2115/6), 12895A\r
2033 (2100), and 12897B (1000) support the full 10-77 range of select codes.\r
2034\r
2035 The 12578A supports byte-sized transfers by setting bit 14. Bit 14 is\r
2036 ignored by all other DMA cards, which support word transfers only.\r
2037\r
2038 NOTE: LIx/MIx reads floating S-bus (1 on 21MX, 0 on 211x/2100).\r
2039\r
2040 NOTE: CRS clears control and command flip-flops, whereas CLC clears only\r
2041 control.\r
2042*/\r
2043\r
2044int32 dmpio (int32 inst, int32 IR, int32 dat)\r
2045{\r
2046int32 ch;\r
2047\r
2048ch = IR & 1; /* get channel number */\r
2049\r
2050switch (inst) { /* case on opcode */\r
2051\r
2052 case ioFLG: /* flag */\r
2053 if ((IR & I_HC) == 0) { /* set->abort */\r
2054 setFLG (DMA0 + ch); /* set flag */\r
2055 clrCMD (DMA0 + ch); /* clr cmd */\r
2056 }\r
2057 break;\r
2058\r
2059 case ioSFC: /* skip flag clear */\r
2060 if (FLG (DMA0 + ch) == 0) PC = (PC + 1) & VAMASK;\r
2061 break;\r
2062\r
2063 case ioSFS: /* skip flag set */\r
2064 if (FLG (DMA0 + ch) != 0) PC = (PC + 1) & VAMASK;\r
2065 break;\r
2066\r
2067 case ioLIX: /* load */\r
2068 dat = 0;\r
2069\r
2070 case ioMIX: /* merge */\r
2071 if (UNIT_CPU_TYPE == UNIT_TYPE_1000)\r
2072 dat = DMASK;\r
2073 break;\r
2074\r
2075 case ioOTX: /* output */\r
2076 if (UNIT_CPU_MODEL == UNIT_2114) /* 12607? */\r
2077 dmac[ch].cw1 = (dat & 0137707) | 010; /* mask SC, convert to 10-17 */\r
2078 else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 12578? */\r
2079 dmac[ch].cw1 = dat; /* store full select code, flags */\r
2080 else /* 12895, 12897 */\r
2081 dmac[ch].cw1 = dat & ~DMA1_PB; /* clip byte-packing flag */\r
2082 break;\r
2083\r
2084 case ioCRS: /* control reset */\r
2085 clrCMD (DMA0 + ch); /* clear command flip-flop */\r
2086\r
2087 case ioCTL: /* control */\r
2088 if (IR & I_CTL) { clrCTL (DMA0 + ch); } /* CLC: cmd unchgd */\r
2089 else { /* STC */\r
2090 if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* slow DMA card? */\r
2091 dmac[ch].latency = 1; /* needs startup latency */\r
2092 else\r
2093 dmac[ch].latency = 0; /* DCPC starts immediately */\r
2094\r
2095 dmac[ch].packer = 0; /* clear packing register */\r
2096 setCTL (DMA0 + ch); /* set ctl, cmd */\r
2097 setCMD (DMA0 + ch);\r
2098 }\r
2099 break;\r
2100\r
2101 default:\r
2102 break;\r
2103 }\r
2104\r
2105if (IR & I_HC) { clrFLG (DMA0 + ch); } /* HC option */\r
2106return dat;\r
2107}\r
2108\r
2109/* DMA cycle routine\r
2110\r
2111 The 12578A card supports byte-packing. If bit 14 in control word 1 is set,\r
2112 each transfer will involve one read/write from memory and two output/input\r
2113 operations in order to transfer sequential bytes to/from the device.\r
2114\r
2115 The last cycle (word count reaches 0) logic is quite tricky.\r
2116 Input cases:\r
2117 - CLC requested: issue CLC\r
2118 Output cases:\r
2119 - neither STC nor CLC requested: issue CLF\r
2120 - STC requested but not CLC: issue STC,C\r
2121 - CLC requested but not STC: issue CLC,C\r
2122 - STC and CLC both requested: issue STC,C and CLC,C, in that order\r
2123 Either: issue EDT (pass DMA channel number and I/O flag)\r
2124*/\r
2125\r
2126void dma_cycle (uint32 ch, uint32 map)\r
2127{\r
2128int32 temp, dev, MA;\r
2129int32 inp = dmac[ch].cw2 & DMA2_OI; /* input flag */\r
2130int32 byt = dmac[ch].cw1 & DMA1_PB; /* pack bytes flag */\r
2131\r
2132if (dmac[ch].latency) { /* start-up latency? */\r
2133 dmac[ch].latency = dmac[ch].latency - 1; /* decrease it */\r
2134 return; /* that's all this cycle */\r
2135 }\r
2136\r
2137dev = dmac[ch].cw1 & I_DEVMASK; /* get device */\r
2138MA = dmac[ch].cw2 & VAMASK; /* get mem addr */\r
2139\r
2140if (inp) { /* input cycle? */\r
2141 temp = devdisp (dev, ioLIX, dev, 0); /* do LIA dev */\r
2142\r
2143 if (byt) { /* byte packing? */\r
2144 if (dmac[ch].packer & DMA_OE) { /* second byte? */\r
2145 temp = (dmac[ch].packer << 8) | /* merge stored byte */\r
2146 (temp & DMASK8);\r
2147 WriteIO (MA, temp, map); /* store word data */\r
2148 }\r
2149 else /* first byte */\r
2150 dmac[ch].packer = (temp & DMASK8); /* save it */\r
2151\r
2152 dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */\r
2153 }\r
2154 else /* no byte packing */\r
2155 WriteIO (MA, temp, map); /* store word data */\r
2156 }\r
2157else { /* output cycle */\r
2158 if (byt) { /* byte packing? */\r
2159 if (dmac[ch].packer & DMA_OE) /* second byte? */\r
2160 temp = dmac[ch].packer & DMASK8; /* retrieve it */\r
2161\r
2162 else { /* first byte */\r
2163 dmac[ch].packer = ReadIO (MA, map); /* read word data */\r
2164 temp = (dmac[ch].packer >> 8) & DMASK8; /* get high byte */\r
2165 }\r
2166\r
2167 dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */\r
2168 }\r
2169 else /* no byte packing */\r
2170 temp = ReadIO (MA, map); /* read word data */\r
2171\r
2172 devdisp (dev, ioOTX, dev, temp); /* do OTA dev */\r
2173 }\r
2174\r
2175if ((dmac[ch].packer & DMA_OE) == 0) { /* new byte or no packing? */\r
2176 dmac[ch].cw2 = (dmac[ch].cw2 & DMA2_OI) | /* increment address */\r
2177 ((dmac[ch].cw2 + 1) & VAMASK);\r
2178 dmac[ch].cw3 = (dmac[ch].cw3 + 1) & DMASK; /* increment word count */\r
2179 }\r
2180\r
2181if (dmac[ch].cw3) { /* more to do? */\r
2182 if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */\r
2183 devdisp (dev, ioCTL, I_HC + dev, 0); /* do STC,C dev */\r
2184 else devdisp (dev, ioFLG, I_HC + dev, 0); /* else CLF dev */\r
2185 }\r
2186else {\r
2187 if (inp) { /* last cycle, input? */\r
2188 if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */\r
2189 devdisp (dev, ioCTL, I_CTL + dev, 0); /* yes */\r
2190 } /* end input */\r
2191 else { /* output */\r
2192 if ((dmac[ch].cw1 & (DMA1_STC | DMA1_CLC)) == 0)\r
2193 devdisp (dev, ioFLG, I_HC + dev, 0); /* clear flag */\r
2194 if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */\r
2195 devdisp (dev, ioCTL, I_HC + dev, 0); /* do STC,C dev */\r
2196 if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */\r
2197 devdisp (dev, ioCTL, I_HC + I_CTL + dev, 0); /* yes */\r
2198 } /* end output */\r
2199 setFLG (DMA0 + ch); /* set DMA flg */\r
2200 clrCMD (DMA0 + ch); /* clr DMA cmd */\r
2201 devdisp (dev, ioEDT, dev, inp | ch); /* do EDT */\r
2202 }\r
2203return;\r
2204}\r
2205\r
2206/* Unimplemented device routine\r
2207\r
2208 NOTE: For SC < 10, LIx/MIx reads floating S-bus (-1 on 21MX, 0 on 211x/2100).\r
2209 For SC >= 10, LIx/MIx reads floating I/O bus (0 on all machines).\r
2210*/\r
2211\r
2212int32 nulio (int32 inst, int32 IR, int32 dat)\r
2213{\r
2214int32 devd;\r
2215\r
2216devd = IR & I_DEVMASK; /* get device no */\r
2217switch (inst) { /* case on opcode */\r
2218\r
2219 case ioSFC: /* skip flag clear */\r
2220 PC = (PC + 1) & VAMASK;\r
2221 break;\r
2222\r
2223 case ioLIX: /* load */\r
2224 dat = 0;\r
2225\r
2226 case ioMIX: /* merge */\r
2227 if ((devd < VARDEV) && (UNIT_CPU_TYPE == UNIT_TYPE_1000))\r
2228 dat = DMASK;\r
2229 break;\r
2230\r
2231 default:\r
2232 break;\r
2233 }\r
2234\r
2235return (stop_dev << IOT_V_REASON) | dat;\r
2236}\r
2237\r
2238/* Reset routines */\r
2239\r
2240t_stat cpu_reset (DEVICE *dptr)\r
2241{\r
2242E = 0;\r
2243O = 0;\r
2244ion = ion_defer = 0;\r
2245clrCMD (PWR);\r
2246clrCTL (PWR);\r
2247clrFLG (PWR);\r
2248clrFBF (PWR);\r
2249dev_srq[0] = dev_srq[0] & ~M_FXDEV;\r
2250dms_enb = dms_ump = 0; /* init DMS */\r
2251dms_sr = 0;\r
2252dms_vr = 0;\r
2253pcq_r = find_reg ("PCQ", NULL, dptr);\r
2254sim_brk_types = ALL_BKPTS;\r
2255sim_brk_dflt = SWMASK ('N'); /* type is nomap as DMS is off */\r
2256\r
2257if (M == NULL) { /* initial call? */\r
2258 M = calloc (PASIZE, sizeof (uint16)); /* alloc mem */\r
2259\r
2260 if (M == NULL) /* alloc fail? */\r
2261 return SCPE_MEM;\r
2262 else { /* do one-time init */\r
2263 MEMSIZE = 32768; /* set initial memory size */\r
2264 cpu_set_model (NULL, UNIT_2116, NULL, NULL); /* set initial CPU model */\r
2265 SR = 001000; /* select PTR boot ROM at SC 10 */\r
2266 cpu_boot (0, NULL); /* install loader for 2116 */\r
2267 cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (was enabled) */\r
2268 SR = 0; /* clear S */\r
2269 sim_vm_post = &hp_post_cmd; /* set cmd post proc */\r
2270 }\r
2271}\r
2272\r
2273if (pcq_r) pcq_r->qptr = 0;\r
2274else return SCPE_IERR;\r
2275return SCPE_OK;\r
2276}\r
2277\r
2278t_stat mp_reset (DEVICE *dptr)\r
2279{\r
2280clrCTL (PRO);\r
2281clrFLG (PRO);\r
2282clrFBF (PRO);\r
2283mp_fence = 0; /* init mprot */\r
2284mp_viol = 0;\r
2285mp_mevff = 0;\r
2286mp_evrff = 1;\r
2287return SCPE_OK;\r
2288}\r
2289\r
2290t_stat dma0_reset (DEVICE *tptr)\r
2291{\r
2292if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */\r
2293 hp_enbdis_pair (&dma0_dev, &dma1_dev); /* make pair cons */\r
2294clrCMD (DMA0);\r
2295clrCTL (DMA0);\r
2296setFLG (DMA0);\r
2297clrSRQ (DMA0);\r
2298clrCTL (DMALT0);\r
2299dmac[0].latency = dmac[0].packer = 0;\r
2300if (sim_switches & SWMASK ('P')) /* power up? */\r
2301 dmac[0].cw1 = dmac[0].cw2 = dmac[0].cw3 = 0;\r
2302return SCPE_OK;\r
2303}\r
2304\r
2305t_stat dma1_reset (DEVICE *tptr)\r
2306{\r
2307if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */\r
2308 hp_enbdis_pair (&dma1_dev, &dma0_dev); /* make pair cons */\r
2309clrCMD (DMA1);\r
2310clrCTL (DMA1);\r
2311setFLG (DMA1);\r
2312clrSRQ (DMA1);\r
2313clrCTL (DMALT1);\r
2314dmac[1].latency = dmac[1].packer = 0;\r
2315if (sim_switches & SWMASK ('P')) /* power up? */\r
2316 dmac[1].cw1 = dmac[1].cw2 = dmac[1].cw3 = 0;\r
2317return SCPE_OK;\r
2318}\r
2319\r
2320/* Memory examine */\r
2321\r
2322t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r
2323{\r
2324int32 d;\r
2325\r
2326if ((sw & ALL_MAPMODES) && (dms_enb == 0)) /* req map with DMS off? */\r
2327 return SCPE_NOFNC; /* command not allowed */\r
2328addr = dms_cons (addr, sw);\r
2329if (addr >= MEMSIZE) return SCPE_NXM;\r
2330if (!(sw & SIM_SW_REST) && (addr == 0)) d = saved_AR;\r
2331else if (!(sw & SIM_SW_REST) && (addr == 1)) d = saved_BR;\r
2332else d = M[addr];\r
2333if (vptr != NULL) *vptr = d & DMASK;\r
2334return SCPE_OK;\r
2335}\r
2336\r
2337/* Memory deposit */\r
2338\r
2339t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r
2340{\r
2341if ((sw & ALL_MAPMODES) && (dms_enb == 0)) /* req map with DMS off? */\r
2342 return SCPE_NOFNC; /* command not allowed */\r
2343addr = dms_cons (addr, sw);\r
2344if (addr >= MEMSIZE) return SCPE_NXM;\r
2345if (!(sw & SIM_SW_REST) && (addr == 0)) saved_AR = val & DMASK;\r
2346else if (!(sw & SIM_SW_REST) && (addr == 1)) saved_BR = val & DMASK;\r
2347else M[addr] = val & DMASK;\r
2348return SCPE_OK;\r
2349}\r
2350\r
2351/* Set device number */\r
2352\r
2353t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc)\r
2354{\r
2355DEVICE *dptr = (DEVICE *) desc;\r
2356DIB *dibp;\r
2357int32 i, newdev;\r
2358t_stat r;\r
2359\r
2360if (cptr == NULL) return SCPE_ARG;\r
2361if ((desc == NULL) || (num > 1)) return SCPE_IERR;\r
2362dibp = (DIB *) dptr->ctxt;\r
2363if (dibp == NULL) return SCPE_IERR;\r
2364newdev = get_uint (cptr, 8, I_DEVMASK - num, &r);\r
2365if (r != SCPE_OK) return r;\r
2366if (newdev < VARDEV) return SCPE_ARG;\r
2367for (i = 0; i <= num; i++, dibp++) dibp->devno = newdev + i;\r
2368return SCPE_OK;\r
2369}\r
2370\r
2371/* Show device number */\r
2372\r
2373t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc)\r
2374{\r
2375DEVICE *dptr = (DEVICE *) desc;\r
2376DIB *dibp;\r
2377int32 i;\r
2378\r
2379if ((desc == NULL) || (num > 1)) return SCPE_IERR;\r
2380dibp = (DIB *) dptr->ctxt;\r
2381if (dibp == NULL) return SCPE_IERR;\r
2382fprintf (st, "devno=%o", dibp->devno);\r
2383for (i = 1; i <= num; i++) fprintf (st, "/%o", dibp->devno + i);\r
2384return SCPE_OK;\r
2385}\r
2386\r
2387/* Make a pair of devices consistent */\r
2388\r
2389void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp)\r
2390{\r
2391if (ccp->flags & DEV_DIS) dcp->flags = dcp->flags | DEV_DIS;\r
2392else dcp->flags = dcp->flags & ~DEV_DIS;\r
2393return;\r
2394}\r
2395\r
2396/* VM command post-processor\r
2397\r
2398 Update T register to contents of memory addressed by M register\r
2399 if M register has changed. */\r
2400\r
2401void hp_post_cmd (t_bool from_scp)\r
2402{\r
2403if (MR != saved_MR) { /* M changed since last update? */\r
2404 saved_MR = MR;\r
2405 TR = ReadTAB (MR); /* sync T with new M */\r
2406 }\r
2407return;\r
2408}\r
2409\r
2410/* Test for device conflict */\r
2411\r
2412t_bool dev_conflict (void)\r
2413{\r
2414DEVICE *dptr;\r
2415DIB *dibp;\r
2416uint32 i, j, k;\r
2417t_bool is_conflict = FALSE;\r
2418uint32 conflicts[I_DEVMASK + 1] = { 0 };\r
2419\r
2420for (i = 0; dptr = sim_devices[i]; i++) {\r
2421 dibp = (DIB *) dptr->ctxt;\r
2422 if (dibp && !(dptr->flags & DEV_DIS))\r
2423 if (++conflicts[dibp->devno] > 1)\r
2424 is_conflict = TRUE;\r
2425 }\r
2426\r
2427if (is_conflict) {\r
2428 sim_ttcmd();\r
2429 for (i = 0; i <= I_DEVMASK; i++) {\r
2430 if (conflicts[i] > 1) {\r
2431 k = conflicts[i];\r
2432 printf ("Select code %o conflict:", i);\r
2433 if (sim_log) fprintf (sim_log, "Select code %o conflict:", i);\r
2434 for (j = 0; dptr = sim_devices[j]; j++) {\r
2435 dibp = (DIB *) dptr->ctxt;\r
2436 if (dibp && !(dptr->flags & DEV_DIS) && (i == dibp->devno)) {\r
2437 if (k < conflicts[i]) {\r
2438 printf (" and");\r
2439 if (sim_log) fputs (" and", sim_log);\r
2440 }\r
2441 printf (" %s", sim_dname (dptr));\r
2442 if (sim_log) fprintf (sim_log, " %s", sim_dname (dptr));\r
2443 k = k - 1;\r
2444 if (k == 0) {\r
2445 putchar ('\n');\r
2446 if (sim_log) fputc ('\n', sim_log);\r
2447 break;\r
2448 }\r
2449 }\r
2450 }\r
2451 }\r
2452 }\r
2453 }\r
2454return is_conflict;\r
2455}\r
2456\r
2457/* Change CPU memory size.\r
2458\r
2459 On a 21xx, move the current loader to the top of the new memory size. Then\r
2460 clear "non-existent memory" so that reads return zero, per spec.\r
2461\r
2462 Validation:\r
2463 - New size <= maximum size for current CPU.\r
2464 - New size a positive multiple of 4K (progamming error if not).\r
2465 - If new size < old size, truncation accepted.\r
2466*/\r
2467\r
2468t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc)\r
2469{\r
2470int32 mc = 0;\r
2471uint32 i;\r
2472uint32 model = CPU_MODEL_INDEX; /* current CPU model index */\r
2473uint32 old_size = MEMSIZE; /* current memory size */\r
2474\r
2475if ((uint32) new_size > cpu_features[model].maxmem)\r
2476 return SCPE_NOFNC; /* mem size unsupported */\r
2477\r
2478if ((new_size <= 0) || (new_size > PASIZE) || ((new_size & 07777) != 0))\r
2479 return SCPE_NXM; /* invalid size (prog err) */\r
2480\r
2481if (!(sim_switches & SWMASK ('F'))) { /* force truncation? */\r
2482 for (i = new_size; i < MEMSIZE; i++) mc = mc | M[i];\r
2483 if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r
2484 return SCPE_INCOMP;\r
2485 }\r
2486\r
2487if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx CPU? */\r
2488 cpu_set_ldr (uptr, FALSE, NULL, NULL); /* save loader to shadow RAM */\r
2489 MEMSIZE = new_size; /* set new memory size */\r
2490 fwanxm = MEMSIZE - IBL_LNT; /* reserve memory for loader */\r
2491 }\r
2492else /* loader unsupported */\r
2493 fwanxm = MEMSIZE = new_size; /* set new memory size */\r
2494\r
2495for (i = fwanxm; i < old_size; i++) M[i] = 0; /* zero non-existent memory */\r
2496return SCPE_OK;\r
2497}\r
2498\r
2499/* Change CPU models.\r
2500\r
2501 For convenience, MP and DMA are typically enabled if available; they may be\r
2502 disabled subsequently if desired. Note that the 2114 supports only one DMA\r
2503 channel (channel 0). All other models support two channels.\r
2504\r
2505 Validation:\r
2506 - Sets standard equipment and convenience features.\r
2507 - Changes DMA device name to DCPC if 1000 is selected.\r
2508 - Enforces maximum memory allowed (doesn't change otherwise).\r
2509 - Disables loader on 21xx machines.\r
2510*/\r
2511\r
2512t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc)\r
2513{\r
2514uint32 old_family = UNIT_CPU_FAMILY; /* current CPU type */\r
2515uint32 new_family = new_model & UNIT_FAMILY_MASK; /* new CPU family */\r
2516uint32 new_index = new_model >> UNIT_V_CPU; /* new CPU model index */\r
2517uint32 new_memsize;\r
2518t_stat result;\r
2519\r
2520cpu_unit.flags = cpu_unit.flags & ~UNIT_OPTS | /* set typical features */\r
2521 cpu_features[new_index].typ & UNIT_OPTS; /* mask pseudo-opts */\r
2522\r
2523\r
2524if (cpu_features[new_index].typ & UNIT_MP) /* MP in typ config? */\r
2525 mp_dev.flags = mp_dev.flags & ~DEV_DIS; /* enable it */\r
2526else\r
2527 mp_dev.flags = mp_dev.flags | DEV_DIS; /* disable it */\r
2528\r
2529if (cpu_features[new_index].opt & UNIT_MP) /* MP an option? */\r
2530 mp_dev.flags = mp_dev.flags | DEV_DISABLE; /* make it alterable */\r
2531else\r
2532 mp_dev.flags = mp_dev.flags & ~DEV_DISABLE; /* make it unalterable */\r
2533\r
2534\r
2535if (cpu_features[new_index].typ & UNIT_DMA) { /* DMA in typ config? */\r
2536 dma0_dev.flags = dma0_dev.flags & ~DEV_DIS; /* enable DMA channel 0 */\r
2537\r
2538 if (new_model == UNIT_2114) /* 2114 has only one channel */\r
2539 dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */\r
2540 else /* all others have two channels */\r
2541 dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; /* enable it */\r
2542 }\r
2543else {\r
2544 dma0_dev.flags = dma0_dev.flags | DEV_DIS; /* disable channel 0 */\r
2545 dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */\r
2546 }\r
2547\r
2548if (cpu_features[new_index].opt & UNIT_DMA) { /* DMA an option? */\r
2549 dma0_dev.flags = dma0_dev.flags | DEV_DISABLE; /* make it alterable */\r
2550\r
2551 if (new_model == UNIT_2114) /* 2114 has only one channel */\r
2552 dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */\r
2553 else /* all others have two channels */\r
2554 dma1_dev.flags = dma1_dev.flags | DEV_DISABLE; /* make it alterable */\r
2555 }\r
2556else {\r
2557 dma0_dev.flags = dma0_dev.flags & ~DEV_DISABLE; /* make it unalterable */\r
2558 dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */\r
2559 }\r
2560\r
2561\r
2562if ((old_family == UNIT_FAMILY_1000) && /* if current family is 1000 */\r
2563 (new_family == UNIT_FAMILY_21XX)) { /* and new family is 21xx */\r
2564 deassign_device (&dma0_dev); /* delete DCPC names */\r
2565 deassign_device (&dma1_dev);\r
2566 }\r
2567else if ((old_family == UNIT_FAMILY_21XX) && /* if current family is 21xx */\r
2568 (new_family == UNIT_FAMILY_1000)) { /* and new family is 1000 */\r
2569 assign_device (&dma0_dev, "DCPC0"); /* change DMA device name */\r
2570 assign_device (&dma1_dev, "DCPC1"); /* to DCPC for familiarity */\r
2571 }\r
2572\r
2573if ((MEMSIZE == 0) || /* current mem size not set? */\r
2574 (MEMSIZE > cpu_features[new_index].maxmem)) /* current mem size too large? */\r
2575 new_memsize = cpu_features[new_index].maxmem; /* set it to max supported */\r
2576else\r
2577 new_memsize = MEMSIZE; /* or leave it unchanged */\r
2578\r
2579result = cpu_set_size (uptr, new_memsize, NULL, NULL); /* set memory size */\r
2580\r
2581if (result == SCPE_OK) /* memory change OK? */\r
2582 if (new_family == UNIT_FAMILY_21XX) /* 21xx CPU? */\r
2583 fwanxm = MEMSIZE - IBL_LNT; /* reserve memory for loader */\r
2584 else\r
2585 fwanxm = MEMSIZE; /* loader reserved only for 21xx */\r
2586\r
2587return result;\r
2588}\r
2589\r
2590/* Display the CPU model and optional loader status.\r
2591\r
2592 Loader status is displayed for 21xx models and suppressed for 1000 models.\r
2593*/\r
2594\r
2595t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc)\r
2596{\r
2597fputs ((char *) desc, st); /* write model name */\r
2598\r
2599if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) /* valid only for 21xx */\r
2600 if (fwanxm < MEMSIZE) /* loader area non-existent? */\r
2601 fputs (", loader disabled", st); /* yes, so access disabled */\r
2602 else\r
2603 fputs (", loader enabled", st); /* no, so access enabled */\r
2604return SCPE_OK;\r
2605}\r
2606\r
2607/* Set a CPU option.\r
2608\r
2609 Validation:\r
2610 - Checks that the current CPU model supports the option selected.\r
2611 - If CPU is 2100, ensures that FP/FFP and IOP are mutually exclusive.\r
2612 - If CPU is 2100, ensures that FP is enabled if FFP enabled\r
2613 (FP is required for FFP installation).\r
2614*/\r
2615\r
2616t_stat cpu_set_opt (UNIT *uptr, int32 option, char *cptr, void *desc)\r
2617{\r
2618uint32 model = CPU_MODEL_INDEX; /* current CPU model index */\r
2619\r
2620if ((cpu_features[model].opt & option) == 0) /* option supported? */\r
2621 return SCPE_NOFNC; /* no */\r
2622\r
2623if (UNIT_CPU_TYPE == UNIT_TYPE_2100) {\r
2624 if ((option == UNIT_FP) || (option == UNIT_FFP)) /* 2100 IOP and FP/FFP options */\r
2625 uptr->flags = uptr->flags & ~UNIT_IOP; /* are mutually exclusive */\r
2626 else if (option == UNIT_IOP)\r
2627 uptr->flags = uptr->flags & ~(UNIT_FP | UNIT_FFP);\r
2628\r
2629 if (option == UNIT_FFP) /* 2100 FFP option requires FP */\r
2630 uptr->flags = uptr->flags | UNIT_FP;\r
2631 }\r
2632\r
2633return SCPE_OK;\r
2634}\r
2635\r
2636/* Clear a CPU option.\r
2637\r
2638 Validation:\r
2639 - Checks that the current CPU model supports the option selected.\r
2640 - Clears flag from unit structure (we are processing MTAB_XTD entries).\r
2641 - If CPU is 2100, ensures that FFP is disabled if FP disabled\r
2642 (FP is required for FFP installation).\r
2643*/\r
2644\r
2645t_bool cpu_clr_opt (UNIT *uptr, int32 option, char *cptr, void *desc)\r
2646{\r
2647uint32 model = CPU_MODEL_INDEX; /* current CPU model index */\r
2648\r
2649if ((cpu_features[model].opt & option) == 0) /* option supported? */\r
2650 return SCPE_NOFNC; /* no */\r
2651\r
2652uptr->flags = uptr->flags & ~option; /* disable option */\r
2653\r
2654if ((UNIT_CPU_TYPE == UNIT_TYPE_2100) && /* disabling 2100 FP? */\r
2655 (option == UNIT_FP))\r
2656 uptr->flags = uptr->flags & ~UNIT_FFP; /* yes, so disable FFP too */\r
2657\r
2658return SCPE_OK;\r
2659}\r
2660\r
2661/* 21xx loader enable/disable function.\r
2662\r
2663 The 21xx CPUs store their initial binary loaders in the last 64 words of\r
2664 available memory. This memory is protected by a LOADER ENABLE switch on the\r
2665 front panel. When the switch is off (disabled), main memory effectively ends\r
2666 64 locations earlier, i.e., the loader area is treated as non-existent.\r
2667 Because these are core machines, the loader is retained when system power is\r
2668 off.\r
2669\r
2670 1000 CPUs do not have a protected loader feature. Instead, loaders are\r
2671 stored in PROMs and are copied into main memory for execution by the IBL\r
2672 switch.\r
2673\r
2674 Under simulation, we keep both a total configured memory size (MEMSIZE) and a\r
2675 current configured memory size (fwanxm = "first word address of non-existent\r
2676 memory). When the two are equal, the loader is enabled. When the current\r
2677 size is less than the total size, the loader is disabled.\r
2678\r
2679 Disabling the loader copies the last 64 words to a shadow array, zeros the\r
2680 corresponding memory, and decreases the last word of addressable memory by\r
2681 64. Enabling the loader reverses this process.\r
2682\r
2683 Disabling may be done manually by user command or automatically when a halt\r
2684 instruction is executed. Enabling occurs only by user command. This differs\r
2685 slightly from actual machine operation, which additionally disables the\r
2686 loader when a manual halt is performed. We do not do this to allow\r
2687 breakpoints within and single-stepping through the loaders.\r
2688*/\r
2689\r
2690t_stat cpu_set_ldr (UNIT *uptr, int32 enable, char *cptr, void *desc)\r
2691{\r
2692static uint16 loader[IBL_LNT];\r
2693int32 i;\r
2694t_bool is_enabled = (fwanxm == MEMSIZE);\r
2695\r
2696if ((UNIT_CPU_FAMILY != UNIT_FAMILY_21XX) || /* valid only for 21xx */\r
2697 (MEMSIZE == 0)) /* and for initialized memory */\r
2698 return SCPE_NOFNC;\r
2699\r
2700if (is_enabled && (enable == 0)) { /* disable loader? */\r
2701 fwanxm = MEMSIZE - IBL_LNT; /* decrease available memory */\r
2702 for (i = 0; i < IBL_LNT; i++) { /* copy loader */\r
2703 loader[i] = M[fwanxm + i]; /* from memory */\r
2704 M[fwanxm + i] = 0; /* and zero location */\r
2705 }\r
2706 }\r
2707\r
2708else if ((!is_enabled) && (enable == 1)) { /* enable loader? */\r
2709 for (i = 0; i < IBL_LNT; i++) /* copy loader */\r
2710 M[fwanxm + i] = loader[i]; /* to memory */\r
2711 fwanxm = MEMSIZE; /* increase available memory */\r
2712 }\r
2713\r
2714return SCPE_OK;\r
2715}\r
2716\r
2717/* IBL routine (CPU boot) */\r
2718\r
2719t_stat cpu_boot (int32 unitno, DEVICE *dptr)\r
2720{\r
2721extern const uint16 ptr_rom[IBL_LNT], dq_rom[IBL_LNT];\r
2722extern const uint16 ms_rom[IBL_LNT], ds_rom[IBL_LNT];\r
2723int32 dev = (SR >> IBL_V_DEV) & I_DEVMASK;\r
2724int32 sel = (SR >> IBL_V_SEL) & IBL_M_SEL;\r
2725\r
2726if (dev < 010) return SCPE_NOFNC;\r
2727switch (sel) {\r
2728\r
2729 case 0: /* PTR boot */\r
2730 ibl_copy (ptr_rom, dev);\r
2731 break;\r
2732\r
2733 case 1: /* DP/DQ boot */\r
2734 ibl_copy (dq_rom, dev);\r
2735 break;\r
2736\r
2737 case 2: /* MS boot */\r
2738 ibl_copy (ms_rom, dev);\r
2739 break;\r
2740\r
2741 case 3: /* DS boot */\r
2742 ibl_copy (ds_rom,dev);\r
2743 break;\r
2744 }\r
2745\r
2746return SCPE_OK;\r
2747}\r
2748\r
2749/* IBL boot ROM copy\r
2750\r
2751 - Use memory size to set the initial PC and base of the boot area\r
2752 - Copy boot ROM to memory, updating I/O instructions\r
2753 - Place 2's complement of boot base in last location\r
2754\r
2755 Notes:\r
2756 - SR settings are done by the caller\r
2757 - Boot ROM's must be assembled with a device code of 10 (10 and 11 for\r
2758 devices requiring two codes)\r
2759*/\r
2760\r
2761t_stat ibl_copy (const uint16 pboot[IBL_LNT], int32 dev)\r
2762{\r
2763int32 i;\r
2764uint16 wd;\r
2765\r
2766cpu_set_ldr (NULL, TRUE, NULL, NULL); /* enable loader (ignore errors) */\r
2767\r
2768if (dev < 010) return SCPE_ARG; /* valid device? */\r
2769PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */\r
2770for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */\r
2771 wd = pboot[i]; /* get word */\r
2772 if (((wd & I_NMRMASK) == I_IO) && /* IO instruction? */\r
2773 ((wd & I_DEVMASK) >= 010) && /* dev >= 10? */\r
2774 (I_GETIOOP (wd) != ioHLT)) /* not a HALT? */\r
2775 M[PC + i] = (wd + (dev - 010)) & DMASK; /* change dev code */\r
2776 else M[PC + i] = wd; /* leave unchanged */\r
2777 }\r
2778M[PC + IBL_DPC] = (M[PC + IBL_DPC] + (dev - 010)) & DMASK; /* patch DMA ctrl */\r
2779M[PC + IBL_END] = (~PC + 1) & DMASK; /* fill in start of boot */\r
2780return SCPE_OK;\r
2781}\r