1 /* pdp18b_cpu.c: 18b PDP CPU simulator
3 Copyright (c) 1993-2007, Robert M Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
26 cpu PDP-4/7/9/15 central processor
28 28-Apr-07 RMS Removed clock initialization
29 26-Dec-06 RMS Fixed boundary test in KT15/XVM (reported by Andrew Warkentin)
30 30-Oct-06 RMS Added idle and infinite loop detection
31 08-Oct-06 RMS Added RDCLK instruction
32 Fixed bug, PC off by one on fetch mem mmgt error
33 PDP-15 sets API 3 on mem mmgt trap (like PI)
34 PDP-15 sets API 4 on CAL only if 0-3 inactive
35 CAF clears memory management mode register
36 27-Jun-06 RMS Reset clears AC, L, and MQ
37 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
38 16-Aug-05 RMS Fixed C++ declaration and cast problems
39 22-Jul-05 RMS Removed AAS, error in V1 reference manual
40 06-Nov-04 RMS Added =n to SHOW HISTORY
41 26-Mar-04 RMS Fixed warning from -std=c99
42 14-Jan-04 RMS Fixed g_mode in XVM implementation
43 PDP-15 index, autoincrement generate 18b addresses
44 Revised IO device call interface
45 31-Dec-03 RMS Fixed bug in cpu_set_hist
46 02-Nov-03 RMS Changed PDP-9,-15 default to API
47 26-Oct-03 RMS Fixed bug in PDP-4,-7,-9 autoincrement addressing
48 19-Sep-03 RMS Changed instruction history to be dynamically sized
49 31-Aug-03 RMS Added instruction history
50 Fixed PDP-15-specific implementation of API priorities
51 16-Aug-03 RMS Fixed PDP-15-specific handling of EAE unsigned mul/div
52 27-Jul-03 RMS Added FP15 support
54 Added EAE option to PDP-4
55 Added PDP-15 "re-entrancy ECO"
56 Fixed memory protect/skip interaction
57 Fixed CAF not to reset CPU
58 12-Mar-03 RMS Added logical name support
59 18-Feb-03 RMS Fixed three EAE bugs (found by Hans Pufal)
60 05-Oct-02 RMS Added DIBs, device number support
61 25-Jul-02 RMS Added DECtape support for PDP-4
62 06-Jan-02 RMS Revised enable/disable support
63 30-Dec-01 RMS Added old PC queue
64 30-Nov-01 RMS Added extended SET/SHOW support
65 25-Nov-01 RMS Revised interrupt structure
66 19-Sep-01 RMS Fixed bug in EAE (found by Dave Conroy)
67 17-Sep-01 RMS Fixed typo in conditional
68 10-Aug-01 RMS Removed register from declarations
69 17-Jul-01 RMS Moved function prototype
70 27-May-01 RMS Added second Teletype support, fixed bug in API
71 18-May-01 RMS Added PDP-9,-15 API option
72 16-May-01 RMS Fixed bugs in protection checks
73 26-Apr-01 RMS Added device enable/disable support
74 25-Jan-01 RMS Added DECtape support
75 18-Dec-00 RMS Added PDP-9,-15 memm init register
76 30-Nov-00 RMS Fixed numerous PDP-15 bugs
77 14-Apr-99 RMS Changed t_addr to unsigned
79 The 18b PDP family has five distinct architectural variants: PDP-1,
80 PDP-4, PDP-7, PDP-9, and PDP-15. Of these, the PDP-1 is so unique
81 as to require a different simulator. The PDP-4, PDP-7, PDP-9, and
82 PDP-15 are "upward compatible", with each new variant adding
83 distinct architectural features and incompatibilities.
85 The register state for the 18b PDP's is:
87 all AC<0:17> accumulator
88 all MQ<0:17> multiplier-quotient
90 all PC<0:x> program counter
91 all IORS I/O status register
92 PDP-7, PDP-9 EXTM extend mode
93 PDP-15 BANKM bank mode
95 PDP-9, PDP-15 USMD user mode
96 PDP-9, PDP-15 BR bounds register
97 PDP-15 RR relocation register
98 PDP-15 XVM MMR memory management register
99 PDP-15 XR index register
100 PDP-15 LR limit register
102 The PDP-4, PDP-7, and PDP-9 have five instruction formats: memory
103 reference, load immediate, I/O transfer, EAE, and operate. The PDP-15
104 adds a sixth, index operate, and a seventh, floating point. The memory
105 reference format for the PDP-4, PDP-7, and PDP-9, and for the PDP-15
108 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
109 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
110 | op |in| address | memory reference
111 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
113 The PDP-15 in page mode trades an address bit for indexing capability:
115 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
116 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
117 | op |in| X| address | memory reference
118 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
120 <0:3> mnemonic action
122 00 CAL JMS with MA = 20
124 10 JMS M[MA] = L'mem'user'PC, PC = MA + 1
127 24 XOR AC = AC ^ M[MA]
128 30 ADD L'AC = AC + M[MA] one's complement
129 34 TAD L'AC = AC + M[MA]
130 40 XCT M[MA] is executed as an instruction
131 44 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0
132 50 AND AC = AC & M[MA]
133 54 SAD skip if AC != M[MA]
136 On the PDP-4, PDP-7, and PDP-9, and the PDP-15 in bank mode, memory
137 reference instructions can access an address space of 32K words. The
138 address space is divided into four 8K word fields. An instruction can
139 directly address, via its 13b address, the entire current field. On the
140 PDP-4, PDP-7, and PDP-9, if extend mode is off, indirect addresses access
141 the current field; if on (or a PDP-15), they can access all 32K.
143 On the PDP-15 in page mode, memory reference instructions can access
144 an address space of 128K words. The address is divided into four 32K
145 word blocks, each of which consists of eight 4K pages. An instruction
146 can directly address, via its 12b address, the current page. Indirect
147 addresses can access the current block. Indexed and autoincrement
148 addresses can access all 128K.
150 On the PDP-4 and PDP-7, if an indirect address in in locations 00010-
151 00017 of any field, the indirect address is incremented and rewritten
152 to memory before use. On the PDP-9 and PDP-15, only locations 00010-
153 00017 of field zero autoincrement; special logic will redirect indirect
154 references to 00010-00017 to field zero, even if (on the PDP-9) extend
159 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
160 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
161 | 1 1 0 1| | | | | | | | | | | | | | | EAE
162 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
163 | | | | | | | | | | | | | |
164 | | | | | | | | | | | | | +- or SC (3)
165 | | | | | | | | | | | | +---- or MQ (3)
166 | | | | | | | | | | | +------- compl MQ (3)
167 | | | | | | | | \______________/
169 | | | | | \_____/ +--------- shift count
171 | | | | | +---------------------- EAE command (3)
172 | | | | +---------------------------- clear AC (2)
173 | | | +------------------------------- or AC (2)
174 | | +---------------------------------- load EAE sign (1)
175 | +------------------------------------- clear MQ (1)
176 +---------------------------------------- load link (1)
178 The I/O transfer format is:
180 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
181 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
182 | 1 1 1 0 0 0| device | sdv |cl| pulse | I/O transfer
183 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
185 The IO transfer instruction sends the the specified pulse to the
186 specified I/O device and sub-device. The I/O device may take data
187 from the AC, return data to the AC, initiate or cancel operations,
188 or skip on status. On the PDP-4, PDP-7, and PDP-9, bits <4:5>
189 were designated as subdevice bits but were never used; the PDP-15
190 requires them to be zero.
192 On the PDP-15, the floating point format is:
194 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
195 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
196 | 1 1 1 0 0 1| subopcode | floating point
197 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
199 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
201 Indirection is always single level.
203 On the PDP-15, the index operate format is:
205 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
206 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
207 | 1 1 1 0 1| subopcode | immediate | index operate
208 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
210 The index operate instructions provide various operations on the
211 index and limit registers.
213 The operate format is:
215 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
216 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
217 | 1 1 1 1 0| | | | | | | | | | | | | | operate
218 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
219 | | | | | | | | | | | | |
220 | | | | | | | | | | | | +- CMA (3)
221 | | | | | | | | | | | +---- CML (3)
222 | | | | | | | | | | +------- OAS (3)
223 | | | | | | | | | +---------- RAL (3)
224 | | | | | | | | +------------- RAR (3)
225 | | | | | | | +---------------- HLT (4)
226 | | | | | | +------------------- SMA (1)
227 | | | | | +---------------------- SZA (1)
228 | | | | +------------------------- SNL (1)
229 | | | +---------------------------- invert skip (1)
230 | | +------------------------------- rotate twice (2)
231 | +---------------------------------- CLL (2)
232 +------------------------------------- CLA (2)
234 The operate instruction can be microprogrammed to perform operations
237 The load immediate format is:
239 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
240 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
241 | 1 1 1 1 1| immediate | LAW
242 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
244 <0:4> mnemonic action
248 This routine is the instruction decode routine for the 18b PDP's.
249 It is called from the simulator control program to execute
250 instructions in simulated memory, starting at the simulated PC.
251 It runs until 'reason' is set non-zero.
255 1. Reasons to stop. The simulator can be stopped by:
258 breakpoint encountered
259 unimplemented instruction and STOP_INST flag set
261 I/O error in I/O simulator
263 2. Interrupts. Interrupt requests are maintained in the int_hwre
264 array. int_hwre[0:3] corresponds to API levels 0-3; int_hwre[4]
267 3. Arithmetic. The 18b PDP's implements both 1's and 2's complement
268 arithmetic for signed numbers. In 1's complement arithmetic, a
269 negative number is represented by the complement (XOR 0777777) of
270 its absolute value. Addition of 1's complement numbers requires
271 propagating the carry out of the high order bit back to the low
274 4. Adding I/O devices. Three modules must be modified:
276 pdp18b_defs.h add interrupt request definition
277 pdp18b_sys.c add sim_devices table entry
280 #include "pdp18b_defs.h"
282 #define SEXT(x) ((int32) (((x) & SIGN)? (x) | ~DMASK: (x) & DMASK))
284 #define UNIT_V_NOEAE (UNIT_V_UF + 0) /* EAE absent */
285 #define UNIT_V_NOAPI (UNIT_V_UF + 1) /* API absent */
286 #define UNIT_V_PROT (UNIT_V_UF + 2) /* protection */
287 #define UNIT_V_RELOC (UNIT_V_UF + 3) /* relocation */
288 #define UNIT_V_XVM (UNIT_V_UF + 4) /* XVM */
289 #define UNIT_V_MSIZE (UNIT_V_UF + 5) /* dummy mask */
290 #define UNIT_NOEAE (1 << UNIT_V_NOEAE)
291 #define UNIT_NOAPI (1 << UNIT_V_NOAPI)
292 #define UNIT_PROT (1 << UNIT_V_PROT)
293 #define UNIT_RELOC (1 << UNIT_V_RELOC)
294 #define UNIT_XVM (1 << UNIT_V_XVM)
295 #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
296 #define OP_KSF 0700301
298 #define HIST_API 0x40000000
299 #define HIST_PI 0x20000000
300 #define HIST_PC 0x10000000
302 #define HIST_MAX 65536
303 #define HIST_M_LVL 0x3F
314 #define XVM (cpu_unit.flags & UNIT_XVM)
315 #define RELOC (cpu_unit.flags & UNIT_RELOC)
316 #define PROT (cpu_unit.flags & UNIT_PROT)
319 #define EAE_DFLT UNIT_NOEAE
323 #if defined (PDP4) || defined (PDP7)
324 #define API_DFLT UNIT_NOAPI
326 #define ASW_DFLT 017763
329 #define PROT_DFLT UNIT_PROT
330 #define ASW_DFLT 017720
333 int32 M
[MAXMEMSIZE
] = { 0 }; /* memory */
334 int32 LAC
= 0; /* link'AC */
335 int32 MQ
= 0; /* MQ */
336 int32 PC
= 0; /* PC */
337 int32 iors
= 0; /* IORS */
338 int32 ion
= 0; /* int on */
339 int32 ion_defer
= 0; /* int defer */
340 int32 ion_inh
= 0; /* int inhibit */
341 int32 int_pend
= 0; /* int pending */
342 int32 int_hwre
[API_HLVL
+1] = { 0 }; /* int requests */
343 int32 api_enb
= 0; /* API enable */
344 int32 api_req
= 0; /* API requests */
345 int32 api_act
= 0; /* API active */
346 int32 memm
= 0; /* mem mode */
348 int32 memm_init
= 1; /* mem init */
352 int32 usmd
= 0; /* user mode */
353 int32 usmd_buf
= 0; /* user mode buffer */
354 int32 usmd_defer
= 0; /* user mode defer */
355 int32 trap_pending
= 0; /* trap pending */
356 int32 emir_pending
= 0; /* emir pending */
357 int32 rest_pending
= 0; /* restore pending */
358 int32 BR
= 0; /* mem mgt bounds */
359 int32 RR
= 0; /* mem mgt reloc */
360 int32 MMR
= 0; /* XVM mem mgt */
361 int32 nexm
= 0; /* nx mem flag */
362 int32 prvn
= 0; /* priv viol flag */
363 int32 SC
= 0; /* shift count */
364 int32 eae_ac_sign
= 0; /* EAE AC sign */
365 int32 SR
= 0; /* switch register */
366 int32 ASW
= ASW_DFLT
; /* address switches */
367 int32 XR
= 0; /* index register */
368 int32 LR
= 0; /* limit register */
369 int32 stop_inst
= 0; /* stop on rsrv inst */
370 int32 xct_max
= 16; /* nested XCT limit */
372 int32 pcq
[PCQ_SIZE
] = { 0 }; /* PC queue */
374 int16 pcq
[PCQ_SIZE
] = { 0 }; /* PC queue */
376 int32 pcq_p
= 0; /* PC queue ptr */
377 REG
*pcq_r
= NULL
; /* PC queue reg ptr */
378 int32 hst_p
= 0; /* history pointer */
379 int32 hst_lnt
= 0; /* history length */
380 InstHistory
*hst
= NULL
; /* instruction history */
382 extern int32 sim_int_char
;
383 extern int32 sim_interval
;
384 extern uint32 sim_brk_types
, sim_brk_dflt
, sim_brk_summ
; /* breakpoint info */
385 extern t_bool sim_idle_enab
;
386 extern DEVICE
*sim_devices
[];
387 extern FILE *sim_log
;
389 t_bool
build_dev_tab (void);
390 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
);
391 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
);
392 t_stat
cpu_reset (DEVICE
*dptr
);
393 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
394 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
395 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
397 void cpu_inst_hist (int32 addr
, int32 inst
);
398 void cpu_intr_hist (int32 flag
, int32 lvl
);
399 int32
upd_iors (void);
400 int32
api_eval (int32
*pend
);
401 t_stat
Read (int32 ma
, int32
*dat
, int32 cyc
);
402 t_stat
Write (int32 ma
, int32 dat
, int32 cyc
);
403 t_stat
Ia (int32 ma
, int32
*ea
, t_bool jmp
);
404 int32
Incr_addr (int32 addr
);
405 int32
Jms_word (int32 t
);
407 #define INDEX(i,x) if (!memm && ((i) & I_IDX)) x = ((x) + XR) & DMASK
408 int32
Prot15 (int32 ma
, t_bool bndchk
);
409 int32
Reloc15 (int32 ma
, int32 acc
);
410 int32
RelocXVM (int32 ma
, int32 acc
);
411 extern t_stat
fp15 (int32 ir
);
412 extern int32
clk_task_upd (t_bool clr
);
417 extern int32
clk (int32 dev
, int32 pulse
, int32 AC
);
419 int32 (*dev_tab
[DEV_MAX
])(int32 dev
, int32 pulse
, int32 AC
); /* device dispatch */
421 int32 (*dev_iors
[DEV_MAX
])(void); /* IORS dispatch */
423 static const int32 api_ffo
[256] = {
424 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
425 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
426 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
427 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
428 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
429 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
430 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
434 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
436 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
438 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
442 static const int32 api_vec
[API_HLVL
][32] = {
443 { ACH_PWRFL
}, /* API 0 */
444 { ACH_DTA
, ACH_MTA
, ACH_DRM
, ACH_RF
, ACH_RP
, ACH_RB
}, /* API 1 */
445 { ACH_PTR
, ACH_LPT
, ACH_LPT
}, /* API 2 */
446 { ACH_CLK
, ACH_TTI1
, ACH_TTO1
} /* API 3 */
449 /* CPU data structures
451 cpu_dev CPU device descriptor
453 cpu_reg CPU register list
454 cpu_mod CPU modifier list
458 UDATA (NULL
, UNIT_FIX
+UNIT_BINK
+EAE_DFLT
+API_DFLT
+PROT_DFLT
,
463 { ORDATA (PC
, PC
, ADDRSIZE
) },
464 { ORDATA (AC
, LAC
, 18) },
465 { FLDATA (L
, LAC
, 18) },
466 { ORDATA (MQ
, MQ
, 18) },
467 { ORDATA (SC
, SC
, 6) },
468 { FLDATA (EAE_AC_SIGN
, eae_ac_sign
, 18) },
469 { ORDATA (SR
, SR
, 18) },
470 { ORDATA (ASW
, ASW
, ADDRSIZE
) },
471 { ORDATA (IORS
, iors
, 18), REG_RO
},
472 { BRDATA (INT
, int_hwre
, 8, 32, API_HLVL
+1), REG_RO
},
473 { FLDATA (INT_PEND
, int_pend
, 0), REG_RO
},
474 { FLDATA (ION
, ion
, 0) },
475 { ORDATA (ION_DELAY
, ion_defer
, 2) },
477 { FLDATA (TRAPM
, usmd
, 0) },
478 { FLDATA (TRAPP
, trap_pending
, 0) },
479 { FLDATA (EXTM
, memm
, 0) },
480 { FLDATA (EXTM_INIT
, memm_init
, 0) },
481 { FLDATA (EMIRP
, emir_pending
, 0) },
484 { FLDATA (APIENB
, api_enb
, 0) },
485 { ORDATA (APIREQ
, api_req
, 8) },
486 { ORDATA (APIACT
, api_act
, 8) },
487 { ORDATA (BR
, BR
, ADDRSIZE
) },
488 { FLDATA (USMD
, usmd
, 0) },
489 { FLDATA (USMDBUF
, usmd_buf
, 0) },
490 { FLDATA (USMDDEF
, usmd_defer
, 0) },
491 { FLDATA (NEXM
, nexm
, 0) },
492 { FLDATA (PRVN
, prvn
, 0) },
493 { FLDATA (TRAPP
, trap_pending
, 0) },
494 { FLDATA (EXTM
, memm
, 0) },
495 { FLDATA (EXTM_INIT
, memm_init
, 0) },
496 { FLDATA (EMIRP
, emir_pending
, 0) },
497 { FLDATA (RESTP
, rest_pending
, 0) },
498 { FLDATA (PWRFL
, int_hwre
[API_PWRFL
], INT_V_PWRFL
) },
501 { FLDATA (ION_INH
, ion_inh
, 0) },
502 { FLDATA (APIENB
, api_enb
, 0) },
503 { ORDATA (APIREQ
, api_req
, 8) },
504 { ORDATA (APIACT
, api_act
, 8) },
505 { ORDATA (XR
, XR
, 18) },
506 { ORDATA (LR
, LR
, 18) },
507 { ORDATA (BR
, BR
, 18) },
508 { ORDATA (RR
, RR
, 18) },
509 { ORDATA (MMR
, MMR
, 18) },
510 { FLDATA (USMD
, usmd
, 0) },
511 { FLDATA (USMDBUF
, usmd_buf
, 0) },
512 { FLDATA (USMDDEF
, usmd_defer
, 0) },
513 { FLDATA (NEXM
, nexm
, 0) },
514 { FLDATA (PRVN
, prvn
, 0) },
515 { FLDATA (TRAPP
, trap_pending
, 0) },
516 { FLDATA (BANKM
, memm
, 0) },
517 { FLDATA (BANKM_INIT
, memm_init
, 0) },
518 { FLDATA (RESTP
, rest_pending
, 0) },
519 { FLDATA (PWRFL
, int_hwre
[API_PWRFL
], INT_V_PWRFL
) },
521 { BRDATA (PCQ
, pcq
, 8, ADDRSIZE
, PCQ_SIZE
), REG_RO
+REG_CIRC
},
522 { ORDATA (PCQP
, pcq_p
, 6), REG_HRO
},
523 { FLDATA (STOP_INST
, stop_inst
, 0) },
524 { DRDATA (XCT_MAX
, xct_max
, 8), PV_LEFT
+ REG_NZ
},
525 { ORDATA (WRU
, sim_int_char
, 8) },
529 { UNIT_NOEAE
, UNIT_NOEAE
, "no EAE", "NOEAE", NULL
},
530 { UNIT_NOEAE
, 0, "EAE", "EAE", NULL
},
531 #if defined (PDP9) || defined (PDP15)
532 { UNIT_NOAPI
, UNIT_NOAPI
, "no API", "NOAPI", NULL
},
533 { UNIT_NOAPI
, 0, "API", "API", NULL
},
534 { UNIT_PROT
+UNIT_RELOC
+UNIT_XVM
, 0, "no memory protect",
536 { UNIT_PROT
+UNIT_RELOC
+UNIT_XVM
, UNIT_PROT
, "memory protect",
540 { UNIT_PROT
+UNIT_RELOC
+UNIT_XVM
, UNIT_PROT
+UNIT_RELOC
,
541 "memory relocation", "RELOCATION", NULL
},
542 { UNIT_PROT
+UNIT_RELOC
+UNIT_XVM
, UNIT_PROT
+UNIT_RELOC
+UNIT_XVM
,
543 "XVM", "XVM", NULL
},
545 { MTAB_XTD
|MTAB_VDV
, 0, "IDLE", "IDLE", &sim_set_idle
, &sim_show_idle
},
546 { MTAB_XTD
|MTAB_VDV
, 0, NULL
, "NOIDLE", &sim_clr_idle
, NULL
},
548 { UNIT_MSIZE
, 4096, NULL
, "4K", &cpu_set_size
},
550 { UNIT_MSIZE
, 8192, NULL
, "8K", &cpu_set_size
},
551 #if (MAXMEMSIZE > 8192)
552 { UNIT_MSIZE
, 12288, NULL
, "12K", &cpu_set_size
},
553 { UNIT_MSIZE
, 16384, NULL
, "16K", &cpu_set_size
},
554 { UNIT_MSIZE
, 20480, NULL
, "20K", &cpu_set_size
},
555 { UNIT_MSIZE
, 24576, NULL
, "24K", &cpu_set_size
},
556 { UNIT_MSIZE
, 28672, NULL
, "28K", &cpu_set_size
},
557 { UNIT_MSIZE
, 32768, NULL
, "32K", &cpu_set_size
},
559 #if (MAXMEMSIZE > 32768)
560 { UNIT_MSIZE
, 49152, NULL
, "48K", &cpu_set_size
},
561 { UNIT_MSIZE
, 65536, NULL
, "64K", &cpu_set_size
},
562 { UNIT_MSIZE
, 81920, NULL
, "80K", &cpu_set_size
},
563 { UNIT_MSIZE
, 98304, NULL
, "96K", &cpu_set_size
},
564 { UNIT_MSIZE
, 114688, NULL
, "112K", &cpu_set_size
},
565 { UNIT_MSIZE
, 131072, NULL
, "128K", &cpu_set_size
},
567 { MTAB_XTD
|MTAB_VDV
|MTAB_NMO
|MTAB_SHP
, 0, "HISTORY", "HISTORY",
568 &cpu_set_hist
, &cpu_show_hist
},
573 "CPU", &cpu_unit
, cpu_reg
, cpu_mod
,
574 1, 8, ADDRSIZE
, 1, 8, 18,
575 &cpu_ex
, &cpu_dep
, &cpu_reset
,
579 t_stat
sim_instr (void)
581 int32 api_int
, api_usmd
, skp
;
582 int32 iot_data
, device
, pulse
;
586 if (build_dev_tab ()) return SCPE_STOP
; /* build, chk tables */
587 PC
= PC
& AMASK
; /* clean variables */
592 if (cpu_unit
.flags
& UNIT_NOAPI
) /* no API? */
593 api_enb
= api_req
= api_act
= 0;
594 api_int
= api_eval (&int_pend
); /* eval API */
595 api_usmd
= 0; /* not API user cycle */
597 /* Main instruction fetch/decode loop */
599 while (reason
== 0) { /* loop until halted */
601 int32 IR
, MA
, MB
, esc
, t
, xct_count
;
602 int32 link_init
, fill
;
604 if (sim_interval
<= 0) { /* check clock queue */
605 if (reason
= sim_process_event ()) break;
606 api_int
= api_eval (&int_pend
); /* eval API */
609 /* PDP-4 and PDP-7 traps and interrupts
612 PDP-7 trap: extend mode forced on, M[0] = PC, PC = 2
613 PDP-4, PDP-7 programmable interrupts only */
615 #if defined (PDP4) || defined (PDP7)
618 if (trap_pending
) { /* trap pending? */
619 PCQ_ENTRY
; /* save old PC */
620 MB
= Jms_word (1); /* save state */
621 ion
= 0; /* interrupts off */
622 memm
= 1; /* extend on */
623 emir_pending
= trap_pending
= 0; /* emir, trap off */
624 usmd
= usmd_buf
= 0; /* user mode off */
625 Write (0, MB
, WR
); /* save in 0 */
626 PC
= 2; /* fetch next from 2 */
631 if (int_pend
&& ion
&& !ion_defer
) { /* interrupt? */
632 PCQ_ENTRY
; /* save old PC */
633 MB
= Jms_word (usmd
); /* save state */
634 ion
= 0; /* interrupts off */
635 memm
= 0; /* extend off */
636 emir_pending
= rest_pending
= 0; /* emir, restore off */
637 usmd
= usmd_buf
= 0; /* user mode off */
638 Write (0, MB
, WR
); /* physical write */
639 PC
= 1; /* fetch next from 1 */
642 if (sim_brk_summ
&& sim_brk_test (PC
, SWMASK ('E'))) { /* breakpoint? */
643 reason
= STOP_IBKPT
; /* stop simulation */
647 #endif /* end PDP-4/PDP-7 */
649 /* PDP-9 and PDP-15 traps and interrupts
651 PDP-9 trap: extend mode ???, M[0/20] = PC, PC = 0/21
652 PDP-15 trap: bank mode unchanged, M[0/20] = PC, PC = 0/21
653 PDP-9, PDP-15 API and program interrupts */
655 #if defined (PDP9) || defined (PDP15)
657 if (trap_pending
) { /* trap pending? */
658 PCQ_ENTRY
; /* save old PC */
659 MB
= Jms_word (1); /* save state */
660 if (ion
) { /* int on? */
661 ion
= 0; /* interrupts off */
662 MA
= 0; /* treat like PI */
664 ion_defer
= 2; /* free instruction */
665 if (!(cpu_unit
.flags
& UNIT_NOAPI
)) { /* API? */
666 api_act
= api_act
| API_ML3
; /* set lev 3 active */
667 api_int
= api_eval (&int_pend
); /* re-evaluate */
671 else MA
= 020; /* sortof like CAL */
672 emir_pending
= rest_pending
= trap_pending
= 0; /* emir,rest,trap off */
673 usmd
= usmd_buf
= 0; /* user mode off */
674 Write (MA
, MB
, WR
); /* physical write */
675 PC
= MA
+ 1; /* fetch next */
678 if (api_int
&& !ion_defer
) { /* API intr? */
679 int32 i
, lvl
= api_int
- 1; /* get req level */
680 if (hst_lnt
) cpu_intr_hist (HIST_API
, lvl
); /* record */
681 api_act
= api_act
| (API_ML0
>> lvl
); /* set level active */
682 if (lvl
>= API_HLVL
) { /* software req? */
683 MA
= ACH_SWRE
+ lvl
- API_HLVL
; /* vec = 40:43 */
684 api_req
= api_req
& ~(API_ML0
>> lvl
); /* remove request */
687 MA
= 0; /* assume fails */
688 for (i
= 0; i
< 32; i
++) { /* loop hi to lo */
689 if ((int_hwre
[lvl
] >> i
) & 1) { /* int req set? */
690 MA
= api_vec
[lvl
][i
]; /* get vector */
691 break; /* and stop */
695 if (MA
== 0) { /* bad channel? */
696 reason
= STOP_API
; /* API error */
699 api_int
= api_eval (&int_pend
); /* no API int */
700 api_usmd
= usmd
; /* API user mode cycle */
701 usmd
= usmd_buf
= 0; /* user mode off */
702 emir_pending
= rest_pending
= 0; /* emir, restore off */
704 Read (MA
, &IR
, FE
); /* fetch instruction */
708 if (int_pend
&& ion
&& !ion_defer
&& /* int pending, enabled? */
709 !(api_enb
&& (api_act
& API_MASKPI
))) { /* API off or not masking PI? */
710 PCQ_ENTRY
; /* save old PC */
711 if (hst_lnt
) cpu_intr_hist (HIST_PI
, 0); /* record */
712 MB
= Jms_word (usmd
); /* save state */
713 ion
= 0; /* interrupts off */
714 ion_defer
= 2; /* free instruction */
715 #if defined (PDP9) /* PDP-9, */
716 memm
= 0; /* extend off */
718 if (!(cpu_unit
.flags
& UNIT_NOAPI
)) { /* API? */
719 api_act
= api_act
| API_ML3
; /* set lev 3 active */
720 api_int
= api_eval (&int_pend
); /* re-evaluate */
723 emir_pending
= rest_pending
= 0; /* emir, restore off */
724 usmd
= usmd_buf
= 0; /* user mode off */
725 Write (0, MB
, WR
); /* physical write */
726 PC
= 1; /* fetch next from 1 */
729 if (sim_brk_summ
&& sim_brk_test (PC
, SWMASK ('E'))) { /* breakpoint? */
730 reason
= STOP_IBKPT
; /* stop simulation */
733 if (!usmd_defer
) usmd
= usmd_buf
; /* no IOT? load usmd */
734 else usmd_defer
= 0; /* cancel defer */
736 #endif /* PDP-9/PDP-15 */
738 /* Instruction fetch and address decode */
740 xct_count
= 0; /* track nested XCT's */
741 MA
= PC
; /* fetch at PC */
742 if (Read (MA
, &IR
, FE
)) continue; /* fetch instruction */
743 PC
= Incr_addr (PC
); /* increment PC */
745 xct_instr
: /* label for API, XCT */
746 if (hst_lnt
) cpu_inst_hist (MA
, IR
); /* history? */
747 if (ion_defer
) ion_defer
= ion_defer
- 1; /* count down defer */
748 if (sim_interval
) sim_interval
= sim_interval
- 1;
750 #if defined (PDP15) /* PDP15 */
752 if (memm
) MA
= (MA
& B_EPCMASK
) | (IR
& B_DAMASK
); /* bank mode dir addr */
753 else MA
= (MA
& P_EPCMASK
) | (IR
& P_DAMASK
); /* page mode dir addr */
757 MA
= (MA
& B_EPCMASK
) | (IR
& B_DAMASK
); /* bank mode only */
761 switch ((IR
>> 13) & 037) { /* decode IR<0:4> */
765 case 011: /* LAC, indir */
766 if (Ia (MA
, &MA
, 0)) break;
767 case 010: /* LAC, dir */
769 if (Read (MA
, &MB
, RD
)) break;
770 LAC
= (LAC
& LINK
) | MB
;
775 case 003: /* DAC, indir */
776 if (Ia (MA
, &MA
, 0)) break;
777 case 002: /* DAC, dir */
779 Write (MA
, LAC
& DMASK
, WR
);
784 case 007: /* DZM, indir */
785 if (Ia (MA
, &MA
, 0)) break;
786 case 006: /* DZM, direct */
793 case 025: /* AND, ind */
794 if (Ia (MA
, &MA
, 0)) break;
795 case 024: /* AND, dir */
797 if (Read (MA
, &MB
, RD
)) break;
798 LAC
= LAC
& (MB
| LINK
);
803 case 013: /* XOR, ind */
804 if (Ia (MA
, &MA
, 0)) break;
805 case 012: /* XOR, dir */
807 if (Read (MA
, &MB
, RD
)) break;
813 case 015: /* ADD, indir */
814 if (Ia (MA
, &MA
, 0)) break;
815 case 014: /* ADD, dir */
817 if (Read (MA
, &MB
, RD
)) break;
818 t
= (LAC
& DMASK
) + MB
;
819 if (t
> DMASK
) t
= (t
+ 1) & DMASK
; /* end around carry */
820 if (((~LAC
^ MB
) & (LAC
^ t
)) & SIGN
) /* overflow? */
821 LAC
= LINK
| t
; /* set link */
822 else LAC
= (LAC
& LINK
) | t
;
827 case 017: /* TAD, indir */
828 if (Ia (MA
, &MA
, 0)) break;
829 case 016: /* TAD, dir */
831 if (Read (MA
, &MB
, RD
)) break;
832 LAC
= (LAC
+ MB
) & LACMASK
;
837 case 023: /* ISZ, indir */
838 if (Ia (MA
, &MA
, 0)) break;
839 case 022: /* ISZ, dir */
841 if (Read (MA
, &MB
, RD
)) break;
842 MB
= (MB
+ 1) & DMASK
;
843 if (Write (MA
, MB
, WR
)) break;
844 if (MB
== 0) PC
= Incr_addr (PC
);
849 case 027: /* SAD, indir */
850 if (Ia (MA
, &MA
, 0)) break;
851 case 026: /* SAD, dir */
853 if (Read (MA
, &MB
, RD
)) break;
854 if ((LAC
& DMASK
) != MB
) PC
= Incr_addr (PC
);
859 case 021: /* XCT, indir */
860 if (Ia (MA
, &MA
, 0)) break;
861 case 020: /* XCT, dir */
863 if ((api_usmd
| usmd
) && (xct_count
!= 0)) { /* chained and usmd? */
864 if (usmd
) prvn
= trap_pending
= 1; /* trap if usmd */
865 break; /* nop if api_usmd */
867 if (xct_count
>= xct_max
) { /* too many XCT's? */
871 xct_count
= xct_count
+ 1; /* count XCT's */
873 ion_defer
= 1; /* defer intr */
875 if (Read (MA
, &IR
, FE
)) break; /* fetch inst, mm err? */
876 goto xct_instr
; /* go execute */
878 /* CAL: opcode 00 - api_usmd records whether usmd = 1 at start of API cycle
880 On the PDP-4 and PDP-7, CAL (I) is exactly the same as JMS (I) 20
881 On the PDP-9 and PDP-15, CAL clears user mode
882 On the PDP-9 and PDP-15 with API, CAL activates level 4
883 On the PDP-15, CAL goes to absolute 20, regardless of mode */
885 case 001: case 000: /* CAL */
886 t
= usmd
; /* save user mode */
887 #if defined (PDP15) /* PDP15 */
888 MA
= 020; /* MA = abs 20 */
889 ion_defer
= 1; /* "free instruction" */
891 if (memm
) MA
= 020; /* if ext, abs 20 */
892 else MA
= (PC
& B_EPCMASK
) | 020; /* else bank-rel 20 */
894 #if defined (PDP9) || defined (PDP15)
895 usmd
= usmd_buf
= 0; /* clear user mode */
896 if ((cpu_unit
.flags
& UNIT_NOAPI
) == 0) { /* if API, act lvl 4 */
897 #if defined (PDP15) /* PDP15: if 0-3 inactive */
898 if ((api_act
& (API_ML0
|API_ML1
|API_ML2
|API_ML3
)) == 0)
900 api_act
= api_act
| API_ML4
;
901 api_int
= api_eval (&int_pend
);
904 if (IR
& I_IND
) { /* indirect? */
905 if (Ia (MA
, &MA
, 0)) break;
908 MB
= Jms_word (api_usmd
| t
); /* save state */
913 /* JMS: opcode 010 - api_usmd records whether usmd = 1 at start of API cycle */
915 case 005: /* JMS, indir */
916 if (Ia (MA
, &MA
, 0)) break;
917 case 004: /* JMS, dir */
920 #if defined (PDP15) /* PDP15 */
921 if (!usmd
) ion_defer
= 1; /* "free instruction" */
923 MB
= Jms_word (api_usmd
| usmd
); /* save state */
924 if (Write (MA
, MB
, WR
)) break;
925 PC
= Incr_addr (MA
) & AMASK
;
930 case 031: /* JMP, indir */
931 if (Ia (MA
, &MA
, 1)) break;
933 PCQ_ENTRY
; /* save old PC */
937 /* JMP direct - check for idle */
939 case 030: /* JMP, dir */
941 PCQ_ENTRY
; /* save old PC */
942 if (sim_idle_enab
) { /* idling enabled? */
943 t_bool iof
= (ion_inh
!= 0) || /* IOF if inhibited */
944 ((ion
== 0) && (api_enb
== 0)); /* or PI and api off */
945 if (((MA
^ (PC
- 2)) & AMASK
) == 0) { /* 1) JMP *-1? */
946 if (iof
&& (last_IR
== OP_KSF
) && /* iof, prv KSF, */
947 !TST_INT (TTI
)) /* no TTI flag? */
948 sim_idle (0, FALSE
); /* we're idle */
950 else if (((MA
^ (PC
- 1)) & AMASK
) == 0) { /* 2) JMP *? */
951 if (iof
) reason
= STOP_LOOP
; /* iof? inf loop */
952 else sim_idle (0, FALSE
); /* ion? idle */
960 case 037: /* OPR, indir */
961 LAC
= (LAC
& LINK
) | IR
; /* LAW */
964 case 036: /* OPR, dir */
965 skp
= 0; /* assume no skip */
966 switch ((IR
>> 6) & 017) { /* decode IR<8:11> */
970 if ((LAC
& SIGN
) != 0) skp
= 1;
973 if ((LAC
& DMASK
) == 0) skp
= 1;
975 case 3: /* SZA | SMA */
976 if (((LAC
& DMASK
) == 0) || ((LAC
& SIGN
) != 0))
980 if (LAC
>= LINK
) skp
= 1;
982 case 5: /* SNL | SMA */
983 if (LAC
>= SIGN
) skp
= 1;
985 case 6: /* SNL | SZA */
986 if ((LAC
>= LINK
) || (LAC
== 0)) skp
= 1;
988 case 7: /* SNL | SZA | SMA */
989 if ((LAC
>= SIGN
) || (LAC
== 0)) skp
= 1;
995 if ((LAC
& SIGN
) == 0) skp
= 1;
998 if ((LAC
& DMASK
) != 0) skp
= 1;
1000 case 013: /* SNA & SPA */
1001 if (((LAC
& DMASK
) != 0) && ((LAC
& SIGN
) == 0))
1005 if (LAC
< LINK
) skp
= 1;
1007 case 015: /* SZL & SPA */
1008 if (LAC
< SIGN
) skp
= 1;
1010 case 016: /* SZL & SNA */
1011 if ((LAC
< LINK
) && (LAC
!= 0)) skp
= 1;
1013 case 017: /* SZL & SNA & SPA */
1014 if ((LAC
< SIGN
) && (LAC
!= 0)) skp
= 1;
1016 } /* end switch skips */
1018 switch (((IR
>> 9) & 014) | (IR
& 03)) { /* IR<5:6,16:17> */
1027 case 3: /* CML CMA */
1028 LAC
= LAC
^ LACMASK
;
1033 case 5: /* CLL CMA */
1034 LAC
= (LAC
& DMASK
) ^ DMASK
;
1036 case 6: /* CLL CML = STL */
1039 case 7: /* CLL CML CMA */
1040 LAC
= (LAC
| LINK
) ^ DMASK
;
1045 case 011: /* CLA CMA = STA */
1048 case 012: /* CLA CML */
1049 LAC
= (LAC
& LINK
) ^ LINK
;
1051 case 013: /* CLA CML CMA */
1052 LAC
= (LAC
| DMASK
) ^ LINK
;
1054 case 014: /* CLA CLL */
1057 case 015: /* CLA CLL CMA */
1060 case 016: /* CLA CLL CML */
1063 case 017: /* CLA CLL CML CMA */
1068 if (IR
& 0000004) { /* OAS */
1069 #if defined (PDP9) || defined (PDP15)
1070 if (usmd
) prvn
= trap_pending
= 1; /* trap if usmd */
1071 else if (!api_usmd
) /* nop if api_usmd */
1076 switch (((IR
>> 8) & 04) | ((IR
>> 3) & 03)) { /* decode IR<7,13:14> */
1078 LAC
= ((LAC
<< 1) | (LAC
>> 18)) & LACMASK
;
1081 LAC
= ((LAC
>> 1) | (LAC
<< 18)) & LACMASK
;
1083 case 3: /* RAL RAR */
1084 #if defined (PDP15) /* PDP-15 */
1085 LAC
= (LAC
+ 1) & LACMASK
; /* IAC */
1086 #else /* PDP-4,-7,-9 */
1087 reason
= stop_inst
; /* undefined */
1091 LAC
= ((LAC
<< 2) | (LAC
>> 17)) & LACMASK
;
1094 LAC
= ((LAC
>> 2) | (LAC
<< 17)) & LACMASK
;
1096 case 7: /* RTL RTR */
1097 #if defined (PDP15) /* PDP-15 */
1098 LAC
= ((LAC
>> 9) & 0777) | ((LAC
& 0777) << 9) |
1099 (LAC
& LINK
); /* BSW */
1100 #else /* PDP-4,-7,-9 */
1101 reason
= stop_inst
; /* undefined */
1104 } /* end switch rotate */
1106 if (IR
& 0000040) { /* HLT */
1107 if (usmd
) prvn
= trap_pending
= 1; /* trap if usmd */
1108 else if (!api_usmd
) reason
= STOP_HALT
; /* nop if api_usmd */
1110 if (skp
) PC
= Incr_addr (PC
); /* if skip, inc PC */
1111 break; /* end OPR */
1115 The EAE is microprogrammed to execute variable length signed and
1116 unsigned shift, multiply, divide, and normalize. Most commands are
1117 controlled by a six bit step counter (SC). In the hardware, the step
1118 counter is complemented on load and then counted up to zero; timing
1119 guarantees an initial increment, which completes the two's complement
1120 load. In the simulator, the SC is loaded normally and then counted
1121 down to zero; the read SC command compensates. */
1123 case 033: case 032: /* EAE */
1124 if (cpu_unit
.flags
& UNIT_NOEAE
) break; /* disabled? */
1125 if (IR
& 0020000) /* IR<4>? AC0 to L */
1126 LAC
= ((LAC
<< 1) & LINK
) | (LAC
& DMASK
);
1127 if (IR
& 0010000) MQ
= 0; /* IR<5>? clear MQ */
1128 if ((IR
& 0004000) && (LAC
& SIGN
)) /* IR<6> and minus? */
1129 eae_ac_sign
= LINK
; /* set eae_ac_sign */
1130 else eae_ac_sign
= 0; /* if not, unsigned */
1131 if (IR
& 0002000) MQ
= (MQ
| LAC
) & DMASK
; /* IR<7>? or AC */
1132 else if (eae_ac_sign
) LAC
= LAC
^ DMASK
; /* if not, |AC| */
1133 if (IR
& 0001000) LAC
= LAC
& LINK
; /* IR<8>? clear AC */
1134 link_init
= LAC
& LINK
; /* link temporary */
1135 fill
= link_init
? DMASK
: 0; /* fill = link */
1136 esc
= IR
& 077; /* get eff SC */
1137 switch ((IR
>> 6) & 07) { /* case on IR<9:11> */
1140 if (IR
& 04) MQ
= MQ
^ DMASK
; /* IR<15>? ~MQ */
1141 if (IR
& 02) LAC
= LAC
| MQ
; /* IR<16>? or MQ */
1142 if (IR
& 01) LAC
= LAC
| ((-SC
) & 077); /* IR<17>? or SC */
1145 /* Multiply uses a shift and add algorithm. The PDP-15, unlike prior
1146 implementations, factors IR<6> (signed multiply) into the calculation
1147 of the result sign. */
1149 case 1: /* multiply */
1150 if (Read (PC
, &MB
, FE
)) break; /* get next word */
1151 PC
= Incr_addr (PC
); /* increment PC */
1152 if (eae_ac_sign
) MQ
= MQ
^ DMASK
; /* EAE AC sign? ~MQ */
1153 LAC
= LAC
& DMASK
; /* clear link */
1154 SC
= esc
; /* init SC */
1156 if (MQ
& 1) LAC
= LAC
+ MB
; /* MQ<17>? add */
1157 MQ
= (MQ
>> 1) | ((LAC
& 1) << 17);
1158 LAC
= LAC
>> 1; /* shift AC'MQ right */
1159 SC
= (SC
- 1) & 077; /* decrement SC */
1160 } while (SC
!= 0); /* until SC = 0 */
1162 if ((IR
& 0004000) && (eae_ac_sign
^ link_init
)) {
1164 if (eae_ac_sign
^ link_init
) { /* result negative? */
1171 /* Divide uses a non-restoring divide. Divide uses a subtract and shift
1172 algorithm. The quotient is generated in true form. The PDP-15, unlike
1173 prior implementations, factors IR<6> (signed multiply) into the calculation
1174 of the result sign. */
1176 case 3: /* divide */
1177 if (Read (PC
, &MB
, FE
)) break; /* get next word */
1178 PC
= Incr_addr (PC
); /* increment PC */
1179 if (eae_ac_sign
) MQ
= MQ
^ DMASK
; /* EAE AC sign? ~MQ */
1180 if ((LAC
& DMASK
) >= MB
) { /* overflow? */
1181 LAC
= (LAC
- MB
) | LINK
; /* set link */
1184 LAC
= LAC
& DMASK
; /* clear link */
1185 t
= 0; /* init loop */
1186 SC
= esc
; /* init SC */
1188 if (t
) LAC
= (LAC
+ MB
) & LACMASK
;
1189 else LAC
= (LAC
- MB
) & LACMASK
;
1190 t
= (LAC
>> 18) & 1; /* quotient bit */
1191 if (SC
> 1) LAC
= /* skip if last */
1192 ((LAC
<< 1) | (MQ
>> 17)) & LACMASK
;
1193 MQ
= ((MQ
<< 1) | (t
^ 1)) & DMASK
; /* shift in quo bit */
1194 SC
= (SC
- 1) & 077; /* decrement SC */
1195 } while (SC
!= 0); /* until SC = 0 */
1196 if (t
) LAC
= (LAC
+ MB
) & LACMASK
;
1197 if (eae_ac_sign
) LAC
= LAC
^ DMASK
; /* sgn rem = sgn divd */
1199 if ((IR
& 0004000) && (eae_ac_sign
^ link_init
))
1201 if (eae_ac_sign
^ link_init
) /* result negative? */
1206 /* EAE shifts, whether left or right, fill from the link. If the
1207 operand sign has been copied to the link, this provides correct
1208 sign extension for one's complement numbers. */
1210 case 4: /* normalize */
1212 if (!usmd
) ion_defer
= 2; /* free instructions */
1214 for (SC
= esc
; ((LAC
& SIGN
) == ((LAC
<< 1) & SIGN
)); ) {
1215 LAC
= (LAC
<< 1) | ((MQ
>> 17) & 1);
1216 MQ
= (MQ
<< 1) | (link_init
>> 18);
1217 SC
= (SC
- 1) & 077;
1220 LAC
= link_init
| (LAC
& DMASK
); /* trim AC, restore L */
1221 MQ
= MQ
& DMASK
; /* trim MQ */
1222 SC
= SC
& 077; /* trim SC */
1225 case 5: /* long right shift */
1227 MQ
= ((LAC
<< (18 - esc
)) | (MQ
>> esc
)) & DMASK
;
1228 LAC
= ((fill
<< (18 - esc
)) | (LAC
>> esc
)) & LACMASK
;
1232 ((fill
<< (36 - esc
)) | (LAC
>> (esc
- 18))) & DMASK
;
1234 LAC
= link_init
| fill
;
1236 SC
= 0; /* clear step count */
1239 case 6: /* long left shift */
1242 (((LAC
<< esc
) | (MQ
>> (18 - esc
))) & DMASK
);
1243 MQ
= ((MQ
<< esc
) | (fill
>> (18 - esc
))) & DMASK
;
1246 if (esc
< 36) LAC
= link_init
|
1247 (((MQ
<< (esc
- 18)) | (fill
>> (36 - esc
))) & DMASK
);
1248 else LAC
= link_init
| fill
;
1251 SC
= 0; /* clear step count */
1254 case 7: /* AC left shift */
1255 if (esc
< 18) LAC
= link_init
|
1256 (((LAC
<< esc
) | (fill
>> (18 - esc
))) & DMASK
);
1257 else LAC
= link_init
| fill
;
1258 SC
= 0; /* clear step count */
1260 } /* end switch IR */
1261 break; /* end case EAE */
1263 /* PDP-15 index operates: opcode 72 */
1265 case 035: /* index operates */
1268 t
= (IR
& 0400)? (IR
| 0777000): (IR
& 0377); /* sext immediate */
1269 switch ((IR
>> 9) & 017) { /* case on IR<5:8> */
1277 LAC
= (LAC
& LINK
) | ((LAC
+ t
) & DMASK
);
1280 LAC
= (LAC
& LINK
) | XR
;
1283 XR
= (XR
+ t
) & DMASK
;
1284 if (SEXT (XR
) >= SEXT (LR
)) PC
= Incr_addr (PC
);
1290 LAC
= (LAC
& LINK
) | LR
;
1295 case 014: /* CLAC */
1301 case 016: /* CLLR */
1305 XR
= (XR
+ t
) & DMASK
;
1307 } /* end switch IR */
1308 break; /* end case */
1313 The 18b PDP's have different definitions of various control IOT's.
1315 IOT PDP-4 PDP-7 PDP-9 PDP-15
1317 700002 IOF IOF IOF IOF
1318 700022 undefined undefined undefined ORMM (XVM)
1319 700042 ION ION ION ION
1320 700024 undefined undefined undefined LDMM (XVM)
1321 700062 undefined ITON undefined undefined
1322 701701 undefined undefined MPSK MPSK
1323 701741 undefined undefined MPSNE MPSNE
1324 701702 undefined undefined MPCV MPCV
1325 701722 undefined undefined undefined MPRC (XVM)
1326 701742 undefined undefined MPEU MPEU
1327 701704 undefined undefined MPLD MPLD
1328 701724 undefined undefined undefined MPLR (KT15, XVM)
1329 701744 undefined undefined MPCNE MPCNE
1330 701764 undefined undefined undefined IPFH (XVM)
1331 703201 undefined undefined PFSF PFSF
1332 703301 undefined TTS TTS TTS
1333 703341 undefined SKP7 SKP7 SPCO
1334 703302 undefined CAF CAF CAF
1335 703304 undefined undefined DBK DBK
1336 703344 undefined undefined DBR DBR
1337 705501 undefined undefined SPI SPI
1338 705521 undefined undefined undefined ENB
1339 705502 undefined undefined RPL RPL
1340 705522 undefined undefined undefined INH
1341 705504 undefined undefined ISA ISA
1342 707701 undefined SEM SEM undefined
1343 707741 undefined undefined undefined SKP15
1344 707761 undefined undefined undefined SBA
1345 707702 undefined EEM EEM undefined
1346 707742 undefined EMIR EMIR RES
1347 707762 undefined undefined undefined DBA
1348 707704 undefined LEM LEM undefined
1349 707764 undefined undefined undefined EBA */
1353 if (IR
& 0010000) { /* floating point? */
1354 reason
= fp15 (IR
); /* process */
1358 if ((api_usmd
| usmd
) && /* user, not XVM UIOT? */
1359 (!XVM
|| !(MMR
& MM_UIOT
))) {
1360 if (usmd
) prvn
= trap_pending
= 1; /* trap if user */
1361 break; /* nop if api_usmd */
1363 device
= (IR
>> 6) & 077; /* device = IR<6:11> */
1364 pulse
= IR
& 067; /* pulse = IR<12:17> */
1365 if (IR
& 0000010) LAC
= LAC
& LINK
; /* clear AC? */
1366 iot_data
= LAC
& DMASK
; /* AC unchanged */
1368 /* PDP-4 system IOT's */
1371 switch (device
) { /* decode IR<6:11> */
1373 case 0: /* CPU and clock */
1374 if (pulse
== 002) ion
= 0; /* IOF */
1375 else if (pulse
== 042) ion
= ion_defer
= 1; /* ION */
1376 else iot_data
= clk (device
, pulse
, iot_data
);
1380 /* PDP-7 system IOT's */
1383 switch (device
) { /* decode IR<6:11> */
1385 case 0: /* CPU and clock */
1386 if (pulse
== 002) ion
= 0; /* IOF */
1387 else if (pulse
== 042) ion
= ion_defer
= 1; /* ION */
1388 else if (pulse
== 062) /* ITON */
1389 usmd
= usmd_buf
= ion
= ion_defer
= 1;
1390 else iot_data
= clk (device
, pulse
, iot_data
);
1393 case 033: /* CPU control */
1394 if ((pulse
== 001) || (pulse
== 041)) PC
= Incr_addr (PC
);
1395 else if (pulse
== 002) reset_all (1); /* CAF - skip CPU */
1398 case 077: /* extended memory */
1399 if ((pulse
== 001) && memm
) PC
= Incr_addr (PC
);
1400 else if (pulse
== 002) memm
= 1; /* EEM */
1401 else if (pulse
== 042) /* EMIR */
1402 memm
= emir_pending
= 1; /* ext on, restore */
1403 else if (pulse
== 004) memm
= 0; /* LEM */
1407 /* PDP-9 system IOT's */
1410 ion_defer
= 1; /* delay interrupts */
1411 usmd_defer
= 1; /* defer load user */
1412 switch (device
) { /* decode IR<6:11> */
1414 case 000: /* CPU and clock */
1415 if (pulse
== 002) ion
= 0; /* IOF */
1416 else if (pulse
== 042) ion
= 1; /* ION */
1417 else iot_data
= clk (device
, pulse
, iot_data
);
1420 case 017: /* mem protection */
1421 if (PROT
) { /* enabled? */
1422 if ((pulse
== 001) && prvn
) /* MPSK */
1423 PC
= Incr_addr (PC
);
1424 else if ((pulse
== 041) && nexm
) /* MPSNE */
1425 PC
= Incr_addr (PC
);
1426 else if (pulse
== 002) prvn
= 0; /* MPCV */
1427 else if (pulse
== 042) usmd_buf
= 1; /* MPEU */
1428 else if (pulse
== 004) /* MPLD */
1430 else if (pulse
== 044) nexm
= 0; /* MPCNE */
1432 else reason
= stop_inst
;
1435 case 032: /* power fail */
1436 if ((pulse
== 001) && (TST_INT (PWRFL
)))
1437 PC
= Incr_addr (PC
);
1440 case 033: /* CPU control */
1441 if ((pulse
== 001) || (pulse
== 041)) PC
= Incr_addr (PC
);
1442 else if (pulse
== 002) { /* CAF */
1443 reset_all (1); /* reset all exc CPU */
1444 cpu_caf (); /* CAF to CPU */
1446 else if (pulse
== 044) rest_pending
= 1; /* DBR */
1447 if (((cpu_unit
.flags
& UNIT_NOAPI
) == 0) && (pulse
& 004)) {
1448 int32 t
= api_ffo
[api_act
& 0377];
1449 api_act
= api_act
& ~(API_ML0
>> t
);
1453 case 055: /* API control */
1454 if (cpu_unit
.flags
& UNIT_NOAPI
) reason
= stop_inst
;
1455 else if (pulse
== 001) { /* SPI */
1456 if (((LAC
& SIGN
) && api_enb
) ||
1457 ((LAC
& 0377) > api_act
))
1458 iot_data
= iot_data
| IOT_SKP
;
1460 else if (pulse
== 002) { /* RPL */
1461 iot_data
= iot_data
| (api_enb
<< 17) |
1462 (api_req
<< 8) | api_act
;
1464 else if (pulse
== 004) { /* ISA */
1465 api_enb
= (iot_data
& SIGN
)? 1: 0;
1466 api_req
= api_req
| ((LAC
>> 8) & 017);
1467 api_act
= api_act
| (LAC
& 0377);
1471 case 077: /* extended memory */
1472 if ((pulse
== 001) && memm
) PC
= Incr_addr (PC
);
1473 else if (pulse
== 002) memm
= 1; /* EEM */
1474 else if (pulse
== 042) /* EMIR */
1475 memm
= emir_pending
= 1; /* ext on, restore */
1476 else if (pulse
== 004) memm
= 0; /* LEM */
1480 /* PDP-15 system IOT's - includes "re-entrancy ECO" ENB/INH as standard */
1483 ion_defer
= 1; /* delay interrupts */
1484 usmd_defer
= 1; /* defer load user */
1485 switch (device
) { /* decode IR<6:11> */
1487 case 000: /* CPU and clock */
1488 if (pulse
== 002) ion
= 0; /* IOF */
1489 else if (pulse
== 042) ion
= 1; /* ION */
1490 else if (XVM
&& (pulse
== 022)) /* ORMM/RDMM */
1492 else if (XVM
&& (pulse
== 024)) /* LDMM */
1494 else iot_data
= clk (device
, pulse
, iot_data
);
1497 case 017: /* mem protection */
1498 if (PROT
) { /* enabled? */
1499 t
= XVM
? BRMASK_XVM
: BRMASK
;
1500 if ((pulse
== 001) && prvn
) /* MPSK */
1501 PC
= Incr_addr (PC
);
1502 else if ((pulse
== 041) && nexm
) /* MPSNE */
1503 PC
= Incr_addr (PC
);
1504 else if (pulse
== 002) prvn
= 0; /* MPCV */
1505 else if (pulse
== 042) /* MPEU */
1507 else if (XVM
&& (pulse
== 062)) /* RDCLK */
1508 iot_data
= clk_task_upd (TRUE
);
1509 else if (pulse
== 004) BR
= LAC
& t
; /* MPLD */
1510 else if (RELOC
&& (pulse
== 024)) /* MPLR */
1512 else if (pulse
== 044) nexm
= 0; /* MPCNE */
1514 else reason
= stop_inst
;
1517 case 032: /* power fail */
1518 if ((pulse
== 001) && (TST_INT (PWRFL
)))
1519 PC
= Incr_addr (PC
);
1522 case 033: /* CPU control */
1523 if ((pulse
== 001) || (pulse
== 041)) PC
= Incr_addr (PC
);
1524 else if (pulse
== 002) { /* CAF */
1525 reset_all (2); /* reset all exc CPU, FP15 */
1526 cpu_caf (); /* CAF to CPU */
1528 else if (pulse
== 044) rest_pending
= 1; /* DBR */
1529 if (((cpu_unit
.flags
& UNIT_NOAPI
) == 0) && (pulse
& 004)) {
1530 int32 t
= api_ffo
[api_act
& 0377];
1531 api_act
= api_act
& ~(API_ML0
>> t
);
1535 case 055: /* API control */
1536 if (cpu_unit
.flags
& UNIT_NOAPI
) reason
= stop_inst
;
1537 else if (pulse
== 001) { /* SPI */
1538 if (((LAC
& SIGN
) && api_enb
) ||
1539 ((LAC
& 0377) > api_act
))
1540 iot_data
= iot_data
| IOT_SKP
;
1542 else if (pulse
== 002) { /* RPL */
1543 iot_data
= iot_data
| (api_enb
<< 17) |
1544 (api_req
<< 8) | api_act
;
1546 else if (pulse
== 004) { /* ISA */
1547 api_enb
= (iot_data
& SIGN
)? 1: 0;
1548 api_req
= api_req
| ((LAC
>> 8) & 017);
1549 api_act
= api_act
| (LAC
& 0377);
1551 else if (pulse
== 021) ion_inh
= 0; /* ENB */
1552 else if (pulse
== 022) ion_inh
= 1; /* INH */
1555 case 077: /* bank addressing */
1556 if ((pulse
== 041) || ((pulse
== 061) && memm
))
1557 PC
= Incr_addr (PC
); /* SKP15, SBA */
1558 else if (pulse
== 042) rest_pending
= 1; /* RES */
1559 else if (pulse
== 062) memm
= 0; /* DBA */
1560 else if (pulse
== 064) memm
= 1; /* EBA */
1564 /* IOT, continued */
1566 default: /* devices */
1567 if (dev_tab
[device
]) /* defined? */
1568 iot_data
= dev_tab
[device
] (device
, pulse
, iot_data
);
1569 else reason
= stop_inst
; /* stop on flag */
1571 } /* end switch device */
1573 LAC
= LAC
| (iot_data
& DMASK
);
1574 if (iot_data
& IOT_SKP
) PC
= Incr_addr (PC
);
1575 if (iot_data
>= IOT_REASON
) reason
= iot_data
>> IOT_V_REASON
;
1576 api_int
= api_eval (&int_pend
); /* eval API */
1577 break; /* end case IOT */
1578 } /* end switch opcode */
1580 api_usmd
= 0; /* API cycle over */
1581 last_IR
= IR
; /* save IR for next */
1584 /* Simulation halted */
1586 iors
= upd_iors (); /* get IORS */
1587 pcq_r
->qptr
= pcq_p
; /* update pc q ptr */
1593 int32
api_eval (int32
*pend
)
1597 *pend
= 0; /* assume no intr */
1598 #if defined (PDP15) /* PDP15 only */
1599 if (ion_inh
) return 0; /* inhibited? */
1601 for (i
= 0; i
< API_HLVL
+1; i
++) { /* any intr? */
1602 if (int_hwre
[i
]) *pend
= 1;
1604 if (api_enb
== 0) return 0; /* off? no req */
1605 api_req
= api_req
& ~(API_ML0
|API_ML1
|API_ML2
|API_ML3
); /* clr req<0:3> */
1606 for (i
= 0; i
< API_HLVL
; i
++) { /* loop thru levels */
1607 if (int_hwre
[i
]) /* req on level? */
1608 api_req
= api_req
| (API_ML0
>> i
); /* set api req */
1610 hi
= api_ffo
[api_req
& 0377]; /* find hi req */
1611 if (hi
< api_ffo
[api_act
& 0377]) return (hi
+ 1);
1615 /* Process IORS instruction */
1617 int32
upd_iors (void)
1621 d
= (ion
? IOS_ION
: 0); /* ION */
1622 for (p
= 0; dev_iors
[p
] != NULL
; p
++) /* loop thru table */
1623 d
= d
| dev_iors
[p
](); /* OR in results */
1627 #if defined (PDP4) || defined (PDP7)
1629 /* Read, write, indirect, increment routines
1630 On the PDP-4 and PDP-7,
1631 There are autoincrement locations in every field. If a field
1632 does not exist, it is impossible to generate an
1633 autoincrement reference (all instructions are CAL).
1634 Indirect addressing range is determined by extend mode.
1635 JMP I with EMIR pending can only clear extend
1636 There is no memory protection, nxm reads zero and ignores writes. */
1638 t_stat
Read (int32 ma
, int32
*dat
, int32 cyc
)
1641 if (MEM_ADDR_OK (ma
)) *dat
= M
[ma
] & DMASK
;
1646 t_stat
Write (int32 ma
, int32 dat
, int32 cyc
)
1649 if (MEM_ADDR_OK (ma
)) M
[ma
] = dat
& DMASK
;
1653 t_stat
Ia (int32 ma
, int32
*ea
, t_bool jmp
)
1658 if ((ma
& B_DAMASK
& ~07) == 010) { /* autoindex? */
1659 Read (ma
, &t
, DF
); /* add 1 before use */
1660 t
= (t
+ 1) & DMASK
;
1661 sta
= Write (ma
, t
, DF
);
1663 else sta
= Read (ma
, &t
, DF
); /* fetch indirect */
1664 if (jmp
) { /* jmp i? */
1665 if (emir_pending
&& (((t
>> 16) & 1) == 0)) memm
= 0;
1666 emir_pending
= rest_pending
= 0;
1668 if (memm
) *ea
= t
& IAMASK
; /* extend? 15b ia */
1669 else *ea
= (ma
& B_EPCMASK
) | (t
& B_DAMASK
); /* bank-rel ia */
1673 int32
Incr_addr (int32 ma
)
1675 return ((ma
& B_EPCMASK
) | ((ma
+ 1) & B_DAMASK
));
1678 int32
Jms_word (int32 t
)
1680 return (((LAC
& LINK
) >> 1) | ((memm
& 1) << 16) |
1681 ((t
& 1) << 15) | (PC
& IAMASK
));
1688 /* Read, write, indirect, increment routines
1690 The autoincrement registers are in field zero only. Regardless
1691 of extend mode, indirect addressing through 00010-00017
1692 will access absolute locations 00010-00017.
1693 Indirect addressing range is determined by extend mode. If
1694 extend mode is off, and autoincrementing is used, the
1695 resolved address is in bank 0 (KG09B maintenance manual).
1696 JMP I with EMIR pending can only clear extend
1697 JMP I with DBK pending restores L, user mode, extend mode
1698 Memory protection is implemented for foreground/background operation. */
1700 t_stat
Read (int32 ma
, int32
*dat
, int32 cyc
)
1703 if (usmd
) { /* user mode? */
1704 if (!MEM_ADDR_OK (ma
)) { /* nxm? */
1705 nexm
= prvn
= trap_pending
= 1; /* set flags, trap */
1709 if ((cyc
!= DF
) && (ma
< BR
)) { /* boundary viol? */
1710 prvn
= trap_pending
= 1; /* set flag, trap */
1715 if (MEM_ADDR_OK (ma
)) *dat
= M
[ma
] & DMASK
; /* valid mem? ok */
1717 *dat
= 0; /* set flag, no trap */
1723 t_stat
Write (int32 ma
, int32 dat
, int32 cyc
)
1727 if (!MEM_ADDR_OK (ma
)) { /* nxm? */
1728 nexm
= prvn
= trap_pending
= 1; /* set flags, trap */
1731 if ((cyc
!= DF
) && (ma
< BR
)) { /* boundary viol? */
1732 prvn
= trap_pending
= 1; /* set flag, trap */
1736 if (MEM_ADDR_OK (ma
)) M
[ma
] = dat
& DMASK
; /* valid mem? ok */
1737 else nexm
= 1; /* set flag, no trap */
1741 t_stat
Ia (int32 ma
, int32
*ea
, t_bool jmp
)
1746 if ((ma
& B_DAMASK
& ~07) == 010) { /* autoindex? */
1747 ma
= ma
& 017; /* always in bank 0 */
1748 Read (ma
, &t
, DF
); /* +1 before use */
1749 t
= (t
+ 1) & DMASK
;
1750 sta
= Write (ma
, t
, DF
);
1752 else sta
= Read (ma
, &t
, DF
);
1753 if (jmp
) { /* jmp i? */
1754 if (emir_pending
&& (((t
>> 16) & 1) == 0)) memm
= 0;
1755 if (rest_pending
) { /* restore pending? */
1756 LAC
= ((t
<< 1) & LINK
) | (LAC
& DMASK
); /* restore L */
1757 memm
= (t
>> 16) & 1; /* restore extend */
1758 usmd
= usmd_buf
= (t
>> 15) & 1; /* restore user */
1760 emir_pending
= rest_pending
= 0;
1762 if (memm
) *ea
= t
& IAMASK
; /* extend? 15b ia */
1763 else *ea
= (ma
& B_EPCMASK
) | (t
& B_DAMASK
); /* bank-rel ia */
1767 int32
Incr_addr (int32 ma
)
1769 return ((ma
& B_EPCMASK
) | ((ma
+ 1) & B_DAMASK
));
1772 int32
Jms_word (int32 t
)
1774 return (((LAC
& LINK
) >> 1) | ((memm
& 1) << 16) |
1775 ((t
& 1) << 15) | (PC
& IAMASK
));
1782 /* Read, write, indirect, increment routines
1784 The autoincrement registers are in page zero only. Regardless
1785 of bank mode, indirect addressing through 00010-00017
1786 will access absolute locations 00010-00017.
1787 Indirect addressing range is determined by autoincrementing.
1788 Any indirect can trigger a restore.
1789 Memory protection is implemented for foreground/background operation.
1790 Read and write mask addresses to 17b except for XVM systems */
1792 t_stat
Read (int32 ma
, int32
*dat
, int32 cyc
)
1796 if (usmd
) { /* user mode? */
1797 if (XVM
) pa
= RelocXVM (ma
, REL_R
); /* XVM relocation? */
1798 else if (RELOC
) pa
= Reloc15 (ma
, REL_R
); /* PDP-15 relocation? */
1799 else pa
= Prot15 (ma
, cyc
== FE
); /* PDP-15 prot, fetch only */
1800 if (pa
< 0) { /* error? */
1805 else pa
= ma
& AMASK
; /* no prot or reloc */
1806 if (MEM_ADDR_OK (pa
)) *dat
= M
[pa
] & DMASK
; /* valid mem? ok */
1808 nexm
= 1; /* set flag, no trap */
1814 t_stat
Write (int32 ma
, int32 dat
, int32 cyc
)
1818 if (usmd
) { /* user mode? */
1819 if (XVM
) pa
= RelocXVM (ma
, REL_W
); /* XVM relocation? */
1820 else if (RELOC
) pa
= Reloc15 (ma
, REL_W
); /* PDP-15 relocation? */
1821 else pa
= Prot15 (ma
, cyc
!= DF
); /* PDP-15 prot, !defer */
1822 if (pa
< 0) return MM_ERR
; /* error? */
1824 else pa
= ma
& AMASK
; /* no prot or reloc */
1825 if (MEM_ADDR_OK (pa
)) M
[pa
] = dat
& DMASK
; /* valid mem? ok */
1826 else nexm
= 1; /* set flag, no trap */
1830 /* XVM will do 18b defers if user_mode and G_Mode != 0 */
1832 t_stat
Ia (int32 ma
, int32
*ea
, t_bool jmp
)
1835 int32 damask
= memm
? B_DAMASK
: P_DAMASK
;
1836 static const int32 g_mask
[4] = { MM_G_W0
, MM_G_W1
, MM_G_W2
, MM_G_W3
};
1839 if ((ma
& damask
& ~07) == 010) { /* autoincrement? */
1840 ma
= ma
& 017; /* always in bank 0 */
1841 Read (ma
, &t
, DF
); /* +1 before use */
1842 t
= (t
+ 1) & DMASK
;
1843 sta
= Write (ma
, t
, DF
);
1845 else sta
= Read (ma
, &t
, DF
);
1846 if (rest_pending
) { /* restore pending? */
1847 LAC
= ((t
<< 1) & LINK
) | (LAC
& DMASK
); /* restore L */
1848 memm
= (t
>> 16) & 1; /* restore bank */
1849 usmd
= usmd_buf
= (t
>> 15) & 1; /* restore user */
1850 emir_pending
= rest_pending
= 0;
1852 gmode
= MM_GETGM (MMR
); /* get G_mode */
1853 if (usmd
&& XVM
&& gmode
) /* XVM user mode? */
1854 *ea
= t
& g_mask
[gmode
]; /* mask ia to size */
1855 else if ((ma
& damask
& ~07) == 010) *ea
= t
& DMASK
; /* autoindex? */
1856 else *ea
= (PC
& BLKMASK
) | (t
& IAMASK
); /* within 32K */
1860 t_stat
Incr_addr (int32 ma
)
1862 if (memm
) return ((ma
& B_EPCMASK
) | ((ma
+ 1) & B_DAMASK
));
1863 return ((ma
& P_EPCMASK
) | ((ma
+ 1) & P_DAMASK
));
1866 /* XVM will store all 18b of PC if user mode and G_mode != 0 */
1868 int32
Jms_word (int32 t
)
1870 if (usmd
&& XVM
&& (MMR
& MM_GM
)) return PC
;
1871 return (((LAC
& LINK
) >> 1) | ((memm
& 1) << 16) |
1872 ((t
& 1) << 15) | (PC
& IAMASK
));
1875 /* PDP-15 protection (KM15 option) */
1877 int32
Prot15 (int32 ma
, t_bool bndchk
)
1879 ma
= ma
& AMASK
; /* 17b addressing */
1880 if (!MEM_ADDR_OK (ma
)) { /* nxm? */
1881 nexm
= prvn
= trap_pending
= 1; /* set flags, trap */
1884 if (bndchk
&& (ma
< BR
)) { /* boundary viol? */
1885 prvn
= trap_pending
= 1; /* set flag, trap */
1888 return ma
; /* no relocation */
1891 /* PDP-15 relocation and protection (KT15 option) */
1893 int32
Reloc15 (int32 ma
, int32 rc
)
1897 ma
= ma
& AMASK
; /* 17b addressing */
1898 if (ma
> (BR
| 0377)) { /* boundary viol? */
1899 if (rc
!= REL_C
) prvn
= trap_pending
= 1; /* set flag, trap */
1902 pa
= (ma
+ RR
) & AMASK
; /* relocate address */
1903 if (!MEM_ADDR_OK (pa
)) { /* nxm? */
1904 if (rc
!= REL_C
) nexm
= prvn
= trap_pending
= 1; /* set flags, trap */
1910 /* XVM relocation and protection option */
1912 int32
RelocXVM (int32 ma
, int32 rc
)
1914 int32 pa
, gmode
, slr
;
1915 static const int32 g_base
[4] = { MM_G_B0
, MM_G_B1
, MM_G_B2
, MM_G_B3
};
1916 static const int32 slr_lnt
[4] = { MM_SLR_L0
, MM_SLR_L1
, MM_SLR_L2
, MM_SLR_L3
};
1918 gmode
= MM_GETGM (MMR
); /* get G_mode */
1919 slr
= MM_GETSLR (MMR
); /* get segment length */
1920 if (MMR
& MM_RDIS
) pa
= ma
; /* reloc disabled? */
1921 else if ((MMR
& MM_SH
) && /* shared enabled and */
1922 (ma
>= g_base
[gmode
]) && /* >= shared base and */
1923 (ma
< (g_base
[gmode
] + slr_lnt
[slr
]))) { /* < shared end? */
1924 if (ma
& 017400) { /* ESAS? */
1925 if ((rc
== REL_W
) && (MMR
& MM_WP
)) { /* write and protected? */
1926 prvn
= trap_pending
= 1; /* set flag, trap */
1929 pa
= (((MMR
& MM_SBR_MASK
) << 8) + ma
) & DMASK
; /* ESAS reloc */
1931 else pa
= RR
+ (ma
& 0377); /* no, ISAS reloc */
1934 if (ma
> (BR
| 0377)) { /* normal reloc, viol? */
1935 if (rc
!= REL_C
) prvn
= trap_pending
= 1; /* set flag, trap */
1938 pa
= (RR
+ ma
) & DMASK
; /* relocate address */
1940 if (!MEM_ADDR_OK (pa
)) { /* nxm? */
1941 if (rc
!= REL_C
) nexm
= prvn
= trap_pending
= 1; /* set flags, trap */
1951 t_stat
cpu_reset (DEVICE
*dptr
)
1957 ion
= ion_defer
= ion_inh
= 0;
1959 api_enb
= api_req
= api_act
= 0;
1963 usmd
= usmd_buf
= usmd_defer
= 0;
1965 nexm
= prvn
= trap_pending
= 0;
1966 emir_pending
= rest_pending
= 0;
1967 pcq_r
= find_reg ("PCQ", NULL
, dptr
);
1968 if (pcq_r
) pcq_r
->qptr
= 0;
1969 else return SCPE_IERR
;
1970 sim_brk_types
= sim_brk_dflt
= SWMASK ('E');
1974 /* CAF routine (CPU reset isn't called by CAF) */
1978 api_enb
= api_req
= api_act
= 0; /* reset API system */
1979 nexm
= prvn
= trap_pending
= 0; /* reset MM system */
1980 usmd
= usmd_buf
= usmd_defer
= 0;
1985 /* Memory examine */
1987 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1990 if (usmd
&& (sw
& SWMASK ('V'))) {
1991 if (XVM
) addr
= RelocXVM (addr
, REL_C
);
1992 else if (RELOC
) addr
= Reloc15 (addr
, REL_C
);
1993 if ((int32
) addr
< 0) return STOP_MME
;
1996 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1997 if (vptr
!= NULL
) *vptr
= M
[addr
] & DMASK
;
2001 /* Memory deposit */
2003 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
2006 if (usmd
&& (sw
& SWMASK ('V'))) {
2007 if (XVM
) addr
= RelocXVM (addr
, REL_C
);
2008 else if (RELOC
) addr
= Reloc15 (addr
, REL_C
);
2009 if ((int32
) addr
< 0) return STOP_MME
;
2012 if (addr
>= MEMSIZE
) return SCPE_NXM
;
2013 M
[addr
] = val
& DMASK
;
2017 /* Change memory size */
2019 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
2024 if ((val
<= 0) || (val
> MAXMEMSIZE
) || ((val
& 07777) != 0))
2026 for (i
= val
; i
< MEMSIZE
; i
++) mc
= mc
| M
[i
];
2027 if ((mc
!= 0) && (!get_yn ("Really truncate memory [N]?", FALSE
)))
2030 for (i
= MEMSIZE
; i
< MAXMEMSIZE
; i
++) M
[i
] = 0;
2034 /* Change device number for a device */
2036 t_stat
set_devno (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
2043 if (cptr
== NULL
) return SCPE_ARG
;
2044 if (uptr
== NULL
) return SCPE_IERR
;
2045 dptr
= find_dev_from_unit (uptr
);
2046 if (dptr
== NULL
) return SCPE_IERR
;
2047 dibp
= (DIB
*) dptr
->ctxt
;
2048 if (dibp
== NULL
) return SCPE_IERR
;
2049 newdev
= get_uint (cptr
, 8, DEV_MAX
- 1, &r
); /* get new */
2050 if ((r
!= SCPE_OK
) || (newdev
== dibp
->dev
)) return r
;
2051 dibp
->dev
= newdev
; /* store */
2055 /* Show device number for a device */
2057 t_stat
show_devno (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2062 if (uptr
== NULL
) return SCPE_IERR
;
2063 dptr
= find_dev_from_unit (uptr
);
2064 if (dptr
== NULL
) return SCPE_IERR
;
2065 dibp
= (DIB
*) dptr
->ctxt
;
2066 if (dibp
== NULL
) return SCPE_IERR
;
2067 fprintf (st
, "devno=%02o", dibp
->dev
);
2068 if (dibp
->num
> 1) fprintf (st
, "-%2o", dibp
->dev
+ dibp
->num
- 1);
2072 /* CPU device handler - should never get here! */
2074 int32
bad_dev (int32 dev
, int32 pulse
, int32 AC
)
2076 return (SCPE_IERR
<< IOT_V_REASON
) | AC
; /* broken! */
2079 /* Build device dispatch table */
2081 t_bool
build_dev_tab (void)
2086 static const uint8 std_dev
[] =
2089 #elif defined (PDP7)
2092 { 000, 017, 033, 055, 077 };
2095 for (i
= 0; i
< DEV_MAX
; i
++) { /* clr tables */
2099 for (i
= 0; i
< ((uint32
) sizeof (std_dev
)); i
++) /* std entries */
2100 dev_tab
[std_dev
[i
]] = &bad_dev
;
2101 for (i
= p
= 0; (dptr
= sim_devices
[i
]) != NULL
; i
++) { /* add devices */
2102 dibp
= (DIB
*) dptr
->ctxt
; /* get DIB */
2103 if (dibp
&& !(dptr
->flags
& DEV_DIS
)) { /* enabled? */
2104 if (dibp
->iors
) dev_iors
[p
++] = dibp
->iors
; /* if IORS, add */
2105 for (j
= 0; j
< dibp
->num
; j
++) { /* loop thru disp */
2106 if (dibp
->dsp
[j
]) { /* any dispatch? */
2107 if (dev_tab
[dibp
->dev
+ j
]) { /* already filled? */
2108 printf ("%s device number conflict at %02o\n",
2109 sim_dname (dptr
), dibp
->dev
+ j
);
2110 if (sim_log
) fprintf (sim_log
,
2111 "%s device number conflict at %02o\n",
2112 sim_dname (dptr
), dibp
->dev
+ j
);
2115 dev_tab
[dibp
->dev
+ j
] = dibp
->dsp
[j
]; /* fill */
2125 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
2131 for (i
= 0; i
< hst_lnt
; i
++) hst
[i
].pc
= 0;
2135 lnt
= (int32
) get_uint (cptr
, 10, HIST_MAX
, &r
);
2136 if ((r
!= SCPE_OK
) || (lnt
&& (lnt
< HIST_MIN
))) return SCPE_ARG
;
2144 hst
= (InstHistory
*) calloc (lnt
, sizeof (InstHistory
));
2145 if (hst
== NULL
) return SCPE_MEM
;
2153 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2155 int32 l
, j
, k
, di
, lnt
;
2156 char *cptr
= (char *) desc
;
2157 t_value sim_eval
[2];
2160 extern t_stat
fprint_sym (FILE *ofile
, t_addr addr
, t_value
*val
,
2161 UNIT
*uptr
, int32 sw
);
2163 if (hst_lnt
== 0) return SCPE_NOFNC
; /* enabled? */
2165 lnt
= (int32
) get_uint (cptr
, 10, hst_lnt
, &r
);
2166 if ((r
!= SCPE_OK
) || (lnt
== 0)) return SCPE_ARG
;
2169 di
= hst_p
- lnt
; /* work forward */
2170 if (di
< 0) di
= di
+ hst_lnt
;
2171 fprintf (st
, "PC L AC MQ IR\n\n");
2172 for (k
= 0; k
< lnt
; k
++) { /* print specified */
2173 h
= &hst
[(di
++) % hst_lnt
]; /* entry pointer */
2174 if (h
->pc
& HIST_PC
) { /* instruction? */
2175 l
= (h
->lac
>> 18) & 1; /* link */
2176 fprintf (st
, "%06o %o %06o %06o ", h
->pc
& AMASK
, l
, h
->lac
& DMASK
, h
->mq
);
2177 sim_eval
[0] = h
->ir
;
2178 sim_eval
[1] = h
->ir1
;
2179 if ((fprint_sym (st
, h
->pc
& AMASK
, sim_eval
, &cpu_unit
, SWMASK ('M'))) > 0)
2180 fprintf (st
, "(undefined) %06o", h
->ir
);
2181 } /* end else instruction */
2182 else if (h
->pc
& (HIST_API
| HIST_PI
)) { /* interrupt event? */
2183 if (h
->pc
& HIST_PI
) /* PI? */
2184 fprintf (st
, "%06o PI LVL 0-4 =", h
->pc
& AMASK
);
2185 else fprintf (st
, "%06o API %d LVL 0-4 =", h
->pc
& AMASK
, h
->mq
);
2186 for (j
= API_HLVL
; j
>= 0; j
--)
2187 fprintf (st
, " %02o", (h
->ir
>> (j
* HIST_V_LVL
)) & HIST_M_LVL
);
2189 else continue; /* invalid */
2190 fputc ('\n', st
); /* end line */
2195 /* Record events in history table */
2197 void cpu_inst_hist (int32 addr
, int32 inst
)
2201 hst
[hst_p
].pc
= addr
| HIST_PC
;
2202 hst
[hst_p
].ir
= inst
;
2203 if (cpu_ex (&word
, (addr
+ 1) & AMASK
, &cpu_unit
, SWMASK ('V')))
2205 else hst
[hst_p
].ir1
= word
;
2206 hst
[hst_p
].lac
= LAC
;
2208 hst_p
= (hst_p
+ 1);
2209 if (hst_p
>= hst_lnt
) hst_p
= 0;
2213 void cpu_intr_hist (int32 flag
, int32 lvl
)
2217 hst
[hst_p
].pc
= PC
| flag
;
2219 for (j
= 0; j
< API_HLVL
+1; j
++) hst
[hst_p
].ir
=
2220 (hst
[hst_p
].ir
<< HIST_V_LVL
) | (int_hwre
[j
] & HIST_M_LVL
);
2223 hst
[hst_p
].mq
= lvl
;
2224 hst_p
= (hst_p
+ 1);
2225 if (hst_p
>= hst_lnt
) hst_p
= 0;