Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* pdp8_cpu.c: PDP-8 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 central processor\r | |
27 | \r | |
28 | 28-Apr-07 RMS Removed clock initialization\r | |
29 | 30-Oct-06 RMS Added idle and infinite loop detection\r | |
30 | 30-Sep-06 RMS Fixed SC value after DVI overflow (found by Don North)\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 | 06-Nov-04 RMS Added =n to SHOW HISTORY\r | |
34 | 31-Dec-03 RMS Fixed bug in set_cpu_hist\r | |
35 | 13-Oct-03 RMS Added instruction history\r | |
36 | Added TSC8-75 support (from Bernhard Baehr)\r | |
37 | 12-Mar-03 RMS Added logical name support\r | |
38 | 04-Oct-02 RMS Revamped device dispatching, added device number support\r | |
39 | 06-Jan-02 RMS Added device enable/disable routines\r | |
40 | 30-Dec-01 RMS Added old PC queue\r | |
41 | 16-Dec-01 RMS Fixed bugs in EAE\r | |
42 | 07-Dec-01 RMS Revised to use new breakpoint package\r | |
43 | 30-Nov-01 RMS Added RL8A, extended SET/SHOW support\r | |
44 | 16-Sep-01 RMS Fixed bug in reset routine, added KL8A support\r | |
45 | 10-Aug-01 RMS Removed register from declarations\r | |
46 | 17-Jul-01 RMS Moved function prototype\r | |
47 | 07-Jun-01 RMS Fixed bug in JMS to non-existent memory\r | |
48 | 25-Apr-01 RMS Added device enable/disable support\r | |
49 | 18-Mar-01 RMS Added DF32 support\r | |
50 | 05-Mar-01 RMS Added clock calibration support\r | |
51 | 15-Feb-01 RMS Added DECtape support\r | |
52 | 14-Apr-99 RMS Changed t_addr to unsigned\r | |
53 | \r | |
54 | The register state for the PDP-8 is:\r | |
55 | \r | |
56 | AC<0:11> accumulator\r | |
57 | MQ<0:11> multiplier-quotient\r | |
58 | L link flag\r | |
59 | PC<0:11> program counter\r | |
60 | IF<0:2> instruction field\r | |
61 | IB<0:2> instruction buffer\r | |
62 | DF<0:2> data field\r | |
63 | UF user flag\r | |
64 | UB user buffer\r | |
65 | SF<0:6> interrupt save field\r | |
66 | \r | |
67 | The PDP-8 has three instruction formats: memory reference, I/O transfer,\r | |
68 | and operate. The memory reference format is:\r | |
69 | \r | |
70 | 0 1 2 3 4 5 6 7 8 9 10 11\r | |
71 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
72 | | op |in|zr| page offset | memory reference\r | |
73 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
74 | \r | |
75 | <0:2> mnemonic action\r | |
76 | \r | |
77 | 000 AND AC = AC & M[MA]\r | |
78 | 001 TAD L'AC = AC + M[MA]\r | |
79 | 010 DCA M[MA] = AC, AC = 0\r | |
80 | 011 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0\r | |
81 | 100 JMS M[MA] = PC, PC = MA + 1\r | |
82 | 101 JMP PC = MA\r | |
83 | \r | |
84 | <3:4> mode action\r | |
85 | 00 page zero MA = IF'0'IR<5:11>\r | |
86 | 01 current page MA = IF'PC<0:4>'IR<5:11>\r | |
87 | 10 indirect page zero MA = xF'M[IF'0'IR<5:11>]\r | |
88 | 11 indirect current page MA = xF'M[IF'PC<0:4>'IR<5:11>]\r | |
89 | \r | |
90 | where x is D for AND, TAD, ISZ, DCA, and I for JMS, JMP.\r | |
91 | \r | |
92 | Memory reference instructions can access an address space of 32K words.\r | |
93 | The address space is divided into eight 4K word fields; each field is\r | |
94 | divided into thirty-two 128 word pages. An instruction can directly\r | |
95 | address, via its 7b offset, locations 0-127 on page zero or on the current\r | |
96 | page. All 32k words can be accessed via indirect addressing and the\r | |
97 | instruction and data field registers. If an indirect address is in\r | |
98 | locations 0010-0017 of any field, the indirect address is incremented\r | |
99 | and rewritten to memory before use.\r | |
100 | \r | |
101 | The I/O transfer format is as follows:\r | |
102 | \r | |
103 | 0 1 2 3 4 5 6 7 8 9 10 11\r | |
104 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
105 | | op | device | pulse | I/O transfer\r | |
106 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
107 | \r | |
108 | The IO transfer instruction sends the the specified pulse to the\r | |
109 | specified I/O device. The I/O device may take data from the AC,\r | |
110 | return data to the AC, initiate or cancel operations, or skip on\r | |
111 | status.\r | |
112 | \r | |
113 | The operate format is as follows:\r | |
114 | \r | |
115 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
116 | | 1| 1| 1| 0| | | | | | | | | operate group 1\r | |
117 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
118 | | | | | | | | |\r | |
119 | | | | | | | | +--- increment AC 3\r | |
120 | | | | | | | +--- rotate 1 or 2 4\r | |
121 | | | | | | +--- rotate left 4\r | |
122 | | | | | +--- rotate right 4\r | |
123 | | | | +--- complement L 2\r | |
124 | | | +--- complement AC 2\r | |
125 | | +--- clear L 1\r | |
126 | +-- clear AC 1\r | |
127 | \r | |
128 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
129 | | 1| 1| 1| 1| | | | | | | | 0| operate group 2\r | |
130 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
131 | | | | | | | |\r | |
132 | | | | | | | +--- halt 3\r | |
133 | | | | | | +--- or switch register 3\r | |
134 | | | | | +--- reverse skip sense 1\r | |
135 | | | | +--- skip on L != 0 1\r | |
136 | | | +--- skip on AC == 0 1\r | |
137 | | +--- skip on AC < 0 1\r | |
138 | +-- clear AC 2\r | |
139 | \r | |
140 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
141 | | 1| 1| 1| 1| | | | | | | | 1| operate group 3\r | |
142 | +--+--+--+--+--+--+--+--+--+--+--+--+\r | |
143 | | | | | \______/\r | |
144 | | | | | |\r | |
145 | | | +--|-----+--- EAE command 3\r | |
146 | | | +--- AC -> MQ, 0 -> AC 2\r | |
147 | | +--- MQ v AC --> AC 2\r | |
148 | +-- clear AC 1\r | |
149 | \r | |
150 | The operate instruction can be microprogrammed to perform operations\r | |
151 | on the AC, MQ, and link.\r | |
152 | \r | |
153 | This routine is the instruction decode routine for the PDP-8.\r | |
154 | It is called from the simulator control program to execute\r | |
155 | instructions in simulated memory, starting at the simulated PC.\r | |
156 | It runs until 'reason' is set non-zero.\r | |
157 | \r | |
158 | General notes:\r | |
159 | \r | |
160 | 1. Reasons to stop. The simulator can be stopped by:\r | |
161 | \r | |
162 | HALT instruction\r | |
163 | breakpoint encountered\r | |
164 | unimplemented instruction and stop_inst flag set\r | |
165 | I/O error in I/O simulator\r | |
166 | \r | |
167 | 2. Interrupts. Interrupts are maintained by three parallel variables:\r | |
168 | \r | |
169 | dev_done device done flags\r | |
170 | int_enable interrupt enable flags\r | |
171 | int_req interrupt requests\r | |
172 | \r | |
173 | In addition, int_req contains the interrupt enable flag, the\r | |
174 | CIF not pending flag, and the ION not pending flag. If all\r | |
175 | three of these flags are set, and at least one interrupt request\r | |
176 | is set, then an interrupt occurs.\r | |
177 | \r | |
178 | 3. Non-existent memory. On the PDP-8, reads to non-existent memory\r | |
179 | return zero, and writes are ignored. In the simulator, the\r | |
180 | largest possible memory is instantiated and initialized to zero.\r | |
181 | Thus, only writes outside the current field (indirect writes) need\r | |
182 | be checked against actual memory size.\r | |
183 | \r | |
184 | 3. Adding I/O devices. These modules must be modified:\r | |
185 | \r | |
186 | pdp8_defs.h add device number and interrupt definitions\r | |
187 | pdp8_sys.c add sim_devices table entry\r | |
188 | */\r | |
189 | \r | |
190 | #include "pdp8_defs.h"\r | |
191 | \r | |
192 | #define PCQ_SIZE 64 /* must be 2**n */\r | |
193 | #define PCQ_MASK (PCQ_SIZE - 1)\r | |
194 | #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = MA\r | |
195 | #define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */\r | |
196 | #define UNIT_NOEAE (1 << UNIT_V_NOEAE)\r | |
197 | #define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy mask */\r | |
198 | #define UNIT_MSIZE (1 << UNIT_V_MSIZE)\r | |
199 | #define OP_KSF 06031 /* for idle */\r | |
200 | \r | |
201 | #define HIST_PC 0x40000000\r | |
202 | #define HIST_MIN 64\r | |
203 | #define HIST_MAX 65536\r | |
204 | \r | |
205 | typedef struct {\r | |
206 | int32 pc;\r | |
207 | int32 ea;\r | |
208 | int16 ir;\r | |
209 | int16 opnd;\r | |
210 | int16 lac;\r | |
211 | int16 mq;\r | |
212 | } InstHistory;\r | |
213 | \r | |
214 | uint16 M[MAXMEMSIZE] = { 0 }; /* main memory */\r | |
215 | int32 saved_LAC = 0; /* saved L'AC */\r | |
216 | int32 saved_MQ = 0; /* saved MQ */\r | |
217 | int32 saved_PC = 0; /* saved IF'PC */\r | |
218 | int32 saved_DF = 0; /* saved Data Field */\r | |
219 | int32 IB = 0; /* Instruction Buffer */\r | |
220 | int32 SF = 0; /* Save Field */\r | |
221 | int32 emode = 0; /* EAE mode */\r | |
222 | int32 gtf = 0; /* EAE gtf flag */\r | |
223 | int32 SC = 0; /* EAE shift count */\r | |
224 | int32 UB = 0; /* User mode Buffer */\r | |
225 | int32 UF = 0; /* User mode Flag */\r | |
226 | int32 OSR = 0; /* Switch Register */\r | |
227 | int32 tsc_ir = 0; /* TSC8-75 IR */\r | |
228 | int32 tsc_pc = 0; /* TSC8-75 PC */\r | |
229 | int32 tsc_cdf = 0; /* TSC8-75 CDF flag */\r | |
230 | int32 tsc_enb = 0; /* TSC8-75 enabled */\r | |
231 | int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r | |
232 | int32 pcq_p = 0; /* PC queue ptr */\r | |
233 | REG *pcq_r = NULL; /* PC queue reg ptr */\r | |
234 | int32 dev_done = 0; /* dev done flags */\r | |
235 | int32 int_enable = INT_INIT_ENABLE; /* intr enables */\r | |
236 | int32 int_req = 0; /* intr requests */\r | |
237 | int32 stop_inst = 0; /* trap on ill inst */\r | |
238 | int32 (*dev_tab[DEV_MAX])(int32 IR, int32 dat); /* device dispatch */\r | |
239 | int32 hst_p = 0; /* history pointer */\r | |
240 | int32 hst_lnt = 0; /* history length */\r | |
241 | InstHistory *hst = NULL; /* instruction history */\r | |
242 | \r | |
243 | extern int32 sim_interval;\r | |
244 | extern int32 sim_int_char;\r | |
245 | extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r | |
246 | extern DEVICE *sim_devices[];\r | |
247 | extern FILE *sim_log;\r | |
248 | extern t_bool sim_idle_enab;\r | |
249 | \r | |
250 | t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r | |
251 | t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r | |
252 | t_stat cpu_reset (DEVICE *dptr);\r | |
253 | t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
254 | t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
255 | t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
256 | t_bool build_dev_tab (void);\r | |
257 | \r | |
258 | /* CPU data structures\r | |
259 | \r | |
260 | cpu_dev CPU device descriptor\r | |
261 | cpu_unit CPU unit descriptor\r | |
262 | cpu_reg CPU register list\r | |
263 | cpu_mod CPU modifier list\r | |
264 | */\r | |
265 | \r | |
266 | UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };\r | |
267 | \r | |
268 | REG cpu_reg[] = {\r | |
269 | { ORDATA (PC, saved_PC, 15) },\r | |
270 | { ORDATA (AC, saved_LAC, 12) },\r | |
271 | { FLDATA (L, saved_LAC, 12) },\r | |
272 | { ORDATA (MQ, saved_MQ, 12) },\r | |
273 | { ORDATA (SR, OSR, 12) },\r | |
274 | { GRDATA (IF, saved_PC, 8, 3, 12) },\r | |
275 | { GRDATA (DF, saved_DF, 8, 3, 12) },\r | |
276 | { GRDATA (IB, IB, 8, 3, 12) },\r | |
277 | { ORDATA (SF, SF, 7) },\r | |
278 | { FLDATA (UB, UB, 0) },\r | |
279 | { FLDATA (UF, UF, 0) },\r | |
280 | { ORDATA (SC, SC, 5) },\r | |
281 | { FLDATA (GTF, gtf, 0) },\r | |
282 | { FLDATA (EMODE, emode, 0) },\r | |
283 | { FLDATA (ION, int_req, INT_V_ION) },\r | |
284 | { FLDATA (ION_DELAY, int_req, INT_V_NO_ION_PENDING) },\r | |
285 | { FLDATA (CIF_DELAY, int_req, INT_V_NO_CIF_PENDING) },\r | |
286 | { FLDATA (PWR_INT, int_req, INT_V_PWR) },\r | |
287 | { FLDATA (UF_INT, int_req, INT_V_UF) },\r | |
288 | { ORDATA (INT, int_req, INT_V_ION+1), REG_RO },\r | |
289 | { ORDATA (DONE, dev_done, INT_V_DIRECT), REG_RO },\r | |
290 | { ORDATA (ENABLE, int_enable, INT_V_DIRECT), REG_RO },\r | |
291 | { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC },\r | |
292 | { ORDATA (PCQP, pcq_p, 6), REG_HRO },\r | |
293 | { FLDATA (STOP_INST, stop_inst, 0) },\r | |
294 | { ORDATA (WRU, sim_int_char, 8) },\r | |
295 | { NULL }\r | |
296 | };\r | |
297 | \r | |
298 | MTAB cpu_mod[] = {\r | |
299 | { UNIT_NOEAE, UNIT_NOEAE, "no EAE", "NOEAE", NULL },\r | |
300 | { UNIT_NOEAE, 0, "EAE", "EAE", NULL },\r | |
301 | { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },\r | |
302 | { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },\r | |
303 | { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },\r | |
304 | { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },\r | |
305 | { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },\r | |
306 | { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },\r | |
307 | { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },\r | |
308 | { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },\r | |
309 | { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },\r | |
310 | { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },\r | |
311 | { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",\r | |
312 | &cpu_set_hist, &cpu_show_hist },\r | |
313 | { 0 }\r | |
314 | };\r | |
315 | \r | |
316 | DEVICE cpu_dev = {\r | |
317 | "CPU", &cpu_unit, cpu_reg, cpu_mod,\r | |
318 | 1, 8, 15, 1, 8, 12,\r | |
319 | &cpu_ex, &cpu_dep, &cpu_reset,\r | |
320 | NULL, NULL, NULL,\r | |
321 | NULL, 0\r | |
322 | };\r | |
323 | \r | |
324 | t_stat sim_instr (void)\r | |
325 | {\r | |
326 | int32 IR, MB, IF, DF, LAC, MQ;\r | |
327 | uint32 PC, MA;\r | |
328 | int32 device, pulse, temp, iot_data;\r | |
329 | t_stat reason;\r | |
330 | \r | |
331 | /* Restore register state */\r | |
332 | \r | |
333 | if (build_dev_tab ()) return SCPE_STOP; /* build dev_tab */\r | |
334 | PC = saved_PC & 007777; /* load local copies */\r | |
335 | IF = saved_PC & 070000;\r | |
336 | DF = saved_DF & 070000;\r | |
337 | LAC = saved_LAC & 017777;\r | |
338 | MQ = saved_MQ & 07777;\r | |
339 | int_req = INT_UPDATE;\r | |
340 | reason = 0;\r | |
341 | \r | |
342 | /* Main instruction fetch/decode loop */\r | |
343 | \r | |
344 | while (reason == 0) { /* loop until halted */\r | |
345 | \r | |
346 | if (sim_interval <= 0) { /* check clock queue */\r | |
347 | if (reason = sim_process_event ()) break;\r | |
348 | }\r | |
349 | \r | |
350 | if (int_req > INT_PENDING) { /* interrupt? */\r | |
351 | int_req = int_req & ~INT_ION; /* interrupts off */\r | |
352 | SF = (UF << 6) | (IF >> 9) | (DF >> 12); /* form save field */\r | |
353 | IF = IB = DF = UF = UB = 0; /* clear mem ext */\r | |
354 | PCQ_ENTRY; /* save old PC */\r | |
355 | M[0] = PC; /* save PC in 0 */\r | |
356 | PC = 1; /* fetch next from 1 */\r | |
357 | }\r | |
358 | \r | |
359 | MA = IF | PC; /* form PC */\r | |
360 | if (sim_brk_summ && sim_brk_test (MA, SWMASK ('E'))) { /* breakpoint? */\r | |
361 | reason = STOP_IBKPT; /* stop simulation */\r | |
362 | break;\r | |
363 | }\r | |
364 | \r | |
365 | IR = M[MA]; /* fetch instruction */\r | |
366 | PC = (PC + 1) & 07777; /* increment PC */\r | |
367 | int_req = int_req | INT_NO_ION_PENDING; /* clear ION delay */\r | |
368 | sim_interval = sim_interval - 1;\r | |
369 | \r | |
370 | /* Instruction decoding.\r | |
371 | \r | |
372 | The opcode (IR<0:2>), indirect flag (IR<3>), and page flag (IR<4>)\r | |
373 | are decoded together. This produces 32 decode points, four per\r | |
374 | major opcode. For IOT, the extra decode points are not useful;\r | |
375 | for OPR, only the group flag (IR<3>) is used.\r | |
376 | \r | |
377 | AND, TAD, ISZ, DCA calculate a full 15b effective address.\r | |
378 | JMS, JMP calculate a 12b field-relative effective address.\r | |
379 | \r | |
380 | Autoindex calculations always occur within the same field as the\r | |
381 | instruction fetch. The field must exist; otherwise, the instruction\r | |
382 | fetched would be 0000, and indirect addressing could not occur.\r | |
383 | \r | |
384 | Note that MA contains IF'PC.\r | |
385 | */\r | |
386 | \r | |
387 | if (hst_lnt) { /* history enabled? */\r | |
388 | int32 ea;\r | |
389 | \r | |
390 | hst_p = (hst_p + 1); /* next entry */\r | |
391 | if (hst_p >= hst_lnt) hst_p = 0;\r | |
392 | hst[hst_p].pc = MA | HIST_PC; /* save PC, IR, LAC, MQ */\r | |
393 | hst[hst_p].ir = IR;\r | |
394 | hst[hst_p].lac = LAC;\r | |
395 | hst[hst_p].mq = MQ;\r | |
396 | if (IR < 06000) { /* mem ref? */\r | |
397 | if (IR & 0200) ea = (MA & 077600) | (IR & 0177);\r | |
398 | else ea = IF | (IR & 0177); /* direct addr */\r | |
399 | if (IR & 0400) { /* indirect? */\r | |
400 | if (IR < 04000) { /* mem operand? */\r | |
401 | if ((ea & 07770) != 00010) ea = DF | M[ea];\r | |
402 | else ea = DF | ((M[ea] + 1) & 07777);\r | |
403 | }\r | |
404 | else { /* no, jms/jmp */\r | |
405 | if ((ea & 07770) != 00010) ea = IB | M[ea];\r | |
406 | else ea = IB | ((M[ea] + 1) & 07777);\r | |
407 | }\r | |
408 | }\r | |
409 | hst[hst_p].ea = ea; /* save eff addr */\r | |
410 | hst[hst_p].opnd = M[ea]; /* save operand */\r | |
411 | }\r | |
412 | }\r | |
413 | \r | |
414 | switch ((IR >> 7) & 037) { /* decode IR<0:4> */\r | |
415 | \r | |
416 | /* Opcode 0, AND */\r | |
417 | \r | |
418 | case 000: /* AND, dir, zero */\r | |
419 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
420 | LAC = LAC & (M[MA] | 010000);\r | |
421 | break;\r | |
422 | \r | |
423 | case 001: /* AND, dir, curr */\r | |
424 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
425 | LAC = LAC & (M[MA] | 010000);\r | |
426 | break;\r | |
427 | \r | |
428 | case 002: /* AND, indir, zero */\r | |
429 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
430 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
431 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
432 | LAC = LAC & (M[MA] | 010000);\r | |
433 | break;\r | |
434 | \r | |
435 | case 003: /* AND, indir, curr */\r | |
436 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
437 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
438 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
439 | LAC = LAC & (M[MA] | 010000);\r | |
440 | break;\r | |
441 | \r | |
442 | /* Opcode 1, TAD */\r | |
443 | \r | |
444 | case 004: /* TAD, dir, zero */\r | |
445 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
446 | LAC = (LAC + M[MA]) & 017777;\r | |
447 | break;\r | |
448 | \r | |
449 | case 005: /* TAD, dir, curr */\r | |
450 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
451 | LAC = (LAC + M[MA]) & 017777;\r | |
452 | break;\r | |
453 | \r | |
454 | case 006: /* TAD, indir, zero */\r | |
455 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
456 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
457 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
458 | LAC = (LAC + M[MA]) & 017777;\r | |
459 | break;\r | |
460 | \r | |
461 | case 007: /* TAD, indir, curr */\r | |
462 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
463 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
464 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
465 | LAC = (LAC + M[MA]) & 017777;\r | |
466 | break;\r | |
467 | \r | |
468 | /* Opcode 2, ISZ */\r | |
469 | \r | |
470 | case 010: /* ISZ, dir, zero */\r | |
471 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
472 | M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */\r | |
473 | if (MB == 0) PC = (PC + 1) & 07777;\r | |
474 | break;\r | |
475 | \r | |
476 | case 011: /* ISZ, dir, curr */\r | |
477 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
478 | M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */\r | |
479 | if (MB == 0) PC = (PC + 1) & 07777;\r | |
480 | break;\r | |
481 | \r | |
482 | case 012: /* ISZ, indir, zero */\r | |
483 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
484 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
485 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
486 | MB = (M[MA] + 1) & 07777;\r | |
487 | if (MEM_ADDR_OK (MA)) M[MA] = MB;\r | |
488 | if (MB == 0) PC = (PC + 1) & 07777;\r | |
489 | break;\r | |
490 | \r | |
491 | case 013: /* ISZ, indir, curr */\r | |
492 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
493 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
494 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
495 | MB = (M[MA] + 1) & 07777;\r | |
496 | if (MEM_ADDR_OK (MA)) M[MA] = MB;\r | |
497 | if (MB == 0) PC = (PC + 1) & 07777;\r | |
498 | break;\r | |
499 | \r | |
500 | /* Opcode 3, DCA */\r | |
501 | \r | |
502 | case 014: /* DCA, dir, zero */\r | |
503 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
504 | M[MA] = LAC & 07777;\r | |
505 | LAC = LAC & 010000;\r | |
506 | break;\r | |
507 | \r | |
508 | case 015: /* DCA, dir, curr */\r | |
509 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
510 | M[MA] = LAC & 07777;\r | |
511 | LAC = LAC & 010000;\r | |
512 | break;\r | |
513 | \r | |
514 | case 016: /* DCA, indir, zero */\r | |
515 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
516 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
517 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
518 | if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777;\r | |
519 | LAC = LAC & 010000;\r | |
520 | break;\r | |
521 | \r | |
522 | case 017: /* DCA, indir, curr */\r | |
523 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
524 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
525 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
526 | if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777;\r | |
527 | LAC = LAC & 010000;\r | |
528 | break;\r | |
529 | \r | |
530 | /* Opcode 4, JMS. From Bernhard Baehr's description of the TSC8-75:\r | |
531 | \r | |
532 | (In user mode) the current JMS opcode is moved to the ERIOT register, the ECDF\r | |
533 | flag is cleared. The address of the JMS instruction is loaded into the ERTB\r | |
534 | register and the TSC8-75 I/O flag is raised. When the TSC8-75 is enabled, the\r | |
535 | target addess of the JMS is loaded into PC, but nothing else (loading of IF, UF,\r | |
536 | clearing the interrupt inhibit flag, storing of the return address in the first\r | |
537 | word of the subroutine) happens. When the TSC8-75 is disabled, the JMS is performed\r | |
538 | as usual. */\r | |
539 | \r | |
540 | case 020: /* JMS, dir, zero */\r | |
541 | PCQ_ENTRY;\r | |
542 | MA = IR & 0177; /* dir addr, page zero */\r | |
543 | if (UF) { /* user mode? */\r | |
544 | tsc_ir = IR; /* save instruction */\r | |
545 | tsc_cdf = 0; /* clear flag */\r | |
546 | }\r | |
547 | if (UF && tsc_enb) { /* user mode, TSC enab? */\r | |
548 | tsc_pc = (PC - 1) & 07777; /* save PC */\r | |
549 | int_req = int_req | INT_TSC; /* request intr */\r | |
550 | }\r | |
551 | else { /* normal */\r | |
552 | IF = IB; /* change IF */\r | |
553 | UF = UB; /* change UF */\r | |
554 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r | |
555 | MA = IF | MA;\r | |
556 | if (MEM_ADDR_OK (MA)) M[MA] = PC;\r | |
557 | }\r | |
558 | PC = (MA + 1) & 07777;\r | |
559 | break;\r | |
560 | \r | |
561 | case 021: /* JMS, dir, curr */\r | |
562 | PCQ_ENTRY;\r | |
563 | MA = (MA & 007600) | (IR & 0177); /* dir addr, curr page */\r | |
564 | if (UF) { /* user mode? */\r | |
565 | tsc_ir = IR; /* save instruction */\r | |
566 | tsc_cdf = 0; /* clear flag */\r | |
567 | }\r | |
568 | if (UF && tsc_enb) { /* user mode, TSC enab? */\r | |
569 | tsc_pc = (PC - 1) & 07777; /* save PC */\r | |
570 | int_req = int_req | INT_TSC; /* request intr */\r | |
571 | }\r | |
572 | else { /* normal */\r | |
573 | IF = IB; /* change IF */\r | |
574 | UF = UB; /* change UF */\r | |
575 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r | |
576 | MA = IF | MA;\r | |
577 | if (MEM_ADDR_OK (MA)) M[MA] = PC;\r | |
578 | }\r | |
579 | PC = (MA + 1) & 07777;\r | |
580 | break;\r | |
581 | \r | |
582 | case 022: /* JMS, indir, zero */\r | |
583 | PCQ_ENTRY;\r | |
584 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
585 | if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */\r | |
586 | else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
587 | if (UF) { /* user mode? */\r | |
588 | tsc_ir = IR; /* save instruction */\r | |
589 | tsc_cdf = 0; /* clear flag */\r | |
590 | }\r | |
591 | if (UF && tsc_enb) { /* user mode, TSC enab? */\r | |
592 | tsc_pc = (PC - 1) & 07777; /* save PC */\r | |
593 | int_req = int_req | INT_TSC; /* request intr */\r | |
594 | }\r | |
595 | else { /* normal */\r | |
596 | IF = IB; /* change IF */\r | |
597 | UF = UB; /* change UF */\r | |
598 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r | |
599 | MA = IF | MA;\r | |
600 | if (MEM_ADDR_OK (MA)) M[MA] = PC;\r | |
601 | }\r | |
602 | PC = (MA + 1) & 07777;\r | |
603 | break;\r | |
604 | \r | |
605 | case 023: /* JMS, indir, curr */\r | |
606 | PCQ_ENTRY;\r | |
607 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
608 | if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */\r | |
609 | else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
610 | if (UF) { /* user mode? */\r | |
611 | tsc_ir = IR; /* save instruction */\r | |
612 | tsc_cdf = 0; /* clear flag */\r | |
613 | }\r | |
614 | if (UF && tsc_enb) { /* user mode, TSC enab? */\r | |
615 | tsc_pc = (PC - 1) & 07777; /* save PC */\r | |
616 | int_req = int_req | INT_TSC; /* request intr */\r | |
617 | }\r | |
618 | else { /* normal */\r | |
619 | IF = IB; /* change IF */\r | |
620 | UF = UB; /* change UF */\r | |
621 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r | |
622 | MA = IF | MA;\r | |
623 | if (MEM_ADDR_OK (MA)) M[MA] = PC;\r | |
624 | }\r | |
625 | PC = (MA + 1) & 07777;\r | |
626 | break;\r | |
627 | \r | |
628 | /* Opcode 5, JMP. From Bernhard Baehr's description of the TSC8-75:\r | |
629 | \r | |
630 | (In user mode) the current JMP opcode is moved to the ERIOT register, the ECDF\r | |
631 | flag is cleared. The address of the JMP instruction is loaded into the ERTB\r | |
632 | register and the TSC8-75 I/O flag is raised. Then the JMP is performed as usual\r | |
633 | (including the setting of IF, UF and clearing the interrupt inhibit flag). */\r | |
634 | \r | |
635 | \r | |
636 | case 024: /* JMP, dir, zero */\r | |
637 | PCQ_ENTRY;\r | |
638 | MA = IR & 0177; /* dir addr, page zero */\r | |
639 | if (UF) { /* user mode? */\r | |
640 | tsc_ir = IR; /* save instruction */\r | |
641 | tsc_cdf = 0; /* clear flag */\r | |
642 | if (tsc_enb) { /* TSC8 enabled? */\r | |
643 | tsc_pc = (PC - 1) & 07777; /* save PC */\r | |
644 | int_req = int_req | INT_TSC; /* request intr */\r | |
645 | }\r | |
646 | }\r | |
647 | IF = IB; /* change IF */\r | |
648 | UF = UB; /* change UF */\r | |
649 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r | |
650 | PC = MA;\r | |
651 | break;\r | |
652 | \r | |
653 | /* If JMP direct, also check for idle (KSF/JMP *-1) and infinite loop */\r | |
654 | \r | |
655 | case 025: /* JMP, dir, curr */\r | |
656 | PCQ_ENTRY;\r | |
657 | MA = (MA & 007600) | (IR & 0177); /* dir addr, curr page */\r | |
658 | if (UF) { /* user mode? */\r | |
659 | tsc_ir = IR; /* save instruction */\r | |
660 | tsc_cdf = 0; /* clear flag */\r | |
661 | if (tsc_enb) { /* TSC8 enabled? */\r | |
662 | tsc_pc = (PC - 1) & 07777; /* save PC */\r | |
663 | int_req = int_req | INT_TSC; /* request intr */\r | |
664 | }\r | |
665 | }\r | |
666 | if (sim_idle_enab && /* idling enabled? */\r | |
667 | (IF == IB)) { /* to same bank? */\r | |
668 | if (MA == ((PC - 2) & 07777)) { /* 1) JMP *-1? */\r | |
669 | if (!(int_req & (INT_ION|INT_TTI)) && /* iof, TTI flag off? */\r | |
670 | (M[IB|((PC - 2) & 07777)] == OP_KSF)) /* next is KSF? */\r | |
671 | sim_idle (TMR_CLK, FALSE); /* we're idle */\r | |
672 | } /* end JMP *-1 */\r | |
673 | else if (MA == ((PC - 1) & 07777)) { /* 2) JMP *? */\r | |
674 | if (!(int_req & INT_ION)) /* iof? */\r | |
675 | reason = STOP_LOOP; /* then infinite loop */\r | |
676 | else if (!(int_req & INT_ALL)) /* ion, not intr? */\r | |
677 | sim_idle (TMR_CLK, FALSE); /* we're idle */\r | |
678 | } /* end JMP */\r | |
679 | } /* end idle enabled */\r | |
680 | IF = IB; /* change IF */\r | |
681 | UF = UB; /* change UF */\r | |
682 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r | |
683 | PC = MA;\r | |
684 | break;\r | |
685 | \r | |
686 | case 026: /* JMP, indir, zero */\r | |
687 | PCQ_ENTRY;\r | |
688 | MA = IF | (IR & 0177); /* dir addr, page zero */\r | |
689 | if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */\r | |
690 | else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
691 | if (UF) { /* user mode? */\r | |
692 | tsc_ir = IR; /* save instruction */\r | |
693 | tsc_cdf = 0; /* clear flag */\r | |
694 | if (tsc_enb) { /* TSC8 enabled? */\r | |
695 | tsc_pc = (PC - 1) & 07777; /* save PC */\r | |
696 | int_req = int_req | INT_TSC; /* request intr */\r | |
697 | }\r | |
698 | }\r | |
699 | IF = IB; /* change IF */\r | |
700 | UF = UB; /* change UF */\r | |
701 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r | |
702 | PC = MA;\r | |
703 | break;\r | |
704 | \r | |
705 | case 027: /* JMP, indir, curr */\r | |
706 | PCQ_ENTRY;\r | |
707 | MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */\r | |
708 | if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */\r | |
709 | else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
710 | if (UF) { /* user mode? */\r | |
711 | tsc_ir = IR; /* save instruction */\r | |
712 | tsc_cdf = 0; /* clear flag */\r | |
713 | if (tsc_enb) { /* TSC8 enabled? */\r | |
714 | tsc_pc = (PC - 1) & 07777; /* save PC */\r | |
715 | int_req = int_req | INT_TSC; /* request intr */\r | |
716 | }\r | |
717 | }\r | |
718 | IF = IB; /* change IF */\r | |
719 | UF = UB; /* change UF */\r | |
720 | int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */\r | |
721 | PC = MA;\r | |
722 | break;\r | |
723 | \r | |
724 | /* Opcode 7, OPR group 1 */\r | |
725 | \r | |
726 | case 034:case 035: /* OPR, group 1 */\r | |
727 | switch ((IR >> 4) & 017) { /* decode IR<4:7> */\r | |
728 | case 0: /* nop */\r | |
729 | break;\r | |
730 | case 1: /* CML */\r | |
731 | LAC = LAC ^ 010000;\r | |
732 | break;\r | |
733 | case 2: /* CMA */\r | |
734 | LAC = LAC ^ 07777;\r | |
735 | break;\r | |
736 | case 3: /* CMA CML */\r | |
737 | LAC = LAC ^ 017777;\r | |
738 | break;\r | |
739 | case 4: /* CLL */\r | |
740 | LAC = LAC & 07777;\r | |
741 | break;\r | |
742 | case 5: /* CLL CML = STL */\r | |
743 | LAC = LAC | 010000;\r | |
744 | break;\r | |
745 | case 6: /* CLL CMA */\r | |
746 | LAC = (LAC ^ 07777) & 07777;\r | |
747 | break;\r | |
748 | case 7: /* CLL CMA CML */\r | |
749 | LAC = (LAC ^ 07777) | 010000;\r | |
750 | break;\r | |
751 | case 010: /* CLA */\r | |
752 | LAC = LAC & 010000;\r | |
753 | break;\r | |
754 | case 011: /* CLA CML */\r | |
755 | LAC = (LAC & 010000) ^ 010000;\r | |
756 | break;\r | |
757 | case 012: /* CLA CMA = STA */\r | |
758 | LAC = LAC | 07777;\r | |
759 | break;\r | |
760 | case 013: /* CLA CMA CML */\r | |
761 | LAC = (LAC | 07777) ^ 010000;\r | |
762 | break;\r | |
763 | case 014: /* CLA CLL */\r | |
764 | LAC = 0;\r | |
765 | break;\r | |
766 | case 015: /* CLA CLL CML */\r | |
767 | LAC = 010000;\r | |
768 | break;\r | |
769 | case 016: /* CLA CLL CMA */\r | |
770 | LAC = 07777;\r | |
771 | break;\r | |
772 | case 017: /* CLA CLL CMA CML */\r | |
773 | LAC = 017777;\r | |
774 | break;\r | |
775 | } /* end switch opers */\r | |
776 | \r | |
777 | if (IR & 01) LAC = (LAC + 1) & 017777; /* IAC */\r | |
778 | switch ((IR >> 1) & 07) { /* decode IR<8:10> */\r | |
779 | case 0: /* nop */\r | |
780 | break;\r | |
781 | case 1: /* BSW */\r | |
782 | LAC = (LAC & 010000) | ((LAC >> 6) & 077) | ((LAC & 077) << 6);\r | |
783 | break;\r | |
784 | case 2: /* RAL */\r | |
785 | LAC = ((LAC << 1) | (LAC >> 12)) & 017777;\r | |
786 | break;\r | |
787 | case 3: /* RTL */\r | |
788 | LAC = ((LAC << 2) | (LAC >> 11)) & 017777;\r | |
789 | break;\r | |
790 | case 4: /* RAR */\r | |
791 | LAC = ((LAC >> 1) | (LAC << 12)) & 017777;\r | |
792 | break;\r | |
793 | case 5: /* RTR */\r | |
794 | LAC = ((LAC >> 2) | (LAC << 11)) & 017777;\r | |
795 | break;\r | |
796 | case 6: /* RAL RAR - undef */\r | |
797 | LAC = LAC & (IR | 010000); /* uses AND path */\r | |
798 | break;\r | |
799 | case 7: /* RTL RTR - undef */\r | |
800 | LAC = (LAC & 010000) | (MA & 07600) | (IR & 0177);\r | |
801 | break; /* uses address path */\r | |
802 | } /* end switch shifts */\r | |
803 | break; /* end group 1 */\r | |
804 | \r | |
805 | /* OPR group 2. From Bernhard Baehr's description of the TSC8-75:\r | |
806 | \r | |
807 | (In user mode) HLT (7402), OSR (7404) and microprogrammed combinations with\r | |
808 | HLT and OSR: Additional to raising a user mode interrupt, the current OPR\r | |
809 | opcode is moved to the ERIOT register and the ECDF flag is cleared. */\r | |
810 | \r | |
811 | case 036:case 037: /* OPR, groups 2, 3 */\r | |
812 | if ((IR & 01) == 0) { /* group 2 */\r | |
813 | switch ((IR >> 3) & 017) { /* decode IR<6:8> */\r | |
814 | case 0: /* nop */\r | |
815 | break;\r | |
816 | case 1: /* SKP */\r | |
817 | PC = (PC + 1) & 07777;\r | |
818 | break;\r | |
819 | case 2: /* SNL */\r | |
820 | if (LAC >= 010000) PC = (PC + 1) & 07777;\r | |
821 | break;\r | |
822 | case 3: /* SZL */\r | |
823 | if (LAC < 010000) PC = (PC + 1) & 07777;\r | |
824 | break;\r | |
825 | case 4: /* SZA */\r | |
826 | if ((LAC & 07777) == 0) PC = (PC + 1) & 07777;\r | |
827 | break;\r | |
828 | case 5: /* SNA */\r | |
829 | if ((LAC & 07777) != 0) PC = (PC + 1) & 07777;\r | |
830 | break;\r | |
831 | case 6: /* SZA | SNL */\r | |
832 | if ((LAC == 0) || (LAC >= 010000))\r | |
833 | PC = (PC + 1) & 07777;\r | |
834 | break;\r | |
835 | case 7: /* SNA & SZL */\r | |
836 | if ((LAC != 0) && (LAC < 010000)) PC = (PC + 1) & 07777;\r | |
837 | break;\r | |
838 | case 010: /* SMA */\r | |
839 | if ((LAC & 04000) != 0) PC = (PC + 1) & 07777;\r | |
840 | break;\r | |
841 | case 011: /* SPA */\r | |
842 | if ((LAC & 04000) == 0) PC = (PC + 1) & 07777;\r | |
843 | break;\r | |
844 | case 012: /* SMA | SNL */\r | |
845 | if (LAC >= 04000) PC = (PC + 1) & 07777;\r | |
846 | break;\r | |
847 | case 013: /* SPA & SZL */\r | |
848 | if (LAC < 04000) PC = (PC + 1) & 07777;\r | |
849 | break;\r | |
850 | case 014: /* SMA | SZA */\r | |
851 | if (((LAC & 04000) != 0) || ((LAC & 07777) == 0))\r | |
852 | PC = (PC + 1) & 07777;\r | |
853 | break;\r | |
854 | case 015: /* SPA & SNA */\r | |
855 | if (((LAC & 04000) == 0) && ((LAC & 07777) != 0))\r | |
856 | PC = (PC + 1) & 07777;\r | |
857 | break;\r | |
858 | case 016: /* SMA | SZA | SNL */\r | |
859 | if ((LAC >= 04000) || (LAC == 0)) PC = (PC + 1) & 07777;\r | |
860 | break;\r | |
861 | case 017: /* SPA & SNA & SZL */\r | |
862 | if ((LAC < 04000) && (LAC != 0)) PC = (PC + 1) & 07777;\r | |
863 | break;\r | |
864 | } /* end switch skips */\r | |
865 | if (IR & 0200) LAC = LAC & 010000; /* CLA */\r | |
866 | if ((IR & 06) && UF) { /* user mode? */\r | |
867 | int_req = int_req | INT_UF; /* request intr */\r | |
868 | tsc_ir = IR; /* save instruction */\r | |
869 | tsc_cdf = 0; /* clear flag */\r | |
870 | }\r | |
871 | else {\r | |
872 | if (IR & 04) LAC = LAC | OSR; /* OSR */\r | |
873 | if (IR & 02) reason = STOP_HALT; /* HLT */\r | |
874 | }\r | |
875 | break;\r | |
876 | } /* end if group 2 */\r | |
877 | \r | |
878 | /* OPR group 3 standard\r | |
879 | \r | |
880 | MQA!MQL exchanges AC and MQ, as follows:\r | |
881 | \r | |
882 | temp = MQ;\r | |
883 | MQ = LAC & 07777;\r | |
884 | LAC = LAC & 010000 | temp;\r | |
885 | */\r | |
886 | \r | |
887 | temp = MQ; /* group 3 */\r | |
888 | if (IR & 0200) LAC = LAC & 010000; /* CLA */\r | |
889 | if (IR & 0020) { /* MQL */\r | |
890 | MQ = LAC & 07777;\r | |
891 | LAC = LAC & 010000;\r | |
892 | }\r | |
893 | if (IR & 0100) LAC = LAC | temp; /* MQA */\r | |
894 | if ((IR & 0056) && (cpu_unit.flags & UNIT_NOEAE)) {\r | |
895 | reason = stop_inst; /* EAE not present */\r | |
896 | break;\r | |
897 | }\r | |
898 | \r | |
899 | /* OPR group 3 EAE\r | |
900 | \r | |
901 | The EAE operates in two modes:\r | |
902 | \r | |
903 | Mode A, PDP-8/I compatible\r | |
904 | Mode B, extended capability\r | |
905 | \r | |
906 | Mode B provides eight additional subfunctions; in addition, some\r | |
907 | of the Mode A functions operate differently in Mode B.\r | |
908 | \r | |
909 | The mode switch instructions are decoded explicitly and cannot be\r | |
910 | microprogrammed with other EAE functions (SWAB performs an MQL as\r | |
911 | part of standard group 3 decoding). If mode switching is decoded,\r | |
912 | all other EAE timing is suppressed.\r | |
913 | */\r | |
914 | \r | |
915 | if (IR == 07431) { /* SWAB */\r | |
916 | emode = 1; /* set mode flag */\r | |
917 | break;\r | |
918 | }\r | |
919 | if (IR == 07447) { /* SWBA */\r | |
920 | emode = gtf = 0; /* clear mode, gtf */\r | |
921 | break;\r | |
922 | }\r | |
923 | \r | |
924 | /* If not switching modes, the EAE operation is determined by the mode\r | |
925 | and IR<6,8:10>:\r | |
926 | \r | |
927 | <6:10> mode A mode B comments\r | |
928 | \r | |
929 | 0x000 NOP NOP\r | |
930 | 0x001 SCL ACS\r | |
931 | 0x010 MUY MUY if mode B, next = address\r | |
932 | 0x011 DVI DVI if mode B, next = address\r | |
933 | 0x100 NMI NMI if mode B, clear AC if\r | |
934 | result = 4000'0000\r | |
935 | 0x101 SHL SHL if mode A, extra shift\r | |
936 | 0x110 ASR ASR if mode A, extra shift\r | |
937 | 0x111 LSR LSR if mode A, extra shift\r | |
938 | 1x000 SCA SCA\r | |
939 | 1x001 SCA + SCL DAD\r | |
940 | 1x010 SCA + MUY DST\r | |
941 | 1x011 SCA + DVI SWBA NOP if not detected earlier\r | |
942 | 1x100 SCA + NMI DPSZ \r | |
943 | 1x101 SCA + SHL DPIC must be combined with MQA!MQL\r | |
944 | 1x110 SCA + ASR DCM must be combined with MQA!MQL\r | |
945 | 1x111 SCA + LSR SAM\r | |
946 | \r | |
947 | EAE instructions which fetch memory operands use the CPU's DEFER\r | |
948 | state to read the first word; if the address operand is in locations\r | |
949 | x0010 - x0017, it is autoincremented.\r | |
950 | */\r | |
951 | \r | |
952 | if (emode == 0) gtf = 0; /* mode A? clr gtf */\r | |
953 | switch ((IR >> 1) & 027) { /* decode IR<6,8:10> */\r | |
954 | \r | |
955 | case 020: /* mode A, B: SCA */\r | |
956 | LAC = LAC | SC;\r | |
957 | break;\r | |
958 | case 000: /* mode A, B: NOP */\r | |
959 | break;\r | |
960 | \r | |
961 | case 021: /* mode B: DAD */\r | |
962 | if (emode) {\r | |
963 | MA = IF | PC;\r | |
964 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
965 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
966 | MQ = MQ + M[MA];\r | |
967 | MA = DF | ((MA + 1) & 07777);\r | |
968 | LAC = (LAC & 07777) + M[MA] + (MQ >> 12);\r | |
969 | MQ = MQ & 07777;\r | |
970 | PC = (PC + 1) & 07777;\r | |
971 | break;\r | |
972 | }\r | |
973 | LAC = LAC | SC; /* mode A: SCA then */\r | |
974 | case 001: /* mode B: ACS */\r | |
975 | if (emode) {\r | |
976 | SC = LAC & 037;\r | |
977 | LAC = LAC & 010000;\r | |
978 | }\r | |
979 | else { /* mode A: SCL */\r | |
980 | SC = (~M[IF | PC]) & 037;\r | |
981 | PC = (PC + 1) & 07777;\r | |
982 | }\r | |
983 | break;\r | |
984 | \r | |
985 | case 022: /* mode B: DST */\r | |
986 | if (emode) {\r | |
987 | MA = IF | PC;\r | |
988 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
989 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
990 | if (MEM_ADDR_OK (MA)) M[MA] = MQ & 07777;\r | |
991 | MA = DF | ((MA + 1) & 07777);\r | |
992 | if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777;\r | |
993 | PC = (PC + 1) & 07777;\r | |
994 | break;\r | |
995 | }\r | |
996 | LAC = LAC | SC; /* mode A: SCA then */\r | |
997 | case 002: /* MUY */\r | |
998 | MA = IF | PC;\r | |
999 | if (emode) { /* mode B: defer */\r | |
1000 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
1001 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
1002 | }\r | |
1003 | temp = (MQ * M[MA]) + (LAC & 07777);\r | |
1004 | LAC = (temp >> 12) & 07777;\r | |
1005 | MQ = temp & 07777;\r | |
1006 | PC = (PC + 1) & 07777;\r | |
1007 | SC = 014; /* 12 shifts */\r | |
1008 | break;\r | |
1009 | \r | |
1010 | case 023: /* mode B: SWBA */\r | |
1011 | if (emode) break;\r | |
1012 | LAC = LAC | SC; /* mode A: SCA then */\r | |
1013 | case 003: /* DVI */\r | |
1014 | MA = IF | PC;\r | |
1015 | if (emode) { /* mode B: defer */\r | |
1016 | if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */\r | |
1017 | else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */\r | |
1018 | }\r | |
1019 | if ((LAC & 07777) >= M[MA]) { /* overflow? */\r | |
1020 | LAC = LAC | 010000; /* set link */\r | |
1021 | MQ = ((MQ << 1) + 1) & 07777; /* rotate MQ */\r | |
1022 | SC = 0; /* no shifts */\r | |
1023 | }\r | |
1024 | else {\r | |
1025 | temp = ((LAC & 07777) << 12) | MQ;\r | |
1026 | MQ = temp / M[MA];\r | |
1027 | LAC = temp % M[MA];\r | |
1028 | SC = 015; /* 13 shifts */\r | |
1029 | }\r | |
1030 | PC = (PC + 1) & 07777;\r | |
1031 | break;\r | |
1032 | \r | |
1033 | case 024: /* mode B: DPSZ */\r | |
1034 | if (emode) {\r | |
1035 | if (((LAC | MQ) & 07777) == 0) PC = (PC + 1) & 07777;\r | |
1036 | break;\r | |
1037 | }\r | |
1038 | LAC = LAC | SC; /* mode A: SCA then */\r | |
1039 | case 004: /* NMI */\r | |
1040 | temp = (LAC << 12) | MQ; /* preserve link */\r | |
1041 | for (SC = 0; ((temp & 017777777) != 0) &&\r | |
1042 | (temp & 040000000) == ((temp << 1) & 040000000); SC++)\r | |
1043 | temp = temp << 1;\r | |
1044 | LAC = (temp >> 12) & 017777;\r | |
1045 | MQ = temp & 07777;\r | |
1046 | if (emode && ((LAC & 07777) == 04000) && (MQ == 0))\r | |
1047 | LAC = LAC & 010000; /* clr if 4000'0000 */\r | |
1048 | break;\r | |
1049 | \r | |
1050 | case 025: /* mode B: DPIC */\r | |
1051 | if (emode) {\r | |
1052 | temp = (LAC + 1) & 07777; /* SWP already done! */\r | |
1053 | LAC = MQ + (temp == 0);\r | |
1054 | MQ = temp;\r | |
1055 | break;\r | |
1056 | }\r | |
1057 | LAC = LAC | SC; /* mode A: SCA then */\r | |
1058 | case 5: /* SHL */\r | |
1059 | SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */\r | |
1060 | if (SC > 25) temp = 0; /* >25? result = 0 */\r | |
1061 | else temp = ((LAC << 12) | MQ) << SC; /* <=25? shift LAC:MQ */\r | |
1062 | LAC = (temp >> 12) & 017777;\r | |
1063 | MQ = temp & 07777;\r | |
1064 | PC = (PC + 1) & 07777;\r | |
1065 | SC = emode? 037: 0; /* SC = 0 if mode A */\r | |
1066 | break;\r | |
1067 | \r | |
1068 | case 026: /* mode B: DCM */\r | |
1069 | if (emode) {\r | |
1070 | temp = (-LAC) & 07777; /* SWP already done! */\r | |
1071 | LAC = (MQ ^ 07777) + (temp == 0);\r | |
1072 | MQ = temp;\r | |
1073 | break;\r | |
1074 | }\r | |
1075 | LAC = LAC | SC; /* mode A: SCA then */\r | |
1076 | case 6: /* ASR */\r | |
1077 | SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */\r | |
1078 | temp = ((LAC & 07777) << 12) | MQ; /* sext from AC0 */\r | |
1079 | if (LAC & 04000) temp = temp | ~037777777;\r | |
1080 | if (emode && (SC != 0)) gtf = (temp >> (SC - 1)) & 1;\r | |
1081 | if (SC > 25) temp = (LAC & 04000)? -1: 0;\r | |
1082 | else temp = temp >> SC;\r | |
1083 | LAC = (temp >> 12) & 017777;\r | |
1084 | MQ = temp & 07777;\r | |
1085 | PC = (PC + 1) & 07777;\r | |
1086 | SC = emode? 037: 0; /* SC = 0 if mode A */\r | |
1087 | break;\r | |
1088 | \r | |
1089 | case 027: /* mode B: SAM */\r | |
1090 | if (emode) {\r | |
1091 | temp = LAC & 07777;\r | |
1092 | LAC = MQ + (temp ^ 07777) + 1; /* L'AC = MQ - AC */\r | |
1093 | gtf = (temp <= MQ) ^ ((temp ^ MQ) >> 11);\r | |
1094 | break;\r | |
1095 | }\r | |
1096 | LAC = LAC | SC; /* mode A: SCA then */\r | |
1097 | case 7: /* LSR */\r | |
1098 | SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */\r | |
1099 | temp = ((LAC & 07777) << 12) | MQ; /* clear link */\r | |
1100 | if (emode && (SC != 0)) gtf = (temp >> (SC - 1)) & 1;\r | |
1101 | if (SC > 24) temp = 0; /* >24? result = 0 */\r | |
1102 | else temp = temp >> SC; /* <=24? shift AC:MQ */\r | |
1103 | LAC = (temp >> 12) & 07777;\r | |
1104 | MQ = temp & 07777;\r | |
1105 | PC = (PC + 1) & 07777;\r | |
1106 | SC = emode? 037: 0; /* SC = 0 if mode A */\r | |
1107 | break;\r | |
1108 | } /* end switch */\r | |
1109 | break; /* end case 7 */\r | |
1110 | \r | |
1111 | /* Opcode 6, IOT. From Bernhard Baehr's description of the TSC8-75:\r | |
1112 | \r | |
1113 | (In user mode) Additional to raising a user mode interrupt, the current IOT\r | |
1114 | opcode is moved to the ERIOT register. When the IOT is a CDF instruction (62x1),\r | |
1115 | the ECDF flag is set, otherwise it is cleared. */\r | |
1116 | \r | |
1117 | case 030:case 031:case 032:case 033: /* IOT */\r | |
1118 | if (UF) { /* privileged? */\r | |
1119 | int_req = int_req | INT_UF; /* request intr */\r | |
1120 | tsc_ir = IR; /* save instruction */\r | |
1121 | if ((IR & 07707) == 06201) tsc_cdf = 1; /* set/clear flag */\r | |
1122 | else tsc_cdf = 0;\r | |
1123 | break;\r | |
1124 | }\r | |
1125 | device = (IR >> 3) & 077; /* device = IR<3:8> */\r | |
1126 | pulse = IR & 07; /* pulse = IR<9:11> */\r | |
1127 | iot_data = LAC & 07777; /* AC unchanged */\r | |
1128 | switch (device) { /* decode IR<3:8> */\r | |
1129 | \r | |
1130 | case 000: /* CPU control */\r | |
1131 | switch (pulse) { /* decode IR<9:11> */\r | |
1132 | \r | |
1133 | case 0: /* SKON */\r | |
1134 | if (int_req & INT_ION) PC = (PC + 1) & 07777;\r | |
1135 | int_req = int_req & ~INT_ION;\r | |
1136 | break;\r | |
1137 | \r | |
1138 | case 1: /* ION */\r | |
1139 | int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING;\r | |
1140 | break;\r | |
1141 | \r | |
1142 | case 2: /* IOF */\r | |
1143 | int_req = int_req & ~INT_ION;\r | |
1144 | break;\r | |
1145 | \r | |
1146 | case 3: /* SRQ */\r | |
1147 | if (int_req & INT_ALL) PC = (PC + 1) & 07777;\r | |
1148 | break;\r | |
1149 | \r | |
1150 | case 4: /* GTF */\r | |
1151 | LAC = (LAC & 010000) |\r | |
1152 | ((LAC & 010000) >> 1) | (gtf << 10) |\r | |
1153 | (((int_req & INT_ALL) != 0) << 9) |\r | |
1154 | (((int_req & INT_ION) != 0) << 7) | SF;\r | |
1155 | break;\r | |
1156 | \r | |
1157 | case 5: /* RTF */\r | |
1158 | gtf = ((LAC & 02000) >> 10);\r | |
1159 | UB = (LAC & 0100) >> 6;\r | |
1160 | IB = (LAC & 0070) << 9;\r | |
1161 | DF = (LAC & 0007) << 12;\r | |
1162 | LAC = ((LAC & 04000) << 1) | iot_data;\r | |
1163 | int_req = (int_req | INT_ION) & ~INT_NO_CIF_PENDING;\r | |
1164 | break;\r | |
1165 | \r | |
1166 | case 6: /* SGT */\r | |
1167 | if (gtf) PC = (PC + 1) & 07777;\r | |
1168 | break;\r | |
1169 | \r | |
1170 | case 7: /* CAF */\r | |
1171 | gtf = 0;\r | |
1172 | emode = 0;\r | |
1173 | int_req = int_req & INT_NO_CIF_PENDING;\r | |
1174 | dev_done = 0;\r | |
1175 | int_enable = INT_INIT_ENABLE;\r | |
1176 | LAC = 0;\r | |
1177 | reset_all (1); /* reset all dev */\r | |
1178 | break;\r | |
1179 | } /* end switch pulse */\r | |
1180 | break; /* end case 0 */\r | |
1181 | \r | |
1182 | case 020:case 021:case 022:case 023:\r | |
1183 | case 024:case 025:case 026:case 027: /* memory extension */\r | |
1184 | switch (pulse) { /* decode IR<9:11> */\r | |
1185 | \r | |
1186 | case 1: /* CDF */\r | |
1187 | DF = (IR & 0070) << 9;\r | |
1188 | break;\r | |
1189 | \r | |
1190 | case 2: /* CIF */\r | |
1191 | IB = (IR & 0070) << 9;\r | |
1192 | int_req = int_req & ~INT_NO_CIF_PENDING;\r | |
1193 | break;\r | |
1194 | \r | |
1195 | case 3: /* CDF CIF */\r | |
1196 | DF = IB = (IR & 0070) << 9;\r | |
1197 | int_req = int_req & ~INT_NO_CIF_PENDING;\r | |
1198 | break;\r | |
1199 | \r | |
1200 | case 4:\r | |
1201 | switch (device & 07) { /* decode IR<6:8> */\r | |
1202 | \r | |
1203 | case 0: /* CINT */\r | |
1204 | int_req = int_req & ~INT_UF;\r | |
1205 | break;\r | |
1206 | \r | |
1207 | case 1: /* RDF */\r | |
1208 | LAC = LAC | (DF >> 9);\r | |
1209 | break;\r | |
1210 | \r | |
1211 | case 2: /* RIF */\r | |
1212 | LAC = LAC | (IF >> 9);\r | |
1213 | break;\r | |
1214 | \r | |
1215 | case 3: /* RIB */\r | |
1216 | LAC = LAC | SF;\r | |
1217 | break;\r | |
1218 | \r | |
1219 | case 4: /* RMF */\r | |
1220 | UB = (SF & 0100) >> 6;\r | |
1221 | IB = (SF & 0070) << 9;\r | |
1222 | DF = (SF & 0007) << 12;\r | |
1223 | int_req = int_req & ~INT_NO_CIF_PENDING;\r | |
1224 | break;\r | |
1225 | \r | |
1226 | case 5: /* SINT */\r | |
1227 | if (int_req & INT_UF) PC = (PC + 1) & 07777;\r | |
1228 | break;\r | |
1229 | \r | |
1230 | case 6: /* CUF */\r | |
1231 | UB = 0;\r | |
1232 | int_req = int_req & ~INT_NO_CIF_PENDING;\r | |
1233 | break;\r | |
1234 | \r | |
1235 | case 7: /* SUF */\r | |
1236 | UB = 1;\r | |
1237 | int_req = int_req & ~INT_NO_CIF_PENDING;\r | |
1238 | break;\r | |
1239 | } /* end switch device */\r | |
1240 | break;\r | |
1241 | \r | |
1242 | default:\r | |
1243 | reason = stop_inst;\r | |
1244 | break;\r | |
1245 | } /* end switch pulse */\r | |
1246 | break; /* end case 20-27 */\r | |
1247 | \r | |
1248 | case 010: /* power fail */\r | |
1249 | switch (pulse) { /* decode IR<9:11> */\r | |
1250 | \r | |
1251 | case 1: /* SBE */\r | |
1252 | break;\r | |
1253 | \r | |
1254 | case 2: /* SPL */\r | |
1255 | if (int_req & INT_PWR) PC = (PC + 1) & 07777;\r | |
1256 | break;\r | |
1257 | \r | |
1258 | case 3: /* CAL */\r | |
1259 | int_req = int_req & ~INT_PWR;\r | |
1260 | break;\r | |
1261 | \r | |
1262 | default:\r | |
1263 | reason = stop_inst;\r | |
1264 | break;\r | |
1265 | } /* end switch pulse */\r | |
1266 | break; /* end case 10 */\r | |
1267 | \r | |
1268 | default: /* I/O device */\r | |
1269 | if (dev_tab[device]) { /* dev present? */\r | |
1270 | iot_data = dev_tab[device] (IR, iot_data);\r | |
1271 | LAC = (LAC & 010000) | (iot_data & 07777);\r | |
1272 | if (iot_data & IOT_SKP) PC = (PC + 1) & 07777;\r | |
1273 | if (iot_data >= IOT_REASON)\r | |
1274 | reason = iot_data >> IOT_V_REASON;\r | |
1275 | }\r | |
1276 | else reason = stop_inst; /* stop on flag */\r | |
1277 | break;\r | |
1278 | } /* end switch device */\r | |
1279 | break; /* end case IOT */\r | |
1280 | } /* end switch opcode */\r | |
1281 | } /* end while */\r | |
1282 | \r | |
1283 | /* Simulation halted */\r | |
1284 | \r | |
1285 | saved_PC = IF | (PC & 07777); /* save copies */\r | |
1286 | saved_DF = DF & 070000;\r | |
1287 | saved_LAC = LAC & 017777;\r | |
1288 | saved_MQ = MQ & 07777;\r | |
1289 | pcq_r->qptr = pcq_p; /* update pc q ptr */\r | |
1290 | return reason;\r | |
1291 | } /* end sim_instr */\r | |
1292 | \r | |
1293 | /* Reset routine */\r | |
1294 | \r | |
1295 | t_stat cpu_reset (DEVICE *dptr)\r | |
1296 | {\r | |
1297 | int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING;\r | |
1298 | saved_DF = IB = saved_PC & 070000;\r | |
1299 | UF = UB = gtf = emode = 0;\r | |
1300 | pcq_r = find_reg ("PCQ", NULL, dptr);\r | |
1301 | if (pcq_r) pcq_r->qptr = 0;\r | |
1302 | else return SCPE_IERR;\r | |
1303 | sim_brk_types = sim_brk_dflt = SWMASK ('E');\r | |
1304 | return SCPE_OK;\r | |
1305 | }\r | |
1306 | \r | |
1307 | /* Memory examine */\r | |
1308 | \r | |
1309 | t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r | |
1310 | {\r | |
1311 | if (addr >= MEMSIZE) return SCPE_NXM;\r | |
1312 | if (vptr != NULL) *vptr = M[addr] & 07777;\r | |
1313 | return SCPE_OK;\r | |
1314 | }\r | |
1315 | \r | |
1316 | /* Memory deposit */\r | |
1317 | \r | |
1318 | t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r | |
1319 | {\r | |
1320 | if (addr >= MEMSIZE) return SCPE_NXM;\r | |
1321 | M[addr] = val & 07777;\r | |
1322 | return SCPE_OK;\r | |
1323 | }\r | |
1324 | \r | |
1325 | /* Memory size change */\r | |
1326 | \r | |
1327 | t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1328 | {\r | |
1329 | int32 mc = 0;\r | |
1330 | uint32 i;\r | |
1331 | \r | |
1332 | if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))\r | |
1333 | return SCPE_ARG;\r | |
1334 | for (i = val; i < MEMSIZE; i++) mc = mc | M[i];\r | |
1335 | if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r | |
1336 | return SCPE_OK;\r | |
1337 | MEMSIZE = val;\r | |
1338 | for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;\r | |
1339 | return SCPE_OK;\r | |
1340 | }\r | |
1341 | \r | |
1342 | /* Change device number for a device */\r | |
1343 | \r | |
1344 | t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1345 | {\r | |
1346 | DEVICE *dptr;\r | |
1347 | DIB *dibp;\r | |
1348 | uint32 newdev;\r | |
1349 | t_stat r;\r | |
1350 | \r | |
1351 | if (cptr == NULL) return SCPE_ARG;\r | |
1352 | if (uptr == NULL) return SCPE_IERR;\r | |
1353 | dptr = find_dev_from_unit (uptr);\r | |
1354 | if (dptr == NULL) return SCPE_IERR;\r | |
1355 | dibp = (DIB *) dptr->ctxt;\r | |
1356 | if (dibp == NULL) return SCPE_IERR;\r | |
1357 | newdev = get_uint (cptr, 8, DEV_MAX - 1, &r); /* get new */\r | |
1358 | if ((r != SCPE_OK) || (newdev == dibp->dev)) return r;\r | |
1359 | dibp->dev = newdev; /* store */\r | |
1360 | return SCPE_OK;\r | |
1361 | }\r | |
1362 | \r | |
1363 | /* Show device number for a device */\r | |
1364 | \r | |
1365 | t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
1366 | {\r | |
1367 | DEVICE *dptr;\r | |
1368 | DIB *dibp;\r | |
1369 | \r | |
1370 | if (uptr == NULL) return SCPE_IERR;\r | |
1371 | dptr = find_dev_from_unit (uptr);\r | |
1372 | if (dptr == NULL) return SCPE_IERR;\r | |
1373 | dibp = (DIB *) dptr->ctxt;\r | |
1374 | if (dibp == NULL) return SCPE_IERR;\r | |
1375 | fprintf (st, "devno=%02o", dibp->dev);\r | |
1376 | if (dibp->num > 1) fprintf (st, "-%2o", dibp->dev + dibp->num - 1);\r | |
1377 | return SCPE_OK;\r | |
1378 | }\r | |
1379 | \r | |
1380 | /* CPU device handler - should never get here! */\r | |
1381 | \r | |
1382 | int32 bad_dev (int32 IR, int32 AC)\r | |
1383 | {\r | |
1384 | return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */\r | |
1385 | }\r | |
1386 | \r | |
1387 | /* Build device dispatch table */\r | |
1388 | \r | |
1389 | t_bool build_dev_tab (void)\r | |
1390 | {\r | |
1391 | DEVICE *dptr;\r | |
1392 | DIB *dibp;\r | |
1393 | uint32 i, j;\r | |
1394 | static const uint8 std_dev[] = {\r | |
1395 | 000, 010, 020, 021, 022, 023, 024, 025, 026, 027\r | |
1396 | };\r | |
1397 | \r | |
1398 | for (i = 0; i < DEV_MAX; i++) dev_tab[i] = NULL; /* clr table */\r | |
1399 | for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */\r | |
1400 | dev_tab[std_dev[i]] = &bad_dev;\r | |
1401 | for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */\r | |
1402 | dibp = (DIB *) dptr->ctxt; /* get DIB */\r | |
1403 | if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */\r | |
1404 | for (j = 0; j < dibp->num; j++) { /* loop thru disp */\r | |
1405 | if (dibp->dsp[j]) { /* any dispatch? */\r | |
1406 | if (dev_tab[dibp->dev + j]) { /* already filled? */\r | |
1407 | printf ("%s device number conflict at %02o\n",\r | |
1408 | sim_dname (dptr), dibp->dev + j);\r | |
1409 | if (sim_log) fprintf (sim_log,\r | |
1410 | "%s device number conflict at %02o\n",\r | |
1411 | sim_dname (dptr), dibp->dev + j);\r | |
1412 | return TRUE;\r | |
1413 | }\r | |
1414 | dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */\r | |
1415 | } /* end if dsp */\r | |
1416 | } /* end for j */\r | |
1417 | } /* end if enb */\r | |
1418 | } /* end for i */\r | |
1419 | return FALSE;\r | |
1420 | }\r | |
1421 | \r | |
1422 | /* Set history */\r | |
1423 | \r | |
1424 | t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1425 | {\r | |
1426 | int32 i, lnt;\r | |
1427 | t_stat r;\r | |
1428 | \r | |
1429 | if (cptr == NULL) {\r | |
1430 | for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;\r | |
1431 | hst_p = 0;\r | |
1432 | return SCPE_OK;\r | |
1433 | }\r | |
1434 | lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);\r | |
1435 | if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;\r | |
1436 | hst_p = 0;\r | |
1437 | if (hst_lnt) {\r | |
1438 | free (hst);\r | |
1439 | hst_lnt = 0;\r | |
1440 | hst = NULL;\r | |
1441 | }\r | |
1442 | if (lnt) {\r | |
1443 | hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));\r | |
1444 | if (hst == NULL) return SCPE_MEM;\r | |
1445 | hst_lnt = lnt;\r | |
1446 | }\r | |
1447 | return SCPE_OK;\r | |
1448 | }\r | |
1449 | \r | |
1450 | /* Show history */\r | |
1451 | \r | |
1452 | t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
1453 | {\r | |
1454 | int32 l, k, di, lnt;\r | |
1455 | char *cptr = (char *) desc;\r | |
1456 | t_stat r;\r | |
1457 | t_value sim_eval;\r | |
1458 | InstHistory *h;\r | |
1459 | extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,\r | |
1460 | UNIT *uptr, int32 sw);\r | |
1461 | \r | |
1462 | if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */\r | |
1463 | if (cptr) {\r | |
1464 | lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);\r | |
1465 | if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG;\r | |
1466 | }\r | |
1467 | else lnt = hst_lnt;\r | |
1468 | di = hst_p - lnt; /* work forward */\r | |
1469 | if (di < 0) di = di + hst_lnt;\r | |
1470 | fprintf (st, "PC L AC MQ ea IR\n\n");\r | |
1471 | for (k = 0; k < lnt; k++) { /* print specified */\r | |
1472 | h = &hst[(++di) % hst_lnt]; /* entry pointer */\r | |
1473 | if (h->pc & HIST_PC) { /* instruction? */\r | |
1474 | l = (h->lac >> 12) & 1; /* link */\r | |
1475 | fprintf (st, "%05o %o %04o %04o ", h->pc & ADDRMASK, l, h->lac & 07777, h->mq);\r | |
1476 | if (h->ir < 06000) fprintf (st, "%05o ", h->ea);\r | |
1477 | else fprintf (st, " ");\r | |
1478 | sim_eval = h->ir;\r | |
1479 | if ((fprint_sym (st, h->pc & ADDRMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)\r | |
1480 | fprintf (st, "(undefined) %04o", h->ir);\r | |
1481 | if (h->ir < 04000) fprintf (st, " [%04o]", h->opnd);\r | |
1482 | fputc ('\n', st); /* end line */\r | |
1483 | } /* end else instruction */\r | |
1484 | } /* end for */\r | |
1485 | return SCPE_OK;\r | |
1486 | }\r |