Commit | Line | Data |
---|---|---|
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 | |
292 | typedef 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 | |
301 | int32 M[MAXMEMSIZE] = { 0 }; /* memory */\r | |
302 | int32 AC = 0; /* AC */\r | |
303 | int32 IO = 0; /* IO */\r | |
304 | int32 PC = 0; /* PC */\r | |
305 | int32 MA = 0; /* MA */\r | |
306 | int32 MB = 0; /* MB */\r | |
307 | int32 OV = 0; /* overflow */\r | |
308 | int32 SS = 0; /* sense switches */\r | |
309 | int32 PF = 0; /* program flags */\r | |
310 | int32 TA = 0; /* address switches */\r | |
311 | int32 TW = 0; /* test word */\r | |
312 | int32 iosta = 0; /* status reg */\r | |
313 | int32 sbs = 0; /* sequence break */\r | |
314 | int32 sbs_init = 0; /* seq break start */\r | |
315 | int32 ioh = 0; /* I/O halt */\r | |
316 | int32 ios = 0; /* I/O syncronizer */\r | |
317 | int32 cpls = 0; /* pending compl */\r | |
318 | int32 sbs_req = 0; /* sbs requests */\r | |
319 | int32 sbs_enb = 0; /* sbs enabled */\r | |
320 | int32 sbs_act = 0; /* sbs active */\r | |
321 | int32 extm = 0; /* ext mem mode */\r | |
322 | int32 rm = 0; /* restrict mode */\r | |
323 | int32 rmask = 0; /* restrict mask */\r | |
324 | int32 rname[RN45_SIZE]; /* rename table */\r | |
325 | int32 rtb = 0; /* restr trap buf */\r | |
326 | int32 extm_init = 0; /* ext mem startup */\r | |
327 | int32 stop_inst = 0; /* stop rsrv inst */\r | |
328 | int32 xct_max = 16; /* XCT limit */\r | |
329 | int32 ind_max = 16; /* ind limit */\r | |
330 | uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r | |
331 | int32 pcq_p = 0; /* PC queue ptr */\r | |
332 | REG *pcq_r = NULL; /* PC queue reg ptr */\r | |
333 | int32 hst_p = 0; /* history pointer */\r | |
334 | int32 hst_lnt = 0; /* history length */\r | |
335 | InstHistory *hst = NULL; /* inst history */\r | |
336 | \r | |
337 | extern UNIT *sim_clock_queue;\r | |
338 | extern int32 sim_int_char;\r | |
339 | extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r | |
340 | \r | |
341 | t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r | |
342 | t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r | |
343 | t_stat cpu_reset (DEVICE *dptr);\r | |
344 | t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
345 | t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
346 | t_stat cpu_set_1d (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
347 | t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
348 | t_stat Ea (int32 IR);\r | |
349 | t_stat Ea_ch (int32 IR, int32 *byte_num);\r | |
350 | int32 inc_bp (int32 bp);\r | |
351 | t_stat set_rmv (int32 code);\r | |
352 | int32 sbs_eval (void);\r | |
353 | int32 sbs_ffo (int32 mask);\r | |
354 | t_stat Read (void);\r | |
355 | t_stat Write (void);\r | |
356 | \r | |
357 | extern int32 ptr (int32 inst, int32 dev, int32 dat);\r | |
358 | extern int32 ptp (int32 inst, int32 dev, int32 dat);\r | |
359 | extern int32 tti (int32 inst, int32 dev, int32 dat);\r | |
360 | extern int32 tto (int32 inst, int32 dev, int32 dat);\r | |
361 | extern int32 lpt (int32 inst, int32 dev, int32 dat);\r | |
362 | extern int32 dt (int32 inst, int32 dev, int32 dat);\r | |
363 | extern int32 drm (int32 inst, int32 dev, int32 dat);\r | |
364 | extern int32 clk (int32 inst, int32 dev, int32 dat);\r | |
365 | extern int32 dcs (int32 inst, int32 dev, int32 dat);\r | |
366 | \r | |
367 | const 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 | |
402 | const 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 | |
421 | const 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 | |
431 | UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };\r | |
432 | \r | |
433 | REG 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 | |
472 | MTAB 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 | |
495 | DEVICE 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 | |
503 | t_stat sim_instr (void)\r | |
504 | {\r | |
505 | extern int32 sim_interval;\r | |
506 | int32 IR, op, i, t, xct_count;\r | |
507 | int32 sign, signd, v, sbs_lvl, byno;\r | |
508 | int32 dev, pulse, io_data, sc, skip;\r | |
509 | t_stat reason;\r | |
510 | static 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 | |
520 | if (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 | |
528 | else { /* 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 | |
534 | if (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 | |
538 | else 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 | |
542 | reason = 0;\r | |
543 | while (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 | |
1250 | pcq_r->qptr = pcq_p; /* update pc q ptr */\r | |
1251 | return reason;\r | |
1252 | }\r | |
1253 | \r | |
1254 | /* Effective address routine for standard memory reference instructions */\r | |
1255 | \r | |
1256 | t_stat Ea (int32 IR)\r | |
1257 | {\r | |
1258 | int32 i;\r | |
1259 | t_stat r;\r | |
1260 | \r | |
1261 | MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */\r | |
1262 | if (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 | |
1276 | if (hst_p) hst[hst_p].ea = MA; /* history enabled? */\r | |
1277 | return SCPE_OK;\r | |
1278 | }\r | |
1279 | \r | |
1280 | /* Effective address routine for character instructions */\r | |
1281 | \r | |
1282 | t_stat Ea_ch (int32 IR, int32 *bn)\r | |
1283 | {\r | |
1284 | int32 i;\r | |
1285 | t_stat r;\r | |
1286 | \r | |
1287 | MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */\r | |
1288 | if (extm) { /* extend? */\r | |
1289 | if (r = Read ()) return r; /* read; err? */\r | |
1290 | }\r | |
1291 | else { /* 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 | |
1299 | if (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 | |
1306 | if (extm) MA = MB & AMASK; /* final ea */\r | |
1307 | else MA = (PC & EPCMASK) | (MB & DAMASK);\r | |
1308 | if (hst_p) hst[hst_p].ea = MA; /* history enabled? */\r | |
1309 | return SCPE_OK;\r | |
1310 | }\r | |
1311 | \r | |
1312 | /* Increment byte pointer, allowing for ring mode */\r | |
1313 | \r | |
1314 | int32 inc_bp (int32 bp)\r | |
1315 | {\r | |
1316 | bp = bp + (1 << 16); /* add to bit<1> */\r | |
1317 | if (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 | |
1322 | return bp;\r | |
1323 | }\r | |
1324 | \r | |
1325 | /* Read and write memory */\r | |
1326 | \r | |
1327 | t_stat Read (void)\r | |
1328 | {\r | |
1329 | if (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 | |
1333 | MB = M[MA];\r | |
1334 | if (hst_p) hst[hst_p].opnd = MB; /* history enabled? */\r | |
1335 | return SCPE_OK;\r | |
1336 | }\r | |
1337 | \r | |
1338 | t_stat Write (void)\r | |
1339 | {\r | |
1340 | if (hst_p) hst[hst_p].opnd = M[MA]; /* hist? old contents */\r | |
1341 | if (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 | |
1345 | if (MEM_ADDR_OK (MA)) M[MA] = MB;\r | |
1346 | return SCPE_OK;\r | |
1347 | }\r | |
1348 | \r | |
1349 | /* Restrict mode trap */\r | |
1350 | \r | |
1351 | t_stat set_rmv (int32 code)\r | |
1352 | {\r | |
1353 | rtb = code | (MB & RTB_MB_MASK);\r | |
1354 | return ERR_RMV;\r | |
1355 | }\r | |
1356 | \r | |
1357 | /* Evaluate SBS system */\r | |
1358 | \r | |
1359 | int32 sbs_eval (void)\r | |
1360 | {\r | |
1361 | int32 hi;\r | |
1362 | \r | |
1363 | if (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 | |
1368 | return 0;\r | |
1369 | }\r | |
1370 | \r | |
1371 | /* Find first one in a 16b field */\r | |
1372 | \r | |
1373 | int32 sbs_ffo (int32 mask)\r | |
1374 | {\r | |
1375 | if (mask & 0177400)\r | |
1376 | return ffo_map[(mask >> 8) & 0377];\r | |
1377 | else return (ffo_map[mask & 0377] + 8);\r | |
1378 | }\r | |
1379 | \r | |
1380 | /* Device request interrupt */\r | |
1381 | \r | |
1382 | t_stat dev_req_int (int32 lvl)\r | |
1383 | {\r | |
1384 | if (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 | |
1389 | else sbs |= SB_RQ; /* PI request */\r | |
1390 | return SCPE_OK;\r | |
1391 | }\r | |
1392 | \r | |
1393 | /* Device set/show SBS level */\r | |
1394 | \r | |
1395 | t_stat dev_set_sbs (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1396 | {\r | |
1397 | int32 *lvl = (int32 *) desc;\r | |
1398 | int32 newlvl;\r | |
1399 | t_stat r;\r | |
1400 | \r | |
1401 | if ((cptr == NULL) || (*cptr == 0)) return SCPE_ARG;\r | |
1402 | newlvl = get_uint (cptr, 10, SBS_LVLS - 1, &r);\r | |
1403 | if (r != SCPE_OK) return SCPE_ARG;\r | |
1404 | *lvl = newlvl;\r | |
1405 | return SCPE_OK;\r | |
1406 | }\r | |
1407 | \r | |
1408 | t_stat dev_show_sbs (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
1409 | {\r | |
1410 | int32 *lvl = (int32 *) desc;\r | |
1411 | \r | |
1412 | if (lvl == NULL) return SCPE_IERR;\r | |
1413 | fprintf (st, "SBS level %d", *lvl);\r | |
1414 | return SCPE_OK;\r | |
1415 | }\r | |
1416 | \r | |
1417 | /* Reset routine */\r | |
1418 | \r | |
1419 | t_stat cpu_reset (DEVICE *dptr)\r | |
1420 | {\r | |
1421 | int32 i;\r | |
1422 | \r | |
1423 | sbs = sbs_init;\r | |
1424 | extm = extm_init;\r | |
1425 | ioh = 0;\r | |
1426 | ios = 0;\r | |
1427 | cpls = 0;\r | |
1428 | sbs_act = 0;\r | |
1429 | sbs_req = 0;\r | |
1430 | sbs_enb = 0;\r | |
1431 | OV = 0;\r | |
1432 | PF = 0;\r | |
1433 | MA = 0;\r | |
1434 | MB = 0;\r | |
1435 | rm = 0;\r | |
1436 | rtb = 0;\r | |
1437 | rmask = 0;\r | |
1438 | for (i = 0; i < RN45_SIZE; i++) rname[i] = i;\r | |
1439 | pcq_r = find_reg ("PCQ", NULL, dptr);\r | |
1440 | if (pcq_r) pcq_r->qptr = 0;\r | |
1441 | else return SCPE_IERR;\r | |
1442 | sim_brk_types = sim_brk_dflt = SWMASK ('E');\r | |
1443 | return SCPE_OK;\r | |
1444 | }\r | |
1445 | \r | |
1446 | /* Memory examine */\r | |
1447 | \r | |
1448 | t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r | |
1449 | {\r | |
1450 | if (addr >= MEMSIZE) return SCPE_NXM;\r | |
1451 | if (vptr != NULL) *vptr = M[addr] & DMASK;\r | |
1452 | return SCPE_OK;\r | |
1453 | }\r | |
1454 | \r | |
1455 | /* Memory deposit */\r | |
1456 | \r | |
1457 | t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r | |
1458 | {\r | |
1459 | if (addr >= MEMSIZE) return SCPE_NXM;\r | |
1460 | M[addr] = val & DMASK;\r | |
1461 | return SCPE_OK;\r | |
1462 | }\r | |
1463 | \r | |
1464 | /* Change memory size */\r | |
1465 | \r | |
1466 | t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1467 | {\r | |
1468 | int32 mc = 0;\r | |
1469 | uint32 i;\r | |
1470 | \r | |
1471 | if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))\r | |
1472 | return SCPE_ARG;\r | |
1473 | for (i = val; i < MEMSIZE; i++) mc = mc | M[i];\r | |
1474 | if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r | |
1475 | return SCPE_OK;\r | |
1476 | MEMSIZE = val;\r | |
1477 | for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;\r | |
1478 | return SCPE_OK;\r | |
1479 | }\r | |
1480 | \r | |
1481 | /* Set PDP-1D */\r | |
1482 | \r | |
1483 | t_stat cpu_set_1d (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1484 | {\r | |
1485 | uptr->flags |= UNIT_SBS|UNIT_MDV;\r | |
1486 | return SCPE_OK;\r | |
1487 | }\r | |
1488 | \r | |
1489 | /* Set history */\r | |
1490 | \r | |
1491 | t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1492 | {\r | |
1493 | int32 i, lnt;\r | |
1494 | t_stat r;\r | |
1495 | \r | |
1496 | if (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 | |
1501 | lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);\r | |
1502 | if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;\r | |
1503 | hst_p = 0;\r | |
1504 | if (hst_lnt) {\r | |
1505 | free (hst);\r | |
1506 | hst_lnt = 0;\r | |
1507 | hst = NULL;\r | |
1508 | }\r | |
1509 | if (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 | |
1514 | return SCPE_OK;\r | |
1515 | }\r | |
1516 | \r | |
1517 | /* Show history */\r | |
1518 | \r | |
1519 | t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
1520 | {\r | |
1521 | int32 ov, pf, op, k, di, lnt;\r | |
1522 | char *cptr = (char *) desc;\r | |
1523 | t_stat r;\r | |
1524 | t_value sim_eval;\r | |
1525 | InstHistory *h;\r | |
1526 | extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,\r | |
1527 | UNIT *uptr, int32 sw);\r | |
1528 | \r | |
1529 | if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */\r | |
1530 | if (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 | |
1534 | else lnt = hst_lnt;\r | |
1535 | di = hst_p - lnt; /* work forward */\r | |
1536 | if (di < 0) di = di + hst_lnt;\r | |
1537 | fprintf (st, "PC OV AC IO PF EA IR\n\n");\r | |
1538 | for (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 | |
1557 | return SCPE_OK;\r | |
1558 | }\r |