First Commit of my working state
[simh.git] / PDP18B / pdp18b_cpu.c
CommitLineData
196ba1fc
PH
1/* pdp18b_cpu.c: 18b PDP 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-4/7/9/15 central processor\r
27\r
28 28-Apr-07 RMS Removed clock initialization\r
29 26-Dec-06 RMS Fixed boundary test in KT15/XVM (reported by Andrew Warkentin)\r
30 30-Oct-06 RMS Added idle and infinite loop detection\r
31 08-Oct-06 RMS Added RDCLK instruction\r
32 Fixed bug, PC off by one on fetch mem mmgt error\r
33 PDP-15 sets API 3 on mem mmgt trap (like PI)\r
34 PDP-15 sets API 4 on CAL only if 0-3 inactive\r
35 CAF clears memory management mode register\r
36 27-Jun-06 RMS Reset clears AC, L, and MQ\r
37 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)\r
38 16-Aug-05 RMS Fixed C++ declaration and cast problems\r
39 22-Jul-05 RMS Removed AAS, error in V1 reference manual\r
40 06-Nov-04 RMS Added =n to SHOW HISTORY\r
41 26-Mar-04 RMS Fixed warning from -std=c99\r
42 14-Jan-04 RMS Fixed g_mode in XVM implementation\r
43 PDP-15 index, autoincrement generate 18b addresses\r
44 Revised IO device call interface\r
45 31-Dec-03 RMS Fixed bug in cpu_set_hist\r
46 02-Nov-03 RMS Changed PDP-9,-15 default to API\r
47 26-Oct-03 RMS Fixed bug in PDP-4,-7,-9 autoincrement addressing\r
48 19-Sep-03 RMS Changed instruction history to be dynamically sized\r
49 31-Aug-03 RMS Added instruction history\r
50 Fixed PDP-15-specific implementation of API priorities\r
51 16-Aug-03 RMS Fixed PDP-15-specific handling of EAE unsigned mul/div\r
52 27-Jul-03 RMS Added FP15 support\r
53 Added XVM support\r
54 Added EAE option to PDP-4\r
55 Added PDP-15 "re-entrancy ECO"\r
56 Fixed memory protect/skip interaction\r
57 Fixed CAF not to reset CPU\r
58 12-Mar-03 RMS Added logical name support\r
59 18-Feb-03 RMS Fixed three EAE bugs (found by Hans Pufal)\r
60 05-Oct-02 RMS Added DIBs, device number support\r
61 25-Jul-02 RMS Added DECtape support for PDP-4\r
62 06-Jan-02 RMS Revised enable/disable support\r
63 30-Dec-01 RMS Added old PC queue\r
64 30-Nov-01 RMS Added extended SET/SHOW support\r
65 25-Nov-01 RMS Revised interrupt structure\r
66 19-Sep-01 RMS Fixed bug in EAE (found by Dave Conroy)\r
67 17-Sep-01 RMS Fixed typo in conditional\r
68 10-Aug-01 RMS Removed register from declarations\r
69 17-Jul-01 RMS Moved function prototype\r
70 27-May-01 RMS Added second Teletype support, fixed bug in API\r
71 18-May-01 RMS Added PDP-9,-15 API option\r
72 16-May-01 RMS Fixed bugs in protection checks\r
73 26-Apr-01 RMS Added device enable/disable support\r
74 25-Jan-01 RMS Added DECtape support\r
75 18-Dec-00 RMS Added PDP-9,-15 memm init register\r
76 30-Nov-00 RMS Fixed numerous PDP-15 bugs\r
77 14-Apr-99 RMS Changed t_addr to unsigned\r
78\r
79 The 18b PDP family has five distinct architectural variants: PDP-1,\r
80 PDP-4, PDP-7, PDP-9, and PDP-15. Of these, the PDP-1 is so unique\r
81 as to require a different simulator. The PDP-4, PDP-7, PDP-9, and\r
82 PDP-15 are "upward compatible", with each new variant adding\r
83 distinct architectural features and incompatibilities.\r
84\r
85 The register state for the 18b PDP's is:\r
86\r
87 all AC<0:17> accumulator\r
88 all MQ<0:17> multiplier-quotient\r
89 all L link flag\r
90 all PC<0:x> program counter\r
91 all IORS I/O status register\r
92 PDP-7, PDP-9 EXTM extend mode\r
93 PDP-15 BANKM bank mode\r
94 PDP-7 USMD trap mode\r
95 PDP-9, PDP-15 USMD user mode\r
96 PDP-9, PDP-15 BR bounds register\r
97 PDP-15 RR relocation register\r
98 PDP-15 XVM MMR memory management register\r
99 PDP-15 XR index register\r
100 PDP-15 LR limit register\r
101\r
102 The PDP-4, PDP-7, and PDP-9 have five instruction formats: memory\r
103 reference, load immediate, I/O transfer, EAE, and operate. The PDP-15\r
104 adds a sixth, index operate, and a seventh, floating point. The memory\r
105 reference format for the PDP-4, PDP-7, and PDP-9, and for the PDP-15\r
106 in bank mode, is:\r
107\r
108 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
109 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
110 | op |in| address | memory reference\r
111 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
112\r
113 The PDP-15 in page mode trades an address bit for indexing capability:\r
114\r
115 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
116 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
117 | op |in| X| address | memory reference\r
118 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
119\r
120 <0:3> mnemonic action\r
121\r
122 00 CAL JMS with MA = 20\r
123 04 DAC M[MA] = AC\r
124 10 JMS M[MA] = L'mem'user'PC, PC = MA + 1\r
125 14 DZM M[MA] = 0\r
126 20 LAC AC = M[MA]\r
127 24 XOR AC = AC ^ M[MA]\r
128 30 ADD L'AC = AC + M[MA] one's complement\r
129 34 TAD L'AC = AC + M[MA]\r
130 40 XCT M[MA] is executed as an instruction\r
131 44 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0\r
132 50 AND AC = AC & M[MA]\r
133 54 SAD skip if AC != M[MA]\r
134 60 JMP PC = MA\r
135\r
136 On the PDP-4, PDP-7, and PDP-9, and the PDP-15 in bank mode, memory\r
137 reference instructions can access an address space of 32K words. The\r
138 address space is divided into four 8K word fields. An instruction can\r
139 directly address, via its 13b address, the entire current field. On the\r
140 PDP-4, PDP-7, and PDP-9, if extend mode is off, indirect addresses access\r
141 the current field; if on (or a PDP-15), they can access all 32K.\r
142\r
143 On the PDP-15 in page mode, memory reference instructions can access\r
144 an address space of 128K words. The address is divided into four 32K\r
145 word blocks, each of which consists of eight 4K pages. An instruction\r
146 can directly address, via its 12b address, the current page. Indirect\r
147 addresses can access the current block. Indexed and autoincrement\r
148 addresses can access all 128K.\r
149\r
150 On the PDP-4 and PDP-7, if an indirect address in in locations 00010-\r
151 00017 of any field, the indirect address is incremented and rewritten\r
152 to memory before use. On the PDP-9 and PDP-15, only locations 00010-\r
153 00017 of field zero autoincrement; special logic will redirect indirect\r
154 references to 00010-00017 to field zero, even if (on the PDP-9) extend\r
155 mode is off.\r
156\r
157 The EAE format is:\r
158\r
159 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
160 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
161 | 1 1 0 1| | | | | | | | | | | | | | | EAE\r
162 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
163 | | | | | | | | | | | | | |\r
164 | | | | | | | | | | | | | +- or SC (3)\r
165 | | | | | | | | | | | | +---- or MQ (3)\r
166 | | | | | | | | | | | +------- compl MQ (3)\r
167 | | | | | | | | \______________/\r
168 | | | | | | | | |\r
169 | | | | | \_____/ +--------- shift count\r
170 | | | | | |\r
171 | | | | | +---------------------- EAE command (3)\r
172 | | | | +---------------------------- clear AC (2)\r
173 | | | +------------------------------- or AC (2)\r
174 | | +---------------------------------- load EAE sign (1)\r
175 | +------------------------------------- clear MQ (1)\r
176 +---------------------------------------- load link (1)\r
177\r
178 The I/O transfer format is:\r
179\r
180 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
181 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
182 | 1 1 1 0 0 0| device | sdv |cl| pulse | I/O transfer\r
183 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
184\r
185 The IO transfer instruction sends the the specified pulse to the\r
186 specified I/O device and sub-device. The I/O device may take data\r
187 from the AC, return data to the AC, initiate or cancel operations,\r
188 or skip on status. On the PDP-4, PDP-7, and PDP-9, bits <4:5>\r
189 were designated as subdevice bits but were never used; the PDP-15\r
190 requires them to be zero.\r
191\r
192 On the PDP-15, the floating point format is:\r
193\r
194 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
195 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
196 | 1 1 1 0 0 1| subopcode | floating point\r
197 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
198 |in| address |\r
199 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
200\r
201 Indirection is always single level.\r
202\r
203 On the PDP-15, the index operate format is:\r
204\r
205 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
206 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
207 | 1 1 1 0 1| subopcode | immediate | index operate\r
208 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
209\r
210 The index operate instructions provide various operations on the\r
211 index and limit registers.\r
212\r
213 The operate format is:\r
214\r
215 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
216 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
217 | 1 1 1 1 0| | | | | | | | | | | | | | operate\r
218 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
219 | | | | | | | | | | | | |\r
220 | | | | | | | | | | | | +- CMA (3)\r
221 | | | | | | | | | | | +---- CML (3)\r
222 | | | | | | | | | | +------- OAS (3)\r
223 | | | | | | | | | +---------- RAL (3)\r
224 | | | | | | | | +------------- RAR (3)\r
225 | | | | | | | +---------------- HLT (4)\r
226 | | | | | | +------------------- SMA (1)\r
227 | | | | | +---------------------- SZA (1)\r
228 | | | | +------------------------- SNL (1)\r
229 | | | +---------------------------- invert skip (1)\r
230 | | +------------------------------- rotate twice (2)\r
231 | +---------------------------------- CLL (2)\r
232 +------------------------------------- CLA (2)\r
233\r
234 The operate instruction can be microprogrammed to perform operations\r
235 on the AC and link.\r
236\r
237 The load immediate format is:\r
238\r
239 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17\r
240 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
241 | 1 1 1 1 1| immediate | LAW\r
242 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r
243\r
244 <0:4> mnemonic action\r
245\r
246 76 LAW AC = IR\r
247\r
248 This routine is the instruction decode routine for the 18b PDP's.\r
249 It is called from the simulator control program to execute\r
250 instructions in simulated memory, starting at the simulated PC.\r
251 It runs until 'reason' is set non-zero.\r
252\r
253 General notes:\r
254\r
255 1. Reasons to stop. The simulator can be stopped by:\r
256\r
257 HALT instruction\r
258 breakpoint encountered\r
259 unimplemented instruction and STOP_INST flag set\r
260 nested XCT's\r
261 I/O error in I/O simulator\r
262\r
263 2. Interrupts. Interrupt requests are maintained in the int_hwre\r
264 array. int_hwre[0:3] corresponds to API levels 0-3; int_hwre[4]\r
265 holds PI requests.\r
266\r
267 3. Arithmetic. The 18b PDP's implements both 1's and 2's complement\r
268 arithmetic for signed numbers. In 1's complement arithmetic, a\r
269 negative number is represented by the complement (XOR 0777777) of\r
270 its absolute value. Addition of 1's complement numbers requires\r
271 propagating the carry out of the high order bit back to the low\r
272 order bit.\r
273\r
274 4. Adding I/O devices. Three modules must be modified:\r
275\r
276 pdp18b_defs.h add interrupt request definition\r
277 pdp18b_sys.c add sim_devices table entry\r
278*/\r
279\r
280#include "pdp18b_defs.h"\r
281\r
282#define SEXT(x) ((int32) (((x) & SIGN)? (x) | ~DMASK: (x) & DMASK))\r
283\r
284#define UNIT_V_NOEAE (UNIT_V_UF + 0) /* EAE absent */\r
285#define UNIT_V_NOAPI (UNIT_V_UF + 1) /* API absent */\r
286#define UNIT_V_PROT (UNIT_V_UF + 2) /* protection */\r
287#define UNIT_V_RELOC (UNIT_V_UF + 3) /* relocation */\r
288#define UNIT_V_XVM (UNIT_V_UF + 4) /* XVM */\r
289#define UNIT_V_MSIZE (UNIT_V_UF + 5) /* dummy mask */\r
290#define UNIT_NOEAE (1 << UNIT_V_NOEAE)\r
291#define UNIT_NOAPI (1 << UNIT_V_NOAPI)\r
292#define UNIT_PROT (1 << UNIT_V_PROT)\r
293#define UNIT_RELOC (1 << UNIT_V_RELOC)\r
294#define UNIT_XVM (1 << UNIT_V_XVM)\r
295#define UNIT_MSIZE (1 << UNIT_V_MSIZE)\r
296#define OP_KSF 0700301\r
297\r
298#define HIST_API 0x40000000\r
299#define HIST_PI 0x20000000\r
300#define HIST_PC 0x10000000\r
301#define HIST_MIN 64\r
302#define HIST_MAX 65536\r
303#define HIST_M_LVL 0x3F\r
304#define HIST_V_LVL 6\r
305\r
306typedef struct {\r
307 int32 pc;\r
308 int32 ir;\r
309 int32 ir1;\r
310 int32 lac;\r
311 int32 mq;\r
312 } InstHistory;\r
313\r
314#define XVM (cpu_unit.flags & UNIT_XVM)\r
315#define RELOC (cpu_unit.flags & UNIT_RELOC)\r
316#define PROT (cpu_unit.flags & UNIT_PROT)\r
317\r
318#if defined (PDP4)\r
319#define EAE_DFLT UNIT_NOEAE\r
320#else\r
321#define EAE_DFLT 0\r
322#endif\r
323#if defined (PDP4) || defined (PDP7)\r
324#define API_DFLT UNIT_NOAPI\r
325#define PROT_DFLT 0\r
326#define ASW_DFLT 017763\r
327#else\r
328#define API_DFLT 0\r
329#define PROT_DFLT UNIT_PROT\r
330#define ASW_DFLT 017720\r
331#endif\r
332\r
333int32 M[MAXMEMSIZE] = { 0 }; /* memory */\r
334int32 LAC = 0; /* link'AC */\r
335int32 MQ = 0; /* MQ */\r
336int32 PC = 0; /* PC */\r
337int32 iors = 0; /* IORS */\r
338int32 ion = 0; /* int on */\r
339int32 ion_defer = 0; /* int defer */\r
340int32 ion_inh = 0; /* int inhibit */\r
341int32 int_pend = 0; /* int pending */\r
342int32 int_hwre[API_HLVL+1] = { 0 }; /* int requests */\r
343int32 api_enb = 0; /* API enable */\r
344int32 api_req = 0; /* API requests */\r
345int32 api_act = 0; /* API active */\r
346int32 memm = 0; /* mem mode */\r
347#if defined (PDP15)\r
348int32 memm_init = 1; /* mem init */\r
349#else\r
350int32 memm_init = 0;\r
351#endif\r
352int32 usmd = 0; /* user mode */\r
353int32 usmd_buf = 0; /* user mode buffer */\r
354int32 usmd_defer = 0; /* user mode defer */\r
355int32 trap_pending = 0; /* trap pending */\r
356int32 emir_pending = 0; /* emir pending */\r
357int32 rest_pending = 0; /* restore pending */\r
358int32 BR = 0; /* mem mgt bounds */\r
359int32 RR = 0; /* mem mgt reloc */\r
360int32 MMR = 0; /* XVM mem mgt */\r
361int32 nexm = 0; /* nx mem flag */\r
362int32 prvn = 0; /* priv viol flag */\r
363int32 SC = 0; /* shift count */\r
364int32 eae_ac_sign = 0; /* EAE AC sign */\r
365int32 SR = 0; /* switch register */\r
366int32 ASW = ASW_DFLT; /* address switches */\r
367int32 XR = 0; /* index register */\r
368int32 LR = 0; /* limit register */\r
369int32 stop_inst = 0; /* stop on rsrv inst */\r
370int32 xct_max = 16; /* nested XCT limit */\r
371#if defined (PDP15)\r
372int32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r
373#else\r
374int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r
375#endif\r
376int32 pcq_p = 0; /* PC queue ptr */\r
377REG *pcq_r = NULL; /* PC queue reg ptr */\r
378int32 hst_p = 0; /* history pointer */\r
379int32 hst_lnt = 0; /* history length */\r
380InstHistory *hst = NULL; /* instruction history */\r
381\r
382extern int32 sim_int_char;\r
383extern int32 sim_interval;\r
384extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r
385extern t_bool sim_idle_enab;\r
386extern DEVICE *sim_devices[];\r
387extern FILE *sim_log;\r
388\r
389t_bool build_dev_tab (void);\r
390t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
391t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
392t_stat cpu_reset (DEVICE *dptr);\r
393t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r
394t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);\r
395t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);\r
396void cpu_caf (void);\r
397void cpu_inst_hist (int32 addr, int32 inst);\r
398void cpu_intr_hist (int32 flag, int32 lvl);\r
399int32 upd_iors (void);\r
400int32 api_eval (int32 *pend);\r
401t_stat Read (int32 ma, int32 *dat, int32 cyc);\r
402t_stat Write (int32 ma, int32 dat, int32 cyc);\r
403t_stat Ia (int32 ma, int32 *ea, t_bool jmp);\r
404int32 Incr_addr (int32 addr);\r
405int32 Jms_word (int32 t);\r
406#if defined (PDP15)\r
407#define INDEX(i,x) if (!memm && ((i) & I_IDX)) x = ((x) + XR) & DMASK\r
408int32 Prot15 (int32 ma, t_bool bndchk);\r
409int32 Reloc15 (int32 ma, int32 acc);\r
410int32 RelocXVM (int32 ma, int32 acc);\r
411extern t_stat fp15 (int32 ir);\r
412extern int32 clk_task_upd (t_bool clr);\r
413#else\r
414#define INDEX(i,x)\r
415#endif\r
416\r
417extern int32 clk (int32 dev, int32 pulse, int32 AC);\r
418\r
419int32 (*dev_tab[DEV_MAX])(int32 dev, int32 pulse, int32 AC); /* device dispatch */\r
420\r
421int32 (*dev_iors[DEV_MAX])(void); /* IORS dispatch */\r
422\r
423static const int32 api_ffo[256] = {\r
424 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,\r
425 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\r
426 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\r
427 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\r
428 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
429 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
430 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
434 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
436 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
438 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
440 };\r
441\r
442static const int32 api_vec[API_HLVL][32] = {\r
443 { ACH_PWRFL }, /* API 0 */\r
444 { ACH_DTA, ACH_MTA, ACH_DRM, ACH_RF, ACH_RP, ACH_RB }, /* API 1 */\r
445 { ACH_PTR, ACH_LPT, ACH_LPT }, /* API 2 */\r
446 { ACH_CLK, ACH_TTI1, ACH_TTO1 } /* API 3 */\r
447 };\r
448\r
449/* CPU data structures\r
450\r
451 cpu_dev CPU device descriptor\r
452 cpu_unit CPU unit\r
453 cpu_reg CPU register list\r
454 cpu_mod CPU modifier list\r
455*/\r
456\r
457UNIT cpu_unit = {\r
458 UDATA (NULL, UNIT_FIX+UNIT_BINK+EAE_DFLT+API_DFLT+PROT_DFLT,\r
459 MAXMEMSIZE)\r
460 };\r
461\r
462REG cpu_reg[] = {\r
463 { ORDATA (PC, PC, ADDRSIZE) },\r
464 { ORDATA (AC, LAC, 18) },\r
465 { FLDATA (L, LAC, 18) },\r
466 { ORDATA (MQ, MQ, 18) },\r
467 { ORDATA (SC, SC, 6) },\r
468 { FLDATA (EAE_AC_SIGN, eae_ac_sign, 18) },\r
469 { ORDATA (SR, SR, 18) },\r
470 { ORDATA (ASW, ASW, ADDRSIZE) },\r
471 { ORDATA (IORS, iors, 18), REG_RO },\r
472 { BRDATA (INT, int_hwre, 8, 32, API_HLVL+1), REG_RO },\r
473 { FLDATA (INT_PEND, int_pend, 0), REG_RO },\r
474 { FLDATA (ION, ion, 0) },\r
475 { ORDATA (ION_DELAY, ion_defer, 2) },\r
476#if defined (PDP7) \r
477 { FLDATA (TRAPM, usmd, 0) },\r
478 { FLDATA (TRAPP, trap_pending, 0) },\r
479 { FLDATA (EXTM, memm, 0) },\r
480 { FLDATA (EXTM_INIT, memm_init, 0) },\r
481 { FLDATA (EMIRP, emir_pending, 0) },\r
482#endif\r
483#if defined (PDP9)\r
484 { FLDATA (APIENB, api_enb, 0) },\r
485 { ORDATA (APIREQ, api_req, 8) },\r
486 { ORDATA (APIACT, api_act, 8) },\r
487 { ORDATA (BR, BR, ADDRSIZE) },\r
488 { FLDATA (USMD, usmd, 0) },\r
489 { FLDATA (USMDBUF, usmd_buf, 0) },\r
490 { FLDATA (USMDDEF, usmd_defer, 0) },\r
491 { FLDATA (NEXM, nexm, 0) },\r
492 { FLDATA (PRVN, prvn, 0) },\r
493 { FLDATA (TRAPP, trap_pending, 0) },\r
494 { FLDATA (EXTM, memm, 0) },\r
495 { FLDATA (EXTM_INIT, memm_init, 0) },\r
496 { FLDATA (EMIRP, emir_pending, 0) },\r
497 { FLDATA (RESTP, rest_pending, 0) },\r
498 { FLDATA (PWRFL, int_hwre[API_PWRFL], INT_V_PWRFL) },\r
499#endif\r
500#if defined (PDP15)\r
501 { FLDATA (ION_INH, ion_inh, 0) },\r
502 { FLDATA (APIENB, api_enb, 0) },\r
503 { ORDATA (APIREQ, api_req, 8) },\r
504 { ORDATA (APIACT, api_act, 8) },\r
505 { ORDATA (XR, XR, 18) },\r
506 { ORDATA (LR, LR, 18) },\r
507 { ORDATA (BR, BR, 18) },\r
508 { ORDATA (RR, RR, 18) },\r
509 { ORDATA (MMR, MMR, 18) },\r
510 { FLDATA (USMD, usmd, 0) },\r
511 { FLDATA (USMDBUF, usmd_buf, 0) },\r
512 { FLDATA (USMDDEF, usmd_defer, 0) },\r
513 { FLDATA (NEXM, nexm, 0) },\r
514 { FLDATA (PRVN, prvn, 0) },\r
515 { FLDATA (TRAPP, trap_pending, 0) },\r
516 { FLDATA (BANKM, memm, 0) },\r
517 { FLDATA (BANKM_INIT, memm_init, 0) },\r
518 { FLDATA (RESTP, rest_pending, 0) },\r
519 { FLDATA (PWRFL, int_hwre[API_PWRFL], INT_V_PWRFL) },\r
520#endif\r
521 { BRDATA (PCQ, pcq, 8, ADDRSIZE, PCQ_SIZE), REG_RO+REG_CIRC },\r
522 { ORDATA (PCQP, pcq_p, 6), REG_HRO },\r
523 { FLDATA (STOP_INST, stop_inst, 0) },\r
524 { DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ },\r
525 { ORDATA (WRU, sim_int_char, 8) },\r
526 { NULL } };\r
527\r
528MTAB cpu_mod[] = {\r
529 { UNIT_NOEAE, UNIT_NOEAE, "no EAE", "NOEAE", NULL },\r
530 { UNIT_NOEAE, 0, "EAE", "EAE", NULL },\r
531#if defined (PDP9) || defined (PDP15)\r
532 { UNIT_NOAPI, UNIT_NOAPI, "no API", "NOAPI", NULL },\r
533 { UNIT_NOAPI, 0, "API", "API", NULL },\r
534 { UNIT_PROT+UNIT_RELOC+UNIT_XVM, 0, "no memory protect",\r
535 "NOPROTECT", NULL },\r
536 { UNIT_PROT+UNIT_RELOC+UNIT_XVM, UNIT_PROT, "memory protect",\r
537 "PROTECT", NULL },\r
538#endif\r
539#if defined (PDP15)\r
540 { UNIT_PROT+UNIT_RELOC+UNIT_XVM, UNIT_PROT+UNIT_RELOC,\r
541 "memory relocation", "RELOCATION", NULL },\r
542 { UNIT_PROT+UNIT_RELOC+UNIT_XVM, UNIT_PROT+UNIT_RELOC+UNIT_XVM,\r
543 "XVM", "XVM", NULL },\r
544#endif\r
545 { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },\r
546 { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },\r
547#if defined (PDP4)\r
548 { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },\r
549#endif\r
550 { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },\r
551#if (MAXMEMSIZE > 8192)\r
552 { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },\r
553 { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },\r
554 { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },\r
555 { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },\r
556 { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },\r
557 { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },\r
558#endif\r
559#if (MAXMEMSIZE > 32768)\r
560 { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size },\r
561 { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },\r
562 { UNIT_MSIZE, 81920, NULL, "80K", &cpu_set_size },\r
563 { UNIT_MSIZE, 98304, NULL, "96K", &cpu_set_size },\r
564 { UNIT_MSIZE, 114688, NULL, "112K", &cpu_set_size },\r
565 { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size },\r
566#endif\r
567 { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",\r
568 &cpu_set_hist, &cpu_show_hist },\r
569 { 0 }\r
570 };\r
571\r
572DEVICE cpu_dev = {\r
573 "CPU", &cpu_unit, cpu_reg, cpu_mod,\r
574 1, 8, ADDRSIZE, 1, 8, 18,\r
575 &cpu_ex, &cpu_dep, &cpu_reset,\r
576 NULL, NULL, NULL\r
577 };\r
578\r
579t_stat sim_instr (void)\r
580{\r
581int32 api_int, api_usmd, skp;\r
582int32 iot_data, device, pulse;\r
583int32 last_IR;\r
584t_stat reason;\r
585\r
586if (build_dev_tab ()) return SCPE_STOP; /* build, chk tables */\r
587PC = PC & AMASK; /* clean variables */\r
588LAC = LAC & LACMASK;\r
589MQ = MQ & DMASK;\r
590reason = 0;\r
591last_IR = -1;\r
592if (cpu_unit.flags & UNIT_NOAPI) /* no API? */\r
593 api_enb = api_req = api_act = 0;\r
594api_int = api_eval (&int_pend); /* eval API */\r
595api_usmd = 0; /* not API user cycle */\r
596\r
597/* Main instruction fetch/decode loop */\r
598\r
599while (reason == 0) { /* loop until halted */\r
600\r
601 int32 IR, MA, MB, esc, t, xct_count;\r
602 int32 link_init, fill;\r
603\r
604 if (sim_interval <= 0) { /* check clock queue */\r
605 if (reason = sim_process_event ()) break;\r
606 api_int = api_eval (&int_pend); /* eval API */\r
607 }\r
608\r
609/* PDP-4 and PDP-7 traps and interrupts\r
610\r
611 PDP-4 no trap\r
612 PDP-7 trap: extend mode forced on, M[0] = PC, PC = 2\r
613 PDP-4, PDP-7 programmable interrupts only */\r
614\r
615#if defined (PDP4) || defined (PDP7)\r
616#if defined (PDP7)\r
617\r
618 if (trap_pending) { /* trap pending? */\r
619 PCQ_ENTRY; /* save old PC */\r
620 MB = Jms_word (1); /* save state */\r
621 ion = 0; /* interrupts off */\r
622 memm = 1; /* extend on */\r
623 emir_pending = trap_pending = 0; /* emir, trap off */\r
624 usmd = usmd_buf = 0; /* user mode off */\r
625 Write (0, MB, WR); /* save in 0 */\r
626 PC = 2; /* fetch next from 2 */\r
627 }\r
628\r
629#endif\r
630\r
631 if (int_pend && ion && !ion_defer) { /* interrupt? */\r
632 PCQ_ENTRY; /* save old PC */\r
633 MB = Jms_word (usmd); /* save state */\r
634 ion = 0; /* interrupts off */\r
635 memm = 0; /* extend off */\r
636 emir_pending = rest_pending = 0; /* emir, restore off */\r
637 usmd = usmd_buf = 0; /* user mode off */\r
638 Write (0, MB, WR); /* physical write */\r
639 PC = 1; /* fetch next from 1 */\r
640 }\r
641\r
642 if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */\r
643 reason = STOP_IBKPT; /* stop simulation */\r
644 break;\r
645 }\r
646\r
647#endif /* end PDP-4/PDP-7 */\r
648\r
649/* PDP-9 and PDP-15 traps and interrupts\r
650\r
651 PDP-9 trap: extend mode ???, M[0/20] = PC, PC = 0/21\r
652 PDP-15 trap: bank mode unchanged, M[0/20] = PC, PC = 0/21\r
653 PDP-9, PDP-15 API and program interrupts */\r
654\r
655#if defined (PDP9) || defined (PDP15)\r
656\r
657 if (trap_pending) { /* trap pending? */\r
658 PCQ_ENTRY; /* save old PC */\r
659 MB = Jms_word (1); /* save state */\r
660 if (ion) { /* int on? */\r
661 ion = 0; /* interrupts off */\r
662 MA = 0; /* treat like PI */\r
663#if defined (PDP15)\r
664 ion_defer = 2; /* free instruction */\r
665 if (!(cpu_unit.flags & UNIT_NOAPI)) { /* API? */\r
666 api_act = api_act | API_ML3; /* set lev 3 active */\r
667 api_int = api_eval (&int_pend); /* re-evaluate */\r
668 }\r
669#endif\r
670 }\r
671 else MA = 020; /* sortof like CAL */\r
672 emir_pending = rest_pending = trap_pending = 0; /* emir,rest,trap off */\r
673 usmd = usmd_buf = 0; /* user mode off */\r
674 Write (MA, MB, WR); /* physical write */\r
675 PC = MA + 1; /* fetch next */\r
676 }\r
677\r
678 if (api_int && !ion_defer) { /* API intr? */\r
679 int32 i, lvl = api_int - 1; /* get req level */\r
680 if (hst_lnt) cpu_intr_hist (HIST_API, lvl); /* record */\r
681 api_act = api_act | (API_ML0 >> lvl); /* set level active */\r
682 if (lvl >= API_HLVL) { /* software req? */\r
683 MA = ACH_SWRE + lvl - API_HLVL; /* vec = 40:43 */\r
684 api_req = api_req & ~(API_ML0 >> lvl); /* remove request */\r
685 }\r
686 else {\r
687 MA = 0; /* assume fails */\r
688 for (i = 0; i < 32; i++) { /* loop hi to lo */\r
689 if ((int_hwre[lvl] >> i) & 1) { /* int req set? */\r
690 MA = api_vec[lvl][i]; /* get vector */\r
691 break; /* and stop */\r
692 }\r
693 }\r
694 }\r
695 if (MA == 0) { /* bad channel? */\r
696 reason = STOP_API; /* API error */\r
697 break;\r
698 }\r
699 api_int = api_eval (&int_pend); /* no API int */\r
700 api_usmd = usmd; /* API user mode cycle */\r
701 usmd = usmd_buf = 0; /* user mode off */\r
702 emir_pending = rest_pending = 0; /* emir, restore off */\r
703 xct_count = 0;\r
704 Read (MA, &IR, FE); /* fetch instruction */\r
705 goto xct_instr;\r
706 }\r
707\r
708 if (int_pend && ion && !ion_defer && /* int pending, enabled? */\r
709 !(api_enb && (api_act & API_MASKPI))) { /* API off or not masking PI? */\r
710 PCQ_ENTRY; /* save old PC */\r
711 if (hst_lnt) cpu_intr_hist (HIST_PI, 0); /* record */\r
712 MB = Jms_word (usmd); /* save state */\r
713 ion = 0; /* interrupts off */\r
714 ion_defer = 2; /* free instruction */\r
715#if defined (PDP9) /* PDP-9, */\r
716 memm = 0; /* extend off */\r
717#else /* PDP-15 */\r
718 if (!(cpu_unit.flags & UNIT_NOAPI)) { /* API? */\r
719 api_act = api_act | API_ML3; /* set lev 3 active */\r
720 api_int = api_eval (&int_pend); /* re-evaluate */\r
721 }\r
722#endif\r
723 emir_pending = rest_pending = 0; /* emir, restore off */\r
724 usmd = usmd_buf = 0; /* user mode off */\r
725 Write (0, MB, WR); /* physical write */\r
726 PC = 1; /* fetch next from 1 */\r
727 }\r
728\r
729 if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */\r
730 reason = STOP_IBKPT; /* stop simulation */\r
731 break;\r
732 }\r
733 if (!usmd_defer) usmd = usmd_buf; /* no IOT? load usmd */\r
734 else usmd_defer = 0; /* cancel defer */\r
735\r
736#endif /* PDP-9/PDP-15 */\r
737\r
738/* Instruction fetch and address decode */\r
739\r
740 xct_count = 0; /* track nested XCT's */\r
741 MA = PC; /* fetch at PC */\r
742 if (Read (MA, &IR, FE)) continue; /* fetch instruction */\r
743 PC = Incr_addr (PC); /* increment PC */\r
744\r
745 xct_instr: /* label for API, XCT */\r
746 if (hst_lnt) cpu_inst_hist (MA, IR); /* history? */\r
747 if (ion_defer) ion_defer = ion_defer - 1; /* count down defer */\r
748 if (sim_interval) sim_interval = sim_interval - 1;\r
749\r
750#if defined (PDP15) /* PDP15 */\r
751\r
752 if (memm) MA = (MA & B_EPCMASK) | (IR & B_DAMASK); /* bank mode dir addr */\r
753 else MA = (MA & P_EPCMASK) | (IR & P_DAMASK); /* page mode dir addr */\r
754\r
755#else /* others */\r
756\r
757 MA = (MA & B_EPCMASK) | (IR & B_DAMASK); /* bank mode only */\r
758\r
759#endif\r
760\r
761 switch ((IR >> 13) & 037) { /* decode IR<0:4> */\r
762\r
763/* LAC: opcode 20 */\r
764\r
765 case 011: /* LAC, indir */\r
766 if (Ia (MA, &MA, 0)) break;\r
767 case 010: /* LAC, dir */\r
768 INDEX (IR, MA);\r
769 if (Read (MA, &MB, RD)) break;\r
770 LAC = (LAC & LINK) | MB;\r
771 break;\r
772\r
773/* DAC: opcode 04 */\r
774\r
775 case 003: /* DAC, indir */\r
776 if (Ia (MA, &MA, 0)) break;\r
777 case 002: /* DAC, dir */\r
778 INDEX (IR, MA);\r
779 Write (MA, LAC & DMASK, WR);\r
780 break;\r
781\r
782/* DZM: opcode 14 */\r
783\r
784 case 007: /* DZM, indir */\r
785 if (Ia (MA, &MA, 0)) break;\r
786 case 006: /* DZM, direct */\r
787 INDEX (IR, MA);\r
788 Write (MA, 0, WR);\r
789 break;\r
790\r
791/* AND: opcode 50 */\r
792\r
793 case 025: /* AND, ind */\r
794 if (Ia (MA, &MA, 0)) break;\r
795 case 024: /* AND, dir */\r
796 INDEX (IR, MA);\r
797 if (Read (MA, &MB, RD)) break;\r
798 LAC = LAC & (MB | LINK);\r
799 break;\r
800\r
801/* XOR: opcode 24 */\r
802\r
803 case 013: /* XOR, ind */\r
804 if (Ia (MA, &MA, 0)) break;\r
805 case 012: /* XOR, dir */\r
806 INDEX (IR, MA);\r
807 if (Read (MA, &MB, RD)) break;\r
808 LAC = LAC ^ MB;\r
809 break;\r
810\r
811/* ADD: opcode 30 */\r
812\r
813 case 015: /* ADD, indir */\r
814 if (Ia (MA, &MA, 0)) break;\r
815 case 014: /* ADD, dir */\r
816 INDEX (IR, MA);\r
817 if (Read (MA, &MB, RD)) break;\r
818 t = (LAC & DMASK) + MB;\r
819 if (t > DMASK) t = (t + 1) & DMASK; /* end around carry */\r
820 if (((~LAC ^ MB) & (LAC ^ t)) & SIGN) /* overflow? */\r
821 LAC = LINK | t; /* set link */\r
822 else LAC = (LAC & LINK) | t;\r
823 break;\r
824\r
825/* TAD: opcode 34 */\r
826\r
827 case 017: /* TAD, indir */\r
828 if (Ia (MA, &MA, 0)) break;\r
829 case 016: /* TAD, dir */\r
830 INDEX (IR, MA);\r
831 if (Read (MA, &MB, RD)) break;\r
832 LAC = (LAC + MB) & LACMASK;\r
833 break;\r
834\r
835/* ISZ: opcode 44 */\r
836\r
837 case 023: /* ISZ, indir */\r
838 if (Ia (MA, &MA, 0)) break;\r
839 case 022: /* ISZ, dir */\r
840 INDEX (IR, MA);\r
841 if (Read (MA, &MB, RD)) break;\r
842 MB = (MB + 1) & DMASK;\r
843 if (Write (MA, MB, WR)) break;\r
844 if (MB == 0) PC = Incr_addr (PC);\r
845 break;\r
846\r
847/* SAD: opcode 54 */\r
848\r
849 case 027: /* SAD, indir */\r
850 if (Ia (MA, &MA, 0)) break;\r
851 case 026: /* SAD, dir */\r
852 INDEX (IR, MA);\r
853 if (Read (MA, &MB, RD)) break;\r
854 if ((LAC & DMASK) != MB) PC = Incr_addr (PC);\r
855 break;\r
856\r
857/* XCT: opcode 40 */\r
858\r
859 case 021: /* XCT, indir */\r
860 if (Ia (MA, &MA, 0)) break;\r
861 case 020: /* XCT, dir */\r
862 INDEX (IR, MA);\r
863 if ((api_usmd | usmd) && (xct_count != 0)) { /* chained and usmd? */\r
864 if (usmd) prvn = trap_pending = 1; /* trap if usmd */\r
865 break; /* nop if api_usmd */\r
866 }\r
867 if (xct_count >= xct_max) { /* too many XCT's? */\r
868 reason = STOP_XCT;\r
869 break;\r
870 }\r
871 xct_count = xct_count + 1; /* count XCT's */\r
872#if defined (PDP9)\r
873 ion_defer = 1; /* defer intr */\r
874#endif\r
875 if (Read (MA, &IR, FE)) break; /* fetch inst, mm err? */\r
876 goto xct_instr; /* go execute */\r
877\r
878/* CAL: opcode 00 - api_usmd records whether usmd = 1 at start of API cycle\r
879\r
880 On the PDP-4 and PDP-7, CAL (I) is exactly the same as JMS (I) 20\r
881 On the PDP-9 and PDP-15, CAL clears user mode\r
882 On the PDP-9 and PDP-15 with API, CAL activates level 4\r
883 On the PDP-15, CAL goes to absolute 20, regardless of mode */\r
884\r
885 case 001: case 000: /* CAL */\r
886 t = usmd; /* save user mode */\r
887#if defined (PDP15) /* PDP15 */\r
888 MA = 020; /* MA = abs 20 */\r
889 ion_defer = 1; /* "free instruction" */\r
890#else /* others */\r
891 if (memm) MA = 020; /* if ext, abs 20 */\r
892 else MA = (PC & B_EPCMASK) | 020; /* else bank-rel 20 */\r
893#endif\r
894#if defined (PDP9) || defined (PDP15)\r
895 usmd = usmd_buf = 0; /* clear user mode */\r
896 if ((cpu_unit.flags & UNIT_NOAPI) == 0) { /* if API, act lvl 4 */\r
897#if defined (PDP15) /* PDP15: if 0-3 inactive */\r
898 if ((api_act & (API_ML0|API_ML1|API_ML2|API_ML3)) == 0)\r
899#endif\r
900 api_act = api_act | API_ML4;\r
901 api_int = api_eval (&int_pend);\r
902 }\r
903#endif\r
904 if (IR & I_IND) { /* indirect? */\r
905 if (Ia (MA, &MA, 0)) break;\r
906 }\r
907 PCQ_ENTRY;\r
908 MB = Jms_word (api_usmd | t); /* save state */\r
909 Write (MA, MB, WR);\r
910 PC = Incr_addr (MA);\r
911 break;\r
912\r
913/* JMS: opcode 010 - api_usmd records whether usmd = 1 at start of API cycle */\r
914\r
915 case 005: /* JMS, indir */\r
916 if (Ia (MA, &MA, 0)) break;\r
917 case 004: /* JMS, dir */\r
918 INDEX (IR, MA);\r
919 PCQ_ENTRY;\r
920#if defined (PDP15) /* PDP15 */\r
921 if (!usmd) ion_defer = 1; /* "free instruction" */\r
922#endif\r
923 MB = Jms_word (api_usmd | usmd); /* save state */\r
924 if (Write (MA, MB, WR)) break;\r
925 PC = Incr_addr (MA) & AMASK;\r
926 break;\r
927\r
928/* JMP: opcode 60 */\r
929\r
930 case 031: /* JMP, indir */\r
931 if (Ia (MA, &MA, 1)) break;\r
932 INDEX (IR, MA);\r
933 PCQ_ENTRY; /* save old PC */\r
934 PC = MA & AMASK;\r
935 break;\r
936\r
937/* JMP direct - check for idle */\r
938\r
939 case 030: /* JMP, dir */\r
940 INDEX (IR, MA);\r
941 PCQ_ENTRY; /* save old PC */\r
942 if (sim_idle_enab) { /* idling enabled? */\r
943 t_bool iof = (ion_inh != 0) || /* IOF if inhibited */\r
944 ((ion == 0) && (api_enb == 0)); /* or PI and api off */\r
945 if (((MA ^ (PC - 2)) & AMASK) == 0) { /* 1) JMP *-1? */\r
946 if (iof && (last_IR == OP_KSF) && /* iof, prv KSF, */\r
947 !TST_INT (TTI)) /* no TTI flag? */\r
948 sim_idle (0, FALSE); /* we're idle */\r
949 }\r
950 else if (((MA ^ (PC - 1)) & AMASK) == 0) { /* 2) JMP *? */\r
951 if (iof) reason = STOP_LOOP; /* iof? inf loop */\r
952 else sim_idle (0, FALSE); /* ion? idle */ \r
953 }\r
954 } /* end idle */\r
955 PC = MA & AMASK;\r
956 break;\r
957\r
958/* OPR: opcode 74 */\r
959\r
960 case 037: /* OPR, indir */\r
961 LAC = (LAC & LINK) | IR; /* LAW */\r
962 break;\r
963\r
964 case 036: /* OPR, dir */\r
965 skp = 0; /* assume no skip */\r
966 switch ((IR >> 6) & 017) { /* decode IR<8:11> */\r
967 case 0: /* nop */\r
968 break;\r
969 case 1: /* SMA */\r
970 if ((LAC & SIGN) != 0) skp = 1;\r
971 break;\r
972 case 2: /* SZA */\r
973 if ((LAC & DMASK) == 0) skp = 1;\r
974 break;\r
975 case 3: /* SZA | SMA */\r
976 if (((LAC & DMASK) == 0) || ((LAC & SIGN) != 0))\r
977 skp = 1; \r
978 break;\r
979 case 4: /* SNL */\r
980 if (LAC >= LINK) skp = 1;\r
981 break;\r
982 case 5: /* SNL | SMA */\r
983 if (LAC >= SIGN) skp = 1;\r
984 break;\r
985 case 6: /* SNL | SZA */\r
986 if ((LAC >= LINK) || (LAC == 0)) skp = 1;\r
987 break;\r
988 case 7: /* SNL | SZA | SMA */\r
989 if ((LAC >= SIGN) || (LAC == 0)) skp = 1;\r
990 break;\r
991 case 010: /* SKP */\r
992 skp = 1;\r
993 break;\r
994 case 011: /* SPA */\r
995 if ((LAC & SIGN) == 0) skp = 1;\r
996 break;\r
997 case 012: /* SNA */\r
998 if ((LAC & DMASK) != 0) skp = 1;\r
999 break;\r
1000 case 013: /* SNA & SPA */\r
1001 if (((LAC & DMASK) != 0) && ((LAC & SIGN) == 0))\r
1002 skp = 1;\r
1003 break;\r
1004 case 014: /* SZL */\r
1005 if (LAC < LINK) skp = 1;\r
1006 break;\r
1007 case 015: /* SZL & SPA */\r
1008 if (LAC < SIGN) skp = 1;\r
1009 break;\r
1010 case 016: /* SZL & SNA */\r
1011 if ((LAC < LINK) && (LAC != 0)) skp = 1;\r
1012 break;\r
1013 case 017: /* SZL & SNA & SPA */\r
1014 if ((LAC < SIGN) && (LAC != 0)) skp = 1;\r
1015 break;\r
1016 } /* end switch skips */\r
1017\r
1018 switch (((IR >> 9) & 014) | (IR & 03)) { /* IR<5:6,16:17> */\r
1019 case 0: /* NOP */\r
1020 break;\r
1021 case 1: /* CMA */\r
1022 LAC = LAC ^ DMASK;\r
1023 break;\r
1024 case 2: /* CML */\r
1025 LAC = LAC ^ LINK;\r
1026 break;\r
1027 case 3: /* CML CMA */\r
1028 LAC = LAC ^ LACMASK;\r
1029 break;\r
1030 case 4: /* CLL */\r
1031 LAC = LAC & DMASK;\r
1032 break;\r
1033 case 5: /* CLL CMA */\r
1034 LAC = (LAC & DMASK) ^ DMASK;\r
1035 break;\r
1036 case 6: /* CLL CML = STL */\r
1037 LAC = LAC | LINK;\r
1038 break;\r
1039 case 7: /* CLL CML CMA */\r
1040 LAC = (LAC | LINK) ^ DMASK;\r
1041 break;\r
1042 case 010: /* CLA */\r
1043 LAC = LAC & LINK;\r
1044 break;\r
1045 case 011: /* CLA CMA = STA */\r
1046 LAC = LAC | DMASK;\r
1047 break;\r
1048 case 012: /* CLA CML */\r
1049 LAC = (LAC & LINK) ^ LINK;\r
1050 break;\r
1051 case 013: /* CLA CML CMA */\r
1052 LAC = (LAC | DMASK) ^ LINK;\r
1053 break;\r
1054 case 014: /* CLA CLL */\r
1055 LAC = 0;\r
1056 break;\r
1057 case 015: /* CLA CLL CMA */\r
1058 LAC = DMASK;\r
1059 break;\r
1060 case 016: /* CLA CLL CML */\r
1061 LAC = LINK;\r
1062 break;\r
1063 case 017: /* CLA CLL CML CMA */\r
1064 LAC = LACMASK;\r
1065 break;\r
1066 } /* end decode */\r
1067\r
1068 if (IR & 0000004) { /* OAS */\r
1069#if defined (PDP9) || defined (PDP15)\r
1070 if (usmd) prvn = trap_pending = 1; /* trap if usmd */\r
1071 else if (!api_usmd) /* nop if api_usmd */\r
1072#endif\r
1073 LAC = LAC | SR;\r
1074 }\r
1075\r
1076 switch (((IR >> 8) & 04) | ((IR >> 3) & 03)) { /* decode IR<7,13:14> */\r
1077 case 1: /* RAL */\r
1078 LAC = ((LAC << 1) | (LAC >> 18)) & LACMASK;\r
1079 break;\r
1080 case 2: /* RAR */\r
1081 LAC = ((LAC >> 1) | (LAC << 18)) & LACMASK;\r
1082 break;\r
1083 case 3: /* RAL RAR */\r
1084#if defined (PDP15) /* PDP-15 */\r
1085 LAC = (LAC + 1) & LACMASK; /* IAC */\r
1086#else /* PDP-4,-7,-9 */\r
1087 reason = stop_inst; /* undefined */\r
1088#endif\r
1089 break;\r
1090 case 5: /* RTL */\r
1091 LAC = ((LAC << 2) | (LAC >> 17)) & LACMASK;\r
1092 break;\r
1093 case 6: /* RTR */\r
1094 LAC = ((LAC >> 2) | (LAC << 17)) & LACMASK;\r
1095 break;\r
1096 case 7: /* RTL RTR */\r
1097#if defined (PDP15) /* PDP-15 */\r
1098 LAC = ((LAC >> 9) & 0777) | ((LAC & 0777) << 9) |\r
1099 (LAC & LINK); /* BSW */\r
1100#else /* PDP-4,-7,-9 */\r
1101 reason = stop_inst; /* undefined */\r
1102#endif\r
1103 break;\r
1104 } /* end switch rotate */\r
1105\r
1106 if (IR & 0000040) { /* HLT */\r
1107 if (usmd) prvn = trap_pending = 1; /* trap if usmd */\r
1108 else if (!api_usmd) reason = STOP_HALT; /* nop if api_usmd */\r
1109 }\r
1110 if (skp) PC = Incr_addr (PC); /* if skip, inc PC */\r
1111 break; /* end OPR */\r
1112\r
1113/* EAE: opcode 64 \r
1114\r
1115 The EAE is microprogrammed to execute variable length signed and\r
1116 unsigned shift, multiply, divide, and normalize. Most commands are\r
1117 controlled by a six bit step counter (SC). In the hardware, the step\r
1118 counter is complemented on load and then counted up to zero; timing\r
1119 guarantees an initial increment, which completes the two's complement\r
1120 load. In the simulator, the SC is loaded normally and then counted\r
1121 down to zero; the read SC command compensates. */\r
1122\r
1123 case 033: case 032: /* EAE */\r
1124 if (cpu_unit.flags & UNIT_NOEAE) break; /* disabled? */\r
1125 if (IR & 0020000) /* IR<4>? AC0 to L */\r
1126 LAC = ((LAC << 1) & LINK) | (LAC & DMASK);\r
1127 if (IR & 0010000) MQ = 0; /* IR<5>? clear MQ */\r
1128 if ((IR & 0004000) && (LAC & SIGN)) /* IR<6> and minus? */\r
1129 eae_ac_sign = LINK; /* set eae_ac_sign */\r
1130 else eae_ac_sign = 0; /* if not, unsigned */\r
1131 if (IR & 0002000) MQ = (MQ | LAC) & DMASK; /* IR<7>? or AC */\r
1132 else if (eae_ac_sign) LAC = LAC ^ DMASK; /* if not, |AC| */\r
1133 if (IR & 0001000) LAC = LAC & LINK; /* IR<8>? clear AC */\r
1134 link_init = LAC & LINK; /* link temporary */\r
1135 fill = link_init? DMASK: 0; /* fill = link */\r
1136 esc = IR & 077; /* get eff SC */\r
1137 switch ((IR >> 6) & 07) { /* case on IR<9:11> */\r
1138\r
1139 case 0: /* setup */\r
1140 if (IR & 04) MQ = MQ ^ DMASK; /* IR<15>? ~MQ */\r
1141 if (IR & 02) LAC = LAC | MQ; /* IR<16>? or MQ */\r
1142 if (IR & 01) LAC = LAC | ((-SC) & 077); /* IR<17>? or SC */\r
1143 break;\r
1144\r
1145/* Multiply uses a shift and add algorithm. The PDP-15, unlike prior\r
1146 implementations, factors IR<6> (signed multiply) into the calculation\r
1147 of the result sign. */\r
1148\r
1149 case 1: /* multiply */\r
1150 if (Read (PC, &MB, FE)) break; /* get next word */\r
1151 PC = Incr_addr (PC); /* increment PC */\r
1152 if (eae_ac_sign) MQ = MQ ^ DMASK; /* EAE AC sign? ~MQ */\r
1153 LAC = LAC & DMASK; /* clear link */\r
1154 SC = esc; /* init SC */\r
1155 do { /* loop */\r
1156 if (MQ & 1) LAC = LAC + MB; /* MQ<17>? add */\r
1157 MQ = (MQ >> 1) | ((LAC & 1) << 17);\r
1158 LAC = LAC >> 1; /* shift AC'MQ right */\r
1159 SC = (SC - 1) & 077; /* decrement SC */\r
1160 } while (SC != 0); /* until SC = 0 */\r
1161#if defined (PDP15)\r
1162 if ((IR & 0004000) && (eae_ac_sign ^ link_init)) {\r
1163#else\r
1164 if (eae_ac_sign ^ link_init) { /* result negative? */\r
1165#endif\r
1166 LAC = LAC ^ DMASK;\r
1167 MQ = MQ ^ DMASK;\r
1168 }\r
1169 break;\r
1170\r
1171/* Divide uses a non-restoring divide. Divide uses a subtract and shift\r
1172 algorithm. The quotient is generated in true form. The PDP-15, unlike\r
1173 prior implementations, factors IR<6> (signed multiply) into the calculation\r
1174 of the result sign. */\r
1175\r
1176 case 3: /* divide */\r
1177 if (Read (PC, &MB, FE)) break; /* get next word */\r
1178 PC = Incr_addr (PC); /* increment PC */\r
1179 if (eae_ac_sign) MQ = MQ ^ DMASK; /* EAE AC sign? ~MQ */\r
1180 if ((LAC & DMASK) >= MB) { /* overflow? */\r
1181 LAC = (LAC - MB) | LINK; /* set link */\r
1182 break;\r
1183 }\r
1184 LAC = LAC & DMASK; /* clear link */\r
1185 t = 0; /* init loop */\r
1186 SC = esc; /* init SC */\r
1187 do { /* loop */\r
1188 if (t) LAC = (LAC + MB) & LACMASK;\r
1189 else LAC = (LAC - MB) & LACMASK;\r
1190 t = (LAC >> 18) & 1; /* quotient bit */\r
1191 if (SC > 1) LAC = /* skip if last */\r
1192 ((LAC << 1) | (MQ >> 17)) & LACMASK;\r
1193 MQ = ((MQ << 1) | (t ^ 1)) & DMASK; /* shift in quo bit */\r
1194 SC = (SC - 1) & 077; /* decrement SC */\r
1195 } while (SC != 0); /* until SC = 0 */\r
1196 if (t) LAC = (LAC + MB) & LACMASK;\r
1197 if (eae_ac_sign) LAC = LAC ^ DMASK; /* sgn rem = sgn divd */\r
1198#if defined (PDP15)\r
1199 if ((IR & 0004000) && (eae_ac_sign ^ link_init))\r
1200#else\r
1201 if (eae_ac_sign ^ link_init) /* result negative? */\r
1202#endif\r
1203 MQ = MQ ^ DMASK;\r
1204 break;\r
1205\r
1206/* EAE shifts, whether left or right, fill from the link. If the\r
1207 operand sign has been copied to the link, this provides correct\r
1208 sign extension for one's complement numbers. */\r
1209\r
1210 case 4: /* normalize */\r
1211#if defined (PDP15)\r
1212 if (!usmd) ion_defer = 2; /* free instructions */\r
1213#endif\r
1214 for (SC = esc; ((LAC & SIGN) == ((LAC << 1) & SIGN)); ) {\r
1215 LAC = (LAC << 1) | ((MQ >> 17) & 1);\r
1216 MQ = (MQ << 1) | (link_init >> 18);\r
1217 SC = (SC - 1) & 077;\r
1218 if (SC == 0) break;\r
1219 }\r
1220 LAC = link_init | (LAC & DMASK); /* trim AC, restore L */\r
1221 MQ = MQ & DMASK; /* trim MQ */\r
1222 SC = SC & 077; /* trim SC */\r
1223 break;\r
1224\r
1225 case 5: /* long right shift */\r
1226 if (esc < 18) {\r
1227 MQ = ((LAC << (18 - esc)) | (MQ >> esc)) & DMASK;\r
1228 LAC = ((fill << (18 - esc)) | (LAC >> esc)) & LACMASK;\r
1229 }\r
1230 else {\r
1231 if (esc < 36) MQ =\r
1232 ((fill << (36 - esc)) | (LAC >> (esc - 18))) & DMASK;\r
1233 else MQ = fill;\r
1234 LAC = link_init | fill;\r
1235 }\r
1236 SC = 0; /* clear step count */\r
1237 break;\r
1238\r
1239 case 6: /* long left shift */\r
1240 if (esc < 18) {\r
1241 LAC = link_init |\r
1242 (((LAC << esc) | (MQ >> (18 - esc))) & DMASK);\r
1243 MQ = ((MQ << esc) | (fill >> (18 - esc))) & DMASK;\r
1244 }\r
1245 else {\r
1246 if (esc < 36) LAC = link_init | \r
1247 (((MQ << (esc - 18)) | (fill >> (36 - esc))) & DMASK);\r
1248 else LAC = link_init | fill;\r
1249 MQ = fill;\r
1250 }\r
1251 SC = 0; /* clear step count */\r
1252 break;\r
1253\r
1254 case 7: /* AC left shift */\r
1255 if (esc < 18) LAC = link_init |\r
1256 (((LAC << esc) | (fill >> (18 - esc))) & DMASK);\r
1257 else LAC = link_init | fill;\r
1258 SC = 0; /* clear step count */\r
1259 break;\r
1260 } /* end switch IR */\r
1261 break; /* end case EAE */\r
1262\r
1263/* PDP-15 index operates: opcode 72 */\r
1264\r
1265 case 035: /* index operates */\r
1266\r
1267#if defined (PDP15)\r
1268 t = (IR & 0400)? (IR | 0777000): (IR & 0377); /* sext immediate */\r
1269 switch ((IR >> 9) & 017) { /* case on IR<5:8> */\r
1270 case 001: /* PAX */\r
1271 XR = LAC & DMASK;\r
1272 break;\r
1273 case 002: /* PAL */\r
1274 LR = LAC & DMASK;\r
1275 break;\r
1276 case 003: /* AAC */\r
1277 LAC = (LAC & LINK) | ((LAC + t) & DMASK);\r
1278 break;\r
1279 case 004: /* PXA */\r
1280 LAC = (LAC & LINK) | XR;\r
1281 break;\r
1282 case 005: /* AXS */\r
1283 XR = (XR + t) & DMASK;\r
1284 if (SEXT (XR) >= SEXT (LR)) PC = Incr_addr (PC);\r
1285 break;\r
1286 case 006: /* PXL */\r
1287 LR = XR;\r
1288 break;\r
1289 case 010: /* PLA */\r
1290 LAC = (LAC & LINK) | LR;\r
1291 break;\r
1292 case 011: /* PLX */\r
1293 XR = LR;\r
1294 break;\r
1295 case 014: /* CLAC */\r
1296 LAC = LAC & LINK;\r
1297 break;\r
1298 case 015: /* CLX */\r
1299 XR = 0;\r
1300 break;\r
1301 case 016: /* CLLR */\r
1302 LR = 0;\r
1303 break;\r
1304 case 017: /* AXR */\r
1305 XR = (XR + t) & DMASK;\r
1306 break;\r
1307 } /* end switch IR */\r
1308 break; /* end case */\r
1309#endif\r
1310\r
1311/* IOT: opcode 70 \r
1312\r
1313 The 18b PDP's have different definitions of various control IOT's.\r
1314\r
1315 IOT PDP-4 PDP-7 PDP-9 PDP-15\r
1316\r
1317 700002 IOF IOF IOF IOF\r
1318 700022 undefined undefined undefined ORMM (XVM)\r
1319 700042 ION ION ION ION\r
1320 700024 undefined undefined undefined LDMM (XVM)\r
1321 700062 undefined ITON undefined undefined\r
1322 701701 undefined undefined MPSK MPSK\r
1323 701741 undefined undefined MPSNE MPSNE\r
1324 701702 undefined undefined MPCV MPCV\r
1325 701722 undefined undefined undefined MPRC (XVM)\r
1326 701742 undefined undefined MPEU MPEU\r
1327 701704 undefined undefined MPLD MPLD\r
1328 701724 undefined undefined undefined MPLR (KT15, XVM)\r
1329 701744 undefined undefined MPCNE MPCNE\r
1330 701764 undefined undefined undefined IPFH (XVM)\r
1331 703201 undefined undefined PFSF PFSF\r
1332 703301 undefined TTS TTS TTS\r
1333 703341 undefined SKP7 SKP7 SPCO\r
1334 703302 undefined CAF CAF CAF\r
1335 703304 undefined undefined DBK DBK\r
1336 703344 undefined undefined DBR DBR\r
1337 705501 undefined undefined SPI SPI\r
1338 705521 undefined undefined undefined ENB\r
1339 705502 undefined undefined RPL RPL\r
1340 705522 undefined undefined undefined INH\r
1341 705504 undefined undefined ISA ISA\r
1342 707701 undefined SEM SEM undefined\r
1343 707741 undefined undefined undefined SKP15\r
1344 707761 undefined undefined undefined SBA\r
1345 707702 undefined EEM EEM undefined\r
1346 707742 undefined EMIR EMIR RES\r
1347 707762 undefined undefined undefined DBA\r
1348 707704 undefined LEM LEM undefined\r
1349 707764 undefined undefined undefined EBA */\r
1350\r
1351 case 034: /* IOT */\r
1352#if defined (PDP15)\r
1353 if (IR & 0010000) { /* floating point? */\r
1354 reason = fp15 (IR); /* process */\r
1355 break;\r
1356 }\r
1357#endif\r
1358 if ((api_usmd | usmd) && /* user, not XVM UIOT? */\r
1359 (!XVM || !(MMR & MM_UIOT))) {\r
1360 if (usmd) prvn = trap_pending = 1; /* trap if user */\r
1361 break; /* nop if api_usmd */\r
1362 }\r
1363 device = (IR >> 6) & 077; /* device = IR<6:11> */\r
1364 pulse = IR & 067; /* pulse = IR<12:17> */\r
1365 if (IR & 0000010) LAC = LAC & LINK; /* clear AC? */\r
1366 iot_data = LAC & DMASK; /* AC unchanged */\r
1367\r
1368/* PDP-4 system IOT's */\r
1369\r
1370#if defined (PDP4)\r
1371 switch (device) { /* decode IR<6:11> */\r
1372\r
1373 case 0: /* CPU and clock */\r
1374 if (pulse == 002) ion = 0; /* IOF */\r
1375 else if (pulse == 042) ion = ion_defer = 1; /* ION */\r
1376 else iot_data = clk (device, pulse, iot_data);\r
1377 break;\r
1378#endif\r
1379\r
1380/* PDP-7 system IOT's */\r
1381\r
1382#if defined (PDP7)\r
1383 switch (device) { /* decode IR<6:11> */\r
1384\r
1385 case 0: /* CPU and clock */\r
1386 if (pulse == 002) ion = 0; /* IOF */\r
1387 else if (pulse == 042) ion = ion_defer = 1; /* ION */\r
1388 else if (pulse == 062) /* ITON */\r
1389 usmd = usmd_buf = ion = ion_defer = 1;\r
1390 else iot_data = clk (device, pulse, iot_data);\r
1391 break;\r
1392\r
1393 case 033: /* CPU control */\r
1394 if ((pulse == 001) || (pulse == 041)) PC = Incr_addr (PC);\r
1395 else if (pulse == 002) reset_all (1); /* CAF - skip CPU */\r
1396 break;\r
1397\r
1398 case 077: /* extended memory */\r
1399 if ((pulse == 001) && memm) PC = Incr_addr (PC);\r
1400 else if (pulse == 002) memm = 1; /* EEM */\r
1401 else if (pulse == 042) /* EMIR */\r
1402 memm = emir_pending = 1; /* ext on, restore */\r
1403 else if (pulse == 004) memm = 0; /* LEM */\r
1404 break;\r
1405#endif\r
1406\r
1407/* PDP-9 system IOT's */\r
1408\r
1409#if defined (PDP9)\r
1410 ion_defer = 1; /* delay interrupts */\r
1411 usmd_defer = 1; /* defer load user */\r
1412 switch (device) { /* decode IR<6:11> */\r
1413 \r
1414 case 000: /* CPU and clock */\r
1415 if (pulse == 002) ion = 0; /* IOF */\r
1416 else if (pulse == 042) ion = 1; /* ION */\r
1417 else iot_data = clk (device, pulse, iot_data);\r
1418 break;\r
1419\r
1420 case 017: /* mem protection */\r
1421 if (PROT) { /* enabled? */\r
1422 if ((pulse == 001) && prvn) /* MPSK */\r
1423 PC = Incr_addr (PC);\r
1424 else if ((pulse == 041) && nexm) /* MPSNE */\r
1425 PC = Incr_addr (PC);\r
1426 else if (pulse == 002) prvn = 0; /* MPCV */\r
1427 else if (pulse == 042) usmd_buf = 1; /* MPEU */\r
1428 else if (pulse == 004) /* MPLD */\r
1429 BR = LAC & BRMASK;\r
1430 else if (pulse == 044) nexm = 0; /* MPCNE */\r
1431 }\r
1432 else reason = stop_inst;\r
1433 break;\r
1434\r
1435 case 032: /* power fail */\r
1436 if ((pulse == 001) && (TST_INT (PWRFL)))\r
1437 PC = Incr_addr (PC);\r
1438 break;\r
1439\r
1440 case 033: /* CPU control */\r
1441 if ((pulse == 001) || (pulse == 041)) PC = Incr_addr (PC);\r
1442 else if (pulse == 002) { /* CAF */\r
1443 reset_all (1); /* reset all exc CPU */\r
1444 cpu_caf (); /* CAF to CPU */\r
1445 }\r
1446 else if (pulse == 044) rest_pending = 1; /* DBR */\r
1447 if (((cpu_unit.flags & UNIT_NOAPI) == 0) && (pulse & 004)) {\r
1448 int32 t = api_ffo[api_act & 0377];\r
1449 api_act = api_act & ~(API_ML0 >> t);\r
1450 }\r
1451 break;\r
1452\r
1453 case 055: /* API control */\r
1454 if (cpu_unit.flags & UNIT_NOAPI) reason = stop_inst;\r
1455 else if (pulse == 001) { /* SPI */\r
1456 if (((LAC & SIGN) && api_enb) ||\r
1457 ((LAC & 0377) > api_act))\r
1458 iot_data = iot_data | IOT_SKP;\r
1459 }\r
1460 else if (pulse == 002) { /* RPL */\r
1461 iot_data = iot_data | (api_enb << 17) |\r
1462 (api_req << 8) | api_act;\r
1463 }\r
1464 else if (pulse == 004) { /* ISA */\r
1465 api_enb = (iot_data & SIGN)? 1: 0;\r
1466 api_req = api_req | ((LAC >> 8) & 017);\r
1467 api_act = api_act | (LAC & 0377);\r
1468 }\r
1469 break;\r
1470\r
1471 case 077: /* extended memory */\r
1472 if ((pulse == 001) && memm) PC = Incr_addr (PC);\r
1473 else if (pulse == 002) memm = 1; /* EEM */\r
1474 else if (pulse == 042) /* EMIR */\r
1475 memm = emir_pending = 1; /* ext on, restore */\r
1476 else if (pulse == 004) memm = 0; /* LEM */\r
1477 break;\r
1478#endif\r
1479\r
1480/* PDP-15 system IOT's - includes "re-entrancy ECO" ENB/INH as standard */\r
1481\r
1482#if defined (PDP15)\r
1483 ion_defer = 1; /* delay interrupts */\r
1484 usmd_defer = 1; /* defer load user */\r
1485 switch (device) { /* decode IR<6:11> */\r
1486\r
1487 case 000: /* CPU and clock */\r
1488 if (pulse == 002) ion = 0; /* IOF */\r
1489 else if (pulse == 042) ion = 1; /* ION */\r
1490 else if (XVM && (pulse == 022)) /* ORMM/RDMM */\r
1491 iot_data = MMR;\r
1492 else if (XVM && (pulse == 024)) /* LDMM */\r
1493 MMR = iot_data;\r
1494 else iot_data = clk (device, pulse, iot_data);\r
1495 break;\r
1496\r
1497 case 017: /* mem protection */\r
1498 if (PROT) { /* enabled? */\r
1499 t = XVM? BRMASK_XVM: BRMASK;\r
1500 if ((pulse == 001) && prvn) /* MPSK */\r
1501 PC = Incr_addr (PC);\r
1502 else if ((pulse == 041) && nexm) /* MPSNE */\r
1503 PC = Incr_addr (PC);\r
1504 else if (pulse == 002) prvn = 0; /* MPCV */\r
1505 else if (pulse == 042) /* MPEU */\r
1506 usmd_buf = 1;\r
1507 else if (XVM && (pulse == 062)) /* RDCLK */\r
1508 iot_data = clk_task_upd (TRUE);\r
1509 else if (pulse == 004) BR = LAC & t; /* MPLD */\r
1510 else if (RELOC && (pulse == 024)) /* MPLR */\r
1511 RR = LAC & t;\r
1512 else if (pulse == 044) nexm = 0; /* MPCNE */\r
1513 }\r
1514 else reason = stop_inst;\r
1515 break;\r
1516\r
1517 case 032: /* power fail */\r
1518 if ((pulse == 001) && (TST_INT (PWRFL)))\r
1519 PC = Incr_addr (PC);\r
1520 break;\r
1521\r
1522 case 033: /* CPU control */\r
1523 if ((pulse == 001) || (pulse == 041)) PC = Incr_addr (PC);\r
1524 else if (pulse == 002) { /* CAF */\r
1525 reset_all (2); /* reset all exc CPU, FP15 */\r
1526 cpu_caf (); /* CAF to CPU */\r
1527 }\r
1528 else if (pulse == 044) rest_pending = 1; /* DBR */\r
1529 if (((cpu_unit.flags & UNIT_NOAPI) == 0) && (pulse & 004)) {\r
1530 int32 t = api_ffo[api_act & 0377];\r
1531 api_act = api_act & ~(API_ML0 >> t);\r
1532 }\r
1533 break;\r
1534\r
1535 case 055: /* API control */\r
1536 if (cpu_unit.flags & UNIT_NOAPI) reason = stop_inst;\r
1537 else if (pulse == 001) { /* SPI */\r
1538 if (((LAC & SIGN) && api_enb) ||\r
1539 ((LAC & 0377) > api_act))\r
1540 iot_data = iot_data | IOT_SKP;\r
1541 }\r
1542 else if (pulse == 002) { /* RPL */\r
1543 iot_data = iot_data | (api_enb << 17) |\r
1544 (api_req << 8) | api_act;\r
1545 }\r
1546 else if (pulse == 004) { /* ISA */\r
1547 api_enb = (iot_data & SIGN)? 1: 0;\r
1548 api_req = api_req | ((LAC >> 8) & 017);\r
1549 api_act = api_act | (LAC & 0377);\r
1550 }\r
1551 else if (pulse == 021) ion_inh = 0; /* ENB */\r
1552 else if (pulse == 022) ion_inh = 1; /* INH */\r
1553 break;\r
1554\r
1555 case 077: /* bank addressing */\r
1556 if ((pulse == 041) || ((pulse == 061) && memm))\r
1557 PC = Incr_addr (PC); /* SKP15, SBA */\r
1558 else if (pulse == 042) rest_pending = 1; /* RES */\r
1559 else if (pulse == 062) memm = 0; /* DBA */\r
1560 else if (pulse == 064) memm = 1; /* EBA */\r
1561 break;\r
1562#endif\r
1563\r
1564/* IOT, continued */\r
1565\r
1566 default: /* devices */\r
1567 if (dev_tab[device]) /* defined? */\r
1568 iot_data = dev_tab[device] (device, pulse, iot_data);\r
1569 else reason = stop_inst; /* stop on flag */\r
1570 break;\r
1571 } /* end switch device */\r
1572\r
1573 LAC = LAC | (iot_data & DMASK);\r
1574 if (iot_data & IOT_SKP) PC = Incr_addr (PC);\r
1575 if (iot_data >= IOT_REASON) reason = iot_data >> IOT_V_REASON;\r
1576 api_int = api_eval (&int_pend); /* eval API */\r
1577 break; /* end case IOT */\r
1578 } /* end switch opcode */\r
1579\r
1580 api_usmd = 0; /* API cycle over */\r
1581 last_IR = IR; /* save IR for next */\r
1582 } /* end while */\r
1583\r
1584/* Simulation halted */\r
1585\r
1586iors = upd_iors (); /* get IORS */\r
1587pcq_r->qptr = pcq_p; /* update pc q ptr */\r
1588return reason;\r
1589}\r
1590\r
1591/* Evaluate API */\r
1592\r
1593int32 api_eval (int32 *pend)\r
1594{\r
1595int32 i, hi;\r
1596\r
1597*pend = 0; /* assume no intr */\r
1598#if defined (PDP15) /* PDP15 only */\r
1599if (ion_inh) return 0; /* inhibited? */\r
1600#endif\r
1601for (i = 0; i < API_HLVL+1; i++) { /* any intr? */\r
1602 if (int_hwre[i]) *pend = 1;\r
1603 }\r
1604if (api_enb == 0) return 0; /* off? no req */\r
1605api_req = api_req & ~(API_ML0|API_ML1|API_ML2|API_ML3); /* clr req<0:3> */\r
1606for (i = 0; i < API_HLVL; i++) { /* loop thru levels */\r
1607 if (int_hwre[i]) /* req on level? */\r
1608 api_req = api_req | (API_ML0 >> i); /* set api req */\r
1609 }\r
1610hi = api_ffo[api_req & 0377]; /* find hi req */\r
1611if (hi < api_ffo[api_act & 0377]) return (hi + 1);\r
1612return 0;\r
1613}\r
1614\r
1615/* Process IORS instruction */\r
1616\r
1617int32 upd_iors (void)\r
1618{\r
1619int32 d, p;\r
1620\r
1621d = (ion? IOS_ION: 0); /* ION */\r
1622for (p = 0; dev_iors[p] != NULL; p++) /* loop thru table */\r
1623 d = d | dev_iors[p](); /* OR in results */\r
1624return d;\r
1625}\r
1626\r
1627#if defined (PDP4) || defined (PDP7)\r
1628\r
1629/* Read, write, indirect, increment routines\r
1630 On the PDP-4 and PDP-7,\r
1631 There are autoincrement locations in every field. If a field\r
1632 does not exist, it is impossible to generate an\r
1633 autoincrement reference (all instructions are CAL).\r
1634 Indirect addressing range is determined by extend mode.\r
1635 JMP I with EMIR pending can only clear extend\r
1636 There is no memory protection, nxm reads zero and ignores writes. */\r
1637\r
1638t_stat Read (int32 ma, int32 *dat, int32 cyc)\r
1639{\r
1640ma = ma & AMASK;\r
1641if (MEM_ADDR_OK (ma)) *dat = M[ma] & DMASK;\r
1642else *dat = 0;\r
1643return MM_OK;\r
1644}\r
1645\r
1646t_stat Write (int32 ma, int32 dat, int32 cyc)\r
1647{\r
1648ma = ma & AMASK;\r
1649if (MEM_ADDR_OK (ma)) M[ma] = dat & DMASK;\r
1650return MM_OK;\r
1651}\r
1652\r
1653t_stat Ia (int32 ma, int32 *ea, t_bool jmp)\r
1654{\r
1655int32 t;\r
1656t_stat sta = MM_OK;\r
1657\r
1658if ((ma & B_DAMASK & ~07) == 010) { /* autoindex? */\r
1659 Read (ma, &t, DF); /* add 1 before use */\r
1660 t = (t + 1) & DMASK;\r
1661 sta = Write (ma, t, DF);\r
1662 }\r
1663else sta = Read (ma, &t, DF); /* fetch indirect */\r
1664if (jmp) { /* jmp i? */\r
1665 if (emir_pending && (((t >> 16) & 1) == 0)) memm = 0;\r
1666 emir_pending = rest_pending = 0;\r
1667 }\r
1668if (memm) *ea = t & IAMASK; /* extend? 15b ia */\r
1669else *ea = (ma & B_EPCMASK) | (t & B_DAMASK); /* bank-rel ia */\r
1670return sta;\r
1671}\r
1672\r
1673int32 Incr_addr (int32 ma)\r
1674{\r
1675return ((ma & B_EPCMASK) | ((ma + 1) & B_DAMASK));\r
1676}\r
1677\r
1678int32 Jms_word (int32 t)\r
1679{\r
1680return (((LAC & LINK) >> 1) | ((memm & 1) << 16) |\r
1681 ((t & 1) << 15) | (PC & IAMASK));\r
1682}\r
1683\r
1684#endif\r
1685\r
1686#if defined (PDP9)\r
1687\r
1688/* Read, write, indirect, increment routines\r
1689 On the PDP-9,\r
1690 The autoincrement registers are in field zero only. Regardless\r
1691 of extend mode, indirect addressing through 00010-00017\r
1692 will access absolute locations 00010-00017.\r
1693 Indirect addressing range is determined by extend mode. If\r
1694 extend mode is off, and autoincrementing is used, the\r
1695 resolved address is in bank 0 (KG09B maintenance manual).\r
1696 JMP I with EMIR pending can only clear extend\r
1697 JMP I with DBK pending restores L, user mode, extend mode\r
1698 Memory protection is implemented for foreground/background operation. */\r
1699\r
1700t_stat Read (int32 ma, int32 *dat, int32 cyc)\r
1701{\r
1702ma = ma & AMASK;\r
1703if (usmd) { /* user mode? */\r
1704 if (!MEM_ADDR_OK (ma)) { /* nxm? */\r
1705 nexm = prvn = trap_pending = 1; /* set flags, trap */\r
1706 *dat = 0;\r
1707 return MM_ERR;\r
1708 }\r
1709 if ((cyc != DF) && (ma < BR)) { /* boundary viol? */\r
1710 prvn = trap_pending = 1; /* set flag, trap */\r
1711 *dat = 0;\r
1712 return MM_ERR;\r
1713 }\r
1714 }\r
1715if (MEM_ADDR_OK (ma)) *dat = M[ma] & DMASK; /* valid mem? ok */\r
1716else {\r
1717 *dat = 0; /* set flag, no trap */\r
1718 nexm = 1;\r
1719 }\r
1720return MM_OK;\r
1721}\r
1722\r
1723t_stat Write (int32 ma, int32 dat, int32 cyc)\r
1724{\r
1725ma = ma & AMASK;\r
1726if (usmd) {\r
1727 if (!MEM_ADDR_OK (ma)) { /* nxm? */\r
1728 nexm = prvn = trap_pending = 1; /* set flags, trap */\r
1729 return MM_ERR;\r
1730 }\r
1731 if ((cyc != DF) && (ma < BR)) { /* boundary viol? */\r
1732 prvn = trap_pending = 1; /* set flag, trap */\r
1733 return MM_ERR;\r
1734 }\r
1735 }\r
1736if (MEM_ADDR_OK (ma)) M[ma] = dat & DMASK; /* valid mem? ok */\r
1737else nexm = 1; /* set flag, no trap */\r
1738return MM_OK;\r
1739}\r
1740\r
1741t_stat Ia (int32 ma, int32 *ea, t_bool jmp)\r
1742{\r
1743int32 t;\r
1744t_stat sta = MM_OK;\r
1745\r
1746if ((ma & B_DAMASK & ~07) == 010) { /* autoindex? */\r
1747 ma = ma & 017; /* always in bank 0 */\r
1748 Read (ma, &t, DF); /* +1 before use */\r
1749 t = (t + 1) & DMASK;\r
1750 sta = Write (ma, t, DF);\r
1751 }\r
1752else sta = Read (ma, &t, DF);\r
1753if (jmp) { /* jmp i? */\r
1754 if (emir_pending && (((t >> 16) & 1) == 0)) memm = 0;\r
1755 if (rest_pending) { /* restore pending? */\r
1756 LAC = ((t << 1) & LINK) | (LAC & DMASK); /* restore L */\r
1757 memm = (t >> 16) & 1; /* restore extend */\r
1758 usmd = usmd_buf = (t >> 15) & 1; /* restore user */\r
1759 }\r
1760 emir_pending = rest_pending = 0;\r
1761 }\r
1762if (memm) *ea = t & IAMASK; /* extend? 15b ia */\r
1763else *ea = (ma & B_EPCMASK) | (t & B_DAMASK); /* bank-rel ia */\r
1764return sta;\r
1765}\r
1766\r
1767int32 Incr_addr (int32 ma)\r
1768{\r
1769return ((ma & B_EPCMASK) | ((ma + 1) & B_DAMASK));\r
1770}\r
1771\r
1772int32 Jms_word (int32 t)\r
1773{\r
1774return (((LAC & LINK) >> 1) | ((memm & 1) << 16) |\r
1775 ((t & 1) << 15) | (PC & IAMASK));\r
1776}\r
1777\r
1778#endif\r
1779\r
1780#if defined (PDP15)\r
1781\r
1782/* Read, write, indirect, increment routines\r
1783 On the PDP-15,\r
1784 The autoincrement registers are in page zero only. Regardless\r
1785 of bank mode, indirect addressing through 00010-00017\r
1786 will access absolute locations 00010-00017.\r
1787 Indirect addressing range is determined by autoincrementing.\r
1788 Any indirect can trigger a restore.\r
1789 Memory protection is implemented for foreground/background operation.\r
1790 Read and write mask addresses to 17b except for XVM systems */\r
1791\r
1792t_stat Read (int32 ma, int32 *dat, int32 cyc)\r
1793{\r
1794int32 pa;\r
1795\r
1796if (usmd) { /* user mode? */\r
1797 if (XVM) pa = RelocXVM (ma, REL_R); /* XVM relocation? */\r
1798 else if (RELOC) pa = Reloc15 (ma, REL_R); /* PDP-15 relocation? */\r
1799 else pa = Prot15 (ma, cyc == FE); /* PDP-15 prot, fetch only */\r
1800 if (pa < 0) { /* error? */\r
1801 *dat = 0;\r
1802 return MM_ERR;\r
1803 }\r
1804 }\r
1805else pa = ma & AMASK; /* no prot or reloc */\r
1806if (MEM_ADDR_OK (pa)) *dat = M[pa] & DMASK; /* valid mem? ok */\r
1807else {\r
1808 nexm = 1; /* set flag, no trap */\r
1809 *dat = 0;\r
1810 }\r
1811return MM_OK;\r
1812}\r
1813\r
1814t_stat Write (int32 ma, int32 dat, int32 cyc)\r
1815{\r
1816int32 pa;\r
1817\r
1818if (usmd) { /* user mode? */\r
1819 if (XVM) pa = RelocXVM (ma, REL_W); /* XVM relocation? */\r
1820 else if (RELOC) pa = Reloc15 (ma, REL_W); /* PDP-15 relocation? */\r
1821 else pa = Prot15 (ma, cyc != DF); /* PDP-15 prot, !defer */\r
1822 if (pa < 0) return MM_ERR; /* error? */\r
1823 }\r
1824else pa = ma & AMASK; /* no prot or reloc */\r
1825if (MEM_ADDR_OK (pa)) M[pa] = dat & DMASK; /* valid mem? ok */\r
1826else nexm = 1; /* set flag, no trap */\r
1827return MM_OK;\r
1828}\r
1829\r
1830/* XVM will do 18b defers if user_mode and G_Mode != 0 */\r
1831\r
1832t_stat Ia (int32 ma, int32 *ea, t_bool jmp)\r
1833{\r
1834int32 gmode, t;\r
1835int32 damask = memm? B_DAMASK: P_DAMASK;\r
1836static const int32 g_mask[4] = { MM_G_W0, MM_G_W1, MM_G_W2, MM_G_W3 };\r
1837t_stat sta = MM_OK;\r
1838\r
1839if ((ma & damask & ~07) == 010) { /* autoincrement? */\r
1840 ma = ma & 017; /* always in bank 0 */\r
1841 Read (ma, &t, DF); /* +1 before use */\r
1842 t = (t + 1) & DMASK;\r
1843 sta = Write (ma, t, DF);\r
1844 }\r
1845else sta = Read (ma, &t, DF);\r
1846if (rest_pending) { /* restore pending? */\r
1847 LAC = ((t << 1) & LINK) | (LAC & DMASK); /* restore L */\r
1848 memm = (t >> 16) & 1; /* restore bank */\r
1849 usmd = usmd_buf = (t >> 15) & 1; /* restore user */\r
1850 emir_pending = rest_pending = 0;\r
1851 }\r
1852gmode = MM_GETGM (MMR); /* get G_mode */\r
1853if (usmd && XVM && gmode) /* XVM user mode? */\r
1854 *ea = t & g_mask[gmode]; /* mask ia to size */\r
1855else if ((ma & damask & ~07) == 010) *ea = t & DMASK; /* autoindex? */\r
1856else *ea = (PC & BLKMASK) | (t & IAMASK); /* within 32K */\r
1857return sta;\r
1858}\r
1859\r
1860t_stat Incr_addr (int32 ma)\r
1861{\r
1862if (memm) return ((ma & B_EPCMASK) | ((ma + 1) & B_DAMASK));\r
1863return ((ma & P_EPCMASK) | ((ma + 1) & P_DAMASK));\r
1864}\r
1865\r
1866/* XVM will store all 18b of PC if user mode and G_mode != 0 */\r
1867\r
1868int32 Jms_word (int32 t)\r
1869{\r
1870if (usmd && XVM && (MMR & MM_GM)) return PC;\r
1871return (((LAC & LINK) >> 1) | ((memm & 1) << 16) |\r
1872 ((t & 1) << 15) | (PC & IAMASK));\r
1873}\r
1874\r
1875/* PDP-15 protection (KM15 option) */\r
1876\r
1877int32 Prot15 (int32 ma, t_bool bndchk)\r
1878{\r
1879ma = ma & AMASK; /* 17b addressing */\r
1880if (!MEM_ADDR_OK (ma)) { /* nxm? */\r
1881 nexm = prvn = trap_pending = 1; /* set flags, trap */\r
1882 return -1;\r
1883 }\r
1884if (bndchk && (ma < BR)) { /* boundary viol? */\r
1885 prvn = trap_pending = 1; /* set flag, trap */\r
1886 return -1;\r
1887 }\r
1888return ma; /* no relocation */\r
1889}\r
1890\r
1891/* PDP-15 relocation and protection (KT15 option) */\r
1892\r
1893int32 Reloc15 (int32 ma, int32 rc)\r
1894{\r
1895int32 pa;\r
1896\r
1897ma = ma & AMASK; /* 17b addressing */\r
1898if (ma > (BR | 0377)) { /* boundary viol? */\r
1899 if (rc != REL_C) prvn = trap_pending = 1; /* set flag, trap */\r
1900 return -1;\r
1901 }\r
1902pa = (ma + RR) & AMASK; /* relocate address */\r
1903if (!MEM_ADDR_OK (pa)) { /* nxm? */\r
1904 if (rc != REL_C) nexm = prvn = trap_pending = 1; /* set flags, trap */\r
1905 return -1;\r
1906 }\r
1907return pa;\r
1908}\r
1909\r
1910/* XVM relocation and protection option */\r
1911\r
1912int32 RelocXVM (int32 ma, int32 rc)\r
1913{\r
1914int32 pa, gmode, slr;\r
1915static const int32 g_base[4] = { MM_G_B0, MM_G_B1, MM_G_B2, MM_G_B3 };\r
1916static const int32 slr_lnt[4] = { MM_SLR_L0, MM_SLR_L1, MM_SLR_L2, MM_SLR_L3 };\r
1917\r
1918gmode = MM_GETGM (MMR); /* get G_mode */\r
1919slr = MM_GETSLR (MMR); /* get segment length */\r
1920if (MMR & MM_RDIS) pa = ma; /* reloc disabled? */\r
1921else if ((MMR & MM_SH) && /* shared enabled and */\r
1922 (ma >= g_base[gmode]) && /* >= shared base and */\r
1923 (ma < (g_base[gmode] + slr_lnt[slr]))) { /* < shared end? */\r
1924 if (ma & 017400) { /* ESAS? */\r
1925 if ((rc == REL_W) && (MMR & MM_WP)) { /* write and protected? */\r
1926 prvn = trap_pending = 1; /* set flag, trap */\r
1927 return -1;\r
1928 }\r
1929 pa = (((MMR & MM_SBR_MASK) << 8) + ma) & DMASK; /* ESAS reloc */\r
1930 }\r
1931 else pa = RR + (ma & 0377); /* no, ISAS reloc */\r
1932 }\r
1933else {\r
1934 if (ma > (BR | 0377)) { /* normal reloc, viol? */\r
1935 if (rc != REL_C) prvn = trap_pending = 1; /* set flag, trap */\r
1936 return -1;\r
1937 }\r
1938 pa = (RR + ma) & DMASK; /* relocate address */\r
1939 }\r
1940if (!MEM_ADDR_OK (pa)) { /* nxm? */\r
1941 if (rc != REL_C) nexm = prvn = trap_pending = 1; /* set flags, trap */\r
1942 return -1;\r
1943 }\r
1944return pa;\r
1945}\r
1946\r
1947#endif\r
1948\r
1949/* Reset routine */\r
1950\r
1951t_stat cpu_reset (DEVICE *dptr)\r
1952{\r
1953LAC = 0;\r
1954MQ = 0;\r
1955SC = 0;\r
1956eae_ac_sign = 0;\r
1957ion = ion_defer = ion_inh = 0;\r
1958CLR_INT (PWRFL);\r
1959api_enb = api_req = api_act = 0;\r
1960BR = 0;\r
1961RR = 0;\r
1962MMR = 0;\r
1963usmd = usmd_buf = usmd_defer = 0;\r
1964memm = memm_init;\r
1965nexm = prvn = trap_pending = 0;\r
1966emir_pending = rest_pending = 0;\r
1967pcq_r = find_reg ("PCQ", NULL, dptr);\r
1968if (pcq_r) pcq_r->qptr = 0;\r
1969else return SCPE_IERR;\r
1970sim_brk_types = sim_brk_dflt = SWMASK ('E');\r
1971return SCPE_OK;\r
1972}\r
1973\r
1974/* CAF routine (CPU reset isn't called by CAF) */\r
1975\r
1976void cpu_caf (void)\r
1977{\r
1978api_enb = api_req = api_act = 0; /* reset API system */\r
1979nexm = prvn = trap_pending = 0; /* reset MM system */\r
1980usmd = usmd_buf = usmd_defer = 0;\r
1981MMR = 0;\r
1982return;\r
1983}\r
1984\r
1985/* Memory examine */\r
1986\r
1987t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r
1988{\r
1989#if defined (PDP15)\r
1990if (usmd && (sw & SWMASK ('V'))) {\r
1991 if (XVM) addr = RelocXVM (addr, REL_C);\r
1992 else if (RELOC) addr = Reloc15 (addr, REL_C);\r
1993 if ((int32) addr < 0) return STOP_MME;\r
1994 }\r
1995#endif\r
1996if (addr >= MEMSIZE) return SCPE_NXM;\r
1997if (vptr != NULL) *vptr = M[addr] & DMASK;\r
1998return SCPE_OK;\r
1999}\r
2000\r
2001/* Memory deposit */\r
2002\r
2003t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r
2004{\r
2005#if defined (PDP15)\r
2006if (usmd && (sw & SWMASK ('V'))) {\r
2007 if (XVM) addr = RelocXVM (addr, REL_C);\r
2008 else if (RELOC) addr = Reloc15 (addr, REL_C);\r
2009 if ((int32) addr < 0) return STOP_MME;\r
2010 }\r
2011#endif\r
2012if (addr >= MEMSIZE) return SCPE_NXM;\r
2013M[addr] = val & DMASK;\r
2014return SCPE_OK;\r
2015}\r
2016\r
2017/* Change memory size */\r
2018\r
2019t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r
2020{\r
2021int32 mc = 0;\r
2022uint32 i;\r
2023\r
2024if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))\r
2025 return SCPE_ARG;\r
2026for (i = val; i < MEMSIZE; i++) mc = mc | M[i];\r
2027if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r
2028 return SCPE_OK;\r
2029MEMSIZE = val;\r
2030for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;\r
2031return SCPE_OK;\r
2032}\r
2033\r
2034/* Change device number for a device */\r
2035\r
2036t_stat set_devno (UNIT *uptr, int32 val, char *cptr, void *desc)\r
2037{\r
2038DEVICE *dptr;\r
2039DIB *dibp;\r
2040uint32 newdev;\r
2041t_stat r;\r
2042\r
2043if (cptr == NULL) return SCPE_ARG;\r
2044if (uptr == NULL) return SCPE_IERR;\r
2045dptr = find_dev_from_unit (uptr);\r
2046if (dptr == NULL) return SCPE_IERR;\r
2047dibp = (DIB *) dptr->ctxt;\r
2048if (dibp == NULL) return SCPE_IERR;\r
2049newdev = get_uint (cptr, 8, DEV_MAX - 1, &r); /* get new */\r
2050if ((r != SCPE_OK) || (newdev == dibp->dev)) return r;\r
2051dibp->dev = newdev; /* store */\r
2052return SCPE_OK;\r
2053}\r
2054\r
2055/* Show device number for a device */\r
2056\r
2057t_stat show_devno (FILE *st, UNIT *uptr, int32 val, void *desc)\r
2058{\r
2059DEVICE *dptr;\r
2060DIB *dibp;\r
2061\r
2062if (uptr == NULL) return SCPE_IERR;\r
2063dptr = find_dev_from_unit (uptr);\r
2064if (dptr == NULL) return SCPE_IERR;\r
2065dibp = (DIB *) dptr->ctxt;\r
2066if (dibp == NULL) return SCPE_IERR;\r
2067fprintf (st, "devno=%02o", dibp->dev);\r
2068if (dibp->num > 1) fprintf (st, "-%2o", dibp->dev + dibp->num - 1);\r
2069return SCPE_OK;\r
2070}\r
2071\r
2072/* CPU device handler - should never get here! */\r
2073\r
2074int32 bad_dev (int32 dev, int32 pulse, int32 AC)\r
2075{\r
2076return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */\r
2077}\r
2078\r
2079/* Build device dispatch table */\r
2080\r
2081t_bool build_dev_tab (void)\r
2082{\r
2083DEVICE *dptr;\r
2084DIB *dibp;\r
2085uint32 i, j, p;\r
2086static const uint8 std_dev[] =\r
2087#if defined (PDP4)\r
2088 { 000 };\r
2089#elif defined (PDP7)\r
2090 { 000, 033, 077 };\r
2091#else\r
2092 { 000, 017, 033, 055, 077 };\r
2093#endif\r
2094\r
2095for (i = 0; i < DEV_MAX; i++) { /* clr tables */\r
2096 dev_tab[i] = NULL;\r
2097 dev_iors[i] = NULL;\r
2098 }\r
2099for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */\r
2100 dev_tab[std_dev[i]] = &bad_dev;\r
2101for (i = p = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */\r
2102 dibp = (DIB *) dptr->ctxt; /* get DIB */\r
2103 if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */\r
2104 if (dibp->iors) dev_iors[p++] = dibp->iors; /* if IORS, add */\r
2105 for (j = 0; j < dibp->num; j++) { /* loop thru disp */\r
2106 if (dibp->dsp[j]) { /* any dispatch? */\r
2107 if (dev_tab[dibp->dev + j]) { /* already filled? */\r
2108 printf ("%s device number conflict at %02o\n",\r
2109 sim_dname (dptr), dibp->dev + j);\r
2110 if (sim_log) fprintf (sim_log,\r
2111 "%s device number conflict at %02o\n",\r
2112 sim_dname (dptr), dibp->dev + j);\r
2113 return TRUE;\r
2114 }\r
2115 dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */\r
2116 } /* end if dsp */\r
2117 } /* end for j */\r
2118 } /* end if enb */\r
2119 } /* end for i */\r
2120return FALSE;\r
2121}\r
2122\r
2123/* Set history */\r
2124\r
2125t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)\r
2126{\r
2127int32 i, lnt;\r
2128t_stat r;\r
2129\r
2130if (cptr == NULL) {\r
2131 for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;\r
2132 hst_p = 0;\r
2133 return SCPE_OK;\r
2134 }\r
2135lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);\r
2136if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;\r
2137hst_p = 0;\r
2138if (hst_lnt) {\r
2139 free (hst);\r
2140 hst_lnt = 0;\r
2141 hst = NULL;\r
2142 }\r
2143if (lnt) {\r
2144 hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));\r
2145 if (hst == NULL) return SCPE_MEM;\r
2146 hst_lnt = lnt;\r
2147 }\r
2148return SCPE_OK;\r
2149}\r
2150\r
2151/* Show history */\r
2152\r
2153t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)\r
2154{\r
2155int32 l, j, k, di, lnt;\r
2156char *cptr = (char *) desc;\r
2157t_value sim_eval[2];\r
2158t_stat r;\r
2159InstHistory *h;\r
2160extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,\r
2161 UNIT *uptr, int32 sw);\r
2162\r
2163if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */\r
2164if (cptr) {\r
2165 lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);\r
2166 if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG;\r
2167 }\r
2168else lnt = hst_lnt;\r
2169di = hst_p - lnt; /* work forward */\r
2170if (di < 0) di = di + hst_lnt;\r
2171fprintf (st, "PC L AC MQ IR\n\n");\r
2172for (k = 0; k < lnt; k++) { /* print specified */\r
2173 h = &hst[(di++) % hst_lnt]; /* entry pointer */\r
2174 if (h->pc & HIST_PC) { /* instruction? */\r
2175 l = (h->lac >> 18) & 1; /* link */\r
2176 fprintf (st, "%06o %o %06o %06o ", h->pc & AMASK, l, h->lac & DMASK, h->mq);\r
2177 sim_eval[0] = h->ir;\r
2178 sim_eval[1] = h->ir1;\r
2179 if ((fprint_sym (st, h->pc & AMASK, sim_eval, &cpu_unit, SWMASK ('M'))) > 0)\r
2180 fprintf (st, "(undefined) %06o", h->ir);\r
2181 } /* end else instruction */\r
2182 else if (h->pc & (HIST_API | HIST_PI)) { /* interrupt event? */\r
2183 if (h->pc & HIST_PI) /* PI? */\r
2184 fprintf (st, "%06o PI LVL 0-4 =", h->pc & AMASK);\r
2185 else fprintf (st, "%06o API %d LVL 0-4 =", h->pc & AMASK, h->mq);\r
2186 for (j = API_HLVL; j >= 0; j--)\r
2187 fprintf (st, " %02o", (h->ir >> (j * HIST_V_LVL)) & HIST_M_LVL);\r
2188 }\r
2189 else continue; /* invalid */\r
2190 fputc ('\n', st); /* end line */\r
2191 } /* end for */\r
2192return SCPE_OK;\r
2193}\r
2194\r
2195/* Record events in history table */\r
2196\r
2197void cpu_inst_hist (int32 addr, int32 inst)\r
2198{\r
2199t_value word = 0;\r
2200\r
2201hst[hst_p].pc = addr | HIST_PC;\r
2202hst[hst_p].ir = inst;\r
2203if (cpu_ex (&word, (addr + 1) & AMASK, &cpu_unit, SWMASK ('V')))\r
2204 hst[hst_p].ir1 = 0;\r
2205else hst[hst_p].ir1 = word;\r
2206hst[hst_p].lac = LAC;\r
2207hst[hst_p].mq = MQ;\r
2208hst_p = (hst_p + 1);\r
2209if (hst_p >= hst_lnt) hst_p = 0;\r
2210return;\r
2211}\r
2212\r
2213void cpu_intr_hist (int32 flag, int32 lvl)\r
2214{\r
2215int32 j;\r
2216\r
2217hst[hst_p].pc = PC | flag;\r
2218hst[hst_p].ir = 0;\r
2219for (j = 0; j < API_HLVL+1; j++) hst[hst_p].ir = \r
2220 (hst[hst_p].ir << HIST_V_LVL) | (int_hwre[j] & HIST_M_LVL);\r
2221hst[hst_p].ir1 = 0;\r
2222hst[hst_p].lac = 0;\r
2223hst[hst_p].mq = lvl;\r
2224hst_p = (hst_p + 1);\r
2225if (hst_p >= hst_lnt) hst_p = 0;\r
2226return;\r
2227}\r