First Commit of my working state
[simh.git] / PDP1 / pdp1_cpu.c
CommitLineData
196ba1fc
PH
1/* pdp1_cpu.c: PDP-1 CPU simulator\r
2\r
3 Copyright (c) 1993-2007, Robert M. Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 cpu PDP-1 central processor\r
27\r
28 30-May-07 RMS Fixed typo in SBS clear (from Norm Lastovica)\r
29 28-Dec-06 RMS Added 16-channel SBS support, PDP-1D support\r
30 28-Jun-06 RMS Fixed bugs in MUS and DIV\r
31 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)\r
32 16-Aug-05 RMS Fixed C++ declaration and cast problems\r
33 09-Nov-04 RMS Added instruction history\r
34 07-Sep-03 RMS Added additional explanation on I/O simulation\r
35 01-Sep-03 RMS Added address switches for hardware readin\r
36 23-Jul-03 RMS Revised to detect I/O wait hang\r
37 05-Dec-02 RMS Added drum support\r
38 06-Oct-02 RMS Revised for V2.10\r
39 20-Aug-02 RMS Added DECtape support\r
40 30-Dec-01 RMS Added old PC queue\r
41 07-Dec-01 RMS Revised to use breakpoint package\r
42 30-Nov-01 RMS Added extended SET/SHOW support\r
43 16-Dec-00 RMS Fixed bug in XCT address calculation\r
44 14-Apr-99 RMS Changed t_addr to unsigned\r
45\r
46 The PDP-1 was Digital's first computer. Although Digital built four\r
47 other 18b computers, the later systems (the PDP-4, PDP-7, PDP-9, and\r
48 PDP-15) were similar to each other and quite different from the PDP-1.\r
49 Accordingly, the PDP-1 requires a distinct simulator.\r
50\r
51 The register state for the PDP-1 is:\r
52\r
53 AC<0:17> accumulator\r
54 IO<0:17> IO register\r
55 OV overflow flag\r
56 PC<0:15> program counter\r
57 IOSTA I/O status register\r
58 SBS<0:2> sequence break flip flops\r
59 IOH I/O halt flip flop\r
60 IOS I/O synchronizer (completion) flip flop\r
61 EXTM extend mode\r
62 PF<1:6> program flags\r
63 SS<1:6> sense switches\r
64 TW<0:17> test word (switch register)\r
65\r
66 The 16-channel sequence break system adds additional state:\r
67\r
68 sbs_req<0:15> interrupt requests\r
69 sbs_enb<0:15> enabled levels\r
70 sbs_act<0:15> active levels\r
71\r
72 The PDP-1D adds additional state:\r
73\r
74 L link (SN 45 only)\r
75 RNG ring mode\r
76 RM restrict mode\r
77 RMASK restrict mode mask\r
78 RNAME rename table (SN 45 only)\r
79 RTB restict mode trap buffer (SN 45 only)\r
80\r
81 Questions:\r
82\r
83 cks: which bits are line printer print done and space done?\r
84 cks: is there a bit for sequence break enabled (yes, according\r
85 to the 1963 Handbook)\r
86 sbs: do sequence breaks accumulate while the system is disabled\r
87 (yes, according to the Maintenance Manual)\r
88\r
89 The PDP-1 has seven instruction formats: memory reference, skips,\r
90 shifts, load immediate, I/O transfer, operate, and (PDP-1D) special.\r
91 The memory reference format is:\r
92\r
93 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
94 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
95 | op |in| address | memory reference\r
96 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
97\r
98 <0:4> <5> mnemonic action\r
99\r
100 00\r
101 02 AND AC = AC & M[MA]\r
102 04 IOR AC = AC | M[MA]\r
103 06 XOR AC = AC ^ M[MA]\r
104 10 XCT M[MA] is executed as an instruction\r
105 12 LCH load character (PDP-1D)\r
106 14 DCH store character (PDP-1D)\r
107 16 0 CAL M[100] = AC, AC = PC, PC = 101\r
108 16 1 JDA M[MA] = AC, AC = PC, PC = MA + 1\r
109 20 LAC AC = M[MA]\r
110 22 LIO IO = M[MA]\r
111 24 DAC M[MA] = AC\r
112 26 DAP M[MA]<6:17> = AC<6:17>\r
113 30 DIP M[MA]<0:5> = AC<0:5>\r
114 32 DIO M[MA] = IO\r
115 34 DZM M[MA] = 0\r
116 36 TAD L'AC = AC + M[MA] + L\r
117 40 ADD AC = AC + M[MA]\r
118 42 SUB AC = AC - M[MA]\r
119 44 IDX AC = M[MA] = M[MA] + 1\r
120 46 ISP AC = M[MA] = M[MA] + 1, skip if AC >= 0\r
121 50 SAD skip if AC != M[MA]\r
122 52 SAS skip if AC == M[MA]\r
123 54 MUL AC'IO = AC * M[MA]\r
124 56 DIV AC, IO = AC'IO / M[MA]\r
125 60 JMP PC = MA\r
126 62 JSP AC = PC, PC = MA\r
127\r
128 Memory reference instructions can access an address space of 64K words.\r
129 The address space is divided into sixteen 4K word fields. An\r
130 instruction can directly address, via its 12b address, the entire\r
131 current field. If extend mode is off, indirect addresses access\r
132 the current field, and indirect addressing is multi-level; if off,\r
133 they can access all 64K, and indirect addressing is single level.\r
134\r
135 The skip format is:\r
136\r
137 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
138 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
139 | 1 1 0 1 0| | | | | | | | | | | | | | skip\r
140 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
141 | | | | | | | \______/ \______/\r
142 | | | | | | | | |\r
143 | | | | | | | | +---- program flags\r
144 | | | | | | | +------------- sense switches\r
145 | | | | | | +------------------- AC == 0\r
146 | | | | | +---------------------- AC >= 0\r
147 | | | | +------------------------- AC < 0\r
148 | | | +---------------------------- OV == 0\r
149 | | +------------------------------- IO >= 0\r
150 | +---------------------------------- IO != 0 (PDP-1D)\r
151 +------------------------------------- invert skip\r
152\r
153 The shift format is:\r
154\r
155 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
156 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
157 | 1 1 0 1 1| subopcode | encoded count | shift\r
158 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
159\r
160 The load immediate format is:\r
161\r
162 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
163 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
164 | 1 1 1 0 0| S| immediate | LAW\r
165 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
166\r
167 <0:4> mnemonic action\r
168\r
169 70 LAW if S = 0, AC = IR<6:17>\r
170 else AC = ~IR<6:17>\r
171\r
172 The I/O transfer format is:\r
173\r
174 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
175 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
176 | 1 1 1 0 1| W| C| subopcode | device | I/O transfer\r
177 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
178\r
179 The IO transfer instruction sends the the specified subopcode to\r
180 specified I/O device. The I/O device may take data from the IO or\r
181 return data to the IO, initiate or cancel operations, etc. The\r
182 W bit specifies whether the CPU waits for completion, the C bit\r
183 whether a completion pulse will be returned from the device.\r
184\r
185 The special operate format (PDP-1D) is:\r
186\r
187 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
188 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
189 | 1 1 1 1 0| | | | | | | | | | | | | | special\r
190 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
191 | | | | | | | | | | |\r
192 | | | | | | | | | | +------- CML (3)\r
193 | | | | | | | | | +---------- CLL (1)\r
194 | | | | | | | | +------------- SZL (1)\r
195 | | | | | | | +---------------- SCF (1)\r
196 | | | | | | +------------------- SCI (1)\r
197 | | | | | +---------------------- SCM (2)\r
198 | | | | +------------------------- IDA (3)\r
199 | | | +---------------------------- IDC (4)\r
200 | | +------------------------------- IFI (2)\r
201 | +---------------------------------- IIF (2)\r
202 +------------------------------------- reverse skip\r
203\r
204 The special operate instruction can be microprogrammed.\r
205\r
206 The standard operate format is:\r
207\r
208 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
209 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
210 | 1 1 1 1 1| | | | | | | | | | | | | | operate\r
211 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
212 | | | | | | | | | | \______/\r
213 | | | | | | | | | | |\r
214 | | | | | | | | | | +---- PF select\r
215 | | | | | | | | | +---------- clear/set PF\r
216 | | | | | | | | +------------- LIA (PDP-1D)\r
217 | | | | | | | +---------------- LAI (PDP-1D)\r
218 | | | | | | +------------------- or PC\r
219 | | | | | +---------------------- CLA\r
220 | | | | +------------------------- halt\r
221 | | | +---------------------------- CMA\r
222 | | +------------------------------- or TW\r
223 | +---------------------------------- CLI\r
224 +------------------------------------- CMI (PDP-1D)\r
225\r
226 The standard operate instruction can be microprogrammed.\r
227\r
228 This routine is the instruction decode routine for the PDP-1.\r
229 It is called from the simulator control program to execute\r
230 instructions in simulated memory, starting at the simulated PC.\r
231 It runs until 'reason' is set non-zero.\r
232\r
233 General notes:\r
234\r
235 1. Reasons to stop. The simulator can be stopped by:\r
236\r
237 HALT instruction\r
238 breakpoint encountered\r
239 unimplemented instruction and STOP_INST flag set\r
240 XCT loop\r
241 indirect address loop\r
242 infinite wait state\r
243 I/O error in I/O simulator\r
244\r
245 2. Interrupts. With a single channel sequence break system, the\r
246 PDP-1 has a single break request (flop b2, here sbs<SB_V_RQ>).\r
247 If sequence breaks are enabled (flop sbm, here sbs<SB_V_ON>),\r
248 and one is not already in progress (flop b4, here sbs<SB_V_IP>),\r
249 a sequence break occurs. With a 16-channel sequence break\r
250 system, the PDP-1 has 16 request flops (sbs_req), 16 enable\r
251 flops (sbs_enb), and 16 active flops (sbs_act). It also has\r
252 16 synchronizer flops, which are not needed in simulation.\r
253\r
254 3. Arithmetic. The PDP-1 is a 1's complement system. In 1's\r
255 complement arithmetic, a negative number is represented by the\r
256 complement (XOR 0777777) of its absolute value. Addition of 1's\r
257 complement numbers requires propagating the carry out of the high\r
258 order bit back to the low order bit.\r
259\r
260 4. Adding I/O devices. Three modules must be modified:\r
261\r
262 pdp1_defs.h add interrupt request definition\r
263 pdp1_cpu.c add IOT dispatch code\r
264 pdp1_sys.c add sim_devices table entry\r
265*/\r
266\r
267#include "pdp1_defs.h"\r
268\r
269#define PCQ_SIZE 64 /* must be 2**n */\r
270#define PCQ_MASK (PCQ_SIZE - 1)\r
271#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC\r
272#define UNIT_V_MDV (UNIT_V_UF + 0) /* mul/div */\r
273#define UNIT_V_SBS (UNIT_V_UF + 1)\r
274#define UNIT_V_1D (UNIT_V_UF + 2)\r
275#define UNIT_V_1D45 (UNIT_V_UF + 3)\r
276#define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy mask */\r
277#define UNIT_MDV (1 << UNIT_V_MDV)\r
278#define UNIT_SBS (1 << UNIT_V_SBS)\r
279#define UNIT_1D (1 << UNIT_V_1D)\r
280#define UNIT_1D45 (1 << UNIT_V_1D45)\r
281#define UNIT_MSIZE (1 << UNIT_V_MSIZE)\r
282\r
283#define HIST_PC 0x40000000\r
284#define HIST_V_SHF 18\r
285#define HIST_MIN 64\r
286#define HIST_MAX 65536\r
287\r
288#define MA_GETBNK(x) ((cpu_unit.flags & UNIT_1D45)? \\r
289 (((x) >> RM45_V_BNK) & RM45_M_BNK): \\r
290 (((x) >> RM48_V_BNK) & RM48_M_BNK))\r
291\r
292typedef struct {\r
293 uint32 pc;\r
294 uint32 ir;\r
295 uint32 ovac;\r
296 uint32 pfio;\r
297 uint32 ea;\r
298 uint32 opnd;\r
299 } InstHistory;\r
300\r
301int32 M[MAXMEMSIZE] = { 0 }; /* memory */\r
302int32 AC = 0; /* AC */\r
303int32 IO = 0; /* IO */\r
304int32 PC = 0; /* PC */\r
305int32 MA = 0; /* MA */\r
306int32 MB = 0; /* MB */\r
307int32 OV = 0; /* overflow */\r
308int32 SS = 0; /* sense switches */\r
309int32 PF = 0; /* program flags */\r
310int32 TA = 0; /* address switches */\r
311int32 TW = 0; /* test word */\r
312int32 iosta = 0; /* status reg */\r
313int32 sbs = 0; /* sequence break */\r
314int32 sbs_init = 0; /* seq break start */\r
315int32 ioh = 0; /* I/O halt */\r
316int32 ios = 0; /* I/O syncronizer */\r
317int32 cpls = 0; /* pending compl */\r
318int32 sbs_req = 0; /* sbs requests */\r
319int32 sbs_enb = 0; /* sbs enabled */\r
320int32 sbs_act = 0; /* sbs active */\r
321int32 extm = 0; /* ext mem mode */\r
322int32 rm = 0; /* restrict mode */\r
323int32 rmask = 0; /* restrict mask */\r
324int32 rname[RN45_SIZE]; /* rename table */\r
325int32 rtb = 0; /* restr trap buf */\r
326int32 extm_init = 0; /* ext mem startup */\r
327int32 stop_inst = 0; /* stop rsrv inst */\r
328int32 xct_max = 16; /* XCT limit */\r
329int32 ind_max = 16; /* ind limit */\r
330uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r
331int32 pcq_p = 0; /* PC queue ptr */\r
332REG *pcq_r = NULL; /* PC queue reg ptr */\r
333int32 hst_p = 0; /* history pointer */\r
334int32 hst_lnt = 0; /* history length */\r
335InstHistory *hst = NULL; /* inst history */\r
336\r
337extern UNIT *sim_clock_queue;\r
338extern int32 sim_int_char;\r
339extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r
340\r
341t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
342t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
343t_stat cpu_reset (DEVICE *dptr);\r
344t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r
345t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);\r
346t_stat cpu_set_1d (UNIT *uptr, int32 val, char *cptr, void *desc);\r
347t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);\r
348t_stat Ea (int32 IR);\r
349t_stat Ea_ch (int32 IR, int32 *byte_num);\r
350int32 inc_bp (int32 bp);\r
351t_stat set_rmv (int32 code);\r
352int32 sbs_eval (void);\r
353int32 sbs_ffo (int32 mask);\r
354t_stat Read (void);\r
355t_stat Write (void);\r
356\r
357extern int32 ptr (int32 inst, int32 dev, int32 dat);\r
358extern int32 ptp (int32 inst, int32 dev, int32 dat);\r
359extern int32 tti (int32 inst, int32 dev, int32 dat);\r
360extern int32 tto (int32 inst, int32 dev, int32 dat);\r
361extern int32 lpt (int32 inst, int32 dev, int32 dat);\r
362extern int32 dt (int32 inst, int32 dev, int32 dat);\r
363extern int32 drm (int32 inst, int32 dev, int32 dat);\r
364extern int32 clk (int32 inst, int32 dev, int32 dat);\r
365extern int32 dcs (int32 inst, int32 dev, int32 dat);\r
366\r
367const int32 sc_map[512] = {\r
368 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */\r
369 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00001xxxx */\r
370 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00010xxxx */\r
371 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 00011xxxx */\r
372 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00100xxxx */\r
373 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 00101xxxx */\r
374 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 00110xxxx */\r
375 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 00111xxxx */\r
376 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 01000xxxx */\r
377 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 01001xxxx */\r
378 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 01010xxxx */\r
379 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 01011xxxx */\r
380 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 01100xxxx */\r
381 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 01101xxxx */\r
382 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 01110xxxx */\r
383 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 01111xxxx */\r
384 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 10000xxxx */\r
385 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 10001xxxx */\r
386 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 10010xxxx */\r
387 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 10011xxxx */\r
388 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 10100xxxx */\r
389 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 10101xxxx */\r
390 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 10110xxxx */\r
391 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11011xxxx */\r
392 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 11000xxxx */\r
393 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 11001xxxx */\r
394 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 11010xxxx */\r
395 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11011xxxx */\r
396 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 11100xxxx */\r
397 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11101xxxx */\r
398 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11110xxxx */\r
399 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9 /* 11111xxxx */\r
400 };\r
401\r
402const int32 ffo_map[256] = {\r
403 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,\r
404 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\r
405 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\r
406 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\r
407 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
408 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
409 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
410 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
411 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
412 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
415 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
416 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
417 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
419 };\r
420\r
421const int32 byt_shf[4] = { 0, 0, 6, 12 };\r
422\r
423/* CPU data structures\r
424\r
425 cpu_dev CPU device descriptor\r
426 cpu_unit CPU unit\r
427 cpu_reg CPU register list\r
428 cpu_mod CPU modifier list\r
429*/\r
430\r
431UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };\r
432\r
433REG cpu_reg[] = {\r
434 { ORDATA (PC, PC, ASIZE) },\r
435 { ORDATA (AC, AC, 18) },\r
436 { ORDATA (IO, IO, 18) },\r
437 { ORDATA (MA, MA, 16) },\r
438 { ORDATA (MB, MB, 18) },\r
439 { FLDATA (OV, OV, 0) },\r
440 { ORDATA (PF, PF, 8) },\r
441 { ORDATA (SS, SS, 6) },\r
442 { ORDATA (TA, TA, ASIZE) },\r
443 { ORDATA (TW, TW, 18) },\r
444 { FLDATA (EXTM, extm, 0) },\r
445 { FLDATA (RNGM, PF, PF_V_RNG) },\r
446 { FLDATA (L, PF, PF_V_L) },\r
447 { FLDATA (RM, rm, 0) },\r
448 { ORDATA (RMASK, rmask, 18) },\r
449 { ORDATA (RTB, rtb, 18) },\r
450 { BRDATA (RNAME, rname, 8, 2, RN45_SIZE) },\r
451 { FLDATA (SBON, sbs, SB_V_ON) },\r
452 { FLDATA (SBRQ, sbs, SB_V_RQ) },\r
453 { FLDATA (SBIP, sbs, SB_V_IP) },\r
454 { ORDATA (SBSREQ, sbs_req, 16) },\r
455 { ORDATA (SBSENB, sbs_enb, 16) },\r
456 { ORDATA (SBSACT, sbs_act, 16) },\r
457 { ORDATA (IOSTA, iosta, 18), REG_RO },\r
458 { ORDATA (CPLS, cpls, 6) },\r
459 { FLDATA (IOH, ioh, 0) },\r
460 { FLDATA (IOS, ios, 0) },\r
461 { BRDATA (PCQ, pcq, 8, ASIZE, PCQ_SIZE), REG_RO+REG_CIRC },\r
462 { ORDATA (PCQP, pcq_p, 6), REG_HRO },\r
463 { FLDATA (STOP_INST, stop_inst, 0) },\r
464 { FLDATA (SBS_INIT, sbs_init, SB_V_ON) },\r
465 { FLDATA (EXTM_INIT, extm_init, 0) },\r
466 { DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ },\r
467 { DRDATA (IND_MAX, ind_max, 8), PV_LEFT + REG_NZ },\r
468 { ORDATA (WRU, sim_int_char, 8) },\r
469 { NULL }\r
470 };\r
471\r
472MTAB cpu_mod[] = {\r
473 { UNIT_1D+UNIT_1D45, 0, "standard CPU", "PDP1C" },\r
474 { UNIT_1D+UNIT_1D45, UNIT_1D, "PDP-1D #48", "PDP1D48", &cpu_set_1d },\r
475 { UNIT_1D+UNIT_1D45, UNIT_1D+UNIT_1D45, "PDP1D #45", "PDP1D45", &cpu_set_1d },\r
476 { UNIT_MDV, UNIT_MDV, "multiply/divide", "MDV", NULL },\r
477 { UNIT_MDV, 0, "no multiply/divide", "NOMDV", NULL },\r
478 { UNIT_SBS, UNIT_SBS, "SBS", "SBS", NULL },\r
479 { UNIT_SBS, 0, "no SBS", "NOSBS", NULL },\r
480 { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },\r
481 { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },\r
482 { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },\r
483 { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },\r
484 { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },\r
485 { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },\r
486 { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },\r
487 { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },\r
488 { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size },\r
489 { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },\r
490 { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",\r
491 &cpu_set_hist, &cpu_show_hist },\r
492 { 0 }\r
493 };\r
494\r
495DEVICE cpu_dev = {\r
496 "CPU", &cpu_unit, cpu_reg, cpu_mod,\r
497 1, 8, ASIZE, 1, 8, 18,\r
498 &cpu_ex, &cpu_dep, &cpu_reset,\r
499 NULL, NULL, NULL,\r
500 NULL, 0\r
501 };\r
502\r
503t_stat sim_instr (void)\r
504{\r
505extern int32 sim_interval;\r
506int32 IR, op, i, t, xct_count;\r
507int32 sign, signd, v, sbs_lvl, byno;\r
508int32 dev, pulse, io_data, sc, skip;\r
509t_stat reason;\r
510static int32 fs_test[8] = {\r
511 0, PF_SS_1, PF_SS_2, PF_SS_3,\r
512 PF_SS_4, PF_SS_5, PF_SS_6, PF_SS_ALL\r
513 };\r
514\r
515#define EPC_WORD ((OV << 17) | (extm << 16) | PC)\r
516#define INCR_ADDR(x) (((x) & EPCMASK) | (((x) + 1) & DAMASK))\r
517#define DECR_ADDR(x) (((x) & EPCMASK) | (((x) - 1) & DAMASK))\r
518#define ABS(x) ((x) ^ (((x) & SIGN)? DMASK: 0))\r
519\r
520if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */\r
521 cpu_unit.flags |= UNIT_SBS|UNIT_MDV; /* 16-chan SBS, mdv */\r
522 if (!(cpu_unit.flags & UNIT_1D45)) { /* SN 48? */\r
523 PF &= ~PF_L; /* no link */\r
524 rtb = 0; /* no RTB */\r
525 for (i = 0; i < RN45_SIZE; i++) rname[i] = i; /* no rename */\r
526 }\r
527 }\r
528else { /* standard PDP-1 */\r
529 PF &= ~(PF_L|PF_RNG); /* no link, ring */\r
530 rm = 0; /* no restrict mode */\r
531 rtb = 0; /* no RTB */\r
532 for (i = 0; i < RN45_SIZE; i++) rname[i] = i; /* no rename */\r
533 }\r
534if (cpu_unit.flags & UNIT_SBS) { /* 16-chan SBS? */\r
535 sbs = sbs & SB_ON; /* yes, only SB ON */\r
536 sbs_lvl = sbs_eval (); /* eval SBS system */\r
537 }\r
538else sbs_lvl = sbs_req = sbs_enb = sbs_act = 0; /* no, clr SBS sys */\r
539\r
540/* Main instruction fetch/decode loop: check events and interrupts */\r
541\r
542reason = 0;\r
543while (reason == 0) { /* loop until halted */\r
544\r
545 if (sim_interval <= 0) { /* check clock queue */\r
546 if (reason = sim_process_event ()) break;\r
547 sbs_lvl = sbs_eval (); /* eval sbs system */\r
548 }\r
549\r
550 if ((cpu_unit.flags & UNIT_SBS)? /* test interrupt */\r
551 ((sbs & SB_ON) && sbs_lvl): /* 16-chan SBS? */\r
552 (sbs == (SB_ON | SB_RQ))) { /* 1-chan SBS? */\r
553 if (cpu_unit.flags & UNIT_SBS) { /* 16-chan intr */\r
554 int32 lvl = sbs_lvl - 1; /* get level */\r
555 MA = lvl << 2; /* status block */\r
556 sbs_req &= ~SBS_MASK (lvl); /* clr lvl request */\r
557 sbs_act |= SBS_MASK (lvl); /* set lvl active */\r
558 sbs_lvl = sbs_eval (); /* re-eval SBS */\r
559 }\r
560 else { /* 1-chan intr */\r
561 MA = 0; /* always level 0 */\r
562 sbs = SB_ON | SB_IP; /* set in prog flag */\r
563 }\r
564 PCQ_ENTRY; /* save old PC */\r
565 MB = AC; /* save AC */\r
566 Write ();\r
567 MA = MA + 1;\r
568 MB = EPC_WORD; /* save OV'EXT'PC */\r
569 Write ();\r
570 MA = MA + 1;\r
571 MB = IO; /* save IO */\r
572 Write ();\r
573 PC = MA + 1; /* PC = block + 3 */\r
574 extm = 0; /* extend off */\r
575 OV = 0; /* clear overflow */\r
576 }\r
577\r
578 if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */\r
579 reason = STOP_IBKPT; /* stop simulation */\r
580 break;\r
581 }\r
582\r
583/* Fetch, decode instruction */\r
584\r
585 MA = PC;\r
586 if (Read ()) break; /* fetch inst */\r
587 IR = MB; /* save in IR */\r
588 PC = INCR_ADDR (PC); /* increment PC */\r
589 xct_count = 0; /* track XCT's */\r
590 sim_interval = sim_interval - 1;\r
591 if (hst_lnt) { /* history enabled? */\r
592 hst_p = (hst_p + 1); /* next entry */\r
593 if (hst_p >= hst_lnt) hst_p = 0;\r
594 hst[hst_p].pc = MA | HIST_PC; /* save state */\r
595 hst[hst_p].ir = IR;\r
596 hst[hst_p].ovac = (OV << HIST_V_SHF) | AC;\r
597 hst[hst_p].pfio = (PF << HIST_V_SHF) | IO;\r
598 }\r
599\r
600 xct_instr: /* label for XCT */\r
601 op = ((IR >> 13) & 037); /* get opcode */\r
602 switch (op) { /* decode IR<0:4> */\r
603\r
604/* Logical, load, store instructions */\r
605\r
606 case 001: /* AND */\r
607 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
608 if (reason = Read ()) break; /* MB <- data */\r
609 AC = AC & MB;\r
610 break;\r
611\r
612 case 002: /* IOR */\r
613 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
614 if (reason = Read ()) break; /* MB <- data */\r
615 AC = AC | MB;\r
616 break;\r
617\r
618 case 003: /* XOR */\r
619 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
620 if (reason = Read ()) break; /* MB <- data */\r
621 AC = AC ^ MB;\r
622 break;\r
623\r
624 case 004: /* XCT */\r
625 if (xct_count >= xct_max) { /* too many XCT's? */\r
626 reason = STOP_XCT;\r
627 break;\r
628 }\r
629 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
630 if (reason = Read ()) break; /* MB <- data */\r
631 xct_count = xct_count + 1; /* count XCT's */\r
632 IR = MB; /* get instruction */\r
633 goto xct_instr; /* go execute */\r
634\r
635 case 005: /* LCH */\r
636 if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */\r
637 if (reason = Ea_ch (IR, &byno)) break; /* MA <- eff addr */\r
638 if (reason = Read ()) break; /* MB <- data */\r
639 AC = (MB << byt_shf[byno]) & 0770000; /* extract byte */\r
640 }\r
641 else reason = stop_inst; /* no, illegal */\r
642 break;\r
643\r
644 case 006: /* DCH */\r
645 if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */\r
646 if (reason = Ea_ch (IR, &byno)) break; /* MA <- eff addr */\r
647 if (reason = Read ()) break; /* MB <- data */\r
648 MB = (MB & ~(0770000 >> byt_shf[byno])) | /* insert byte */\r
649 ((AC & 0770000) >> byt_shf[byno]);\r
650 Write (); /* rewrite */\r
651 AC = ((AC << 6) | (AC >> 12)) & DMASK; /* rot AC left 6 */\r
652 }\r
653 else reason = stop_inst; /* no, illegal */\r
654 break;\r
655\r
656 case 007: /* CAL, JDA */\r
657 MA = (PC & EPCMASK) | ((IR & IA)? (IR & DAMASK): 0100);\r
658 if (hst_p) hst[hst_p].ea = MA; /* history enabled? */\r
659 PCQ_ENTRY;\r
660 MB = AC; /* save AC */\r
661 AC = EPC_WORD;\r
662 PC = INCR_ADDR (MA);\r
663 reason = Write ();\r
664 break;\r
665\r
666 case 010: /* LAC */\r
667 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
668 if (reason = Read ()) break; /* MB <- data */\r
669 AC = MB;\r
670 break;\r
671\r
672 case 011: /* LIO */\r
673 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
674 if (reason = Read ()) break; /* MB <- data */\r
675 IO = MB;\r
676 break;\r
677\r
678 case 012: /* DAC */\r
679 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
680 MB = AC;\r
681 reason = Write ();\r
682 break;\r
683\r
684 case 013: /* DAP */\r
685 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
686 if (reason = Read ()) break; /* MB <- data */\r
687 MB = (AC & DAMASK) | (MB & ~DAMASK);\r
688 reason = Write ();\r
689 break;\r
690\r
691 case 014: /* DIP */\r
692 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
693 if (reason = Read ()) break; /* MB <- data */\r
694 MB = (AC & ~DAMASK) | (MB & DAMASK);\r
695 reason = Write ();\r
696 break;\r
697\r
698 case 015: /* DIO */\r
699 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
700 MB = IO;\r
701 reason = Write ();\r
702 break;\r
703\r
704 case 016: /* DZM */\r
705 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
706 MB = 0;\r
707 reason = Write ();\r
708 break;\r
709\r
710/* Add, subtract, control\r
711\r
712 Add is performed in sequential steps, as follows:\r
713 1. add\r
714 2. end around carry propagate\r
715 3. overflow check\r
716 4. -0 cleanup\r
717\r
718 Subtract is performed in sequential steps, as follows:\r
719 1. complement AC\r
720 2. add\r
721 3. end around carry propagate\r
722 4. overflow check\r
723 5. complement AC\r
724 Because no -0 check is done, (-0) - (+0) yields a result of -0 */\r
725\r
726 case 017: /* TAD */\r
727 if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */\r
728 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
729 if (reason = Read ()) break; /* MB <- data */\r
730 AC = AC + MB + ((PF & PF_L)? 1: 0); /* AC + opnd + L */\r
731 if (AC > DMASK) PF = PF | PF_L; /* carry? set L */\r
732 else PF = PF & ~PF_L; /* no, clear L */\r
733 AC = AC & DMASK; /* mask AC */\r
734 }\r
735 else reason = stop_inst; /* no, illegal */\r
736 break;\r
737\r
738 case 020: /* ADD */\r
739 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
740 if (reason = Read ()) break; /* MB <- data */\r
741 t = AC;\r
742 AC = AC + MB;\r
743 if (AC > 0777777) AC = (AC + 1) & DMASK; /* end around carry */\r
744 if (((~t ^ MB) & (t ^ AC)) & SIGN) OV = 1;\r
745 if (AC == DMASK) AC = 0; /* minus 0 cleanup */\r
746 break;\r
747\r
748 case 021: /* SUB */\r
749 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
750 if (reason = Read ()) break; /* MB <- data */\r
751 t = AC ^ DMASK; /* complement AC */\r
752 AC = t + MB; /* -AC + MB */\r
753 if (AC > DMASK) AC = (AC + 1) & DMASK; /* end around carry */\r
754 if (((~t ^ MB) & (t ^ AC)) & SIGN) OV = 1;\r
755 AC = AC ^ DMASK; /* recomplement AC */\r
756 break;\r
757\r
758 case 022: /* IDX */\r
759 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
760 if (reason = Read ()) break; /* MB <- data */\r
761 AC = MB + 1;\r
762 if (AC >= DMASK) AC = (AC + 1) & DMASK;\r
763 MB = AC;\r
764 reason = Write ();\r
765 break;\r
766\r
767 case 023: /* ISP */\r
768 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
769 if (reason = Read ()) break; /* MB <- data */\r
770 AC = MB + 1;\r
771 if (AC >= DMASK) AC = (AC + 1) & DMASK;\r
772 MB = AC;\r
773 if (!(AC & SIGN)) PC = INCR_ADDR (PC);\r
774 reason = Write ();\r
775 break;\r
776\r
777 case 024: /* SAD */\r
778 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
779 if (reason = Read ()) break; /* MB <- data */\r
780 if (AC != MB) PC = INCR_ADDR (PC);\r
781 break;\r
782\r
783 case 025: /* SAS */\r
784 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
785 if (reason = Read ()) break; /* MB <- data */\r
786 if (AC == MB) PC = INCR_ADDR (PC);\r
787 break;\r
788\r
789 case 030: /* JMP */\r
790 if (sbs && /* SBS enabled? */\r
791 ((PC & EPCMASK) == 0) && /* in bank 0? */\r
792 ((IR & (IA|07703)) == (IA|00001)) && /* jmp i 00x1/5? */\r
793 ((cpu_unit.flags & UNIT_SBS) || /* 16-chan SBS or */\r
794 ((IR & 00074) == 0))) { /* jmp i 0001? */\r
795 if (cpu_unit.flags & UNIT_SBS) { /* 16-chan SBS dbk? */\r
796 int32 lvl = (IR >> 2) & SBS_LVL_MASK; /* lvl = MA<14:15> */\r
797 sbs_act &= ~SBS_MASK (lvl); /* clr level active */\r
798 sbs_lvl = sbs_eval (); /* eval SBS system */\r
799 }\r
800 else sbs = sbs & ~SB_IP; /* 1-chan dbk */\r
801 PCQ_ENTRY; /* save old PC */\r
802 MA = IR & DAMASK; /* ind addr */\r
803 Read (); /* eff addr word */\r
804 OV = (MB >> 17) & 1; /* restore OV */\r
805 extm = (MB >> 16) & 1; /* restore ext mode */\r
806 PC = MB & AMASK; /* jmp i 00x1/5 */\r
807 if (hst_p) hst[hst_p].ea = PC; /* history enabled? */\r
808 }\r
809 else { /* normal JMP */\r
810 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
811 PCQ_ENTRY;\r
812 PC = MA;\r
813 }\r
814 break;\r
815\r
816 case 031: /* JSP */\r
817 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
818 AC = EPC_WORD;\r
819 PCQ_ENTRY;\r
820 PC = MA;\r
821 break;\r
822\r
823 case 034: /* LAW */\r
824 AC = (IR & 07777) ^ ((IR & IA)? 0777777: 0);\r
825 break;\r
826\r
827/* Multiply and divide\r
828\r
829 Multiply and divide step and hardware multiply are exact implementations.\r
830 Hardware divide is a 2's complement analog to the actual hardware.\r
831*/ \r
832\r
833 case 026: /* MUL */\r
834 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
835 if (reason = Read ()) break; /* MB <- data */\r
836 if (cpu_unit.flags & UNIT_MDV) { /* hardware? */\r
837 sign = AC ^ MB; /* result sign */\r
838 IO = ABS (AC); /* IO = |AC| */\r
839 v = ABS (MB); /* v = |mpy| */\r
840 for (i = AC = 0; i < 17; i++) {\r
841 if (IO & 1) AC = AC + v;\r
842 IO = (IO >> 1) | ((AC & 1) << 17);\r
843 AC = AC >> 1;\r
844 }\r
845 if ((sign & SIGN) && (AC | IO)) { /* negative, > 0? */\r
846 AC = AC ^ DMASK;\r
847 IO = IO ^ DMASK;\r
848 }\r
849 }\r
850 else { /* multiply step */\r
851 if (IO & 1) AC = AC + MB;\r
852 if (AC > DMASK) AC = (AC + 1) & DMASK;\r
853 IO = (IO >> 1) | ((AC & 1) << 17);\r
854 AC = AC >> 1;\r
855 }\r
856 break;\r
857\r
858 case 027: /* DIV */\r
859 if (reason = Ea (IR)) break; /* MA <- eff addr */\r
860 if (reason = Read ()) break; /* MB <- data */\r
861 if (cpu_unit.flags & UNIT_MDV) { /* hardware */\r
862 sign = AC ^ MB; /* result sign */\r
863 signd = AC; /* remainder sign */\r
864 v = ABS (MB); /* v = |divr| */\r
865 if (ABS (AC) >= v) break; /* overflow? */\r
866 if (AC & SIGN) {\r
867 AC = AC ^ DMASK; /* AC'IO = |AC'IO| */\r
868 IO = IO ^ DMASK;\r
869 }\r
870 for (i = t = 0; i < 18; i++) {\r
871 if (t) AC = (AC + v) & DMASK;\r
872 else AC = (AC - v) & DMASK;\r
873 t = AC >> 17;\r
874 if (i != 17) AC = ((AC << 1) | (IO >> 17)) & DMASK;\r
875 IO = ((IO << 1) | (t ^ 1)) & 0777777;\r
876 }\r
877 if (t) AC = (AC + v) & DMASK; /* fix remainder */\r
878 t = ((signd & SIGN) && AC)? AC ^ DMASK: AC;\r
879 AC = ((sign & SIGN) && IO)? IO ^ DMASK: IO;\r
880 IO = t;\r
881 PC = INCR_ADDR (PC); /* skip */\r
882 }\r
883 else { /* divide step */\r
884 t = AC >> 17;\r
885 AC = ((AC << 1) | (IO >> 17)) & DMASK;\r
886 IO = ((IO << 1) | (t ^ 1)) & DMASK;\r
887 if (IO & 1) AC = AC + (MB ^ DMASK);\r
888 else AC = AC + MB + 1;\r
889 if (AC > DMASK) AC = (AC + 1) & DMASK;\r
890 if (AC == DMASK) AC = 0;\r
891 }\r
892 break;\r
893\r
894/* Skips */\r
895\r
896 case 032: /* skip */\r
897 v = (IR >> 3) & 07; /* sense switches */\r
898 t = IR & 07; /* program flags */\r
899 skip = (((cpu_unit.flags & UNIT_1D) &&\r
900 (IR & 04000) && (IO != 0)) || /* SNI (PDP-1D) */\r
901 ((IR & 02000) && !(IO & SIGN)) || /* SPI */\r
902 ((IR & 01000) && (OV == 0)) || /* SZO */\r
903 ((IR & 00400) && (AC & SIGN)) || /* SMA */\r
904 ((IR & 00200) && !(AC & SIGN)) || /* SPA */\r
905 ((IR & 00100) && (AC == 0)) || /* SZA */\r
906 (v && ((SS & fs_test[v]) == 0)) || /* SZSn */\r
907 (t && ((PF & fs_test[t]) == 0))); /* SZFn */\r
908 if (IR & IA) skip = skip ^ 1; /* invert skip? */\r
909 if (skip) PC = INCR_ADDR (PC);\r
910 if (IR & 01000) OV = 0; /* SOV clears OV */\r
911 break;\r
912\r
913/* Shifts */\r
914\r
915 case 033:\r
916 sc = sc_map[IR & 0777]; /* map shift count */\r
917 switch ((IR >> 9) & 017) { /* case on IR<5:8> */\r
918\r
919 case 001: /* RAL */\r
920 AC = ((AC << sc) | (AC >> (18 - sc))) & DMASK;\r
921 break;\r
922\r
923 case 002: /* RIL */\r
924 IO = ((IO << sc) | (IO >> (18 - sc))) & DMASK;\r
925 break;\r
926\r
927 case 003: /* RCL */\r
928 t = AC;\r
929 AC = ((AC << sc) | (IO >> (18 - sc))) & DMASK;\r
930 IO = ((IO << sc) | (t >> (18 - sc))) & DMASK;\r
931 break;\r
932\r
933 case 005: /* SAL */\r
934 t = (AC & SIGN)? DMASK: 0;\r
935 AC = (AC & SIGN) | ((AC << sc) & 0377777) |\r
936 (t >> (18 - sc));\r
937 break;\r
938\r
939 case 006: /* SIL */\r
940 t = (IO & SIGN)? DMASK: 0;\r
941 IO = (IO & SIGN) | ((IO << sc) & 0377777) |\r
942 (t >> (18 - sc));\r
943 break;\r
944\r
945 case 007: /* SCL */\r
946 t = (AC & SIGN)? DMASK: 0;\r
947 AC = (AC & SIGN) | ((AC << sc) & 0377777) | \r
948 (IO >> (18 - sc));\r
949 IO = ((IO << sc) | (t >> (18 - sc))) & DMASK;\r
950 break;\r
951\r
952 case 011: /* RAR */\r
953 AC = ((AC >> sc) | (AC << (18 - sc))) & DMASK;\r
954 break;\r
955\r
956 case 012: /* RIR */\r
957 IO = ((IO >> sc) | (IO << (18 - sc))) & DMASK;\r
958 break;\r
959\r
960 case 013: /* RCR */\r
961 t = IO;\r
962 IO = ((IO >> sc) | (AC << (18 - sc))) & DMASK;\r
963 AC = ((AC >> sc) | (t << (18 - sc))) & DMASK;\r
964 break;\r
965\r
966 case 015: /* SAR */\r
967 t = (AC & SIGN)? DMASK: 0;\r
968 AC = ((AC >> sc) | (t << (18 - sc))) & DMASK;\r
969 break;\r
970\r
971 case 016: /* SIR */\r
972 t = (IO & SIGN)? DMASK: 0;\r
973 IO = ((IO >> sc) | (t << (18 - sc))) & DMASK;\r
974 break;\r
975\r
976 case 017: /* SCR */\r
977 t = (AC & SIGN)? DMASK: 0;\r
978 IO = ((IO >> sc) | (AC << (18 - sc))) & DMASK;\r
979 AC = ((AC >> sc) | (t << (18 - sc))) & DMASK;\r
980 break;\r
981\r
982 default: /* undefined */\r
983 reason = stop_inst;\r
984 break;\r
985 } /* end switch shf */\r
986 break;\r
987\r
988/* Special operates (PDP-1D) - performed in order shown */\r
989\r
990 case 036: /* special */\r
991 if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */\r
992 if (IR & 000100) IO = 0; /* SCI */\r
993 if (IR & 000040) PF = 0; /* SCF */\r
994 if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */\r
995 if ((IR & 000020) && /* SZL/SNL? */\r
996 (((PF & PF_L) == 0) == ((IR & IA) == 0)))\r
997 PC = INCR_ADDR (PC);\r
998 if (IR & 000010) PF = PF & ~PF_L; /* CLL */\r
999 if (IR & 000200) { /* SCM */\r
1000 AC = (AC ^ DMASK) + ((PF & PF_L)? 1: 0);\r
1001 if (AC > DMASK) PF = PF | PF_L; /* carry? set L */\r
1002 else PF = PF & ~PF_L; /* no, clear L */\r
1003 AC = AC & DMASK; /* mask AC */\r
1004 }\r
1005 }\r
1006 t = IO & PF_VR_ALL;\r
1007 if (IR & 004000) IO = IO | PF; /* IIF */\r
1008 if (IR & 002000) PF = PF | t; /* IFI */\r
1009 if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */\r
1010 if (IR & 000004) PF = PF ^ PF_L; /* CML */\r
1011 if (IR & 000400) /* IDA */\r
1012 AC = (PF & PF_RNG)?\r
1013 (AC & 0777770) | ((AC + 1) & 07):\r
1014 (AC + 1) & DMASK;\r
1015 }\r
1016 else PF = PF & ~PF_L; /* no link */\r
1017 if (IR & 01000) AC = inc_bp (AC); /* IDC */\r
1018 }\r
1019 else reason = stop_inst; /* no, illegal */\r
1020 break;\r
1021\r
1022/* Operates - performed in the order shown */\r
1023\r
1024 case 037: /* operate */\r
1025 if (IR & 004000) IO = 0; /* CLI */\r
1026 if (IR & 000200) AC = 0; /* CLA */\r
1027 if (IR & 002000) AC = AC | TW; /* LAT */\r
1028 if (IR & 000100) AC = AC | EPC_WORD; /* LAP */\r
1029 if (IR & 001000) AC = AC ^ DMASK; /* CMA */\r
1030 if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */\r
1031 if (IR & 010000) IO = IO ^ DMASK; /* CMI */\r
1032 MB = IO;\r
1033 if (IR & 000020) IO = AC; /* LIA */\r
1034 if (IR & 000040) AC = MB; /* LAI */\r
1035 }\r
1036 t = IR & 07; /* flag select */\r
1037 if (IR & 010) PF = PF | fs_test[t]; /* STFn */\r
1038 else PF = PF & ~fs_test[t]; /* CLFn */\r
1039 if (IR & 000400) { /* HLT */\r
1040 if (rm && !sbs_act) /* restrict, ~brk? */\r
1041 reason = set_rmv (RTB_HLT); /* violation */\r
1042 else reason = STOP_HALT; /* no, halt */\r
1043 }\r
1044 break;\r
1045\r
1046/* IOT - The simulator behaves functionally like a real PDP-1 but does not\r
1047 use the same mechanisms or state bits. In particular,\r
1048\r
1049 - If an IOT does not specify IO_WAIT, the IOT will be executed, and the\r
1050 I/O halt flag (IOH) will not be disturbed. On the real PDP-1, IOH is\r
1051 stored in IHS, IOH is cleared, the IOT is executed, and then IOH is\r
1052 restored from IHS. Because IHS is not otherwise used, it is not\r
1053 explicitly simulated.\r
1054 - If an IOT does specify IO_WAIT, then IOH specifies whether an I/O halt\r
1055 (wait) is already in progress.\r
1056 > If already set, I/O wait is in progress. The simulator looks for\r
1057 a completion pulse (IOS). If there is a pulse, IOH is cleared. If\r
1058 not, the IOT is fetched again. In either case, execution of the\r
1059 IOT is skipped.\r
1060 > If not set, I/O wait must start. IOH is set, the PC is backed up,\r
1061 and the IOT is executed.\r
1062 - On a real PDP-1, IOC is the I/O command enable and enables the IOT\r
1063 pulses. In the simulator, the enabling of IOT pulses is done through\r
1064 code flow, and IOC is not explicitly simulated.\r
1065*/\r
1066\r
1067 case 035:\r
1068 if (rm && !sbs_act) { /* restrict, ~brk? */\r
1069 reason = set_rmv (RTB_IOT); /* violation */\r
1070 break;\r
1071 }\r
1072 if (IR & IO_WAIT) { /* wait? */\r
1073 if (ioh) { /* I/O halt? */\r
1074 if (ios) ioh = 0; /* comp pulse? done */\r
1075 else { /* wait more */\r
1076 PC = DECR_ADDR (PC); /* re-execute */\r
1077 if (cpls == 0) { /* pending pulses? */\r
1078 reason = STOP_WAIT; /* no, CPU hangs */\r
1079 break;\r
1080 }\r
1081 sim_interval = 0; /* force event */\r
1082 }\r
1083 break; /* skip iot */\r
1084 }\r
1085 ioh = 1; /* turn on halt */\r
1086 PC = DECR_ADDR (PC); /* re-execute */\r
1087 }\r
1088 dev = IR & 077; /* get dev addr */\r
1089 pulse = (IR >> 6) & 077; /* get pulse data */\r
1090 io_data = IO; /* default data */\r
1091 switch (dev) { /* case on dev */\r
1092\r
1093 case 000: /* I/O wait */\r
1094 break;\r
1095\r
1096 case 001:\r
1097 if (IR & 003700) io_data = dt (IR, dev, IO); /* DECtape */\r
1098 else io_data = ptr (IR, dev, IO); /* paper tape rdr */\r
1099 break;\r
1100\r
1101 case 002: case 030: /* paper tape rdr */\r
1102 io_data = ptr (IR, dev, IO);\r
1103 break;\r
1104\r
1105 case 003: /* typewriter */\r
1106 io_data = tto (IR, dev, IO);\r
1107 break;\r
1108\r
1109 case 004: /* keyboard */\r
1110 io_data = tti (IR, dev, IO);\r
1111 break;\r
1112\r
1113 case 005: case 006: /* paper tape punch */\r
1114 io_data = ptp (IR, dev, IO);\r
1115 break;\r
1116\r
1117 case 010: /* leave ring mode */\r
1118 if (cpu_unit.flags & UNIT_1D) PF = PF & ~PF_RNG;\r
1119 else reason = stop_inst;\r
1120 break;\r
1121\r
1122 case 011: /* enter ring mode */\r
1123 if (cpu_unit.flags & UNIT_1D) PF = PF | PF_RNG;\r
1124 else reason = stop_inst;\r
1125 break;\r
1126\r
1127 case 022: /* data comm sys */\r
1128 io_data = dcs (IR, dev, IO);\r
1129 break;\r
1130\r
1131 case 032: /* clock */\r
1132 io_data = clk (IR, dev, IO);\r
1133 break;\r
1134\r
1135 case 033: /* check status */\r
1136 io_data = iosta | ((sbs & SB_ON)? IOS_SQB: 0);\r
1137 break;\r
1138\r
1139 case 035: /* check trap buf */\r
1140 if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */\r
1141 io_data = rtb;\r
1142 rtb = 0;\r
1143 }\r
1144 else reason = stop_inst;\r
1145 break;\r
1146\r
1147 case 045: /* line printer */\r
1148 io_data = lpt (IR, dev, IO);\r
1149 break;\r
1150\r
1151 case 050: /* deact seq break */\r
1152 if (cpu_unit.flags & UNIT_SBS)\r
1153 sbs_enb &= ~SBS_MASK (pulse & SBS_LVL_MASK);\r
1154 else reason = stop_inst;\r
1155 break;\r
1156\r
1157 case 051: /* act seq break */\r
1158 if (cpu_unit.flags & UNIT_SBS)\r
1159 sbs_enb |= SBS_MASK (pulse & SBS_LVL_MASK);\r
1160 else reason = stop_inst;\r
1161 break;\r
1162\r
1163 case 052: /* start seq break */\r
1164 if (cpu_unit.flags & UNIT_SBS)\r
1165 sbs_req |= SBS_MASK (pulse & SBS_LVL_MASK);\r
1166 else reason = stop_inst;\r
1167 break;\r
1168\r
1169 case 053: /* clear all chan */\r
1170 if (cpu_unit.flags & UNIT_SBS) sbs_enb = 0;\r
1171 else reason = stop_inst;\r
1172 break;\r
1173\r
1174 case 054: /* seq brk off */\r
1175 sbs = sbs & ~SB_ON;\r
1176 break;\r
1177\r
1178 case 055: /* seq brk on */\r
1179 sbs = sbs | SB_ON;\r
1180 break;\r
1181\r
1182 case 056: /* clear seq brk */\r
1183 sbs = 0; /* clear PI */\r
1184 sbs_req = 0;\r
1185 sbs_enb = 0;\r
1186 sbs_act = 0;\r
1187 break;\r
1188\r
1189 case 061: case 062: case 063: /* drum */\r
1190 io_data = drm (IR, dev, IO);\r
1191 break;\r
1192\r
1193 case 064: /* drum/leave rm */\r
1194 if (cpu_unit.flags & UNIT_1D) rm = 0;\r
1195 else io_data = drm (IR, dev, IO);\r
1196 break;\r
1197\r
1198 case 065: /* enter rm */\r
1199 if (cpu_unit.flags & UNIT_1D) {\r
1200 rm = 1;\r
1201 rmask = IO;\r
1202 }\r
1203 else reason = stop_inst;\r
1204 break;\r
1205\r
1206 case 066: /* rename mem */\r
1207 if (cpu_unit.flags & UNIT_1D45) { /* SN45? */\r
1208 int32 from = (IR >> 9) & RM45_M_BNK;\r
1209 int32 to = (IR >> 6) & RM45_M_BNK;\r
1210 rname[from] = to;\r
1211 }\r
1212 else reason = stop_inst;\r
1213 break;\r
1214\r
1215 case 067: /* reset renaming */\r
1216 if (cpu_unit.flags & UNIT_1D45) { /* SN45 */\r
1217 for (i = 0; i < RN45_SIZE; i++) rname[i] = i;\r
1218 }\r
1219 else reason = stop_inst;\r
1220 break;\r
1221\r
1222 case 074: /* extend mode */\r
1223 extm = (IR >> 11) & 1; /* set from IR<6> */\r
1224 break;\r
1225\r
1226 default: /* undefined */\r
1227 reason = stop_inst;\r
1228 break;\r
1229 } /* end switch dev */\r
1230\r
1231 IO = io_data & DMASK;\r
1232 if (io_data & IOT_SKP) PC = INCR_ADDR (PC); /* skip? */\r
1233 if (io_data >= IOT_REASON) reason = io_data >> IOT_V_REASON;\r
1234 sbs_lvl = sbs_eval (); /* eval SBS system */\r
1235 break;\r
1236\r
1237 default: /* undefined */\r
1238 if (rm && !sbs_act) /* restrict, ~brk? */\r
1239 reason = set_rmv (RTB_ILL); /* violation */\r
1240 else reason = STOP_RSRV; /* halt */\r
1241 break;\r
1242 } /* end switch op */\r
1243\r
1244 if (reason == ERR_RMV) { /* restrict viol? */\r
1245 sbs_req |= SBS_MASK (SBS_LVL_RMV); /* request break */\r
1246 sbs_lvl = sbs_eval (); /* re-eval SBS */\r
1247 reason = 0; /* continue */\r
1248 }\r
1249 } /* end while */\r
1250pcq_r->qptr = pcq_p; /* update pc q ptr */\r
1251return reason;\r
1252}\r
1253\r
1254/* Effective address routine for standard memory reference instructions */\r
1255\r
1256t_stat Ea (int32 IR)\r
1257{\r
1258int32 i;\r
1259t_stat r;\r
1260\r
1261MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */\r
1262if (IR & IA) { /* indirect addr? */\r
1263 if (extm) { /* extend? */\r
1264 if (r = Read ()) return r; /* read; err? */\r
1265 MA = MB & AMASK; /* one level */\r
1266 }\r
1267 else { /* multi-level */\r
1268 for (i = 0; i < ind_max; i++) { /* count indirects */\r
1269 if (r = Read ()) return r; /* get ind word */\r
1270 MA = (PC & EPCMASK) | (MB & DAMASK);\r
1271 if ((MB & IA) == 0) break;\r
1272 }\r
1273 if (i >= ind_max) return STOP_IND; /* indirect loop? */\r
1274 } /* end else !extm */\r
1275 } /* end if indirect */\r
1276if (hst_p) hst[hst_p].ea = MA; /* history enabled? */\r
1277return SCPE_OK;\r
1278}\r
1279\r
1280/* Effective address routine for character instructions */\r
1281\r
1282t_stat Ea_ch (int32 IR, int32 *bn)\r
1283{\r
1284int32 i;\r
1285t_stat r;\r
1286\r
1287MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */\r
1288if (extm) { /* extend? */\r
1289 if (r = Read ()) return r; /* read; err? */\r
1290 }\r
1291else { /* multi-level */\r
1292 for (i = 0; i < ind_max; i++) { /* count indirects */\r
1293 if (r = Read ()) return r; /* get ind word */\r
1294 if ((MB & IA) == 0) break;\r
1295 MA = (PC & EPCMASK) | (MB & DAMASK);\r
1296 }\r
1297 if (i >= ind_max) return STOP_IND; /* indirect loop? */\r
1298 } /* end else !extm */\r
1299if (IR & IA) { /* automatic mode? */\r
1300 if (rm & !sbs_act & ((MB & 0607777) == 0607777)) /* page cross? */\r
1301 return set_rmv (RTB_CHR);\r
1302 MB = inc_bp (MB); /* incr byte ptr */\r
1303 Write (); /* rewrite */\r
1304 }\r
1305*bn = (MB >> 16) & 03; /* byte num */\r
1306if (extm) MA = MB & AMASK; /* final ea */\r
1307else MA = (PC & EPCMASK) | (MB & DAMASK);\r
1308if (hst_p) hst[hst_p].ea = MA; /* history enabled? */\r
1309return SCPE_OK;\r
1310}\r
1311\r
1312/* Increment byte pointer, allowing for ring mode */\r
1313\r
1314int32 inc_bp (int32 bp)\r
1315{\r
1316bp = bp + (1 << 16); /* add to bit<1> */\r
1317if (bp > DMASK) { /* carry out? */\r
1318 if (PF & PF_RNG) /* ring mode? */\r
1319 bp = (1 << 16) | (bp & 0177770) | ((bp + 1) & 07);\r
1320 else bp = (1 << 16) | ((bp + 1) & AMASK);\r
1321 }\r
1322return bp;\r
1323}\r
1324\r
1325/* Read and write memory */\r
1326\r
1327t_stat Read (void)\r
1328{\r
1329if (rm && !sbs_act) { /* restrict check? */\r
1330 int32 bnk = MA_GETBNK (MA); /* get bank */\r
1331 if ((rmask << bnk) & SIGN) return set_rmv (0);\r
1332 }\r
1333MB = M[MA];\r
1334if (hst_p) hst[hst_p].opnd = MB; /* history enabled? */\r
1335return SCPE_OK;\r
1336}\r
1337\r
1338t_stat Write (void)\r
1339{\r
1340if (hst_p) hst[hst_p].opnd = M[MA]; /* hist? old contents */\r
1341if (rm && !sbs_act) { /* restrict check? */\r
1342 int32 bnk = MA_GETBNK (MA); /* get bank */\r
1343 if ((rmask << bnk) & SIGN) return set_rmv (0);\r
1344 }\r
1345if (MEM_ADDR_OK (MA)) M[MA] = MB;\r
1346return SCPE_OK;\r
1347}\r
1348\r
1349/* Restrict mode trap */\r
1350\r
1351t_stat set_rmv (int32 code)\r
1352{\r
1353rtb = code | (MB & RTB_MB_MASK);\r
1354return ERR_RMV;\r
1355}\r
1356\r
1357/* Evaluate SBS system */\r
1358\r
1359int32 sbs_eval (void)\r
1360{\r
1361int32 hi;\r
1362\r
1363if (cpu_unit.flags & UNIT_SBS) { /* SBS enabled? */\r
1364 if (sbs_req == 0) return 0; /* any requests? */\r
1365 hi = sbs_ffo (sbs_req); /* find highest */\r
1366 if (hi < sbs_ffo (sbs_act)) return hi + 1; /* higher? */\r
1367 }\r
1368return 0;\r
1369}\r
1370\r
1371/* Find first one in a 16b field */\r
1372\r
1373int32 sbs_ffo (int32 mask)\r
1374{\r
1375if (mask & 0177400)\r
1376 return ffo_map[(mask >> 8) & 0377];\r
1377else return (ffo_map[mask & 0377] + 8);\r
1378}\r
1379\r
1380/* Device request interrupt */\r
1381\r
1382t_stat dev_req_int (int32 lvl)\r
1383{\r
1384if (cpu_unit.flags & UNIT_SBS) { /* SBS enabled? */\r
1385 if (lvl >= SBS_LVLS) return SCPE_IERR; /* invalid level? */\r
1386 if (sbs_enb & SBS_MASK (lvl)) /* level active? */\r
1387 sbs_req |= SBS_MASK (lvl); /* set SBS request */\r
1388 }\r
1389else sbs |= SB_RQ; /* PI request */\r
1390return SCPE_OK;\r
1391}\r
1392\r
1393/* Device set/show SBS level */\r
1394\r
1395t_stat dev_set_sbs (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1396{\r
1397int32 *lvl = (int32 *) desc;\r
1398int32 newlvl;\r
1399t_stat r;\r
1400\r
1401if ((cptr == NULL) || (*cptr == 0)) return SCPE_ARG;\r
1402newlvl = get_uint (cptr, 10, SBS_LVLS - 1, &r);\r
1403if (r != SCPE_OK) return SCPE_ARG;\r
1404*lvl = newlvl;\r
1405return SCPE_OK;\r
1406}\r
1407\r
1408t_stat dev_show_sbs (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1409{\r
1410int32 *lvl = (int32 *) desc;\r
1411\r
1412if (lvl == NULL) return SCPE_IERR;\r
1413fprintf (st, "SBS level %d", *lvl);\r
1414return SCPE_OK;\r
1415}\r
1416\r
1417/* Reset routine */\r
1418\r
1419t_stat cpu_reset (DEVICE *dptr)\r
1420{\r
1421int32 i;\r
1422\r
1423sbs = sbs_init;\r
1424extm = extm_init;\r
1425ioh = 0;\r
1426ios = 0;\r
1427cpls = 0;\r
1428sbs_act = 0;\r
1429sbs_req = 0;\r
1430sbs_enb = 0;\r
1431OV = 0;\r
1432PF = 0;\r
1433MA = 0;\r
1434MB = 0;\r
1435rm = 0;\r
1436rtb = 0;\r
1437rmask = 0;\r
1438for (i = 0; i < RN45_SIZE; i++) rname[i] = i;\r
1439pcq_r = find_reg ("PCQ", NULL, dptr);\r
1440if (pcq_r) pcq_r->qptr = 0;\r
1441else return SCPE_IERR;\r
1442sim_brk_types = sim_brk_dflt = SWMASK ('E');\r
1443return SCPE_OK;\r
1444}\r
1445\r
1446/* Memory examine */\r
1447\r
1448t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r
1449{\r
1450if (addr >= MEMSIZE) return SCPE_NXM;\r
1451if (vptr != NULL) *vptr = M[addr] & DMASK;\r
1452return SCPE_OK;\r
1453}\r
1454\r
1455/* Memory deposit */\r
1456\r
1457t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r
1458{\r
1459if (addr >= MEMSIZE) return SCPE_NXM;\r
1460M[addr] = val & DMASK;\r
1461return SCPE_OK;\r
1462}\r
1463\r
1464/* Change memory size */\r
1465\r
1466t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1467{\r
1468int32 mc = 0;\r
1469uint32 i;\r
1470\r
1471if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))\r
1472 return SCPE_ARG;\r
1473for (i = val; i < MEMSIZE; i++) mc = mc | M[i];\r
1474if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r
1475 return SCPE_OK;\r
1476MEMSIZE = val;\r
1477for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;\r
1478return SCPE_OK;\r
1479}\r
1480\r
1481/* Set PDP-1D */\r
1482\r
1483t_stat cpu_set_1d (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1484{\r
1485uptr->flags |= UNIT_SBS|UNIT_MDV;\r
1486return SCPE_OK;\r
1487}\r
1488\r
1489/* Set history */\r
1490\r
1491t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1492{\r
1493int32 i, lnt;\r
1494t_stat r;\r
1495\r
1496if (cptr == NULL) {\r
1497 for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;\r
1498 hst_p = 0;\r
1499 return SCPE_OK;\r
1500 }\r
1501lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);\r
1502if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;\r
1503hst_p = 0;\r
1504if (hst_lnt) {\r
1505 free (hst);\r
1506 hst_lnt = 0;\r
1507 hst = NULL;\r
1508 }\r
1509if (lnt) {\r
1510 hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));\r
1511 if (hst == NULL) return SCPE_MEM;\r
1512 hst_lnt = lnt;\r
1513 }\r
1514return SCPE_OK;\r
1515}\r
1516\r
1517/* Show history */\r
1518\r
1519t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1520{\r
1521int32 ov, pf, op, k, di, lnt;\r
1522char *cptr = (char *) desc;\r
1523t_stat r;\r
1524t_value sim_eval;\r
1525InstHistory *h;\r
1526extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,\r
1527 UNIT *uptr, int32 sw);\r
1528\r
1529if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */\r
1530if (cptr) {\r
1531 lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);\r
1532 if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG;\r
1533 }\r
1534else lnt = hst_lnt;\r
1535di = hst_p - lnt; /* work forward */\r
1536if (di < 0) di = di + hst_lnt;\r
1537fprintf (st, "PC OV AC IO PF EA IR\n\n");\r
1538for (k = 0; k < lnt; k++) { /* print specified */\r
1539 h = &hst[(++di) % hst_lnt]; /* entry pointer */\r
1540 if (h->pc & HIST_PC) { /* instruction? */\r
1541 ov = (h->ovac >> HIST_V_SHF) & 1; /* overflow */\r
1542 pf = (h->pfio >> HIST_V_SHF) & PF_VR_ALL; /* prog flags */\r
1543 op = ((h->ir >> 13) & 037); /* get opcode */\r
1544 fprintf (st, "%06o %o %06o %06o %03o ",\r
1545 h->pc & AMASK, ov, h->ovac & DMASK, h->pfio & DMASK, pf);\r
1546 if ((op < 032) && (op != 007)) /* mem ref instr */\r
1547 fprintf (st, "%06o ", h->ea);\r
1548 else fprintf (st, " ");\r
1549 sim_eval = h->ir;\r
1550 if ((fprint_sym (st, h->pc & AMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)\r
1551 fprintf (st, "(undefined) %06o", h->ir);\r
1552 else if (op < 030) /* mem ref instr */\r
1553 fprintf (st, " [%06o]", h->opnd);\r
1554 fputc ('\n', st); /* end line */\r
1555 } /* end else instruction */\r
1556 } /* end for */\r
1557return SCPE_OK;\r
1558}\r