1 /* h316_cpu.c: Honeywell 316/516 CPU simulator
3 Copyright (c) 1999-2007, Robert M. Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
28 28-Apr-07 RMS Removed clock initialization
29 03-Apr-06 RMS Fixed bugs in LLL, LRL (from Theo Engel)
30 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
31 16-Aug-05 RMS Fixed C++ declaration and cast problems
32 15-Feb-05 RMS Added start button interrupt
33 01-Dec-04 RMS Fixed bug in DIV
34 06-Nov-04 RMS Added =n to SHOW HISTORY
35 04-Jan-04 RMS Removed unnecessary compare
36 31-Dec-03 RMS Fixed bug in cpu_set_hist
37 24-Oct-03 RMS Added DMA/DMC support, instruction history
38 30-Dec-01 RMS Added old PC queue
39 03-Nov-01 RMS Fixed NOHSA modifier
40 30-Nov-01 RMS Added extended SET/SHOW support
42 The register state for the Honeywell 316/516 CPU is:
47 PC<1:16> P register (program counter)
48 Y<1:16> memory address register
49 MB<1:16> memory data register
52 DP double precision mode flag
54 SR[1:4]<0> sense switches 1-4
56 The Honeywell 316/516 has six instruction formats: memory reference,
57 I/O, control, shift, skip, and operate.
59 The memory reference format is:
61 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
62 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
63 |in|xr| op |sc| offset | memory reference
64 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
66 <13:10> mnemonic action
68 0000 (other) see control, shift, skip, operate instructions
71 0011 ANA A = A & M[MA]
73 0101 ERA A = A ^ M[MA]
74 0110 ADD A = A + M[MA]
75 0111 SUB A = A - M[MA]
76 1000 JST M[MA] = P, P = MA + 1
77 1001 CAS skip if A == M[MA], double skip if A < M[MA]
78 1010 IRS M[MA] = M[MA] + 1, skip if M[MA] == 0
80 1100 (I/O) see I/O instructions
81 1101 LDX/STX X = M[MA] (xr = 1), M[MA] = x (xr = 0)
85 In non-extend mode, memory reference instructions can access an address
86 space of 16K words. Multiple levels of indirection are supported, and
87 each indirect word supplies its own indirect and index bits.
91 0,0,0 sector zero direct MA = IR<8:0>
92 0,0,1 current direct MA = P<13:9>'IR<8:0>
93 0,1,0 sector zero indexed MA = IR<8:0> + X
94 0,1,1 current direct MA = P<13:9>'IR<8:0> + X
95 1,0,0 sector zero indirect MA = M[IR<8:0>]
96 1,0,1 current indirect MA = M[P<13:9>'IR<8:0>]
97 1,1,0 sector zero indirect indexed MA = M[IR<8:0> + X]
98 1,1,1 current indirect indexed MA = M[MA = P<13:9>'IR<8:0> + X]
100 In extend mode, memory reference instructions can access an address
101 space of 32K words. Multiple levels of indirection are supported, but
102 only post-indexing, based on the original instruction word index flag,
105 The control format is:
107 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
108 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
109 | 0 0 0 0 0 0| opcode | control
110 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
114 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
115 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
116 | 0 1 0 0 0 0|dr|sz|type | shift count | shift
117 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
120 | | +--------------------- type
121 | +------------------------- long/A only
122 +---------------------------- right/left
126 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
127 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
128 | 1 0 0 0 0 0|rv|po|pe|ev|ze|s1|s2|s3|s4|cz| skip
129 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
131 | | | | | | | | | +- skip if C = 0
132 | | | | | | | | +---- skip if ssw 4 = 0
133 | | | | | | | +------- skip if ssw 3 = 0
134 | | | | | | +---------- skip if ssw 2 = 0
135 | | | | | +------------- skip if ssw 1 = 0
136 | | | | +---------------- skip if A == 0
137 | | | +------------------- skip if A<0> == 0
138 | | +---------------------- skip if mem par err
139 | +------------------------- skip if A<15> = 0
140 +---------------------------- reverse skip sense
142 The operate format is:
144 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
145 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
146 | 1 1 0 0 0 0| opcode | operate
147 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
151 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
152 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
153 | op | 1 1 0 0| function | device | I/O transfer
154 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
156 The IO transfer instruction controls the specified device.
157 Depending on the opcode, the instruction may set or clear
158 the device flag, start or stop I/O, or read or write data.
160 This routine is the instruction decode routine for the Honeywell
161 316/516. It is called from the simulator control program to execute
162 instructions in simulated memory, starting at the simulated PC.
163 It runs until 'reason' is set non-zero.
167 1. Reasons to stop. The simulator can be stopped by:
170 breakpoint encountered
171 infinite indirection loop
172 unimplemented instruction and stop_inst flag set
173 unknown I/O device and stop_dev flag set
174 I/O error in I/O simulator
176 2. Interrupts. Interrupts are maintained by two parallel variables:
178 dev_int device interrupt flags
179 dev_enb device interrupt enable flags
181 In addition, dev_int contains the interrupt enable and interrupt no
182 defer flags. If interrupt enable and interrupt no defer are set, and
183 at least one interrupt request is pending, then an interrupt occurs.
184 The order of flags in these variables corresponds to the order
185 in the SMK instruction.
187 3. Non-existent memory. On the H316/516, reads to non-existent memory
188 return zero, and writes are ignored. In the simulator, the
189 largest possible memory is instantiated and initialized to zero.
190 Thus, only writes need be checked against actual memory size.
192 4. Adding I/O devices. These modules must be modified:
194 h316_defs.h add interrupt request definition
195 h316_cpu.c add device dispatch table entry
196 h316_sys.c add sim_devices table entry
199 #include "h316_defs.h"
201 #define PCQ_SIZE 64 /* must be 2**n */
202 #define PCQ_MASK (PCQ_SIZE - 1)
203 #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
204 #define PCQ_TOP pcq[pcq_p]
205 #define m7 0001000 /* for generics */
216 #define HIST_PC 0x40000000
217 #define HIST_C 0x20000000
218 #define HIST_EA 0x10000000
220 #define HIST_MAX 65536
232 uint16 M
[MAXMEMSIZE
] = { 0 }; /* memory */
233 int32 saved_AR
= 0; /* A register */
234 int32 saved_BR
= 0; /* B register */
235 int32 saved_XR
= 0; /* X register */
236 int32 PC
= 0; /* P register */
237 int32 C
= 0; /* C register */
238 int32 ext
= 0; /* extend mode */
239 int32 pme
= 0; /* prev mode extend */
240 int32 extoff_pending
= 0; /* extend off pending */
241 int32 dp
= 0; /* double mode */
242 int32 sc
= 0; /* shift count */
243 int32 ss
[4]; /* sense switches */
244 int32 dev_int
= 0; /* dev ready */
245 int32 dev_enb
= 0; /* dev enable */
246 int32 ind_max
= 8; /* iadr nest limit */
247 int32 stop_inst
= 1; /* stop on ill inst */
248 int32 stop_dev
= 2; /* stop on ill dev */
249 uint16 pcq
[PCQ_SIZE
] = { 0 }; /* PC queue */
250 int32 pcq_p
= 0; /* PC queue ptr */
251 REG
*pcq_r
= NULL
; /* PC queue reg ptr */
252 uint32 dma_nch
= DMA_MAX
; /* number of chan */
253 uint32 dma_ad
[DMA_MAX
] = { 0 }; /* DMA addresses */
254 uint32 dma_wc
[DMA_MAX
] = { 0 }; /* DMA word count */
255 uint32 dma_eor
[DMA_MAX
] = { 0 }; /* DMA end of range */
256 uint32 chan_req
= 0; /* channel requests */
257 uint32 chan_map
[DMA_MAX
+ DMC_MAX
] = { 0 }; /* chan->dev map */
258 int32 (*iotab
[DEV_MAX
])(int32 inst
, int32 fnc
, int32 dat
, int32 dev
) = { NULL
};
259 int32 hst_p
= 0; /* history pointer */
260 int32 hst_lnt
= 0; /* history length */
261 InstHistory
*hst
= NULL
; /* instruction history */
263 extern int32 sim_int_char
;
264 extern int32 sim_interval
;
265 extern uint32 sim_brk_types
, sim_brk_dflt
, sim_brk_summ
; /* breakpoint info */
266 extern FILE *sim_log
;
267 extern DEVICE
*sim_devices
[];
269 t_bool
devtab_init (void);
270 int32
dmaio (int32 inst
, int32 fnc
, int32 dat
, int32 dev
);
271 int32
undio (int32 inst
, int32 fnc
, int32 dat
, int32 dev
);
272 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
);
273 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
);
274 t_stat
cpu_reset (DEVICE
*dptr
);
275 t_stat
cpu_set_noext (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
276 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
277 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
278 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
279 t_stat
cpu_show_dma (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
280 t_stat
cpu_set_nchan (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
281 t_stat
cpu_show_nchan (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
283 extern t_stat
fprint_sym (FILE *of
, t_addr addr
, t_value
*val
,
284 UNIT
*uptr
, int32 sw
);
286 /* CPU data structures
288 cpu_dev CPU device descriptor
289 cpu_unit CPU unit descriptor
290 cpu_reg CPU register list
291 cpu_mod CPU modifiers list
294 DIB cpu_dib
= { DMA
, IOBUS
, 1, &dmaio
};
297 UDATA (NULL
, UNIT_FIX
+UNIT_BINK
+UNIT_EXT
+UNIT_HSA
+UNIT_DMC
, MAXMEMSIZE
)
301 { ORDATA (P
, PC
, 15) },
302 { ORDATA (A
, saved_AR
, 16) },
303 { ORDATA (B
, saved_BR
, 16) },
304 { ORDATA (X
, XR
, 16) },
305 { ORDATA (SC
, sc
, 16) },
306 { FLDATA (C
, C
, 0) },
307 { FLDATA (EXT
, ext
, 0) },
308 { FLDATA (PME
, pme
, 0) },
309 { FLDATA (EXT_OFF
, extoff_pending
, 0) },
310 { FLDATA (DP
, dp
, 0) },
311 { FLDATA (SS1
, ss
[0], 0) },
312 { FLDATA (SS2
, ss
[1], 0) },
313 { FLDATA (SS3
, ss
[2], 0) },
314 { FLDATA (SS4
, ss
[3], 0) },
315 { FLDATA (ION
, dev_int
, INT_V_ON
) },
316 { FLDATA (INODEF
, dev_int
, INT_V_NODEF
) },
317 { FLDATA (START
, dev_int
, INT_V_START
) },
318 { ORDATA (DEVINT
, dev_int
, 16), REG_RO
},
319 { ORDATA (DEVENB
, dev_enb
, 16), REG_RO
},
320 { ORDATA (CHREQ
, chan_req
, DMA_MAX
+ DMC_MAX
) },
321 { BRDATA (DMAAD
, dma_ad
, 8, 16, DMA_MAX
) },
322 { BRDATA (DMAWC
, dma_wc
, 8, 16, DMA_MAX
) },
323 { BRDATA (DMAEOR
, dma_eor
, 8, 1, DMA_MAX
) },
324 { ORDATA (DMANCH
, dma_nch
, 3), REG_HRO
},
325 { FLDATA (MPERDY
, dev_int
, INT_V_MPE
) },
326 { FLDATA (MPEENB
, dev_enb
, INT_V_MPE
) },
327 { FLDATA (STOP_INST
, stop_inst
, 0) },
328 { FLDATA (STOP_DEV
, stop_dev
, 1) },
329 { DRDATA (INDMAX
, ind_max
, 8), REG_NZ
+ PV_LEFT
},
330 { BRDATA (PCQ
, pcq
, 8, 15, PCQ_SIZE
), REG_RO
+ REG_CIRC
},
331 { ORDATA (PCQP
, pcq_p
, 6), REG_HRO
},
332 { ORDATA (WRU
, sim_int_char
, 8) },
337 { UNIT_EXT
, 0, "no extend", "NOEXTEND", &cpu_set_noext
},
338 { UNIT_EXT
, UNIT_EXT
, "extend", "EXTEND", NULL
},
339 { UNIT_HSA
, 0, "no HSA", "NOHSA", NULL
},
340 { UNIT_HSA
, UNIT_HSA
, "HSA", "HSA", NULL
},
341 { UNIT_MSIZE
, 4096, NULL
, "4K", &cpu_set_size
},
342 { UNIT_MSIZE
, 8192, NULL
, "8K", &cpu_set_size
},
343 { UNIT_MSIZE
, 12288, NULL
, "12K", &cpu_set_size
},
344 { UNIT_MSIZE
, 16384, NULL
, "16K", &cpu_set_size
},
345 { UNIT_MSIZE
, 24576, NULL
, "24K", &cpu_set_size
},
346 { UNIT_MSIZE
, 32768, NULL
, "32K", &cpu_set_size
},
347 { MTAB_XTD
| MTAB_VDV
, 0, "channels", "CHANNELS",
348 &cpu_set_nchan
, &cpu_show_nchan
, NULL
},
349 { UNIT_DMC
, 0, "no DMC", "NODMC", NULL
},
350 { UNIT_DMC
, UNIT_DMC
, "DMC", "DMC", NULL
},
351 { MTAB_XTD
|MTAB_VDV
|MTAB_NMO
|MTAB_SHP
, 0, "HISTORY", "HISTORY",
352 &cpu_set_hist
, &cpu_show_hist
},
353 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 0, "DMA1", NULL
,
354 NULL
, &cpu_show_dma
, NULL
},
355 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 1, "DMA2", NULL
,
356 NULL
, &cpu_show_dma
, NULL
},
357 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 2, "DMA3", NULL
,
358 NULL
, &cpu_show_dma
, NULL
},
359 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 3, "DMA4", NULL
,
360 NULL
, &cpu_show_dma
, NULL
},
365 "CPU", &cpu_unit
, cpu_reg
, cpu_mod
,
367 &cpu_ex
, &cpu_dep
, &cpu_reset
,
372 t_stat
sim_instr (void)
374 int32 AR
, BR
, MB
, Y
, t1
, t2
, t3
, skip
, dev
;
377 t_stat
Ea (int32 inst
, int32
*addr
);
378 void Write (int32 addr
, int32 val
);
379 int32
Add16 (int32 val1
, int32 val2
);
380 int32
Add31 (int32 val1
, int32 val2
);
381 int32
Operate (int32 MB
, int32 AR
);
383 #define Read(ad) M[(ad)]
384 #define GETDBL_S(h,l) (((h) << 15) | ((l) & MMASK))
385 #define GETDBL_U(h,l) (((h) << 16) | (l))
386 #define PUTDBL_S(x) AR = ((x) >> 15) & DMASK; \
387 BR = (BR & SIGN) | ((x) & MMASK)
388 #define PUTDBL_U(x) AR = ((x) >> 16) & DMASK; \
390 #define SEXT(x) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK))
391 #define NEWA(c,n) (ext? (((c) & ~X_AMASK) | ((n) & X_AMASK)): \
392 (((c) & ~NX_AMASK) | ((n) & NX_AMASK)))
394 /* Restore register state */
396 if (devtab_init ()) return SCPE_STOP
; /* init tables */
397 AR
= saved_AR
& DMASK
; /* restore reg */
398 BR
= saved_BR
& DMASK
;
399 XR
= saved_XR
& DMASK
;
400 PC
= PC
& ((cpu_unit
.flags
& UNIT_EXT
)? X_AMASK
: NX_AMASK
); /* mask PC */
403 /* Main instruction fetch/decode loop */
405 while (reason
== 0) { /* loop until halted */
407 if (sim_interval
<= 0) { /* check clock queue */
408 if (reason
= sim_process_event ()) break;
411 /* Channel breaks (DMA and DMC) */
413 if (chan_req
) { /* channel request? */
414 int32 i
, t
, ch
, dev
, st
, end
, ad
, dmcad
;
416 for (i
= 0, ch
= chan_req
; ch
!= 0; i
++, ch
= ch
>> 1) {
417 if (ch
& 1) { /* req on chan i? */
418 dev
= chan_map
[i
]; /* get dev for chan */
419 if (iotab
[dev
] == &undio
) return SCPE_IERR
;
420 chan_req
= chan_req
& ~(1 << i
); /* clear req */
421 if (Q_DMA (i
)) st
= dma_ad
[i
]; /* DMA? */
423 dmcad
= DMC_BASE
+ ((i
- DMC_V_DMC1
) << 1);
424 st
= Read (dmcad
); /* DMC ctrl word */
426 ad
= st
& X_AMASK
; /* get curr addr */
427 if (st
& DMA_IN
) { /* input? */
428 t
= iotab
[dev
] (ioINA
, 0, 0, dev
); /* input word */
429 if ((t
& IOT_SKIP
) == 0) return STOP_DMAER
;
430 if ((r
= t
>> IOT_V_REASON
) != 0) return r
;
431 Write (ad
, t
& DMASK
); /* write to mem */
433 else { /* no, output */
434 t
= iotab
[dev
] (ioOTA
, 0, Read (ad
), dev
); /* output word */
435 if ((t
& IOT_SKIP
) == 0) return STOP_DMAER
;
436 if (r
= (t
>> IOT_V_REASON
)) return r
;
438 if (Q_DMA (i
)) { /* DMA? */
439 dma_ad
[i
] = (dma_ad
[i
] & DMA_IN
) | ((ad
+ 1) & X_AMASK
);
440 dma_wc
[i
] = (dma_wc
[i
] + 1) & 077777; /* update wc */
441 if (dma_wc
[i
] == 0) { /* done? */
442 dma_eor
[i
] = 1; /* set end of range */
443 t
= iotab
[dev
] (ioEND
, 0, 0, dev
); /* send end range */
444 if ((r
= t
>> IOT_V_REASON
) != 0) return r
;
448 st
= (st
& DMA_IN
) | ((ad
+ 1) & X_AMASK
);
449 Write (dmcad
, st
); /* update start */
450 end
= Read (dmcad
+ 1); /* get end */
451 if (((ad
^ end
) & X_AMASK
) == 0) { /* start == end? */
452 t
= iotab
[dev
] (ioEND
, 0, 0, dev
); /* send end range */
453 if ((r
= t
>> IOT_V_REASON
) != 0) return r
;
454 } /* end if end range */
456 } /* end if chan i */
458 } /* end if chan_req */
463 if ((dev_int
& (INT_PEND
|INT_NMI
|dev_enb
)) > INT_PEND
) {/* int req? */
464 pme
= ext
; /* save extend */
465 if (cpu_unit
.flags
& UNIT_EXT
) ext
= 1; /* ext opt? extend on */
466 dev_int
= dev_int
& ~INT_ON
; /* intr off */
467 MB
= 0120000 | M_INT
; /* inst = JST* 63 */
470 /* Instruction fetch */
474 sim_brk_test (PC
, SWMASK ('E'))) { /* breakpoint? */
475 reason
= STOP_IBKPT
; /* stop simulation */
478 Y
= PC
; /* set mem addr */
479 MB
= Read (Y
); /* fetch instr */
480 PC
= NEWA (Y
, Y
+ 1); /* incr PC */
481 dev_int
= dev_int
| INT_NODEF
;
484 dev_int
= dev_int
& ~INT_START
; /* clr start button int */
485 sim_interval
= sim_interval
- 1;
486 if (hst_lnt
) { /* instr hist? */
487 hst_p
= (hst_p
+ 1); /* next entry */
488 if (hst_p
>= hst_lnt
) hst_p
= 0;
489 hst
[hst_p
].pc
= Y
| HIST_PC
| (C
? HIST_C
: 0); /* fill slots */
496 /* Memory reference instructions */
498 switch (I_GETOP (MB
)) { /* case on <1:6> */
500 case 001: case 021: case 041: case 061: /* JMP */
501 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
502 PCQ_ENTRY
; /* save PC */
503 PC
= NEWA (PC
, Y
); /* set new PC */
504 if (extoff_pending
) ext
= extoff_pending
= 0; /* cond ext off */
507 case 002: case 022: case 042: case 062: /* LDA */
508 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
509 if (dp
) { /* double prec? */
510 AR
= Read (Y
& ~1); /* get doubleword */
514 else AR
= Read (Y
); /* no, get word */
517 case 003: case 023: case 043: case 063: /* ANA */
518 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
522 case 004: case 024: case 044: case 064: /* STA */
523 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
524 Write (Y
, AR
); /* store A */
525 if (dp
) { /* double prec? */
526 Write (Y
| 1, BR
); /* store B */
531 case 005: case 025: case 045: case 065: /* ERA */
532 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
536 case 006: case 026: case 046: case 066: /* ADD */
537 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
538 if (dp
) { /* double prec? */
539 t1
= GETDBL_S (AR
, BR
); /* get A'B */
540 t2
= GETDBL_S (Read (Y
& ~1), Read (Y
| 1));
541 t1
= Add31 (t1
, t2
); /* 31b add */
545 else AR
= Add16 (AR
, Read (Y
)); /* no, 16b add */
548 case 007: case 027: case 047: case 067: /* SUB */
549 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
550 if (dp
) { /* double prec? */
551 t1
= GETDBL_S (AR
, BR
); /* get A'B */
552 t2
= GETDBL_S (Read (Y
& ~1), Read (Y
| 1));
553 t1
= Add31 (t1
, -t2
); /* 31b sub */
557 else AR
= Add16 (AR
, (-Read (Y
)) & DMASK
); /* no, 16b sub */
560 case 010: case 030: case 050: case 070: /* JST */
561 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
562 MB
= NEWA (Read (Y
), PC
); /* merge old PC */
565 PC
= NEWA (PC
, Y
+ 1); /* set new PC */
568 case 011: case 031: case 051: case 071: /* CAS */
569 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
571 if (AR
== MB
) PC
= NEWA (PC
, PC
+ 1);
572 else if (SEXT (AR
) < SEXT (MB
)) PC
= NEWA (PC
, PC
+ 2);
575 case 012: case 032: case 052: case 072: /* IRS */
576 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
577 MB
= (Read (Y
) + 1) & DMASK
; /* incr, rewrite */
579 if (MB
== 0) PC
= NEWA (PC
, PC
+ 1); /* skip if zero */
582 case 013: case 033: case 053: case 073: /* IMA */
583 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
585 Write (Y
, AR
); /* A to mem */
586 AR
= MB
; /* mem to A */
589 case 015: case 055: /* STX */
590 if (reason
= Ea (MB
& ~IDX
, &Y
)) break; /* eff addr */
591 Write (Y
, XR
); /* store XR */
594 case 035: case 075: /* LDX */
595 if (reason
= Ea (MB
& ~IDX
, &Y
)) break; /* eff addr */
596 XR
= Read (Y
); /* load XR */
599 case 016: case 036: case 056: case 076: /* MPY */
600 if (cpu_unit
.flags
& UNIT_HSA
) { /* installed? */
601 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
602 t1
= SEXT (AR
) * SEXT (Read (Y
));
606 else reason
= stop_inst
;
609 case 017: case 037: case 057: case 077: /* DIV */
610 if (cpu_unit
.flags
& UNIT_HSA
) { /* installed? */
611 if (reason
= Ea (MB
, &Y
)) break; /* eff addr */
612 t2
= SEXT (Read (Y
)); /* divr */
613 if (t2
) { /* divr != 0? */
614 t1
= GETDBL_S (SEXT (AR
), BR
); /* get A'B signed */
615 BR
= (t1
% t2
) & DMASK
; /* remainder */
616 t1
= t1
/ t2
; /* quotient */
618 if ((t1
> MMASK
) || (t1
< (-SIGN
))) C
= 1;
624 else reason
= stop_inst
;
627 /* I/O instructions */
631 t2
= iotab
[dev
] (ioOCP
, I_GETFNC (MB
), AR
, dev
);
632 reason
= t2
>> IOT_V_REASON
;
637 t2
= iotab
[dev
] (ioSKS
, I_GETFNC (MB
), AR
, dev
);
638 reason
= t2
>> IOT_V_REASON
;
639 if (t2
& IOT_SKIP
) PC
= NEWA (PC
, PC
+ 1); /* skip? */
644 if (MB
& INCLRA
) AR
= 0;
645 t2
= iotab
[dev
] (ioINA
, I_GETFNC (MB
& ~INCLRA
), AR
, dev
);
646 reason
= t2
>> IOT_V_REASON
;
647 if (t2
& IOT_SKIP
) PC
= NEWA (PC
, PC
+ 1); /* skip? */
648 AR
= t2
& DMASK
; /* data */
653 t2
= iotab
[dev
] (ioOTA
, I_GETFNC (MB
), AR
, dev
);
654 reason
= t2
>> IOT_V_REASON
;
655 if (t2
& IOT_SKIP
) PC
= NEWA (PC
, PC
+ 1); /* skip? */
661 if ((MB
& 1) == 0) { /* HLT */
662 if ((reason
= sim_process_event ()) != SCPE_OK
) break;
666 if (MB
& m14
) { /* SGL, DBL */
667 if (cpu_unit
.flags
& UNIT_HSA
) dp
= (MB
& m15
)? 1: 0;
668 else reason
= stop_inst
;
670 if (MB
& m13
) { /* DXA, EXA */
671 if (!(cpu_unit
.flags
& UNIT_EXT
)) reason
= stop_inst
;
672 else if (MB
& m15
) { /* EXA */
674 extoff_pending
= 0; /* DXA */
676 else extoff_pending
= 1;
678 if (MB
& m12
) CLR_INT (INT_MPE
); /* RMP */
679 if (MB
& m11
) { /* SCA, INK */
680 if (MB
& m15
) /* INK */
681 AR
= (C
<< 15) | (dp
<< 14) | (pme
<< 13) | (sc
& 037);
682 else if (cpu_unit
.flags
& UNIT_HSA
) /* SCA */
684 else reason
= stop_inst
;
686 else if (MB
& m10
) { /* NRM */
687 if (cpu_unit
.flags
& UNIT_HSA
) {
689 (sc
<= 32) && ((AR
& SIGN
) != ((AR
<< 1) & SIGN
));
691 AR
= (AR
& SIGN
) | ((AR
<< 1) & MMASK
) |
693 BR
= (BR
& SIGN
) | ((BR
<< 1) & MMASK
);
697 else reason
= stop_inst
;
699 else if (MB
& m9
) { /* IAB */
704 if (MB
& m8
) /* ENB */
705 dev_int
= (dev_int
| INT_ON
) & ~INT_NODEF
;
706 if (MB
& m7
) /* INH */
707 dev_int
= dev_int
& ~INT_ON
;
712 Shifts are microcoded as follows:
716 op<9> = shift/rotate (rotate bits "or" into new position)
717 op<10> = logical/arithmetic
719 If !op<7> && op<10> (right arithmetic), A<1> propagates rightward
720 If op<7> && op<10> (left arithmetic), C is set if A<1> changes state
721 If !op<8> && op<10> (long arithmetic), B<1> is skipped
723 This microcoding "explains" how the 4 undefined opcodes actually work
724 003 = long arith rotate right, skip B<1>, propagate A<1>,
725 bits rotated out "or" into A<1>
726 007 = short arith rotate right, propagate A<1>,
727 bits rotated out "or" into A<1>
728 013 = long arith rotate left, skip B<1>, C = overflow
729 017 = short arith rotate left, C = overflow
734 sc
= 0; /* clear sc */
735 if ((t1
= (-MB
) & SHFMASK
) == 0) break; /* shift count */
736 switch (I_GETFNC (MB
)) { /* case shift fnc */
739 if (t1
> 32) ut
= 0; /* >32? all 0 */
741 ut
= GETDBL_U (AR
, BR
); /* get A'B */
742 C
= (ut
>> (t1
- 1)) & 1; /* C = last out */
743 if (t1
== 32) ut
= 0; /* =32? all 0 */
744 else ut
= ut
>> t1
; /* log right */
746 PUTDBL_U (ut
); /* store A,B */
750 if (t1
> 31) t1
= 31; /* limit to 31 */
751 t2
= GETDBL_S (SEXT (AR
), BR
); /* get A'B signed */
752 C
= (t2
>> (t1
- 1)) & 1; /* C = last out */
753 t2
= t2
>> t1
; /* arith right */
754 PUTDBL_S (t2
); /* store A,B */
758 t2
= t1
% 32; /* mod 32 */
759 ut
= GETDBL_U (AR
, BR
); /* get A'B */
760 ut
= (ut
>> t2
) | (ut
<< (32 - t2
)); /* rot right */
761 C
= (ut
>> 31) & 1; /* C = A<1> */
762 PUTDBL_U (ut
); /* store A,B */
765 case 003: /* "long right arot" */
766 if (reason
= stop_inst
) break; /* stop on undef? */
767 for (t2
= 0; t2
< t1
; t2
++) { /* bit by bit */
768 C
= BR
& 1; /* C = last out */
769 BR
= (BR
& SIGN
) | ((AR
& 1) << 14) |
771 AR
= ((AR
& SIGN
) | (C
<< 15)) | (AR
>> 1);
776 if (t1
> 16) AR
= 0; /* > 16? all 0 */
778 C
= (AR
>> (t1
- 1)) & 1; /* C = last out */
779 AR
= (AR
>> t1
) & DMASK
; /* log right */
784 if (t1
> 16) t1
= 16; /* limit to 16 */
785 C
= ((SEXT (AR
)) >> (t1
- 1)) & 1; /* C = last out */
786 AR
= ((SEXT (AR
)) >> t1
) & DMASK
; /* arith right */
790 t2
= t1
% 16; /* mod 16 */
791 AR
= ((AR
>> t2
) | (AR
<< (16 - t2
))) & DMASK
;
792 C
= (AR
>> 15) & 1; /* C = A<1> */
795 case 007: /* "short right arot" */
796 if (reason
= stop_inst
) break; /* stop on undef? */
797 for (t2
= 0; t2
< t1
; t2
++) { /* bit by bit */
798 C
= AR
& 1; /* C = last out */
799 AR
= ((AR
& SIGN
) | (C
<< 15)) | (AR
>> 1);
804 if (t1
> 32) ut
= 0; /* > 32? all 0 */
806 ut
= GETDBL_U (AR
, BR
); /* get A'B */
807 C
= (ut
>> (32 - t1
)) & 1; /* C = last out */
808 if (t1
== 32) ut
= 0; /* =32? all 0 */
809 else ut
= ut
<< t1
; /* log left */
811 PUTDBL_U (ut
); /* store A,B */
815 if (t1
> 31) t1
= 31; /* limit to 31 */
816 t2
= GETDBL_S (SEXT (AR
), BR
); /* get A'B */
817 t3
= t2
<< t1
; /* "arith" left */
818 PUTDBL_S (t3
); /* store A'B */
819 if ((t2
>> (31 - t1
)) != /* shf out = sgn? */
820 ((AR
& SIGN
)? -1: 0)) C
= 1;
824 t2
= t1
% 32; /* mod 32 */
825 ut
= GETDBL_U (AR
, BR
); /* get A'B */
826 ut
= (ut
<< t2
) | (ut
>> (32 - t2
)); /* rot left */
827 C
= ut
& 1; /* C = B<16> */
828 PUTDBL_U (ut
); /* store A,B */
831 case 013: /* "long left arot" */
832 if (reason
= stop_inst
) break; /* stop on undef? */
833 for (t2
= 0; t2
< t1
; t2
++) { /* bit by bit */
834 AR
= (AR
<< 1) | ((BR
>> 14) & 1);
835 BR
= (BR
& SIGN
) | ((BR
<< 1) & MMASK
) |
837 if ((AR
& SIGN
) != ((AR
>> 1) & SIGN
)) C
= 1;
843 if (t1
> 16) AR
= 0; /* > 16? all 0 */
845 C
= (AR
>> (16 - t1
)) & 1; /* C = last out */
846 AR
= (AR
<< t1
) & DMASK
; /* log left */
851 if (t1
> 16) t1
= 16; /* limit to 16 */
852 t2
= SEXT (AR
); /* save AR */
853 AR
= (AR
<< t1
) & DMASK
; /* "arith" left */
854 if ((t2
>> (16 - t1
)) != /* shf out + sgn */
855 ((AR
& SIGN
)? -1: 0)) C
= 1;
859 t2
= t1
% 16; /* mod 16 */
860 AR
= ((AR
<< t2
) | (AR
>> (16 - t2
))) & DMASK
;
861 C
= AR
& 1; /* C = A<16> */
864 case 017: /* "short left arot" */
865 if (reason
= stop_inst
) break; /* stop on undef? */
866 for (t2
= 0; t2
< t1
; t2
++) { /* bit by bit */
867 if ((AR
& SIGN
) != ((AR
<< 1) & SIGN
)) C
= 1;
868 AR
= ((AR
<< 1) | (AR
>> 15)) & DMASK
;
870 break; /* end case fnc */
878 if (((MB
& 000001) && C
) || /* SSC */
879 ((MB
& 000002) && ss
[3]) || /* SS4 */
880 ((MB
& 000004) && ss
[2]) || /* SS3 */
881 ((MB
& 000010) && ss
[1]) || /* SS2 */
882 ((MB
& 000020) && ss
[0]) || /* SS1 */
883 ((MB
& 000040) && AR
) || /* SNZ */
884 ((MB
& 000100) && (AR
& 1)) || /* SLN */
885 ((MB
& 000200) && (TST_INTREQ (INT_MPE
))) || /* SPS */
886 ((MB
& 000400) && (AR
& SIGN
))) skip
= 1; /* SMI */
887 if ((MB
& 001000) == 0) skip
= skip
^ 1; /* reverse? */
888 PC
= NEWA (PC
, PC
+ skip
);
894 if (MB
== 0140024) AR
= AR
^ SIGN
; /* CHS */
895 else if (MB
== 0140040) AR
= 0; /* CRA */
896 else if (MB
== 0140100) AR
= AR
& ~SIGN
; /* SSP */
897 else if (MB
== 0140200) C
= 0; /* RCB */
898 else if (MB
== 0140320) { /* CSA */
899 C
= (AR
& SIGN
) >> 15;
902 else if (MB
== 0140401) AR
= AR
^ DMASK
; /* CMA */
903 else if (MB
== 0140407) { /* TCA */
907 else if (MB
== 0140500) AR
= AR
| SIGN
; /* SSM */
908 else if (MB
== 0140600) C
= 1; /* SCB */
909 else if (MB
== 0141044) AR
= AR
& 0177400; /* CAR */
910 else if (MB
== 0141050) AR
= AR
& 0377; /* CAL */
911 else if (MB
== 0141140) AR
= AR
>> 8; /* ICL */
912 else if (MB
== 0141206) AR
= Add16 (AR
, 1); /* AOA */
913 else if (MB
== 0141216) AR
= Add16 (AR
, C
); /* ACA */
914 else if (MB
== 0141240) AR
= (AR
<< 8) & DMASK
; /* ICR */
915 else if (MB
== 0141340) /* ICA */
916 AR
= ((AR
<< 8) | (AR
>> 8)) & DMASK
;
917 else if (reason
= stop_inst
) break;
918 else AR
= Operate (MB
, AR
); /* undefined */
923 saved_AR
= AR
& DMASK
;
924 saved_BR
= BR
& DMASK
;
925 saved_XR
= XR
& DMASK
;
926 pcq_r
->qptr
= pcq_p
; /* update pc q ptr */
932 The effective address calculation consists of three phases:
933 - base address calculation: 0/pagenumber'displacement
934 - (extend): indirect address resolution
935 (non-extend): pre-indexing
936 - (extend): post-indexing
937 (non-extend): indirect address/post-indexing resolution
939 In extend mode, address calculations are carried out to 16b
940 and masked to 15b at exit. In non-extend mode, address bits
941 <1:2> are preserved by the NEWA macro; address bit <1> is
945 t_stat
Ea (int32 IR
, int32
*addr
)
948 int32 Y
= IR
& (IA
| DISP
); /* ind + disp */
950 if (IR
& SC
) Y
= ((PC
- 1) & PAGENO
) | Y
; /* cur sec? + pageno */
951 if (ext
) { /* extend mode? */
952 for (i
= 0; (i
< ind_max
) && (Y
& IA
); i
++) { /* resolve ind addr */
953 Y
= Read (Y
& X_AMASK
); /* get ind addr */
955 if (IR
& IDX
) Y
= Y
+ XR
; /* post-index */
957 else { /* non-extend */
958 Y
= NEWA (PC
, Y
+ ((IR
& IDX
)? XR
: 0)); /* pre-index */
959 for (i
= 0; (i
< ind_max
) && (IR
& IA
); i
++) { /* resolve ind addr */
960 IR
= Read (Y
& X_AMASK
); /* get ind addr */
961 Y
= NEWA (Y
, IR
+ ((IR
& IDX
)? XR
: 0)); /* post-index */
964 *addr
= Y
= Y
& X_AMASK
; /* return addr */
965 if (hst_lnt
) { /* history? */
966 hst
[hst_p
].pc
= hst
[hst_p
].pc
| HIST_EA
;
968 hst
[hst_p
].opnd
= Read (Y
);
970 if (i
>= ind_max
) return STOP_IND
; /* too many ind? */
976 void Write (int32 addr
, int32 val
)
978 if (((addr
== 0) || (addr
>= 020)) && MEM_ADDR_OK (addr
))
985 int32
Add16 (int32 v1
, int32 v2
)
989 if (((v1
^ ~v2
) & (v1
^ r
)) & SIGN
) C
= 1;
994 int32
Add31 (int32 v1
, int32 v2
)
998 if (((v1
^ ~v2
) & (v1
^ r
)) & DP_SIGN
) C
= 1;
1003 /* Unimplemented I/O device */
1005 int32
undio (int32 op
, int32 fnc
, int32 val
, int32 dev
)
1007 return ((stop_dev
<< IOT_V_REASON
) | val
);
1012 int32
dmaio (int32 inst
, int32 fnc
, int32 dat
, int32 dev
)
1014 int32 ch
= (fnc
- 1) & 03;
1016 switch (inst
) { /* case on opcode */
1018 case ioOCP
: /* OCP */
1019 if ((fnc
>= 001) && (fnc
<= 004)) { /* load addr ctr */
1024 else if ((fnc
>= 011) && (fnc
<= 014)) /* load range ctr */
1025 dma_wc
[ch
] = (dma_wc
[ch
] | dat
) & 077777;
1026 else return IOBADFNC (dat
); /* undefined */
1029 case ioINA
: /* INA */
1030 if ((fnc
>= 011) && (fnc
<= 014)) {
1031 if (dma_eor
[ch
]) return dat
; /* end range? nop */
1032 return IOSKIP (0100000 | dma_wc
[ch
]); /* return range */
1034 else return IOBADFNC (dat
);
1040 /* Undefined operate instruction. This code is reached when the
1041 opcode does not correspond to a standard operate instruction.
1042 It simulates the behavior of the actual logic.
1044 An operate instruction executes in 4 or 6 phases. A 'normal'
1045 instruction takes 4 phases:
1048 t2/tlate t2/t2 extended into t3
1052 A '1.5 cycle' instruction takes 6 phases:
1055 t2/tlate t2/t2 extended into t3
1057 t2/tlate 'special' t2/t2 extended into t3
1061 The key signals, by phase, are the following
1063 tlate EASTL enable A to sum leg 1 (else 0)
1064 (((m12+m16)x!azzzz)+(m9+m11+azzzz)
1065 EASBM enable 0 to sum leg 2 (else 177777)
1067 JAMKN jam carry network to 0 = force XOR
1069 EIKI7 force carry into adder
1070 ((m15x(C+!m13))x!JAMKN)
1072 t3 CLDTR set D to 177777 (always)
1073 ESDTS enable adder sum to D (always)
1074 SETAZ enable repeat cycle = set azzzz
1078 t2 CLATR clear A register (due to azzzz)
1079 EDAHS enable D high to A high register (due to azzzz)
1080 EDALS enable D low to A low register (due to azzzz)
1085 t4 CLATR clear A register
1087 CLA1R clear A1 register
1089 EDAHS enable D high to A high register
1091 EDALS enable D low to A low register
1093 ETAHS enable D transposed to A high register
1095 ETALS enable D transposed to A low register
1097 EDA1R enable D1 to A1 register
1099 CBITL clear C, conditionally set C from adder output
1101 CBITG conditionally set C if D1
1103 CBITE unconditionally set C
1107 int32
Operate (int32 MB
, int32 AR
)
1109 int32 D
, jamkn
, eiki7
, easbm
, eastl
, setaz
;
1110 int32 clatr
, cla1r
, edahs
, edals
, etahs
, etals
, eda1r
;
1111 int32 cbitl
, cbitg
, cbite
;
1112 int32 aleg
, bleg
, ARx
;
1116 ARx
= AR
; /* default */
1117 jamkn
= (MB
& (m12
+m16
)) != 0; /* m12+m16 */
1118 easbm
= (MB
& (m9
+m11
)) != 0; /* m9+m11 */
1119 eastl
= jamkn
|| easbm
; /* m9+m11+m12+m16 */
1120 setaz
= (MB
& (m8
+m15
)) == (m8
+m15
); /* m8xm15*/
1121 eiki7
= (MB
& m15
) && (C
|| !(MB
& m13
)); /* cin */
1122 aleg
= eastl
? AR
: 0; /* a input */
1123 bleg
= easbm
? 0: DMASK
; /* b input */
1124 if (jamkn
) D
= aleg
^ bleg
; /* jammin? xor */
1125 else D
= (aleg
+ bleg
+ eiki7
) & DMASK
; /* else add */
1127 /* Possible repeat at end of tlate - special t2, repeat tlate */
1130 ARx
= D
; /* forced: t2 */
1131 aleg
= ARx
; /* forced: tlate */
1132 bleg
= 0; /* forced */
1133 jamkn
= 0; /* forced */
1134 D
= (aleg
+ bleg
+ eiki7
) & DMASK
; /* forced add */
1135 sc
= 0; /* ends repeat */
1140 clatr
= (MB
& (m11
+m15
+m16
)) != 0; /* m11+m15+m16 */
1141 cla1r
= (MB
& (m10
+m14
)) != 0; /* m10+m14 */
1142 edahs
= ((MB
& (m11
+m14
)) == (m11
+m14
)) || /* (m11xm14)+m15+m16 */
1144 edals
= ((MB
& (m11
+m13
)) == (m11
+m13
)) || /* (m11xm13)+m15+m16 */
1146 etahs
= (MB
& (m9
+m11
)) == (m9
+m11
); /* m9xm11 */
1147 etals
= (MB
& (m10
+m11
)) == (m10
+m11
); /* m10xm11 */
1148 eda1r
= ((MB
& (m8
+m10
)) == (m8
+m10
)) || (MB
& m14
); /* (m8xm10)+m14 */
1149 cbitl
= (MB
& (m9
+m11
)) == m9
; /* m9x!m11 */
1150 cbite
= (MB
& (m8
+m9
)) == (m8
+m9
); /* m8xm9 */
1151 cbitg
= (MB
& (m10
+m12
)) == (m10
+m12
); /* m10xm12 */
1153 if (clatr
) ARx
= 0; /* clear A */
1154 if (cla1r
) ARx
= ARx
& ~SIGN
; /* clear A1 */
1155 if (edahs
) ARx
= ARx
| (D
& 0177400); /* D hi to A hi */
1156 if (edals
) ARx
= ARx
| (D
& 0000377); /* D lo to A lo */
1157 if (etahs
) ARx
= ARx
| ((D
<< 8) & 0177400); /* D lo to A hi */
1158 if (etals
) ARx
= ARx
| ((D
>> 8) & 0000377); /* D hi to A lo */
1159 if (eda1r
) ARx
= ARx
| (D
& SIGN
); /* D1 to A1 */
1160 if (cbitl
) { /* ovflo to C */
1162 /* Overflow calculation. Cases:
1164 aleg bleg cin overflow
1166 0 x x can't overflow
1167 A 0 0 can't overflow
1168 A -1 1 can't overflow
1169 A 0 1 overflow if 77777->100000
1170 A -1 0 overflow if 100000->77777
1174 ((bleg
&& !eiki7
&& (D
== 0077777)) ||
1175 (!bleg
&& eiki7
&& (D
== 0100000)))) C
= 1;
1178 if (cbite
|| (cbitg
&& (D
& SIGN
))) C
= 1; /* C = 1 */
1182 /* Reset routines */
1184 t_stat
cpu_reset (DEVICE
*dptr
)
1188 saved_AR
= saved_BR
= saved_XR
= 0;
1191 ext
= pme
= extoff_pending
= 0;
1192 dev_int
= dev_int
& ~(INT_PEND
|INT_NMI
);
1194 for (i
= 0; i
< DMA_MAX
; i
++) dma_ad
[i
] = dma_wc
[i
] = dma_eor
[i
] = 0;
1196 pcq_r
= find_reg ("PCQ", NULL
, dptr
);
1197 if (pcq_r
) pcq_r
->qptr
= 0;
1198 else return SCPE_IERR
;
1199 sim_brk_types
= sim_brk_dflt
= SWMASK ('E');
1203 /* Memory examine */
1205 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1209 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1210 if (addr
== 0) d
= saved_XR
;
1212 if (vptr
!= NULL
) *vptr
= d
& DMASK
;
1216 /* Memory deposit */
1218 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1220 if (addr
>= MEMSIZE
) return SCPE_NXM
;
1221 if (addr
== 0) saved_XR
= val
& DMASK
;
1222 else M
[addr
] = val
& DMASK
;
1226 /* Option processors */
1228 t_stat
cpu_set_noext (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1230 if (MEMSIZE
> (NX_AMASK
+ 1)) return SCPE_ARG
;
1234 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1239 if ((val
<= 0) || (val
> MAXMEMSIZE
) || ((val
& 07777) != 0) ||
1240 (((cpu_unit
.flags
& UNIT_EXT
) == 0) && (val
> (NX_AMASK
+ 1))))
1242 for (i
= val
; i
< MEMSIZE
; i
++) mc
= mc
| M
[i
];
1243 if ((mc
!= 0) && (!get_yn ("Really truncate memory [N]?", FALSE
)))
1246 for (i
= MEMSIZE
; i
< MAXMEMSIZE
; i
++) M
[i
] = 0;
1250 t_stat
cpu_set_nchan (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1255 if (cptr
== NULL
) return SCPE_ARG
;
1256 newmax
= get_uint (cptr
, 10, DMA_MAX
, &r
); /* get new max */
1257 if ((r
!= SCPE_OK
) || (newmax
== dma_nch
)) return r
; /* err or no chg? */
1258 dma_nch
= newmax
; /* set new max */
1259 for (i
= newmax
; i
< DMA_MAX
; i
++) { /* reset chan */
1260 dma_ad
[i
] = dma_wc
[i
] = dma_eor
[i
] = 0;
1261 chan_req
= chan_req
& ~(1 << i
);
1266 /* Show DMA channels */
1268 t_stat
cpu_show_nchan (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1270 if (dma_nch
) fprintf (st
, "DMA channels = %d", dma_nch
);
1271 else fprintf (st
, "no DMA channels");
1275 /* Show channel state */
1277 t_stat
cpu_show_dma (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1279 if ((val
< 0) || (val
>= DMA_MAX
)) return SCPE_IERR
;
1280 fputs ((dma_ad
[val
] & DMA_IN
)? "Input": "Output", st
);
1281 fprintf (st
, ", addr = %06o, count = %06o, ", dma_ad
[val
] & X_AMASK
, dma_wc
[val
]);
1282 fprintf (st
, "end of range %s\n", (dma_eor
[val
]? "set": "clear"));
1286 /* Set I/O device to IOBUS / DMA channel / DMC channel */
1288 t_stat
io_set_iobus (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1293 if (val
|| cptr
|| (uptr
== NULL
)) return SCPE_IERR
;
1294 dptr
= find_dev_from_unit (uptr
);
1295 if (dptr
== NULL
) return SCPE_IERR
;
1296 dibp
= (DIB
*) dptr
->ctxt
;
1297 if (dibp
== NULL
) return SCPE_IERR
;
1302 t_stat
io_set_dma (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1309 if ((cptr
== NULL
) || (uptr
== NULL
)) return SCPE_IERR
;
1310 dptr
= find_dev_from_unit (uptr
);
1311 if (dptr
== NULL
) return SCPE_IERR
;
1312 dibp
= (DIB
*) dptr
->ctxt
;
1313 if (dibp
== NULL
) return SCPE_IERR
;
1314 if (dma_nch
== 0) return SCPE_NOFNC
;
1315 newc
= get_uint (cptr
, 10, DMA_MAX
, &r
); /* get new */
1316 if ((r
!= SCPE_OK
) || (newc
== 0) || (newc
> dma_nch
)) return SCPE_ARG
;
1317 dibp
->chan
= (newc
- DMA_MIN
) + DMA_V_DMA1
+ 1; /* store */
1321 t_stat
io_set_dmc (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1328 if ((cptr
== NULL
) || (uptr
== NULL
)) return SCPE_IERR
;
1329 dptr
= find_dev_from_unit (uptr
);
1330 if (dptr
== NULL
) return SCPE_IERR
;
1331 dibp
= (DIB
*) dptr
->ctxt
;
1332 if (dibp
== NULL
) return SCPE_IERR
;
1333 if (!(cpu_unit
.flags
& UNIT_DMC
)) return SCPE_NOFNC
;
1334 newc
= get_uint (cptr
, 10, DMC_MAX
, &r
); /* get new */
1335 if ((r
!= SCPE_OK
) || (newc
== 0)) return SCPE_ARG
;
1336 dibp
->chan
= (newc
- DMC_MIN
) + DMC_V_DMC1
+ 1; /* store */
1340 /* Show channel configuration */
1342 t_stat
io_show_chan (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1347 if (uptr
== NULL
) return SCPE_IERR
;
1348 dptr
= find_dev_from_unit (uptr
);
1349 if (dptr
== NULL
) return SCPE_IERR
;
1350 dibp
= (DIB
*) dptr
->ctxt
;
1351 if (dibp
== NULL
) return SCPE_IERR
;
1352 if (dibp
->chan
== 0) fprintf (st
, "IO bus");
1353 else if (dibp
->chan
< (DMC_V_DMC1
+ 1))
1354 fprintf (st
, "DMA channel %d", dibp
->chan
);
1355 else fprintf (st
, "DMC channel %d", dibp
->chan
- DMC_V_DMC1
);
1359 /* Set up I/O dispatch and channel maps */
1361 t_bool
devtab_init (void)
1365 uint32 i
, j
, dno
, chan
;
1367 for (i
= 0; i
< DEV_MAX
; i
++) iotab
[i
] = NULL
;
1368 for (i
= 0; i
< (DMA_MAX
+ DMC_MAX
); i
++) chan_map
[i
] = 0;
1369 for (i
= 0; dptr
= sim_devices
[i
]; i
++) { /* loop thru devices */
1370 dibp
= (DIB
*) dptr
->ctxt
; /* get DIB */
1371 if ((dibp
== NULL
) || (dptr
->flags
& DEV_DIS
)) continue; /* exist, enabled? */
1372 dno
= dibp
->dev
; /* device number */
1373 for (j
= 0; j
< dibp
->num
; j
++) { /* repeat for slots */
1374 if (iotab
[dno
+ j
]) { /* conflict? */
1375 printf ("%s device number conflict, devno = %02o\n",
1376 sim_dname (dptr
), dno
+ j
);
1377 if (sim_log
) fprintf (sim_log
,
1378 "%s device number conflict, devno = %02o\n",
1379 sim_dname (dptr
), dno
+ j
);
1382 iotab
[dno
+ j
] = dibp
->io
; /* set I/O routine */
1384 if (dibp
->chan
) { /* DMA/DMC? */
1385 chan
= dibp
->chan
- 1;
1386 if ((chan
< DMC_V_DMC1
) && (chan
>= dma_nch
)) {
1387 printf ("%s configured for DMA channel %d\n",
1388 sim_dname (dptr
), chan
+ 1);
1389 if (sim_log
) fprintf (sim_log
,
1390 "%s configured for DMA channel %d\n",
1391 sim_dname (dptr
), chan
+ 1);
1394 if ((chan
>= DMC_V_DMC1
) && !(cpu_unit
.flags
& UNIT_DMC
)) {
1395 printf ("%s configured for DMC, option disabled\n",
1397 if (sim_log
) fprintf (sim_log
,
1398 "%s configured for DMC, option disabled\n",
1402 if (chan_map
[chan
]) { /* channel conflict? */
1403 printf ("%s DMA/DMC channel conflict, devno = %02o\n",
1404 sim_dname (dptr
), dno
);
1405 if (sim_log
) fprintf (sim_log
,
1406 "%s DMA/DMC channel conflict, devno = %02o\n",
1407 sim_dname (dptr
), dno
);
1410 chan_map
[chan
] = dno
; /* channel back map */
1413 for (i
= 0; i
< DEV_MAX
; i
++) { /* fill in blanks */
1414 if (iotab
[i
] == NULL
) iotab
[i
] = &undio
;
1421 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1427 for (i
= 0; i
< hst_lnt
; i
++) hst
[i
].pc
= 0;
1431 lnt
= (int32
) get_uint (cptr
, 10, HIST_MAX
, &r
);
1432 if ((r
!= SCPE_OK
) || (lnt
&& (lnt
< HIST_MIN
))) return SCPE_ARG
;
1440 hst
= (InstHistory
*) calloc (lnt
, sizeof (InstHistory
));
1441 if (hst
== NULL
) return SCPE_MEM
;
1449 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1451 int32 cr
, k
, di
, op
, lnt
;
1452 char *cptr
= (char *) desc
;
1456 extern t_stat
fprint_sym (FILE *ofile
, t_addr addr
, t_value
*val
,
1457 UNIT
*uptr
, int32 sw
);
1458 static uint8 has_opnd
[16] = {
1459 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1
1462 if (hst_lnt
== 0) return SCPE_NOFNC
; /* enabled? */
1464 lnt
= (int32
) get_uint (cptr
, 10, hst_lnt
, &r
);
1465 if ((r
!= SCPE_OK
) || (lnt
== 0)) return SCPE_ARG
;
1468 di
= hst_p
- lnt
; /* work forward */
1469 if (di
< 0) di
= di
+ hst_lnt
;
1470 fprintf (st
, "PC C A B X ea IR\n\n");
1471 for (k
= 0; k
< lnt
; k
++) { /* print specified */
1472 h
= &hst
[(++di
) % hst_lnt
]; /* entry pointer */
1473 if (h
->pc
& HIST_PC
) { /* instruction? */
1474 cr
= (h
->pc
& HIST_C
)? 1: 0; /* carry */
1475 fprintf (st
, "%05o %o %06o %06o %06o ",
1476 h
->pc
& X_AMASK
, cr
, h
->ar
, h
->br
, h
->xr
);
1477 if (h
->pc
& HIST_EA
) fprintf (st
, "%05o ", h
->ea
);
1478 else fprintf (st
, " ");
1480 if ((fprint_sym (st
, h
->pc
& X_AMASK
, &sim_eval
,
1481 &cpu_unit
, SWMASK ('M'))) > 0)
1482 fprintf (st
, "(undefined) %06o", h
->ir
);
1483 op
= I_GETOP (h
->ir
) & 017; /* base op */
1484 if (has_opnd
[op
]) fprintf (st
, " [%06o]", h
->opnd
);
1485 fputc ('\n', st
); /* end line */
1486 } /* end else instruction */