Commit | Line | Data |
---|---|---|
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 | |
222 | typedef 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 | |
232 | uint16 M[MAXMEMSIZE] = { 0 }; /* memory */\r | |
233 | int32 saved_AR = 0; /* A register */\r | |
234 | int32 saved_BR = 0; /* B register */\r | |
235 | int32 saved_XR = 0; /* X register */\r | |
236 | int32 PC = 0; /* P register */\r | |
237 | int32 C = 0; /* C register */\r | |
238 | int32 ext = 0; /* extend mode */\r | |
239 | int32 pme = 0; /* prev mode extend */\r | |
240 | int32 extoff_pending = 0; /* extend off pending */\r | |
241 | int32 dp = 0; /* double mode */\r | |
242 | int32 sc = 0; /* shift count */\r | |
243 | int32 ss[4]; /* sense switches */\r | |
244 | int32 dev_int = 0; /* dev ready */\r | |
245 | int32 dev_enb = 0; /* dev enable */\r | |
246 | int32 ind_max = 8; /* iadr nest limit */\r | |
247 | int32 stop_inst = 1; /* stop on ill inst */\r | |
248 | int32 stop_dev = 2; /* stop on ill dev */\r | |
249 | uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */\r | |
250 | int32 pcq_p = 0; /* PC queue ptr */\r | |
251 | REG *pcq_r = NULL; /* PC queue reg ptr */\r | |
252 | uint32 dma_nch = DMA_MAX; /* number of chan */\r | |
253 | uint32 dma_ad[DMA_MAX] = { 0 }; /* DMA addresses */\r | |
254 | uint32 dma_wc[DMA_MAX] = { 0 }; /* DMA word count */\r | |
255 | uint32 dma_eor[DMA_MAX] = { 0 }; /* DMA end of range */\r | |
256 | uint32 chan_req = 0; /* channel requests */\r | |
257 | uint32 chan_map[DMA_MAX + DMC_MAX] = { 0 }; /* chan->dev map */\r | |
258 | int32 (*iotab[DEV_MAX])(int32 inst, int32 fnc, int32 dat, int32 dev) = { NULL };\r | |
259 | int32 hst_p = 0; /* history pointer */\r | |
260 | int32 hst_lnt = 0; /* history length */\r | |
261 | InstHistory *hst = NULL; /* instruction history */\r | |
262 | \r | |
263 | extern int32 sim_int_char;\r | |
264 | extern int32 sim_interval;\r | |
265 | extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r | |
266 | extern FILE *sim_log;\r | |
267 | extern DEVICE *sim_devices[];\r | |
268 | \r | |
269 | t_bool devtab_init (void);\r | |
270 | int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev);\r | |
271 | int32 undio (int32 inst, int32 fnc, int32 dat, int32 dev);\r | |
272 | t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r | |
273 | t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r | |
274 | t_stat cpu_reset (DEVICE *dptr);\r | |
275 | t_stat cpu_set_noext (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
276 | t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
277 | t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
278 | t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
279 | t_stat cpu_show_dma (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
280 | t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
281 | t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
282 | \r | |
283 | extern 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 | |
294 | DIB cpu_dib = { DMA, IOBUS, 1, &dmaio };\r | |
295 | \r | |
296 | UNIT cpu_unit = {\r | |
297 | UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_EXT+UNIT_HSA+UNIT_DMC, MAXMEMSIZE)\r | |
298 | };\r | |
299 | \r | |
300 | REG 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 | |
336 | MTAB 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 | |
364 | DEVICE 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 | |
372 | t_stat sim_instr (void)\r | |
373 | {\r | |
374 | int32 AR, BR, MB, Y, t1, t2, t3, skip, dev;\r | |
375 | uint32 ut;\r | |
376 | t_stat reason;\r | |
377 | t_stat Ea (int32 inst, int32 *addr);\r | |
378 | void Write (int32 addr, int32 val);\r | |
379 | int32 Add16 (int32 val1, int32 val2);\r | |
380 | int32 Add31 (int32 val1, int32 val2);\r | |
381 | int32 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 | |
396 | if (devtab_init ()) return SCPE_STOP; /* init tables */\r | |
397 | AR = saved_AR & DMASK; /* restore reg */\r | |
398 | BR = saved_BR & DMASK;\r | |
399 | XR = saved_XR & DMASK;\r | |
400 | PC = PC & ((cpu_unit.flags & UNIT_EXT)? X_AMASK: NX_AMASK); /* mask PC */\r | |
401 | reason = 0;\r | |
402 | \r | |
403 | /* Main instruction fetch/decode loop */\r | |
404 | \r | |
405 | while (reason == 0) { /* loop until halted */\r | |
406 | \r | |
407 | if (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 | |
413 | if (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 | |
463 | if ((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 | |
472 | else {\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 | |
484 | dev_int = dev_int & ~INT_START; /* clr start button int */\r | |
485 | sim_interval = sim_interval - 1;\r | |
486 | if (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 | |
498 | switch (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 | |
923 | saved_AR = AR & DMASK;\r | |
924 | saved_BR = BR & DMASK;\r | |
925 | saved_XR = XR & DMASK;\r | |
926 | pcq_r->qptr = pcq_p; /* update pc q ptr */\r | |
927 | return 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 | |
945 | t_stat Ea (int32 IR, int32 *addr)\r | |
946 | {\r | |
947 | int32 i;\r | |
948 | int32 Y = IR & (IA | DISP); /* ind + disp */\r | |
949 | \r | |
950 | if (IR & SC) Y = ((PC - 1) & PAGENO) | Y; /* cur sec? + pageno */\r | |
951 | if (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 | |
957 | else { /* 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 | |
965 | if (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 | |
970 | if (i >= ind_max) return STOP_IND; /* too many ind? */\r | |
971 | return SCPE_OK;\r | |
972 | }\r | |
973 | \r | |
974 | /* Write memory */\r | |
975 | \r | |
976 | void Write (int32 addr, int32 val)\r | |
977 | {\r | |
978 | if (((addr == 0) || (addr >= 020)) && MEM_ADDR_OK (addr))\r | |
979 | M[addr] = val;\r | |
980 | return;\r | |
981 | }\r | |
982 | \r | |
983 | /* Add */\r | |
984 | \r | |
985 | int32 Add16 (int32 v1, int32 v2)\r | |
986 | {\r | |
987 | int32 r = v1 + v2;\r | |
988 | \r | |
989 | if (((v1 ^ ~v2) & (v1 ^ r)) & SIGN) C = 1;\r | |
990 | else C = 0;\r | |
991 | return (r & DMASK);\r | |
992 | }\r | |
993 | \r | |
994 | int32 Add31 (int32 v1, int32 v2)\r | |
995 | {\r | |
996 | int32 r = v1 + v2;\r | |
997 | \r | |
998 | if (((v1 ^ ~v2) & (v1 ^ r)) & DP_SIGN) C = 1;\r | |
999 | else C = 0;\r | |
1000 | return r;\r | |
1001 | }\r | |
1002 | \r | |
1003 | /* Unimplemented I/O device */\r | |
1004 | \r | |
1005 | int32 undio (int32 op, int32 fnc, int32 val, int32 dev)\r | |
1006 | {\r | |
1007 | return ((stop_dev << IOT_V_REASON) | val);\r | |
1008 | }\r | |
1009 | \r | |
1010 | /* DMA control */\r | |
1011 | \r | |
1012 | int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev)\r | |
1013 | {\r | |
1014 | int32 ch = (fnc - 1) & 03;\r | |
1015 | \r | |
1016 | switch (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 | |
1037 | return 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 | |
1107 | int32 Operate (int32 MB, int32 AR)\r | |
1108 | {\r | |
1109 | int32 D, jamkn, eiki7, easbm, eastl, setaz;\r | |
1110 | int32 clatr, cla1r, edahs, edals, etahs, etals, eda1r;\r | |
1111 | int32 cbitl, cbitg, cbite;\r | |
1112 | int32 aleg, bleg, ARx;\r | |
1113 | \r | |
1114 | /* Phase tlate */\r | |
1115 | \r | |
1116 | ARx = AR; /* default */\r | |
1117 | jamkn = (MB & (m12+m16)) != 0; /* m12+m16 */\r | |
1118 | easbm = (MB & (m9+m11)) != 0; /* m9+m11 */\r | |
1119 | eastl = jamkn || easbm; /* m9+m11+m12+m16 */\r | |
1120 | setaz = (MB & (m8+m15)) == (m8+m15); /* m8xm15*/\r | |
1121 | eiki7 = (MB & m15) && (C || !(MB & m13)); /* cin */\r | |
1122 | aleg = eastl? AR: 0; /* a input */\r | |
1123 | bleg = easbm? 0: DMASK; /* b input */\r | |
1124 | if (jamkn) D = aleg ^ bleg; /* jammin? xor */\r | |
1125 | else D = (aleg + bleg + eiki7) & DMASK; /* else add */\r | |
1126 | \r | |
1127 | /* Possible repeat at end of tlate - special t2, repeat tlate */\r | |
1128 | \r | |
1129 | if (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 | |
1140 | clatr = (MB & (m11+m15+m16)) != 0; /* m11+m15+m16 */\r | |
1141 | cla1r = (MB & (m10+m14)) != 0; /* m10+m14 */\r | |
1142 | edahs = ((MB & (m11+m14)) == (m11+m14)) || /* (m11xm14)+m15+m16 */\r | |
1143 | (MB & (m15+m16));\r | |
1144 | edals = ((MB & (m11+m13)) == (m11+m13)) || /* (m11xm13)+m15+m16 */\r | |
1145 | (MB & (m15+m16));\r | |
1146 | etahs = (MB & (m9+m11)) == (m9+m11); /* m9xm11 */\r | |
1147 | etals = (MB & (m10+m11)) == (m10+m11); /* m10xm11 */\r | |
1148 | eda1r = ((MB & (m8+m10)) == (m8+m10)) || (MB & m14); /* (m8xm10)+m14 */\r | |
1149 | cbitl = (MB & (m9+m11)) == m9; /* m9x!m11 */\r | |
1150 | cbite = (MB & (m8+m9)) == (m8+m9); /* m8xm9 */\r | |
1151 | cbitg = (MB & (m10+m12)) == (m10+m12); /* m10xm12 */\r | |
1152 | \r | |
1153 | if (clatr) ARx = 0; /* clear A */\r | |
1154 | if (cla1r) ARx = ARx & ~SIGN; /* clear A1 */\r | |
1155 | if (edahs) ARx = ARx | (D & 0177400); /* D hi to A hi */\r | |
1156 | if (edals) ARx = ARx | (D & 0000377); /* D lo to A lo */\r | |
1157 | if (etahs) ARx = ARx | ((D << 8) & 0177400); /* D lo to A hi */\r | |
1158 | if (etals) ARx = ARx | ((D >> 8) & 0000377); /* D hi to A lo */\r | |
1159 | if (eda1r) ARx = ARx | (D & SIGN); /* D1 to A1 */\r | |
1160 | if (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 | |
1178 | if (cbite || (cbitg && (D & SIGN))) C = 1; /* C = 1 */\r | |
1179 | return ARx;\r | |
1180 | }\r | |
1181 | \r | |
1182 | /* Reset routines */\r | |
1183 | \r | |
1184 | t_stat cpu_reset (DEVICE *dptr)\r | |
1185 | {\r | |
1186 | int32 i;\r | |
1187 | \r | |
1188 | saved_AR = saved_BR = saved_XR = 0;\r | |
1189 | C = 0;\r | |
1190 | dp = 0;\r | |
1191 | ext = pme = extoff_pending = 0;\r | |
1192 | dev_int = dev_int & ~(INT_PEND|INT_NMI);\r | |
1193 | dev_enb = 0;\r | |
1194 | for (i = 0; i < DMA_MAX; i++) dma_ad[i] = dma_wc[i] = dma_eor[i] = 0;\r | |
1195 | chan_req = 0;\r | |
1196 | pcq_r = find_reg ("PCQ", NULL, dptr);\r | |
1197 | if (pcq_r) pcq_r->qptr = 0;\r | |
1198 | else return SCPE_IERR;\r | |
1199 | sim_brk_types = sim_brk_dflt = SWMASK ('E');\r | |
1200 | return SCPE_OK;\r | |
1201 | }\r | |
1202 | \r | |
1203 | /* Memory examine */\r | |
1204 | \r | |
1205 | t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r | |
1206 | {\r | |
1207 | int32 d;\r | |
1208 | \r | |
1209 | if (addr >= MEMSIZE) return SCPE_NXM;\r | |
1210 | if (addr == 0) d = saved_XR;\r | |
1211 | else d = M[addr];\r | |
1212 | if (vptr != NULL) *vptr = d & DMASK;\r | |
1213 | return SCPE_OK;\r | |
1214 | }\r | |
1215 | \r | |
1216 | /* Memory deposit */\r | |
1217 | \r | |
1218 | t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r | |
1219 | {\r | |
1220 | if (addr >= MEMSIZE) return SCPE_NXM;\r | |
1221 | if (addr == 0) saved_XR = val & DMASK;\r | |
1222 | else M[addr] = val & DMASK;\r | |
1223 | return SCPE_OK;\r | |
1224 | }\r | |
1225 | \r | |
1226 | /* Option processors */\r | |
1227 | \r | |
1228 | t_stat cpu_set_noext (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1229 | {\r | |
1230 | if (MEMSIZE > (NX_AMASK + 1)) return SCPE_ARG;\r | |
1231 | return SCPE_OK;\r | |
1232 | }\r | |
1233 | \r | |
1234 | t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1235 | {\r | |
1236 | int32 mc = 0;\r | |
1237 | uint32 i;\r | |
1238 | \r | |
1239 | if ((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 | |
1242 | for (i = val; i < MEMSIZE; i++) mc = mc | M[i];\r | |
1243 | if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r | |
1244 | return SCPE_OK;\r | |
1245 | MEMSIZE = val;\r | |
1246 | for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;\r | |
1247 | return SCPE_OK;\r | |
1248 | }\r | |
1249 | \r | |
1250 | t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1251 | {\r | |
1252 | uint32 i, newmax;\r | |
1253 | t_stat r;\r | |
1254 | \r | |
1255 | if (cptr == NULL) return SCPE_ARG;\r | |
1256 | newmax = get_uint (cptr, 10, DMA_MAX, &r); /* get new max */\r | |
1257 | if ((r != SCPE_OK) || (newmax == dma_nch)) return r; /* err or no chg? */\r | |
1258 | dma_nch = newmax; /* set new max */\r | |
1259 | for (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 | |
1263 | return SCPE_OK;\r | |
1264 | }\r | |
1265 | \r | |
1266 | /* Show DMA channels */\r | |
1267 | \r | |
1268 | t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
1269 | {\r | |
1270 | if (dma_nch) fprintf (st, "DMA channels = %d", dma_nch);\r | |
1271 | else fprintf (st, "no DMA channels");\r | |
1272 | return SCPE_OK;\r | |
1273 | }\r | |
1274 | \r | |
1275 | /* Show channel state */\r | |
1276 | \r | |
1277 | t_stat cpu_show_dma (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
1278 | {\r | |
1279 | if ((val < 0) || (val >= DMA_MAX)) return SCPE_IERR;\r | |
1280 | fputs ((dma_ad[val] & DMA_IN)? "Input": "Output", st);\r | |
1281 | fprintf (st, ", addr = %06o, count = %06o, ", dma_ad[val] & X_AMASK, dma_wc[val]);\r | |
1282 | fprintf (st, "end of range %s\n", (dma_eor[val]? "set": "clear"));\r | |
1283 | return SCPE_OK;\r | |
1284 | }\r | |
1285 | \r | |
1286 | /* Set I/O device to IOBUS / DMA channel / DMC channel */\r | |
1287 | \r | |
1288 | t_stat io_set_iobus (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1289 | {\r | |
1290 | DEVICE *dptr;\r | |
1291 | DIB *dibp;\r | |
1292 | \r | |
1293 | if (val || cptr || (uptr == NULL)) return SCPE_IERR;\r | |
1294 | dptr = find_dev_from_unit (uptr);\r | |
1295 | if (dptr == NULL) return SCPE_IERR;\r | |
1296 | dibp = (DIB *) dptr->ctxt;\r | |
1297 | if (dibp == NULL) return SCPE_IERR;\r | |
1298 | dibp->chan = 0;\r | |
1299 | return SCPE_OK;\r | |
1300 | }\r | |
1301 | \r | |
1302 | t_stat io_set_dma (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1303 | {\r | |
1304 | DEVICE *dptr;\r | |
1305 | DIB *dibp;\r | |
1306 | uint32 newc;\r | |
1307 | t_stat r;\r | |
1308 | \r | |
1309 | if ((cptr == NULL) || (uptr == NULL)) return SCPE_IERR;\r | |
1310 | dptr = find_dev_from_unit (uptr);\r | |
1311 | if (dptr == NULL) return SCPE_IERR;\r | |
1312 | dibp = (DIB *) dptr->ctxt;\r | |
1313 | if (dibp == NULL) return SCPE_IERR;\r | |
1314 | if (dma_nch == 0) return SCPE_NOFNC;\r | |
1315 | newc = get_uint (cptr, 10, DMA_MAX, &r); /* get new */\r | |
1316 | if ((r != SCPE_OK) || (newc == 0) || (newc > dma_nch)) return SCPE_ARG;\r | |
1317 | dibp->chan = (newc - DMA_MIN) + DMA_V_DMA1 + 1; /* store */\r | |
1318 | return SCPE_OK;\r | |
1319 | }\r | |
1320 | \r | |
1321 | t_stat io_set_dmc (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1322 | {\r | |
1323 | DEVICE *dptr;\r | |
1324 | DIB *dibp;\r | |
1325 | uint32 newc;\r | |
1326 | t_stat r;\r | |
1327 | \r | |
1328 | if ((cptr == NULL) || (uptr == NULL)) return SCPE_IERR;\r | |
1329 | dptr = find_dev_from_unit (uptr);\r | |
1330 | if (dptr == NULL) return SCPE_IERR;\r | |
1331 | dibp = (DIB *) dptr->ctxt;\r | |
1332 | if (dibp == NULL) return SCPE_IERR;\r | |
1333 | if (!(cpu_unit.flags & UNIT_DMC)) return SCPE_NOFNC;\r | |
1334 | newc = get_uint (cptr, 10, DMC_MAX, &r); /* get new */\r | |
1335 | if ((r != SCPE_OK) || (newc == 0)) return SCPE_ARG;\r | |
1336 | dibp->chan = (newc - DMC_MIN) + DMC_V_DMC1 + 1; /* store */\r | |
1337 | return SCPE_OK;\r | |
1338 | }\r | |
1339 | \r | |
1340 | /* Show channel configuration */\r | |
1341 | \r | |
1342 | t_stat io_show_chan (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
1343 | {\r | |
1344 | DEVICE *dptr;\r | |
1345 | DIB *dibp;\r | |
1346 | \r | |
1347 | if (uptr == NULL) return SCPE_IERR;\r | |
1348 | dptr = find_dev_from_unit (uptr);\r | |
1349 | if (dptr == NULL) return SCPE_IERR;\r | |
1350 | dibp = (DIB *) dptr->ctxt;\r | |
1351 | if (dibp == NULL) return SCPE_IERR;\r | |
1352 | if (dibp->chan == 0) fprintf (st, "IO bus");\r | |
1353 | else if (dibp->chan < (DMC_V_DMC1 + 1))\r | |
1354 | fprintf (st, "DMA channel %d", dibp->chan);\r | |
1355 | else fprintf (st, "DMC channel %d", dibp->chan - DMC_V_DMC1);\r | |
1356 | return SCPE_OK;\r | |
1357 | }\r | |
1358 | \r | |
1359 | /* Set up I/O dispatch and channel maps */\r | |
1360 | \r | |
1361 | t_bool devtab_init (void)\r | |
1362 | {\r | |
1363 | DEVICE *dptr;\r | |
1364 | DIB *dibp;\r | |
1365 | uint32 i, j, dno, chan;\r | |
1366 | \r | |
1367 | for (i = 0; i < DEV_MAX; i++) iotab[i] = NULL;\r | |
1368 | for (i = 0; i < (DMA_MAX + DMC_MAX); i++) chan_map[i] = 0;\r | |
1369 | for (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 | |
1413 | for (i = 0; i < DEV_MAX; i++) { /* fill in blanks */\r | |
1414 | if (iotab[i] == NULL) iotab[i] = &undio;\r | |
1415 | }\r | |
1416 | return FALSE;\r | |
1417 | }\r | |
1418 | \r | |
1419 | /* Set history */\r | |
1420 | \r | |
1421 | t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1422 | {\r | |
1423 | int32 i, lnt;\r | |
1424 | t_stat r;\r | |
1425 | \r | |
1426 | if (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 | |
1431 | lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);\r | |
1432 | if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;\r | |
1433 | hst_p = 0;\r | |
1434 | if (hst_lnt) {\r | |
1435 | free (hst);\r | |
1436 | hst_lnt = 0;\r | |
1437 | hst = NULL;\r | |
1438 | }\r | |
1439 | if (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 | |
1444 | return SCPE_OK;\r | |
1445 | }\r | |
1446 | \r | |
1447 | /* Show history */\r | |
1448 | \r | |
1449 | t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
1450 | {\r | |
1451 | int32 cr, k, di, op, lnt;\r | |
1452 | char *cptr = (char *) desc;\r | |
1453 | t_value sim_eval;\r | |
1454 | t_stat r;\r | |
1455 | InstHistory *h;\r | |
1456 | extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,\r | |
1457 | UNIT *uptr, int32 sw);\r | |
1458 | static 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 | |
1462 | if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */\r | |
1463 | if (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 | |
1467 | else lnt = hst_lnt;\r | |
1468 | di = hst_p - lnt; /* work forward */\r | |
1469 | if (di < 0) di = di + hst_lnt;\r | |
1470 | fprintf (st, "PC C A B X ea IR\n\n");\r | |
1471 | for (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 | |
1488 | return SCPE_OK;\r | |
1489 | }\r |