1 /* pdp1_cpu.c: PDP-1 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-1 central processor
28 30-May-07 RMS Fixed typo in SBS clear (from Norm Lastovica)
29 28-Dec-06 RMS Added 16-channel SBS support, PDP-1D support
30 28-Jun-06 RMS Fixed bugs in MUS and DIV
31 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
32 16-Aug-05 RMS Fixed C++ declaration and cast problems
33 09-Nov-04 RMS Added instruction history
34 07-Sep-03 RMS Added additional explanation on I/O simulation
35 01-Sep-03 RMS Added address switches for hardware readin
36 23-Jul-03 RMS Revised to detect I/O wait hang
37 05-Dec-02 RMS Added drum support
38 06-Oct-02 RMS Revised for V2.10
39 20-Aug-02 RMS Added DECtape support
40 30-Dec-01 RMS Added old PC queue
41 07-Dec-01 RMS Revised to use breakpoint package
42 30-Nov-01 RMS Added extended SET/SHOW support
43 16-Dec-00 RMS Fixed bug in XCT address calculation
44 14-Apr-99 RMS Changed t_addr to unsigned
46 The PDP-1 was Digital's first computer. Although Digital built four
47 other 18b computers, the later systems (the PDP-4, PDP-7, PDP-9, and
48 PDP-15) were similar to each other and quite different from the PDP-1.
49 Accordingly, the PDP-1 requires a distinct simulator.
51 The register state for the PDP-1 is:
56 PC<0:15> program counter
57 IOSTA I/O status register
58 SBS<0:2> sequence break flip flops
59 IOH I/O halt flip flop
60 IOS I/O synchronizer (completion) flip flop
63 SS<1:6> sense switches
64 TW<0:17> test word (switch register)
66 The 16-channel sequence break system adds additional state:
68 sbs_req<0:15> interrupt requests
69 sbs_enb<0:15> enabled levels
70 sbs_act<0:15> active levels
72 The PDP-1D adds additional state:
77 RMASK restrict mode mask
78 RNAME rename table (SN 45 only)
79 RTB restict mode trap buffer (SN 45 only)
83 cks: which bits are line printer print done and space done?
84 cks: is there a bit for sequence break enabled (yes, according
86 sbs: do sequence breaks accumulate while the system is disabled
87 (yes, according to the Maintenance Manual)
89 The PDP-1 has seven instruction formats: memory reference, skips,
90 shifts, load immediate, I/O transfer, operate, and (PDP-1D) special.
91 The memory reference format is:
93 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
94 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
95 | op |in| address | memory reference
96 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
98 <0:4> <5> mnemonic action
101 02 AND AC = AC & M[MA]
102 04 IOR AC = AC | M[MA]
103 06 XOR AC = AC ^ M[MA]
104 10 XCT M[MA] is executed as an instruction
105 12 LCH load character (PDP-1D)
106 14 DCH store character (PDP-1D)
107 16 0 CAL M[100] = AC, AC = PC, PC = 101
108 16 1 JDA M[MA] = AC, AC = PC, PC = MA + 1
112 26 DAP M[MA]<6:17> = AC<6:17>
113 30 DIP M[MA]<0:5> = AC<0:5>
116 36 TAD L'AC = AC + M[MA] + L
117 40 ADD AC = AC + M[MA]
118 42 SUB AC = AC - M[MA]
119 44 IDX AC = M[MA] = M[MA] + 1
120 46 ISP AC = M[MA] = M[MA] + 1, skip if AC >= 0
121 50 SAD skip if AC != M[MA]
122 52 SAS skip if AC == M[MA]
123 54 MUL AC'IO = AC * M[MA]
124 56 DIV AC, IO = AC'IO / M[MA]
126 62 JSP AC = PC, PC = MA
128 Memory reference instructions can access an address space of 64K words.
129 The address space is divided into sixteen 4K word fields. An
130 instruction can directly address, via its 12b address, the entire
131 current field. If extend mode is off, indirect addresses access
132 the current field, and indirect addressing is multi-level; if off,
133 they can access all 64K, and indirect addressing is single level.
137 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
138 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
139 | 1 1 0 1 0| | | | | | | | | | | | | | skip
140 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
141 | | | | | | | \______/ \______/
143 | | | | | | | | +---- program flags
144 | | | | | | | +------------- sense switches
145 | | | | | | +------------------- AC == 0
146 | | | | | +---------------------- AC >= 0
147 | | | | +------------------------- AC < 0
148 | | | +---------------------------- OV == 0
149 | | +------------------------------- IO >= 0
150 | +---------------------------------- IO != 0 (PDP-1D)
151 +------------------------------------- invert skip
155 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
156 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
157 | 1 1 0 1 1| subopcode | encoded count | shift
158 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
160 The load immediate format is:
162 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
163 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
164 | 1 1 1 0 0| S| immediate | LAW
165 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
167 <0:4> mnemonic action
169 70 LAW if S = 0, AC = IR<6:17>
172 The I/O transfer format is:
174 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
175 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
176 | 1 1 1 0 1| W| C| subopcode | device | I/O transfer
177 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
179 The IO transfer instruction sends the the specified subopcode to
180 specified I/O device. The I/O device may take data from the IO or
181 return data to the IO, initiate or cancel operations, etc. The
182 W bit specifies whether the CPU waits for completion, the C bit
183 whether a completion pulse will be returned from the device.
185 The special operate format (PDP-1D) is:
187 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
188 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
189 | 1 1 1 1 0| | | | | | | | | | | | | | special
190 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
191 | | | | | | | | | | |
192 | | | | | | | | | | +------- CML (3)
193 | | | | | | | | | +---------- CLL (1)
194 | | | | | | | | +------------- SZL (1)
195 | | | | | | | +---------------- SCF (1)
196 | | | | | | +------------------- SCI (1)
197 | | | | | +---------------------- SCM (2)
198 | | | | +------------------------- IDA (3)
199 | | | +---------------------------- IDC (4)
200 | | +------------------------------- IFI (2)
201 | +---------------------------------- IIF (2)
202 +------------------------------------- reverse skip
204 The special operate instruction can be microprogrammed.
206 The standard operate format is:
208 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
209 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
210 | 1 1 1 1 1| | | | | | | | | | | | | | operate
211 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
212 | | | | | | | | | | \______/
213 | | | | | | | | | | |
214 | | | | | | | | | | +---- PF select
215 | | | | | | | | | +---------- clear/set PF
216 | | | | | | | | +------------- LIA (PDP-1D)
217 | | | | | | | +---------------- LAI (PDP-1D)
218 | | | | | | +------------------- or PC
219 | | | | | +---------------------- CLA
220 | | | | +------------------------- halt
221 | | | +---------------------------- CMA
222 | | +------------------------------- or TW
223 | +---------------------------------- CLI
224 +------------------------------------- CMI (PDP-1D)
226 The standard operate instruction can be microprogrammed.
228 This routine is the instruction decode routine for the PDP-1.
229 It is called from the simulator control program to execute
230 instructions in simulated memory, starting at the simulated PC.
231 It runs until 'reason' is set non-zero.
235 1. Reasons to stop. The simulator can be stopped by:
238 breakpoint encountered
239 unimplemented instruction and STOP_INST flag set
241 indirect address loop
243 I/O error in I/O simulator
245 2. Interrupts. With a single channel sequence break system, the
246 PDP-1 has a single break request (flop b2, here sbs<SB_V_RQ>).
247 If sequence breaks are enabled (flop sbm, here sbs<SB_V_ON>),
248 and one is not already in progress (flop b4, here sbs<SB_V_IP>),
249 a sequence break occurs. With a 16-channel sequence break
250 system, the PDP-1 has 16 request flops (sbs_req), 16 enable
251 flops (sbs_enb), and 16 active flops (sbs_act). It also has
252 16 synchronizer flops, which are not needed in simulation.
254 3. Arithmetic. The PDP-1 is a 1's complement system. In 1's
255 complement arithmetic, a negative number is represented by the
256 complement (XOR 0777777) of its absolute value. Addition of 1's
257 complement numbers requires propagating the carry out of the high
258 order bit back to the low order bit.
260 4. Adding I/O devices. Three modules must be modified:
262 pdp1_defs.h add interrupt request definition
263 pdp1_cpu.c add IOT dispatch code
264 pdp1_sys.c add sim_devices table entry
267 #include "pdp1_defs.h"
269 #define PCQ_SIZE 64 /* must be 2**n */
270 #define PCQ_MASK (PCQ_SIZE - 1)
271 #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
272 #define UNIT_V_MDV (UNIT_V_UF + 0) /* mul/div */
273 #define UNIT_V_SBS (UNIT_V_UF + 1)
274 #define UNIT_V_1D (UNIT_V_UF + 2)
275 #define UNIT_V_1D45 (UNIT_V_UF + 3)
276 #define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy mask */
277 #define UNIT_MDV (1 << UNIT_V_MDV)
278 #define UNIT_SBS (1 << UNIT_V_SBS)
279 #define UNIT_1D (1 << UNIT_V_1D)
280 #define UNIT_1D45 (1 << UNIT_V_1D45)
281 #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
283 #define HIST_PC 0x40000000
284 #define HIST_V_SHF 18
286 #define HIST_MAX 65536
288 #define MA_GETBNK(x) ((cpu_unit.flags & UNIT_1D45)? \
289 (((x) >> RM45_V_BNK) & RM45_M_BNK): \
290 (((x) >> RM48_V_BNK) & RM48_M_BNK))
301 int32 M
[MAXMEMSIZE
] = { 0 }; /* memory */
302 int32 AC
= 0; /* AC */
303 int32 IO
= 0; /* IO */
304 int32 PC
= 0; /* PC */
305 int32 MA
= 0; /* MA */
306 int32 MB
= 0; /* MB */
307 int32 OV
= 0; /* overflow */
308 int32 SS
= 0; /* sense switches */
309 int32 PF
= 0; /* program flags */
310 int32 TA
= 0; /* address switches */
311 int32 TW
= 0; /* test word */
312 int32 iosta
= 0; /* status reg */
313 int32 sbs
= 0; /* sequence break */
314 int32 sbs_init
= 0; /* seq break start */
315 int32 ioh
= 0; /* I/O halt */
316 int32 ios
= 0; /* I/O syncronizer */
317 int32 cpls
= 0; /* pending compl */
318 int32 sbs_req
= 0; /* sbs requests */
319 int32 sbs_enb
= 0; /* sbs enabled */
320 int32 sbs_act
= 0; /* sbs active */
321 int32 extm
= 0; /* ext mem mode */
322 int32 rm
= 0; /* restrict mode */
323 int32 rmask
= 0; /* restrict mask */
324 int32 rname
[RN45_SIZE
]; /* rename table */
325 int32 rtb
= 0; /* restr trap buf */
326 int32 extm_init
= 0; /* ext mem startup */
327 int32 stop_inst
= 0; /* stop rsrv inst */
328 int32 xct_max
= 16; /* XCT limit */
329 int32 ind_max
= 16; /* ind limit */
330 uint16 pcq
[PCQ_SIZE
] = { 0 }; /* PC queue */
331 int32 pcq_p
= 0; /* PC queue ptr */
332 REG
*pcq_r
= NULL
; /* PC queue reg ptr */
333 int32 hst_p
= 0; /* history pointer */
334 int32 hst_lnt
= 0; /* history length */
335 InstHistory
*hst
= NULL
; /* inst history */
337 extern UNIT
*sim_clock_queue
;
338 extern int32 sim_int_char
;
339 extern uint32 sim_brk_types
, sim_brk_dflt
, sim_brk_summ
; /* breakpoint info */
341 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
);
342 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
);
343 t_stat
cpu_reset (DEVICE
*dptr
);
344 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
345 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
346 t_stat
cpu_set_1d (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
347 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
348 t_stat
Ea (int32 IR
);
349 t_stat
Ea_ch (int32 IR
, int32
*byte_num
);
350 int32
inc_bp (int32 bp
);
351 t_stat
set_rmv (int32 code
);
352 int32
sbs_eval (void);
353 int32
sbs_ffo (int32 mask
);
357 extern int32
ptr (int32 inst
, int32 dev
, int32 dat
);
358 extern int32
ptp (int32 inst
, int32 dev
, int32 dat
);
359 extern int32
tti (int32 inst
, int32 dev
, int32 dat
);
360 extern int32
tto (int32 inst
, int32 dev
, int32 dat
);
361 extern int32
lpt (int32 inst
, int32 dev
, int32 dat
);
362 extern int32
dt (int32 inst
, int32 dev
, int32 dat
);
363 extern int32
drm (int32 inst
, int32 dev
, int32 dat
);
364 extern int32
clk (int32 inst
, int32 dev
, int32 dat
);
365 extern int32
dcs (int32 inst
, int32 dev
, int32 dat
);
367 const int32 sc_map
[512] = {
368 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */
369 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00001xxxx */
370 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00010xxxx */
371 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 00011xxxx */
372 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00100xxxx */
373 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 00101xxxx */
374 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 00110xxxx */
375 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 00111xxxx */
376 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 01000xxxx */
377 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 01001xxxx */
378 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 01010xxxx */
379 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 01011xxxx */
380 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 01100xxxx */
381 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 01101xxxx */
382 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 01110xxxx */
383 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 01111xxxx */
384 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 10000xxxx */
385 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 10001xxxx */
386 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 10010xxxx */
387 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 10011xxxx */
388 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 10100xxxx */
389 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 10101xxxx */
390 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 10110xxxx */
391 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11011xxxx */
392 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 11000xxxx */
393 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 11001xxxx */
394 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 11010xxxx */
395 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11011xxxx */
396 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 11100xxxx */
397 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11101xxxx */
398 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11110xxxx */
399 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9 /* 11111xxxx */
402 const int32 ffo_map
[256] = {
403 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
404 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
405 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
406 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
407 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
408 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
409 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
410 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
411 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
412 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
415 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
416 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
417 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
421 const int32 byt_shf
[4] = { 0, 0, 6, 12 };
423 /* CPU data structures
425 cpu_dev CPU device descriptor
427 cpu_reg CPU register list
428 cpu_mod CPU modifier list
431 UNIT cpu_unit
= { UDATA (NULL
, UNIT_FIX
+ UNIT_BINK
, MAXMEMSIZE
) };
434 { ORDATA (PC
, PC
, ASIZE
) },
435 { ORDATA (AC
, AC
, 18) },
436 { ORDATA (IO
, IO
, 18) },
437 { ORDATA (MA
, MA
, 16) },
438 { ORDATA (MB
, MB
, 18) },
439 { FLDATA (OV
, OV
, 0) },
440 { ORDATA (PF
, PF
, 8) },
441 { ORDATA (SS
, SS
, 6) },
442 { ORDATA (TA
, TA
, ASIZE
) },
443 { ORDATA (TW
, TW
, 18) },
444 { FLDATA (EXTM
, extm
, 0) },
445 { FLDATA (RNGM
, PF
, PF_V_RNG
) },
446 { FLDATA (L
, PF
, PF_V_L
) },
447 { FLDATA (RM
, rm
, 0) },
448 { ORDATA (RMASK
, rmask
, 18) },
449 { ORDATA (RTB
, rtb
, 18) },
450 { BRDATA (RNAME
, rname
, 8, 2, RN45_SIZE
) },
451 { FLDATA (SBON
, sbs
, SB_V_ON
) },
452 { FLDATA (SBRQ
, sbs
, SB_V_RQ
) },
453 { FLDATA (SBIP
, sbs
, SB_V_IP
) },
454 { ORDATA (SBSREQ
, sbs_req
, 16) },
455 { ORDATA (SBSENB
, sbs_enb
, 16) },
456 { ORDATA (SBSACT
, sbs_act
, 16) },
457 { ORDATA (IOSTA
, iosta
, 18), REG_RO
},
458 { ORDATA (CPLS
, cpls
, 6) },
459 { FLDATA (IOH
, ioh
, 0) },
460 { FLDATA (IOS
, ios
, 0) },
461 { BRDATA (PCQ
, pcq
, 8, ASIZE
, PCQ_SIZE
), REG_RO
+REG_CIRC
},
462 { ORDATA (PCQP
, pcq_p
, 6), REG_HRO
},
463 { FLDATA (STOP_INST
, stop_inst
, 0) },
464 { FLDATA (SBS_INIT
, sbs_init
, SB_V_ON
) },
465 { FLDATA (EXTM_INIT
, extm_init
, 0) },
466 { DRDATA (XCT_MAX
, xct_max
, 8), PV_LEFT
+ REG_NZ
},
467 { DRDATA (IND_MAX
, ind_max
, 8), PV_LEFT
+ REG_NZ
},
468 { ORDATA (WRU
, sim_int_char
, 8) },
473 { UNIT_1D
+UNIT_1D45
, 0, "standard CPU", "PDP1C" },
474 { UNIT_1D
+UNIT_1D45
, UNIT_1D
, "PDP-1D #48", "PDP1D48", &cpu_set_1d
},
475 { UNIT_1D
+UNIT_1D45
, UNIT_1D
+UNIT_1D45
, "PDP1D #45", "PDP1D45", &cpu_set_1d
},
476 { UNIT_MDV
, UNIT_MDV
, "multiply/divide", "MDV", NULL
},
477 { UNIT_MDV
, 0, "no multiply/divide", "NOMDV", NULL
},
478 { UNIT_SBS
, UNIT_SBS
, "SBS", "SBS", NULL
},
479 { UNIT_SBS
, 0, "no SBS", "NOSBS", NULL
},
480 { UNIT_MSIZE
, 4096, NULL
, "4K", &cpu_set_size
},
481 { UNIT_MSIZE
, 8192, NULL
, "8K", &cpu_set_size
},
482 { UNIT_MSIZE
, 12288, NULL
, "12K", &cpu_set_size
},
483 { UNIT_MSIZE
, 16384, NULL
, "16K", &cpu_set_size
},
484 { UNIT_MSIZE
, 20480, NULL
, "20K", &cpu_set_size
},
485 { UNIT_MSIZE
, 24576, NULL
, "24K", &cpu_set_size
},
486 { UNIT_MSIZE
, 28672, NULL
, "28K", &cpu_set_size
},
487 { UNIT_MSIZE
, 32768, NULL
, "32K", &cpu_set_size
},
488 { UNIT_MSIZE
, 49152, NULL
, "48K", &cpu_set_size
},
489 { UNIT_MSIZE
, 65536, NULL
, "64K", &cpu_set_size
},
490 { MTAB_XTD
|MTAB_VDV
|MTAB_NMO
|MTAB_SHP
, 0, "HISTORY", "HISTORY",
491 &cpu_set_hist
, &cpu_show_hist
},
496 "CPU", &cpu_unit
, cpu_reg
, cpu_mod
,
497 1, 8, ASIZE
, 1, 8, 18,
498 &cpu_ex
, &cpu_dep
, &cpu_reset
,
503 t_stat
sim_instr (void)
505 extern int32 sim_interval
;
506 int32 IR
, op
, i
, t
, xct_count
;
507 int32 sign
, signd
, v
, sbs_lvl
, byno
;
508 int32 dev
, pulse
, io_data
, sc
, skip
;
510 static int32 fs_test
[8] = {
511 0, PF_SS_1
, PF_SS_2
, PF_SS_3
,
512 PF_SS_4
, PF_SS_5
, PF_SS_6
, PF_SS_ALL
515 #define EPC_WORD ((OV << 17) | (extm << 16) | PC)
516 #define INCR_ADDR(x) (((x) & EPCMASK) | (((x) + 1) & DAMASK))
517 #define DECR_ADDR(x) (((x) & EPCMASK) | (((x) - 1) & DAMASK))
518 #define ABS(x) ((x) ^ (((x) & SIGN)? DMASK: 0))
520 if (cpu_unit
.flags
& UNIT_1D
) { /* PDP-1D? */
521 cpu_unit
.flags
|= UNIT_SBS
|UNIT_MDV
; /* 16-chan SBS, mdv */
522 if (!(cpu_unit
.flags
& UNIT_1D45
)) { /* SN 48? */
523 PF
&= ~PF_L
; /* no link */
524 rtb
= 0; /* no RTB */
525 for (i
= 0; i
< RN45_SIZE
; i
++) rname
[i
] = i
; /* no rename */
528 else { /* standard PDP-1 */
529 PF
&= ~(PF_L
|PF_RNG
); /* no link, ring */
530 rm
= 0; /* no restrict mode */
531 rtb
= 0; /* no RTB */
532 for (i
= 0; i
< RN45_SIZE
; i
++) rname
[i
] = i
; /* no rename */
534 if (cpu_unit
.flags
& UNIT_SBS
) { /* 16-chan SBS? */
535 sbs
= sbs
& SB_ON
; /* yes, only SB ON */
536 sbs_lvl
= sbs_eval (); /* eval SBS system */
538 else sbs_lvl
= sbs_req
= sbs_enb
= sbs_act
= 0; /* no, clr SBS sys */
540 /* Main instruction fetch/decode loop: check events and interrupts */
543 while (reason
== 0) { /* loop until halted */
545 if (sim_interval
<= 0) { /* check clock queue */
546 if (reason
= sim_process_event ()) break;
547 sbs_lvl
= sbs_eval (); /* eval sbs system */
550 if ((cpu_unit
.flags
& UNIT_SBS
)? /* test interrupt */
551 ((sbs
& SB_ON
) && sbs_lvl
): /* 16-chan SBS? */
552 (sbs
== (SB_ON
| SB_RQ
))) { /* 1-chan SBS? */
553 if (cpu_unit
.flags
& UNIT_SBS
) { /* 16-chan intr */
554 int32 lvl
= sbs_lvl
- 1; /* get level */
555 MA
= lvl
<< 2; /* status block */
556 sbs_req
&= ~SBS_MASK (lvl
); /* clr lvl request */
557 sbs_act
|= SBS_MASK (lvl
); /* set lvl active */
558 sbs_lvl
= sbs_eval (); /* re-eval SBS */
560 else { /* 1-chan intr */
561 MA
= 0; /* always level 0 */
562 sbs
= SB_ON
| SB_IP
; /* set in prog flag */
564 PCQ_ENTRY
; /* save old PC */
565 MB
= AC
; /* save AC */
568 MB
= EPC_WORD
; /* save OV'EXT'PC */
571 MB
= IO
; /* save IO */
573 PC
= MA
+ 1; /* PC = block + 3 */
574 extm
= 0; /* extend off */
575 OV
= 0; /* clear overflow */
578 if (sim_brk_summ
&& sim_brk_test (PC
, SWMASK ('E'))) { /* breakpoint? */
579 reason
= STOP_IBKPT
; /* stop simulation */
583 /* Fetch, decode instruction */
586 if (Read ()) break; /* fetch inst */
587 IR
= MB
; /* save in IR */
588 PC
= INCR_ADDR (PC
); /* increment PC */
589 xct_count
= 0; /* track XCT's */
590 sim_interval
= sim_interval
- 1;
591 if (hst_lnt
) { /* history enabled? */
592 hst_p
= (hst_p
+ 1); /* next entry */
593 if (hst_p
>= hst_lnt
) hst_p
= 0;
594 hst
[hst_p
].pc
= MA
| HIST_PC
; /* save state */
596 hst
[hst_p
].ovac
= (OV
<< HIST_V_SHF
) | AC
;
597 hst
[hst_p
].pfio
= (PF
<< HIST_V_SHF
) | IO
;
600 xct_instr
: /* label for XCT */
601 op
= ((IR
>> 13) & 037); /* get opcode */
602 switch (op
) { /* decode IR<0:4> */
604 /* Logical, load, store instructions */
607 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
608 if (reason
= Read ()) break; /* MB <- data */
613 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
614 if (reason
= Read ()) break; /* MB <- data */
619 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
620 if (reason
= Read ()) break; /* MB <- data */
625 if (xct_count
>= xct_max
) { /* too many XCT's? */
629 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
630 if (reason
= Read ()) break; /* MB <- data */
631 xct_count
= xct_count
+ 1; /* count XCT's */
632 IR
= MB
; /* get instruction */
633 goto xct_instr
; /* go execute */
636 if (cpu_unit
.flags
& UNIT_1D
) { /* PDP-1D? */
637 if (reason
= Ea_ch (IR
, &byno
)) break; /* MA <- eff addr */
638 if (reason
= Read ()) break; /* MB <- data */
639 AC
= (MB
<< byt_shf
[byno
]) & 0770000; /* extract byte */
641 else reason
= stop_inst
; /* no, illegal */
645 if (cpu_unit
.flags
& UNIT_1D
) { /* PDP-1D? */
646 if (reason
= Ea_ch (IR
, &byno
)) break; /* MA <- eff addr */
647 if (reason
= Read ()) break; /* MB <- data */
648 MB
= (MB
& ~(0770000 >> byt_shf
[byno
])) | /* insert byte */
649 ((AC
& 0770000) >> byt_shf
[byno
]);
650 Write (); /* rewrite */
651 AC
= ((AC
<< 6) | (AC
>> 12)) & DMASK
; /* rot AC left 6 */
653 else reason
= stop_inst
; /* no, illegal */
656 case 007: /* CAL, JDA */
657 MA
= (PC
& EPCMASK
) | ((IR
& IA
)? (IR
& DAMASK
): 0100);
658 if (hst_p
) hst
[hst_p
].ea
= MA
; /* history enabled? */
660 MB
= AC
; /* save AC */
667 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
668 if (reason
= Read ()) break; /* MB <- data */
673 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
674 if (reason
= Read ()) break; /* MB <- data */
679 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
685 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
686 if (reason
= Read ()) break; /* MB <- data */
687 MB
= (AC
& DAMASK
) | (MB
& ~DAMASK
);
692 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
693 if (reason
= Read ()) break; /* MB <- data */
694 MB
= (AC
& ~DAMASK
) | (MB
& DAMASK
);
699 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
705 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
710 /* Add, subtract, control
712 Add is performed in sequential steps, as follows:
714 2. end around carry propagate
718 Subtract is performed in sequential steps, as follows:
721 3. end around carry propagate
724 Because no -0 check is done, (-0) - (+0) yields a result of -0 */
727 if (cpu_unit
.flags
& UNIT_1D
) { /* PDP-1D? */
728 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
729 if (reason
= Read ()) break; /* MB <- data */
730 AC
= AC
+ MB
+ ((PF
& PF_L
)? 1: 0); /* AC + opnd + L */
731 if (AC
> DMASK
) PF
= PF
| PF_L
; /* carry? set L */
732 else PF
= PF
& ~PF_L
; /* no, clear L */
733 AC
= AC
& DMASK
; /* mask AC */
735 else reason
= stop_inst
; /* no, illegal */
739 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
740 if (reason
= Read ()) break; /* MB <- data */
743 if (AC
> 0777777) AC
= (AC
+ 1) & DMASK
; /* end around carry */
744 if (((~t
^ MB
) & (t
^ AC
)) & SIGN
) OV
= 1;
745 if (AC
== DMASK
) AC
= 0; /* minus 0 cleanup */
749 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
750 if (reason
= Read ()) break; /* MB <- data */
751 t
= AC
^ DMASK
; /* complement AC */
752 AC
= t
+ MB
; /* -AC + MB */
753 if (AC
> DMASK
) AC
= (AC
+ 1) & DMASK
; /* end around carry */
754 if (((~t
^ MB
) & (t
^ AC
)) & SIGN
) OV
= 1;
755 AC
= AC
^ DMASK
; /* recomplement AC */
759 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
760 if (reason
= Read ()) break; /* MB <- data */
762 if (AC
>= DMASK
) AC
= (AC
+ 1) & DMASK
;
768 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
769 if (reason
= Read ()) break; /* MB <- data */
771 if (AC
>= DMASK
) AC
= (AC
+ 1) & DMASK
;
773 if (!(AC
& SIGN
)) PC
= INCR_ADDR (PC
);
778 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
779 if (reason
= Read ()) break; /* MB <- data */
780 if (AC
!= MB
) PC
= INCR_ADDR (PC
);
784 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
785 if (reason
= Read ()) break; /* MB <- data */
786 if (AC
== MB
) PC
= INCR_ADDR (PC
);
790 if (sbs
&& /* SBS enabled? */
791 ((PC
& EPCMASK
) == 0) && /* in bank 0? */
792 ((IR
& (IA
|07703)) == (IA
|00001)) && /* jmp i 00x1/5? */
793 ((cpu_unit
.flags
& UNIT_SBS
) || /* 16-chan SBS or */
794 ((IR
& 00074) == 0))) { /* jmp i 0001? */
795 if (cpu_unit
.flags
& UNIT_SBS
) { /* 16-chan SBS dbk? */
796 int32 lvl
= (IR
>> 2) & SBS_LVL_MASK
; /* lvl = MA<14:15> */
797 sbs_act
&= ~SBS_MASK (lvl
); /* clr level active */
798 sbs_lvl
= sbs_eval (); /* eval SBS system */
800 else sbs
= sbs
& ~SB_IP
; /* 1-chan dbk */
801 PCQ_ENTRY
; /* save old PC */
802 MA
= IR
& DAMASK
; /* ind addr */
803 Read (); /* eff addr word */
804 OV
= (MB
>> 17) & 1; /* restore OV */
805 extm
= (MB
>> 16) & 1; /* restore ext mode */
806 PC
= MB
& AMASK
; /* jmp i 00x1/5 */
807 if (hst_p
) hst
[hst_p
].ea
= PC
; /* history enabled? */
809 else { /* normal JMP */
810 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
817 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
824 AC
= (IR
& 07777) ^ ((IR
& IA
)? 0777777: 0);
827 /* Multiply and divide
829 Multiply and divide step and hardware multiply are exact implementations.
830 Hardware divide is a 2's complement analog to the actual hardware.
834 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
835 if (reason
= Read ()) break; /* MB <- data */
836 if (cpu_unit
.flags
& UNIT_MDV
) { /* hardware? */
837 sign
= AC
^ MB
; /* result sign */
838 IO
= ABS (AC
); /* IO = |AC| */
839 v
= ABS (MB
); /* v = |mpy| */
840 for (i
= AC
= 0; i
< 17; i
++) {
841 if (IO
& 1) AC
= AC
+ v
;
842 IO
= (IO
>> 1) | ((AC
& 1) << 17);
845 if ((sign
& SIGN
) && (AC
| IO
)) { /* negative, > 0? */
850 else { /* multiply step */
851 if (IO
& 1) AC
= AC
+ MB
;
852 if (AC
> DMASK
) AC
= (AC
+ 1) & DMASK
;
853 IO
= (IO
>> 1) | ((AC
& 1) << 17);
859 if (reason
= Ea (IR
)) break; /* MA <- eff addr */
860 if (reason
= Read ()) break; /* MB <- data */
861 if (cpu_unit
.flags
& UNIT_MDV
) { /* hardware */
862 sign
= AC
^ MB
; /* result sign */
863 signd
= AC
; /* remainder sign */
864 v
= ABS (MB
); /* v = |divr| */
865 if (ABS (AC
) >= v
) break; /* overflow? */
867 AC
= AC
^ DMASK
; /* AC'IO = |AC'IO| */
870 for (i
= t
= 0; i
< 18; i
++) {
871 if (t
) AC
= (AC
+ v
) & DMASK
;
872 else AC
= (AC
- v
) & DMASK
;
874 if (i
!= 17) AC
= ((AC
<< 1) | (IO
>> 17)) & DMASK
;
875 IO
= ((IO
<< 1) | (t
^ 1)) & 0777777;
877 if (t
) AC
= (AC
+ v
) & DMASK
; /* fix remainder */
878 t
= ((signd
& SIGN
) && AC
)? AC
^ DMASK
: AC
;
879 AC
= ((sign
& SIGN
) && IO
)? IO
^ DMASK
: IO
;
881 PC
= INCR_ADDR (PC
); /* skip */
883 else { /* divide step */
885 AC
= ((AC
<< 1) | (IO
>> 17)) & DMASK
;
886 IO
= ((IO
<< 1) | (t
^ 1)) & DMASK
;
887 if (IO
& 1) AC
= AC
+ (MB
^ DMASK
);
888 else AC
= AC
+ MB
+ 1;
889 if (AC
> DMASK
) AC
= (AC
+ 1) & DMASK
;
890 if (AC
== DMASK
) AC
= 0;
897 v
= (IR
>> 3) & 07; /* sense switches */
898 t
= IR
& 07; /* program flags */
899 skip
= (((cpu_unit
.flags
& UNIT_1D
) &&
900 (IR
& 04000) && (IO
!= 0)) || /* SNI (PDP-1D) */
901 ((IR
& 02000) && !(IO
& SIGN
)) || /* SPI */
902 ((IR
& 01000) && (OV
== 0)) || /* SZO */
903 ((IR
& 00400) && (AC
& SIGN
)) || /* SMA */
904 ((IR
& 00200) && !(AC
& SIGN
)) || /* SPA */
905 ((IR
& 00100) && (AC
== 0)) || /* SZA */
906 (v
&& ((SS
& fs_test
[v
]) == 0)) || /* SZSn */
907 (t
&& ((PF
& fs_test
[t
]) == 0))); /* SZFn */
908 if (IR
& IA
) skip
= skip
^ 1; /* invert skip? */
909 if (skip
) PC
= INCR_ADDR (PC
);
910 if (IR
& 01000) OV
= 0; /* SOV clears OV */
916 sc
= sc_map
[IR
& 0777]; /* map shift count */
917 switch ((IR
>> 9) & 017) { /* case on IR<5:8> */
920 AC
= ((AC
<< sc
) | (AC
>> (18 - sc
))) & DMASK
;
924 IO
= ((IO
<< sc
) | (IO
>> (18 - sc
))) & DMASK
;
929 AC
= ((AC
<< sc
) | (IO
>> (18 - sc
))) & DMASK
;
930 IO
= ((IO
<< sc
) | (t
>> (18 - sc
))) & DMASK
;
934 t
= (AC
& SIGN
)? DMASK
: 0;
935 AC
= (AC
& SIGN
) | ((AC
<< sc
) & 0377777) |
940 t
= (IO
& SIGN
)? DMASK
: 0;
941 IO
= (IO
& SIGN
) | ((IO
<< sc
) & 0377777) |
946 t
= (AC
& SIGN
)? DMASK
: 0;
947 AC
= (AC
& SIGN
) | ((AC
<< sc
) & 0377777) |
949 IO
= ((IO
<< sc
) | (t
>> (18 - sc
))) & DMASK
;
953 AC
= ((AC
>> sc
) | (AC
<< (18 - sc
))) & DMASK
;
957 IO
= ((IO
>> sc
) | (IO
<< (18 - sc
))) & DMASK
;
962 IO
= ((IO
>> sc
) | (AC
<< (18 - sc
))) & DMASK
;
963 AC
= ((AC
>> sc
) | (t
<< (18 - sc
))) & DMASK
;
967 t
= (AC
& SIGN
)? DMASK
: 0;
968 AC
= ((AC
>> sc
) | (t
<< (18 - sc
))) & DMASK
;
972 t
= (IO
& SIGN
)? DMASK
: 0;
973 IO
= ((IO
>> sc
) | (t
<< (18 - sc
))) & DMASK
;
977 t
= (AC
& SIGN
)? DMASK
: 0;
978 IO
= ((IO
>> sc
) | (AC
<< (18 - sc
))) & DMASK
;
979 AC
= ((AC
>> sc
) | (t
<< (18 - sc
))) & DMASK
;
982 default: /* undefined */
985 } /* end switch shf */
988 /* Special operates (PDP-1D) - performed in order shown */
990 case 036: /* special */
991 if (cpu_unit
.flags
& UNIT_1D
) { /* PDP-1D? */
992 if (IR
& 000100) IO
= 0; /* SCI */
993 if (IR
& 000040) PF
= 0; /* SCF */
994 if (cpu_unit
.flags
& UNIT_1D45
) { /* SN 45? */
995 if ((IR
& 000020) && /* SZL/SNL? */
996 (((PF
& PF_L
) == 0) == ((IR
& IA
) == 0)))
998 if (IR
& 000010) PF
= PF
& ~PF_L
; /* CLL */
999 if (IR
& 000200) { /* SCM */
1000 AC
= (AC
^ DMASK
) + ((PF
& PF_L
)? 1: 0);
1001 if (AC
> DMASK
) PF
= PF
| PF_L
; /* carry? set L */
1002 else PF
= PF
& ~PF_L
; /* no, clear L */
1003 AC
= AC
& DMASK
; /* mask AC */
1007 if (IR
& 004000) IO
= IO
| PF
; /* IIF */
1008 if (IR
& 002000) PF
= PF
| t
; /* IFI */
1009 if (cpu_unit
.flags
& UNIT_1D45
) { /* SN 45? */
1010 if (IR
& 000004) PF
= PF
^ PF_L
; /* CML */
1011 if (IR
& 000400) /* IDA */
1013 (AC
& 0777770) | ((AC
+ 1) & 07):
1016 else PF
= PF
& ~PF_L
; /* no link */
1017 if (IR
& 01000) AC
= inc_bp (AC
); /* IDC */
1019 else reason
= stop_inst
; /* no, illegal */
1022 /* Operates - performed in the order shown */
1024 case 037: /* operate */
1025 if (IR
& 004000) IO
= 0; /* CLI */
1026 if (IR
& 000200) AC
= 0; /* CLA */
1027 if (IR
& 002000) AC
= AC
| TW
; /* LAT */
1028 if (IR
& 000100) AC
= AC
| EPC_WORD
; /* LAP */
1029 if (IR
& 001000) AC
= AC
^ DMASK
; /* CMA */
1030 if (cpu_unit
.flags
& UNIT_1D
) { /* PDP-1D? */
1031 if (IR
& 010000) IO
= IO
^ DMASK
; /* CMI */
1033 if (IR
& 000020) IO
= AC
; /* LIA */
1034 if (IR
& 000040) AC
= MB
; /* LAI */
1036 t
= IR
& 07; /* flag select */
1037 if (IR
& 010) PF
= PF
| fs_test
[t
]; /* STFn */
1038 else PF
= PF
& ~fs_test
[t
]; /* CLFn */
1039 if (IR
& 000400) { /* HLT */
1040 if (rm
&& !sbs_act
) /* restrict, ~brk? */
1041 reason
= set_rmv (RTB_HLT
); /* violation */
1042 else reason
= STOP_HALT
; /* no, halt */
1046 /* IOT - The simulator behaves functionally like a real PDP-1 but does not
1047 use the same mechanisms or state bits. In particular,
1049 - If an IOT does not specify IO_WAIT, the IOT will be executed, and the
1050 I/O halt flag (IOH) will not be disturbed. On the real PDP-1, IOH is
1051 stored in IHS, IOH is cleared, the IOT is executed, and then IOH is
1052 restored from IHS. Because IHS is not otherwise used, it is not
1053 explicitly simulated.
1054 - If an IOT does specify IO_WAIT, then IOH specifies whether an I/O halt
1055 (wait) is already in progress.
1056 > If already set, I/O wait is in progress. The simulator looks for
1057 a completion pulse (IOS). If there is a pulse, IOH is cleared. If
1058 not, the IOT is fetched again. In either case, execution of the
1060 > If not set, I/O wait must start. IOH is set, the PC is backed up,
1061 and the IOT is executed.
1062 - On a real PDP-1, IOC is the I/O command enable and enables the IOT
1063 pulses. In the simulator, the enabling of IOT pulses is done through
1064 code flow, and IOC is not explicitly simulated.
1068 if (rm
&& !sbs_act
) { /* restrict, ~brk? */
1069 reason
= set_rmv (RTB_IOT
); /* violation */
1072 if (IR
& IO_WAIT
) { /* wait? */
1073 if (ioh
) { /* I/O halt? */
1074 if (ios
) ioh
= 0; /* comp pulse? done */
1075 else { /* wait more */
1076 PC
= DECR_ADDR (PC
); /* re-execute */
1077 if (cpls
== 0) { /* pending pulses? */
1078 reason
= STOP_WAIT
; /* no, CPU hangs */
1081 sim_interval
= 0; /* force event */
1083 break; /* skip iot */
1085 ioh
= 1; /* turn on halt */
1086 PC
= DECR_ADDR (PC
); /* re-execute */
1088 dev
= IR
& 077; /* get dev addr */
1089 pulse
= (IR
>> 6) & 077; /* get pulse data */
1090 io_data
= IO
; /* default data */
1091 switch (dev
) { /* case on dev */
1093 case 000: /* I/O wait */
1097 if (IR
& 003700) io_data
= dt (IR
, dev
, IO
); /* DECtape */
1098 else io_data
= ptr (IR
, dev
, IO
); /* paper tape rdr */
1101 case 002: case 030: /* paper tape rdr */
1102 io_data
= ptr (IR
, dev
, IO
);
1105 case 003: /* typewriter */
1106 io_data
= tto (IR
, dev
, IO
);
1109 case 004: /* keyboard */
1110 io_data
= tti (IR
, dev
, IO
);
1113 case 005: case 006: /* paper tape punch */
1114 io_data
= ptp (IR
, dev
, IO
);
1117 case 010: /* leave ring mode */
1118 if (cpu_unit
.flags
& UNIT_1D
) PF
= PF
& ~PF_RNG
;
1119 else reason
= stop_inst
;
1122 case 011: /* enter ring mode */
1123 if (cpu_unit
.flags
& UNIT_1D
) PF
= PF
| PF_RNG
;
1124 else reason
= stop_inst
;
1127 case 022: /* data comm sys */
1128 io_data
= dcs (IR
, dev
, IO
);
1131 case 032: /* clock */
1132 io_data
= clk (IR
, dev
, IO
);
1135 case 033: /* check status */
1136 io_data
= iosta
| ((sbs
& SB_ON
)? IOS_SQB
: 0);
1139 case 035: /* check trap buf */
1140 if (cpu_unit
.flags
& UNIT_1D45
) { /* SN 45? */
1144 else reason
= stop_inst
;
1147 case 045: /* line printer */
1148 io_data
= lpt (IR
, dev
, IO
);
1151 case 050: /* deact seq break */
1152 if (cpu_unit
.flags
& UNIT_SBS
)
1153 sbs_enb
&= ~SBS_MASK (pulse
& SBS_LVL_MASK
);
1154 else reason
= stop_inst
;
1157 case 051: /* act seq break */
1158 if (cpu_unit
.flags
& UNIT_SBS
)
1159 sbs_enb
|= SBS_MASK (pulse
& SBS_LVL_MASK
);
1160 else reason
= stop_inst
;
1163 case 052: /* start seq break */
1164 if (cpu_unit
.flags
& UNIT_SBS
)
1165 sbs_req
|= SBS_MASK (pulse
& SBS_LVL_MASK
);
1166 else reason
= stop_inst
;
1169 case 053: /* clear all chan */
1170 if (cpu_unit
.flags
& UNIT_SBS
) sbs_enb
= 0;
1171 else reason
= stop_inst
;
1174 case 054: /* seq brk off */
1178 case 055: /* seq brk on */
1182 case 056: /* clear seq brk */
1183 sbs
= 0; /* clear PI */
1189 case 061: case 062: case 063: /* drum */
1190 io_data
= drm (IR
, dev
, IO
);
1193 case 064: /* drum/leave rm */
1194 if (cpu_unit
.flags
& UNIT_1D
) rm
= 0;
1195 else io_data
= drm (IR
, dev
, IO
);
1198 case 065: /* enter rm */
1199 if (cpu_unit
.flags
& UNIT_1D
) {
1203 else reason
= stop_inst
;
1206 case 066: /* rename mem */
1207 if (cpu_unit
.flags
& UNIT_1D45
) { /* SN45? */
1208 int32 from
= (IR
>> 9) & RM45_M_BNK
;
1209 int32 to
= (IR
>> 6) & RM45_M_BNK
;
1212 else reason
= stop_inst
;
1215 case 067: /* reset renaming */
1216 if (cpu_unit
.flags
& UNIT_1D45
) { /* SN45 */
1217 for (i
= 0; i
< RN45_SIZE
; i
++) rname
[i
] = i
;
1219 else reason
= stop_inst
;
1222 case 074: /* extend mode */
1223 extm
= (IR
>> 11) & 1; /* set from IR<6> */
1226 default: /* undefined */
1229 } /* end switch dev */
1231 IO
= io_data
& DMASK
;
1232 if (io_data
& IOT_SKP
) PC
= INCR_ADDR (PC
); /* skip? */
1233 if (io_data
>= IOT_REASON
) reason
= io_data
>> IOT_V_REASON
;
1234 sbs_lvl
= sbs_eval (); /* eval SBS system */
1237 default: /* undefined */
1238 if (rm
&& !sbs_act
) /* restrict, ~brk? */
1239 reason
= set_rmv (RTB_ILL
); /* violation */
1240 else reason
= STOP_RSRV
; /* halt */
1242 } /* end switch op */
1244 if (reason
== ERR_RMV
) { /* restrict viol? */
1245 sbs_req
|= SBS_MASK (SBS_LVL_RMV
); /* request break */
1246 sbs_lvl
= sbs_eval (); /* re-eval SBS */
1247 reason
= 0; /* continue */
1250 pcq_r
->qptr
= pcq_p
; /* update pc q ptr */
1254 /* Effective address routine for standard memory reference instructions */
1256 t_stat
Ea (int32 IR
)
1261 MA
= (PC
& EPCMASK
) | (IR
& DAMASK
); /* direct address */
1262 if (IR
& IA
) { /* indirect addr? */
1263 if (extm
) { /* extend? */
1264 if (r
= Read ()) return r
; /* read; err? */
1265 MA
= MB
& AMASK
; /* one level */
1267 else { /* multi-level */
1268 for (i
= 0; i
< ind_max
; i
++) { /* count indirects */
1269 if (r
= Read ()) return r
; /* get ind word */
1270 MA
= (PC
& EPCMASK
) | (MB
& DAMASK
);
1271 if ((MB
& IA
) == 0) break;
1273 if (i
>= ind_max
) return STOP_IND
; /* indirect loop? */
1274 } /* end else !extm */
1275 } /* end if indirect */
1276 if (hst_p
) hst
[hst_p
].ea
= MA
; /* history enabled? */
1280 /* Effective address routine for character instructions */
1282 t_stat
Ea_ch (int32 IR
, int32
*bn
)
1287 MA
= (PC
& EPCMASK
) | (IR
& DAMASK
); /* direct address */
1288 if (extm
) { /* extend? */
1289 if (r
= Read ()) return r
; /* read; err? */
1291 else { /* multi-level */
1292 for (i
= 0; i
< ind_max
; i
++) { /* count indirects */
1293 if (r
= Read ()) return r
; /* get ind word */
1294 if ((MB
& IA
) == 0) break;
1295 MA
= (PC
& EPCMASK
) | (MB
& DAMASK
);
1297 if (i
>= ind_max
) return STOP_IND
; /* indirect loop? */
1298 } /* end else !extm */
1299 if (IR
& IA
) { /* automatic mode? */
1300 if (rm
& !sbs_act
& ((MB
& 0607777) == 0607777)) /* page cross? */
1301 return set_rmv (RTB_CHR
);
1302 MB
= inc_bp (MB
); /* incr byte ptr */
1303 Write (); /* rewrite */
1305 *bn
= (MB
>> 16) & 03; /* byte num */
1306 if (extm
) MA
= MB
& AMASK
; /* final ea */
1307 else MA
= (PC
& EPCMASK
) | (MB
& DAMASK
);
1308 if (hst_p
) hst
[hst_p
].ea
= MA
; /* history enabled? */
1312 /* Increment byte pointer, allowing for ring mode */
1314 int32
inc_bp (int32 bp
)
1316 bp
= bp
+ (1 << 16); /* add to bit<1> */
1317 if (bp
> DMASK
) { /* carry out? */
1318 if (PF
& PF_RNG
) /* ring mode? */
1319 bp
= (1 << 16) | (bp
& 0177770) | ((bp
+ 1) & 07);
1320 else bp
= (1 << 16) | ((bp
+ 1) & AMASK
);
1325 /* Read and write memory */
1329 if (rm
&& !sbs_act
) { /* restrict check? */
1330 int32 bnk
= MA_GETBNK (MA
); /* get bank */
1331 if ((rmask
<< bnk
) & SIGN
) return set_rmv (0);
1334 if (hst_p
) hst
[hst_p
].opnd
= MB
; /* history enabled? */
1340 if (hst_p
) hst
[hst_p
].opnd
= M
[MA
]; /* hist? old contents */
1341 if (rm
&& !sbs_act
) { /* restrict check? */
1342 int32 bnk
= MA_GETBNK (MA
); /* get bank */
1343 if ((rmask
<< bnk
) & SIGN
) return set_rmv (0);
1345 if (MEM_ADDR_OK (MA
)) M
[MA
] = MB
;
1349 /* Restrict mode trap */
1351 t_stat
set_rmv (int32 code
)
1353 rtb
= code
| (MB
& RTB_MB_MASK
);
1357 /* Evaluate SBS system */
1359 int32
sbs_eval (void)
1363 if (cpu_unit
.flags
& UNIT_SBS
) { /* SBS enabled? */
1364 if (sbs_req
== 0) return 0; /* any requests? */
1365 hi
= sbs_ffo (sbs_req
); /* find highest */
1366 if (hi
< sbs_ffo (sbs_act
)) return hi
+ 1; /* higher? */
1371 /* Find first one in a 16b field */
1373 int32
sbs_ffo (int32 mask
)
1376 return ffo_map
[(mask
>> 8) & 0377];
1377 else return (ffo_map
[mask
& 0377] + 8);
1380 /* Device request interrupt */
1382 t_stat
dev_req_int (int32 lvl
)
1384 if (cpu_unit
.flags
& UNIT_SBS
) { /* SBS enabled? */
1385 if (lvl
>= SBS_LVLS
) return SCPE_IERR
; /* invalid level? */
1386 if (sbs_enb
& SBS_MASK (lvl
)) /* level active? */
1387 sbs_req
|= SBS_MASK (lvl
); /* set SBS request */
1389 else sbs
|= SB_RQ
; /* PI request */
1393 /* Device set/show SBS level */
1395 t_stat
dev_set_sbs (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1397 int32
*lvl
= (int32
*) desc
;
1401 if ((cptr
== NULL
) || (*cptr
== 0)) return SCPE_ARG
;
1402 newlvl
= get_uint (cptr
, 10, SBS_LVLS
- 1, &r
);
1403 if (r
!= SCPE_OK
) return SCPE_ARG
;
1408 t_stat
dev_show_sbs (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1410 int32
*lvl
= (int32
*) desc
;
1412 if (lvl
== NULL
) return SCPE_IERR
;
1413 fprintf (st
, "SBS level %d", *lvl
);
1419 t_stat
cpu_reset (DEVICE
*dptr
)
1438 for (i
= 0; i
< RN45_SIZE
; i
++) rname
[i
] = i
;
1439 pcq_r
= find_reg ("PCQ", NULL
, dptr
);
1440 if (pcq_r
) pcq_r
->qptr
= 0;
1441 else return SCPE_IERR
;
1442 sim_brk_types
= sim_brk_dflt
= SWMASK ('E');
1446 /* Memory examine */
1448 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1450 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1451 if (vptr
!= NULL
) *vptr
= M
[addr
] & DMASK
;
1455 /* Memory deposit */
1457 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1459 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1460 M
[addr
] = val
& DMASK
;
1464 /* Change memory size */
1466 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1471 if ((val
<= 0) || (val
> MAXMEMSIZE
) || ((val
& 07777) != 0))
1473 for (i
= val
; i
< MEMSIZE
; i
++) mc
= mc
| M
[i
];
1474 if ((mc
!= 0) && (!get_yn ("Really truncate memory [N]?", FALSE
)))
1477 for (i
= MEMSIZE
; i
< MAXMEMSIZE
; i
++) M
[i
] = 0;
1483 t_stat
cpu_set_1d (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1485 uptr
->flags
|= UNIT_SBS
|UNIT_MDV
;
1491 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1497 for (i
= 0; i
< hst_lnt
; i
++) hst
[i
].pc
= 0;
1501 lnt
= (int32
) get_uint (cptr
, 10, HIST_MAX
, &r
);
1502 if ((r
!= SCPE_OK
) || (lnt
&& (lnt
< HIST_MIN
))) return SCPE_ARG
;
1510 hst
= (InstHistory
*) calloc (lnt
, sizeof (InstHistory
));
1511 if (hst
== NULL
) return SCPE_MEM
;
1519 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1521 int32 ov
, pf
, op
, k
, di
, lnt
;
1522 char *cptr
= (char *) desc
;
1526 extern t_stat
fprint_sym (FILE *ofile
, t_addr addr
, t_value
*val
,
1527 UNIT
*uptr
, int32 sw
);
1529 if (hst_lnt
== 0) return SCPE_NOFNC
; /* enabled? */
1531 lnt
= (int32
) get_uint (cptr
, 10, hst_lnt
, &r
);
1532 if ((r
!= SCPE_OK
) || (lnt
== 0)) return SCPE_ARG
;
1535 di
= hst_p
- lnt
; /* work forward */
1536 if (di
< 0) di
= di
+ hst_lnt
;
1537 fprintf (st
, "PC OV AC IO PF EA IR\n\n");
1538 for (k
= 0; k
< lnt
; k
++) { /* print specified */
1539 h
= &hst
[(++di
) % hst_lnt
]; /* entry pointer */
1540 if (h
->pc
& HIST_PC
) { /* instruction? */
1541 ov
= (h
->ovac
>> HIST_V_SHF
) & 1; /* overflow */
1542 pf
= (h
->pfio
>> HIST_V_SHF
) & PF_VR_ALL
; /* prog flags */
1543 op
= ((h
->ir
>> 13) & 037); /* get opcode */
1544 fprintf (st
, "%06o %o %06o %06o %03o ",
1545 h
->pc
& AMASK
, ov
, h
->ovac
& DMASK
, h
->pfio
& DMASK
, pf
);
1546 if ((op
< 032) && (op
!= 007)) /* mem ref instr */
1547 fprintf (st
, "%06o ", h
->ea
);
1548 else fprintf (st
, " ");
1550 if ((fprint_sym (st
, h
->pc
& AMASK
, &sim_eval
, &cpu_unit
, SWMASK ('M'))) > 0)
1551 fprintf (st
, "(undefined) %06o", h
->ir
);
1552 else if (op
< 030) /* mem ref instr */
1553 fprintf (st
, " [%06o]", h
->opnd
);
1554 fputc ('\n', st
); /* end line */
1555 } /* end else instruction */