First Commit of my working state
[simh.git] / PDP8 / pdp8_cpu.c
CommitLineData
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
205typedef 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
214uint16 M[MAXMEMSIZE] = { 0 }; /* main memory */\r
215int32 saved_LAC = 0; /* saved L'AC */\r
216int32 saved_MQ = 0; /* saved MQ */\r
217int32 saved_PC = 0; /* saved IF'PC */\r
218int32 saved_DF = 0; /* saved Data Field */\r
219int32 IB = 0; /* Instruction Buffer */\r
220int32 SF = 0; /* Save Field */\r
221int32 emode = 0; /* EAE mode */\r
222int32 gtf = 0; /* EAE gtf flag */\r
223int32 SC = 0; /* EAE shift count */\r
224int32 UB = 0; /* User mode Buffer */\r
225int32 UF = 0; /* User mode Flag */\r
226int32 OSR = 0; /* Switch Register */\r
227int32 tsc_ir = 0; /* TSC8-75 IR */\r
228int32 tsc_pc = 0; /* TSC8-75 PC */\r
229int32 tsc_cdf = 0; /* TSC8-75 CDF flag */\r
230int32 tsc_enb = 0; /* TSC8-75 enabled */\r
231int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r
232int32 pcq_p = 0; /* PC queue ptr */\r
233REG *pcq_r = NULL; /* PC queue reg ptr */\r
234int32 dev_done = 0; /* dev done flags */\r
235int32 int_enable = INT_INIT_ENABLE; /* intr enables */\r
236int32 int_req = 0; /* intr requests */\r
237int32 stop_inst = 0; /* trap on ill inst */\r
238int32 (*dev_tab[DEV_MAX])(int32 IR, int32 dat); /* device dispatch */\r
239int32 hst_p = 0; /* history pointer */\r
240int32 hst_lnt = 0; /* history length */\r
241InstHistory *hst = NULL; /* instruction history */\r
242\r
243extern int32 sim_interval;\r
244extern int32 sim_int_char;\r
245extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r
246extern DEVICE *sim_devices[];\r
247extern FILE *sim_log;\r
248extern t_bool sim_idle_enab;\r
249\r
250t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
251t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
252t_stat cpu_reset (DEVICE *dptr);\r
253t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r
254t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);\r
255t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);\r
256t_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
266UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };\r
267\r
268REG 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
298MTAB 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
316DEVICE 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
324t_stat sim_instr (void)\r
325{\r
326int32 IR, MB, IF, DF, LAC, MQ;\r
327uint32 PC, MA;\r
328int32 device, pulse, temp, iot_data;\r
329t_stat reason;\r
330\r
331/* Restore register state */\r
332\r
333if (build_dev_tab ()) return SCPE_STOP; /* build dev_tab */\r
334PC = saved_PC & 007777; /* load local copies */\r
335IF = saved_PC & 070000;\r
336DF = saved_DF & 070000;\r
337LAC = saved_LAC & 017777;\r
338MQ = saved_MQ & 07777;\r
339int_req = INT_UPDATE;\r
340reason = 0;\r
341\r
342/* Main instruction fetch/decode loop */\r
343\r
344while (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
414switch ((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
1285saved_PC = IF | (PC & 07777); /* save copies */\r
1286saved_DF = DF & 070000;\r
1287saved_LAC = LAC & 017777;\r
1288saved_MQ = MQ & 07777;\r
1289pcq_r->qptr = pcq_p; /* update pc q ptr */\r
1290return reason;\r
1291} /* end sim_instr */\r
1292\r
1293/* Reset routine */\r
1294\r
1295t_stat cpu_reset (DEVICE *dptr)\r
1296{\r
1297int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING;\r
1298saved_DF = IB = saved_PC & 070000;\r
1299UF = UB = gtf = emode = 0;\r
1300pcq_r = find_reg ("PCQ", NULL, dptr);\r
1301if (pcq_r) pcq_r->qptr = 0;\r
1302else return SCPE_IERR;\r
1303sim_brk_types = sim_brk_dflt = SWMASK ('E');\r
1304return SCPE_OK;\r
1305}\r
1306\r
1307/* Memory examine */\r
1308\r
1309t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r
1310{\r
1311if (addr >= MEMSIZE) return SCPE_NXM;\r
1312if (vptr != NULL) *vptr = M[addr] & 07777;\r
1313return SCPE_OK;\r
1314}\r
1315\r
1316/* Memory deposit */\r
1317\r
1318t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r
1319{\r
1320if (addr >= MEMSIZE) return SCPE_NXM;\r
1321M[addr] = val & 07777;\r
1322return SCPE_OK;\r
1323}\r
1324\r
1325/* Memory size change */\r
1326\r
1327t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1328{\r
1329int32 mc = 0;\r
1330uint32 i;\r
1331\r
1332if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))\r
1333 return SCPE_ARG;\r
1334for (i = val; i < MEMSIZE; i++) mc = mc | M[i];\r
1335if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r
1336 return SCPE_OK;\r
1337MEMSIZE = val;\r
1338for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;\r
1339return SCPE_OK;\r
1340}\r
1341\r
1342/* Change device number for a device */\r
1343\r
1344t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1345{\r
1346DEVICE *dptr;\r
1347DIB *dibp;\r
1348uint32 newdev;\r
1349t_stat r;\r
1350\r
1351if (cptr == NULL) return SCPE_ARG;\r
1352if (uptr == NULL) return SCPE_IERR;\r
1353dptr = find_dev_from_unit (uptr);\r
1354if (dptr == NULL) return SCPE_IERR;\r
1355dibp = (DIB *) dptr->ctxt;\r
1356if (dibp == NULL) return SCPE_IERR;\r
1357newdev = get_uint (cptr, 8, DEV_MAX - 1, &r); /* get new */\r
1358if ((r != SCPE_OK) || (newdev == dibp->dev)) return r;\r
1359dibp->dev = newdev; /* store */\r
1360return SCPE_OK;\r
1361}\r
1362\r
1363/* Show device number for a device */\r
1364\r
1365t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1366{\r
1367DEVICE *dptr;\r
1368DIB *dibp;\r
1369\r
1370if (uptr == NULL) return SCPE_IERR;\r
1371dptr = find_dev_from_unit (uptr);\r
1372if (dptr == NULL) return SCPE_IERR;\r
1373dibp = (DIB *) dptr->ctxt;\r
1374if (dibp == NULL) return SCPE_IERR;\r
1375fprintf (st, "devno=%02o", dibp->dev);\r
1376if (dibp->num > 1) fprintf (st, "-%2o", dibp->dev + dibp->num - 1);\r
1377return SCPE_OK;\r
1378}\r
1379\r
1380/* CPU device handler - should never get here! */\r
1381\r
1382int32 bad_dev (int32 IR, int32 AC)\r
1383{\r
1384return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */\r
1385}\r
1386\r
1387/* Build device dispatch table */\r
1388\r
1389t_bool build_dev_tab (void)\r
1390{\r
1391DEVICE *dptr;\r
1392DIB *dibp;\r
1393uint32 i, j;\r
1394static const uint8 std_dev[] = {\r
1395 000, 010, 020, 021, 022, 023, 024, 025, 026, 027\r
1396 };\r
1397\r
1398for (i = 0; i < DEV_MAX; i++) dev_tab[i] = NULL; /* clr table */\r
1399for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */\r
1400 dev_tab[std_dev[i]] = &bad_dev;\r
1401for (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
1419return FALSE;\r
1420}\r
1421\r
1422/* Set history */\r
1423\r
1424t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1425{\r
1426int32 i, lnt;\r
1427t_stat r;\r
1428\r
1429if (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
1434lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);\r
1435if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;\r
1436hst_p = 0;\r
1437if (hst_lnt) {\r
1438 free (hst);\r
1439 hst_lnt = 0;\r
1440 hst = NULL;\r
1441 }\r
1442if (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
1447return SCPE_OK;\r
1448}\r
1449\r
1450/* Show history */\r
1451\r
1452t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1453{\r
1454int32 l, k, di, lnt;\r
1455char *cptr = (char *) desc;\r
1456t_stat r;\r
1457t_value sim_eval;\r
1458InstHistory *h;\r
1459extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,\r
1460 UNIT *uptr, int32 sw);\r
1461\r
1462if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */\r
1463if (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
1467else lnt = hst_lnt;\r
1468di = hst_p - lnt; /* work forward */\r
1469if (di < 0) di = di + hst_lnt;\r
1470fprintf (st, "PC L AC MQ ea IR\n\n");\r
1471for (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
1485return SCPE_OK;\r
1486}\r