63d3bfbbebdfff55e59ea82d3de16009e4163d7f
1 /* pdp8_cpu.c: PDP-8 CPU simulator
3 Copyright (c) 1993-2007, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
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
54 The register state for the PDP-8 is:
57 MQ<0:11> multiplier-quotient
59 PC<0:11> program counter
60 IF<0:2> instruction field
61 IB<0:2> instruction buffer
65 SF<0:6> interrupt save field
67 The PDP-8 has three instruction formats: memory reference, I/O transfer,
68 and operate. The memory reference format is:
70 0 1 2 3 4 5 6 7 8 9 10 11
71 +--+--+--+--+--+--+--+--+--+--+--+--+
72 | op |in|zr| page offset | memory reference
73 +--+--+--+--+--+--+--+--+--+--+--+--+
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
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>]
90 where x is D for AND, TAD, ISZ, DCA, and I for JMS, JMP.
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.
101 The I/O transfer format is as follows:
103 0 1 2 3 4 5 6 7 8 9 10 11
104 +--+--+--+--+--+--+--+--+--+--+--+--+
105 | op | device | pulse | I/O transfer
106 +--+--+--+--+--+--+--+--+--+--+--+--+
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
113 The operate format is as follows:
115 +--+--+--+--+--+--+--+--+--+--+--+--+
116 | 1| 1| 1| 0| | | | | | | | | operate group 1
117 +--+--+--+--+--+--+--+--+--+--+--+--+
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
128 +--+--+--+--+--+--+--+--+--+--+--+--+
129 | 1| 1| 1| 1| | | | | | | | 0| operate group 2
130 +--+--+--+--+--+--+--+--+--+--+--+--+
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
140 +--+--+--+--+--+--+--+--+--+--+--+--+
141 | 1| 1| 1| 1| | | | | | | | 1| operate group 3
142 +--+--+--+--+--+--+--+--+--+--+--+--+
145 | | +--|-----+--- EAE command 3
146 | | +--- AC -> MQ, 0 -> AC 2
147 | +--- MQ v AC --> AC 2
150 The operate instruction can be microprogrammed to perform operations
151 on the AC, MQ, and link.
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.
160 1. Reasons to stop. The simulator can be stopped by:
163 breakpoint encountered
164 unimplemented instruction and stop_inst flag set
165 I/O error in I/O simulator
167 2. Interrupts. Interrupts are maintained by three parallel variables:
169 dev_done device done flags
170 int_enable interrupt enable flags
171 int_req interrupt requests
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.
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.
184 3. Adding I/O devices. These modules must be modified:
186 pdp8_defs.h add device number and interrupt definitions
187 pdp8_sys.c add sim_devices table entry
190 #include "pdp8_defs.h"
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 */
201 #define HIST_PC 0x40000000
203 #define HIST_MAX 65536
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 */
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
;
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);
258 /* CPU data structures
260 cpu_dev CPU device descriptor
261 cpu_unit CPU unit descriptor
262 cpu_reg CPU register list
263 cpu_mod CPU modifier list
266 UNIT cpu_unit
= { UDATA (NULL
, UNIT_FIX
+ UNIT_BINK
, MAXMEMSIZE
) };
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) },
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
},
317 "CPU", &cpu_unit
, cpu_reg
, cpu_mod
,
319 &cpu_ex
, &cpu_dep
, &cpu_reset
,
324 t_stat
sim_instr (void)
326 int32 IR
, MB
, IF
, DF
, LAC
, MQ
;
328 int32 device
, pulse
, temp
, iot_data
;
331 /* Restore register state */
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
;
342 /* Main instruction fetch/decode loop */
344 while (reason
== 0) { /* loop until halted */
346 if (sim_interval
<= 0) { /* check clock queue */
347 if (reason
= sim_process_event ()) break;
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 */
359 MA
= IF
| PC
; /* form PC */
360 if (sim_brk_summ
&& sim_brk_test (MA
, SWMASK ('E'))) { /* breakpoint? */
361 reason
= STOP_IBKPT
; /* stop simulation */
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;
370 /* Instruction decoding.
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.
377 AND, TAD, ISZ, DCA calculate a full 15b effective address.
378 JMS, JMP calculate a 12b field-relative effective address.
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.
384 Note that MA contains IF'PC.
387 if (hst_lnt
) { /* history enabled? */
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 */
394 hst
[hst_p
].lac
= LAC
;
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);
404 else { /* no, jms/jmp */
405 if ((ea
& 07770) != 00010) ea
= IB
| M
[ea
];
406 else ea
= IB
| ((M
[ea
] + 1) & 07777);
409 hst
[hst_p
].ea
= ea
; /* save eff addr */
410 hst
[hst_p
].opnd
= M
[ea
]; /* save operand */
414 switch ((IR
>> 7) & 037) { /* decode IR<0:4> */
418 case 000: /* AND, dir, zero */
419 MA
= IF
| (IR
& 0177); /* dir addr, page zero */
420 LAC
= LAC
& (M
[MA
] | 010000);
423 case 001: /* AND, dir, curr */
424 MA
= (MA
& 077600) | (IR
& 0177); /* dir addr, curr page */
425 LAC
= LAC
& (M
[MA
] | 010000);
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);
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);
444 case 004: /* TAD, dir, zero */
445 MA
= IF
| (IR
& 0177); /* dir addr, page zero */
446 LAC
= (LAC
+ M
[MA
]) & 017777;
449 case 005: /* TAD, dir, curr */
450 MA
= (MA
& 077600) | (IR
& 0177); /* dir addr, curr page */
451 LAC
= (LAC
+ M
[MA
]) & 017777;
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;
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;
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;
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;
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;
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;
502 case 014: /* DCA, dir, zero */
503 MA
= IF
| (IR
& 0177); /* dir addr, page zero */
508 case 015: /* DCA, dir, curr */
509 MA
= (MA
& 077600) | (IR
& 0177); /* dir addr, curr page */
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;
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;
530 /* Opcode 4, JMS. From Bernhard Baehr's description of the TSC8-75:
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
540 case 020: /* JMS, dir, zero */
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 */
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 */
552 IF
= IB
; /* change IF */
553 UF
= UB
; /* change UF */
554 int_req
= int_req
| INT_NO_CIF_PENDING
; /* clr intr inhibit */
556 if (MEM_ADDR_OK (MA
)) M
[MA
] = PC
;
558 PC
= (MA
+ 1) & 07777;
561 case 021: /* JMS, dir, curr */
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 */
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 */
573 IF
= IB
; /* change IF */
574 UF
= UB
; /* change UF */
575 int_req
= int_req
| INT_NO_CIF_PENDING
; /* clr intr inhibit */
577 if (MEM_ADDR_OK (MA
)) M
[MA
] = PC
;
579 PC
= (MA
+ 1) & 07777;
582 case 022: /* JMS, indir, zero */
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 */
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 */
596 IF
= IB
; /* change IF */
597 UF
= UB
; /* change UF */
598 int_req
= int_req
| INT_NO_CIF_PENDING
; /* clr intr inhibit */
600 if (MEM_ADDR_OK (MA
)) M
[MA
] = PC
;
602 PC
= (MA
+ 1) & 07777;
605 case 023: /* JMS, indir, curr */
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 */
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 */
619 IF
= IB
; /* change IF */
620 UF
= UB
; /* change UF */
621 int_req
= int_req
| INT_NO_CIF_PENDING
; /* clr intr inhibit */
623 if (MEM_ADDR_OK (MA
)) M
[MA
] = PC
;
625 PC
= (MA
+ 1) & 07777;
628 /* Opcode 5, JMP. From Bernhard Baehr's description of the TSC8-75:
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). */
636 case 024: /* JMP, dir, zero */
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 */
647 IF
= IB
; /* change IF */
648 UF
= UB
; /* change UF */
649 int_req
= int_req
| INT_NO_CIF_PENDING
; /* clr intr inhibit */
653 /* If JMP direct, also check for idle (KSF/JMP *-1) and infinite loop */
655 case 025: /* JMP, dir, curr */
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 */
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 */
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 */
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 */
686 case 026: /* JMP, indir, zero */
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 */
699 IF
= IB
; /* change IF */
700 UF
= UB
; /* change UF */
701 int_req
= int_req
| INT_NO_CIF_PENDING
; /* clr intr inhibit */
705 case 027: /* JMP, indir, curr */
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 */
718 IF
= IB
; /* change IF */
719 UF
= UB
; /* change UF */
720 int_req
= int_req
| INT_NO_CIF_PENDING
; /* clr intr inhibit */
724 /* Opcode 7, OPR group 1 */
726 case 034:case 035: /* OPR, group 1 */
727 switch ((IR
>> 4) & 017) { /* decode IR<4:7> */
736 case 3: /* CMA CML */
742 case 5: /* CLL CML = STL */
745 case 6: /* CLL CMA */
746 LAC
= (LAC
^ 07777) & 07777;
748 case 7: /* CLL CMA CML */
749 LAC
= (LAC
^ 07777) | 010000;
754 case 011: /* CLA CML */
755 LAC
= (LAC
& 010000) ^ 010000;
757 case 012: /* CLA CMA = STA */
760 case 013: /* CLA CMA CML */
761 LAC
= (LAC
| 07777) ^ 010000;
763 case 014: /* CLA CLL */
766 case 015: /* CLA CLL CML */
769 case 016: /* CLA CLL CMA */
772 case 017: /* CLA CLL CMA CML */
775 } /* end switch opers */
777 if (IR
& 01) LAC
= (LAC
+ 1) & 017777; /* IAC */
778 switch ((IR
>> 1) & 07) { /* decode IR<8:10> */
782 LAC
= (LAC
& 010000) | ((LAC
>> 6) & 077) | ((LAC
& 077) << 6);
785 LAC
= ((LAC
<< 1) | (LAC
>> 12)) & 017777;
788 LAC
= ((LAC
<< 2) | (LAC
>> 11)) & 017777;
791 LAC
= ((LAC
>> 1) | (LAC
<< 12)) & 017777;
794 LAC
= ((LAC
>> 2) | (LAC
<< 11)) & 017777;
796 case 6: /* RAL RAR - undef */
797 LAC
= LAC
& (IR
| 010000); /* uses AND path */
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 */
805 /* OPR group 2. From Bernhard Baehr's description of the TSC8-75:
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. */
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> */
817 PC
= (PC
+ 1) & 07777;
820 if (LAC
>= 010000) PC
= (PC
+ 1) & 07777;
823 if (LAC
< 010000) PC
= (PC
+ 1) & 07777;
826 if ((LAC
& 07777) == 0) PC
= (PC
+ 1) & 07777;
829 if ((LAC
& 07777) != 0) PC
= (PC
+ 1) & 07777;
831 case 6: /* SZA | SNL */
832 if ((LAC
== 0) || (LAC
>= 010000))
833 PC
= (PC
+ 1) & 07777;
835 case 7: /* SNA & SZL */
836 if ((LAC
!= 0) && (LAC
< 010000)) PC
= (PC
+ 1) & 07777;
839 if ((LAC
& 04000) != 0) PC
= (PC
+ 1) & 07777;
842 if ((LAC
& 04000) == 0) PC
= (PC
+ 1) & 07777;
844 case 012: /* SMA | SNL */
845 if (LAC
>= 04000) PC
= (PC
+ 1) & 07777;
847 case 013: /* SPA & SZL */
848 if (LAC
< 04000) PC
= (PC
+ 1) & 07777;
850 case 014: /* SMA | SZA */
851 if (((LAC
& 04000) != 0) || ((LAC
& 07777) == 0))
852 PC
= (PC
+ 1) & 07777;
854 case 015: /* SPA & SNA */
855 if (((LAC
& 04000) == 0) && ((LAC
& 07777) != 0))
856 PC
= (PC
+ 1) & 07777;
858 case 016: /* SMA | SZA | SNL */
859 if ((LAC
>= 04000) || (LAC
== 0)) PC
= (PC
+ 1) & 07777;
861 case 017: /* SPA & SNA & SZL */
862 if ((LAC
< 04000) && (LAC
!= 0)) PC
= (PC
+ 1) & 07777;
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 */
872 if (IR
& 04) LAC
= LAC
| OSR
; /* OSR */
873 if (IR
& 02) reason
= STOP_HALT
; /* HLT */
876 } /* end if group 2 */
878 /* OPR group 3 standard
880 MQA!MQL exchanges AC and MQ, as follows:
884 LAC = LAC & 010000 | temp;
887 temp
= MQ
; /* group 3 */
888 if (IR
& 0200) LAC
= LAC
& 010000; /* CLA */
889 if (IR
& 0020) { /* MQL */
893 if (IR
& 0100) LAC
= LAC
| temp
; /* MQA */
894 if ((IR
& 0056) && (cpu_unit
.flags
& UNIT_NOEAE
)) {
895 reason
= stop_inst
; /* EAE not present */
901 The EAE operates in two modes:
903 Mode A, PDP-8/I compatible
904 Mode B, extended capability
906 Mode B provides eight additional subfunctions; in addition, some
907 of the Mode A functions operate differently in Mode B.
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.
915 if (IR
== 07431) { /* SWAB */
916 emode
= 1; /* set mode flag */
919 if (IR
== 07447) { /* SWBA */
920 emode
= gtf
= 0; /* clear mode, gtf */
924 /* If not switching modes, the EAE operation is determined by the mode
927 <6:10> mode A mode B comments
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
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
941 1x011 SCA + DVI SWBA NOP if not detected earlier
943 1x101 SCA + SHL DPIC must be combined with MQA!MQL
944 1x110 SCA + ASR DCM must be combined with MQA!MQL
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.
952 if (emode
== 0) gtf
= 0; /* mode A? clr gtf */
953 switch ((IR
>> 1) & 027) { /* decode IR<6,8:10> */
955 case 020: /* mode A, B: SCA */
958 case 000: /* mode A, B: NOP */
961 case 021: /* mode B: DAD */
964 if ((MA
& 07770) != 00010) MA
= DF
| M
[MA
]; /* indirect; autoinc? */
965 else MA
= DF
| (M
[MA
] = (M
[MA
] + 1) & 07777); /* incr before use */
967 MA
= DF
| ((MA
+ 1) & 07777);
968 LAC
= (LAC
& 07777) + M
[MA
] + (MQ
>> 12);
970 PC
= (PC
+ 1) & 07777;
973 LAC
= LAC
| SC
; /* mode A: SCA then */
974 case 001: /* mode B: ACS */
979 else { /* mode A: SCL */
980 SC
= (~M
[IF
| PC
]) & 037;
981 PC
= (PC
+ 1) & 07777;
985 case 022: /* mode B: DST */
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;
996 LAC
= LAC
| SC
; /* mode A: SCA then */
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 */
1003 temp
= (MQ
* M
[MA
]) + (LAC
& 07777);
1004 LAC
= (temp
>> 12) & 07777;
1006 PC
= (PC
+ 1) & 07777;
1007 SC
= 014; /* 12 shifts */
1010 case 023: /* mode B: SWBA */
1012 LAC
= LAC
| SC
; /* mode A: SCA then */
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 */
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 */
1025 temp
= ((LAC
& 07777) << 12) | MQ
;
1028 SC
= 015; /* 13 shifts */
1030 PC
= (PC
+ 1) & 07777;
1033 case 024: /* mode B: DPSZ */
1035 if (((LAC
| MQ
) & 07777) == 0) PC
= (PC
+ 1) & 07777;
1038 LAC
= LAC
| SC
; /* mode A: SCA then */
1040 temp
= (LAC
<< 12) | MQ
; /* preserve link */
1041 for (SC
= 0; ((temp
& 017777777) != 0) &&
1042 (temp
& 040000000) == ((temp
<< 1) & 040000000); SC
++)
1044 LAC
= (temp
>> 12) & 017777;
1046 if (emode
&& ((LAC
& 07777) == 04000) && (MQ
== 0))
1047 LAC
= LAC
& 010000; /* clr if 4000'0000 */
1050 case 025: /* mode B: DPIC */
1052 temp
= (LAC
+ 1) & 07777; /* SWP already done! */
1053 LAC
= MQ
+ (temp
== 0);
1057 LAC
= LAC
| SC
; /* mode A: SCA then */
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;
1064 PC
= (PC
+ 1) & 07777;
1065 SC
= emode
? 037: 0; /* SC = 0 if mode A */
1068 case 026: /* mode B: DCM */
1070 temp
= (-LAC
) & 07777; /* SWP already done! */
1071 LAC
= (MQ
^ 07777) + (temp
== 0);
1075 LAC
= LAC
| SC
; /* mode A: SCA then */
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;
1085 PC
= (PC
+ 1) & 07777;
1086 SC
= emode
? 037: 0; /* SC = 0 if mode A */
1089 case 027: /* mode B: SAM */
1092 LAC
= MQ
+ (temp
^ 07777) + 1; /* L'AC = MQ - AC */
1093 gtf
= (temp
<= MQ
) ^ ((temp
^ MQ
) >> 11);
1096 LAC
= LAC
| SC
; /* mode A: SCA then */
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;
1105 PC
= (PC
+ 1) & 07777;
1106 SC
= emode
? 037: 0; /* SC = 0 if mode A */
1109 break; /* end case 7 */
1111 /* Opcode 6, IOT. From Bernhard Baehr's description of the TSC8-75:
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. */
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 */
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> */
1130 case 000: /* CPU control */
1131 switch (pulse
) { /* decode IR<9:11> */
1134 if (int_req
& INT_ION
) PC
= (PC
+ 1) & 07777;
1135 int_req
= int_req
& ~INT_ION
;
1139 int_req
= (int_req
| INT_ION
) & ~INT_NO_ION_PENDING
;
1143 int_req
= int_req
& ~INT_ION
;
1147 if (int_req
& INT_ALL
) PC
= (PC
+ 1) & 07777;
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
;
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
;
1167 if (gtf
) PC
= (PC
+ 1) & 07777;
1173 int_req
= int_req
& INT_NO_CIF_PENDING
;
1175 int_enable
= INT_INIT_ENABLE
;
1177 reset_all (1); /* reset all dev */
1179 } /* end switch pulse */
1180 break; /* end case 0 */
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> */
1187 DF
= (IR
& 0070) << 9;
1191 IB
= (IR
& 0070) << 9;
1192 int_req
= int_req
& ~INT_NO_CIF_PENDING
;
1195 case 3: /* CDF CIF */
1196 DF
= IB
= (IR
& 0070) << 9;
1197 int_req
= int_req
& ~INT_NO_CIF_PENDING
;
1201 switch (device
& 07) { /* decode IR<6:8> */
1204 int_req
= int_req
& ~INT_UF
;
1208 LAC
= LAC
| (DF
>> 9);
1212 LAC
= LAC
| (IF
>> 9);
1220 UB
= (SF
& 0100) >> 6;
1221 IB
= (SF
& 0070) << 9;
1222 DF
= (SF
& 0007) << 12;
1223 int_req
= int_req
& ~INT_NO_CIF_PENDING
;
1227 if (int_req
& INT_UF
) PC
= (PC
+ 1) & 07777;
1232 int_req
= int_req
& ~INT_NO_CIF_PENDING
;
1237 int_req
= int_req
& ~INT_NO_CIF_PENDING
;
1239 } /* end switch device */
1245 } /* end switch pulse */
1246 break; /* end case 20-27 */
1248 case 010: /* power fail */
1249 switch (pulse
) { /* decode IR<9:11> */
1255 if (int_req
& INT_PWR
) PC
= (PC
+ 1) & 07777;
1259 int_req
= int_req
& ~INT_PWR
;
1265 } /* end switch pulse */
1266 break; /* end case 10 */
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
;
1276 else reason
= stop_inst
; /* stop on flag */
1278 } /* end switch device */
1279 break; /* end case IOT */
1280 } /* end switch opcode */
1283 /* Simulation halted */
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 */
1291 } /* end sim_instr */
1295 t_stat
cpu_reset (DEVICE
*dptr
)
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');
1307 /* Memory examine */
1309 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1311 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1312 if (vptr
!= NULL
) *vptr
= M
[addr
] & 07777;
1316 /* Memory deposit */
1318 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1320 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1321 M
[addr
] = val
& 07777;
1325 /* Memory size change */
1327 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1332 if ((val
<= 0) || (val
> MAXMEMSIZE
) || ((val
& 07777) != 0))
1334 for (i
= val
; i
< MEMSIZE
; i
++) mc
= mc
| M
[i
];
1335 if ((mc
!= 0) && (!get_yn ("Really truncate memory [N]?", FALSE
)))
1338 for (i
= MEMSIZE
; i
< MAXMEMSIZE
; i
++) M
[i
] = 0;
1342 /* Change device number for a device */
1344 t_stat
set_dev (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
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 */
1363 /* Show device number for a device */
1365 t_stat
show_dev (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
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);
1380 /* CPU device handler - should never get here! */
1382 int32
bad_dev (int32 IR
, int32 AC
)
1384 return (SCPE_IERR
<< IOT_V_REASON
) | AC
; /* broken! */
1387 /* Build device dispatch table */
1389 t_bool
build_dev_tab (void)
1394 static const uint8 std_dev
[] = {
1395 000, 010, 020, 021, 022, 023, 024, 025, 026, 027
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
);
1414 dev_tab
[dibp
->dev
+ j
] = dibp
->dsp
[j
]; /* fill */
1424 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1430 for (i
= 0; i
< hst_lnt
; i
++) hst
[i
].pc
= 0;
1434 lnt
= (int32
) get_uint (cptr
, 10, HIST_MAX
, &r
);
1435 if ((r
!= SCPE_OK
) || (lnt
&& (lnt
< HIST_MIN
))) return SCPE_ARG
;
1443 hst
= (InstHistory
*) calloc (lnt
, sizeof (InstHistory
));
1444 if (hst
== NULL
) return SCPE_MEM
;
1452 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1454 int32 l
, k
, di
, lnt
;
1455 char *cptr
= (char *) desc
;
1459 extern t_stat
fprint_sym (FILE *ofile
, t_addr addr
, t_value
*val
,
1460 UNIT
*uptr
, int32 sw
);
1462 if (hst_lnt
== 0) return SCPE_NOFNC
; /* enabled? */
1464 lnt
= (int32
) get_uint (cptr
, 10, hst_lnt
, &r
);
1465 if ((r
!= SCPE_OK
) || (lnt
== 0)) return SCPE_ARG
;
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
, " ");
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 */