First Commit of my working state
[simh.git] / PDP1 / pdp1_cpu.c
1 /* pdp1_cpu.c: PDP-1 CPU simulator
2
3 Copyright (c) 1993-2007, Robert M. Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 cpu PDP-1 central processor
27
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
45
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.
50
51 The register state for the PDP-1 is:
52
53 AC<0:17> accumulator
54 IO<0:17> IO register
55 OV overflow flag
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
61 EXTM extend mode
62 PF<1:6> program flags
63 SS<1:6> sense switches
64 TW<0:17> test word (switch register)
65
66 The 16-channel sequence break system adds additional state:
67
68 sbs_req<0:15> interrupt requests
69 sbs_enb<0:15> enabled levels
70 sbs_act<0:15> active levels
71
72 The PDP-1D adds additional state:
73
74 L link (SN 45 only)
75 RNG ring mode
76 RM restrict mode
77 RMASK restrict mode mask
78 RNAME rename table (SN 45 only)
79 RTB restict mode trap buffer (SN 45 only)
80
81 Questions:
82
83 cks: which bits are line printer print done and space done?
84 cks: is there a bit for sequence break enabled (yes, according
85 to the 1963 Handbook)
86 sbs: do sequence breaks accumulate while the system is disabled
87 (yes, according to the Maintenance Manual)
88
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:
92
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
97
98 <0:4> <5> mnemonic action
99
100 00
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
109 20 LAC AC = M[MA]
110 22 LIO IO = M[MA]
111 24 DAC M[MA] = AC
112 26 DAP M[MA]<6:17> = AC<6:17>
113 30 DIP M[MA]<0:5> = AC<0:5>
114 32 DIO M[MA] = IO
115 34 DZM M[MA] = 0
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]
125 60 JMP PC = MA
126 62 JSP AC = PC, PC = MA
127
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.
134
135 The skip format is:
136
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 | | | | | | | \______/ \______/
142 | | | | | | | | |
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
152
153 The shift format is:
154
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
159
160 The load immediate format is:
161
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
166
167 <0:4> mnemonic action
168
169 70 LAW if S = 0, AC = IR<6:17>
170 else AC = ~IR<6:17>
171
172 The I/O transfer format is:
173
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
178
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.
184
185 The special operate format (PDP-1D) is:
186
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
203
204 The special operate instruction can be microprogrammed.
205
206 The standard operate format is:
207
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)
225
226 The standard operate instruction can be microprogrammed.
227
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.
232
233 General notes:
234
235 1. Reasons to stop. The simulator can be stopped by:
236
237 HALT instruction
238 breakpoint encountered
239 unimplemented instruction and STOP_INST flag set
240 XCT loop
241 indirect address loop
242 infinite wait state
243 I/O error in I/O simulator
244
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.
253
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.
259
260 4. Adding I/O devices. Three modules must be modified:
261
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
265 */
266
267 #include "pdp1_defs.h"
268
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)
282
283 #define HIST_PC 0x40000000
284 #define HIST_V_SHF 18
285 #define HIST_MIN 64
286 #define HIST_MAX 65536
287
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))
291
292 typedef struct {
293 uint32 pc;
294 uint32 ir;
295 uint32 ovac;
296 uint32 pfio;
297 uint32 ea;
298 uint32 opnd;
299 } InstHistory;
300
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 */
336
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 */
340
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);
354 t_stat Read (void);
355 t_stat Write (void);
356
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);
366
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 */
400 };
401
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
419 };
420
421 const int32 byt_shf[4] = { 0, 0, 6, 12 };
422
423 /* CPU data structures
424
425 cpu_dev CPU device descriptor
426 cpu_unit CPU unit
427 cpu_reg CPU register list
428 cpu_mod CPU modifier list
429 */
430
431 UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };
432
433 REG cpu_reg[] = {
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) },
469 { NULL }
470 };
471
472 MTAB cpu_mod[] = {
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 },
492 { 0 }
493 };
494
495 DEVICE cpu_dev = {
496 "CPU", &cpu_unit, cpu_reg, cpu_mod,
497 1, 8, ASIZE, 1, 8, 18,
498 &cpu_ex, &cpu_dep, &cpu_reset,
499 NULL, NULL, NULL,
500 NULL, 0
501 };
502
503 t_stat sim_instr (void)
504 {
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;
509 t_stat reason;
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
513 };
514
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))
519
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 */
526 }
527 }
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 */
533 }
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 */
537 }
538 else sbs_lvl = sbs_req = sbs_enb = sbs_act = 0; /* no, clr SBS sys */
539
540 /* Main instruction fetch/decode loop: check events and interrupts */
541
542 reason = 0;
543 while (reason == 0) { /* loop until halted */
544
545 if (sim_interval <= 0) { /* check clock queue */
546 if (reason = sim_process_event ()) break;
547 sbs_lvl = sbs_eval (); /* eval sbs system */
548 }
549
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 */
559 }
560 else { /* 1-chan intr */
561 MA = 0; /* always level 0 */
562 sbs = SB_ON | SB_IP; /* set in prog flag */
563 }
564 PCQ_ENTRY; /* save old PC */
565 MB = AC; /* save AC */
566 Write ();
567 MA = MA + 1;
568 MB = EPC_WORD; /* save OV'EXT'PC */
569 Write ();
570 MA = MA + 1;
571 MB = IO; /* save IO */
572 Write ();
573 PC = MA + 1; /* PC = block + 3 */
574 extm = 0; /* extend off */
575 OV = 0; /* clear overflow */
576 }
577
578 if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
579 reason = STOP_IBKPT; /* stop simulation */
580 break;
581 }
582
583 /* Fetch, decode instruction */
584
585 MA = PC;
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 */
595 hst[hst_p].ir = IR;
596 hst[hst_p].ovac = (OV << HIST_V_SHF) | AC;
597 hst[hst_p].pfio = (PF << HIST_V_SHF) | IO;
598 }
599
600 xct_instr: /* label for XCT */
601 op = ((IR >> 13) & 037); /* get opcode */
602 switch (op) { /* decode IR<0:4> */
603
604 /* Logical, load, store instructions */
605
606 case 001: /* AND */
607 if (reason = Ea (IR)) break; /* MA <- eff addr */
608 if (reason = Read ()) break; /* MB <- data */
609 AC = AC & MB;
610 break;
611
612 case 002: /* IOR */
613 if (reason = Ea (IR)) break; /* MA <- eff addr */
614 if (reason = Read ()) break; /* MB <- data */
615 AC = AC | MB;
616 break;
617
618 case 003: /* XOR */
619 if (reason = Ea (IR)) break; /* MA <- eff addr */
620 if (reason = Read ()) break; /* MB <- data */
621 AC = AC ^ MB;
622 break;
623
624 case 004: /* XCT */
625 if (xct_count >= xct_max) { /* too many XCT's? */
626 reason = STOP_XCT;
627 break;
628 }
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 */
634
635 case 005: /* LCH */
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 */
640 }
641 else reason = stop_inst; /* no, illegal */
642 break;
643
644 case 006: /* DCH */
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 */
652 }
653 else reason = stop_inst; /* no, illegal */
654 break;
655
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? */
659 PCQ_ENTRY;
660 MB = AC; /* save AC */
661 AC = EPC_WORD;
662 PC = INCR_ADDR (MA);
663 reason = Write ();
664 break;
665
666 case 010: /* LAC */
667 if (reason = Ea (IR)) break; /* MA <- eff addr */
668 if (reason = Read ()) break; /* MB <- data */
669 AC = MB;
670 break;
671
672 case 011: /* LIO */
673 if (reason = Ea (IR)) break; /* MA <- eff addr */
674 if (reason = Read ()) break; /* MB <- data */
675 IO = MB;
676 break;
677
678 case 012: /* DAC */
679 if (reason = Ea (IR)) break; /* MA <- eff addr */
680 MB = AC;
681 reason = Write ();
682 break;
683
684 case 013: /* DAP */
685 if (reason = Ea (IR)) break; /* MA <- eff addr */
686 if (reason = Read ()) break; /* MB <- data */
687 MB = (AC & DAMASK) | (MB & ~DAMASK);
688 reason = Write ();
689 break;
690
691 case 014: /* DIP */
692 if (reason = Ea (IR)) break; /* MA <- eff addr */
693 if (reason = Read ()) break; /* MB <- data */
694 MB = (AC & ~DAMASK) | (MB & DAMASK);
695 reason = Write ();
696 break;
697
698 case 015: /* DIO */
699 if (reason = Ea (IR)) break; /* MA <- eff addr */
700 MB = IO;
701 reason = Write ();
702 break;
703
704 case 016: /* DZM */
705 if (reason = Ea (IR)) break; /* MA <- eff addr */
706 MB = 0;
707 reason = Write ();
708 break;
709
710 /* Add, subtract, control
711
712 Add is performed in sequential steps, as follows:
713 1. add
714 2. end around carry propagate
715 3. overflow check
716 4. -0 cleanup
717
718 Subtract is performed in sequential steps, as follows:
719 1. complement AC
720 2. add
721 3. end around carry propagate
722 4. overflow check
723 5. complement AC
724 Because no -0 check is done, (-0) - (+0) yields a result of -0 */
725
726 case 017: /* TAD */
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 */
734 }
735 else reason = stop_inst; /* no, illegal */
736 break;
737
738 case 020: /* ADD */
739 if (reason = Ea (IR)) break; /* MA <- eff addr */
740 if (reason = Read ()) break; /* MB <- data */
741 t = AC;
742 AC = AC + MB;
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 */
746 break;
747
748 case 021: /* SUB */
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 */
756 break;
757
758 case 022: /* IDX */
759 if (reason = Ea (IR)) break; /* MA <- eff addr */
760 if (reason = Read ()) break; /* MB <- data */
761 AC = MB + 1;
762 if (AC >= DMASK) AC = (AC + 1) & DMASK;
763 MB = AC;
764 reason = Write ();
765 break;
766
767 case 023: /* ISP */
768 if (reason = Ea (IR)) break; /* MA <- eff addr */
769 if (reason = Read ()) break; /* MB <- data */
770 AC = MB + 1;
771 if (AC >= DMASK) AC = (AC + 1) & DMASK;
772 MB = AC;
773 if (!(AC & SIGN)) PC = INCR_ADDR (PC);
774 reason = Write ();
775 break;
776
777 case 024: /* SAD */
778 if (reason = Ea (IR)) break; /* MA <- eff addr */
779 if (reason = Read ()) break; /* MB <- data */
780 if (AC != MB) PC = INCR_ADDR (PC);
781 break;
782
783 case 025: /* SAS */
784 if (reason = Ea (IR)) break; /* MA <- eff addr */
785 if (reason = Read ()) break; /* MB <- data */
786 if (AC == MB) PC = INCR_ADDR (PC);
787 break;
788
789 case 030: /* JMP */
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 */
799 }
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? */
808 }
809 else { /* normal JMP */
810 if (reason = Ea (IR)) break; /* MA <- eff addr */
811 PCQ_ENTRY;
812 PC = MA;
813 }
814 break;
815
816 case 031: /* JSP */
817 if (reason = Ea (IR)) break; /* MA <- eff addr */
818 AC = EPC_WORD;
819 PCQ_ENTRY;
820 PC = MA;
821 break;
822
823 case 034: /* LAW */
824 AC = (IR & 07777) ^ ((IR & IA)? 0777777: 0);
825 break;
826
827 /* Multiply and divide
828
829 Multiply and divide step and hardware multiply are exact implementations.
830 Hardware divide is a 2's complement analog to the actual hardware.
831 */
832
833 case 026: /* MUL */
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);
843 AC = AC >> 1;
844 }
845 if ((sign & SIGN) && (AC | IO)) { /* negative, > 0? */
846 AC = AC ^ DMASK;
847 IO = IO ^ DMASK;
848 }
849 }
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);
854 AC = AC >> 1;
855 }
856 break;
857
858 case 027: /* DIV */
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? */
866 if (AC & SIGN) {
867 AC = AC ^ DMASK; /* AC'IO = |AC'IO| */
868 IO = IO ^ DMASK;
869 }
870 for (i = t = 0; i < 18; i++) {
871 if (t) AC = (AC + v) & DMASK;
872 else AC = (AC - v) & DMASK;
873 t = AC >> 17;
874 if (i != 17) AC = ((AC << 1) | (IO >> 17)) & DMASK;
875 IO = ((IO << 1) | (t ^ 1)) & 0777777;
876 }
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;
880 IO = t;
881 PC = INCR_ADDR (PC); /* skip */
882 }
883 else { /* divide step */
884 t = AC >> 17;
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;
891 }
892 break;
893
894 /* Skips */
895
896 case 032: /* skip */
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 */
911 break;
912
913 /* Shifts */
914
915 case 033:
916 sc = sc_map[IR & 0777]; /* map shift count */
917 switch ((IR >> 9) & 017) { /* case on IR<5:8> */
918
919 case 001: /* RAL */
920 AC = ((AC << sc) | (AC >> (18 - sc))) & DMASK;
921 break;
922
923 case 002: /* RIL */
924 IO = ((IO << sc) | (IO >> (18 - sc))) & DMASK;
925 break;
926
927 case 003: /* RCL */
928 t = AC;
929 AC = ((AC << sc) | (IO >> (18 - sc))) & DMASK;
930 IO = ((IO << sc) | (t >> (18 - sc))) & DMASK;
931 break;
932
933 case 005: /* SAL */
934 t = (AC & SIGN)? DMASK: 0;
935 AC = (AC & SIGN) | ((AC << sc) & 0377777) |
936 (t >> (18 - sc));
937 break;
938
939 case 006: /* SIL */
940 t = (IO & SIGN)? DMASK: 0;
941 IO = (IO & SIGN) | ((IO << sc) & 0377777) |
942 (t >> (18 - sc));
943 break;
944
945 case 007: /* SCL */
946 t = (AC & SIGN)? DMASK: 0;
947 AC = (AC & SIGN) | ((AC << sc) & 0377777) |
948 (IO >> (18 - sc));
949 IO = ((IO << sc) | (t >> (18 - sc))) & DMASK;
950 break;
951
952 case 011: /* RAR */
953 AC = ((AC >> sc) | (AC << (18 - sc))) & DMASK;
954 break;
955
956 case 012: /* RIR */
957 IO = ((IO >> sc) | (IO << (18 - sc))) & DMASK;
958 break;
959
960 case 013: /* RCR */
961 t = IO;
962 IO = ((IO >> sc) | (AC << (18 - sc))) & DMASK;
963 AC = ((AC >> sc) | (t << (18 - sc))) & DMASK;
964 break;
965
966 case 015: /* SAR */
967 t = (AC & SIGN)? DMASK: 0;
968 AC = ((AC >> sc) | (t << (18 - sc))) & DMASK;
969 break;
970
971 case 016: /* SIR */
972 t = (IO & SIGN)? DMASK: 0;
973 IO = ((IO >> sc) | (t << (18 - sc))) & DMASK;
974 break;
975
976 case 017: /* SCR */
977 t = (AC & SIGN)? DMASK: 0;
978 IO = ((IO >> sc) | (AC << (18 - sc))) & DMASK;
979 AC = ((AC >> sc) | (t << (18 - sc))) & DMASK;
980 break;
981
982 default: /* undefined */
983 reason = stop_inst;
984 break;
985 } /* end switch shf */
986 break;
987
988 /* Special operates (PDP-1D) - performed in order shown */
989
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)))
997 PC = INCR_ADDR (PC);
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 */
1004 }
1005 }
1006 t = IO & PF_VR_ALL;
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 */
1012 AC = (PF & PF_RNG)?
1013 (AC & 0777770) | ((AC + 1) & 07):
1014 (AC + 1) & DMASK;
1015 }
1016 else PF = PF & ~PF_L; /* no link */
1017 if (IR & 01000) AC = inc_bp (AC); /* IDC */
1018 }
1019 else reason = stop_inst; /* no, illegal */
1020 break;
1021
1022 /* Operates - performed in the order shown */
1023
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 */
1032 MB = IO;
1033 if (IR & 000020) IO = AC; /* LIA */
1034 if (IR & 000040) AC = MB; /* LAI */
1035 }
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 */
1043 }
1044 break;
1045
1046 /* IOT - The simulator behaves functionally like a real PDP-1 but does not
1047 use the same mechanisms or state bits. In particular,
1048
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
1059 IOT is skipped.
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.
1065 */
1066
1067 case 035:
1068 if (rm && !sbs_act) { /* restrict, ~brk? */
1069 reason = set_rmv (RTB_IOT); /* violation */
1070 break;
1071 }
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 */
1079 break;
1080 }
1081 sim_interval = 0; /* force event */
1082 }
1083 break; /* skip iot */
1084 }
1085 ioh = 1; /* turn on halt */
1086 PC = DECR_ADDR (PC); /* re-execute */
1087 }
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 */
1092
1093 case 000: /* I/O wait */
1094 break;
1095
1096 case 001:
1097 if (IR & 003700) io_data = dt (IR, dev, IO); /* DECtape */
1098 else io_data = ptr (IR, dev, IO); /* paper tape rdr */
1099 break;
1100
1101 case 002: case 030: /* paper tape rdr */
1102 io_data = ptr (IR, dev, IO);
1103 break;
1104
1105 case 003: /* typewriter */
1106 io_data = tto (IR, dev, IO);
1107 break;
1108
1109 case 004: /* keyboard */
1110 io_data = tti (IR, dev, IO);
1111 break;
1112
1113 case 005: case 006: /* paper tape punch */
1114 io_data = ptp (IR, dev, IO);
1115 break;
1116
1117 case 010: /* leave ring mode */
1118 if (cpu_unit.flags & UNIT_1D) PF = PF & ~PF_RNG;
1119 else reason = stop_inst;
1120 break;
1121
1122 case 011: /* enter ring mode */
1123 if (cpu_unit.flags & UNIT_1D) PF = PF | PF_RNG;
1124 else reason = stop_inst;
1125 break;
1126
1127 case 022: /* data comm sys */
1128 io_data = dcs (IR, dev, IO);
1129 break;
1130
1131 case 032: /* clock */
1132 io_data = clk (IR, dev, IO);
1133 break;
1134
1135 case 033: /* check status */
1136 io_data = iosta | ((sbs & SB_ON)? IOS_SQB: 0);
1137 break;
1138
1139 case 035: /* check trap buf */
1140 if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */
1141 io_data = rtb;
1142 rtb = 0;
1143 }
1144 else reason = stop_inst;
1145 break;
1146
1147 case 045: /* line printer */
1148 io_data = lpt (IR, dev, IO);
1149 break;
1150
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;
1155 break;
1156
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;
1161 break;
1162
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;
1167 break;
1168
1169 case 053: /* clear all chan */
1170 if (cpu_unit.flags & UNIT_SBS) sbs_enb = 0;
1171 else reason = stop_inst;
1172 break;
1173
1174 case 054: /* seq brk off */
1175 sbs = sbs & ~SB_ON;
1176 break;
1177
1178 case 055: /* seq brk on */
1179 sbs = sbs | SB_ON;
1180 break;
1181
1182 case 056: /* clear seq brk */
1183 sbs = 0; /* clear PI */
1184 sbs_req = 0;
1185 sbs_enb = 0;
1186 sbs_act = 0;
1187 break;
1188
1189 case 061: case 062: case 063: /* drum */
1190 io_data = drm (IR, dev, IO);
1191 break;
1192
1193 case 064: /* drum/leave rm */
1194 if (cpu_unit.flags & UNIT_1D) rm = 0;
1195 else io_data = drm (IR, dev, IO);
1196 break;
1197
1198 case 065: /* enter rm */
1199 if (cpu_unit.flags & UNIT_1D) {
1200 rm = 1;
1201 rmask = IO;
1202 }
1203 else reason = stop_inst;
1204 break;
1205
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;
1210 rname[from] = to;
1211 }
1212 else reason = stop_inst;
1213 break;
1214
1215 case 067: /* reset renaming */
1216 if (cpu_unit.flags & UNIT_1D45) { /* SN45 */
1217 for (i = 0; i < RN45_SIZE; i++) rname[i] = i;
1218 }
1219 else reason = stop_inst;
1220 break;
1221
1222 case 074: /* extend mode */
1223 extm = (IR >> 11) & 1; /* set from IR<6> */
1224 break;
1225
1226 default: /* undefined */
1227 reason = stop_inst;
1228 break;
1229 } /* end switch dev */
1230
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 */
1235 break;
1236
1237 default: /* undefined */
1238 if (rm && !sbs_act) /* restrict, ~brk? */
1239 reason = set_rmv (RTB_ILL); /* violation */
1240 else reason = STOP_RSRV; /* halt */
1241 break;
1242 } /* end switch op */
1243
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 */
1248 }
1249 } /* end while */
1250 pcq_r->qptr = pcq_p; /* update pc q ptr */
1251 return reason;
1252 }
1253
1254 /* Effective address routine for standard memory reference instructions */
1255
1256 t_stat Ea (int32 IR)
1257 {
1258 int32 i;
1259 t_stat r;
1260
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 */
1266 }
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;
1272 }
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? */
1277 return SCPE_OK;
1278 }
1279
1280 /* Effective address routine for character instructions */
1281
1282 t_stat Ea_ch (int32 IR, int32 *bn)
1283 {
1284 int32 i;
1285 t_stat r;
1286
1287 MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */
1288 if (extm) { /* extend? */
1289 if (r = Read ()) return r; /* read; err? */
1290 }
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);
1296 }
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 */
1304 }
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? */
1309 return SCPE_OK;
1310 }
1311
1312 /* Increment byte pointer, allowing for ring mode */
1313
1314 int32 inc_bp (int32 bp)
1315 {
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);
1321 }
1322 return bp;
1323 }
1324
1325 /* Read and write memory */
1326
1327 t_stat Read (void)
1328 {
1329 if (rm && !sbs_act) { /* restrict check? */
1330 int32 bnk = MA_GETBNK (MA); /* get bank */
1331 if ((rmask << bnk) & SIGN) return set_rmv (0);
1332 }
1333 MB = M[MA];
1334 if (hst_p) hst[hst_p].opnd = MB; /* history enabled? */
1335 return SCPE_OK;
1336 }
1337
1338 t_stat Write (void)
1339 {
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);
1344 }
1345 if (MEM_ADDR_OK (MA)) M[MA] = MB;
1346 return SCPE_OK;
1347 }
1348
1349 /* Restrict mode trap */
1350
1351 t_stat set_rmv (int32 code)
1352 {
1353 rtb = code | (MB & RTB_MB_MASK);
1354 return ERR_RMV;
1355 }
1356
1357 /* Evaluate SBS system */
1358
1359 int32 sbs_eval (void)
1360 {
1361 int32 hi;
1362
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? */
1367 }
1368 return 0;
1369 }
1370
1371 /* Find first one in a 16b field */
1372
1373 int32 sbs_ffo (int32 mask)
1374 {
1375 if (mask & 0177400)
1376 return ffo_map[(mask >> 8) & 0377];
1377 else return (ffo_map[mask & 0377] + 8);
1378 }
1379
1380 /* Device request interrupt */
1381
1382 t_stat dev_req_int (int32 lvl)
1383 {
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 */
1388 }
1389 else sbs |= SB_RQ; /* PI request */
1390 return SCPE_OK;
1391 }
1392
1393 /* Device set/show SBS level */
1394
1395 t_stat dev_set_sbs (UNIT *uptr, int32 val, char *cptr, void *desc)
1396 {
1397 int32 *lvl = (int32 *) desc;
1398 int32 newlvl;
1399 t_stat r;
1400
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;
1404 *lvl = newlvl;
1405 return SCPE_OK;
1406 }
1407
1408 t_stat dev_show_sbs (FILE *st, UNIT *uptr, int32 val, void *desc)
1409 {
1410 int32 *lvl = (int32 *) desc;
1411
1412 if (lvl == NULL) return SCPE_IERR;
1413 fprintf (st, "SBS level %d", *lvl);
1414 return SCPE_OK;
1415 }
1416
1417 /* Reset routine */
1418
1419 t_stat cpu_reset (DEVICE *dptr)
1420 {
1421 int32 i;
1422
1423 sbs = sbs_init;
1424 extm = extm_init;
1425 ioh = 0;
1426 ios = 0;
1427 cpls = 0;
1428 sbs_act = 0;
1429 sbs_req = 0;
1430 sbs_enb = 0;
1431 OV = 0;
1432 PF = 0;
1433 MA = 0;
1434 MB = 0;
1435 rm = 0;
1436 rtb = 0;
1437 rmask = 0;
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');
1443 return SCPE_OK;
1444 }
1445
1446 /* Memory examine */
1447
1448 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
1449 {
1450 if (addr >= MEMSIZE) return SCPE_NXM;
1451 if (vptr != NULL) *vptr = M[addr] & DMASK;
1452 return SCPE_OK;
1453 }
1454
1455 /* Memory deposit */
1456
1457 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
1458 {
1459 if (addr >= MEMSIZE) return SCPE_NXM;
1460 M[addr] = val & DMASK;
1461 return SCPE_OK;
1462 }
1463
1464 /* Change memory size */
1465
1466 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
1467 {
1468 int32 mc = 0;
1469 uint32 i;
1470
1471 if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
1472 return SCPE_ARG;
1473 for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
1474 if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
1475 return SCPE_OK;
1476 MEMSIZE = val;
1477 for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
1478 return SCPE_OK;
1479 }
1480
1481 /* Set PDP-1D */
1482
1483 t_stat cpu_set_1d (UNIT *uptr, int32 val, char *cptr, void *desc)
1484 {
1485 uptr->flags |= UNIT_SBS|UNIT_MDV;
1486 return SCPE_OK;
1487 }
1488
1489 /* Set history */
1490
1491 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
1492 {
1493 int32 i, lnt;
1494 t_stat r;
1495
1496 if (cptr == NULL) {
1497 for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
1498 hst_p = 0;
1499 return SCPE_OK;
1500 }
1501 lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
1502 if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
1503 hst_p = 0;
1504 if (hst_lnt) {
1505 free (hst);
1506 hst_lnt = 0;
1507 hst = NULL;
1508 }
1509 if (lnt) {
1510 hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));
1511 if (hst == NULL) return SCPE_MEM;
1512 hst_lnt = lnt;
1513 }
1514 return SCPE_OK;
1515 }
1516
1517 /* Show history */
1518
1519 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
1520 {
1521 int32 ov, pf, op, k, di, lnt;
1522 char *cptr = (char *) desc;
1523 t_stat r;
1524 t_value sim_eval;
1525 InstHistory *h;
1526 extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
1527 UNIT *uptr, int32 sw);
1528
1529 if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
1530 if (cptr) {
1531 lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
1532 if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG;
1533 }
1534 else lnt = hst_lnt;
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, " ");
1549 sim_eval = h->ir;
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 */
1556 } /* end for */
1557 return SCPE_OK;
1558 }