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