1 /* pdp10_cpu.c: PDP-10 CPU simulator
2
3 Copyright (c) 1993-2012, 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 KS10 central processor
27
28 25-Mar-12 RMS Added missing parameters to prototypes (Mark Pizzolato)
29 17-Jul-07 RMS Fixed non-portable usage in SHOW HISTORY
30 28-Apr-07 RMS Removed clock initialization
31 22-Sep-05 RMS Fixed declarations (Sterling Garwood)
32 Fixed warning in MOVNI
33 16-Aug-05 RMS Fixed C++ declaration and cast problems
34 10-Nov-04 RMS Added instruction history
35 08-Oct-02 RMS Revised to build dib_tab dynamically
36 Added SHOW IOSPACE
37 30-Dec-01 RMS Added old PC queue
38 25-Dec-01 RMS Cleaned up sim_inst declarations
39 07-Dec-01 RMS Revised to use new breakpoint package
40 21-Nov-01 RMS Implemented ITS 1-proceed hack
41 31-Aug-01 RMS Changed int64 to t_int64 for Windoze
42 10-Aug-01 RMS Removed register in declarations
43 17-Jul-01 RMS Moved function prototype
44 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug
45 29-Apr-01 RMS Fixed modifier naming conflict
46 Fixed XCTR/XCTRI, UMOVE/UMOVEM, BLTUB/BLTBU for ITS
47 Added CLRCSH for ITS
48
49 The 36b system family had six different implementions: PDP-6, KA10, KI10,
50 L10, KL10 extended, and KS10. This simulator implements the KS10.
51
52 The register state for the KS10 is:
53
54 AC[8][16] accumulators
55 PC program counter
56 flags<0:11> state flags
57 pi_enb<1:7> enabled PI levels
58 pi_act<1:7> active PI levels
59 pi_prq<1:7> program PI requests
60 apr_enb<0:7> enabled system flags
61 apr_flg<0:7> system flags
62 ebr executive base register
63 ubr user base register
64 hsb halt status block address
65 spt SPT base
66 cst CST base
67 pur process use register
68 cstm CST mask
69
70 The PDP-10 had just two instruction formats: memory reference
71 and I/O.
72
73 000000000 0111 1 1111 112222222222333333
74 012345678 9012 3 4567 890123456789012345
75 +---------+----+-+----+------------------+
76 | opcode | ac |i| idx| address | memory reference
77 +---------+----+-+----+------------------+
78
79 000 0000000 111 1 1111 112222222222333333
80 012 3456789 012 3 4567 890123456789012345
81 +---+-------+---+-+----+------------------+
82 |111|device |iop|i| idx| address | I/O
83 +---+-------+---+-+----+------------------+
84
85 This routine is the instruction decode routine for the PDP-10.
86 It is called from the simulator control program to execute
87 instructions in simulated memory, starting at the simulated PC.
88 It runs until an abort occurs.
89
90 General notes:
91
92 1. Reasons to stop. The simulator can be stopped by:
93
94 HALT instruction
95 MUUO instruction in executive mode
96 pager error in interrupt sequence
97 invalid vector table in interrupt sequence
98 illegal instruction in interrupt sequence
99 breakpoint encountered
100 nested indirects exceeding limit
101 nested XCT's exceeding limit
102 I/O error in I/O simulator
103
104 2. Interrupts. PDP-10's have a seven level priority interrupt
105 system. Interrupt requests can come from internal sources,
106 such as APR program requests, or external sources, such as
107 I/O devices. The requests are stored in pi_prq for program
108 requests, pi_apr for other internal flags, and pi_ioq for
109 I/O device flags. Internal and device (but not program)
110 interrupts must be enabled on a level by level basis. When
111 an interrupt is granted on a level, interrupts at that level
112 and below are masked until the interrupt is dismissed.
113
114 The I/O device interrupt system is taken from the PDP-11.
115 int_req stores the interrupt requests for Unibus I/O devices.
116 Routines in the Unibus adapter map requests in int_req to
117 PDP-10 levels. The Unibus adapter also calculates which
118 device to get a vector from when a PDP-10 interrupt is granted.
119
120 3. Arithmetic. The PDP-10 is a 2's complement system.
121
122 4. Adding I/O devices. These modules must be modified:
123
124 pdp10_defs.h add device address and interrupt definitions
125 pdp10_sys.c add sim_devices table entry
126
127 A note on ITS 1-proceed. The simulator follows the implementation
128 on the KS10, keeping 1-proceed as a side flag (its_1pr) rather than
129 as flags<8>. This simplifies the flag saving instructions, which
130 don't have to clear flags<8> before saving it. Instead, the page
131 fail and interrupt code must restore flags<8> from its_1pr. Unlike
132 the KS10, the simulator will not lose the 1-proceed trap if the
133 1-proceeded instructions clears 1-proceed.
134 */
135
136 #include "pdp10_defs.h"
137 #include <setjmp.h>
138
139 #define PCQ_SIZE 64 /* must be 2**n */
140 #define PCQ_MASK (PCQ_SIZE - 1)
141 #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
142
143 #define HIST_PC 0x40000000
144 #define HIST_MIN 64
145 #define HIST_MAX 65536
146
147 typedef struct {
148 a10 pc;
149 a10 ea;
150 d10 ir;
151 d10 ac;
152 } InstHistory;
153
154 d10 *M = NULL; /* memory */
155 d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */
156 d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */
157 a10 epta, upta; /* proc tbl addr (dyn) */
158 a10 saved_PC = 0; /* scp: saved PC */
159 d10 pager_word = 0; /* pager: error word */
160 a10 pager_PC = 0; /* pager: saved PC */
161 int32 pager_flags = 0; /* pager: trap flags */
162 t_bool pager_pi = FALSE; /* pager: in pi seq */
163 t_bool pager_tc = FALSE; /* pager: trap cycle */
164 d10 ebr = 0; /* exec base reg */
165 d10 ubr = 0; /* user base reg */
166 d10 hsb = 0; /* halt status block */
167 d10 spt = 0; /* TOPS20 paging regs */
168 d10 cst = 0;
169 d10 pur = 0;
170 d10 cstm = 0;
171 a10 dbr1 = 0; /* ITS paging regs */
172 a10 dbr2 = 0;
173 a10 dbr3 = 0;
174 a10 dbr4 = 0;
175 d10 pcst = 0; /* ITS PC sampling */
176 int32 pi_on = 0; /* pi system enable */
177 int32 pi_enb = 0; /* pi enabled levels */
178 int32 pi_act = 0; /* pi active levels */
179 int32 pi_ioq = 0; /* pi io requests */
180 int32 pi_apr = 0; /* pi apr requests */
181 int32 pi_prq = 0; /* pi prog requests */
182 int32 apr_enb = 0; /* apr enables */
183 int32 apr_flg = 0; /* apr flags */
184 int32 apr_lvl = 0; /* apr level */
185 int32 qintr = 0; /* interrupt pending */
186 int32 flags = 0; /* flags */
187 int32 its_1pr = 0; /* ITS 1-proceed */
188 int32 stop_op0 = 0; /* stop on 0 */
189 int32 rlog = 0; /* extend fixup log */
190 int32 ind_max = 32; /* nested ind limit */
191 int32 xct_max = 32; /* nested XCT limit */
192 int32 t20_idlelock = 0; /* TOPS-20 idle lock */
193 a10 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
194 int32 pcq_p = 0; /* PC queue ptr */
195 REG *pcq_r = NULL; /* PC queue reg ptr */
196 jmp_buf save_env;
197 int32 hst_p = 0; /* history pointer */
198 int32 hst_lnt = 0; /* history length */
199 InstHistory *hst = NULL; /* instruction history */
200
201 extern int32 sim_int_char;
202 extern int32 sim_interval;
203 extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
204
205 /* Forward and external declarations */
206
207 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
208 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
209 t_stat cpu_reset (DEVICE *dptr);
210 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
211 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
212 d10 adjsp (d10 val, a10 ea);
213 void ibp (a10 ea, int32 pflgs);
214 d10 ldb (a10 ea, int32 pflgs);
215 void dpb (d10 val, a10 ea, int32 pflgs);
216 void adjbp (int32 ac, a10 ea, int32 pflgs);
217 d10 add (d10 val, d10 mb);
218 d10 sub (d10 val, d10 mb);
219 void dadd (int32 ac, d10 *rs);
220 void dsub (int32 ac, d10 *rs);
221 int32 jffo (d10 val);
222 d10 lsh (d10 val, a10 ea);
223 d10 rot (d10 val, a10 ea);
224 d10 ash (d10 val, a10 ea);
225 void lshc (int32 ac, a10 ea);
226 void rotc (int32 ac, a10 ea);
227 void ashc (int32 ac, a10 ea);
228 void circ (int32 ac, a10 ea);
229 void blt (int32 ac, a10 ea, int32 pflgs);
230 void bltu (int32 ac, a10 ea, int32 pflgs, int dir);
231 a10 calc_ea (d10 inst, int32 prv);
232 a10 calc_ioea (d10 inst, int32 prv);
233 d10 calc_jrstfea (d10 inst, int32 pflgs);
234 void pi_dismiss (void);
235 void set_newflags (d10 fl, t_bool jrst);
236 extern t_bool aprid (a10 ea, int32 prv);
237 t_bool wrpi (a10 ea, int32 prv);
238 t_bool rdpi (a10 ea, int32 prv);
239 t_bool czpi (a10 ea, int32 prv);
240 t_bool copi (a10 ea, int32 prv);
241 t_bool wrapr (a10 ea, int32 prv);
242 t_bool rdapr (a10 ea, int32 prv);
243 t_bool czapr (a10 ea, int32 prv);
244 t_bool coapr (a10 ea, int32 prv);
245 int32 pi_eval (void);
246 int32 test_int (void);
247 void set_ac_display (d10 *acbase);
248
249 extern t_stat build_dib_tab (void);
250 extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc);
251 extern d10 Read (a10 ea, int32 prv); /* read, read check */
252 extern d10 ReadM (a10 ea, int32 prv); /* read, write check */
253 extern d10 ReadE (a10 ea); /* read, exec */
254 extern d10 ReadP (a10 ea); /* read, physical */
255 extern void Write (a10 ea, d10 val, int32 prv); /* write */
256 extern void WriteE (a10 ea, d10 val); /* write, exec */
257 extern void WriteP (a10 ea, d10 val); /* write, physical */
258 extern t_bool AccViol (a10 ea, int32 prv, int32 mode); /* access check */
259 extern void set_dyn_ptrs (void);
260 extern a10 conmap (a10 ea, int32 mode, int32 sw);
261 extern void fe_intr ();
262 extern void dfad (int32 ac, d10 *rs, int32 inv);
263 extern void dfmp (int32 ac, d10 *rs);
264 extern void dfdv (int32 ac, d10 *rs);
265 extern void dmul (int32 ac, d10 *rs);
266 extern void ddiv (int32 ac, d10 *rs);
267 extern void fix (int32 ac, d10 mb, t_bool rnd);
268 extern d10 fad (d10 val, d10 mb, t_bool rnd, int32 inv);
269 extern d10 fmp (d10 val, d10 mb, t_bool rnd);
270 extern t_bool fdv (d10 val, d10 mb, d10 *rs, t_bool rnd);
271 extern d10 fsc (d10 val, a10 ea);
272 extern d10 fltr (d10 mb);
273 extern int xtend (int32 ac, a10 ea, int32 pflgs);
274 extern void xtcln (int32 rlog);
275 extern d10 map (a10 ea, int32 prv);
276 extern d10 imul (d10 val, d10 mb);
277 extern t_bool idiv (d10 val, d10 mb, d10 *rs);
278 extern void mul (d10 val, d10 mb, d10 *rs);
279 extern t_bool divi (int32 ac, d10 mb, d10 *rs);
280 extern t_bool io710 (int32 ac, a10 ea);
281 extern t_bool io711 (int32 ac, a10 ea);
282 extern d10 io712 (a10 ea);
283 extern void io713 (d10 val, a10 ea);
284 extern void io714 (d10 val, a10 ea);
285 extern void io715 (d10 val, a10 ea);
286 extern t_bool io720 (int32 ac, a10 ea);
287 extern t_bool io721 (int32 ac, a10 ea);
288 extern d10 io722 (a10 ea);
289 extern void io723 (d10 val, a10 ea);
290 extern void io724 (d10 val, a10 ea);
291 extern void io725 (d10 val, a10 ea);
292 extern t_bool clrcsh (a10 ea, int32 prv);
293 extern t_bool clrpt (a10 ea, int32 prv);
294 extern t_bool wrubr (a10 ea, int32 prv);
295 extern t_bool wrebr (a10 ea, int32 prv);
296 extern t_bool wrhsb (a10 ea, int32 prv);
297 extern t_bool wrspb (a10 ea, int32 prv);
298 extern t_bool wrcsb (a10 ea, int32 prv);
299 extern t_bool wrpur (a10 ea, int32 prv);
300 extern t_bool wrcstm (a10 ea, int32 prv);
301 extern t_bool ldbr1 (a10 ea, int32 prv);
302 extern t_bool ldbr2 (a10 ea, int32 prv);
303 extern t_bool ldbr3 (a10 ea, int32 prv);
304 extern t_bool ldbr4 (a10 ea, int32 prv);
305 extern t_bool rdubr (a10 ea, int32 prv);
306 extern t_bool rdebr (a10 ea, int32 prv);
307 extern t_bool rdhsb (a10 ea, int32 prv);
308 extern t_bool rdspb (a10 ea, int32 prv);
309 extern t_bool rdcsb (a10 ea, int32 prv);
310 extern t_bool rdpur (a10 ea, int32 prv);
311 extern t_bool rdcstm (a10 ea, int32 prv);
312 extern t_bool sdbr1 (a10 ea, int32 prv);
313 extern t_bool sdbr2 (a10 ea, int32 prv);
314 extern t_bool sdbr3 (a10 ea, int32 prv);
315 extern t_bool sdbr4 (a10 ea, int32 prv);
316 extern t_bool rdtim (a10 ea, int32 prv);
317 extern t_bool rdint (a10 ea, int32 prv);
318 extern t_bool wrtim (a10 ea, int32 prv);
319 extern t_bool wrint (a10 ea, int32 prv);
320 extern t_bool rdpcst (a10 ea, int32 prv);
321 extern t_bool wrpcst (a10 ea, int32 prv);
322 extern t_bool spm (a10 ea, int32 prv);
323 extern t_bool lpmr (a10 ea, int32 prv);
324 extern int32 pi_ub_vec (int32 lvl, int32 *uba);
325 extern t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc);
326
327 /* CPU data structures
328
329 cpu_dev CPU device descriptor
330 cpu_unit CPU unit
331 cpu_reg CPU register list
332 cpu_mod CPU modifier list
333 */
334
335 UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MAXMEMSIZE) };
336
337 REG cpu_reg[] = {
338 { ORDATA (PC, saved_PC, VASIZE) },
339 { ORDATA (FLAGS, flags, 18) },
340 { ORDATA (AC0, acs[0], 36) }, /* addr in memory */
341 { ORDATA (AC1, acs[1], 36) }, /* modified at exit */
342 { ORDATA (AC2, acs[2], 36) }, /* to SCP */
343 { ORDATA (AC3, acs[3], 36) },
344 { ORDATA (AC4, acs[4], 36) },
345 { ORDATA (AC5, acs[5], 36) },
346 { ORDATA (AC6, acs[6], 36) },
347 { ORDATA (AC7, acs[7], 36) },
348 { ORDATA (AC10, acs[10], 36) },
349 { ORDATA (AC11, acs[11], 36) },
350 { ORDATA (AC12, acs[12], 36) },
351 { ORDATA (AC13, acs[13], 36) },
352 { ORDATA (AC14, acs[14], 36) },
353 { ORDATA (AC15, acs[15], 36) },
354 { ORDATA (AC16, acs[16], 36) },
355 { ORDATA (AC17, acs[17], 36) },
356 { ORDATA (PFW, pager_word, 36) },
357 { ORDATA (EBR, ebr, EBR_N_EBR) },
358 { FLDATA (PGON, ebr, EBR_V_PGON) },
359 { FLDATA (T20P, ebr, EBR_V_T20P) },
360 { ORDATA (UBR, ubr, 36) },
361 { GRDATA (CURAC, ubr, 8, 3, UBR_V_CURAC), REG_RO },
362 { GRDATA (PRVAC, ubr, 8, 3, UBR_V_PRVAC) },
363 { ORDATA (SPT, spt, 36) },
364 { ORDATA (CST, cst, 36) },
365 { ORDATA (PUR, pur, 36) },
366 { ORDATA (CSTM, cstm, 36) },
367 { ORDATA (HSB, hsb, 36) },
368 { ORDATA (DBR1, dbr1, PASIZE) },
369 { ORDATA (DBR2, dbr2, PASIZE) },
370 { ORDATA (DBR3, dbr3, PASIZE) },
371 { ORDATA (DBR4, dbr4, PASIZE) },
372 { ORDATA (PCST, pcst, 36) },
373 { ORDATA (PIENB, pi_enb, 7) },
374 { FLDATA (PION, pi_on, 0) },
375 { ORDATA (PIACT, pi_act, 7) },
376 { ORDATA (PIPRQ, pi_prq, 7) },
377 { ORDATA (PIIOQ, pi_ioq, 7), REG_RO },
378 { ORDATA (PIAPR, pi_apr, 7), REG_RO },
379 { ORDATA (APRENB, apr_enb, 8) },
380 { ORDATA (APRFLG, apr_flg, 8) },
381 { ORDATA (APRLVL, apr_lvl, 3) },
382 { ORDATA (RLOG, rlog, 10) },
383 { FLDATA (F1PR, its_1pr, 0) },
384 { BRDATA (PCQ, pcq, 8, VASIZE, PCQ_SIZE), REG_RO+REG_CIRC },
385 { ORDATA (PCQP, pcq_p, 6), REG_HRO },
386 { DRDATA (INDMAX, ind_max, 8), PV_LEFT + REG_NZ },
387 { DRDATA (XCTMAX, xct_max, 8), PV_LEFT + REG_NZ },
388 { ORDATA (WRU, sim_int_char, 8) },
389 { FLDATA (STOP_ILL, stop_op0, 0) },
390 { BRDATA (REG, acs, 8, 36, AC_NUM * AC_NBLK) },
391 { NULL }
392 };
393
394 MTAB cpu_mod[] = {
395 { UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, "TOPS-10", "TOPS-10", &tim_set_mod },
396 { UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, NULL , "TOPS10", &tim_set_mod },
397 { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, "TOPS-20", "TOPS-20", &tim_set_mod },
398 { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, NULL, "TOPS20", &tim_set_mod },
399 { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_ITS, "ITS", "ITS", &tim_set_mod },
400 { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_KLAD, "diagnostic mode", "KLAD", &tim_set_mod },
401 { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
402 { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
403 { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL,
404 NULL, &show_iospace },
405 { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
406 &cpu_set_hist, &cpu_show_hist },
407 { 0 }
408 };
409
410 DEVICE cpu_dev = {
411 "CPU", &cpu_unit, cpu_reg, cpu_mod,
412 1, 8, PASIZE, 1, 8, 36,
413 &cpu_ex, &cpu_dep, &cpu_reset,
414 NULL, NULL, NULL
415 };
416
417 /* Data arrays */
418
419 const int32 pi_l2bit[8] = {
420 0, 0100, 0040, 0020, 0010, 0004, 0002, 0001
421 };
422
423 const int32 pi_m2lvl[128] = {
424 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
425 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
426 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
427 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
428 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
429 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
430 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
432 };
433
434 const d10 bytemask[64] = { 0,
435 01, 03, 07, 017, 037, 077,
436 0177, 0377, 0777, 01777, 03777, 07777,
437 017777, 037777, 077777,
438 0177777, 0377777, 0777777,
439 01777777, 03777777, 07777777,
440 017777777, 037777777, 077777777,
441 0177777777, 0377777777, 0777777777,
442 01777777777, 03777777777, 07777777777,
443 017777777777, 037777777777, 077777777777,
444 0177777777777, 0377777777777, 0777777777777,
445 ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES,
446 ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES,
447 ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES
448 };
449
450 static t_bool (*io700d[16])(a10, int32) = {
451 &aprid, NULL, NULL, NULL, &wrapr, &rdapr, &czapr, &coapr,
452 NULL, NULL, NULL, NULL, &wrpi, &rdpi, &czpi, &copi
453 };
454 static t_bool (*io701d[16])(a10, int32) = {
455 NULL, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL,
456 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
457 };
458 static t_bool (*io702d[16])(a10, int32) = {
459 &rdspb, &rdcsb, &rdpur, &rdcstm, &rdtim, &rdint, &rdhsb, NULL,
460 &wrspb, &wrcsb, &wrpur, &wrcstm, &wrtim, &wrint, &wrhsb, NULL
461 };
462 #define io700i io700d
463 static t_bool (*io701i[16])(a10, int32) = {
464 &clrcsh, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL,
465 NULL, &rdpcst, NULL, &wrpcst, NULL, NULL, NULL, NULL
466 };
467 static t_bool (*io702i[16])(a10, int32) = {
468 &sdbr1, &sdbr2, &sdbr3, &sdbr4, &rdtim, &rdint, &rdhsb, &spm,
469 &ldbr1, &ldbr2, &ldbr3, &ldbr4, &wrtim, &wrint, &wrhsb, &lpmr
470 };
471
472 /* JRST classes and validation table */
473
474 #define JRST_U 1 /* ok anywhere */
475 #define JRST_E 2 /* ok exec mode */
476 #define JRST_UIO 3 /* ok user I/O mode */
477
478 static t_stat jrst_tab[16] = {
479 JRST_U, JRST_U, JRST_U, 0, JRST_E, JRST_U, JRST_E, JRST_E,
480 JRST_UIO, 0, JRST_UIO, 0, JRST_E, JRST_U, 0, 0
481 };
482
483 /* Address operations */
484
485 #define IM ((d10) ea)
486 #define IMS (((d10) ea) << 18)
487 #define JUMP(x) PCQ_ENTRY, PC = ((a10) (x)) & AMASK
488 #define SUBJ(x) CLRF (F_AFI | F_FPD | F_TR); JUMP (x)
489 #define INCPC PC = INCA (PC)
490
491 /* AC operations */
492
493 #define AOBAC AC(ac) = AOB (AC(ac))
494 #define SOBAC AC(ac) = SOB (AC(ac))
495 #define G2AC rs[0] = AC(ac), rs[1] = AC(P1)
496 #define S1AC AC(ac) = rs[0]
497 #define S2AC S1AC, AC(P1) = rs[1]
498 #define LAC if (ac) AC(ac) = mb
499
500 /* Memory operations */
501
502 #define RD mb = Read (ea, MM_OPND)
503 #define RDAC AC(ac) = Read (ea, MM_OPND)
504 #define RM mb = ReadM (ea, MM_OPND)
505 #define RMAC AC(ac) = ReadM (ea, MM_OPND)
506 #define RDP mb = Read (((a10) AC(ac)) & AMASK, MM_BSTK)
507 #define RD2 rs[0] = Read (ea, MM_OPND); \
508 rs[1] = Read (INCA (ea), MM_OPND)
509 #define WR Write (ea, mb, MM_OPND)
510 #define WRAC Write (ea, AC(ac), MM_OPND)
511 #define WRP(x) Write (((a10) INCA (AC(ac))), (x), MM_BSTK)
512 #define WR1 Write (ea, rs[0], MM_OPND)
513 #define WR2 ReadM (INCA (ea), MM_OPND); \
514 Write (ea, rs[0], MM_OPND); \
515 Write (INCA (ea), rs[1], MM_OPND)
516
517 /* Tests and compares */
518
519 #define TL(a) (TSTS (a) != 0)
520 #define TE(a) ((a) == 0)
521 #define TLE(a) (TL (a) || TE (a))
522 #define TGE(a) (TSTS (a) == 0)
523 #define TN(a) ((a) != 0)
524 #define TG(a) (TGE (a) && TN (a))
525 #define CL(a) ((TSTS (AC(ac) ^ a))? (a < AC(ac)): (AC(ac) < a))
526 #define CE(a) (AC(ac) == a)
527 #define CLE(a) (CL (a) || CE (a))
528 #define CGE(a) (!CL (a))
529 #define CN(a) (AC(ac) != a)
530 #define CG(a) (CGE (a) && CN (a))
531
532 /* Word assemblies */
533
534 #define FLPC XWD (flags, PC)
535 #define UUOWORD (((d10) op) << INST_V_OP) | (((d10) ac) << INST_V_AC) | ea
536 #define APRHWORD ((apr_flg << APR_V_FLG) | (apr_lvl & APR_M_LVL) | \
537 ((apr_flg & apr_enb)? APR_IRQ: 0))
538 #define APRWORD ((apr_enb << (APR_V_FLG + 18)) | APRHWORD)
539 #define PIHWORD ((pi_act << PI_V_ACT) | (pi_on << PI_V_ON) | \
540 (pi_enb << PI_V_ENB))
541 #define PIWORD ((pi_prq << PI_V_PRQ) | PIHWORD)
542
543 /* Instruction operations */
544
545 #define CIBP if (!TSTF (F_FPD)) { ibp (ea, pflgs); SETF (F_FPD); }
546 #define LDB AC(ac) = ldb (ea, pflgs)
547 #define DPB dpb (AC(ac), ea, pflgs)
548 #define FAD(s) fad (AC(ac), s, FALSE, 0)
549 #define FADR(s) fad (AC(ac), s, TRUE, 0)
550 #define FSB(s) fad (AC(ac), s, FALSE, 1)
551 #define FSBR(s) fad (AC(ac), s, TRUE, 1)
552 #define FMP(s) fmp (AC(ac), s, FALSE)
553 #define FMPR(s) fmp (AC(ac), s, TRUE)
554 #define FDV(s) fdv (AC(ac), s, rs, FALSE)
555 #define FDVR(s) fdv (AC(ac), s, rs, TRUE)
556 #define MOVN(s) NEG (s); MOVNF(s)
557 #define MOVM(s) ABS (s); MOVMF(s)
558 #define ADD(s) add (AC(ac), s)
559 #define SUB(s) sub (AC(ac), s)
560 #define IMUL(s) imul (AC(ac), s)
561 #define IDIV(s) idiv (AC(ac), s, rs)
562 #define MUL(s) mul (AC(ac), s, rs)
563 #define DIV(s) divi (ac, s, rs)
564 #define AOJ AC(ac) = INC (AC(ac)); INCF (AC(ac))
565 #define AOS RM; mb = INC (mb); WR; INCF (mb); LAC
566 #define SOJ AC(ac) = DEC (AC(ac)); DECF (AC(ac))
567 #define SOS RM; mb = DEC (mb); WR; DECF (mb); LAC
568 #define SETCA(s) ~AC(ac) & DMASK
569 #define SETCM(s) ~(s) & DMASK;
570 #define AND(s) AC(ac) & (s)
571 #define ANDCA(s) ~AC(ac) & (s)
572 #define ANDCM(s) AC(ac) & ~(s)
573 #define ANDCB(s) (~AC(ac) & ~(s)) & DMASK
574 #define IOR(s) AC(ac) | (s)
575 #define ORCA(s) (~AC(ac) | (s)) & DMASK
576 #define ORCM(s) (AC(ac) | ~(s)) & DMASK
577 #define ORCB(s) (~AC(ac) | ~(s)) & DMASK
578 #define XOR(s) AC(ac) ^ (s)
579 #define EQV(s) (~(AC(ac) ^ (s))) & DMASK
580 #define LL(s,d) ((s) & LMASK) | ((d) & RMASK)
581 #define RL(s,d) (((s) << 18) & LMASK) | ((d) & RMASK)
582 #define RR(s,d) ((s) & RMASK) | ((d) & LMASK)
583 #define LR(s,d) (((s) >> 18) & RMASK) | ((d) & LMASK)
584 #define LLO(s) ((s) & LMASK) | RMASK
585 #define RLO(s) (((s) << 18) & LMASK) | RMASK
586 #define RRO(s) ((s) & RMASK) | LMASK
587 #define LRO(s) (((s) >> 18) & RMASK) | LMASK
588 #define LLE(s) ((s) & LMASK) | (((s) & LSIGN)? RMASK: 0)
589 #define RLE(s) (((s) << 18) & LMASK) | (((s) & RSIGN)? RMASK: 0)
590 #define RRE(s) ((s) & RMASK) | (((s) & RSIGN)? LMASK: 0)
591 #define LRE(s) (((s) >> 18) & RMASK) | (((s) & LSIGN)? LMASK: 0)
592 #define TD_ RD
593 #define TS_ RD; mb = SWP (mb)
594 #define TL_ mb = IMS
595 #define TR_ mb = IM
596 #define T_Z AC(ac) = AC(ac) & ~mb
597 #define T_O AC(ac) = AC(ac) | mb
598 #define T_C AC(ac) = AC(ac) ^ mb
599 #define T__E if ((AC(ac) & mb) == 0) INCPC
600 #define T__N if ((AC(ac) & mb) != 0) INCPC
601 #define T__A INCPC
602 #define IOC if (TSTF (F_USR) && !TSTF (F_UIO)) goto MUUO;
603 #define IO7(x,y) IOC; fptr = ((Q_ITS)? x[ac]: y[ac]); \
604 if (fptr == NULL) goto MUUO; \
605 if (fptr (ea, MM_OPND)) INCPC; break;
606 #define IOA IOC; if (!Q_ITS) ea = calc_ioea (inst, pflgs)
607 #define IOAM IOC; ea = ((Q_ITS)? ((a10) Read (ea, MM_OPND)): \
608 calc_ioea (inst, pflgs))
609
610 /* Flag tests */
611
612 #define MOVNF(x) if ((x) == MAXNEG) SETF (F_C1 | F_AOV | F_T1); \
613 else if ((x) == 0) SETF (F_C0 | F_C1)
614 #define MOVMF(x) if ((x) == MAXNEG) SETF (F_C1 | F_AOV | F_T1)
615 #define INCF(x) if ((x) == 0) SETF (F_C0 | F_C1); \
616 else if ((x) == MAXNEG) SETF (F_C1 | F_AOV | F_T1)
617 #define DECF(x) if ((x) == MAXPOS) SETF (F_C0 | F_AOV | F_T1); \
618 else if ((x) != ONES) SETF (F_C0 | F_C1)
619 #define PUSHF if (LRZ (AC(ac)) == 0) SETF (F_T2)
620 #define POPF if (LRZ (AC(ac)) == RMASK) SETF (F_T2)
621 #define DMOVNF if (rs[1] == 0) { MOVNF (rs[0]); }
622
sim_instr(void)623 t_stat sim_instr (void)
624 {
625 a10 PC; /* set by setjmp */
626 int abortval = 0; /* abort value */
627 t_stat r;
628
629 /* Restore register state */
630
631 if ((r = build_dib_tab ()) != SCPE_OK) /* build, chk dib_tab */
632 return r;
633 pager_PC = PC = saved_PC & AMASK; /* load local PC */
634 set_dyn_ptrs (); /* set up local ptrs */
635 pager_tc = FALSE; /* not in trap cycle */
636 pager_pi = FALSE; /* not in pi sequence */
637 rlog = 0; /* not in extend */
638 pi_eval (); /* eval pi system */
639 if (!Q_ITS) /* ~ITS, clr 1-proc */
640 its_1pr = 0;
641 t20_idlelock = 0; /* clr T20 idle lock */
642
643 /* Abort handling
644
645 Aborts may come from within the simulator to stop simulation (values > 0),
646 for page fails (values < 0), or for an interrupt check (value = 0).
647 */
648
649 abortval = setjmp (save_env); /* set abort hdlr */
650 if ((abortval > 0) || pager_pi) { /* stop or pi err? */
651 if (pager_pi && (abortval == PAGE_FAIL))
652 abortval = STOP_PAGINT; /* stop for pi err */
653 saved_PC = pager_PC & AMASK; /* failing instr PC */
654 set_ac_display (ac_cur); /* set up AC display */
655 pcq_r->qptr = pcq_p; /* update pc q ptr */
656 return abortval; /* return to SCP */
657 }
658
659 /* Page fail - checked against KS10 ucode
660 All state variables MUST be declared global for GCC optimization to work
661 */
662
663 else if (abortval == PAGE_FAIL) { /* page fail */
664 d10 mb;
665 if (rlog) /* clean up extend */
666 xtcln (rlog);
667 rlog = 0; /* clear log */
668 if (pager_tc) /* trap? get flags */
669 flags = pager_flags;
670 if (T20PAG) { /* TOPS-20 paging? */
671 WriteP (upta + UPT_T20_PFL, pager_word); /* write page fail wd */
672 WriteP (upta + UPT_T20_OFL, XWD (flags, 0));
673 WriteP (upta + UPT_T20_OPC, pager_PC);
674 mb = ReadP (upta + UPT_T20_NPC);
675 }
676 else {
677 a10 ea; /* TOPS-10 or ITS */
678 if (Q_ITS) { /* ITS? */
679 ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3);
680 if (its_1pr) /* store 1-proc */
681 flags = flags | F_1PR;
682 its_1pr = 0; /* clear 1-proc */
683 }
684 else ea = upta + UPT_T10_PAG;
685 WriteP (ea, pager_word); /* write page fail wd */
686 WriteP (ADDA (ea, 1), XWD (flags, pager_PC));
687 mb = ReadP (ADDA (ea, 2));
688 }
689 JUMP (mb); /* set new PC */
690 set_newflags (mb, FALSE); /* set new flags */
691 pi_eval (); /* eval pi system */
692 }
693 else PC = pager_PC; /* intr, restore PC */
694
695 /* Main instruction fetch/decode loop: check clock queue, intr, trap, bkpt */
696
697 for ( ;; ) { /* loop until ABORT */
698 int32 op, ac, i, st, xr, xct_cnt, its_2pr, pflgs;
699 a10 ea;
700 d10 inst, mb, indrct, rs[2];
701 t_bool (*fptr)(int32, int32);
702
703 pager_PC = PC; /* update pager PC */
704 pager_tc = FALSE; /* not in trap cycle */
705 pflgs = 0; /* not in PXCT */
706 xct_cnt = 0; /* count XCT's */
707 if (sim_interval <= 0) { /* check clock queue */
708 if ((i = sim_process_event ())) /* error? stop sim */
709 ABORT (i);
710 pi_eval (); /* eval pi system */
711 }
712
713 /* PI interrupt (Unibus or system flags).
714 On the KS10, only JSR and XPCW are allowed as interrupt instructions.
715 Because of exec mode addressing, and unconditional processing of flags,
716 they are explicitly emulated here.
717 */
718
719 if (qintr) {
720 int32 vec, uba;
721 pager_pi = TRUE; /* flag in pi seq */
722 if ((vec = pi_ub_vec (qintr, &uba))) { /* Unibus interrupt? */
723 mb = ReadP (epta + EPT_UBIT + uba); /* get dispatch table */
724 if (mb == 0) /* invalid? stop */
725 ABORT (STOP_ZERINT);
726 inst = ReadE ((((a10) mb) + (vec / 4)) & AMASK);
727 if (inst == 0)
728 ABORT (STOP_ZERINT);
729 }
730 else inst = ReadP (epta + EPT_PIIT + (2 * qintr));
731 op = GET_OP (inst); /* get opcode */
732 ac = GET_AC (inst); /* get ac */
733 if (its_1pr && Q_ITS) { /* 1-proc set? */
734 flags = flags | F_1PR; /* store 1-proc */
735 its_1pr = 0; /* clear 1-proc */
736 }
737 if (op == OP_JSR) { /* JSR? */
738 ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */
739 WriteE (ea, FLPC); /* save flags+PC, exec */
740 JUMP (INCA (ea)); /* PC = ea + 1 */
741 set_newflags (0, FALSE); /* set new flags */
742 }
743 else if ((op == OP_JRST) && (ac == AC_XPCW)) { /* XPCW? */
744 ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */
745 WriteE (ea, XWD (flags, 0)); /* write flags, exec */
746 WriteE (ADDA (ea, 1), PC); /* write PC, exec */
747 rs[0] = ReadE (ADDA (ea, 2)); /* read new flags */
748 rs[1] = ReadE (ADDA (ea, 3)); /* read new PC */
749 JUMP (rs[1]); /* set new PC */
750 set_newflags (rs[0], FALSE); /* set new flags */
751 }
752 else ABORT (STOP_ILLINT); /* invalid instr */
753 pi_act = pi_act | pi_l2bit[qintr]; /* set level active */
754 pi_eval (); /* eval pi system */
755 pager_pi = FALSE; /* end of sequence */
756 if (sim_interval) /* charge for instr */
757 sim_interval--;
758 continue;
759 } /* end if interrupt */
760
761 /* Traps fetch and execute an instruction from the current mode process table.
762 On the KS10, the fetch of the next instruction has started, and a page fail
763 trap on the instruction fetch takes precedence over the trap. During a trap,
764 flags are cleared before the execute, but if the execute aborts, they must
765 be restored. Also, the MUUO processor needs to know whether we are in a
766 trap sequence. Hence, trap in progress is recorded in pflgs, and the
767 traps for pager restoration are recorded in pager_flags.
768 */
769
770 if (TSTF (F_T1 | F_T2) && PAGING) {
771 Read (pager_PC = PC, MM_CUR); /* test fetch */
772 pager_tc = TRUE; /* in a trap sequence */
773 pager_flags = flags; /* save flags */
774 ea = (TSTF (F_USR)? upta + UPT_TRBASE: epta + EPT_TRBASE)
775 + GET_TRAPS (flags);
776 inst = ReadP (ea); /* get trap instr */
777 CLRF (F_T1 | F_T2); /* clear flags */
778 }
779
780 /* Test for instruction breakpoint */
781
782 else {
783 if (sim_brk_summ &&
784 sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
785 ABORT (STOP_IBKPT); /* stop simulation */
786 }
787
788 /* Ready (at last) to get an instruction */
789
790 inst = Read (pager_PC = PC, MM_CUR); /* get instruction */
791 INCPC;
792 sim_interval = sim_interval - 1;
793 }
794
795 its_2pr = its_1pr; /* save 1-proc flag */
796
797 /* Execute instruction. XCT and PXCT also return here. */
798
799 XCT:
800 op = GET_OP (inst); /* get opcode */
801 ac = GET_AC (inst); /* get AC */
802 for (indrct = inst, i = 0; i < ind_max; i++) { /* calc eff addr */
803 ea = GET_ADDR (indrct);
804 xr = GET_XR (indrct);
805 if (xr)
806 ea = (ea + ((a10) XR (xr, MM_EA))) & AMASK;
807 if (TST_IND (indrct))
808 indrct = Read (ea, MM_EA);
809 else break;
810 }
811 if (i >= ind_max)
812 ABORT (STOP_IND); /* too many ind? stop */
813 if (hst_lnt) { /* history enabled? */
814 hst_p = (hst_p + 1); /* next entry */
815 if (hst_p >= hst_lnt)
816 hst_p = 0;
817 hst[hst_p].pc = pager_PC | HIST_PC;
818 hst[hst_p].ea = ea;
819 hst[hst_p].ir = inst;
820 hst[hst_p].ac = AC(ac);
821 }
822 switch (op) { /* case on opcode */
823
824 /* UUO's (0000 - 0077) - checked against KS10 ucode */
825
826 case 0000: if (stop_op0) {
827 ABORT (STOP_ILLEG);
828 }
829 goto MUUO;
830 case 0001: /* local UUO's */
831 case 0002:
832 case 0003:
833 case 0004:
834 case 0005:
835 case 0006:
836 case 0007:
837 case 0010:
838 case 0011:
839 case 0012:
840 case 0013:
841 case 0014:
842 case 0015:
843 case 0016:
844 case 0017:
845 case 0020:
846 case 0021:
847 case 0022:
848 case 0023:
849 case 0024:
850 case 0025:
851 case 0026:
852 case 0027:
853 case 0030:
854 case 0031:
855 case 0032:
856 case 0033:
857 case 0034:
858 case 0035:
859 case 0036:
860 case 0037: Write (040, UUOWORD, MM_CUR); /* store op, ac, ea */
861 inst = Read (041, MM_CUR); /* get new instr */
862 goto XCT;
863
864 /* case 0040 - 0077: MUUO's, handled by default at end of case */
865
866 /* Floating point, bytes, multiple precision (0100 - 0177) */
867
868 /* case 0100: MUUO /* UJEN */
869 /* case 0101: MUUO /* unassigned */
870 case 0102: if (Q_ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */
871 inst = Read (ea, MM_OPND);
872 pflgs = pflgs | ac;
873 goto XCT;
874 }
875 goto MUUO;
876 case 0103: if (Q_ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) */
877 inst = Read (ea, MM_OPND);
878 pflgs = pflgs | ac;
879 goto XCT;
880 }
881 goto MUUO;
882 /* case 0104: MUUO /* JSYS (T20) */
883 case 0105: AC(ac) = adjsp (AC(ac), ea); break; /* ADJSP */
884 /* case 0106: MUUO /* GFMP (KL)*/
885 /* case 0107: MUUO /* GFDV (KL) */
886 case 0110: RD2; dfad (ac, rs, 0); break; /* DFAD */
887 case 0111: RD2; dfad (ac, rs, 1); break; /* DFSB */
888 case 0112: RD2; dfmp (ac, rs); break; /* DFMP */
889 case 0113: RD2; dfdv (ac, rs); break; /* DFDV */
890 case 0114: RD2; dadd (ac, rs); break; /* DADD */
891 case 0115: RD2; dsub (ac, rs); break; /* DSUB */
892 case 0116: RD2; dmul (ac, rs); break; /* DMUL */
893 case 0117: RD2; ddiv (ac, rs); break; /* DDIV */
894 case 0120: RD2; S2AC; break; /* DMOVE */
895 case 0121: RD2; DMOVN (rs); S2AC; DMOVNF; break; /* DMOVN */
896 case 0122: RD; fix(ac, mb, 0); break; /* FIX */
897 case 0123: st = xtend (ac, ea, pflgs); /* EXTEND */
898 rlog = 0; /* clear log */
899 switch (st) {
900 case XT_SKIP:
901 INCPC;
902 case XT_NOSK:
903 break;
904 default:
905 goto MUUO;
906 }
907 break;
908 case 0124: G2AC; WR2; break; /* DMOVEM */
909 case 0125: G2AC; DMOVN (rs); WR2; DMOVNF; break; /* DMOVNM */
910 case 0126: RD; fix (ac, mb, 1); break; /* FIXR */
911 case 0127: RD; AC(ac) = fltr (mb); break; /* FLTR */
912 /* case 0130: MUUO /* UFA */
913 /* case 0131: MUUO /* DFN */
914 case 0132: AC(ac) = fsc (AC(ac), ea); break; /* FSC */
915 case 0133: if (!ac) /* IBP */
916 ibp (ea, pflgs);
917 else adjbp (ac, ea, pflgs); break;
918 case 0134: CIBP; LDB; CLRF (F_FPD); break; /* ILBP */
919 case 0135: LDB; break; /* LDB */
920 case 0136: CIBP; DPB; CLRF (F_FPD); break; /* IDBP */
921 case 0137: DPB; break; /* DPB */
922 case 0140: RD; AC(ac) = FAD (mb); break; /* FAD */
923 /* case 0141: MUUO /* FADL */
924 case 0142: RM; mb = FAD (mb); WR; break; /* FADM */
925 case 0143: RM; AC(ac) = FAD (mb); WRAC; break; /* FADB */
926 case 0144: RD; AC(ac) = FADR (mb); break; /* FADR */
927 case 0145: AC(ac) = FADR (IMS); break; /* FADRI */
928 case 0146: RM; mb = FADR (mb); WR; break; /* FADRM */
929 case 0147: RM; AC(ac) = FADR (mb); WRAC; break; /* FADRB */
930 case 0150: RD; AC(ac) = FSB (mb); break; /* FSB */
931 /* case 0151: MUUO /* FSBL */
932 case 0152: RM; mb = FSB (mb); WR; break; /* FSBM */
933 case 0153: RM; AC(ac) = FSB (mb); WRAC; break; /* FSBB */
934 case 0154: RD; AC(ac) = FSBR (mb); break; /* FSBR */
935 case 0155: AC(ac) = FSBR (IMS); break; /* FSBRI */
936 case 0156: RM; mb = FSBR (mb); WR; break; /* FSBRM */
937 case 0157: RM; AC(ac) = FSBR (mb); WRAC; break; /* FSBRB */
938 case 0160: RD; AC(ac) = FMP (mb); break; /* FMP */
939 /* case 0161: MUUO /* FMPL */
940 case 0162: RM; mb = FMP (mb); WR; break; /* FMPM */
941 case 0163: RM; AC(ac) = FMP (mb); WRAC; break; /* FMPB */
942 case 0164: RD; AC(ac) = FMPR (mb); break; /* FMPR */
943 case 0165: AC(ac) = FMPR (IMS); break; /* FMPRI */
944 case 0166: RM; mb = FMPR (mb); WR; break; /* FMPRM */
945 case 0167: RM; AC(ac) = FMPR (mb); WRAC; break; /* FMPRB */
946 case 0170: RD; if (FDV (mb)) S1AC; break; /* FDV */
947 /* case 0171: MUUO /* FDVL */
948 case 0172: RM; if (FDV (mb)) WR1; break; /* FDVM */
949 case 0173: RM; if (FDV (mb)) { S1AC; WRAC; } break; /* FDVB */
950 case 0174: RD; if (FDVR (mb)) S1AC; break; /* FDVR */
951 case 0175: if (FDVR (IMS)) S1AC; break; /* FDVRI */
952 case 0176: RM; if (FDVR (mb)) WR1; break; /* FDVRM */
953 case 0177: RM; if (FDVR (mb)) { S1AC; WRAC; } break; /* FDVRB */
954
955 /* Move, arithmetic, shift, and jump (0200 - 0277)
956
957 Note that instructions which modify the flags and store a
958 result in memory must prove the writeability of the result
959 location before modifying the flags. Also, 0247 and 0257,
960 if not implemented, are nops, not MUUO's.
961 */
962
963 case 0200: RDAC; break; /* MOVE */
964 case 0201: AC(ac) = ea; break; /* MOVEI */
965 case 0202: WRAC; break; /* MOVEM */
966 case 0203: RM; LAC; break; /* MOVES */
967 case 0204: RD; AC(ac) = SWP (mb); break; /* MOVS */
968 case 0205: AC(ac) = IMS; break; /* MOVSI */
969 case 0206: mb = SWP (AC(ac)); WR; break; /* MOVSM */
970 case 0207: RM; mb = SWP (mb); WR; LAC; break; /* MOVSS */
971 case 0210: RD; AC(ac) = MOVN (mb); break; /* MOVN */
972 case 0211: AC(ac) = NEG (IM); /* MOVNI */
973 if (AC(ac) == 0) SETF (F_C0 | F_C1);
974 break;
975 case 0212: RM; mb = MOVN (AC(ac)); WR; break; /* MOVNM */
976 case 0213: RM; mb = MOVN (mb); WR; LAC; break; /* MOVNS */
977 case 0214: RD; AC(ac) = MOVM (mb); break; /* MOVM */
978 case 0215: AC(ac) = ea; break; /* MOVMI */
979 case 0216: RM; mb = MOVM (AC(ac)); WR; break; /* MOVMM */
980 case 0217: RM; mb = MOVM (mb); WR; LAC; break; /* MOVMS */
981 case 0220: RD; AC(ac) = IMUL (mb); break; /* IMUL */
982 case 0221: AC(ac) = IMUL (IM); break; /* IMULI */
983 case 0222: RM; mb = IMUL (mb); WR; break; /* IMULM */
984 case 0223: RM; AC(ac) = IMUL (mb); WRAC; break; /* IMULB */
985 case 0224: RD; MUL (mb); S2AC; break; /* MUL */
986 case 0225: MUL (IM); S2AC; break; /* MULI */
987 case 0226: RM; MUL (mb); WR1; break; /* MULM */
988 case 0227: RM; MUL (mb); WR1; S2AC; break; /* MULB */
989 case 0230: RD; if (IDIV (mb)) S2AC; break; /* IDIV */
990 case 0231: if (IDIV (IM)) S2AC; break; /* IDIVI */
991 case 0232: RM; if (IDIV (mb)) WR1; break; /* IDIVM */
992 case 0233: RM; if (IDIV (mb)) { WR1; S2AC; } break; /* IDIVB */
993 case 0234: RD; if (DIV (mb)) S2AC; break; /* DIV */
994 case 0235: if (DIV (IM)) S2AC; break; /* DIVI */
995 case 0236: RM; if (DIV (mb)) WR1; break; /* DIVM */
996 case 0237: RM; if (DIV (mb)) { WR1; S2AC; } break; /* DIVB */
997 case 0240: AC(ac) = ash (AC(ac), ea); break; /* ASH */
998 case 0241: AC(ac) = rot (AC(ac), ea); break; /* ROT */
999 case 0242: AC(ac) = lsh (AC(ac), ea); break; /* LSH */
1000 case 0243: AC(P1) = jffo (AC(ac)); /* JFFO */
1001 if (AC(ac)) JUMP (ea);
1002 break;
1003 case 0244: ashc (ac, ea); break; /* ASHC */
1004 case 0245: rotc (ac, ea); break; /* ROTC */
1005 case 0246: lshc (ac, ea); break; /* LSHC */
1006 case 0247: if (Q_ITS) circ (ac, ea); break; /* (ITS) CIRC */
1007 case 0250: RM; WRAC; AC(ac) = mb; break; /* EXCH */
1008 case 0251: blt (ac, ea, pflgs); break; /* BLT */
1009 case 0252: AOBAC; if (TGE (AC(ac))) JUMP (ea); break; /* AOBJP */
1010 case 0253: AOBAC; if (TL (AC(ac))) JUMP (ea); break; /* AOBJN */
1011 /* case 0254: /* shown later /* JRST */
1012 case 0255: if (flags & (ac << 14)) { /* JFCL */
1013 JUMP (ea);
1014 CLRF (ac << 14);
1015 }
1016 break;
1017 case 0256: if (xct_cnt++ >= xct_max) /* XCT */
1018 ABORT (STOP_XCT);
1019 inst = Read (ea, MM_OPND);
1020 if (ac && !TSTF (F_USR) && !Q_ITS)
1021 pflgs = pflgs | ac;
1022 goto XCT;
1023 case 0257: if (Q_ITS) goto MUUO; /* MAP */
1024 AC(ac) = map (ea, MM_OPND);
1025 break;
1026 case 0260: WRP (FLPC); AOBAC; /* PUSHJ */
1027 SUBJ (ea); PUSHF; break;
1028 case 0261: RD; WRP (mb); AOBAC; PUSHF; break; /* PUSH */
1029 case 0262: RDP; WR; SOBAC; POPF; break; /* POP */
1030 case 0263: RDP; JUMP (mb); SOBAC; POPF; break; /* POPJ */
1031 case 0264: Write (ea, FLPC, MM_OPND); /* JSR */
1032 SUBJ (INCR (ea)); break;
1033 case 0265: AC(ac) = FLPC; SUBJ (ea); break; /* JSP */
1034 case 0266: WRAC; AC(ac) = XWD (ea, PC); /* JSA */
1035 JUMP (INCR (ea)); break;
1036 case 0267: AC(ac) = Read ((a10) LRZ (AC(ac)), MM_OPND);/* JRA */
1037 JUMP (ea); break;
1038 case 0270: RD; AC(ac) = ADD (mb); break; /* ADD */
1039 case 0271: AC(ac) = ADD (IM); break; /* ADDI */
1040 case 0272: RM; mb = ADD (mb); WR; break; /* ADDM */
1041 case 0273: RM; AC(ac) = ADD (mb); WRAC; break; /* ADDB */
1042 case 0274: RD; AC(ac) = SUB (mb); break; /* SUB */
1043 case 0275: AC(ac) = SUB (IM); break; /* SUBI */
1044 case 0276: RM; mb = SUB (mb); WR; break; /* SUBM */
1045 case 0277: RM; AC(ac) = SUB (mb); WRAC; break; /* SUBB */
1046
1047 /* Compare, jump, skip instructions (0300 - 0377) - checked against KS10 ucode */
1048
1049 case 0300: break; /* CAI */
1050 case 0301: if (CL (IM)) INCPC; break; /* CAIL */
1051 case 0302: if (CE (IM)) INCPC; break; /* CAIE */
1052 case 0303: if (CLE (IM)) INCPC; break; /* CAILE */
1053 case 0304: INCPC; break; /* CAIA */
1054 case 0305: if (CGE (IM)) INCPC; break; /* CAIGE */
1055 case 0306: if (CN (IM)) INCPC; break; /* CAIN */
1056 case 0307: if (CG (IM)) INCPC; break; /* CAIG */
1057 case 0310: RD; break; /* CAM */
1058 case 0311: RD; if (CL (mb)) INCPC; break; /* CAML */
1059 case 0312: RD; if (CE (mb)) INCPC; break; /* CAME */
1060 case 0313: RD; if (CLE (mb)) INCPC; break; /* CAMLE */
1061 case 0314: RD; INCPC; break; /* CAMA */
1062 case 0315: RD; if (CGE (mb)) INCPC; break; /* CAMGE */
1063 case 0316: RD; if (CN (mb)) INCPC; break; /* CAMN */
1064 case 0317: RD; if (CG (mb)) INCPC; break; /* CAMG */
1065 case 0320: break; /* JUMP */
1066 case 0321: if (TL (AC(ac))) JUMP (ea); break; /* JUMPL */
1067 case 0322: if (TE (AC(ac))) JUMP (ea); break; /* JUMPE */
1068 case 0323: if (TLE( AC(ac))) JUMP (ea); break; /* JUMPLE */
1069 case 0324: JUMP (ea); break; /* JUMPA */
1070 case 0325: if (TGE (AC(ac))) JUMP (ea); break; /* JUMPGE */
1071 case 0326: if (TN (AC(ac))) JUMP (ea); break; /* JUMPN */
1072 case 0327: if (TG (AC(ac))) JUMP (ea); break; /* JUMPG */
1073 case 0330: RD; LAC; break; /* SKIP */
1074 case 0331: RD; LAC; if (TL (mb)) INCPC; break; /* SKIPL */
1075 case 0332: RD; LAC; if (TE (mb)) INCPC; break; /* SKIPE */
1076 case 0333: RD; LAC; if (TLE (mb)) INCPC; break; /* SKIPLE */
1077 case 0334: RD; LAC; INCPC; break; /* SKIPA */
1078 case 0335: RD; LAC; if (TGE (mb)) INCPC; break; /* SKIPGE */
1079 case 0336: RD; LAC; if (TN (mb)) INCPC; break; /* SKIPN */
1080 case 0337: RD; LAC; if (TG (mb)) INCPC; break; /* SKIPG */
1081 case 0340: AOJ; break; /* AOJ */
1082 case 0341: AOJ; if (TL (AC(ac))) JUMP (ea); break; /* AOJL */
1083 case 0342: AOJ; if (TE (AC(ac))) JUMP (ea); break; /* AOJE */
1084 case 0343: AOJ; if (TLE (AC(ac))) JUMP (ea); break; /* AOJLE */
1085 case 0344: AOJ; JUMP(ea); /* AOJA */
1086 if (Q_ITS && Q_IDLE && /* ITS idle? */
1087 TSTF (F_USR) && (pager_PC == 017) && /* user mode, loc 17? */
1088 (ac == 0) && (ea == 017)) /* AOJA 0,17? */
1089 sim_idle (0, FALSE);
1090 break;
1091 case 0345: AOJ; if (TGE (AC(ac))) JUMP (ea); break; /* AOJGE */
1092 case 0346: AOJ; if (TN (AC(ac))) JUMP (ea); break; /* AOJN */
1093 case 0347: AOJ; if (TG (AC(ac))) JUMP (ea); break; /* AOJG */
1094 case 0350: AOS; break; /* AOS */
1095 case 0351: AOS; if (TL (mb)) INCPC; break; /* AOSL */
1096 case 0352: AOS; if (TE (mb)) INCPC; break; /* AOSE */
1097 case 0353: AOS; if (TLE (mb)) INCPC; break; /* AOSLE */
1098 case 0354: AOS; INCPC; break; /* AOSA */
1099 case 0355: AOS; if (TGE (mb)) INCPC; break; /* AOSGE */
1100 case 0356: AOS; if (TN (mb)) INCPC; break; /* AOSN */
1101 case 0357: AOS; if (TG (mb)) INCPC; break; /* AOSG */
1102 case 0360: SOJ; break; /* SOJ */
1103 case 0361: SOJ; if (TL (AC(ac))) JUMP (ea); break; /* SOJL */
1104 case 0362: SOJ; if (TE (AC(ac))) JUMP (ea); break; /* SOJE */
1105 case 0363: SOJ; if (TLE (AC(ac))) JUMP (ea); break; /* SOJLE */
1106 case 0364: SOJ; JUMP(ea); break; /* SOJA */
1107 case 0365: SOJ; if (TGE (AC(ac))) JUMP (ea); break; /* SOJGE */
1108 case 0366: SOJ; if (TN (AC(ac))) JUMP (ea); break; /* SOJN */
1109 case 0367: SOJ; if (TG (AC(ac))) JUMP (ea); /* SOJG */
1110 if ((ea == pager_PC) && Q_IDLE) { /* to self, idle enab? */
1111 extern int32 tmr_poll;
1112 if ((ac == 6) && (ea == 1) && /* SOJG 6,1? */
1113 TSTF (F_USR) && Q_T10) /* T10, user mode? */
1114 sim_idle (0, FALSE);
1115 else if (!t20_idlelock && /* interlock off? */
1116 (ac == 2) && (ea == 3) && /* SOJG 2,3? */
1117 !TSTF (F_USR) && Q_T20 && /* T20, mon mode? */
1118 (sim_interval > (tmr_poll >> 1))) { /* >= half clock? */
1119 t20_idlelock = 1; /* set interlock */
1120 if (sim_os_ms_sleep (1)) /* sleep 1ms */
1121 sim_interval = 0; /* if ok, sched event */
1122 }
1123 }
1124 break;
1125 case 0370: SOS; break; /* SOS */
1126 case 0371: SOS; if (TL (mb)) INCPC; break; /* SOSL */
1127 case 0372: SOS; if (TE (mb)) INCPC; break; /* SOSE */
1128 case 0373: SOS; if (TLE (mb)) INCPC; break; /* SOSLE */
1129 case 0374: SOS; INCPC; break; /* SOSA */
1130 case 0375: SOS; if (TGE (mb)) INCPC; break; /* SOSGE */
1131 case 0376: SOS; if (TN (mb)) INCPC; break; /* SOSN */
1132 case 0377: SOS; if (TG (mb)) INCPC; break; /* SOSG */
1133
1134 /* Boolean instructions (0400 - 0477) - checked against KS10 ucode
1135
1136 Note that for boolean B, the initial read checks writeability of
1137 the memory operand; hence, it is safe to modify the AC.
1138 */
1139
1140 case 0400: AC(ac) = 0; break; /* SETZ */
1141 case 0401: AC(ac) = 0; break; /* SETZI */
1142 case 0402: mb = 0; WR; break; /* SETZM */
1143 case 0403: mb = 0; WR; AC(ac) = 0; break; /* SETZB */
1144 case 0404: RD; AC(ac) = AND (mb); break; /* AND */
1145 case 0405: AC(ac) = AND (IM); break; /* ANDI */
1146 case 0406: RM; mb = AND (mb); WR; break; /* ANDM */
1147 case 0407: RM; AC(ac) = AND (mb); WRAC; break; /* ANDB */
1148 case 0410: RD; AC(ac) = ANDCA (mb); break; /* ANDCA */
1149 case 0411: AC(ac) = ANDCA (IM); break; /* ANDCAI */
1150 case 0412: RM; mb = ANDCA (mb); WR; break; /* ANDCAM */
1151 case 0413: RM; AC(ac) = ANDCA (mb); WRAC; break; /* ANDCAB */
1152 case 0414: RDAC; break; /* SETM */
1153 case 0415: AC(ac) = ea; break; /* SETMI */
1154 case 0416: RM; WR; break; /* SETMM */
1155 case 0417: RMAC; WRAC; break; /* SETMB */
1156 case 0420: RD; AC(ac) = ANDCM (mb); break; /* ANDCM */
1157 case 0421: AC(ac) = ANDCM (IM); break; /* ANDCMI */
1158 case 0422: RM; mb = ANDCM (mb); WR; break; /* ANDCMM */
1159 case 0423: RM; AC(ac) = ANDCM (mb); WRAC; break; /* ANDCMB */
1160 case 0424: break; /* SETA */
1161 case 0425: break; /* SETAI */
1162 case 0426: WRAC; break; /* SETAM */
1163 case 0427: WRAC; break; /* SETAB */
1164 case 0430: RD; AC(ac) = XOR (mb); break; /* XOR */
1165 case 0431: AC(ac) = XOR (IM); break; /* XORI */
1166 case 0432: RM; mb = XOR (mb); WR; break; /* XORM */
1167 case 0433: RM; AC(ac) = XOR (mb); WRAC; break; /* XORB */
1168 case 0434: RD; AC(ac) = IOR (mb); break; /* IOR */
1169 case 0435: AC(ac) = IOR (IM); break; /* IORI */
1170 case 0436: RM; mb = IOR (mb); WR; break; /* IORM */
1171 case 0437: RM; AC(ac) = IOR (mb); WRAC; break; /* IORB */
1172 case 0440: RD; AC(ac) = ANDCB (mb); break; /* ANDCB */
1173 case 0441: AC(ac) = ANDCB (IM); break; /* ANDCBI */
1174 case 0442: RM; mb = ANDCB (mb); WR; break; /* ANDCBM */
1175 case 0443: RM; AC(ac) = ANDCB (mb); WRAC; break; /* ANDCBB */
1176 case 0444: RD; AC(ac) = EQV (mb); break; /* EQV */
1177 case 0445: AC(ac) = EQV (IM); break; /* EQVI */
1178 case 0446: RM; mb = EQV (mb); WR; break; /* EQVM */
1179 case 0447: RM; AC(ac) = EQV (mb); WRAC; break; /* EQVB */
1180 case 0450: RD; AC(ac) = SETCA (mb); break; /* SETCA */
1181 case 0451: AC(ac) = SETCA (IM); break; /* SETCAI */
1182 case 0452: RM; mb = SETCA (mb); WR; break; /* SETCAM */
1183 case 0453: RM; AC(ac) = SETCA (mb); WRAC; break; /* SETCAB */
1184 case 0454: RD; AC(ac) = ORCA (mb); break; /* ORCA */
1185 case 0455: AC(ac) = ORCA (IM); break; /* ORCAI */
1186 case 0456: RM; mb = ORCA (mb); WR; break; /* ORCAM */
1187 case 0457: RM; AC(ac) = ORCA (mb); WRAC; break; /* ORCAB */
1188 case 0460: RD; AC(ac) = SETCM (mb); break; /* SETCM */
1189 case 0461: AC(ac) = SETCM (IM); break; /* SETCMI */
1190 case 0462: RM; mb = SETCM (mb); WR; break; /* SETCMM */
1191 case 0463: RM; AC(ac) = SETCM (mb); WRAC; break; /* SETCMB */
1192 case 0464: RD; AC(ac) = ORCM (mb); break; /* ORCM */
1193 case 0465: AC(ac) = ORCM (IM); break; /* ORCMI */
1194 case 0466: RM; mb = ORCM (mb); WR; break; /* ORCMM */
1195 case 0467: RM; AC(ac) = ORCM (mb); WRAC; break; /* ORCMB */
1196 case 0470: RD; AC(ac) = ORCB (mb); break; /* ORCB */
1197 case 0471: AC(ac) = ORCB (IM); break; /* ORCBI */
1198 case 0472: RM; mb = ORCB (mb); WR; break; /* ORCBM */
1199 case 0473: RM; AC(ac) = ORCB (mb); WRAC; break; /* ORCBB */
1200 case 0474: AC(ac) = ONES; break; /* SETO */
1201 case 0475: AC(ac) = ONES; break; /* SETOI */
1202 case 0476: mb = ONES; WR; break; /* SETOM */
1203 case 0477: mb = ONES; WR; AC(ac) = ONES; break; /* SETOB */
1204
1205 /* Halfword instructions (0500 - 0577) - checked against KS10 ucode */
1206
1207 case 0500: RD; AC(ac) = LL (mb, AC(ac)); break; /* HLL */
1208 case 0501: AC(ac) = LL (IM, AC(ac)); break; /* HLLI */
1209 case 0502: RM; mb = LL (AC(ac), mb); WR; break; /* HLLM */
1210 case 0503: RM; mb = LL (mb, mb); WR; LAC; break; /* HLLS */
1211 case 0504: RD; AC(ac) = RL (mb, AC(ac)); break; /* HRL */
1212 case 0505: AC(ac) = RL (IM, AC(ac)); break; /* HRLI */
1213 case 0506: RM; mb = RL (AC(ac), mb); WR; break; /* HRLM */
1214 case 0507: RM; mb = RL (mb, mb); WR; LAC; break; /* HRLS */
1215 case 0510: RD; AC(ac) = LLZ (mb); break; /* HLLZ */
1216 case 0511: AC(ac) = LLZ (IM); break; /* HLLZI */
1217 case 0512: mb = LLZ (AC(ac)); WR; break; /* HLLZM */
1218 case 0513: RM; mb = LLZ (mb); WR; LAC; break; /* HLLZS */
1219 case 0514: RD; AC(ac) = RLZ (mb); break; /* HRLZ */
1220 case 0515: AC(ac) = RLZ (IM); break; /* HRLZI */
1221 case 0516: mb = RLZ (AC(ac)); WR; break; /* HRLZM */
1222 case 0517: RM; mb = RLZ (mb); WR; LAC; break; /* HRLZS */
1223 case 0520: RD; AC(ac) = LLO (mb); break; /* HLLO */
1224 case 0521: AC(ac) = LLO (IM); break; /* HLLOI */
1225 case 0522: mb = LLO (AC(ac)); WR; break; /* HLLOM */
1226 case 0523: RM; mb = LLO (mb); WR; LAC; break; /* HLLOS */
1227 case 0524: RD; AC(ac) = RLO (mb); break; /* HRLO */
1228 case 0525: AC(ac) = RLO (IM); break; /* HRLOI */
1229 case 0526: mb = RLO (AC(ac)); WR; break; /* HRLOM */
1230 case 0527: RM; mb = RLO (mb); WR; LAC; break; /* HRLOS */
1231 case 0530: RD; AC(ac) = LLE (mb); break; /* HLLE */
1232 case 0531: AC(ac) = LLE (IM); break; /* HLLEI */
1233 case 0532: mb = LLE (AC(ac)); WR; break; /* HLLEM */
1234 case 0533: RM; mb = LLE (mb); WR; LAC; break; /* HLLES */
1235 case 0534: RD; AC(ac) = RLE (mb); break; /* HRLE */
1236 case 0535: AC(ac) = RLE (IM); break; /* HRLEI */
1237 case 0536: mb = RLE (AC(ac)); WR; break; /* HRLEM */
1238 case 0537: RM; mb = RLE (mb); WR; LAC; break; /* HRLES */
1239 case 0540: RD; AC(ac) = RR (mb, AC(ac)); break; /* HRR */
1240 case 0541: AC(ac) = RR (IM, AC(ac)); break; /* HRRI */
1241 case 0542: RM; mb = RR (AC(ac), mb); WR; break; /* HRRM */
1242 case 0543: RM; mb = RR (mb, mb); WR; LAC; break; /* HRRS */
1243 case 0544: RD; AC(ac) = LR (mb, AC(ac)); break; /* HLR */
1244 case 0545: AC(ac) = LR (IM, AC(ac)); break; /* HLRI */
1245 case 0546: RM; mb = LR (AC(ac), mb); WR; break; /* HLRM */
1246 case 0547: RM; mb = LR (mb, mb); WR; LAC; break; /* HLRS */
1247 case 0550: RD; AC(ac) = RRZ (mb); break; /* HRRZ */
1248 case 0551: AC(ac) = RRZ (IM); break; /* HRRZI */
1249 case 0552: mb = RRZ (AC(ac)); WR; break; /* HRRZM */
1250 case 0553: RM; mb = RRZ(mb); WR; LAC; break; /* HRRZS */
1251 case 0554: RD; AC(ac) = LRZ (mb); break; /* HLRZ */
1252 case 0555: AC(ac) = LRZ (IM); break; /* HLRZI */
1253 case 0556: mb = LRZ (AC(ac)); WR; break; /* HLRZM */
1254 case 0557: RM; mb = LRZ (mb); WR; LAC; break; /* HLRZS */
1255 case 0560: RD; AC(ac) = RRO (mb); break; /* HRRO */
1256 case 0561: AC(ac) = RRO (IM); break; /* HRROI */
1257 case 0562: mb = RRO (AC(ac)); WR; break; /* HRROM */
1258 case 0563: RM; mb = RRO (mb); WR; LAC; break; /* HRROS */
1259 case 0564: RD; AC(ac) = LRO (mb); break; /* HLRO */
1260 case 0565: AC(ac) = LRO (IM); break; /* HLROI */
1261 case 0566: mb = LRO (AC(ac)); WR; break; /* HLROM */
1262 case 0567: RM; mb = LRO (mb); WR; LAC; break; /* HLROS */
1263 case 0570: RD; AC(ac) = RRE (mb); break; /* HRRE */
1264 case 0571: AC(ac) = RRE (IM); break; /* HRREI */
1265 case 0572: mb = RRE (AC(ac)); WR; break; /* HRREM */
1266 case 0573: RM; mb = RRE (mb); WR; LAC; break; /* HRRES */
1267 case 0574: RD; AC(ac) = LRE (mb); break; /* HLRE */
1268 case 0575: AC(ac) = LRE (IM); break; /* HLREI */
1269 case 0576: mb = LRE (AC(ac)); WR; break; /* HLREM */
1270 case 0577: RM; mb = LRE (mb); WR; LAC; break; /* HLRES */
1271
1272 /* Test instructions (0600 - 0677) - checked against KS10 ucode
1273 In the KS10 ucode, TDN and TSN do not fetch an operand; the Processor
1274 Reference Manual describes them as NOPs that reference memory.
1275 */
1276
1277 case 0600: break; /* TRN */
1278 case 0601: break; /* TLN */
1279 case 0602: TR_; T__E; break; /* TRNE */
1280 case 0603: TL_; T__E; break; /* TLNE */
1281 case 0604: T__A; break; /* TRNA */
1282 case 0605: T__A; break; /* TLNA */
1283 case 0606: TR_; T__N; break; /* TRNN */
1284 case 0607: TL_; T__N; break; /* TLNN */
1285 case 0610: TD_; break; /* TDN */
1286 case 0611: TS_; break; /* TSN */
1287 case 0612: TD_; T__E; break; /* TDNE */
1288 case 0613: TS_; T__E; break; /* TSNE */
1289 case 0614: TD_; T__A; break; /* TDNA */
1290 case 0615: TS_; T__A; break; /* TSNA */
1291 case 0616: TD_; T__N; break; /* TDNN */
1292 case 0617: TS_; T__N; break; /* TSNN */
1293 case 0620: TR_; T_Z; break; /* TRZ */
1294 case 0621: TL_; T_Z; break; /* TLZ */
1295 case 0622: TR_; T__E; T_Z; break; /* TRZE */
1296 case 0623: TL_; T__E; T_Z; break; /* TLZE */
1297 case 0624: TR_; T__A; T_Z; break; /* TRZA */
1298 case 0625: TL_; T__A; T_Z; break; /* TLZA */
1299 case 0626: TR_; T__N; T_Z; break; /* TRZN */
1300 case 0627: TL_; T__N; T_Z; break; /* TLZN */
1301 case 0630: TD_; T_Z; break; /* TDZ */
1302 case 0631: TS_; T_Z; break; /* TSZ */
1303 case 0632: TD_; T__E; T_Z; break; /* TDZE */
1304 case 0633: TS_; T__E; T_Z; break; /* TSZE */
1305 case 0634: TD_; T__A; T_Z; break; /* TDZA */
1306 case 0635: TS_; T__A; T_Z; break; /* TSZA */
1307 case 0636: TD_; T__N; T_Z; break; /* TDZN */
1308 case 0637: TS_; T__N; T_Z; break; /* TSZN */
1309 case 0640: TR_; T_C; break; /* TRC */
1310 case 0641: TL_; T_C; break; /* TLC */
1311 case 0642: TR_; T__E; T_C; break; /* TRCE */
1312 case 0643: TL_; T__E; T_C; break; /* TLCE */
1313 case 0644: TR_; T__A; T_C; break; /* TRCA */
1314 case 0645: TL_; T__A; T_C; break; /* TLCA */
1315 case 0646: TR_; T__N; T_C; break; /* TRCN */
1316 case 0647: TL_; T__N; T_C; break; /* TLCN */
1317 case 0650: TD_; T_C; break; /* TDC */
1318 case 0651: TS_; T_C; break; /* TSC */
1319 case 0652: TD_; T__E; T_C; break; /* TDCE */
1320 case 0653: TS_; T__E; T_C; break; /* TSCE */
1321 case 0654: TD_; T__A; T_C; break; /* TDCA */
1322 case 0655: TS_; T__A; T_C; break; /* TSCA */
1323 case 0656: TD_; T__N; T_C; break; /* TDCN */
1324 case 0657: TS_; T__N; T_C; break; /* TSCN */
1325 case 0660: TR_; T_O; break; /* TRO */
1326 case 0661: TL_; T_O; break; /* TLO */
1327 case 0662: TR_; T__E; T_O; break; /* TROE */
1328 case 0663: TL_; T__E; T_O; break; /* TLOE */
1329 case 0664: TR_; T__A; T_O; break; /* TROA */
1330 case 0665: TL_; T__A; T_O; break; /* TLOA */
1331 case 0666: TR_; T__N; T_O; break; /* TRON */
1332 case 0667: TL_; T__N; T_O; break; /* TLON */
1333 case 0670: TD_; T_O; break; /* TDO */
1334 case 0671: TS_; T_O; break; /* TSO */
1335 case 0672: TD_; T__E; T_O; break; /* TDOE */
1336 case 0673: TS_; T__E; T_O; break; /* TSOE */
1337 case 0674: TD_; T__A; T_O; break; /* TDOA */
1338 case 0675: TS_; T__A; T_O; break; /* TSOA */
1339 case 0676: TD_; T__N; T_O; break; /* TDON */
1340 case 0677: TS_; T__N; T_O; break; /* TSON */
1341
1342 /* I/O instructions (0700 - 0777)
1343
1344 Only the defined I/O instructions have explicit case labels;
1345 the rest default to unimplemented (monitor UUO). Note that
1346 710-715 and 720-725 have different definitions under ITS and
1347 use normal effective addresses instead of the special address
1348 calculation required by TOPS-10 and TOPS-20.
1349 */
1350
1351 case 0700: IO7 (io700i, io700d); break; /* I/O 0 */
1352 case 0701: IO7 (io701i, io701d); break; /* I/O 1 */
1353 case 0702: IO7 (io702i, io702d); break; /* I/O 2 */
1354 case 0704: IOC; AC(ac) = Read (ea, OPND_PXCT); break; /* UMOVE */
1355 case 0705: IOC; Write (ea, AC(ac), OPND_PXCT); break; /* UMOVEM */
1356 case 0710: IOA; if (io710 (ac, ea)) INCPC; break; /* TIOE, IORDI */
1357 case 0711: IOA; if (io711 (ac, ea)) INCPC; break; /* TION, IORDQ */
1358 case 0712: IOAM; AC(ac) = io712 (ea); break; /* RDIO, IORD */
1359 case 0713: IOAM; io713 (AC(ac), ea); break; /* WRIO, IOWR */
1360 case 0714: IOA; io714 (AC(ac), ea); break; /* BSIO, IOWRI */
1361 case 0715: IOA; io715 (AC(ac), ea); break; /* BCIO, IOWRQ */
1362 case 0716: IOC; bltu (ac, ea, pflgs, 0); break; /* BLTBU */
1363 case 0717: IOC; bltu (ac, ea, pflgs, 1); break; /* BLTUB */
1364 case 0720: IOA; if (io720 (ac, ea)) INCPC; break; /* TIOEB, IORDBI */
1365 case 0721: IOA; if (io721 (ac, ea)) INCPC; break; /* TIONB, IORDBQ */
1366 case 0722: IOAM; AC(ac) = io722 (ea); break; /* RDIOB, IORDB */
1367 case 0723: IOAM; io723 (AC(ac), ea); break; /* WRIOB, IOWRB */
1368 case 0724: IOA; io724 (AC(ac), ea); break; /* BSIOB, IOWRBI */
1369 case 0725: IOA; io725 (AC(ac), ea); break; /* BCIOB, IOWRBQ */
1370
1371 /* If undefined, monitor UUO - checked against KS10 ucode
1372 The KS10 implements a much more limited version of MUUO flag handling.
1373 In the KS10, the trap ucode checks for opcodes 000-077. If the opcode
1374 is in that range, the trap flags are not cleared. Instead, the MUUO
1375 microcode stores the flags with traps cleared, and uses the trap flags
1376 to determine how to vector. Thus, MUUO's >= 100 will vector incorrectly.
1377 */
1378
1379 default:
1380 MUUO:
1381 its_2pr = 0; /* clear trap */
1382 if (T20PAG) { /* TOPS20 paging? */
1383 int32 tf = (op << (INST_V_OP - 18)) | (ac << (INST_V_AC - 18));
1384 WriteP (upta + UPT_MUUO, XWD ( /* store flags,,op+ac */
1385 flags & ~(F_T2 | F_T1), tf)); /* traps clear */
1386 WriteP (upta + UPT_MUPC, PC); /* store PC */
1387 WriteP (upta + UPT_T20_UEA, ea); /* store eff addr */
1388 WriteP (upta + UPT_T20_CTX, UBRWORD); /* store context */
1389 }
1390 else { /* TOPS10/ITS */
1391 WriteP (upta + UPT_MUUO, UUOWORD); /* store instr word */
1392 WriteP (upta + UPT_MUPC, XWD ( /* store flags,,PC */
1393 flags & ~(F_T2 | F_T1), PC)); /* traps clear */
1394 WriteP (upta + UPT_T10_CTX, UBRWORD); /* store context */
1395 }
1396 ea = upta + (TSTF (F_USR)? UPT_UNPC: UPT_ENPC) +
1397 (pager_tc? UPT_NPCT: 0); /* calculate vector */
1398 mb = ReadP (ea); /* new flags, PC */
1399 JUMP (mb); /* set new PC */
1400 if (TSTF (F_USR)) /* set PCU */
1401 mb = mb | XWD (F_UIO, 0);
1402 set_newflags (mb, FALSE); /* set new flags */
1403 break;
1404
1405 /* JRST - checked against KS10 ucode
1406 Differences from the KS10: the KS10
1407 - (JRSTF, JEN) refetches the base instruction from PC - 1
1408 - (XJEN) dismisses interrupt before reading the new flags and PC
1409 - (XPCW) writes the old flags and PC before reading the new
1410 ITS microcode includes extended JRST's, although they are not used
1411 */
1412
1413 case 0254: /* JRST */
1414 i = jrst_tab[ac]; /* get subop flags */
1415 if ((i == 0) || ((i == JRST_E) && TSTF (F_USR)) ||
1416 ((i == JRST_UIO) && TSTF (F_USR) && !TSTF (F_UIO)))
1417 goto MUUO; /* not legal */
1418 switch (ac) { /* case on subopcode */
1419
1420 case 000: /* JRST 0 = jump */
1421 case 001: /* JRST 1 = portal */
1422 JUMP (ea);
1423 break;
1424
1425 case 002: /* JRST 2 = JRSTF */
1426 mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */
1427 JUMP (ea); /* set new PC */
1428 set_newflags (mb, TRUE); /* set new flags */
1429 break;
1430
1431 case 004: /* JRST 4 = halt */
1432 JUMP (ea); /* old_PC = halt + 1 */
1433 pager_PC = PC; /* force right PC */
1434 ABORT (STOP_HALT); /* known to be exec */
1435 break;
1436
1437 case 005: /* JRST 5 = XJRSTF */
1438 RD2; /* read doubleword */
1439 JUMP (rs[1]); /* set new PC */
1440 set_newflags (rs[0], TRUE); /* set new flags */
1441 break;
1442
1443 case 006: /* JRST 6 = XJEN */
1444 RD2; /* read doubleword */
1445 pi_dismiss (); /* page ok, dismiss */
1446 JUMP (rs[1]); /* set new PC */
1447 set_newflags (rs[0], FALSE); /* known to be exec */
1448 break;
1449
1450 case 007: /* JRST 7 = XPCW */
1451 ea = ADDA (i = ea, 2); /* new flags, PC */
1452 RD2; /* read, test page fail */
1453 ReadM (INCA (i), MM_OPND); /* test PC write */
1454 Write (i, XWD (flags, 0), MM_OPND); /* write flags */
1455 Write (INCA (i), PC, MM_OPND); /* write PC */
1456 JUMP (rs[1]); /* set new PC */
1457 set_newflags (rs[0], FALSE); /* known to be exec */
1458 break;
1459
1460 case 010: /* JRST 10 = dismiss */
1461 pi_dismiss (); /* dismiss int */
1462 JUMP (ea); /* set new PC */
1463 break;
1464
1465 case 012: /* JRST 12 = JEN */
1466 mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */
1467 JUMP (ea); /* set new PC */
1468 set_newflags (mb, TRUE); /* set new flags */
1469 pi_dismiss (); /* dismiss int */
1470 break;
1471
1472 case 014: /* JRST 14 = SFM */
1473 Write (ea, XWD (flags, 0), MM_OPND);
1474 break;
1475
1476 case 015: /* JRST 15 = XJRST */
1477 if (!T20PAG) /* only in TOPS20 paging */
1478 goto MUUO;
1479 JUMP (Read (ea, MM_OPND)); /* jump to M[ea] */
1480 break;
1481 } /* end case subop */
1482 break;
1483 } /* end case op */
1484
1485 if (its_2pr) { /* 1-proc trap? */
1486 its_1pr = its_2pr = 0; /* clear trap */
1487 if (Q_ITS) { /* better be ITS */
1488 WriteP (upta + UPT_1PO, FLPC); /* wr old flgs, PC */
1489 mb = ReadP (upta + UPT_1PN); /* rd new flgs, PC */
1490 JUMP (mb); /* set PC */
1491 set_newflags (mb, TRUE); /* set new flags */
1492 }
1493 } /* end if 2-proc */
1494 } /* end for */
1495
1496 /* Should never get here */
1497
1498 ABORT (STOP_UNKNOWN);
1499 }
1500
1501 /* Single word integer routines */
1502
1503 /* Integer add
1504
1505 Truth table for integer add
1506
1507 case a b r flags
1508 1 + + + none
1509 2 + + - AOV + C1
1510 3 + - + C0 + C1
1511 4 + - - -
1512 5 - + + C0 + C1
1513 6 - + - -
1514 7 - - + AOV + C0
1515 8 - - - C0 + C1
1516 */
1517
add(d10 a,d10 b)1518 d10 add (d10 a, d10 b)
1519 {
1520 d10 r;
1521
1522 r = (a + b) & DMASK;
1523 if (TSTS (a & b)) { /* cases 7,8 */
1524 if (TSTS (r)) /* case 8 */
1525 SETF (F_C0 | F_C1);
1526 else SETF (F_C0 | F_AOV | F_T1); /* case 7 */
1527 return r;
1528 }
1529 if (!TSTS (a | b)) { /* cases 1,2 */
1530 if (TSTS (r)) /* case 2 */
1531 SETF (F_C1 | F_AOV | F_T1);
1532 return r; /* case 1 */
1533 }
1534 if (!TSTS (r)) /* cases 3,5 */
1535 SETF (F_C0 | F_C1);
1536 return r;
1537 }
1538
1539 /* Integer subtract - actually ac + ~op + 1 */
1540
sub(d10 a,d10 b)1541 d10 sub (d10 a, d10 b)
1542 {
1543 d10 r;
1544
1545 r = (a - b) & DMASK;
1546 if (TSTS (a & ~b)) { /* cases 7,8 */
1547 if (TSTS (r)) /* case 8 */
1548 SETF (F_C0 | F_C1);
1549 else SETF (F_C0 | F_AOV | F_T1); /* case 7 */
1550 return r;
1551 }
1552 if (!TSTS (a | ~b)) { /* cases 1,2 */
1553 if (TSTS (r)) /* case 2 */
1554 SETF (F_C1 | F_AOV | F_T1);
1555 return r; /* case 1 */
1556 }
1557 if (!TSTS (r)) /* cases 3,5 */
1558 SETF (F_C0 | F_C1);
1559 return r;
1560 }
1561
1562
1563 /* Logical shift */
1564
lsh(d10 val,a10 ea)1565 d10 lsh (d10 val, a10 ea)
1566 {
1567 int32 sc = LIT8 (ea);
1568
1569 if (sc > 35)
1570 return 0;
1571 if (ea & RSIGN)
1572 return (val >> sc);
1573 return ((val << sc) & DMASK);
1574 }
1575
1576 /* Rotate */
1577
rot(d10 val,a10 ea)1578 d10 rot (d10 val, a10 ea)
1579 {
1580 int32 sc = LIT8 (ea) % 36;
1581
1582 if (sc == 0)
1583 return val;
1584 if (ea & RSIGN)
1585 sc = 36 - sc;
1586 return (((val << sc) | (val >> (36 - sc))) & DMASK);
1587 }
1588
1589 /* Double word integer instructions */
1590
1591 /* Double add - see case table for single add */
1592
dadd(int32 ac,d10 * rs)1593 void dadd (int32 ac, d10 *rs)
1594 {
1595 d10 r;
1596 int32 p1 = ADDAC (ac, 1);
1597
1598 AC(p1) = CLRS (AC(p1)) + CLRS (rs[1]); /* add lo */
1599 r = (AC(ac) + rs[0] + (TSTS (AC(p1))? 1: 0)) & DMASK; /* add hi+cry */
1600 if (TSTS (AC(ac) & rs[0])) { /* cases 7,8 */
1601 if (TSTS (r)) /* case 8 */
1602 SETF (F_C0 | F_C1);
1603 else SETF (F_C0 | F_AOV | F_T1); /* case 7 */
1604 }
1605 else if (!TSTS (AC(ac) | rs[0])) { /* cases 1,2 */
1606 if (TSTS (r)) /* case 2 */
1607 SETF (F_C1 | F_AOV | F_T1);
1608 }
1609 else if (!TSTS (r)) /* cases 3,5 */
1610 SETF (F_C0 | F_C1);
1611 AC(ac) = r;
1612 AC(p1) = TSTS (r)? SETS (AC(p1)): CLRS (AC(p1));
1613 return;
1614 }
1615
1616 /* Double subtract - see comments for single subtract */
1617
dsub(int32 ac,d10 * rs)1618 void dsub (int32 ac, d10 *rs)
1619 {
1620 d10 r;
1621 int32 p1 = ADDAC (ac, 1);
1622
1623 AC(p1) = CLRS (AC(p1)) - CLRS (rs[1]); /* sub lo */
1624 r = (AC(ac) - rs[0] - (TSTS (AC(p1))? 1: 0)) & DMASK; /* sub hi,borrow */
1625 if (TSTS (AC(ac) & ~rs[0])) { /* cases 7,8 */
1626 if (TSTS (r)) /* case 8 */
1627 SETF (F_C0 | F_C1);
1628 else SETF (F_C0 | F_AOV | F_T1); /* case 7 */
1629 }
1630 else if (!TSTS (AC(ac) | ~rs[0])) { /* cases 1,2 */
1631 if (TSTS (r)) /* case 2 */
1632 SETF (F_C1 | F_AOV | F_T1);
1633 }
1634 else if (!TSTS (r)) /* cases 3,5 */
1635 SETF (F_C0 | F_C1);
1636 AC(ac) = r;
1637 AC(p1) = (TSTS (r)? SETS (AC(p1)): CLRS (AC(p1))) & DMASK;
1638 return;
1639 }
1640
1641
1642 /* Logical shift combined */
1643
lshc(int32 ac,a10 ea)1644 void lshc (int32 ac, a10 ea)
1645 {
1646 int32 p1 = ADDAC (ac, 1);
1647 int32 sc = LIT8 (ea);
1648
1649 if (sc > 71)
1650 AC(ac) = AC(p1) = 0;
1651 else if (ea & RSIGN) {
1652 if (sc >= 36) {
1653 AC(p1) = AC(ac) >> (sc - 36);
1654 AC(ac) = 0;
1655 }
1656 else {
1657 AC(p1) = ((AC(p1) >> sc) | (AC(ac) << (36 - sc))) & DMASK;
1658 AC(ac) = AC(ac) >> sc;
1659 }
1660 }
1661 else {
1662 if (sc >= 36) {
1663 AC(ac) = (AC(p1) << (sc - 36)) & DMASK;
1664 AC(p1) = 0;
1665 }
1666 else {
1667 AC(ac) = ((AC(ac) << sc) | (AC(p1) >> (36 - sc))) & DMASK;
1668 AC(p1) = (AC(p1) << sc) & DMASK;
1669 }
1670 }
1671 return;
1672 }
1673
1674 /* Rotate combined */
1675
rotc(int32 ac,a10 ea)1676 void rotc (int32 ac, a10 ea)
1677 {
1678 int32 p1 = ADDAC (ac, 1);
1679 int32 sc = LIT8 (ea) % 72;
1680 d10 t = AC(ac);
1681
1682 if (sc == 0)
1683 return;
1684 if (ea & RSIGN)
1685 sc = 72 - sc;
1686 if (sc >= 36) {
1687 AC(ac) = ((AC(p1) << (sc - 36)) | (t >> (72 - sc))) & DMASK;
1688 AC(p1) = ((t << (sc - 36)) | (AC(p1) >> (72 - sc))) & DMASK;
1689 }
1690 else {
1691 AC(ac) = ((t << sc) | (AC(p1) >> (36 - sc))) & DMASK;
1692 AC(p1) = ((AC(p1) << sc) | (t >> (36 - sc))) & DMASK;
1693 }
1694 return;
1695 }
1696
1697 /* Arithmetic shifts */
1698
ash(d10 val,a10 ea)1699 d10 ash (d10 val, a10 ea)
1700 {
1701 int32 sc = LIT8 (ea);
1702 d10 sign = TSTS (val);
1703 d10 fill = sign? ONES: 0;
1704 d10 so;
1705
1706 if (sc == 0)
1707 return val;
1708 if (sc > 35) /* cap sc at 35 */
1709 sc = 35;
1710 if (ea & RSIGN)
1711 return (((val >> sc) | (fill << (36 - sc))) & DMASK);
1712 so = val >> (35 - sc); /* bits lost left + sign */
1713 if (so != (sign? bytemask[sc + 1]: 0))
1714 SETF (F_AOV | F_T1);
1715 return (sign | ((val << sc) & MMASK));
1716 }
1717
ashc(int32 ac,a10 ea)1718 void ashc (int32 ac, a10 ea)
1719 {
1720 int32 sc = LIT8 (ea);
1721 int32 p1 = ADDAC (ac, 1);
1722 d10 sign = TSTS (AC(ac));
1723 d10 fill = sign? ONES: 0;
1724 d10 so;
1725
1726 if (sc == 0)
1727 return;
1728 if (sc > 70) /* cap sc at 70 */
1729 sc = 70;
1730 AC(ac) = CLRS (AC(ac)); /* clear signs */
1731 AC(p1) = CLRS (AC(p1));
1732 if (ea & RSIGN) {
1733 if (sc >= 35) { /* right 36..70 */
1734 AC(p1) = ((AC(ac) >> (sc - 35)) | (fill << (70 - sc))) & DMASK;
1735 AC(ac) = fill;
1736 }
1737 else {
1738 AC(p1) = sign | /* right 1..35 */
1739 (((AC(p1) >> sc) | (AC(ac) << (35 - sc))) & MMASK);
1740 AC(ac) = ((AC(ac) >> sc) | (fill << (35 - sc))) & DMASK;
1741 }
1742 }
1743 else {
1744 if (sc >= 35) { /* left 36..70 */
1745 so = AC(p1) >> (70 - sc); /* bits lost left */
1746 if ((AC(ac) != (sign? MMASK: 0)) ||
1747 (so != (sign? bytemask[sc - 35]: 0)))
1748 SETF (F_AOV | F_T1);
1749 AC(ac) = sign | ((AC(p1) << (sc - 35)) & MMASK);
1750 AC(p1) = sign;
1751 }
1752 else {
1753 so = AC(ac) >> (35 - sc); /* bits lost left */
1754 if (so != (sign? bytemask[sc]: 0))
1755 SETF (F_AOV | F_T1);
1756 AC(ac) = sign |
1757 (((AC(ac) << sc) | (AC(p1) >> (35 - sc))) & MMASK);
1758 AC(p1) = sign | ((AC(p1) << sc) & MMASK);
1759 }
1760 }
1761 return;
1762 }
1763
1764 /* Effective address routines */
1765
1766 /* Calculate effective address - used by byte instructions, extended
1767 instructions, and interrupts to get a different mapping context from
1768 the main loop. prv is either EABP_PXCT or MM_CUR.
1769 */
1770
calc_ea(d10 inst,int32 prv)1771 a10 calc_ea (d10 inst, int32 prv)
1772 {
1773 int32 i, ea, xr;
1774 d10 indrct;
1775
1776 for (indrct = inst, i = 0; i < ind_max; i++) {
1777 ea = GET_ADDR (indrct);
1778 xr = GET_XR (indrct);
1779 if (xr)
1780 ea = (ea + ((a10) XR (xr, prv))) & AMASK;
1781 if (TST_IND (indrct))
1782 indrct = Read (ea, prv);
1783 else break;
1784 }
1785 if (i >= ind_max)
1786 ABORT (STOP_IND);
1787 return ea;
1788 }
1789
1790 /* Calculate I/O effective address. Cases:
1791 - No index or indirect, return addr from instruction
1792 - Index only, index >= 0, return 36b sum of addr + index
1793 - Index only, index <= 0, return 18b sum of addr + index
1794 - Indirect, calculate 18b sum of addr + index, return
1795 entire word fetch (single level)
1796 */
1797
calc_ioea(d10 inst,int32 pflgs)1798 a10 calc_ioea (d10 inst, int32 pflgs)
1799 {
1800 int32 xr;
1801 a10 ea;
1802
1803 xr = GET_XR (inst);
1804 ea = GET_ADDR (inst);
1805 if (TST_IND (inst)) { /* indirect? */
1806 if (xr)
1807 ea = (ea + ((a10) XR (xr, MM_EA))) & AMASK;
1808 ea = (a10) Read (ea, MM_EA);
1809 }
1810 else if (xr) { /* direct + idx? */
1811 ea = ea + ((a10) XR (xr, MM_EA));
1812 if (TSTS (XR (xr, MM_EA)))
1813 ea = ea & AMASK;
1814 }
1815 return ea;
1816 }
1817
1818 /* Calculate JRSTF effective address. This routine preserves
1819 the left half of the effective address, to be the new flags.
1820 */
1821
calc_jrstfea(d10 inst,int32 pflgs)1822 d10 calc_jrstfea (d10 inst, int32 pflgs)
1823 {
1824 int32 i, xr;
1825 d10 mb;
1826
1827 for (i = 0; i < ind_max; i++) {
1828 mb = inst;
1829 xr = GET_XR (inst);
1830 if (xr)
1831 mb = (mb & AMASK) + XR (xr, MM_EA);
1832 if (TST_IND (inst))
1833 inst = Read (((a10) mb) & AMASK, MM_EA);
1834 else break;
1835 }
1836 if (i >= ind_max)
1837 ABORT (STOP_IND);
1838 return (mb & DMASK);
1839 }
1840
1841 /* Byte pointer routines */
1842
1843 /* Increment byte pointer - checked against KS10 ucode */
1844
ibp(a10 ea,int32 pflgs)1845 void ibp (a10 ea, int32 pflgs)
1846 {
1847 int32 p, s;
1848 d10 bp;
1849
1850 bp = ReadM (ea, MM_OPND); /* get byte ptr */
1851 p = GET_P (bp); /* get P and S */
1852 s = GET_S (bp);
1853 p = p - s; /* adv P */
1854 if (p < 0) { /* end of word? */
1855 bp = (bp & LMASK) | (INCR (bp)); /* incr addr */
1856 p = (36 - s) & 077; /* reset P */
1857 }
1858 bp = PUT_P (bp, p); /* store new P */
1859 Write (ea, bp, MM_OPND); /* store byte ptr */
1860 return;
1861 }
1862
1863 /* Load byte */
1864
ldb(a10 ea,int32 pflgs)1865 d10 ldb (a10 ea, int32 pflgs)
1866 {
1867 a10 ba;
1868 int32 p, s;
1869 d10 bp, wd;
1870
1871 bp = Read (ea, MM_OPND); /* get byte ptr */
1872 p = GET_P (bp); /* get P and S */
1873 s = GET_S (bp);
1874 ba = calc_ea (bp, MM_EABP); /* get addr of byte */
1875 wd = Read (ba, MM_BSTK); /* read word */
1876 wd = (wd >> p); /* align byte */
1877 wd = wd & bytemask[s]; /* mask to size */
1878 return wd;
1879 }
1880
1881 /* Deposit byte - must use read and write to get page fail correct */
1882
dpb(d10 val,a10 ea,int32 pflgs)1883 void dpb (d10 val, a10 ea, int32 pflgs)
1884 {
1885 a10 ba;
1886 int32 p, s;
1887 d10 bp, wd, mask;
1888
1889 bp = Read (ea, MM_OPND); /* get byte ptr */
1890 p = GET_P (bp); /* get P and S */
1891 s = GET_S (bp);
1892 ba = calc_ea (bp, MM_EABP); /* get addr of byte */
1893 wd = Read (ba, MM_BSTK); /* read word */
1894 mask = bytemask[s] << p; /* shift mask, val */
1895 val = val << p;
1896 wd = (wd & ~mask) | (val & mask); /* insert byte */
1897 Write (ba, wd & DMASK, MM_BSTK);
1898 return;
1899 }
1900
1901 /* Adjust byte pointer - checked against KS10 ucode
1902 The KS10 divide checks if the bytes per word = 0, which is a simpler
1903 formulation of the processor reference manual check.
1904 */
1905
adjbp(int32 ac,a10 ea,int32 pflgs)1906 void adjbp (int32 ac, a10 ea, int32 pflgs)
1907 {
1908 int32 p, s;
1909 d10 bp, newby, left, byadj, bywrd, val, wdadj;
1910
1911 val = AC(ac); /* get adjustment */
1912 bp = Read (ea, MM_OPND); /* get byte pointer */
1913 p = GET_P (bp); /* get p */
1914 s = GET_S (bp); /* get s */
1915 if (s) {
1916 left = (36 - p) / s; /* bytes to left of p */
1917 bywrd = left + (p / s); /* bytes per word */
1918 if (bywrd == 0) { /* zero bytes? */
1919 SETF (F_AOV | F_T1 | F_DCK); /* set flags */
1920 return; /* abort operation */
1921 }
1922 newby = left + SXT (val); /* adjusted byte # */
1923 wdadj = newby / bywrd; /* word adjustment */
1924 byadj = (newby >= 0)? newby % bywrd: -((-newby) % bywrd);
1925 if (byadj <= 0) {
1926 byadj = byadj + bywrd; /* make adj positive */
1927 wdadj = wdadj - 1;
1928 }
1929 p = (36 - ((int32) byadj) * s) - ((36 - p) % s); /* new p */
1930 bp = (PUT_P (bp, p) & LMASK) | ((bp + wdadj) & RMASK);
1931 }
1932 AC(ac) = bp;
1933 return;
1934 }
1935
1936 /* Block transfer - checked against KS10 ucode
1937 The KS10 uses instruction specific recovery code in page fail
1938 to set the AC properly for restart. Lacking this mechanism,
1939 the simulator must test references in advance.
1940 The clocking test guarantees forward progress under single step.
1941 */
1942
blt(int32 ac,a10 ea,int32 pflgs)1943 void blt (int32 ac, a10 ea, int32 pflgs)
1944 {
1945 a10 srca = (a10) LRZ (AC(ac));
1946 a10 dsta = (a10) RRZ (AC(ac));
1947 a10 lnt = ea - dsta + 1;
1948 d10 srcv;
1949 int32 flg, t;
1950
1951 AC(ac) = XWD (srca + lnt, dsta + lnt);
1952 for (flg = 0; dsta <= ea; flg++) { /* loop */
1953 if (flg && (t = test_int ())) { /* timer event? */
1954 AC(ac) = XWD (srca, dsta); /* AC for intr */
1955 ABORT (t);
1956 }
1957 if (AccViol (srca & AMASK, MM_BSTK, PTF_RD)) { /* src access viol? */
1958 AC(ac) = XWD (srca, dsta); /* AC for page fail */
1959 Read (srca & AMASK, MM_BSTK); /* force trap */
1960 }
1961 if (AccViol (dsta & AMASK, MM_OPND, PTF_WR)) { /* dst access viol? */
1962 AC(ac) = XWD (srca, dsta); /* AC for page fail */
1963 ReadM (dsta & AMASK, MM_OPND); /* force trap */
1964 }
1965 srcv = Read (srca & AMASK, MM_BSTK); /* read */
1966 Write (dsta & AMASK, srcv, MM_OPND); /* write */
1967 srca = srca + 1; /* incr addr */
1968 dsta = dsta + 1;
1969 }
1970 return;
1971 }
1972
1973 /* I/O block transfers - byte to Unibus (0) and Unibus to byte (1) */
1974
1975 #define BYTE1 0776000000000
1976 #define BYTE2 0001774000000
1977 #define BYTE3 0000003770000
1978 #define BYTE4 0000000007760
1979 /* unused 0000000000017 */
1980
bltu(int32 ac,a10 ea,int32 pflgs,int dir)1981 void bltu (int32 ac, a10 ea, int32 pflgs, int dir)
1982 {
1983 a10 srca = (a10) LRZ (AC(ac));
1984 a10 dsta = (a10) RRZ (AC(ac));
1985 a10 lnt = ea - dsta + 1;
1986 d10 srcv, dstv;
1987 int32 flg, t;
1988
1989 AC(ac) = XWD (srca + lnt, dsta + lnt);
1990 for (flg = 0; dsta <= ea; flg++) { /* loop */
1991 if (flg && (t = test_int ())) { /* timer event? */
1992 AC(ac) = XWD (srca, dsta); /* AC for intr */
1993 ABORT (t);
1994 }
1995 if (AccViol (srca & AMASK, MM_BSTK, PTF_RD)) { /* src access viol? */
1996 AC(ac) = XWD (srca, dsta); /* AC for page fail */
1997 Read (srca & AMASK, MM_BSTK); /* force trap */
1998 }
1999 if (AccViol (dsta & AMASK, MM_OPND, PTF_WR)) { /* dst access viol? */
2000 AC(ac) = XWD (srca, dsta); /* AC for page fail */
2001 ReadM (dsta & AMASK, MM_OPND); /* force trap */
2002 }
2003 srcv = Read (srca & AMASK, MM_BSTK); /* read */
2004 if (dir) dstv = ((srcv << 10) & BYTE1) | ((srcv >> 6) & BYTE2) |
2005 ((srcv << 12) & BYTE3) | ((srcv >> 4) & BYTE4);
2006 else dstv = ((srcv & BYTE1) >> 10) | ((srcv & BYTE2) << 6) |
2007 ((srcv & BYTE3) >> 12) | ((srcv & BYTE4) << 4);
2008 Write (dsta & AMASK, dstv, MM_OPND); /* write */
2009 srca = srca + 1; /* incr addr */
2010 dsta = dsta + 1;
2011 }
2012 return;
2013 }
2014
2015 /* Utility routine to test for I/O event and interrupt */
2016
test_int(void)2017 int32 test_int (void)
2018 {
2019 int32 t;
2020
2021 if (sim_interval <= 0) { /* check queue */
2022 if ((t = sim_process_event ())) /* IO event? */
2023 return t;
2024 if (pi_eval ()) /* interrupt? */
2025 return (INTERRUPT);
2026 }
2027 else sim_interval--; /* count clock */
2028 return 0;
2029 }
2030
2031 /* Adjust stack pointer
2032
2033 The reference manual says to trap on:
2034 1) E < 0, left changes from + to -
2035 2) E >= 0, left changes from - to +
2036 This is the same as trap on:
2037 1) E and left result have same signs
2038 2) initial value and left result have different signs
2039 */
2040
adjsp(d10 val,a10 ea)2041 d10 adjsp (d10 val, a10 ea)
2042 {
2043 d10 imm = ea;
2044 d10 left, right;
2045
2046 left = ADDL (val, imm);
2047 right = ADDR (val, imm);
2048 if (TSTS ((val ^ left) & (~left ^ RLZ (imm))))
2049 SETF (F_T2);
2050 return (left | right);
2051 }
2052
2053 /* Jump if find first ones
2054 Takes advantage of 7 bit find first table for priority interrupts.
2055 */
2056
jffo(d10 val)2057 int32 jffo (d10 val)
2058 {
2059 int32 i, by;
2060
2061 if ((val & DMASK) == 0)
2062 return 0;
2063 for (i = 0; i <= 28; i = i + 7) { /* scan five bytes */
2064 by = (int32) ((val >> (29 - i)) & 0177);
2065 if (by)
2066 return (pi_m2lvl[by] + i - 1);
2067 }
2068 return 35; /* must be bit 35 */
2069 }
2070
2071 /* Circulate - ITS only instruction
2072
2073 Bits rotated out of AC are rotated into the opposite end of AC+1 - why?
2074 No attempt is made to optimize this instruction.
2075 */
2076
circ(int32 ac,int32 ea)2077 void circ (int32 ac, int32 ea)
2078 {
2079 int32 sc = LIT8 (ea) % 72;
2080 int32 p1 = ADDAC (ac,1);
2081 int32 i;
2082 d10 val;
2083
2084 if (sc == 0) /* any shift? */
2085 return;
2086 if (ea & RSIGN) /* if right, make left */
2087 sc = 72 - sc;
2088 for (i = 0; i < sc; i++) { /* one bit at a time */
2089 val = TSTS (AC(ac)); /* shift out */
2090 AC(ac) = ((AC(ac) << 1) | (AC(p1) & 1)) & DMASK;
2091 AC(p1) = (AC(p1) >> 1) | val; /* shift in */
2092 }
2093 return;
2094 }
2095
2096 /* Arithmetic processor (APR)
2097
2098 The APR subsystem includes miscellaneous interrupts that are individually
2099 maskable but which interrupt on a single, selectable level
2100
2101 Instructions for the arithmetic processor:
2102 APRID read system id
2103 WRAPR (CONO APR) write system flags
2104 RDAPR (CONI APR) read system flags
2105 (CONSO APR) test system flags
2106 (CONSZ APR) test system flags
2107 */
2108
aprid(a10 ea,int32 prv)2109 t_bool aprid (a10 ea, int32 prv)
2110 {
2111 Write (ea, (Q_ITS)? UC_AIDITS: UC_AIDDEC, prv);
2112 return FALSE;
2113 }
2114
2115 /* Checked against KS10 ucode */
2116
wrapr(a10 ea,int32 prv)2117 t_bool wrapr (a10 ea, int32 prv)
2118 {
2119 int32 bits = APR_GETF (ea);
2120
2121 apr_lvl = ea & APR_M_LVL;
2122 if (ea & APR_SENB) /* set enables? */
2123 apr_enb = apr_enb | bits;
2124 if (ea & APR_CENB) /* clear enables? */
2125 apr_enb = apr_enb & ~bits;
2126 if (ea & APR_CFLG) /* clear flags? */
2127 apr_flg = apr_flg & ~bits;
2128 if (ea & APR_SFLG) /* set flags? */
2129 apr_flg = apr_flg | bits;
2130 if (apr_flg & APRF_ITC) { /* interrupt console? */
2131 fe_intr (); /* explicit callout */
2132 apr_flg = apr_flg & ~APRF_ITC; /* interrupt clears */
2133 }
2134 pi_eval (); /* eval pi system */
2135 return FALSE;
2136 }
2137
rdapr(a10 ea,int32 prv)2138 t_bool rdapr (a10 ea, int32 prv)
2139 {
2140 Write (ea, (d10) APRWORD, prv);
2141 return FALSE;
2142 }
2143
czapr(a10 ea,int32 prv)2144 t_bool czapr (a10 ea, int32 prv)
2145 {
2146 return ((APRHWORD & ea)? FALSE: TRUE);
2147 }
2148
coapr(a10 ea,int32 prv)2149 t_bool coapr (a10 ea, int32 prv)
2150 {
2151 return ((APRHWORD & ea)? TRUE: FALSE);
2152 }
2153
2154 /* Routine to change the processor flags, called from JRST, MUUO, interrupt.
2155 If jrst is TRUE, must munge flags for executive security.
2156 Because the KS10 lacks the public flag, these checks are simplified.
2157 */
2158
set_newflags(d10 newf,t_bool jrst)2159 void set_newflags (d10 newf, t_bool jrst)
2160 {
2161 int32 fl = (int32) LRZ (newf);
2162
2163 if (jrst && TSTF (F_USR)) { /* if in user now */
2164 fl = fl | F_USR; /* can't clear user */
2165 if (!TSTF (F_UIO)) /* if !UIO, can't set */
2166 fl = fl & ~F_UIO;
2167 }
2168 if (Q_ITS && (fl & F_1PR)) { /* ITS 1-proceed? */
2169 its_1pr = 1; /* set flag */
2170 fl = fl & ~F_1PR; /* vanish bit */
2171 }
2172 flags = fl & F_MASK; /* set new flags */
2173 set_dyn_ptrs (); /* set new ptrs */
2174 return;
2175 }
2176
2177 /* Priority interrupt system (PI)
2178
2179 The priority interrupt system has three sources of requests
2180 (pi_apr) system flags - synthesized on the fly
2181 (pi_ioq) I/O interrupts - synthesized on the fly
2182 pi_prq program requests
2183 APR and I/O requests are masked with the PI enable mask; the program
2184 requests are not. If priority interrupts are enabled, and there is
2185 a request at a level exceeding the currently active level, then an
2186 interrupt occurs.
2187
2188 Instructions for the priority interrupt system:
2189 WRPI (CONO PI) write pi system
2190 RDPI (CONI PI) read pi system
2191 (CONSO PI) test pi system
2192 (CONSZ PI) test pi system
2193
2194 Routines for the priority interrupt system:
2195 pi_eval return level number of highest interrupt
2196 pi_dismiss dismiss highest outstanding interrupt
2197
2198 Checked against KS10 ucode - KS10 UUO's if <18:21> are non-zero
2199 */
2200
wrpi(a10 ea,int32 prv)2201 t_bool wrpi (a10 ea, int32 prv)
2202 {
2203 int32 lvl = ea & PI_M_LVL;
2204
2205 if (ea & PI_INIT)
2206 pi_on = pi_enb = pi_act = pi_prq = 0;
2207 if (ea & PI_CPRQ) /* clear prog reqs? */
2208 pi_prq = pi_prq & ~lvl;
2209 if (ea & PI_SPRQ) /* set prog reqs? */
2210 pi_prq = pi_prq | lvl;
2211 if (ea & PI_SENB) /* enable levels? */
2212 pi_enb = pi_enb | lvl;
2213 if (ea & PI_CENB) /* disable levels? */
2214 pi_enb = pi_enb & ~lvl;
2215 if (ea & PI_SON) /* enable pi? */
2216 pi_on = 1;
2217 if (ea & PI_CON) /* disable pi? */
2218 pi_on = 0;
2219 pi_eval (); /* eval pi system */
2220 return FALSE;
2221 }
2222
rdpi(a10 ea,int32 prv)2223 t_bool rdpi (a10 ea, int32 prv)
2224 {
2225 Write (ea, (d10) PIWORD, prv);
2226 return FALSE;
2227 }
2228
czpi(a10 ea,int32 prv)2229 t_bool czpi (a10 ea, int32 prv)
2230 {
2231 return ((PIHWORD & ea)? FALSE: TRUE);
2232 }
2233
copi(a10 ea,int32 prv)2234 t_bool copi (a10 ea, int32 prv)
2235 {
2236 return ((PIHWORD & ea)? TRUE: FALSE);
2237 }
2238
2239 /* Priority interrupt evaluation
2240
2241 The Processor Reference Manuals says that program interrupt
2242 requests occur whether the corresponding level is enabled or
2243 not. However, the KS10, starting with microcode edit 47,
2244 masked program requests under the enable mask, just like APR
2245 and I/O requests. This is not formally documented but appears
2246 to be necessary for the TOPS20 console port to run correclty.
2247 */
2248
pi_eval(void)2249 int32 pi_eval (void)
2250 {
2251 int32 reqlvl, actlvl;
2252 extern int32 pi_ub_eval ();
2253
2254 qintr = 0;
2255 if (pi_on) {
2256 pi_apr = (apr_flg & apr_enb)? pi_l2bit[apr_lvl]: 0;
2257 pi_ioq = pi_ub_eval ();
2258 reqlvl = pi_m2lvl[((pi_apr | pi_ioq | pi_prq) & pi_enb)];
2259 actlvl = pi_m2lvl[pi_act];
2260 if ((actlvl == 0) || (reqlvl < actlvl))
2261 qintr = reqlvl;
2262 }
2263 return qintr;
2264 }
2265
pi_dismiss(void)2266 void pi_dismiss (void)
2267 {
2268 pi_act = pi_act & ~pi_l2bit[pi_m2lvl[pi_act]]; /* clr left most bit */
2269 pi_eval (); /* eval pi system */
2270 return;
2271 }
2272
2273 /* Reset routine */
2274
cpu_reset(DEVICE * dptr)2275 t_stat cpu_reset (DEVICE *dptr)
2276 {
2277 flags = 0; /* clear flags */
2278 its_1pr = 0; /* clear 1-proceed */
2279 ebr = ubr = 0; /* clear paging */
2280 pi_enb = pi_act = pi_prq = 0; /* clear PI */
2281 apr_enb = apr_flg = apr_lvl = 0; /* clear APR */
2282 pcst = 0; /* clear PC samp */
2283 rlog = 0; /* clear reg log */
2284 hsb = (Q_ITS)? UC_HSBITS: UC_HSBDEC; /* set HSB */
2285 set_dyn_ptrs ();
2286 set_ac_display (ac_cur);
2287 pi_eval ();
2288 if (M == NULL)
2289 M = (d10 *) calloc (MAXMEMSIZE, sizeof (d10));
2290 if (M == NULL)
2291 return SCPE_MEM;
2292 pcq_r = find_reg ("PCQ", NULL, dptr);
2293 if (pcq_r)
2294 pcq_r->qptr = 0;
2295 else return SCPE_IERR;
2296 sim_brk_types = sim_brk_dflt = SWMASK ('E');
2297 return SCPE_OK;
2298 }
2299
2300 /* Memory examine */
2301
cpu_ex(t_value * vptr,t_addr ea,UNIT * uptr,int32 sw)2302 t_stat cpu_ex (t_value *vptr, t_addr ea, UNIT *uptr, int32 sw)
2303 {
2304 if (vptr == NULL)
2305 return SCPE_ARG;
2306 if (ea < AC_NUM)
2307 *vptr = AC(ea) & DMASK;
2308 else {
2309 if (sw & SWMASK ('V')) {
2310 ea = conmap (ea, PTF_CON, sw);
2311 if (ea >= MAXMEMSIZE)
2312 return SCPE_REL;
2313 }
2314 if (ea >= MEMSIZE)
2315 return SCPE_NXM;
2316 *vptr = M[ea] & DMASK;
2317 }
2318 return SCPE_OK;
2319 }
2320
2321 /* Memory deposit */
2322
cpu_dep(t_value val,t_addr ea,UNIT * uptr,int32 sw)2323 t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw)
2324 {
2325 if (ea < AC_NUM)
2326 AC(ea) = val & DMASK;
2327 else {
2328 if (sw & SWMASK ('V')) {
2329 ea = conmap (ea, PTF_CON | PTF_WR, sw);
2330 if (ea >= MAXMEMSIZE)
2331 return SCPE_REL;
2332 }
2333 if (ea >= MEMSIZE)
2334 return SCPE_NXM;
2335 M[ea] = val & DMASK;
2336 }
2337 return SCPE_OK;
2338 }
2339
2340 /* Set current AC pointers for SCP */
2341
set_ac_display(d10 * acbase)2342 void set_ac_display (d10 *acbase)
2343 {
2344 extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr);
2345 REG *rptr;
2346 int i;
2347
2348 rptr = find_reg ("AC0", NULL, &cpu_dev);
2349 if (rptr == NULL)
2350 return;
2351 for (i = 0; i < AC_NUM; i++, rptr++)
2352 rptr->loc = (void *) (acbase + i);
2353 return;
2354 }
2355
2356 /* Set history */
2357
cpu_set_hist(UNIT * uptr,int32 val,char * cptr,void * desc)2358 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
2359 {
2360 int32 i, lnt;
2361 t_stat r;
2362
2363 if (cptr == NULL) {
2364 for (i = 0; i < hst_lnt; i++)
2365 hst[i].pc = 0;
2366 hst_p = 0;
2367 return SCPE_OK;
2368 }
2369 lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
2370 if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
2371 return SCPE_ARG;
2372 hst_p = 0;
2373 if (hst_lnt) {
2374 free (hst);
2375 hst_lnt = 0;
2376 hst = NULL;
2377 }
2378 if (lnt) {
2379 hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));
2380 if (hst == NULL)
2381 return SCPE_MEM;
2382 hst_lnt = lnt;
2383 }
2384 return SCPE_OK;
2385 }
2386
2387 /* Show history */
2388
cpu_show_hist(FILE * st,UNIT * uptr,int32 val,void * desc)2389 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
2390 {
2391 int32 k, di, lnt;
2392 char *cptr = (char *) desc;
2393 t_stat r;
2394 t_value sim_eval;
2395 InstHistory *h;
2396 extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
2397 UNIT *uptr, int32 sw);
2398
2399 if (hst_lnt == 0) /* enabled? */
2400 return SCPE_NOFNC;
2401 if (cptr) {
2402 lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
2403 if ((r != SCPE_OK) || (lnt == 0))
2404 return SCPE_ARG;
2405 }
2406 else lnt = hst_lnt;
2407 di = hst_p - lnt; /* work forward */
2408 if (di < 0)
2409 di = di + hst_lnt;
2410 fprintf (st, "PC AC EA IR\n\n");
2411 for (k = 0; k < lnt; k++) { /* print specified */
2412 h = &hst[(++di) % hst_lnt]; /* entry pointer */
2413 if (h->pc & HIST_PC) { /* instruction? */
2414 fprintf (st, "%06o ", h->pc & AMASK);
2415 fprint_val (st, h->ac, 8, 36, PV_RZRO);
2416 fputs (" ", st);
2417 fprintf (st, "%06o ", h->ea);
2418 sim_eval = h->ir;
2419 if ((fprint_sym (st, h->pc & AMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0) {
2420 fputs ("(undefined) ", st);
2421 fprint_val (st, h->ir, 8, 36, PV_RZRO);
2422 }
2423 fputc ('\n', st); /* end line */
2424 } /* end else instruction */
2425 } /* end for */
2426 return SCPE_OK;
2427 }
2428