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