1 /* h316_cpu.c: Honeywell 316/516 CPU simulator
2
3 Copyright (c) 1999-2011, 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 H316/H516 CPU
27
28 19-Nov-11 RMS Fixed XR behavior (Adrian Wise)
29 19-Nov-11 RMS Fixed bugs in double precision, normalization, SC (Adrian Wise)
30 10-Jan-10 RMS Fixed bugs in LDX, STX introduced in 3.8-1 (Theo Engel)
31 28-Apr-07 RMS Removed clock initialization
32 03-Apr-06 RMS Fixed bugs in LLL, LRL (Theo Engel)
33 22-Sep-05 RMS Fixed declarations (Sterling Garwood)
34 16-Aug-05 RMS Fixed C++ declaration and cast problems
35 15-Feb-05 RMS Added start button interrupt
36 01-Dec-04 RMS Fixed bug in DIV
37 06-Nov-04 RMS Added =n to SHOW HISTORY
38 04-Jan-04 RMS Removed unnecessary compare
39 31-Dec-03 RMS Fixed bug in cpu_set_hist
40 24-Oct-03 RMS Added DMA/DMC support, instruction history
41 30-Dec-01 RMS Added old PC queue
42 03-Nov-01 RMS Fixed NOHSA modifier
43 30-Nov-01 RMS Added extended SET/SHOW support
44
45 The register state for the Honeywell 316/516 CPU is:
46
47 AR<1:16> A register
48 BR<1:16> B register
49 XR<1:16> X register
50 PC<1:16> P register (program counter)
51 Y<1:16> memory address register
52 MB<1:16> memory data register
53 C overflow flag
54 EXT extend mode flag
55 DP double precision mode flag
56 SC<1:6> shift count
57 SR[1:4]<0> sense switches 1-4
58
59 The Honeywell 316/516 has six instruction formats: memory reference,
60 I/O, control, shift, skip, and operate.
61
62 The memory reference format is:
63
64 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
65 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
66 |in|xr| op |sc| offset | memory reference
67 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
68
69 <13:10> mnemonic action
70
71 0000 (other) see control, shift, skip, operate instructions
72 0001 JMP P = MA
73 0010 LDA A = M[MA]
74 0011 ANA A = A & M[MA]
75 0100 STA M[MA] = A
76 0101 ERA A = A ^ M[MA]
77 0110 ADD A = A + M[MA]
78 0111 SUB A = A - M[MA]
79 1000 JST M[MA] = P, P = MA + 1
80 1001 CAS skip if A == M[MA], double skip if A < M[MA]
81 1010 IRS M[MA] = M[MA] + 1, skip if M[MA] == 0
82 1011 IMA A <=> M[MA]
83 1100 (I/O) see I/O instructions
84 1101 LDX/STX X = M[MA] (xr = 1), M[MA] = x (xr = 0)
85 1110 MPY multiply
86 1111 DIV divide
87
88 In non-extend mode, memory reference instructions can access an address
89 space of 16K words. Multiple levels of indirection are supported, and
90 each indirect word supplies its own indirect and index bits.
91
92 <1,2,7> mode action
93
94 0,0,0 sector zero direct MA = IR<8:0>
95 0,0,1 current direct MA = P<13:9>'IR<8:0>
96 0,1,0 sector zero indexed MA = IR<8:0> + X
97 0,1,1 current direct MA = P<13:9>'IR<8:0> + X
98 1,0,0 sector zero indirect MA = M[IR<8:0>]
99 1,0,1 current indirect MA = M[P<13:9>'IR<8:0>]
100 1,1,0 sector zero indirect indexed MA = M[IR<8:0> + X]
101 1,1,1 current indirect indexed MA = M[MA = P<13:9>'IR<8:0> + X]
102
103 In extend mode, memory reference instructions can access an address
104 space of 32K words. Multiple levels of indirection are supported, but
105 only post-indexing, based on the original instruction word index flag,
106 is allowed.
107
108 The control format is:
109
110 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
111 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
112 | 0 0 0 0 0 0| opcode | control
113 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
114
115 The shift format is:
116
117 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
118 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
119 | 0 1 0 0 0 0|dr|sz|type | shift count | shift
120 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
121 | | \-+-/
122 | | |
123 | | +--------------------- type
124 | +------------------------- long/A only
125 +---------------------------- right/left
126
127 The skip format is:
128
129 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
130 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
131 | 1 0 0 0 0 0|rv|po|pe|ev|ze|s1|s2|s3|s4|cz| skip
132 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
133 | | | | | | | | | |
134 | | | | | | | | | +- skip if C = 0
135 | | | | | | | | +---- skip if ssw 4 = 0
136 | | | | | | | +------- skip if ssw 3 = 0
137 | | | | | | +---------- skip if ssw 2 = 0
138 | | | | | +------------- skip if ssw 1 = 0
139 | | | | +---------------- skip if A == 0
140 | | | +------------------- skip if A<0> == 0
141 | | +---------------------- skip if mem par err
142 | +------------------------- skip if A<15> = 0
143 +---------------------------- reverse skip sense
144
145 The operate format is:
146
147 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
148 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
149 | 1 1 0 0 0 0| opcode | operate
150 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
151
152 The I/O format is:
153
154 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
155 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
156 | op | 1 1 0 0| function | device | I/O transfer
157 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
158
159 The IO transfer instruction controls the specified device.
160 Depending on the opcode, the instruction may set or clear
161 the device flag, start or stop I/O, or read or write data.
162
163 This routine is the instruction decode routine for the Honeywell
164 316/516. It is called from the simulator control program to execute
165 instructions in simulated memory, starting at the simulated PC.
166 It runs until 'reason' is set non-zero.
167
168 General notes:
169
170 1. Reasons to stop. The simulator can be stopped by:
171
172 HALT instruction
173 breakpoint encountered
174 infinite indirection loop
175 unimplemented instruction and stop_inst flag set
176 unknown I/O device and stop_dev flag set
177 I/O error in I/O simulator
178
179 2. Interrupts. Interrupts are maintained by two parallel variables:
180
181 dev_int device interrupt flags
182 dev_enb device interrupt enable flags
183
184 In addition, dev_int contains the interrupt enable and interrupt no
185 defer flags. If interrupt enable and interrupt no defer are set, and
186 at least one interrupt request is pending, then an interrupt occurs.
187 The order of flags in these variables corresponds to the order
188 in the SMK instruction.
189
190 3. Non-existent memory. On the H316/516, reads to non-existent memory
191 return zero, and writes are ignored. In the simulator, the
192 largest possible memory is instantiated and initialized to zero.
193 Thus, only writes need be checked against actual memory size.
194
195 4. Adding I/O devices. These modules must be modified:
196
197 h316_defs.h add interrupt request definition
198 h316_cpu.c add device dispatch table entry
199 h316_sys.c add sim_devices table entry
200
201 Notes on the behavior of XR:
202
203 - XR is "shadowed" by memory location 0 as seen by the program currently
204 executing. Thus, in extend mode, this is always absolute location 0.
205 However, if extend mode is off, this is location 0, if the program is
206 executing in the lower bank, or location 040000, if the program is
207 executing in the upper bank. Writing XR writes the shadowed memory
208 location, and vice versa.
209 - However, the front panel console always equates XR to absolute location
210 0, regardless of extend mode. There is no direct examine or deposit
211 to XR; the user must examine or deposit location 0.
212 */
213
214 #include "h316_defs.h"
215
216 #define PCQ_SIZE 64 /* must be 2**n */
217 #define PCQ_MASK (PCQ_SIZE - 1)
218 #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
219 #define PCQ_TOP pcq[pcq_p]
220 #define m7 0001000 /* for generics */
221 #define m8 0000400
222 #define m9 0000200
223 #define m10 0000100
224 #define m11 0000040
225 #define m12 0000020
226 #define m13 0000010
227 #define m14 0000004
228 #define m15 0000002
229 #define m16 0000001
230
231 #define HIST_PC 0x40000000
232 #define HIST_C 0x20000000
233 #define HIST_EA 0x10000000
234 #define HIST_MIN 64
235 #define HIST_MAX 65536
236
237 typedef struct {
238 int32 pc;
239 int32 ir;
240 int32 ar;
241 int32 br;
242 int32 xr;
243 int32 ea;
244 int32 opnd;
245 } InstHistory;
246
247 uint16 M[MAXMEMSIZE] = { 0 }; /* memory */
248 int32 saved_AR = 0; /* A register */
249 int32 saved_BR = 0; /* B register */
250 int32 saved_XR = 0; /* X register */
251 int32 XR = 0; /* live copy - must be global */
252 int32 PC = 0; /* P register */
253 int32 C = 0; /* C register */
254 int32 ext = 0; /* extend mode */
255 int32 pme = 0; /* prev mode extend */
256 int32 extoff_pending = 0; /* extend off pending */
257 int32 dp = 0; /* double mode */
258 int32 sc = 0; /* shift count */
259 int32 ss[4]; /* sense switches */
260 int32 dev_int = 0; /* dev ready */
261 int32 dev_enb = 0; /* dev enable */
262 int32 ind_max = 8; /* iadr nest limit */
263 int32 stop_inst = 1; /* stop on ill inst */
264 int32 stop_dev = 2; /* stop on ill dev */
265 uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
266 int32 pcq_p = 0; /* PC queue ptr */
267 REG *pcq_r = NULL; /* PC queue reg ptr */
268 uint32 dma_nch = DMA_MAX; /* number of chan */
269 uint32 dma_ad[DMA_MAX] = { 0 }; /* DMA addresses */
270 uint32 dma_wc[DMA_MAX] = { 0 }; /* DMA word count */
271 uint32 dma_eor[DMA_MAX] = { 0 }; /* DMA end of range */
272 uint32 chan_req = 0; /* channel requests */
273 uint32 chan_map[DMA_MAX + DMC_MAX] = { 0 }; /* chan->dev map */
274 int32 (*iotab[DEV_MAX])(int32 inst, int32 fnc, int32 dat, int32 dev) = { NULL };
275 int32 hst_p = 0; /* history pointer */
276 int32 hst_lnt = 0; /* history length */
277 InstHistory *hst = NULL; /* instruction history */
278
279 extern int32 sim_int_char;
280 extern int32 sim_interval;
281 extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
282 extern FILE *sim_log;
283 extern DEVICE *sim_devices[];
284
285 t_bool devtab_init (void);
286 int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev);
287 int32 undio (int32 inst, int32 fnc, int32 dat, int32 dev);
288 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
289 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
290 t_stat cpu_reset (DEVICE *dptr);
291 t_stat cpu_set_noext (UNIT *uptr, int32 val, char *cptr, void *desc);
292 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
293 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
294 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
295 t_stat cpu_show_dma (FILE *st, UNIT *uptr, int32 val, void *desc);
296 t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc);
297 t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc);
298
299 extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
300 UNIT *uptr, int32 sw);
301
302 /* CPU data structures
303
304 cpu_dev CPU device descriptor
305 cpu_unit CPU unit descriptor
306 cpu_reg CPU register list
307 cpu_mod CPU modifiers list
308 */
309
310 DIB cpu_dib = { DMA, IOBUS, 1, &dmaio };
311
312 UNIT cpu_unit = {
313 UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_EXT+UNIT_HSA+UNIT_DMC, MAXMEMSIZE)
314 };
315
316 REG cpu_reg[] = {
317 { ORDATA (P, PC, 15) },
318 { ORDATA (A, saved_AR, 16) },
319 { ORDATA (B, saved_BR, 16) },
320 { ORDATA (X, saved_XR, 16) },
321 { ORDATA (SC, sc, 16) },
322 { FLDATA (C, C, 0) },
323 { FLDATA (EXT, ext, 0) },
324 { FLDATA (PME, pme, 0) },
325 { FLDATA (EXT_OFF, extoff_pending, 0) },
326 { FLDATA (DP, dp, 0) },
327 { FLDATA (SS1, ss[0], 0) },
328 { FLDATA (SS2, ss[1], 0) },
329 { FLDATA (SS3, ss[2], 0) },
330 { FLDATA (SS4, ss[3], 0) },
331 { FLDATA (ION, dev_int, INT_V_ON) },
332 { FLDATA (INODEF, dev_int, INT_V_NODEF) },
333 { FLDATA (START, dev_int, INT_V_START) },
334 { ORDATA (DEVINT, dev_int, 16), REG_RO },
335 { ORDATA (DEVENB, dev_enb, 16), REG_RO },
336 { ORDATA (CHREQ, chan_req, DMA_MAX + DMC_MAX) },
337 { BRDATA (DMAAD, dma_ad, 8, 16, DMA_MAX) },
338 { BRDATA (DMAWC, dma_wc, 8, 16, DMA_MAX) },
339 { BRDATA (DMAEOR, dma_eor, 8, 1, DMA_MAX) },
340 { ORDATA (DMANCH, dma_nch, 3), REG_HRO },
341 { FLDATA (MPERDY, dev_int, INT_V_MPE) },
342 { FLDATA (MPEENB, dev_enb, INT_V_MPE) },
343 { FLDATA (STOP_INST, stop_inst, 0) },
344 { FLDATA (STOP_DEV, stop_dev, 1) },
345 { DRDATA (INDMAX, ind_max, 8), REG_NZ + PV_LEFT },
346 { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO + REG_CIRC },
347 { ORDATA (PCQP, pcq_p, 6), REG_HRO },
348 { ORDATA (WRU, sim_int_char, 8) },
349 { NULL }
350 };
351
352 MTAB cpu_mod[] = {
353 { UNIT_EXT, 0, "no extend", "NOEXTEND", &cpu_set_noext },
354 { UNIT_EXT, UNIT_EXT, "extend", "EXTEND", NULL },
355 { UNIT_HSA, 0, "no HSA", "NOHSA", NULL },
356 { UNIT_HSA, UNIT_HSA, "HSA", "HSA", NULL },
357 { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
358 { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
359 { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },
360 { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
361 { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
362 { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
363 { MTAB_XTD | MTAB_VDV, 0, "channels", "CHANNELS",
364 &cpu_set_nchan, &cpu_show_nchan, NULL },
365 { UNIT_DMC, 0, "no DMC", "NODMC", NULL },
366 { UNIT_DMC, UNIT_DMC, "DMC", "DMC", NULL },
367 { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
368 &cpu_set_hist, &cpu_show_hist },
369 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DMA1", NULL,
370 NULL, &cpu_show_dma, NULL },
371 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DMA2", NULL,
372 NULL, &cpu_show_dma, NULL },
373 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 2, "DMA3", NULL,
374 NULL, &cpu_show_dma, NULL },
375 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 3, "DMA4", NULL,
376 NULL, &cpu_show_dma, NULL },
377 { 0 }
378 };
379
380 DEVICE cpu_dev = {
381 "CPU", &cpu_unit, cpu_reg, cpu_mod,
382 1, 8, 15, 1, 8, 16,
383 &cpu_ex, &cpu_dep, &cpu_reset,
384 NULL, NULL, NULL,
385 &cpu_dib, 0
386 };
387
sim_instr(void)388 t_stat sim_instr (void)
389 {
390 int32 AR, BR, MB, Y, t1, t2, t3, skip, dev;
391 uint32 ut;
392 t_stat reason;
393 t_stat Ea (int32 inst, int32 *addr);
394 void Write (int32 addr, int32 val);
395 int32 Add16 (int32 val1, int32 val2);
396 int32 Add31 (int32 val1, int32 val2);
397 int32 Operate (int32 MB, int32 AR);
398
399 #define Read(ad) M[(ad)]
400 #define GETDBL_S(h,l) (((h) << 15) | ((l) & MMASK))
401 #define GETDBL_U(h,l) (((h) << 16) | (l))
402 #define PUTDBL_S(x) AR = ((x) >> 15) & DMASK; \
403 BR = (BR & SIGN) | ((x) & MMASK)
404 #define PUTDBL_U(x) AR = ((x) >> 16) & DMASK; \
405 BR = (x) & DMASK
406 #define PUTDBL_Z(x) AR = ((x) >> 15) & DMASK; \
407 BR = (x) & MMASK
408 #define SEXT(x) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK))
409 #define NEWA(c,n) (ext? (((c) & ~X_AMASK) | ((n) & X_AMASK)): \
410 (((c) & ~NX_AMASK) | ((n) & NX_AMASK)))
411
412 /* Restore register state */
413
414 if (devtab_init ()) /* init tables */
415 return SCPE_STOP;
416 AR = saved_AR & DMASK; /* restore reg */
417 BR = saved_BR & DMASK;
418 XR = saved_XR & DMASK;
419 PC = PC & ((cpu_unit.flags & UNIT_EXT)? X_AMASK: NX_AMASK); /* mask PC */
420 reason = 0;
421
422 /* Main instruction fetch/decode loop */
423
424 while (reason == 0) { /* loop until halted */
425
426 if (sim_interval <= 0) { /* check clock queue */
427 if ((reason = sim_process_event ()))
428 break;
429 }
430
431 /* Channel breaks (DMA and DMC) */
432
433 if (chan_req) { /* channel request? */
434 int32 i, t, ch, dev, st, end, ad, dmcad;
435 t_stat r;
436 for (i = 0, ch = chan_req; ch != 0; i++, ch = ch >> 1) {
437 if (ch & 1) { /* req on chan i? */
438 dev = chan_map[i]; /* get dev for chan */
439 if (iotab[dev] == &undio)
440 return SCPE_IERR;
441 chan_req = chan_req & ~(1 << i); /* clear req */
442 if (Q_DMA (i)) /* DMA? */
443 st = dma_ad[i];
444 else { /* DMC */
445 dmcad = DMC_BASE + ((i - DMC_V_DMC1) << 1);
446 st = Read (dmcad); /* DMC ctrl word */
447 }
448 ad = st & X_AMASK; /* get curr addr */
449 if (st & DMA_IN) { /* input? */
450 t = iotab[dev] (ioINA, 0, 0, dev); /* input word */
451 if ((t & IOT_SKIP) == 0)
452 return STOP_DMAER;
453 if ((r = t >> IOT_V_REASON) != 0)
454 return r;
455 Write (ad, t & DMASK); /* write to mem */
456 }
457 else { /* no, output */
458 t = iotab[dev] (ioOTA, 0, Read (ad), dev); /* output word */
459 if ((t & IOT_SKIP) == 0)
460 return STOP_DMAER;
461 if ((r = (t >> IOT_V_REASON)))
462 return r;
463 }
464 if (Q_DMA (i)) { /* DMA? */
465 dma_ad[i] = (dma_ad[i] & DMA_IN) | ((ad + 1) & X_AMASK);
466 dma_wc[i] = (dma_wc[i] + 1) & 077777; /* update wc */
467 if (dma_wc[i] == 0) { /* done? */
468 dma_eor[i] = 1; /* set end of range */
469 t = iotab[dev] (ioEND, 0, 0, dev); /* send end range */
470 if ((r = t >> IOT_V_REASON) != 0)
471 return r;
472 }
473 }
474 else { /* DMC */
475 st = (st & DMA_IN) | ((ad + 1) & X_AMASK);
476 Write (dmcad, st); /* update start */
477 end = Read (dmcad + 1); /* get end */
478 if (((ad ^ end) & X_AMASK) == 0) { /* start == end? */
479 t = iotab[dev] (ioEND, 0, 0, dev); /* send end range */
480 if ((r = t >> IOT_V_REASON) != 0)
481 return r;
482 } /* end if end range */
483 } /* end else DMC */
484 } /* end if chan i */
485 } /* end for */
486 } /* end if chan_req */
487
488
489 /* Interrupts */
490
491 if ((dev_int & (INT_PEND|INT_NMI|dev_enb)) > INT_PEND) {/* int req? */
492 pme = ext; /* save extend */
493 if (cpu_unit.flags & UNIT_EXT) /* ext opt? extend on */
494 ext = 1;
495 dev_int = dev_int & ~INT_ON; /* intr off */
496 MB = 0120000 | M_INT; /* inst = JST* 63 */
497 }
498
499 /* Instruction fetch */
500
501 else {
502 if (sim_brk_summ &&
503 sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
504 reason = STOP_IBKPT; /* stop simulation */
505 break;
506 }
507 Y = PC; /* set mem addr */
508 MB = Read (Y); /* fetch instr */
509 PC = NEWA (Y, Y + 1); /* incr PC */
510 dev_int = dev_int | INT_NODEF;
511 }
512
513 dev_int = dev_int & ~INT_START; /* clr start button int */
514 sim_interval = sim_interval - 1;
515 if (hst_lnt) { /* instr hist? */
516 hst_p = (hst_p + 1); /* next entry */
517 if (hst_p >= hst_lnt)
518 hst_p = 0;
519 hst[hst_p].pc = Y | HIST_PC | (C? HIST_C: 0); /* fill slots */
520 hst[hst_p].ir = MB;
521 hst[hst_p].ar = AR;
522 hst[hst_p].br = BR;
523 hst[hst_p].xr = XR;
524 }
525
526 /* Memory reference instructions */
527
528 switch (I_GETOP (MB)) { /* case on <1:6> */
529
530 case 001: case 021: case 041: case 061: /* JMP */
531 if ((reason = Ea (MB, &Y))) /* eff addr */
532 break;
533 PCQ_ENTRY; /* save PC */
534 PC = NEWA (PC, Y); /* set new PC */
535 if (extoff_pending) /* cond ext off */
536 ext = extoff_pending = 0;
537 break;
538
539 case 002: case 022: case 042: case 062: /* LDA */
540 if ((reason = Ea (MB, &Y))) /* eff addr */
541 break;
542 if (dp) { /* double prec? */
543 AR = Read (Y & ~1); /* get doubleword */
544 BR = Read (Y | 1);
545 sc = 0;
546 }
547 else AR = Read (Y); /* no, get word */
548 break;
549
550 case 003: case 023: case 043: case 063: /* ANA */
551 if ((reason = Ea (MB, &Y))) /* eff addr */
552 break;
553 AR = AR & Read (Y);
554 break;
555
556 case 004: case 024: case 044: case 064: /* STA */
557 if ((reason = Ea (MB, &Y))) /* eff addr */
558 break;
559 Write (Y, AR); /* store A */
560 if (dp) { /* double prec? */
561 Write (Y | 1, BR); /* store B */
562 sc = 0;
563 }
564 break;
565
566 case 005: case 025: case 045: case 065: /* ERA */
567 if ((reason = Ea (MB, &Y))) /* eff addr */
568 break;
569 AR = AR ^ Read (Y);
570 break;
571
572 case 006: case 026: case 046: case 066: /* ADD */
573 if ((reason = Ea (MB, &Y))) /* eff addr */
574 break;
575 if (dp) { /* double prec? */
576 t1 = GETDBL_S (AR, BR); /* get A'B */
577 t2 = GETDBL_S (Read (Y & ~1), Read (Y | 1));
578 t1 = Add31 (t1, t2); /* 31b add */
579 PUTDBL_Z (t1);
580 sc = 0;
581 }
582 else AR = Add16 (AR, Read (Y)); /* no, 16b add */
583 break;
584
585 case 007: case 027: case 047: case 067: /* SUB */
586 if ((reason = Ea (MB, &Y))) /* eff addr */
587 break;
588 if (dp) { /* double prec? */
589 t1 = GETDBL_S (AR, BR); /* get A'B */
590 t2 = GETDBL_S (Read (Y & ~1), Read (Y | 1));
591 t1 = Add31 (t1, -t2); /* 31b sub */
592 PUTDBL_Z (t1);
593 sc = 0;
594 }
595 else AR = Add16 (AR, (-Read (Y)) & DMASK); /* no, 16b sub */
596 break;
597
598 case 010: case 030: case 050: case 070: /* JST */
599 if ((reason = Ea (MB, &Y))) /* eff addr */
600 break;
601 MB = NEWA (Read (Y), PC); /* merge old PC */
602 Write (Y, MB);
603 PCQ_ENTRY;
604 PC = NEWA (PC, Y + 1); /* set new PC */
605 break;
606
607 case 011: case 031: case 051: case 071: /* CAS */
608 if ((reason = Ea (MB, &Y))) /* eff addr */
609 break;
610 MB = Read (Y);
611 if (AR == MB)
612 PC = NEWA (PC, PC + 1);
613 else if (SEXT (AR) < SEXT (MB))
614 PC = NEWA (PC, PC + 2);
615 break;
616
617 case 012: case 032: case 052: case 072: /* IRS */
618 if ((reason = Ea (MB, &Y))) /* eff addr */
619 break;
620 MB = (Read (Y) + 1) & DMASK; /* incr, rewrite */
621 Write (Y, MB);
622 if (MB == 0) /* skip if zero */
623 PC = NEWA (PC, PC + 1);
624 break;
625
626 case 013: case 033: case 053: case 073: /* IMA */
627 if ((reason = Ea (MB, &Y))) /* eff addr */
628 break;
629 MB = Read (Y);
630 Write (Y, AR); /* A to mem */
631 AR = MB; /* mem to A */
632 break;
633
634 case 015: case 055: /* STX */
635 if ((reason = Ea (MB & ~IDX, &Y))) /* eff addr */
636 break;
637 Write (Y, XR); /* store XR */
638 break;
639
640 case 035: case 075: /* LDX */
641 if ((reason = Ea (MB & ~IDX, &Y))) /* eff addr */
642 break;
643 XR = Read (Y); /* load XR */
644 M[M_XR] = XR; /* update mem too */
645 break;
646
647 case 016: case 036: case 056: case 076: /* MPY */
648 if (cpu_unit.flags & UNIT_HSA) { /* installed? */
649 if ((reason = Ea (MB, &Y))) /* eff addr */
650 break;
651 t1 = SEXT (AR) * SEXT (Read (Y));
652 PUTDBL_Z (t1);
653 sc = 0;
654 }
655 else reason = stop_inst;
656 break;
657
658 case 017: case 037: case 057: case 077: /* DIV */
659 if (cpu_unit.flags & UNIT_HSA) { /* installed? */
660 if ((reason = Ea (MB, &Y))) /* eff addr */
661 break;
662 t2 = SEXT (Read (Y)); /* divr */
663 if (t2) { /* divr != 0? */
664 t1 = GETDBL_S (SEXT (AR), BR); /* get A'B signed */
665 BR = (t1 % t2) & DMASK; /* remainder */
666 t1 = t1 / t2; /* quotient */
667 AR = t1 & DMASK;
668 if ((t1 > MMASK) || (t1 < (-SIGN)))
669 C = 1;
670 else C = 0;
671 sc = 0;
672 }
673 else C = 1;
674 }
675 else reason = stop_inst;
676 break;
677
678 /* I/O instructions */
679
680 case 014: /* OCP */
681 dev = MB & DEVMASK;
682 t2 = iotab[dev] (ioOCP, I_GETFNC (MB), AR, dev);
683 reason = t2 >> IOT_V_REASON;
684 break;
685
686 case 034: /* SKS */
687 dev = MB & DEVMASK;
688 t2 = iotab[dev] (ioSKS, I_GETFNC (MB), AR, dev);
689 reason = t2 >> IOT_V_REASON;
690 if (t2 & IOT_SKIP) /* skip? */
691 PC = NEWA (PC, PC + 1);
692 break;
693
694 case 054: /* INA */
695 dev = MB & DEVMASK;
696 if (MB & INCLRA)
697 AR = 0;
698 t2 = iotab[dev] (ioINA, I_GETFNC (MB & ~INCLRA), AR, dev);
699 reason = t2 >> IOT_V_REASON;
700 if (t2 & IOT_SKIP) /* skip? */
701 PC = NEWA (PC, PC + 1);
702 AR = t2 & DMASK; /* data */
703 break;
704
705 case 074: /* OTA */
706 dev = MB & DEVMASK;
707 t2 = iotab[dev] (ioOTA, I_GETFNC (MB), AR, dev);
708 reason = t2 >> IOT_V_REASON;
709 if (t2 & IOT_SKIP) /* skip? */
710 PC = NEWA (PC, PC + 1);
711 break;
712
713 /* Control */
714
715 case 000:
716 if ((MB & 1) == 0) { /* HLT */
717 if ((reason = sim_process_event ()) != SCPE_OK)
718 break;
719 reason = STOP_HALT;
720 break;
721 }
722 if (MB & m14) { /* SGL, DBL */
723 if (cpu_unit.flags & UNIT_HSA)
724 dp = (MB & m15)? 1: 0;
725 else reason = stop_inst;
726 }
727 if (MB & m13) { /* DXA, EXA */
728 if (!(cpu_unit.flags & UNIT_EXT))
729 reason = stop_inst;
730 else if (MB & m15) { /* EXA */
731 ext = 1;
732 extoff_pending = 0; /* DXA */
733 }
734 else extoff_pending = 1;
735 }
736 if (MB & m12) /* RMP */
737 CLR_INT (INT_MPE);
738 if (MB & m11) { /* SCA, INK */
739 if (MB & m15) /* INK */
740 AR = (C << 15) | (dp << 14) | (pme << 13) | (sc & 077);
741 else if (cpu_unit.flags & UNIT_HSA) /* SCA */
742 AR = sc & 077;
743 else reason = stop_inst;
744 }
745 else if (MB & m10) { /* NRM */
746 if (cpu_unit.flags & UNIT_HSA) {
747 for (sc = 0;
748 (sc < 32) && ((AR & SIGN) == ((AR << 1) & SIGN));
749 sc++) {
750 AR = (AR & SIGN) | ((AR << 1) & MMASK) |
751 ((BR >> 14) & 1);
752 BR = (BR & SIGN) | ((BR << 1) & MMASK);
753 }
754 sc = sc & 037;
755 }
756 else reason = stop_inst;
757 }
758 else if (MB & m9) { /* IAB */
759 sc = BR;
760 BR = AR;
761 AR = sc;
762 }
763 if (MB & m8) /* ENB */
764 dev_int = (dev_int | INT_ON) & ~INT_NODEF;
765 if (MB & m7) /* INH */
766 dev_int = dev_int & ~INT_ON;
767 break;
768
769 /* Shift
770
771 Shifts are microcoded as follows:
772
773 op<7> = right/left
774 op<8> = long/short
775 op<9> = shift/rotate (rotate bits "or" into new position)
776 op<10> = logical/arithmetic
777
778 If !op<7> && op<10> (right arithmetic), A<1> propagates rightward
779 If op<7> && op<10> (left arithmetic), C is set if A<1> changes state
780 If !op<8> && op<10> (long arithmetic), B<1> is skipped
781
782 This microcoding "explains" how the 4 undefined opcodes actually work
783 003 = long arith rotate right, skip B<1>, propagate A<1>,
784 bits rotated out "or" into A<1>
785 007 = short arith rotate right, propagate A<1>,
786 bits rotated out "or" into A<1>
787 013 = long arith rotate left, skip B<1>, C = overflow
788 017 = short arith rotate left, C = overflow
789 */
790
791 case 020:
792 C = 0; /* clear C */
793 sc = 0; /* clear sc */
794 if ((t1 = (-MB) & SHFMASK) == 0) /* shift count */
795 break;
796 switch (I_GETFNC (MB)) { /* case shift fnc */
797
798 case 000: /* LRL */
799 if (t1 > 32) /* >32? all 0 */
800 ut = 0;
801 else {
802 ut = GETDBL_U (AR, BR); /* get A'B */
803 C = (ut >> (t1 - 1)) & 1; /* C = last out */
804 if (t1 == 32) /* =32? all 0 */
805 ut = 0;
806 else ut = ut >> t1; /* log right */
807 }
808 PUTDBL_U (ut); /* store A,B */
809 break;
810
811 case 001: /* LRS */
812 if (t1 > 31) /* limit to 31 */
813 t1 = 31;
814 t2 = GETDBL_S (SEXT (AR), BR); /* get A'B signed */
815 C = (t2 >> (t1 - 1)) & 1; /* C = last out */
816 t2 = t2 >> t1; /* arith right */
817 PUTDBL_S (t2); /* store A,B */
818 break;
819
820 case 002: /* LRR */
821 t2 = t1 % 32; /* mod 32 */
822 ut = GETDBL_U (AR, BR); /* get A'B */
823 ut = (ut >> t2) | (ut << (32 - t2)); /* rot right */
824 C = (ut >> 31) & 1; /* C = A<1> */
825 PUTDBL_U (ut); /* store A,B */
826 break;
827
828 case 003: /* "long right arot" */
829 if ((reason = stop_inst)) /* stop on undef? */
830 break;
831 for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
832 C = BR & 1; /* C = last out */
833 BR = (BR & SIGN) | ((AR & 1) << 14) |
834 ((BR & MMASK) >> 1);
835 AR = ((AR & SIGN) | (C << 15)) | (AR >> 1);
836 }
837 break;
838
839 case 004: /* LGR */
840 if (t1 > 16) /* > 16? all 0 */
841 AR = 0;
842 else {
843 C = (AR >> (t1 - 1)) & 1; /* C = last out */
844 AR = (AR >> t1) & DMASK; /* log right */
845 }
846 break;
847
848 case 005: /* ARS */
849 if (t1 > 16) /* limit to 16 */
850 t1 = 16;
851 C = ((SEXT (AR)) >> (t1 - 1)) & 1; /* C = last out */
852 AR = ((SEXT (AR)) >> t1) & DMASK; /* arith right */
853 break;
854
855 case 006: /* ARR */
856 t2 = t1 % 16; /* mod 16 */
857 AR = ((AR >> t2) | (AR << (16 - t2))) & DMASK;
858 C = (AR >> 15) & 1; /* C = A<1> */
859 break;
860
861 case 007: /* "short right arot" */
862 if ((reason = stop_inst)) /* stop on undef? */
863 break;
864 for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
865 C = AR & 1; /* C = last out */
866 AR = ((AR & SIGN) | (C << 15)) | (AR >> 1);
867 }
868 break;
869
870 case 010: /* LLL */
871 if (t1 > 32) /* > 32? all 0 */
872 ut = 0;
873 else {
874 ut = GETDBL_U (AR, BR); /* get A'B */
875 C = (ut >> (32 - t1)) & 1; /* C = last out */
876 if (t1 == 32) /* =32? all 0 */
877 ut = 0;
878 else ut = ut << t1; /* log left */
879 }
880 PUTDBL_U (ut); /* store A,B */
881 break;
882
883 case 011: /* LLS */
884 if (t1 > 31) /* limit to 31 */
885 t1 = 31;
886 t2 = GETDBL_S (SEXT (AR), BR); /* get A'B */
887 t3 = t2 << t1; /* "arith" left */
888 PUTDBL_S (t3); /* store A'B */
889 if ((t2 >> (31 - t1)) != /* shf out = sgn? */
890 ((AR & SIGN)? -1: 0)) C = 1;
891 break;
892
893 case 012: /* LLR */
894 t2 = t1 % 32; /* mod 32 */
895 ut = GETDBL_U (AR, BR); /* get A'B */
896 ut = (ut << t2) | (ut >> (32 - t2)); /* rot left */
897 C = ut & 1; /* C = B<16> */
898 PUTDBL_U (ut); /* store A,B */
899 break;
900
901 case 013: /* "long left arot" */
902 if ((reason = stop_inst)) /* stop on undef? */
903 break;
904 for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
905 AR = (AR << 1) | ((BR >> 14) & 1);
906 BR = (BR & SIGN) | ((BR << 1) & MMASK) |
907 ((AR >> 16) & 1);
908 if ((AR & SIGN) != ((AR >> 1) & SIGN)) C = 1;
909 AR = AR & DMASK;
910 }
911 break;
912
913 case 014: /* LGL */
914 if (t1 > 16) /* > 16? all 0 */
915 AR = 0;
916 else {
917 C = (AR >> (16 - t1)) & 1; /* C = last out */
918 AR = (AR << t1) & DMASK; /* log left */
919 }
920 break;
921
922 case 015: /* ALS */
923 if (t1 > 16) /* limit to 16 */
924 t1 = 16;
925 t2 = SEXT (AR); /* save AR */
926 AR = (AR << t1) & DMASK; /* "arith" left */
927 if ((t2 >> (16 - t1)) != /* shf out + sgn */
928 ((AR & SIGN)? -1: 0)) C = 1;
929 break;
930
931 case 016: /* ALR */
932 t2 = t1 % 16; /* mod 16 */
933 AR = ((AR << t2) | (AR >> (16 - t2))) & DMASK;
934 C = AR & 1; /* C = A<16> */
935 break;
936
937 case 017: /* "short left arot" */
938 if ((reason = stop_inst)) /* stop on undef? */
939 break;
940 for (t2 = 0; t2 < t1; t2++) { /* bit by bit */
941 if ((AR & SIGN) != ((AR << 1) & SIGN)) C = 1;
942 AR = ((AR << 1) | (AR >> 15)) & DMASK;
943 }
944 break; /* end case fnc */
945 }
946 break;
947
948 /* Skip */
949
950 case 040:
951 skip = 0;
952 if (((MB & 000001) && C) || /* SSC */
953 ((MB & 000002) && ss[3]) || /* SS4 */
954 ((MB & 000004) && ss[2]) || /* SS3 */
955 ((MB & 000010) && ss[1]) || /* SS2 */
956 ((MB & 000020) && ss[0]) || /* SS1 */
957 ((MB & 000040) && AR) || /* SNZ */
958 ((MB & 000100) && (AR & 1)) || /* SLN */
959 ((MB & 000200) && (TST_INTREQ (INT_MPE))) || /* SPS */
960 ((MB & 000400) && (AR & SIGN))) /* SMI */
961 skip = 1;
962 if ((MB & 001000) == 0) /* reverse? */
963 skip = skip ^ 1;
964 PC = NEWA (PC, PC + skip);
965 break;
966
967 /* Operate */
968
969 case 060:
970 if (MB == 0140024) /* CHS */
971 AR = AR ^ SIGN;
972 else if (MB == 0140040) /* CRA */
973 AR = 0;
974 else if (MB == 0140100) /* SSP */
975 AR = AR & ~SIGN;
976 else if (MB == 0140200) /* RCB */
977 C = 0;
978 else if (MB == 0140320) { /* CSA */
979 C = (AR & SIGN) >> 15;
980 AR = AR & ~SIGN;
981 }
982 else if (MB == 0140401) /* CMA */
983 AR = AR ^ DMASK;
984 else if (MB == 0140407) { /* TCA */
985 AR = (-AR) & DMASK;
986 sc = 0;
987 }
988 else if (MB == 0140500) /* SSM */
989 AR = AR | SIGN;
990 else if (MB == 0140600) /* SCB */
991 C = 1;
992 else if (MB == 0141044) /* CAR */
993 AR = AR & 0177400;
994 else if (MB == 0141050) /* CAL */
995 AR = AR & 0377;
996 else if (MB == 0141140) /* ICL */
997 AR = AR >> 8;
998 else if (MB == 0141206) /* AOA */
999 AR = Add16 (AR, 1);
1000 else if (MB == 0141216) /* ACA */
1001 AR = Add16 (AR, C);
1002 else if (MB == 0141240) /* ICR */
1003 AR = (AR << 8) & DMASK;
1004 else if (MB == 0141340) /* ICA */
1005 AR = ((AR << 8) | (AR >> 8)) & DMASK;
1006 else if ((reason = stop_inst))
1007 break;
1008 else AR = Operate (MB, AR); /* undefined */
1009 break;
1010 } /* end case op */
1011 } /* end while */
1012
1013 saved_AR = AR & DMASK;
1014 saved_BR = BR & DMASK;
1015 saved_XR = XR & DMASK;
1016 pcq_r->qptr = pcq_p; /* update pc q ptr */
1017 return reason;
1018 }
1019
1020 /* Effective address
1021
1022 The effective address calculation consists of three phases:
1023 - base address calculation: 0/pagenumber'displacement
1024 - (extend): indirect address resolution
1025 (non-extend): pre-indexing
1026 - (extend): post-indexing
1027 (non-extend): indirect address/post-indexing resolution
1028
1029 In extend mode, address calculations are carried out to 16b
1030 and masked to 15b at exit. In non-extend mode, address bits
1031 <1:2> are preserved by the NEWA macro; address bit <1> is
1032 masked at exit.
1033 */
1034
Ea(int32 IR,int32 * addr)1035 t_stat Ea (int32 IR, int32 *addr)
1036 {
1037 int32 i;
1038 int32 Y = IR & (IA | DISP); /* ind + disp */
1039
1040 if (IR & SC) Y = ((PC - 1) & PAGENO) | Y; /* cur sec? + pageno */
1041 if (ext) { /* extend mode? */
1042 for (i = 0; (i < ind_max) && (Y & IA); i++) { /* resolve ind addr */
1043 Y = Read (Y & X_AMASK); /* get ind addr */
1044 }
1045 if (IR & IDX) Y = Y + XR; /* post-index */
1046 } /* end if ext */
1047 else { /* non-extend */
1048 Y = NEWA (PC, Y + ((IR & IDX)? XR: 0)); /* pre-index */
1049 for (i = 0; (i < ind_max) && (IR & IA); i++) { /* resolve ind addr */
1050 IR = Read (Y & X_AMASK); /* get ind addr */
1051 Y = NEWA (Y, IR + ((IR & IDX)? XR: 0)); /* post-index */
1052 }
1053 } /* end else */
1054 *addr = Y = Y & X_AMASK; /* return addr */
1055 if (hst_lnt) { /* history? */
1056 hst[hst_p].pc = hst[hst_p].pc | HIST_EA;
1057 hst[hst_p].ea = Y;
1058 hst[hst_p].opnd = Read (Y);
1059 }
1060 if (i >= ind_max)
1061 return STOP_IND; /* too many ind? */
1062 return SCPE_OK;
1063 }
1064
1065 /* Write memory */
1066
Write(int32 addr,int32 val)1067 void Write (int32 addr, int32 val)
1068 {
1069 if (((addr == 0) || (addr >= 020)) && MEM_ADDR_OK (addr))
1070 M[addr] = val;
1071 if (addr == M_XR) /* write XR loc? */
1072 XR = val; /* update XR */
1073 return;
1074 }
1075
1076 /* Add */
1077
Add16(int32 v1,int32 v2)1078 int32 Add16 (int32 v1, int32 v2)
1079 {
1080 int32 r = v1 + v2;
1081
1082 if (((v1 ^ ~v2) & (v1 ^ r)) & SIGN)
1083 C = 1;
1084 else C = 0;
1085 return (r & DMASK);
1086 }
1087
Add31(int32 v1,int32 v2)1088 int32 Add31 (int32 v1, int32 v2)
1089 {
1090 int32 r = v1 + v2;
1091
1092 if (((v1 ^ ~v2) & (v1 ^ r)) & DP_SIGN)
1093 C = 1;
1094 else C = 0;
1095 return r;
1096 }
1097
1098 /* Unimplemented I/O device */
1099
undio(int32 op,int32 fnc,int32 val,int32 dev)1100 int32 undio (int32 op, int32 fnc, int32 val, int32 dev)
1101 {
1102 return ((stop_dev << IOT_V_REASON) | val);
1103 }
1104
1105 /* DMA control */
1106
dmaio(int32 inst,int32 fnc,int32 dat,int32 dev)1107 int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev)
1108 {
1109 int32 ch = (fnc - 1) & 03;
1110
1111 switch (inst) { /* case on opcode */
1112
1113 case ioOCP: /* OCP */
1114 if ((fnc >= 001) && (fnc <= 004)) { /* load addr ctr */
1115 dma_ad[ch] = dat;
1116 dma_wc[ch] = 0;
1117 dma_eor[ch] = 0;
1118 }
1119 else if ((fnc >= 011) && (fnc <= 014)) /* load range ctr */
1120 dma_wc[ch] = (dma_wc[ch] | dat) & 077777;
1121 else return IOBADFNC (dat); /* undefined */
1122 break;
1123
1124 case ioINA: /* INA */
1125 if ((fnc >= 011) && (fnc <= 014)) {
1126 if (dma_eor[ch]) /* end range? nop */
1127 return dat;
1128 return IOSKIP (0100000 | dma_wc[ch]); /* return range */
1129 }
1130 else return IOBADFNC (dat);
1131 }
1132
1133 return dat;
1134 }
1135
1136 /* Undefined operate instruction. This code is reached when the
1137 opcode does not correspond to a standard operate instruction.
1138 It simulates the behavior of the actual logic.
1139
1140 An operate instruction executes in 4 or 6 phases. A 'normal'
1141 instruction takes 4 phases:
1142
1143 t1 t1
1144 t2/tlate t2/t2 extended into t3
1145 t3/tlate t3
1146 t4 t4
1147
1148 A '1.5 cycle' instruction takes 6 phases:
1149
1150 t1 t1
1151 t2/tlate t2/t2 extended into t3
1152 t3/tlate t3
1153 t2/tlate 'special' t2/t2 extended into t3
1154 t3/tlate t3
1155 t4 t4
1156
1157 The key signals, by phase, are the following
1158
1159 tlate EASTL enable A to sum leg 1 (else 0)
1160 (((m12+m16)x!azzzz)+(m9+m11+azzzz)
1161 EASBM enable 0 to sum leg 2 (else 177777)
1162 (m9+m11+azzzz)
1163 JAMKN jam carry network to 0 = force XOR
1164 ((m12+m16)x!azzzz)
1165 EIKI7 force carry into adder
1166 ((m15x(C+!m13))x!JAMKN)
1167
1168 t3 CLDTR set D to 177777 (always)
1169 ESDTS enable adder sum to D (always)
1170 SETAZ enable repeat cycle = set azzzz
1171 (m8xm15)
1172
1173 if azzzz {
1174 t2 CLATR clear A register (due to azzzz)
1175 EDAHS enable D high to A high register (due to azzzz)
1176 EDALS enable D low to A low register (due to azzzz)
1177
1178 tlate, t3 as above
1179 }
1180
1181 t4 CLATR clear A register
1182 (m11+m15+m16)
1183 CLA1R clear A1 register
1184 (m10+m14)
1185 EDAHS enable D high to A high register
1186 ((m11xm14)+m15+m16)
1187 EDALS enable D low to A low register
1188 ((m11xm13)+m15+m16)
1189 ETAHS enable D transposed to A high register
1190 (m9xm11)
1191 ETALS enable D transposed to A low register
1192 (m10xm11)
1193 EDA1R enable D1 to A1 register
1194 ((m8xm10)+m14)
1195 CBITL clear C, conditionally set C from adder output
1196 (m9x!m11)
1197 CBITG conditionally set C if D1
1198 (m10xm12xD1)
1199 CBITE unconditionally set C
1200 (m8xm9)
1201 */
1202
Operate(int32 MB,int32 AR)1203 int32 Operate (int32 MB, int32 AR)
1204 {
1205 int32 D, jamkn, eiki7, easbm, eastl, setaz;
1206 int32 clatr, cla1r, edahs, edals, etahs, etals, eda1r;
1207 int32 cbitl, cbitg, cbite;
1208 int32 aleg, bleg, ARx;
1209
1210 /* Phase tlate */
1211
1212 ARx = AR; /* default */
1213 jamkn = (MB & (m12+m16)) != 0; /* m12+m16 */
1214 easbm = (MB & (m9+m11)) != 0; /* m9+m11 */
1215 eastl = jamkn || easbm; /* m9+m11+m12+m16 */
1216 setaz = (MB & (m8+m15)) == (m8+m15); /* m8xm15*/
1217 eiki7 = (MB & m15) && (C || !(MB & m13)); /* cin */
1218 aleg = eastl? AR: 0; /* a input */
1219 bleg = easbm? 0: DMASK; /* b input */
1220 if (jamkn) /* jammin? xor */
1221 D = aleg ^ bleg;
1222 else D = (aleg + bleg + eiki7) & DMASK; /* else add */
1223
1224 /* Possible repeat at end of tlate - special t2, repeat tlate */
1225
1226 if (setaz) {
1227 ARx = D; /* forced: t2 */
1228 aleg = ARx; /* forced: tlate */
1229 bleg = 0; /* forced */
1230 jamkn = 0; /* forced */
1231 D = (aleg + bleg + eiki7) & DMASK; /* forced add */
1232 sc = 0; /* ends repeat */
1233 }
1234
1235 /* Phase t4 */
1236
1237 clatr = (MB & (m11+m15+m16)) != 0; /* m11+m15+m16 */
1238 cla1r = (MB & (m10+m14)) != 0; /* m10+m14 */
1239 edahs = ((MB & (m11+m14)) == (m11+m14)) || /* (m11xm14)+m15+m16 */
1240 (MB & (m15+m16));
1241 edals = ((MB & (m11+m13)) == (m11+m13)) || /* (m11xm13)+m15+m16 */
1242 (MB & (m15+m16));
1243 etahs = (MB & (m9+m11)) == (m9+m11); /* m9xm11 */
1244 etals = (MB & (m10+m11)) == (m10+m11); /* m10xm11 */
1245 eda1r = ((MB & (m8+m10)) == (m8+m10)) || (MB & m14); /* (m8xm10)+m14 */
1246 cbitl = (MB & (m9+m11)) == m9; /* m9x!m11 */
1247 cbite = (MB & (m8+m9)) == (m8+m9); /* m8xm9 */
1248 cbitg = (MB & (m10+m12)) == (m10+m12); /* m10xm12 */
1249
1250 if (clatr) /* clear A */
1251 ARx = 0;
1252 if (cla1r) /* clear A1 */
1253 ARx = ARx & ~SIGN;
1254 if (edahs) /* D hi to A hi */
1255 ARx = ARx | (D & 0177400);
1256 if (edals) /* D lo to A lo */
1257 ARx = ARx | (D & 0000377);
1258 if (etahs) /* D lo to A hi */
1259 ARx = ARx | ((D << 8) & 0177400);
1260 if (etals) /* D hi to A lo */
1261 ARx = ARx | ((D >> 8) & 0000377);
1262 if (eda1r) /* D1 to A1 */
1263 ARx = ARx | (D & SIGN);
1264 if (cbitl) { /* ovflo to C */
1265
1266 /* Overflow calculation. Cases:
1267
1268 aleg bleg cin overflow
1269
1270 0 x x can't overflow
1271 A 0 0 can't overflow
1272 A -1 1 can't overflow
1273 A 0 1 overflow if 77777->100000
1274 A -1 0 overflow if 100000->77777
1275 */
1276
1277 if (!jamkn &&
1278 ((bleg && !eiki7 && (D == 0077777)) ||
1279 (!bleg && eiki7 && (D == 0100000))))
1280 C = 1;
1281 else C = 0;
1282 }
1283 if (cbite || (cbitg && (D & SIGN))) /* C = 1 */
1284 C = 1;
1285 return ARx;
1286 }
1287
1288 /* Reset routines */
1289
cpu_reset(DEVICE * dptr)1290 t_stat cpu_reset (DEVICE *dptr)
1291 {
1292 int32 i;
1293
1294 saved_AR = saved_BR = saved_XR = 0;
1295 C = 0;
1296 dp = 0;
1297 ext = pme = extoff_pending = 0;
1298 dev_int = dev_int & ~(INT_PEND|INT_NMI);
1299 dev_enb = 0;
1300 for (i = 0; i < DMA_MAX; i++)
1301 dma_ad[i] = dma_wc[i] = dma_eor[i] = 0;
1302 chan_req = 0;
1303 pcq_r = find_reg ("PCQ", NULL, dptr);
1304 if (pcq_r)
1305 pcq_r->qptr = 0;
1306 else return SCPE_IERR;
1307 sim_brk_types = sim_brk_dflt = SWMASK ('E');
1308 return SCPE_OK;
1309 }
1310
1311 /* Memory examine */
1312
cpu_ex(t_value * vptr,t_addr addr,UNIT * uptr,int32 sw)1313 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
1314 {
1315 if (addr >= MEMSIZE)
1316 return SCPE_NXM;
1317 if (vptr != NULL)
1318 *vptr = M[addr] & DMASK;
1319 return SCPE_OK;
1320 }
1321
1322 /* Memory deposit */
1323
cpu_dep(t_value val,t_addr addr,UNIT * uptr,int32 sw)1324 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
1325 {
1326 if (addr >= MEMSIZE)
1327 return SCPE_NXM;
1328 if (addr == 0)
1329 saved_XR = val & DMASK;
1330 M[addr] = val & DMASK;
1331 return SCPE_OK;
1332 }
1333
1334 /* Option processors */
1335
cpu_set_noext(UNIT * uptr,int32 val,char * cptr,void * desc)1336 t_stat cpu_set_noext (UNIT *uptr, int32 val, char *cptr, void *desc)
1337 {
1338 if (MEMSIZE > (NX_AMASK + 1))
1339 return SCPE_ARG;
1340 return SCPE_OK;
1341 }
1342
cpu_set_size(UNIT * uptr,int32 val,char * cptr,void * desc)1343 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
1344 {
1345 int32 mc = 0;
1346 uint32 i;
1347
1348 if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0) ||
1349 (((cpu_unit.flags & UNIT_EXT) == 0) && (val > (NX_AMASK + 1))))
1350 return SCPE_ARG;
1351 for (i = val; i < MEMSIZE; i++)
1352 mc = mc | M[i];
1353 if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
1354 return SCPE_OK;
1355 MEMSIZE = val;
1356 for (i = MEMSIZE; i < MAXMEMSIZE; i++)
1357 M[i] = 0;
1358 return SCPE_OK;
1359 }
1360
cpu_set_nchan(UNIT * uptr,int32 val,char * cptr,void * desc)1361 t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc)
1362 {
1363 uint32 i, newmax;
1364 t_stat r;
1365
1366 if (cptr == NULL)
1367 return SCPE_ARG;
1368 newmax = get_uint (cptr, 10, DMA_MAX, &r); /* get new max */
1369 if ((r != SCPE_OK) || (newmax == dma_nch)) /* err or no chg? */
1370 return r;
1371 dma_nch = newmax; /* set new max */
1372 for (i = newmax; i < DMA_MAX; i++) { /* reset chan */
1373 dma_ad[i] = dma_wc[i] = dma_eor[i] = 0;
1374 chan_req = chan_req & ~(1 << i);
1375 }
1376 return SCPE_OK;
1377 }
1378
1379 /* Show DMA channels */
1380
cpu_show_nchan(FILE * st,UNIT * uptr,int32 val,void * desc)1381 t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc)
1382 {
1383 if (dma_nch)
1384 fprintf (st, "DMA channels = %d", dma_nch);
1385 else fprintf (st, "no DMA channels");
1386 return SCPE_OK;
1387 }
1388
1389 /* Show channel state */
1390
cpu_show_dma(FILE * st,UNIT * uptr,int32 val,void * desc)1391 t_stat cpu_show_dma (FILE *st, UNIT *uptr, int32 val, void *desc)
1392 {
1393 if ((val < 0) || (val >= DMA_MAX))
1394 return SCPE_IERR;
1395 fputs ((dma_ad[val] & DMA_IN)? "Input": "Output", st);
1396 fprintf (st, ", addr = %06o, count = %06o, ", dma_ad[val] & X_AMASK, dma_wc[val]);
1397 fprintf (st, "end of range %s\n", (dma_eor[val]? "set": "clear"));
1398 return SCPE_OK;
1399 }
1400
1401 /* Set I/O device to IOBUS / DMA channel / DMC channel */
1402
io_set_iobus(UNIT * uptr,int32 val,char * cptr,void * desc)1403 t_stat io_set_iobus (UNIT *uptr, int32 val, char *cptr, void *desc)
1404 {
1405 DEVICE *dptr;
1406 DIB *dibp;
1407
1408 if (val || cptr || (uptr == NULL))
1409 return SCPE_IERR;
1410 dptr = find_dev_from_unit (uptr);
1411 if (dptr == NULL)
1412 return SCPE_IERR;
1413 dibp = (DIB *) dptr->ctxt;
1414 if (dibp == NULL)
1415 return SCPE_IERR;
1416 dibp->chan = 0;
1417 return SCPE_OK;
1418 }
1419
io_set_dma(UNIT * uptr,int32 val,char * cptr,void * desc)1420 t_stat io_set_dma (UNIT *uptr, int32 val, char *cptr, void *desc)
1421 {
1422 DEVICE *dptr;
1423 DIB *dibp;
1424 uint32 newc;
1425 t_stat r;
1426
1427 if ((cptr == NULL) || (uptr == NULL))
1428 return SCPE_IERR;
1429 dptr = find_dev_from_unit (uptr);
1430 if (dptr == NULL)
1431 return SCPE_IERR;
1432 dibp = (DIB *) dptr->ctxt;
1433 if (dibp == NULL)
1434 return SCPE_IERR;
1435 if (dma_nch == 0)
1436 return SCPE_NOFNC;
1437 newc = get_uint (cptr, 10, DMA_MAX, &r); /* get new */
1438 if ((r != SCPE_OK) || (newc == 0) || (newc > dma_nch))
1439 return SCPE_ARG;
1440 dibp->chan = (newc - DMA_MIN) + DMA_V_DMA1 + 1; /* store */
1441 return SCPE_OK;
1442 }
1443
io_set_dmc(UNIT * uptr,int32 val,char * cptr,void * desc)1444 t_stat io_set_dmc (UNIT *uptr, int32 val, char *cptr, void *desc)
1445 {
1446 DEVICE *dptr;
1447 DIB *dibp;
1448 uint32 newc;
1449 t_stat r;
1450
1451 if ((cptr == NULL) || (uptr == NULL))
1452 return SCPE_IERR;
1453 dptr = find_dev_from_unit (uptr);
1454 if (dptr == NULL)
1455 return SCPE_IERR;
1456 dibp = (DIB *) dptr->ctxt;
1457 if (dibp == NULL)
1458 return SCPE_IERR;
1459 if (!(cpu_unit.flags & UNIT_DMC))
1460 return SCPE_NOFNC;
1461 newc = get_uint (cptr, 10, DMC_MAX, &r); /* get new */
1462 if ((r != SCPE_OK) || (newc == 0))
1463 return SCPE_ARG;
1464 dibp->chan = (newc - DMC_MIN) + DMC_V_DMC1 + 1; /* store */
1465 return SCPE_OK;
1466 }
1467
1468 /* Show channel configuration */
1469
io_show_chan(FILE * st,UNIT * uptr,int32 val,void * desc)1470 t_stat io_show_chan (FILE *st, UNIT *uptr, int32 val, void *desc)
1471 {
1472 DEVICE *dptr;
1473 DIB *dibp;
1474
1475 if (uptr == NULL)
1476 return SCPE_IERR;
1477 dptr = find_dev_from_unit (uptr);
1478 if (dptr == NULL)
1479 return SCPE_IERR;
1480 dibp = (DIB *) dptr->ctxt;
1481 if (dibp == NULL)
1482 return SCPE_IERR;
1483 if (dibp->chan == 0)
1484 fprintf (st, "IO bus");
1485 else if (dibp->chan < (DMC_V_DMC1 + 1))
1486 fprintf (st, "DMA channel %d", dibp->chan);
1487 else fprintf (st, "DMC channel %d", dibp->chan - DMC_V_DMC1);
1488 return SCPE_OK;
1489 }
1490
1491 /* Set up I/O dispatch and channel maps */
1492
devtab_init(void)1493 t_bool devtab_init (void)
1494 {
1495 DEVICE *dptr;
1496 DIB *dibp;
1497 uint32 i, j, dno, chan;
1498
1499 for (i = 0; i < DEV_MAX; i++)
1500 iotab[i] = NULL;
1501 for (i = 0; i < (DMA_MAX + DMC_MAX); i++)
1502 chan_map[i] = 0;
1503 for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */
1504 dibp = (DIB *) dptr->ctxt; /* get DIB */
1505 if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */
1506 continue;
1507 dno = dibp->dev; /* device number */
1508 for (j = 0; j < dibp->num; j++) { /* repeat for slots */
1509 if (iotab[dno + j]) { /* conflict? */
1510 printf ("%s device number conflict, devno = %02o\n",
1511 sim_dname (dptr), dno + j);
1512 if (sim_log)
1513 fprintf (sim_log, "%s device number conflict, devno = %02o\n",
1514 sim_dname (dptr), dno + j);
1515 return TRUE;
1516 }
1517 iotab[dno + j] = dibp->io; /* set I/O routine */
1518 } /* end for */
1519 if (dibp->chan) { /* DMA/DMC? */
1520 chan = dibp->chan - 1;
1521 if ((chan < DMC_V_DMC1) && (chan >= dma_nch)) {
1522 printf ("%s configured for DMA channel %d\n",
1523 sim_dname (dptr), chan + 1);
1524 if (sim_log)
1525 fprintf (sim_log, "%s configured for DMA channel %d\n",
1526 sim_dname (dptr), chan + 1);
1527 return TRUE;
1528 }
1529 if ((chan >= DMC_V_DMC1) && !(cpu_unit.flags & UNIT_DMC)) {
1530 printf ("%s configured for DMC, option disabled\n",
1531 sim_dname (dptr));
1532 if (sim_log)
1533 fprintf (sim_log, "%s configured for DMC, option disabled\n",
1534 sim_dname (dptr));
1535 return TRUE;
1536 }
1537 if (chan_map[chan]) { /* channel conflict? */
1538 printf ("%s DMA/DMC channel conflict, devno = %02o\n",
1539 sim_dname (dptr), dno);
1540 if (sim_log)
1541 fprintf (sim_log, "%s DMA/DMC channel conflict, devno = %02o\n",
1542 sim_dname (dptr), dno);
1543 return TRUE;
1544 }
1545 chan_map[chan] = dno; /* channel back map */
1546 }
1547 } /* end for */
1548 for (i = 0; i < DEV_MAX; i++) { /* fill in blanks */
1549 if (iotab[i] == NULL)
1550 iotab[i] = &undio;
1551 }
1552 return FALSE;
1553 }
1554
1555 /* Set history */
1556
cpu_set_hist(UNIT * uptr,int32 val,char * cptr,void * desc)1557 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
1558 {
1559 int32 i, lnt;
1560 t_stat r;
1561
1562 if (cptr == NULL) {
1563 for (i = 0; i < hst_lnt; i++)
1564 hst[i].pc = 0;
1565 hst_p = 0;
1566 return SCPE_OK;
1567 }
1568 lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
1569 if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
1570 return SCPE_ARG;
1571 hst_p = 0;
1572 if (hst_lnt) {
1573 free (hst);
1574 hst_lnt = 0;
1575 hst = NULL;
1576 }
1577 if (lnt) {
1578 hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));
1579 if (hst == NULL)
1580 return SCPE_MEM;
1581 hst_lnt = lnt;
1582 }
1583 return SCPE_OK;
1584 }
1585
1586 /* Show history */
1587
cpu_show_hist(FILE * st,UNIT * uptr,int32 val,void * desc)1588 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
1589 {
1590 int32 cr, k, di, op, lnt;
1591 char *cptr = (char *) desc;
1592 t_value sim_eval;
1593 t_stat r;
1594 InstHistory *h;
1595 extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
1596 UNIT *uptr, int32 sw);
1597 static uint8 has_opnd[16] = {
1598 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1
1599 };
1600
1601 if (hst_lnt == 0) /* enabled? */
1602 return SCPE_NOFNC;
1603 if (cptr) {
1604 lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
1605 if ((r != SCPE_OK) || (lnt == 0))
1606 return SCPE_ARG;
1607 }
1608 else lnt = hst_lnt;
1609 di = hst_p - lnt; /* work forward */
1610 if (di < 0)
1611 di = di + hst_lnt;
1612 fprintf (st, "PC C A B X ea IR\n\n");
1613 for (k = 0; k < lnt; k++) { /* print specified */
1614 h = &hst[(++di) % hst_lnt]; /* entry pointer */
1615 if (h->pc & HIST_PC) { /* instruction? */
1616 cr = (h->pc & HIST_C)? 1: 0; /* carry */
1617 fprintf (st, "%05o %o %06o %06o %06o ",
1618 h->pc & X_AMASK, cr, h->ar, h->br, h->xr);
1619 if (h->pc & HIST_EA)
1620 fprintf (st, "%05o ", h->ea);
1621 else fprintf (st, " ");
1622 sim_eval = h->ir;
1623 if ((fprint_sym (st, h->pc & X_AMASK, &sim_eval,
1624 &cpu_unit, SWMASK ('M'))) > 0)
1625 fprintf (st, "(undefined) %06o", h->ir);
1626 op = I_GETOP (h->ir) & 017; /* base op */
1627 if (has_opnd[op])
1628 fprintf (st, " [%06o]", h->opnd);
1629 fputc ('\n', st); /* end line */
1630 } /* end else instruction */
1631 } /* end for */
1632 return SCPE_OK;
1633 }
1634