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