First Commit of my working state
[simh.git] / Interdata / id16_cpu.c
1 /* id16_cpu.c: Interdata 16b CPU simulator
2
3 Copyright (c) 2000-2007, Robert M. Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 cpu Interdata 16b CPU
27
28 28-Apr-07 RMS Removed clock initialization
29 27-Oct-06 RMS Added idle support
30 Removed separate PASLA clock
31 06-Feb-06 RMS Fixed bug in DH (found by Mark Hittinger)
32 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
33 25-Aug-05 RMS Fixed DH integer overflow cases
34 16-Aug-05 RMS Fixed C++ declaration and cast problems
35 10-Mar-05 RMS Fixed bug in show history routine (from Mark Hittinger)
36 Revised examine/deposit to do words rather than bytes
37 07-Nov-04 RMS Added instruction history
38 22-Sep-03 RMS Added additional instruction decode types
39 07-Feb-03 RMS Fixed bug in SETM, SETMR (found by Mark Pizzolato)
40
41 The register state for the Interdata 16b CPU is:
42
43 R[0:F]<0:15> general registers
44 F[0:7]<0:31> single precision floating point registers
45 D[0:7]<0:63> double precision floating point registers
46 PSW<0:31> processor status word, including
47 STAT<0:11> status flags
48 CC<0:3> condition codes
49 PC<0:15> program counter
50 int_req[8]<0:31> interrupt requests
51 int_enb[8]<0:31> interrupt enables
52
53 The Interdata 16b systems have four instruction formats: register to
54 register, short format, register to memory, and register to storage.
55 The formats are:
56
57 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
58 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
59 | op | R1 | R2 | register-register
60 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
61
62 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
63 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
64 | op | R1 | N | short format
65 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
66
67 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
68 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
69 | op | R1 | RX | register-memory
70 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
71 | address |
72 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
73
74 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
75 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
76 | op | R1 | RX | register-storage
77 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
78 | address |
79 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
80
81 For register-memory and register-storage instructions, an effective
82 address is calculated as follows:
83
84 effective addr = address + RX (if RX > 0)
85
86 Register-memory instructions can access an address space of 64K bytes.
87
88 The Interdata 16b product line had many different models, with varying
89 instruction sets:
90
91 instruction group model = 3 4 5 70 80 716 816 816E
92 base group (61) y y y y y y y y
93 AL, LM, STM (3) - y y y y y y y
94 single prec fp (13) - y y y y y y y
95 model 5 group (36) - - y y y y y y
96 double prec fp (17) - - - - - - y y
97 memory extension (4) - - - - - - - y
98
99 This allows the most common CPU options to be covered by just five
100 model selections: I3, I4, I5/70/80/716, I816, and I816E. Variations
101 within a model (e.g., 816 with no floating point or just single
102 precision floating point) are not implemented.
103
104 The I3 kept its general registers in memory; this is not simulated.
105 Single precision (only) floating point was implemented in microcode,
106 did not have a guard digit, and kept the floating point registers in
107 memory. Double precision floating point was implemented in hardware,
108 provided a guard digit for single precision (but not double), and
109 kept the floating point registers in hardware.
110
111 This routine is the instruction decode routine for the Interdata CPU.
112 It is called from the simulator control program to execute
113 instructions in simulated memory, starting at the simulated PC.
114 It runs until 'reason' is set non-zero.
115
116 General notes:
117
118 1. Reasons to stop. The simulator can be stopped by:
119
120 HALT instruction
121 breakpoint encountered
122 wait state and no I/O outstanding
123 invalid instruction
124 I/O error in I/O simulator
125
126 2. Interrupts. Each device has an interrupt armed flag, an interrupt
127 request flag, and an interrupt enabled flag. To facilitate evaluation,
128 all interrupt requests are kept in int_req, and all enables in int_enb.
129 Interrupt armed flags are local to devices. If external interrupts are
130 enabled in the PSW, and a request is pending, an interrupt occurs.
131
132 3. Non-existent memory. On the Interdata 16b, reads to non-existent
133 memory return zero, and writes are ignored. In the simulator, the
134 largest possible memory is instantiated and initialized to zero.
135 Thus, only writes need be checked against actual memory size.
136
137 4. Adding I/O devices. These modules must be modified:
138
139 id_defs.h add device interrupt definitions
140 id16_sys.c add sim_devices table entry
141 */
142
143 #include "id_defs.h"
144
145 #define PCQ_SIZE 64 /* must be 2**n */
146 #define PCQ_MASK (PCQ_SIZE - 1)
147 #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = oPC
148 #define VAMASK VAMASK16
149 #define VA_S1 0x8000 /* S0/S1 flag */
150
151 #define UNIT_V_MSIZE (UNIT_V_UF + 0) /* dummy mask */
152 #define UNIT_V_ID4 (UNIT_V_UF + 1)
153 #define UNIT_V_716 (UNIT_V_UF + 2)
154 #define UNIT_V_816 (UNIT_V_UF + 3)
155 #define UNIT_V_816E (UNIT_V_UF + 4)
156 #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
157 #define UNIT_ID4 (1 << UNIT_V_ID4)
158 #define UNIT_716 (1 << UNIT_V_716)
159 #define UNIT_816 (1 << UNIT_V_816)
160 #define UNIT_816E (1 << UNIT_V_816E)
161 #define UNIT_TYPE (UNIT_ID4 | UNIT_716 | UNIT_816 | UNIT_816E)
162
163 #define HIST_MIN 64
164 #define HIST_MAX 65536
165
166 typedef struct {
167 uint16 vld;
168 uint16 pc;
169 uint16 ir1;
170 uint16 ir2;
171 uint16 r1;
172 uint16 ea;
173 uint16 opnd;
174 } InstHistory;
175
176 #define PSW_GETMAP(x) (((x) >> PSW_V_MAP) & PSW_M_MAP)
177 #define SEXT16(x) (((x) & SIGN16)? ((int32) ((x) | 0xFFFF8000)): \
178 ((int32) ((x) & 0x7FFF)))
179 #define CC_GL_16(x) if ((x) & SIGN16) cc = CC_L; \
180 else if (x) cc = CC_G; \
181 else cc = 0
182 #define CC_GL_32(x) if ((x) & SIGN32) cc = CC_L; \
183 else if (x) cc = CC_G; \
184 else cc = 0
185 #define BUILD_PSW(x) (((PSW & ~CC_MASK) | (x)) & psw_mask)
186 #define CPU_x16 (cpu_unit.flags & (UNIT_716 | UNIT_816 | UNIT_816E))
187
188 uint32 GREG[16] = { 0 }; /* general registers */
189 uint16 *M = NULL; /* memory */
190 uint32 *R = &GREG[0]; /* register set ptr */
191 uint32 F[8] = { 0 }; /* sp fp registers */
192 dpr_t D[8] = { 0 }; /* dp fp registers */
193 uint32 PSW = 0; /* processor status word */
194 uint32 psw_mask = PSW_x16; /* PSW mask */
195 uint32 PC = 0; /* program counter */
196 uint32 SR = 0; /* switch register */
197 uint32 DR = 0; /* display register */
198 uint32 DRX = 0; /* display extension */
199 uint32 drmod = 0; /* mode */
200 uint32 srpos = 0; /* switch register pos */
201 uint32 drpos = 0; /* display register pos */
202 uint32 s0_rel = 0; /* S0 relocation */
203 uint32 s1_rel = 0; /* S1 relocation */
204 uint32 int_req[INTSZ] = { 0 }; /* interrupt requests */
205 uint32 int_enb[INTSZ] = { 0 }; /* interrupt enables */
206 int32 blkiop = -1; /* block I/O in prog */
207 uint32 qevent = 0; /* events */
208 uint32 stop_inst = 0; /* stop on ill inst */
209 uint32 stop_wait = 0; /* stop on wait */
210 uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
211 int32 pcq_p = 0; /* PC queue ptr */
212 REG *pcq_r = NULL; /* PC queue reg ptr */
213 uint32 dec_flgs = 0; /* decode flags */
214 uint32 fp_in_hwre = 0; /* ucode/hwre fp */
215 uint32 pawidth = PAWIDTH16; /* phys addr mask */
216 uint32 hst_p = 0; /* history pointer */
217 uint32 hst_lnt = 0; /* history length */
218 InstHistory *hst = NULL; /* instruction history */
219 struct BlockIO blk_io; /* block I/O status */
220 uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL };
221
222 extern int32 sim_interval;
223 extern int32 sim_int_char;
224 extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
225 extern t_bool sim_idle_enab;
226
227 uint32 ReadB (uint32 loc);
228 uint32 ReadH (uint32 loc);
229 void WriteB (uint32 loc, uint32 val);
230 void WriteH (uint32 loc, uint32 val);
231 uint32 int_auto (uint32 dev, uint32 cc);
232 uint32 addtoq (uint32 ea, uint32 val, uint32 flg);
233 uint32 remfmq (uint32 ea, uint32 r1, uint32 flg);
234 uint32 newPSW (uint32 val);
235 uint32 swap_psw (uint32 loc, uint32 cc);
236 uint32 testsysq (uint32);
237 uint32 display (uint32 dev, uint32 op, uint32 dat);
238 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
239 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
240 t_stat cpu_reset (DEVICE *dptr);
241 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
242 t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc);
243 t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc);
244 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
245 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
246
247 extern t_bool devtab_init (void);
248 extern void int_eval (void);
249 extern uint32 int_getdev (void);
250 extern t_bool sch_blk (uint32 dev);
251 extern uint32 f_l (uint32 op, uint32 r1, uint32 r2, uint32 ea);
252 extern uint32 f_c (uint32 op, uint32 r1, uint32 r2, uint32 ea);
253 extern uint32 f_as (uint32 op, uint32 r1, uint32 r2, uint32 ea);
254 extern uint32 f_m (uint32 op, uint32 r1, uint32 r2, uint32 ea);
255 extern uint32 f_d (uint32 op, uint32 r1, uint32 r2, uint32 ea);
256 extern uint32 f_fix (uint32 op, uint32 r1, uint32 r2);
257 extern uint32 f_flt (uint32 op, uint32 r1, uint32 r2);
258
259 /* Instruction decoding table - flags are first implementation */
260
261 const uint16 decrom[256] = {
262 0, /* 00 */
263 OP_RR, /* BALR */
264 OP_RR, /* BTCR */
265 OP_RR, /* BFCR */
266 OP_RR, /* NHR */
267 OP_RR, /* CLHR */
268 OP_RR, /* OHR */
269 OP_RR, /* XHR */
270 OP_RR, /* LHR */
271 OP_RR | OP_716, /* CHR */
272 OP_RR, /* AHR */
273 OP_RR, /* SHR */
274 OP_RR, /* MHR */
275 OP_RR, /* DHR */
276 OP_RR, /* ACHR */
277 OP_RR, /* SCHR */
278 0, 0, 0, /* 10:12 */
279 OP_RR | OP_816E | OP_PRV, /* SETMR */
280 0, 0, 0, 0, /* 14:1F */
281 0, 0, 0, 0, 0, 0, 0, 0,
282 OP_NO | OP_716, /* BTBS */
283 OP_NO | OP_716, /* BTFS */
284 OP_NO | OP_716, /* BFBS */
285 OP_NO | OP_716, /* BFFS */
286 OP_NO | OP_716, /* LIS */
287 OP_NO | OP_716, /* LCS */
288 OP_NO | OP_716, /* AIS */
289 OP_NO | OP_716, /* SIS */
290 OP_NO | OP_ID4, /* LER */
291 OP_NO | OP_ID4, /* CER */
292 OP_NO | OP_ID4, /* AER */
293 OP_NO | OP_ID4, /* SER */
294 OP_NO | OP_ID4, /* MER */
295 OP_NO | OP_ID4, /* DER */
296 OP_NO | OP_816, /* FXR */
297 OP_NO | OP_816, /* FLR */
298 0, 0, 0, /* 30:32 */
299 OP_NO | OP_816E | OP_PRV, /* LPSR */
300 0, 0, 0, 0, /* 34:37 */
301 OP_NO | OP_816 | OP_DPF, /* LDR */
302 OP_NO | OP_816 | OP_DPF, /* CDR */
303 OP_NO | OP_816 | OP_DPF, /* ADR */
304 OP_NO | OP_816 | OP_DPF, /* SDR */
305 OP_NO | OP_816 | OP_DPF, /* MDR */
306 OP_NO | OP_816 | OP_DPF, /* DDR */
307 OP_NO | OP_816 | OP_DPF, /* FXDR */
308 OP_NO | OP_816 | OP_DPF, /* FLDR */
309 OP_RX, /* STH */
310 OP_RX, /* BAL */
311 OP_RX, /* BTC */
312 OP_RX, /* BFC */
313 OP_RXH, /* NH */
314 OP_RXH, /* CLH */
315 OP_RXH, /* OH */
316 OP_RXH, /* XH */
317 OP_RXH, /* LH */
318 OP_RXH | OP_716, /* CH */
319 OP_RXH, /* AH */
320 OP_RXH, /* SH */
321 OP_RXH, /* MH */
322 OP_RXH, /* DH */
323 OP_RXH, /* ACH */
324 OP_RXH, /* SCH */
325 0, 0, 0, /* 50:52 */
326 OP_RXH | OP_816E | OP_PRV, /* SETM */
327 0, 0, 0, 0, /* 54:5F */
328 0, 0, 0, 0, 0, 0, 0, 0,
329 OP_RX | OP_ID4, /* STE */
330 OP_RXH | OP_716, /* AHM */
331 0, 0, /* 62:63 */
332 OP_RX | OP_716, /* ATL */
333 OP_RX | OP_716, /* ABL */
334 OP_RX | OP_716, /* RTL */
335 OP_RX | OP_716, /* RBL */
336 OP_RX | OP_ID4, /* LE */
337 OP_RX | OP_ID4, /* CE */
338 OP_RX | OP_ID4, /* AE */
339 OP_RX | OP_ID4, /* SE */
340 OP_RX | OP_ID4, /* ME */
341 OP_RX | OP_ID4, /* DE */
342 0, 0, /* 6E:6F */
343 OP_RX | OP_816 | OP_DPF, /* STD */
344 OP_RX | OP_816, /* SME */
345 OP_RX | OP_816, /* LME */
346 OP_RXH | OP_816E | OP_PRV, /* LPS */
347 0, 0, 0, 0, /* 74:7F */
348 OP_RX | OP_816 | OP_DPF, /* LD */
349 OP_RX | OP_816 | OP_DPF, /* CD */
350 OP_RX | OP_816 | OP_DPF, /* AD */
351 OP_RX | OP_816 | OP_DPF, /* SD */
352 OP_RX | OP_816 | OP_DPF, /* MD */
353 OP_RX | OP_816 | OP_DPF, /* DD */
354 OP_RX | OP_816 | OP_DPF, /* STMD */
355 OP_RX | OP_816 | OP_DPF, /* LMD */
356 0, 0, 0, 0, 0, 0, 0, 0, /* 80:8F */
357 0, 0, 0, 0, 0, 0, 0, 0,
358 OP_NO | OP_716, /* SRLS */
359 OP_NO | OP_716, /* SLLS */
360 OP_NO, /* STBR */
361 OP_RR, /* LDBR */
362 OP_RR | OP_716, /* EXBR */
363 OP_NO | OP_716 | OP_PRV, /* EPSR */
364 OP_RR | OP_PRV, /* WBR */
365 OP_RR | OP_PRV, /* RBR */
366 OP_RR | OP_716 | OP_PRV, /* WHR */
367 OP_RR | OP_716 | OP_PRV, /* RHR */
368 OP_RR | OP_PRV, /* WDR */
369 OP_RR | OP_PRV, /* RDR */
370 OP_RR | OP_716, /* MHUR */
371 OP_RR | OP_PRV, /* SSR */
372 OP_RR | OP_PRV, /* OCR */
373 OP_RR | OP_PRV, /* AIR */
374 0, 0, 0, 0, 0, 0, 0, 0, /* A0:AF */
375 0, 0, 0, 0, 0, 0, 0, 0,
376 0, 0, 0, 0, 0, 0, 0, 0, /* B0:BF */
377 0, 0, 0, 0, 0, 0, 0, 0,
378 OP_RX, /* BXH */
379 OP_RX, /* BXLE */
380 OP_RX | OP_PRV, /* LPSW */
381 OP_RS | OP_716, /* THI */
382 OP_RS, /* NHI */
383 OP_RS, /* CLHI */
384 OP_RS, /* OHI */
385 OP_RS, /* XHI */
386 OP_RS, /* LHI */
387 OP_RS | OP_716, /* CHI */
388 OP_RS, /* AHI */
389 OP_RS, /* SHI */
390 OP_RS, /* SRHL */
391 OP_RS, /* SLHL */
392 OP_RS, /* SRHA */
393 OP_RS, /* SLHA */
394 OP_RX | OP_ID4, /* STM */
395 OP_RX | OP_ID4, /* LM */
396 OP_RX, /* STB */
397 OP_RXB, /* LDB */
398 OP_RXB | OP_716, /* CLB */
399 OP_RX | OP_ID4 | OP_PRV, /* AL */
400 OP_RXH | OP_PRV, /* WB */
401 OP_RXH | OP_PRV, /* RB */
402 OP_RX | OP_716 | OP_PRV, /* WH */
403 OP_RX | OP_716 | OP_PRV, /* RH */
404 OP_RX | OP_PRV, /* WD */
405 OP_RX | OP_PRV, /* RD */
406 OP_RXH | OP_716, /* MHU */
407 OP_RX | OP_PRV, /* SS */
408 OP_RX | OP_PRV, /* OC */
409 OP_RX | OP_PRV, /* AI */
410 0, /* E0 */
411 OP_RX | OP_716, /* SVC */
412 OP_RS | OP_716 | OP_PRV, /* SINT */
413 0, 0, 0, 0, 0, 0, 0, /* E3:E9 */
414 OP_RS | OP_716, /* RRL */
415 OP_RS | OP_716, /* RLL */
416 OP_RS | OP_716, /* SRL */
417 OP_RS | OP_716, /* SLL */
418 OP_RS | OP_716, /* SRA */
419 OP_RS | OP_716, /* SLA */
420 0, 0, 0, 0, 0, 0, 0, 0, /* F0:FF */
421 0, 0, 0, 0, 0, 0, 0, 0
422 };
423
424 /* 8/16E relocation constants for S0 and S1, indexed by PSW<8:11> */
425
426 static uint32 s0_rel_const[16] = { /* addr 0-7FFF */
427 0x00000, 0x00000, 0x00000, 0x00000, /* 0 = no reloc */
428 0x00000, 0x00000, 0x00000, 0x08000, /* 8000 = rel to S1 */
429 0x08000, 0x08000, 0x08000, 0x08000,
430 0x08000, 0x08000, 0x08000, 0x00000
431 };
432
433 static uint32 s1_rel_const[16] = { /* addr 8000-FFFF */
434 0x00000, 0x08000, 0x10000, 0x18000, /* reloc const must */
435 0x20000, 0x28000, 0x30000, 0xFFF8000, /* "sub" base addr */
436 0x00000, 0x08000, 0x10000, 0x18000,
437 0x20000, 0x28000, 0x30000, 0x00000
438 };
439
440 /* CPU data structures
441
442 cpu_dev CPU device descriptor
443 cpu_unit CPU unit descriptor
444 cpu_reg CPU register list
445 cpu_mod CPU modifiers list
446 */
447
448 DIB cpu_dib = { d_DS, -1, v_DS, NULL, &display, NULL };
449
450 UNIT cpu_unit = {
451 UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_716, MAXMEMSIZE16)
452 };
453
454 REG cpu_reg[] = {
455 { HRDATA (PC, PC, 16) },
456 { HRDATA (R0, GREG[0], 16) },
457 { HRDATA (R1, GREG[1], 16) },
458 { HRDATA (R2, GREG[2], 16) },
459 { HRDATA (R3, GREG[3], 16) },
460 { HRDATA (R4, GREG[4], 16) },
461 { HRDATA (R5, GREG[5], 16) },
462 { HRDATA (R6, GREG[6], 16) },
463 { HRDATA (R7, GREG[7], 16) },
464 { HRDATA (R8, GREG[8], 16) },
465 { HRDATA (R9, GREG[9], 16) },
466 { HRDATA (R10, GREG[10], 16) },
467 { HRDATA (R11, GREG[11], 16) },
468 { HRDATA (R12, GREG[12], 16) },
469 { HRDATA (R13, GREG[13], 16) },
470 { HRDATA (R14, GREG[14], 16) },
471 { HRDATA (R15, GREG[15], 16) },
472 { HRDATA (FR0, F[0], 32) },
473 { HRDATA (FR2, F[1], 32) },
474 { HRDATA (FR4, F[2], 32) },
475 { HRDATA (FR6, F[3], 32) },
476 { HRDATA (FR8, F[4], 32) },
477 { HRDATA (FR10, F[5], 32) },
478 { HRDATA (FR12, F[6], 32) },
479 { HRDATA (FR14, F[7], 32) },
480 { HRDATA (D0H, D[0].h, 32) },
481 { HRDATA (D0L, D[0].l, 32) },
482 { HRDATA (D2H, D[1].h, 32) },
483 { HRDATA (D2L, D[1].l, 32) },
484 { HRDATA (D4H, D[2].h, 32) },
485 { HRDATA (D4L, D[2].l, 32) },
486 { HRDATA (D6H, D[3].h, 32) },
487 { HRDATA (D6L, D[3].l, 32) },
488 { HRDATA (D8H, D[4].h, 32) },
489 { HRDATA (D8L, D[4].l, 32) },
490 { HRDATA (D10H, D[5].h, 32) },
491 { HRDATA (D10L, D[5].l, 32) },
492 { HRDATA (D12L, D[6].l, 32) },
493 { HRDATA (D12H, D[6].h, 32) },
494 { HRDATA (D14H, D[7].h, 32) },
495 { HRDATA (D14L, D[7].l, 32) },
496 { HRDATA (PSW, PSW, 16) },
497 { HRDATA (CC, PSW, 4) },
498 { HRDATA (SR, SR, 16) },
499 { HRDATA (DR, DR, 32) },
500 { HRDATA (DRX, DRX, 8) },
501 { FLDATA (DRMOD, drmod, 0) },
502 { FLDATA (SRPOS, srpos, 0) },
503 { HRDATA (DRPOS, drpos, 3) },
504 { BRDATA (IRQ, int_req, 16, 32, 8) },
505 { BRDATA (IEN, int_enb, 16, 32, 8) },
506 { HRDATA (QEVENT, qevent, 4), REG_HRO },
507 { FLDATA (STOP_INST, stop_inst, 0) },
508 { FLDATA (STOP_WAIT, stop_inst, 0) },
509 { BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO+REG_CIRC },
510 { HRDATA (PCQP, pcq_p, 6), REG_HRO },
511 { HRDATA (WRU, sim_int_char, 8) },
512 { HRDATA (BLKIOD, blk_io.dfl, 16), REG_HRO },
513 { HRDATA (BLKIOC, blk_io.cur, 16), REG_HRO },
514 { HRDATA (BLKIOE, blk_io.end, 16), REG_HRO },
515 { NULL }
516 };
517
518 MTAB cpu_mod[] = {
519 { UNIT_TYPE, 0, "I3", "I3", &cpu_set_model },
520 { UNIT_TYPE, UNIT_ID4, "I4", "I4", &cpu_set_model },
521 { UNIT_TYPE, UNIT_716, "7/16", "716", &cpu_set_model },
522 { UNIT_TYPE, UNIT_816, "8/16", "816", &cpu_set_model },
523 { UNIT_TYPE, UNIT_816E, "8/16E", "816E", &cpu_set_model },
524 { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
525 { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
526 { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
527 { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
528 { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
529 { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
530 { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size },
531 { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
532 { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size },
533 { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size },
534 { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT",
535 &cpu_set_consint, NULL, NULL },
536 { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
537 &cpu_set_hist, &cpu_show_hist },
538 { 0 }
539 };
540
541 DEVICE cpu_dev = {
542 "CPU", &cpu_unit, cpu_reg, cpu_mod,
543 1, 16, 18, 2, 16, 16,
544 &cpu_ex, &cpu_dep, &cpu_reset,
545 NULL, NULL, NULL,
546 &cpu_dib, 0
547 };
548
549 t_stat sim_instr (void)
550 {
551 uint32 cc;
552 t_stat reason;
553
554 /* Restore register state */
555
556 if (devtab_init ()) return SCPE_STOP; /* check conflicts */
557 pawidth = PAWIDTH16; /* default width */
558 if (cpu_unit.flags & UNIT_816E) { /* 8/16E? */
559 dec_flgs = 0; /* all instr ok */
560 fp_in_hwre = 1; /* fp in hwre */
561 pawidth = PAWIDTH16E; /* 18b phys addr */
562 psw_mask = PSW_816E; /* mem ext bits */
563 }
564 else if (cpu_unit.flags & UNIT_816) { /* 8/16? */
565 dec_flgs = OP_816E;
566 fp_in_hwre = 1;
567 pawidth = PAWIDTH16;
568 psw_mask = PSW_x16;
569 }
570 else if (cpu_unit.flags & UNIT_716) { /* I5, 70, 80, 7/16? */
571 dec_flgs = OP_816 | OP_816E;
572 fp_in_hwre = 0;
573 pawidth = PAWIDTH16;
574 psw_mask = PSW_x16;
575 }
576 else if (cpu_unit.flags & UNIT_ID4) { /* I4? */
577 dec_flgs = OP_716 | OP_816 | OP_816E;
578 fp_in_hwre = 0;
579 pawidth = PAWIDTH16;
580 psw_mask = PSW_ID4;
581 }
582 else {
583 dec_flgs = OP_ID4 | OP_716 | OP_816 | OP_816E; /* I3 */
584 fp_in_hwre = 0;
585 pawidth = PAWIDTH16;
586 psw_mask = PSW_ID4;
587 }
588 int_eval (); /* eval interrupts */
589 cc = newPSW (PSW & psw_mask); /* split PSW, eval wait */
590 reason = 0;
591
592 /* Process events */
593
594 while (reason == 0) { /* loop until halted */
595 uint32 dev, drom, inc, lim, opnd;
596 uint32 op, r1, r1p1, r2, ea, oPC;
597 uint32 rslt, t, map;
598 uint32 ir1, ir2, ityp;
599 int32 sr, st;
600
601 if (sim_interval <= 0) { /* check clock queue */
602 if (reason = sim_process_event ()) break;
603 int_eval ();
604 }
605
606 if (qevent) { /* any events? */
607 if (qevent & EV_BLK) { /* block I/O in prog? */
608 dev = blk_io.dfl & DEV_MAX; /* get device */
609 cc = dev_tab[dev] (dev, IO_SS, 0) & 0xF; /* sense status */
610 if (cc == STA_BSY) { /* just busy? */
611 sim_interval = 0; /* force I/O event */
612 continue;
613 }
614 else if (cc == 0) { /* ready? */
615 if (blk_io.dfl & BL_RD) { /* read? */
616 t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */
617 if ((t == 0) && (blk_io.dfl & BL_LZ)) continue;
618 blk_io.dfl = blk_io.dfl & ~BL_LZ; /* non-zero seen */
619 WriteB (blk_io.cur, t); /* write mem */
620 }
621 else { /* write */
622 t = ReadB (blk_io.cur); /* read mem */
623 dev_tab[dev] (dev, IO_WD, t); /* put byte */
624 }
625 if (blk_io.cur != blk_io.end) { /* more to do? */
626 blk_io.cur = (blk_io.cur + 1) & VAMASK; /* incr addr */
627 continue;
628 }
629 }
630 qevent = qevent & ~EV_BLK; /* clr block I/O flg */
631 int_eval (); /* re-eval intr */
632 continue;
633 }
634
635 if ((qevent & EV_INT) && (PSW & PSW_EXI)) { /* interrupt? */
636 if (PSW & PSW_AIO) { /* auto enabled? */
637 dev = int_getdev (); /* get int dev */
638 cc = int_auto (dev, cc); /* do auto intr */
639 int_eval (); /* re-eval intr */
640 }
641 else cc = swap_psw (EXIPSW, cc); /* old type, swap */
642 continue;
643 }
644
645 if (PSW & PSW_WAIT) { /* wait state? */
646 if (sim_idle_enab) /* idling enabled? */
647 sim_idle (TMR_LFC, TRUE);
648 else sim_interval = sim_interval - 1; /* no, count cycle */
649 continue;
650 }
651
652 qevent = 0; /* no events */
653 } /* end if event */
654
655 /* Fetch and decode instruction */
656
657 if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
658 reason = STOP_IBKPT; /* stop simulation */
659 break;
660 }
661
662 sim_interval = sim_interval - 1;
663
664 ir1 = ReadH (oPC = PC); /* fetch instr */
665 op = (ir1 >> 8) & 0xFF; /* isolate op, R1, R2 */
666 r1 = (ir1 >> 4) & 0xF;
667 r2 = ir1 & 0xF;
668 drom = decrom[op];
669 ityp = drom & OP_MASK;
670
671 if ((drom == 0) || (drom & dec_flgs)) { /* not in model? */
672 if (stop_inst) reason = STOP_RSRV; /* stop or */
673 else cc = swap_psw (ILOPSW, cc); /* swap PSW */
674 continue;
675 }
676 if ((drom & OP_PRV) && (PSW & PSW_PRO)) { /* priv & protected? */
677 cc = swap_psw (ILOPSW, cc); /* swap PSW */
678 continue;
679 }
680
681 switch (ityp) { /* decode instruction */
682
683 case OP_NO: /* no operand */
684 opnd = r2; /* assume short */
685 break;
686
687 case OP_RR: /* reg-reg */
688 opnd = R[r2]; /* operand is R2 */
689 break;
690
691 case OP_RS: /* reg-storage */
692 case OP_RX: /* reg-mem */
693 PC = (PC + 2) & VAMASK; /* increment PC */
694 ir2 = ea = ReadH (PC); /* fetch address */
695 if (r2) ea = (ir2 + R[r2]) & VAMASK; /* index calculation */
696 opnd = ea; /* operand is ea */
697 break;
698
699 case OP_RXB: /* reg-mem byte */
700 PC = (PC + 2) & VAMASK; /* increment PC */
701 ir2 = ea = ReadH (PC); /* fetch address */
702 if (r2) ea = (ea + R[r2]) & VAMASK; /* index calculation */
703 opnd = ReadB (ea); /* fetch operand */
704 break;
705
706 case OP_RXH: /* reg-mem halfword */
707 PC = (PC + 2) & VAMASK; /* increment PC */
708 ir2 = ea = ReadH (PC); /* fetch address */
709 if (r2) ea = (ea + R[r2]) & VAMASK; /* index calculation */
710 opnd = ReadH (ea); /* fetch operand */
711 break;
712
713 default:
714 return SCPE_IERR;
715 }
716
717 if (hst_lnt) { /* instruction history? */
718 hst[hst_p].vld = 1;
719 hst[hst_p].pc = oPC;
720 hst[hst_p].ir1 = ir1;
721 hst[hst_p].ir2 = ir2;
722 hst[hst_p].r1 = R[r1];
723 hst[hst_p].ea = ea;
724 hst[hst_p].opnd = opnd;
725 hst_p = hst_p + 1;
726 if (hst_p >= hst_lnt) hst_p = 0;
727 }
728
729 PC = (PC + 2) & VAMASK; /* increment PC */
730 switch (op) { /* case on opcode */
731
732 /* Load/store instructions */
733
734 case 0x08: /* LHR - RR */
735 case 0x24: /* LIS - NO */
736 case 0x48: /* LH - RXH */
737 case 0xC8: /* LHI - RS */
738 R[r1] = opnd; /* load operand */
739 CC_GL_16 (R[r1]); /* set G,L */
740 break;
741
742 case 0x25: /* LCS - NO */
743 R[r1] = (~opnd + 1) & DMASK16; /* load complement */
744 CC_GL_16 (R[r1]); /* set G,L */
745 break;
746
747 case 0x40: /* STH - RX */
748 WriteH (ea, R[r1]); /* store register */
749 break;
750
751 case 0xD1: /* LM - RX */
752 for ( ; r1 <= 0xF; r1++) { /* loop thru reg */
753 R[r1] = ReadH (ea); /* load register */
754 ea = (ea + 2) & VAMASK; /* incr mem addr */
755 }
756 break;
757
758 case 0xD0: /* STM - RX */
759 for ( ; r1 <= 0xF; r1++) { /* loop thru reg */
760 WriteH (ea, R[r1]); /* store register */
761 ea = (ea + 2) & VAMASK; /* incr mem addr */
762 }
763 break;
764
765 case 0x93: /* LDBR - RR */
766 case 0xD3: /* LDB - RXB */
767 R[r1] = opnd & DMASK8; /* load byte */
768 break;
769
770 case 0x92: /* STBR - NO */
771 R[r2] = (R[r2] & ~DMASK8) | (R[r1] & DMASK8); /* store byte */
772 break;
773 case 0xD2: /* STB - RX */
774 WriteB (ea, R[r1] & DMASK8); /* store byte */
775 break;
776
777 case 0x94: /* EXBR - RR */
778 R[r1] = (opnd >> 8) | ((opnd & DMASK8) << 8);
779 break;
780
781 /* Control instructions */
782
783 case 0x01: /* BALR - RR */
784 case 0x41: /* BAL - RX */
785 PCQ_ENTRY; /* save old PC */
786 R[r1] = PC; /* save cur PC */
787 PC = opnd; /* branch */
788 break;
789
790 case 0x02: /* BTCR - RR */
791 case 0x42: /* BTC - RX */
792 if (cc & r1) { /* test CC's */
793 PCQ_ENTRY; /* branch if true */
794 PC = opnd;
795 }
796 break;
797
798 case 0x20: /* BTBS - NO */
799 if (cc & r1) { /* test CC's */
800 PCQ_ENTRY; /* branch if true */
801 PC = (oPC - r2 - r2) & VAMASK;
802 }
803 break;
804
805 case 0x21: /* BTFS - NO */
806 if (cc & r1) { /* test CC's */
807 PCQ_ENTRY; /* branch if true */
808 PC = (oPC + r2 + r2) & VAMASK;
809 }
810 break;
811
812 case 0x03: /* BFCR - RR */
813 case 0x43: /* BFC - RX */
814 if ((cc & r1) == 0) { /* test CC's */
815 PCQ_ENTRY; /* branch if false */
816 PC = opnd;
817 }
818 break;
819
820 case 0x22: /* BFBS - NO */
821 if ((cc & r1) == 0) { /* test CC's */
822 PCQ_ENTRY; /* branch if false */
823 PC = (oPC - r2 - r2) & VAMASK;
824 }
825 break;
826
827 case 0x23: /* BFFS - NO */
828 if ((cc & r1) == 0) { /* test CC's */
829 PCQ_ENTRY; /* branch if false */
830 PC = (oPC + r2 + r2) & VAMASK;
831 }
832 break;
833
834 case 0xC0: /* BXH - RX */
835 inc = R[(r1 + 1) & 0xF]; /* inc = R1 + 1 */
836 lim = R[(r1 + 2) & 0xF]; /* lim = R1 + 2 */
837 R[r1] = (R[r1] + inc) & DMASK16; /* R1 = R1 + inc */
838 if (R[r1] > lim) { /* if R1 > lim */
839 PCQ_ENTRY; /* branch */
840 PC = opnd;
841 }
842 break;
843
844 case 0xC1: /* BXLE - RX */
845 inc = R[(r1 + 1) & 0xF]; /* inc = R1 + 1 */
846 lim = R[(r1 + 2) & 0xF]; /* lim = R1 + 2 */
847 R[r1] = (R[r1] + inc) & DMASK16; /* R1 = R1 + inc */
848 if (R[r1] <= lim) { /* if R1 <= lim */
849 PCQ_ENTRY; /* branch */
850 PC = opnd;
851 }
852 break;
853
854 /* Logical instructions */
855
856 case 0x04: /* NHR - RR */
857 case 0x44: /* NH - RXH */
858 case 0xC4: /* NHI - RS */
859 R[r1] = R[r1] & opnd; /* result */
860 CC_GL_16 (R[r1]); /* set G,L */
861 break;
862
863 case 0x06: /* OHR - RR */
864 case 0x46: /* OH - RXH */
865 case 0xC6: /* OHI - RS */
866 R[r1] = R[r1] | opnd; /* result */
867 CC_GL_16 (R[r1]); /* set G,L */
868 break;
869
870 case 0x07: /* XHR - RR */
871 case 0x47: /* XH - RXH */
872 case 0xC7: /* XHI - RS */
873 R[r1] = R[r1] ^ opnd; /* result */
874 CC_GL_16 (R[r1]); /* set G,L */
875 break;
876
877 case 0xC3: /* THI - RS */
878 rslt = R[r1] & opnd; /* result */
879 CC_GL_16 (rslt); /* set G, L */
880 break;
881
882 case 0x05: /* CLHR - RR */
883 case 0x45: /* CLH - RXH */
884 case 0xC5: /* CLHI - RS */
885 rslt = (R[r1] - opnd) & DMASK16; /* result */
886 CC_GL_16 (rslt); /* set G,L */
887 if (R[r1] < opnd) cc = cc | CC_C; /* set C if borrow */
888 if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN16) cc = cc | CC_V;
889 break;
890
891 case 0xD4: /* CLB - RXB */
892 t = R[r1] & DMASK8;
893 rslt = (t - opnd) & DMASK16; /* result */
894 CC_GL_16 (rslt); /* set G,L */
895 if (t < opnd) cc = cc | CC_C; /* set C if borrow */
896 break;
897
898 /* Shift instructions */
899
900 case 0xCC: /* SRHL - RS */
901 opnd = opnd & 0xF; /* shift count */
902 case 0x90: /* SRLS - NO */
903 rslt = R[r1] >> opnd; /* result */
904 CC_GL_16 (rslt); /* set G,L */
905 if (opnd && ((R[r1] >> (opnd - 1)) & 1)) cc = cc | CC_C;
906 R[r1] = rslt; /* store result */
907 break;
908
909 case 0xCD: /* SLHL - RS */
910 opnd = opnd & 0xF; /* shift count */
911 case 0x91: /* SLLS - NO */
912 rslt = R[r1] << opnd; /* raw result */
913 R[r1] = rslt & DMASK16; /* masked result */
914 CC_GL_16 (R[r1]); /* set G,L */
915 if (opnd && (rslt & 0x10000)) cc = cc | CC_C; /* set C if shft out */
916 break;
917
918 case 0xCE: /* SRHA - RS */
919 opnd = opnd & 0xF; /* shift count */
920 rslt = (SEXT16 (R[r1]) >> opnd) & DMASK16; /* result */
921 CC_GL_16 (rslt); /* set G,L */
922 if (opnd && ((R[r1] >> (opnd - 1)) & 1)) cc = cc | CC_C;
923 R[r1] = rslt; /* store result */
924 break;
925
926 case 0xCF: /* SLHA - RS */
927 opnd = opnd & 0xF; /* shift count */
928 rslt = R[r1] << opnd; /* raw result */
929 R[r1] = (R[r1] & SIGN16) | (rslt & MMASK16); /* arith result */
930 CC_GL_16 (R[r1]); /* set G,L */
931 if (opnd && (rslt & SIGN16)) cc = cc | CC_C; /* set C if shft out */
932 break;
933
934 case 0xEA: /* RRL - RS */
935 r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */
936 opnd = opnd & 0x1F; /* shift count */
937 t = (R[r1] << 16) | R[r1p1]; /* form 32b op */
938 if (opnd) rslt = (t >> opnd) | (t << (32 - opnd)); /* result */
939 else rslt = t; /* no shift */
940 CC_GL_32 (rslt); /* set G,L 32b */
941 R[r1] = (rslt >> 16) & DMASK16; /* hi result */
942 R[r1p1] = rslt & DMASK16; /* lo result */
943 break;
944
945 case 0xEB: /* RLL - RS */
946 r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */
947 opnd = opnd & 0x1F; /* shift count */
948 t = (R[r1] << 16) | R[r1p1]; /* form 32b op */
949 if (opnd) rslt = (t << opnd) | (t >> (32 - opnd)); /* result */
950 else rslt = t; /* no shift */
951 CC_GL_32 (rslt); /* set G,L 32b */
952 R[r1] = (rslt >> 16) & DMASK16; /* hi result */
953 R[r1p1] = rslt & DMASK16; /* lo result */
954 break;
955
956 case 0xEC: /* SRL - RS */
957 r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */
958 opnd = opnd & 0x1F; /* shift count */
959 t = (R[r1] << 16) | R[r1p1]; /* form 32b op */
960 rslt = t >> opnd; /* result */
961 CC_GL_32 (rslt); /* set G,L 32b */
962 if (opnd && ((t >> (opnd - 1)) & 1)) cc = cc | CC_C;
963 R[r1] = (rslt >> 16) & DMASK16; /* hi result */
964 R[r1p1] = rslt & DMASK16; /* lo result */
965 break;
966
967 case 0xED: /* SLL - RS */
968 r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */
969 opnd = opnd & 0x1F; /* shift count */
970 t = (R[r1] << 16) | R[r1p1]; /* form 32b op */
971 rslt = t << opnd; /* result */
972 CC_GL_32 (rslt); /* set G,L 32b */
973 if (opnd && ((t << (opnd - 1)) & SIGN32)) cc = cc | CC_C;
974 R[r1] = (rslt >> 16) & DMASK16; /* hi result */
975 R[r1p1] = rslt & DMASK16; /* lo result */
976 break;
977
978 case 0xEE: /* SRA - RS */
979 r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */
980 opnd = opnd & 0x1F; /* shift count */
981 t = (R[r1] << 16) | R[r1p1]; /* form 32b op */
982 rslt = ((int32) t) >> opnd; /* signed result */
983 CC_GL_32 (rslt); /* set G,L 32b */
984 if (opnd && ((t >> (opnd - 1)) & 1)) cc = cc | CC_C;
985 R[r1] = (rslt >> 16) & DMASK16; /* hi result */
986 R[r1p1] = rslt & DMASK16; /* lo result */
987 break;
988
989 case 0xEF: /* SLA - RS */
990 r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */
991 opnd = opnd & 0x1F; /* shift count */
992 t = (R[r1] << 16) | R[r1p1]; /* form 32b op */
993 rslt = (t & SIGN32) | ((t << opnd) & MMASK32); /* signed result */
994 CC_GL_32 (rslt); /* set G,L 32b */
995 if (opnd && ((t << opnd) & SIGN32)) cc = cc | CC_C;
996 R[r1] = (rslt >> 16) & DMASK16; /* hi result */
997 R[r1p1] = rslt & DMASK16; /* lo result */
998 break;
999
1000 /* Arithmetic instructions */
1001
1002 case 0x0A: /* AHR - RR */
1003 case 0x26: /* AIS - NO */
1004 case 0x4A: /* AH - RXH */
1005 case 0xCA: /* AHI - RS */
1006 rslt = (R[r1] + opnd) & DMASK16; /* result */
1007 CC_GL_16 (rslt); /* set G,L */
1008 if (rslt < opnd) cc = cc | CC_C; /* set C if carry */
1009 if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN16) cc = cc | CC_V;
1010 R[r1] = rslt;
1011 break;
1012
1013 case 0x61: /* AHM - RXH */
1014 rslt = (R[r1] + opnd) & DMASK16; /* result */
1015 CC_GL_16 (rslt); /* set G,L */
1016 if (rslt < opnd) cc = cc | CC_C; /* set C if carry */
1017 if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN16) cc = cc | CC_V;
1018 WriteH (ea, rslt); /* store in memory */
1019 break;
1020
1021 case 0x0B: /* SHR - RR */
1022 case 0x27: /* SIS - NO */
1023 case 0x4B: /* SH - RXH */
1024 case 0xCB: /* SHI - RS */
1025 rslt = (R[r1] - opnd) & DMASK16; /* result */
1026 CC_GL_16 (rslt); /* set G,L */
1027 if (R[r1] < opnd) cc = cc | CC_C; /* set C if borrow */
1028 if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN16) cc = cc | CC_V;
1029 R[r1] = rslt;
1030 break;
1031
1032 case 0x09: /* CHR - RR */
1033 case 0x49: /* CH - RXH */
1034 case 0xC9: /* CHI - RS */
1035 sr = SEXT16 (R[r1]); /* sign ext */
1036 st = SEXT16 (opnd);
1037 if (sr < st) cc = CC_C | CC_L; /* < sets C, L */
1038 else if (sr > st) cc = CC_G; /* > sets G */
1039 else cc = 0;
1040 if (((R[r1] ^ opnd) & (~opnd ^ (sr - st))) & SIGN16)
1041 cc = cc | CC_V;
1042 break;
1043
1044 case 0x0C: /* MHR - RR */
1045 case 0x4C: /* MH - RXH */
1046 r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */
1047 rslt = SEXT16 (R[r1p1]) * SEXT16 (opnd); /* multiply */
1048 R[r1] = (rslt >> 16) & DMASK16; /* hi result */
1049 R[r1p1] = rslt & DMASK16; /* lo result */
1050 break;
1051
1052 case 0x9C: /* MHUR - RR */
1053 case 0xDC: /* MHU - RXH */
1054 r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */
1055 rslt = R[r1p1] * opnd; /* multiply, unsigned */
1056 R[r1] = (rslt >> 16) & DMASK16; /* hi result */
1057 R[r1p1] = rslt & DMASK16; /* lo result */
1058 break;
1059
1060 case 0x0D: /* DHR - RR */
1061 case 0x4D: /* DH - RXH */
1062 r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */
1063 if ((opnd == 0) ||
1064 ((R[r1] == 0x8000) && (R[r1p1] == 0) && (opnd == 0xFFFF))) {
1065 if (PSW & PSW_AFI) /* div fault enabled? */
1066 cc = swap_psw (AFIPSW, cc); /* swap PSW */
1067 break;
1068 }
1069 sr = (R[r1] << 16) | R[r1p1]; /* signed 32b divd */
1070 st = sr / SEXT16 (opnd); /* signed quotient */
1071 sr = sr % SEXT16 (opnd); /* remainder */
1072 if ((st < 0x8000) && (st >= -0x8000)) { /* if quo fits */
1073 R[r1] = sr & DMASK16; /* store remainder */
1074 R[r1p1] = st & DMASK16; /* store quotient */
1075 }
1076 else if (PSW & PSW_AFI) /* div fault enabled? */
1077 cc = swap_psw (AFIPSW, cc); /* swap PSW */
1078 break;
1079
1080 case 0x0E: /* ACHR - RR */
1081 case 0x4E: /* ACH - RXH */
1082 t = R[r1] + opnd + ((cc & CC_C) != 0); /* raw result */
1083 rslt = t & DMASK16; /* masked result */
1084 CC_GL_16 (rslt); /* set G,L */
1085 if (t > DMASK16) cc = cc | CC_C; /* set C if carry */
1086 if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN16) cc = cc | CC_V;
1087 R[r1] = rslt; /* store result */
1088 break;
1089
1090 case 0x0F: /* SCHR - RR */
1091 case 0x4F: /* SCH - RXH */
1092 t = R[r1] - opnd - ((cc & CC_C) != 0); /* raw result */
1093 rslt = t & DMASK16; /* masked result */
1094 CC_GL_16 (rslt); /* set G,L */
1095 if (t > DMASK16) cc = cc | CC_C; /* set C if borrow */
1096 if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN16) cc = cc | CC_V;
1097 R[r1] = rslt; /* store result */
1098 break;
1099
1100 /* Floating point instructions */
1101
1102 case 0x28: /* LER - NO */
1103 case 0x38: /* LDR - NO */
1104 case 0x68: /* LE - RX */
1105 case 0x78: /* LD - RX */
1106 cc = f_l (op, r1, r2, ea); /* load */
1107 if ((cc & CC_V) && (PSW & PSW_FPF) && CPU_x16) /* V set, x/16? */
1108 cc = swap_psw (FPFPSW, cc);
1109 break;
1110
1111 case 0x29: /* CER - NO */
1112 case 0x39: /* CDR - NO */
1113 case 0x69: /* CE - RX */
1114 case 0x79: /* CD - RX */
1115 cc = f_c (op, r1, r2, ea); /* compare */
1116 break;
1117
1118 case 0x2A: /* AER - NO */
1119 case 0x2B: /* SER - NO */
1120 case 0x3A: /* ADR - NO */
1121 case 0x3B: /* SDR - NO */
1122 case 0x6A: /* AE - RX */
1123 case 0x6B: /* SE - RX */
1124 case 0x7A: /* AD - RX */
1125 case 0x7B: /* SD - RX */
1126 cc = f_as (op, r1, r2, ea); /* add/sub */
1127 if ((cc & CC_V) && (PSW & PSW_FPF) && CPU_x16) /* V set, x/16? */
1128 cc = swap_psw (FPFPSW, cc);
1129 break;
1130
1131 case 0x2C: /* MER - NO */
1132 case 0x3C: /* MDR - NO */
1133 case 0x6C: /* ME - RX */
1134 case 0x7C: /* MD - RX */
1135 cc = f_m (op, r1, r2, ea); /* multiply */
1136 if ((cc & CC_V) && (PSW & PSW_FPF) && CPU_x16) /* V set, x/16? */
1137 cc = swap_psw (FPFPSW, cc);
1138 break;
1139
1140 case 0x2D: /* DER - NO */
1141 case 0x3D: /* DDR - NO */
1142 case 0x6D: /* DE - RX */
1143 case 0x7D: /* DD - RX */
1144 cc = f_d (op, r1, r2, ea); /* perform divide */
1145 if ((cc & CC_V) && ((cc & CC_C) || /* V set, x/16 or */
1146 ((PSW & PSW_FPF) && CPU_x16))) /* V & C set? */
1147 cc = swap_psw (FPFPSW, cc);
1148 break;
1149
1150 case 0x2E: /* FXR - NO */
1151 case 0x3E: /* FXDR - NO */
1152 cc = f_fix (op, r1, r2); /* cvt to integer */
1153 break;
1154
1155 case 0x2F: /* FLR - NO */
1156 case 0x3F: /* FLDR - NO */
1157 cc = f_flt (op, r1, r2); /* cvt to floating */
1158 break;
1159
1160 case 0x60: /* STE - RX */
1161 t = ReadFReg (r1); /* get fp reg */
1162 WriteF (ea, t, P); /* write */
1163 break;
1164
1165 case 0x70: /* STD - RX */
1166 WriteF (ea, D[r1 >> 1].h, P); /* write hi */
1167 WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, P); /* write lo */
1168 break;
1169
1170 case 0x71: /* STME - RX */
1171 for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */
1172 t = ReadFReg (r1); /* get fp reg */
1173 WriteF (ea, t, P); /* write */
1174 ea = (ea + 4) & VAMASK; /* incr mem addr */
1175 }
1176 break;
1177
1178 case 0x72: /* LME - RX */
1179 for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */
1180 t = ReadF (ea, P); /* get value */
1181 WriteFReg (r1, t); /* write reg */
1182 ea = (ea + 4) & VAMASK; /* incr mem addr */
1183 }
1184 break;
1185
1186 case 0x7E: /* STMD - RX */
1187 for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */
1188 WriteF (ea, D[r1 >> 1].h, P); /* write register */
1189 WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, P);
1190 ea = (ea + 8) & VAMASK; /* incr mem addr */
1191 }
1192 break;
1193
1194 case 0x7F: /* LMD - RX */
1195 for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */
1196 D[r1 >> 1].h = ReadF (ea, P); /* load register */
1197 D[r1 >> 1].l = ReadF ((ea + 4) & VAMASK, P);
1198 ea = (ea + 8) & VAMASK; /* incr mem addr */
1199 }
1200 break;
1201
1202 /* Miscellaneous */
1203
1204 case 0xE1: /* SVC - RX */
1205 PCQ_ENTRY; /* save PC */
1206 WriteH (SVCAP, ea); /* save opnd */
1207 WriteH (SVOPS, BUILD_PSW (cc)); /* save PS */
1208 WriteH (SVOPC, PC); /* save PC */
1209 PC = ReadH (SVNPC + r1 + r1); /* new PC */
1210 cc = newPSW (ReadH (SVNPS)); /* new PS */
1211 break;
1212
1213 case 0xE2: /* SINT - RS */
1214 dev = opnd & DEV_MAX; /* get dev */
1215 cc = int_auto (dev, cc); /* auto intr */
1216 int_eval (); /* re-eval intr */
1217 break;
1218
1219 case 0xC2: /* LPSW - RX */
1220 PCQ_ENTRY; /* effective branch */
1221 PC = ReadH ((ea + 2) & VAMASK); /* read PC */
1222 cc = newPSW (ReadH (ea)); /* read PSW */
1223 if (PSW & PSW_SQI) cc = testsysq (cc); /* test for q */
1224 break;
1225
1226 case 0x95: /* EPSR - NO */
1227 R[r1] = BUILD_PSW (cc); /* save PSW */
1228 case 0x33: /* LPSR - NO */
1229 cc = newPSW (R[r2]); /* load new PSW */
1230 if (PSW & PSW_SQI) cc = testsysq (cc); /* test for q */
1231 break;
1232
1233 case 0x73: /* LPS - RXH */
1234 cc = newPSW (opnd); /* load new PSW */
1235 if (PSW & PSW_SQI) cc = testsysq (cc); /* test for q */
1236 break;
1237
1238 case 0x64: /* ATL - RX */
1239 case 0x65: /* ABL - RX */
1240 cc = addtoq (ea, R[r1], op & 1); /* add to q */
1241 break;
1242
1243 case 0x66: /* RTL - RX */
1244 case 0x67: /* RBL - RX */
1245 cc = remfmq (ea, r1, op & 1); /* remove from q */
1246 break;
1247
1248 case 0x13: /* SETMR - RR */
1249 case 0x53: /* SETM - RXH */
1250 t = BUILD_PSW (cc); /* old PSW */
1251 map = PSW_GETMAP (opnd); /* get new map */
1252 switch (map) { /* case on map */
1253
1254 case 0x7:
1255 map = 0; /* use 1:1 map */
1256 R[r1] = R[r1] ^ SIGN16; /* flip sign */
1257 break;
1258
1259 case 0x8: case 0x9: case 0xA: case 0xB:
1260 case 0xC: case 0xD: case 0xE:
1261 if (R[r1] & SIGN16) map = map & ~0x8; /* S1? clr map<0> */
1262 else {
1263 map = 0; /* else 1:1 map */
1264 R[r1] = R[r1] | SIGN16; /* set sign */
1265 }
1266 break;
1267
1268 default:
1269 break;
1270 }
1271 t = (t & ~PSW_MAP) | (map << PSW_V_MAP); /* insert map */
1272 newPSW (t); /* load new PSW */
1273 CC_GL_16 (R[r1]); /* set G,L */
1274 break;
1275
1276 /* I/O instructions */
1277
1278 case 0xDE: /* OC - RX */
1279 opnd = ReadB (ea); /* fetch operand */
1280 case 0x9E: /* OCR - RR */
1281 dev = R[r1] & DEV_MAX;
1282 if (DEV_ACC (dev)) {
1283 dev_tab[dev] (dev, IO_ADR, 0); /* select */
1284 dev_tab[dev] (dev, IO_OC, opnd & DMASK8); /* send command */
1285 int_eval (); /* re-eval intr */
1286 cc = 0;
1287 }
1288 else cc = CC_V;
1289 break;
1290
1291 case 0xDA: /* WD - RX */
1292 opnd = ReadB (ea); /* fetch operand */
1293 case 0x9A: /* WDR - RR */
1294 dev = R[r1] & DEV_MAX;
1295 if (DEV_ACC (dev)) {
1296 dev_tab[dev] (dev, IO_ADR, 0); /* select */
1297 dev_tab[dev] (dev, IO_WD, opnd & DMASK8); /* send data */
1298 int_eval (); /* re-eval intr */
1299 cc = 0;
1300 }
1301 else cc = CC_V;
1302 break;
1303
1304 case 0xD8: /* WH - RX */
1305 opnd = ReadH (ea); /* fetch operand */
1306 case 0x98: /* WHR - RR */
1307 dev = R[r1] & DEV_MAX;
1308 if (DEV_ACC (dev)) {
1309 if (dev_tab[dev] (dev, IO_ADR, 0)) /* select; hw ok? */
1310 dev_tab[dev] (dev, IO_WH, opnd); /* send data */
1311 else { /* byte only */
1312 dev_tab[dev] (dev, IO_WD, opnd >> 8); /* send hi byte */
1313 dev_tab[dev] (dev, IO_WD, opnd & DMASK8); /* send lo byte */
1314 }
1315 int_eval (); /* re-eval intr */
1316 cc = 0;
1317 }
1318 else cc = CC_V;
1319 break;
1320
1321 case 0x9B: /* RDR - RR */
1322 case 0xDB: /* RD - RX */
1323 dev = R[r1] & DEV_MAX;
1324 if (DEV_ACC (dev)) { /* dev exist? */
1325 dev_tab[dev] (dev, IO_ADR, 0); /* select */
1326 t = dev_tab[dev] (dev, IO_RD, 0); /* get data */
1327 cc = 0;
1328 }
1329 else { /* no */
1330 t = 0; /* read zero */
1331 cc = CC_V; /* set V */
1332 }
1333 if (OP_TYPE (op) != OP_RR) WriteB (ea, t); /* RX or RR? */
1334 else R[r2] = t & DMASK8;
1335 int_eval (); /* re-eval intr */
1336 break;
1337
1338 case 0x99: /* RHR - RR */
1339 case 0xD9: /* RH - RX */
1340 dev = R[r1] & DEV_MAX;
1341 if (DEV_ACC (dev)) { /* dev exist? */
1342 if (dev_tab[dev] (dev, IO_ADR, 0)) /* select, hw ok? */
1343 t = dev_tab[dev] (dev, IO_RH, 0); /* get data */
1344 else { /* byte only */
1345 rslt = dev_tab[dev] (dev, IO_RD, 0); /* get byte */
1346 t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */
1347 t = (rslt << 8) | t; /* merge */
1348 }
1349 cc = 0;
1350 }
1351 else { /* no */
1352 t = 0; /* read zero */
1353 cc = CC_V; /* set V */
1354 }
1355 if (OP_TYPE (op) != OP_RR) WriteH (ea, t); /* RX or RR? */
1356 else R[r2] = t;
1357 int_eval (); /* re-eval intr */
1358 break;
1359
1360 case 0x9F: /* AIR - RR */
1361 case 0xDF: /* AI - RX */
1362 R[r1] = int_getdev (); /* get int dev */
1363 /* fall through */
1364 case 0x9D: /* SSR - RR */
1365 case 0xDD: /* SS - RX */
1366 dev = R[r1] & DEV_MAX;
1367 if (DEV_ACC (dev)) { /* dev exist? */
1368 dev_tab[dev] (dev, IO_ADR, 0); /* select */
1369 t = dev_tab[dev] (dev, IO_SS, 0); /* get status */
1370 }
1371 else t = STA_EX; /* no */
1372 if (OP_TYPE (op) != OP_RR) WriteB (ea, t); /* RR or RX? */
1373 else R[r2] = t & DMASK8;
1374 cc = t & 0xF;
1375 int_eval (); /* re-eval intr */
1376 break;
1377
1378 /* Block I/O instructions
1379
1380 On a real Interdata system, the block I/O instructions can't be
1381 interrupted or stopped. To model this behavior, while allowing
1382 the instructions to go back through fetch for I/O processing and
1383 WRU testing, the simulator implements a 'block I/O in progress'
1384 flag and status block. If a block I/O is in progress, normal
1385 interrupts and fetches are suppressed until the block I/O is done.
1386 */
1387
1388 case 0x96: /* WBR - RR */
1389 case 0xD6: /* WB - RXH */
1390 dev = R[r1] & DEV_MAX;
1391 if (DEV_ACC (dev)) { /* dev exist? */
1392 if (OP_TYPE (op) != OP_RR)
1393 lim = ReadH ((ea + 2) & VAMASK);
1394 else lim = R[(r2 + 1) & 0xF];
1395 if (opnd > lim) cc = 0; /* start > end? */
1396 else { /* no, start I/O */
1397 dev_tab[dev] (dev, IO_ADR, 0); /* select dev */
1398 blk_io.dfl = dev; /* set status block */
1399 blk_io.cur = opnd;
1400 blk_io.end = lim;
1401 qevent = qevent | EV_BLK; /* I/O in prog */
1402 }
1403 }
1404 else cc = CC_V; /* nx dev */
1405 break;
1406
1407 case 0x97: /* RBR - RR */
1408 case 0xD7: /* RB - RXH */
1409 dev = R[r1] & DEV_MAX;
1410 if (DEV_ACC (dev)) { /* dev exist? */
1411 if (OP_TYPE (op) != OP_RR)
1412 lim = ReadH ((ea + 2) & VAMASK);
1413 else lim = R[(r2 + 1) & 0xF];
1414 if (opnd > lim) cc = 0; /* start > end? */
1415 else { /* no, start I/O */
1416 dev_tab[dev] (dev, IO_ADR, 0); /* select dev */
1417 blk_io.dfl = dev | BL_RD; /* set status block */
1418 blk_io.cur = opnd;
1419 blk_io.end = lim;
1420 qevent = qevent | EV_BLK; /* I/O in prog */
1421 }
1422 }
1423 else cc = CC_V; /* nx dev */
1424 break;
1425
1426 case 0xD5: /* AL - RX */
1427 dev = ReadB (AL_DEV); /* get device */
1428 t = ReadB (AL_IOC); /* get command */
1429 if (DEV_ACC (dev)) { /* dev exist? */
1430 if (AL_BUF > ea) cc = 0; /* start > end? */
1431 else { /* no, start I/O */
1432 dev_tab[dev] (dev, IO_ADR, 0); /* select dev */
1433 dev_tab[dev] (dev, IO_OC, t); /* start dev */
1434 blk_io.dfl = dev | BL_RD | BL_LZ; /* set status block */
1435 blk_io.cur = AL_BUF;
1436 blk_io.end = ea;
1437 qevent = qevent | EV_BLK; /* I/O in prog */
1438 }
1439 }
1440 else cc = CC_V; /* nx dev */
1441 break;
1442 } /* end switch */
1443 } /* end while */
1444
1445 /* Simulation halted */
1446
1447 PSW = BUILD_PSW (cc);
1448 PC = PC & VAMASK;
1449 pcq_r->qptr = pcq_p; /* update pc q ptr */
1450 return reason;
1451 }
1452
1453 /* Load new PSW and memory map */
1454
1455 uint32 newPSW (uint32 val)
1456 {
1457 PSW = val & psw_mask; /* store PSW */
1458 int_eval (); /* update intreq */
1459 if (PSW & PSW_WAIT) qevent = qevent | EV_WAIT; /* wait state? */
1460 else qevent = qevent & ~EV_WAIT;
1461 if (cpu_unit.flags & UNIT_816E) { /* mapping enabled? */
1462 uint32 map = PSW_GETMAP (PSW); /* get new map */
1463 s0_rel = s0_rel_const[map]; /* set relocation */
1464 s1_rel = s1_rel_const[map]; /* constants */
1465 }
1466 else s0_rel = s1_rel = 0; /* no relocation */
1467 if (PSW & PSW_AIO) SET_ENB (v_DS); /* PSW<4> controls */
1468 else CLR_ENB (v_DS); /* DS interrupts */
1469 return PSW & CC_MASK;
1470 }
1471
1472 /* Swap PSW */
1473
1474 uint32 swap_psw (uint32 loc, uint32 cc)
1475 {
1476 WriteH (loc, BUILD_PSW (cc)); /* write PSW, PC */
1477 WriteH (loc + 2, PC);
1478 cc = newPSW (ReadH (loc + 4)); /* read PSW, PC */
1479 PC = ReadH (loc + 6);
1480 if (PSW & PSW_SQI) cc = testsysq (cc); /* sys q int enb? */
1481 return cc; /* return CC */
1482 }
1483
1484 /* Test for queue interrupts */
1485
1486 uint32 testsysq (uint32 cc)
1487 {
1488 int32 qb = ReadH (SQP); /* get sys q addr */
1489 int32 usd = ReadB (qb + Q16_USD); /* get use count */
1490
1491 if (usd) { /* any entries? */
1492 WriteH (SQIPSW, BUILD_PSW (cc)); /* swap PSW */
1493 WriteH (SQIPSW + 2, PC);
1494 cc = newPSW (ReadH (SQIPSW + 4));
1495 PC = ReadH (SQIPSW + 6);
1496 }
1497 return cc;
1498 }
1499
1500 /* Add to head of queue */
1501
1502 uint32 addtoq (uint32 ea, uint32 val, uint32 flg)
1503 {
1504 uint32 slt, usd, wra, t;
1505
1506 t = ReadH (ea); /* slots/used */
1507 slt = (t >> 8) & DMASK8; /* # slots */
1508 usd = t & DMASK8; /* # used */
1509 if (usd >= slt) return CC_V; /* list full? */
1510 usd = usd + 1; /* inc # used */
1511 WriteB (ea + Q16_USD, usd); /* rewrite */
1512 if (flg) { /* ABL? */
1513 wra = ReadB ((ea + Q16_BOT) & VAMASK); /* get bottom */
1514 t = wra + 1; /* adv bottom */
1515 if (t >= slt) t = 0; /* wrap if necc */
1516 WriteB ((ea + Q16_BOT) & VAMASK, t); /* rewrite bottom */
1517 }
1518 else { /* ATL */
1519 wra = ReadB ((ea + Q16_TOP) & VAMASK); /* get top */
1520 if (wra == 0) wra = (slt - 1) & DMASK8; /* wrap if necc */
1521 else wra = wra - 1; /* dec top */
1522 WriteB ((ea + Q16_TOP) & VAMASK, wra); /* rewrite top */
1523 }
1524 WriteH ((ea + Q16_BASE + (wra * Q16_SLNT)) & VAMASK, val); /* write slot */
1525 return 0;
1526 }
1527
1528 uint32 remfmq (uint32 ea, uint32 r1, uint32 flg)
1529 {
1530 uint32 slt, usd, rda, t;
1531
1532 t = ReadH (ea); /* get slots/used */
1533 slt = (t >> 8) & DMASK8; /* # slots */
1534 usd = t & DMASK8; /* # used */
1535 if (usd == 0) return CC_V; /* empty? */
1536 usd = usd - 1; /* dec used */
1537 WriteB (ea + Q16_USD, usd); /* rewrite */
1538 if (flg) { /* RBL? */
1539 rda = ReadB ((ea + Q16_BOT) & VAMASK); /* get bottom */
1540 if (rda == 0) rda = (slt - 1) & DMASK8; /* wrap if necc */
1541 else rda = rda - 1; /* dec bottom */
1542 WriteB ((ea + Q16_BOT) & VAMASK, rda); /* rewrite bottom */
1543 }
1544 else {
1545 rda = ReadB ((ea + Q16_TOP) & VAMASK); /* RTL, get top */
1546 t = rda + 1; /* adv top */
1547 if (t >= slt) t = 0; /* wrap if necc */
1548 WriteB ((ea + Q16_TOP) & VAMASK, t); /* rewrite top */
1549 }
1550 R[r1] = ReadH ((ea + Q16_BASE + (rda * Q16_SLNT)) & VAMASK); /* read slot */
1551 if (usd) return CC_G; /* set cc's */
1552 else return 0;
1553 }
1554
1555 /* Automatic interrupt processing */
1556
1557 #define CCW16_ERR(x) (((x)|CCW16_INIT|CCW16_NOP|CCW16_Q) & \
1558 ~(CCW16_CHN|CCW16_CON|CCW16_HI))
1559
1560 uint32 int_auto (uint32 dev, uint32 cc)
1561 {
1562 int32 ba, ea, by, vec, ccw, bpi, fnc, trm, st, i, t;
1563 t_bool sysqe = FALSE;
1564 t_bool rpt = FALSE;
1565
1566 do {
1567 vec = ReadH (INTSVT + dev + dev); /* get vector */
1568 if ((vec & 1) == 0) { /* immed int? */
1569 WriteH (vec, BUILD_PSW (cc)); /* write PSW, PC */
1570 WriteH ((vec + 2) & VAMASK, PC);
1571 cc = newPSW (ReadH ((vec + 4) & VAMASK)); /* read PSW */
1572 PC = (vec + 6) & VAMASK; /* set new PC */
1573 return cc;
1574 }
1575 vec = vec & ~1; /* get CCW addr */
1576 ccw = ReadH (vec); /* read CCW */
1577 if (DEV_ACC (dev)) dev_tab[dev] (dev, IO_ADR, 0); /* select dev */
1578 if (ccw & CCW16_NOP) break; /* NOP? exit */
1579 if (ccw & CCW16_INIT) { /* init set? */
1580 ccw = ccw & ~CCW16_INIT; /* clr init */
1581 WriteH (vec, ccw); /* rewrite */
1582 if (ccw & CCW16_OC) { /* OC set? */
1583 if (DEV_ACC (dev)) { /* dev exist? */
1584 by = ReadB ((vec + CCB16_IOC) & VAMASK);/* read OC byte */
1585 dev_tab[dev] (dev, IO_OC, by); /* send to dev */
1586 }
1587 break; /* and exit */
1588 }
1589 }
1590 fnc = CCW16_FNC (ccw); /* get func */
1591 st = 0; /* default status */
1592 if (fnc == CCW16_DMT) { /* DMT */
1593 ba = ReadH ((vec + CCB16_STR) & VAMASK); /* get cnt wd */
1594 ba = (ba - 1) & DMASK16; /* decr */
1595 WriteH ((vec + CCB16_STR) & VAMASK, ba); /* rewrite */
1596 if (ba) break; /* nz? exit */
1597 } /* end if dmt */
1598 else if (fnc != CCW16_NUL) { /* rd or wr? */
1599 if (DEV_ACC (dev)) /* dev exist? */
1600 st = dev_tab[dev] (dev, IO_SS, 0); /* sense status */
1601 else st = CC_V; /* else timeout */
1602 if (st & 0xF) { /* error? */
1603 ccw = CCW16_ERR (ccw); /* neuter CCW */
1604 WriteH (vec, ccw); /* rewrite CCW */
1605 }
1606 else { /* ok, do xfer */
1607 bpi = CCW16_BPI (ccw); /* get bytes/int */
1608 if (bpi == 0) bpi = 16; /* max 16B */
1609 ba = ReadH ((vec + CCB16_STR) & VAMASK); /* get start */
1610 for (i = 0; i < bpi; i++) { /* do # bytes */
1611 if (fnc == CCW16_RD) { /* chan read? */
1612 by = dev_tab[dev] (dev, IO_RD, 0); /* read byte */
1613 WriteB (ba, by); /* store */
1614 }
1615 else { /* chan write */
1616 by = ReadB (ba); /* fetch */
1617 dev_tab[dev] (dev, IO_WD, by); /* write byte */
1618 }
1619 ba = (ba + 1) & VAMASK; /* incr addr */
1620 }
1621 WriteH ((vec + CCB16_STR) & VAMASK, ba); /* rewrite */
1622 ea = ReadH ((vec + CCB16_END) & VAMASK); /* get end */
1623 trm = ReadB ((vec + CCB16_TRM) & VAMASK); /* get term chr */
1624 if ((ba <= ea) && /* not at end? */
1625 (((ccw & CCW16_TRM) == 0) || /* not term chr? */
1626 (by != trm))) break; /* exit */
1627 ccw = ccw | CCW16_NOP; /* nop CCW */
1628 WriteH (vec, ccw); /* rewrite CCW */
1629 } /* end else sta */
1630 } /* end if r/w */
1631
1632 /* Termination phase */
1633
1634 t = (dev << 8) | (st & DMASK8); /* form dev/sta */
1635 WriteH ((vec + CCB16_DEV) & VAMASK, t); /* write dev/sta */
1636 if (ccw & CCW16_Q) { /* q request? */
1637 t = ReadH (SQP); /* get sys q addr */
1638 if (addtoq (t, vec, ccw & CCW16_HI)) { /* add to sys q */
1639 WriteH (SQOP, vec); /* write to ovflo */
1640 return swap_psw (SQVPSW, cc); /* take exception */
1641 }
1642 else sysqe = TRUE; /* made an entry */
1643 }
1644 if (ccw & CCW16_CHN) { /* chain */
1645 t = ReadH ((vec + CCB16_CHN) & VAMASK); /* get chain wd */
1646 WriteH (INTSVT + dev + dev, t); /* wr int svc tab */
1647 if (ccw & CCW16_CON) rpt = TRUE; /* cont? */
1648 }
1649 } while (rpt);
1650
1651 /* Common exit */
1652
1653 if (sysqe && (PSW & PSW_SQI)) /* sys q ent & enb? */
1654 return swap_psw (SQIPSW, cc); /* take sys q int */
1655 return cc;
1656 }
1657
1658 /* Display register device */
1659
1660 uint32 display (uint32 dev, uint32 op, uint32 dat)
1661 {
1662 int t;
1663
1664 switch (op) {
1665
1666 case IO_ADR: /* select */
1667 if (!drmod) drpos = srpos = 0; /* norm mode? clr */
1668 return BY; /* byte only */
1669
1670 case IO_OC: /* command */
1671 op = op & 0xC0;
1672 if (op == 0x40) { /* x40 = inc */
1673 drmod = 1;
1674 drpos = srpos = 0; /* init cntrs */
1675 }
1676 else if (op == 0x80) drmod = 0; /* x80 = norm */
1677 break;
1678
1679 case IO_WD: /* write */
1680 if (drpos < 4)
1681 DR = (DR & ~(DMASK8 << (drpos * 8))) | (dat << (drpos * 8));
1682 else if (drpos == 4) DRX = dat;
1683 drpos = (drpos + 1) &
1684 ((cpu_unit.flags & (UNIT_716 | UNIT_816))? 7: 3);
1685 break;
1686
1687 case IO_RD: /* read */
1688 t = (SR >> (srpos * 8)) & DMASK8;
1689 srpos = srpos ^ 1;
1690 return t;
1691
1692 case IO_SS: /* status */
1693 return 0x80;
1694 }
1695
1696 return 0;
1697 }
1698
1699 /* Memory interface routines
1700
1701 ReadB read byte (processor)
1702 ReadH read halfword (processor)
1703 ReadF read fullword (processor)
1704 WriteB write byte (processor)
1705 WriteH write halfword (processor)
1706 WriteF write fullword (processor)
1707 IOReadB read byte (IO)
1708 IOWriteB write byte (IO)
1709 IOReadH read halfword (IO)
1710 IOWriteH write halfword (IO)
1711 */
1712
1713 uint32 ReadB (uint32 loc)
1714 {
1715 uint32 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1716
1717 return ((M[pa >> 1] >> ((pa & 1)? 0: 8)) & DMASK8);
1718 }
1719
1720 uint32 ReadH (uint32 loc)
1721 {
1722 uint32 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1723
1724 return M[pa >> 1];
1725 }
1726
1727 uint32 ReadF (uint32 loc, uint32 rel)
1728 {
1729 uint32 pa, pa1;
1730 uint32 loc1 = (loc + 2) & VAMASK;
1731
1732 loc = loc & VAMASK; /* FP doesn't mask */
1733 if (rel) {
1734 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1735 pa1 = (loc1 + ((loc1 & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1736 }
1737 else {
1738 pa = loc;
1739 pa1 = loc1;
1740 }
1741 return (((uint32) M[pa >> 1]) << 16) | ((uint32) M[pa1 >> 1]);
1742 }
1743
1744 void WriteB (uint32 loc, uint32 val)
1745 {
1746 uint32 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1747
1748 val = val & DMASK8;
1749 if (MEM_ADDR_OK (pa)) M[pa >> 1] = ((pa & 1)?
1750 ((M[pa >> 1] & ~DMASK8) | val):
1751 ((M[pa >> 1] & DMASK8) | (val << 8)));
1752 return;
1753 }
1754
1755 void WriteH (uint32 loc, uint32 val)
1756 {
1757 uint32 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1758
1759 if (MEM_ADDR_OK (pa)) M[pa >> 1] = val & DMASK16;
1760 return;
1761 }
1762
1763 void WriteF (uint32 loc, uint32 val, uint32 rel)
1764 {
1765 uint32 pa, pa1;
1766 uint32 loc1 = (loc + 2) & VAMASK;
1767
1768 loc = loc & VAMASK; /* FP doesn't mask */
1769 if (rel) {
1770 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1771 pa1 = (loc1 + ((loc1 & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1772 }
1773 else {
1774 pa = loc;
1775 pa1 = loc1;
1776 }
1777 if (MEM_ADDR_OK (pa)) M[pa >> 1] = (val >> 16) & DMASK16;
1778 if (MEM_ADDR_OK (pa1)) M[pa1 >> 1] = val & DMASK16;
1779 return;
1780 }
1781
1782 uint32 IOReadB (uint32 loc)
1783 {
1784 return ((M[loc >> 1] >> ((loc & 1)? 0: 8)) & DMASK8);
1785 }
1786
1787 void IOWriteB (uint32 loc, uint32 val)
1788 {
1789 val = val & DMASK8;
1790 M[loc >> 1] = ((loc & 1)?
1791 ((M[loc >> 1] & ~DMASK8) | val):
1792 ((M[loc >> 1] & DMASK8) | (val << 8)));
1793 return;
1794 }
1795
1796 uint32 IOReadH (uint32 loc)
1797 {
1798 return (M[loc >> 1] & DMASK16);
1799 }
1800
1801 void IOWriteH (uint32 loc, uint32 val)
1802 {
1803 M[loc >> 1] = val & DMASK16;
1804 return;
1805 }
1806
1807 /* Reset routine */
1808
1809 t_stat cpu_reset (DEVICE *dptr)
1810 {
1811 qevent = 0; /* no events */
1812 newPSW (0); /* PSW = 0 */
1813 DR = 0; /* clr display */
1814 drmod = 0;
1815 blk_io.dfl = blk_io.cur = blk_io.end = 0; /* no block IO */
1816 sim_brk_types = sim_brk_dflt = SWMASK ('E'); /* init bkpts */
1817 if (M == NULL) M = (uint16 *) calloc (MAXMEMSIZE16E >> 1, sizeof (uint16));
1818 if (M == NULL) return SCPE_MEM;
1819 pcq_r = find_reg ("PCQ", NULL, dptr); /* init PCQ */
1820 if (pcq_r) pcq_r->qptr = 0;
1821 else return SCPE_IERR;
1822 return SCPE_OK;
1823 }
1824
1825 /* Memory examine */
1826
1827 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
1828 {
1829 if (sw & SWMASK ('V')) {
1830 if (addr > VAMASK) return SCPE_NXM;
1831 addr = (addr + ((addr & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1832 }
1833 if (addr >= MEMSIZE) return SCPE_NXM;
1834 if (vptr != NULL) *vptr = IOReadH (addr);
1835 return SCPE_OK;
1836 }
1837
1838 /* Memory deposit */
1839
1840 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
1841 {
1842 if (sw & SWMASK ('V')) {
1843 if (addr > VAMASK) return SCPE_NXM;
1844 addr = (addr + ((addr & VA_S1)? s1_rel: s0_rel)) & PAMASK16E;
1845 }
1846 if (addr >= MEMSIZE) return SCPE_NXM;
1847 IOWriteH (addr, val);
1848 return SCPE_OK;
1849 }
1850
1851 /* Change memory size */
1852
1853 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
1854 {
1855 int32 mc = 0;
1856 uint32 i;
1857
1858 if ((val <= 0) || ((val & 0xFFF) != 0) ||
1859 (((uint32) val) > ((uptr->flags & UNIT_816E)? MAXMEMSIZE16E: MAXMEMSIZE16)))
1860 return SCPE_ARG;
1861 for (i = val; i < MEMSIZE; i = i + 2) mc = mc | M[i >> 1];
1862 if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
1863 return SCPE_OK;
1864 MEMSIZE = val;
1865 for (i = MEMSIZE; i < MAXMEMSIZE16E; i = i + 2) M[i >> 1] = 0;
1866 return SCPE_OK;
1867 }
1868
1869 /* Change CPU model */
1870
1871 t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc)
1872 {
1873 uint32 i;
1874
1875 if (!(val & UNIT_816E) && (MEMSIZE > MAXMEMSIZE16)) {
1876 MEMSIZE = MAXMEMSIZE16;
1877 for (i = MEMSIZE; i < MAXMEMSIZE16E; i = i + 2) M[i >> 1] = 0;
1878 printf ("Reducing memory to 64KB\n");
1879 }
1880 return SCPE_OK;
1881 }
1882
1883 /* Set console interrupt */
1884
1885 t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc)
1886 {
1887 if ((uptr->flags & (UNIT_716 | UNIT_816 | UNIT_816E)) == 0)
1888 return SCPE_NOFNC;
1889 if (PSW & PSW_AIO) SET_INT (v_DS);
1890 return SCPE_OK;
1891 }
1892
1893 /* Set history */
1894
1895 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
1896 {
1897 uint32 i, lnt;
1898 t_stat r;
1899
1900 if (cptr == NULL) {
1901 for (i = 0; i < hst_lnt; i++) hst[i].vld = 0;
1902 hst_p = 0;
1903 return SCPE_OK;
1904 }
1905 lnt = (uint32) get_uint (cptr, 10, HIST_MAX, &r);
1906 if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
1907 hst_p = 0;
1908 if (hst_lnt) {
1909 free (hst);
1910 hst_lnt = 0;
1911 hst = NULL;
1912 }
1913 if (lnt) {
1914 hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));
1915 if (hst == NULL) return SCPE_MEM;
1916 hst_lnt = lnt;
1917 }
1918 return SCPE_OK;
1919 }
1920
1921 /* Show history */
1922
1923 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
1924 {
1925 int32 op, k, di, lnt;
1926 char *cptr = (char *) desc;
1927 t_value sim_eval[2];
1928 t_stat r;
1929 InstHistory *h;
1930 extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
1931 UNIT *uptr, int32 sw);
1932
1933 if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
1934 if (cptr) {
1935 lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
1936 if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG;
1937 }
1938 else lnt = hst_lnt;
1939 di = hst_p - lnt; /* work forward */
1940 if (di < 0) di = di + hst_lnt;
1941 fprintf (st, "PC r1 opnd ea IR\n\n");
1942 for (k = 0; k < lnt; k++) { /* print specified */
1943 h = &hst[(di++) % hst_lnt]; /* entry pointer */
1944 if (h->vld) { /* instruction? */
1945 fprintf (st, "%04X %04X %04X ", h->pc, h->r1, h->opnd);
1946 op = (h->ir1 >> 8) & 0xFF;
1947 if (OP_TYPE (op) >= OP_RX) fprintf (st, "%04X ", h->ea);
1948 else fprintf (st, " ");
1949 sim_eval[0] = h->ir1;
1950 sim_eval[1] = h->ir2;
1951 if ((fprint_sym (st, h->pc, sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
1952 fprintf (st, "(undefined) %04X", h->ir1);
1953 fputc ('\n', st); /* end line */
1954 } /* end if instruction */
1955 } /* end for */
1956 return SCPE_OK;
1957 }