First Commit of my working state
[simh.git] / SDS / sds_cpu.c
1 /* sds_cpu.c: SDS 940 CPU simulator
2
3 Copyright (c) 2001-2007, Robert M. Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 cpu central processor
27 rtc real time clock
28
29 28-Apr-07 RMS Removed clock initialization
30 29-Dec-06 RMS Fixed breakpoint variable declarations
31 16-Aug-05 RMS Fixed C++ declaration and cast problems
32 07-Nov-04 RMS Added instruction history
33 01-Mar-03 RMS Added SET/SHOW RTC FREQ support
34
35 The system state for the SDS 940 is:
36
37 A<0:23> A register
38 B<0:23> B register
39 X<0:23> X (index) register
40 OV overflow indicator
41 P<0:13> program counter
42 nml_mode compatible (1) vs 940 (0) mode
43 usr_mode user (1) vs monitor (0) mode
44 RL1<0:23> user map low
45 RL2<0:23> user map high
46 RL4<12:23> monitor map high
47 EM2<0:2> memory extension, block 2
48 EM3<0:2> memory extension, block 3
49 bpt breakpoint switches
50
51 The SDS 940 has three instruction format -- memory reference, register change,
52 and I/O. The memory reference format is:
53
54 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 23
55 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
56 | U| X| P| opcode |IN| address |
57 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
58
59 U force user mode addressing (monitor mode only)
60 X indexed
61 P opcode is a programmed operator
62 opcode opcode
63 IN indirect addressing
64 address virtual address
65
66 Virtual addresses are 14b. Depending on the operating mode (normal, user,
67 or monitor), virtual addresses are translated to 15b or 16b physical addresses.
68
69 normal virtual [000000:017777] are unmapped
70 EM2 and EM3 extend virtual [020000:037777] to 15b
71 user RL1 and RL2 map virtual [000000:037777] to 16b
72 monitor virtual [000000:017777] are unmapped
73 EM2 extends virtual [020000:027777] to 15b
74 RL4 maps virtual [030000:037777] to 16b
75
76 The register change format is:
77
78 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 23
79 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
80 | 0| m| 0| opcode | microcoded register change instruction |
81 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
82
83 The I/O format is:
84
85 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 23
86 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
87 | 0|CH| 0| opcode |mode | I/O function |
88 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
89
90 This routine is the instruction decode routine for the SDS 940.
91 It is called from the simulator control program to execute
92 instructions in simulated memory, starting at the simulated PC.
93 It runs until 'reason' is set non-zero.
94
95 General notes:
96
97 1. Reasons to stop. The simulator can be stopped by:
98
99 HALT instruction
100 breakpoint encountered
101 invalid instruction and stop_invins flag set
102 invalid I/O device and stop_invdev flag set
103 invalid I/O operation and stop_inviop flag set
104 I/O error in I/O simulator
105 indirect loop exceeding limit
106 EXU loop exceeding limit
107 mapping exception in interrupt or trap instruction
108
109 2. Interrupts. The interrupt structure consists of the following:
110
111 int_req interrupt requests (low bit reserved)
112 api_lvl active interrupt levels
113 int_reqhi highest interrupt request
114 api_lvlhi highest interrupt service (0 if none)
115 ion interrupt enable
116 ion_defer interrupt defer (one instruction)
117
118 3. Channels. The SDS 940 has a channel-based I/O structure. Each
119 channel is represented by a set of registers. Channels test the
120 I/O transfer requests from devices, which are kept in xfr_req.
121
122 4. Non-existent memory. On the SDS 940, reads to non-existent memory
123 return zero, and writes are ignored. In the simulator, the
124 largest possible memory is instantiated and initialized to zero.
125 Thus, only writes need be checked against actual memory size.
126
127 5. Adding I/O devices. These modules must be modified:
128
129 sds_defs.h add interrupt, transfer, and alert definitions
130 sds_io.c add alert dispatches aldisp
131 sds_sys.c add pointer to data structures to sim_devices
132 */
133
134 #include "sds_defs.h"
135
136 #define PCQ_SIZE 64 /* must be 2**n */
137 #define PCQ_MASK (PCQ_SIZE - 1)
138 #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = pc
139 #define UNIT_V_MSIZE (UNIT_V_GENIE + 1) /* dummy mask */
140 #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
141
142 #define HIST_XCT 1 /* instruction */
143 #define HIST_INT 2 /* interrupt cycle */
144 #define HIST_TRP 3 /* trap cycle */
145 #define HIST_MIN 64
146 #define HIST_MAX 65536
147 #define HIST_NOEA 0x40000000
148
149 typedef struct {
150 uint32 typ;
151 uint32 pc;
152 uint32 ir;
153 uint32 a;
154 uint32 b;
155 uint32 x;
156 uint32 ea;
157 } InstHistory;
158
159 uint32 M[MAXMEMSIZE] = { 0 }; /* memory */
160 uint32 A, B, X; /* registers */
161 uint32 P; /* program counter */
162 uint32 OV; /* overflow */
163 uint32 xfr_req = 0; /* xfr req */
164 uint32 ion = 0; /* int enable */
165 uint32 ion_defer = 0; /* int defer */
166 uint32 int_req = 0; /* int requests */
167 uint32 int_reqhi = 0; /* highest int request */
168 uint32 api_lvl = 0; /* api active */
169 uint32 api_lvlhi = 0; /* highest api active */
170 t_bool chan_req; /* chan request */
171 uint32 nml_mode = 1; /* normal mode */
172 uint32 usr_mode = 0; /* user mode */
173 uint32 mon_usr_trap = 0; /* mon-user trap */
174 uint32 EM2 = 2, EM3 = 3; /* extension registers */
175 uint32 RL1, RL2, RL4; /* relocation maps */
176 uint32 bpt; /* breakpoint switches */
177 uint32 alert; /* alert dispatch */
178 uint32 em2_dyn, em3_dyn; /* extensions, dynamic */
179 uint32 usr_map[8]; /* user map, dynamic */
180 uint32 mon_map[8]; /* mon map, dynamic */
181 int32 ind_lim = 32; /* indirect limit */
182 int32 exu_lim = 32; /* EXU limit */
183 int32 cpu_genie = 0; /* Genie flag */
184 int32 cpu_astop = 0; /* address stop */
185 int32 stop_invins = 1; /* stop inv inst */
186 int32 stop_invdev = 1; /* stop inv dev */
187 int32 stop_inviop = 1; /* stop inv io op */
188 uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
189 int32 pcq_p = 0; /* PC queue ptr */
190 REG *pcq_r = NULL; /* PC queue reg ptr */
191 int32 hst_p = 0; /* history pointer */
192 int32 hst_lnt = 0; /* history length */
193 InstHistory *hst = NULL; /* instruction history */
194 int32 rtc_pie = 0; /* rtc pulse ie */
195 int32 rtc_tps = 60; /* rtc ticks/sec */
196
197 extern int32 sim_int_char;
198 extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
199
200 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
201 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
202 t_stat cpu_reset (DEVICE *dptr);
203 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
204 t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);
205 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
206 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
207 t_stat Ea (uint32 wd, uint32 *va);
208 t_stat EaSh (uint32 wd, uint32 *va);
209 t_stat Read (uint32 va, uint32 *dat);
210 t_stat Write (uint32 va, uint32 dat);
211 void set_dyn_map (void);
212 uint32 api_findreq (void);
213 void api_dismiss (void);
214 uint32 Add24 (uint32 s1, uint32 s2, uint32 cin);
215 uint32 AddM24 (uint32 s1, uint32 s2);
216 void Mul48 (uint32 mplc, uint32 mplr);
217 void Div48 (uint32 dvdh, uint32 dvdl, uint32 dvr);
218 void RotR48 (uint32 sc);
219 void ShfR48 (uint32 sc, uint32 sgn);
220 t_stat one_inst (uint32 inst, uint32 pc, uint32 mode);
221 void inst_hist (uint32 inst, uint32 pc, uint32 typ);
222 t_stat rtc_inst (uint32 inst);
223 t_stat rtc_svc (UNIT *uptr);
224 t_stat rtc_reset (DEVICE *dptr);
225 t_stat rtc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc);
226 t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);
227
228 extern t_bool io_init (void);
229 extern t_stat op_wyim (uint32 inst, uint32 *dat);
230 extern t_stat op_miwy (uint32 inst, uint32 dat);
231 extern t_stat op_pin (uint32 *dat);
232 extern t_stat op_pot (uint32 dat);
233 extern t_stat op_eomd (uint32 inst);
234 extern t_stat op_sks (uint32 inst, uint32 *skp);
235
236 /* CPU data structures
237
238 cpu_dev CPU device descriptor
239 cpu_unit CPU unit descriptor
240 cpu_reg CPU register list
241 cpu_mod CPU modifiers list
242 */
243
244 UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };
245
246 REG cpu_reg[] = {
247 { ORDATA (P, P, 14) },
248 { ORDATA (A, A, 24) },
249 { ORDATA (B, B, 24) },
250 { ORDATA (X, X, 24) },
251 { FLDATA (OV, OV, 0) },
252 { ORDATA (EM2, EM2, 3) },
253 { ORDATA (EM3, EM3, 3) },
254 { ORDATA (RL1, RL1, 24) },
255 { ORDATA (RL2, RL2, 24) },
256 { ORDATA (RL4, RL4, 12) },
257 { FLDATA (NML, nml_mode, 0) },
258 { FLDATA (USR, usr_mode, 0) },
259 { FLDATA (MONUSR, mon_usr_trap, 0) },
260 { FLDATA (ION, ion, 0) },
261 { FLDATA (INTDEF, ion_defer, 0) },
262 { ORDATA (INTREQ, int_req, 32) },
263 { ORDATA (APILVL, api_lvl, 32) },
264 { DRDATA (INTRHI, int_reqhi, 5) },
265 { DRDATA (APILHI, api_lvlhi, 5), REG_RO },
266 { ORDATA (XFRREQ, xfr_req, 32) },
267 { FLDATA (BPT1, bpt, 3) },
268 { FLDATA (BPT2, bpt, 2) },
269 { FLDATA (BPT3, bpt, 1) },
270 { FLDATA (BPT4, bpt, 0) },
271 { ORDATA (ALERT, alert, 6) },
272 { FLDATA (STOP_INVINS, stop_invins, 0) },
273 { FLDATA (STOP_INVDEV, stop_invdev, 0) },
274 { FLDATA (STOP_INVIOP, stop_inviop, 0) },
275 { DRDATA (INDLIM, ind_lim, 8), REG_NZ+PV_LEFT },
276 { DRDATA (EXULIM, exu_lim, 8), REG_NZ+PV_LEFT },
277 { BRDATA (PCQ, pcq, 8, 14, PCQ_SIZE), REG_RO+REG_CIRC },
278 { ORDATA (PCQP, pcq_p, 6), REG_HRO },
279 { ORDATA (WRU, sim_int_char, 8) },
280 { NULL }
281 };
282
283 MTAB cpu_mod[] = {
284 { UNIT_GENIE, 0, "standard peripherals", "SDS", &cpu_set_type },
285 { UNIT_GENIE, UNIT_GENIE, "Genie peripherals", "GENIE", &cpu_set_type },
286 { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
287 { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
288 { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size },
289 { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
290 { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
291 &cpu_set_hist, &cpu_show_hist },
292 { 0 }
293 };
294
295 DEVICE cpu_dev = {
296 "CPU", &cpu_unit, cpu_reg, cpu_mod,
297 1, 8, 16, 1, 8, 24,
298 &cpu_ex, &cpu_dep, &cpu_reset,
299 NULL, NULL, NULL,
300 NULL, 0
301 };
302
303 /* Clock data structures
304
305 rtc_dev RTC device descriptor
306 rtc_unit RTC unit
307 rtc_reg RTC register list
308 */
309
310 UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), 16000 };
311
312 REG rtc_reg[] = {
313 { FLDATA (PIE, rtc_pie, 0) },
314 { DRDATA (TIME, rtc_unit.wait, 24), REG_NZ + PV_LEFT },
315 { DRDATA (TPS, rtc_tps, 8), PV_LEFT + REG_HRO },
316 { NULL }
317 };
318
319 MTAB rtc_mod[] = {
320 { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",
321 &rtc_set_freq, NULL, NULL },
322 { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",
323 &rtc_set_freq, NULL, NULL },
324 { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
325 NULL, &rtc_show_freq, NULL },
326 { 0 }
327 };
328
329 DEVICE rtc_dev = {
330 "RTC", &rtc_unit, rtc_reg, rtc_mod,
331 1, 8, 8, 1, 8, 8,
332 NULL, NULL, &rtc_reset,
333 NULL, NULL, NULL
334 };
335
336 /* Interrupt tables */
337
338 static const uint32 api_mask[32] = {
339 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, 0xFFFFFFF0,
340 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, 0xFFFFFF00,
341 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800, 0xFFFFF000,
342 0xFFFFE000, 0xFFFFC000, 0xFFFF8000, 0xFFFF0000,
343 0xFFFE0000, 0xFFFC0000, 0xFFF80000, 0xFFF00000,
344 0xFFE00000, 0xFFC00000, 0xFF800000, 0xFF000000,
345 0xFE000000, 0xFC000000, 0xF8000000, 0xF0000000,
346 0xE0000000, 0xC0000000, 0x80000000, 0x00000000
347 };
348
349 static const uint32 int_vec[32] = {
350 0, 0, 0, 0,
351 VEC_FORK, VEC_DRM, VEC_MUXCF,VEC_MUXCO,
352 VEC_MUXT, VEC_MUXR, VEC_HEOR, VEC_HZWC,
353 VEC_GEOR, VEC_GZWC, VEC_FEOR, VEC_FZWC,
354 VEC_EEOR, VEC_EZWC, VEC_DEOR, VEC_DZWC,
355 VEC_CEOR, VEC_CZWC, VEC_WEOR, VEC_YEOR,
356 VEC_WZWC, VEC_YZWC, VEC_RTCP, VEC_RTCS,
357 VEC_IPAR, VEC_CPAR, VEC_PWRF, VEC_PWRO
358 };
359
360 t_stat sim_instr (void)
361 {
362 extern int32 sim_interval;
363 uint32 inst, tinst, pa, save_P, save_mode;
364 t_stat reason, tr;
365
366 /* Restore register state */
367
368 if (io_init ()) return SCPE_STOP; /* init IO; conflict? */
369 reason = 0;
370 xfr_req = xfr_req & ~1; /* <0> reserved */
371 int_req = int_req & ~1; /* <0> reserved */
372 api_lvl = api_lvl & ~1; /* <0> reserved */
373 set_dyn_map (); /* set up mapping */
374 int_reqhi = api_findreq (); /* recalc int req */
375 chan_req = chan_testact (); /* recalc chan act */
376
377 /* Main instruction fetch/decode loop */
378
379 while (reason == 0) { /* loop until halted */
380
381 if (cpu_astop) { /* debug stop? */
382 cpu_astop = 0;
383 return SCPE_STOP;
384 }
385
386 if (sim_interval <= 0) { /* event queue? */
387 if (reason = sim_process_event ()) break; /* process */
388 int_reqhi = api_findreq (); /* recalc int req */
389 chan_req = chan_testact (); /* recalc chan act */
390 }
391
392 if (chan_req) { /* channel request? */
393 if (reason = chan_process ()) break; /* process */
394 int_reqhi = api_findreq (); /* recalc int req */
395 chan_req = chan_testact (); /* recalc chan act */
396 }
397
398 sim_interval = sim_interval - 1; /* count down */
399 if (ion && !ion_defer && int_reqhi) { /* int request? */
400 pa = int_vec[int_reqhi]; /* get vector */
401 if (pa == 0) { /* bad value? */
402 reason = STOP_ILLVEC;
403 break;
404 }
405 tinst = ReadP (pa); /* get inst */
406 save_mode = usr_mode; /* save mode */
407 usr_mode = 0; /* switch to mon */
408 if (hst_lnt) inst_hist (tinst, P, HIST_INT); /* record inst */
409 if (pa != VEC_RTCP) { /* normal intr? */
410 tr = one_inst (tinst, P, save_mode); /* exec intr inst */
411 if (tr) { /* stop code? */
412 usr_mode = save_mode; /* restore mode */
413 reason = (tr > 0)? tr: STOP_MMINT;
414 break;
415 }
416 api_lvl = api_lvl | (1u << int_reqhi); /* set level active */
417 api_lvlhi = int_reqhi; /* elevate api */
418 }
419 else { /* clock intr */
420 tr = rtc_inst (tinst); /* exec RTC inst */
421 usr_mode = save_mode; /* restore mode */
422 if (tr) { /* stop code? */
423 reason = (tr > 0)? tr: STOP_MMINT;
424 break;
425 }
426 int_req = int_req & ~INT_RTCP; /* clr clkp intr */
427 }
428 int_reqhi = api_findreq (); /* recalc int req */
429 }
430 else { /* normal instr */
431 if (sim_brk_summ && sim_brk_test (P, SWMASK ('E'))) { /* breakpoint? */
432 reason = STOP_IBKPT; /* stop simulation */
433 break;
434 }
435 reason = Read (save_P = P, &inst); /* get instr */
436 P = (P + 1) & VA_MASK; /* incr PC */
437 if (reason == SCPE_OK) { /* fetch ok? */
438 ion_defer = 0; /* clear ion */
439 if (hst_lnt) inst_hist (inst, save_P, HIST_XCT);
440 reason = one_inst (inst, save_P, usr_mode); /* exec inst */
441 if (reason > 0) { /* stop code? */
442 if (reason != STOP_HALT) P = save_P;
443 if (reason == STOP_IONRDY) reason = 0;
444 }
445 } /* end if r == 0 */
446 if (reason < 0) { /* mm (fet or ex)? */
447 pa = -reason; /* get vector */
448 reason = 0; /* defang */
449 tinst = ReadP (pa); /* get inst */
450 if (I_GETOP (tinst) != BRM) { /* not BRM? */
451 reason = STOP_TRPINS; /* fatal err */
452 break;
453 }
454 save_mode = usr_mode; /* save mode */
455 usr_mode = 0; /* switch to mon */
456 mon_usr_trap = 0;
457 if (hst_lnt) inst_hist (tinst, save_P, HIST_TRP);
458 tr = one_inst (tinst, save_P, save_mode); /* trap inst */
459 if (tr) { /* stop code? */
460 usr_mode = save_mode; /* restore mode */
461 P = save_P; /* restore PC */
462 reason = (tr > 0)? tr: STOP_MMTRP;
463 break;
464 }
465 } /* end if reason */
466 } /* end else int */
467 } /* end while */
468
469 /* Simulation halted */
470
471 pcq_r->qptr = pcq_p; /* update pc q ptr */
472 return reason;
473 }
474
475 /* Simulate one instruction */
476
477 t_stat one_inst (uint32 inst, uint32 pc, uint32 mode)
478 {
479 uint32 op, shf_op, va, dat;
480 uint32 old_A, old_B, old_X;
481 int32 i, exu_cnt, sc;
482 t_stat r;
483
484 exu_cnt = 0; /* init EXU count */
485 EXU_LOOP:
486 op = I_GETOP (inst); /* get opcode */
487 if (inst & I_POP) { /* POP? */
488 dat = (EM3 << 18) | (EM2 << 15) | I_IND | pc; /* data to save */
489 if (nml_mode) { /* normal mode? */
490 dat = (OV << 23) | dat; /* ov in <0> */
491 WriteP (0, dat);
492 }
493 else if (usr_mode) { /* user mode? */
494 if (inst & I_USR) { /* SYSPOP? */
495 dat = I_USR | (OV << 21) | dat; /* ov in <2> */
496 WriteP (0, dat);
497 usr_mode = 0; /* set mon mode */
498 }
499 else { /* normal POP */
500 dat = (OV << 23) | dat; /* ov in <0> */
501 if (r = Write (0, dat)) return r;
502 }
503 }
504 else { /* mon mode */
505 dat = (OV << 21) | dat; /* ov in <2> */
506 WriteP (0, dat); /* store return */
507 }
508 PCQ_ENTRY; /* save PC */
509 P = 0100 | op; /* new PC */
510 OV = 0; /* clear ovflo */
511 return SCPE_OK; /* end POP */
512 }
513
514 switch (op) { /* case on opcode */
515
516 /* Loads and stores */
517
518 case LDA:
519 if (r = Ea (inst, &va)) return r; /* decode eff addr */
520 if (r = Read (va, &A)) return r; /* get operand */
521 break;
522
523 case LDB:
524 if (r = Ea (inst, &va)) return r; /* decode eff addr */
525 if (r = Read (va, &B)) return r; /* get operand */
526 break;
527
528 case LDX:
529 if (r = Ea (inst, &va)) return r; /* decode eff addr */
530 if (r = Read (va, &X)) return r; /* get operand */
531 break;
532
533 case STA:
534 if (r = Ea (inst, &va)) return r; /* decode eff addr */
535 if (r = Write (va, A)) return r; /* write operand */
536 break;
537
538 case STB:
539 if (r = Ea (inst, &va)) return r; /* decode eff addr */
540 if (r = Write (va, B)) return r; /* write operand */
541 break;
542
543 case STX:
544 if (r = Ea (inst, &va)) return r; /* decode eff addr */
545 if (r = Write (va, X)) return r; /* write operand */
546 break;
547
548 case EAX:
549 if (r = Ea (inst, &va)) return r; /* decode eff addr */
550 if (nml_mode || usr_mode) /* normal or user? */
551 X = (X & ~VA_MASK) | (va & VA_MASK); /* only 14b */
552 else X = (X & ~XVA_MASK) | (va & XVA_MASK); /* mon, 15b */
553 break;
554
555 case XMA:
556 if (r = Ea (inst, &va)) return r; /* decode eff addr */
557 if (r = Read (va, &dat)) return r; /* get operand */
558 if (r = Write (va, A)) return r; /* write A */
559 A = dat; /* load A */
560 break;
561
562 /* Arithmetic and logical */
563
564 case ADD:
565 if (r = Ea (inst, &va)) return r; /* decode eff addr */
566 if (r = Read (va, &dat)) return r; /* get operand */
567 A = Add24 (A, dat, 0); /* add */
568 break;
569
570 case ADC:
571 if (r = Ea (inst, &va)) return r; /* decode eff addr */
572 if (r = Read (va, &dat)) return r; /* get operand */
573 OV = 0; /* clear overflow */
574 A = Add24 (A, dat, X >> 23); /* add with carry */
575 break;
576
577 case SUB:
578 if (r = Ea (inst, &va)) return r; /* decode eff addr */
579 if (r = Read (va, &dat)) return r; /* get operand */
580 A = Add24 (A, dat ^ DMASK, 1); /* subtract */
581 break;
582
583 case SUC:
584 if (r = Ea (inst, &va)) return r; /* decode eff addr */
585 if (r = Read (va, &dat)) return r; /* get operand */
586 OV = 0; /* clear overflow */
587 A = Add24 (A, dat ^ DMASK, X >> 23); /* sub with carry */
588 break;
589
590 case ADM:
591 if (r = Ea (inst, &va)) return r; /* decode eff addr */
592 if (r = Read (va, &dat)) return r; /* get operand */
593 dat = AddM24 (dat, A); /* mem + A */
594 if (r = Write (va, dat)) return r; /* rewrite */
595 break;
596
597 case MIN:
598 if (r = Ea (inst, &va)) return r; /* decode eff addr */
599 if (r = Read (va, &dat)) return r; /* get operand */
600 dat = AddM24 (dat, 1); /* mem + 1 */
601 if (r = Write (va, dat)) return r; /* rewrite */
602 break;
603
604 case MUL:
605 if (r = Ea (inst, &va)) return r; /* decode eff addr */
606 if (r = Read (va, &dat)) return r; /* get operand */
607 Mul48 (A, dat); /* multiply */
608 break;
609
610 case DIV:
611 if (r = Ea (inst, &va)) return r; /* decode eff addr */
612 if (r = Read (va, &dat)) return r; /* get operand */
613 Div48 (A, B, dat); /* divide */
614 break;
615
616 case ETR:
617 if (r = Ea (inst, &va)) return r; /* decode eff addr */
618 if (r = Read (va, &dat)) return r; /* get operand */
619 A = A & dat; /* and */
620 break;
621
622 case MRG:
623 if (r = Ea (inst, &va)) return r; /* decode eff addr */
624 if (r = Read (va, &dat)) return r; /* get operand */
625 A = A | dat; /* or */
626 break;
627
628 case EOR:
629 if (r = Ea (inst, &va)) return r; /* decode eff addr */
630 if (r = Read (va, &dat)) return r; /* get operand */
631 A = A ^ dat; /* xor */
632 break;
633
634 /* Skips */
635
636 case SKE:
637 if (r = Ea (inst, &va)) return r; /* decode eff addr */
638 if (r = Read (va, &dat)) return r; /* get operand */
639 if (A == dat) P = (P + 1) & VA_MASK; /* if A = op, skip */
640 break;
641
642 case SKG:
643 if (r = Ea (inst, &va)) return r; /* decode eff addr */
644 if (r = Read (va, &dat)) return r; /* get operand */
645 if (SXT (A) > SXT (dat)) P = (P + 1) & VA_MASK; /* if A > op, skip */
646 break;
647
648 case SKM:
649 if (r = Ea (inst, &va)) return r; /* decode eff addr */
650 if (r = Read (va, &dat)) return r; /* get operand */
651 if (((A ^ dat) & B) == 0) P = (P + 1) & VA_MASK; /* if A = op masked */
652 break;
653
654 case SKA:
655 if (r = Ea (inst, &va)) return r; /* decode eff addr */
656 if (r = Read (va, &dat)) return r; /* get operand */
657 if ((A & dat) == 0) P = (P + 1) & VA_MASK; /* if !(A & op), skip */
658 break;
659
660 case SKB:
661 if (r = Ea (inst, &va)) return r; /* decode eff addr */
662 if (r = Read (va, &dat)) return r; /* get operand */
663 if ((B & dat) == 0) P = (P + 1) & VA_MASK; /* if !(B & op), skip */
664 break;
665
666 case SKN:
667 if (r = Ea (inst, &va)) return r; /* decode eff addr */
668 if (r = Read (va, &dat)) return r; /* get operand */
669 if (dat & SIGN) P = (P + 1) & VA_MASK; /* if op < 0, skip */
670 break;
671
672 case SKR:
673 if (r = Ea (inst, &va)) return r; /* decode eff addr */
674 if (r = Read (va, &dat)) return r; /* get operand */
675 dat = AddM24 (dat, DMASK); /* decr operand */
676 if (r = Write (va, dat)) return r; /* rewrite operand */
677 if (dat & SIGN) P = (P + 1) & VA_MASK; /* if op < 0, skip */
678 break;
679
680 case SKD:
681 if (r = Ea (inst, &va)) return r; /* decode eff addr */
682 if (r = Read (va, &dat)) return r; /* get operand */
683 if (SXT_EXP (B) < SXT_EXP (dat)) { /* B < dat? */
684 X = (dat - B) & DMASK; /* X = dat - B */
685 P = (P + 1) & VA_MASK; /* skip */
686 }
687 else X = (B - dat) & DMASK; /* X = B - dat */
688 break;
689
690 /* Control */
691
692 case NOP:
693 break;
694
695 case HLT:
696 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */
697 return STOP_HALT; /* halt CPU */
698
699 case EXU:
700 exu_cnt = exu_cnt + 1; /* count chained EXU */
701 if (exu_cnt > exu_lim) return STOP_EXULIM; /* too many? */
702 if (r = Ea (inst, &va)) return r; /* decode eff addr */
703 if (r = Read (va, &dat)) return r; /* get operand */
704 inst = dat;
705 goto EXU_LOOP;
706
707 case BRU:
708 if (nml_mode && (inst & I_IND)) api_dismiss (); /* normal BRU*, dism */
709 if (r = Ea (inst, &va)) return r; /* decode eff addr */
710 if (r = Read (va, &dat)) return r; /* test dest access */
711 PCQ_ENTRY;
712 P = va & VA_MASK; /* branch */
713 break;
714
715 case BRX:
716 if (r = Ea (inst, &va)) return r; /* decode eff addr */
717 X = (X + 1) & DMASK; /* incr X */
718 if (X & I_IND) { /* bit 9 set? */
719 if (r = Read (va, &dat)) return r; /* test dest access */
720 PCQ_ENTRY;
721 P = va & VA_MASK; /* branch */
722 }
723 break;
724
725 case BRM:
726 if (r = Ea (inst, &va)) return r; /* decode eff addr */
727 dat = (EM3 << 18) | (EM2 << 15) | pc; /* form return word */
728 if (!nml_mode && !usr_mode) /* monitor mode? */
729 dat = dat | (mode << 23) | (OV << 21);
730 else dat = dat | (OV << 23); /* normal or user */
731 if (r = Write (va, dat)) return r; /* write ret word */
732 PCQ_ENTRY;
733 P = (va + 1) & VA_MASK; /* branch */
734 break;
735
736 case BRR:
737 if (r = Ea (inst, &va)) return r; /* decode eff addr */
738 if (r = Read (va, &dat)) return r; /* get operand */
739 PCQ_ENTRY;
740 P = (dat + 1) & VA_MASK; /* branch */
741 if (!nml_mode && !usr_mode) { /* monitor mode? */
742 OV = OV | ((dat >> 21) & 1); /* restore OV */
743 if ((va & VA_USR) | (dat & I_USR)) { /* mode change? */
744 usr_mode = 1;
745 if (mon_usr_trap) return MM_MONUSR;
746 }
747 }
748 else OV = OV | ((dat >> 23) & 1); /* restore OV */
749 break;
750
751 case BRI:
752 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */
753 if (r = Ea (inst, &va)) return r; /* decode eff addr */
754 if (r = Read (va, &dat)) return r; /* get operand */
755 api_dismiss (); /* dismiss hi api */
756 PCQ_ENTRY;
757 P = dat & VA_MASK; /* branch */
758 if (!nml_mode) { /* monitor mode? */
759 OV = (dat >> 21) & 1; /* restore OV */
760 if ((va & VA_USR) | (dat & I_USR)) { /* mode change? */
761 usr_mode = 1;
762 if (mon_usr_trap) return MM_MONUSR;
763 }
764 }
765 else OV = (dat >> 23) & 1; /* restore OV */
766 break;
767
768 /* Register change (microprogrammed) */
769
770 case RCH:
771 old_A = A; /* save orig reg */
772 old_B = B;
773 old_X = X;
774 if (inst & 000001211) { /* A change? */
775 if (inst & 01000) dat = (~old_A + 1) & DMASK; /* CNA */
776 else dat = 0;
777 if (inst & 00200) dat = dat | old_X;
778 if (inst & 00010) dat = dat | old_B;
779 if (inst & 00100) A = (A & ~EXPMASK) | (dat & EXPMASK);
780 else A = dat;
781 }
782 if (inst & 000000046) { /* B change? */
783 if (inst & 00040) dat = old_X;
784 else dat = 0;
785 if (inst & 00004) dat = dat | old_A;
786 if (inst & 00100) B = (B & ~EXPMASK) | (dat & EXPMASK);
787 else B = dat;
788 }
789 if (inst & 020000420) { /* X change? */
790 if (inst & 00400) dat = old_A;
791 else dat = 0;
792 if (inst & 00020) dat = dat | old_B;
793 if (inst & 00100) X = SXT_EXP (dat) & DMASK;
794 else X = dat;
795 }
796 break;
797
798 /* Overflow instruction */
799
800 case OVF:
801 if ((inst & 0100) & OV) P = (P + 1) & VA_MASK;
802 if (inst & 0001) OV = 0;
803 if ((inst & 0010) && (((X >> 1) ^ X) & EXPS)) OV = 1;
804 break;
805
806 /* Shifts */
807
808 case RSH:
809 if (r = EaSh (inst, &va)) return r; /* decode eff addr */
810 shf_op = I_GETSHFOP (va); /* get eff op */
811 sc = va & I_SHFMSK; /* get eff count */
812 switch (shf_op) { /* case on sub-op */
813 case 00: /* right arithmetic */
814 if (sc) ShfR48 (sc, (A & SIGN)? DMASK: 0);
815 break;
816 case 04: /* right cycle */
817 sc = sc % 48; /* mod 48 */
818 if (sc) RotR48 (sc);
819 break;
820 case 05: /* right logical */
821 if (sc) ShfR48 (sc, 0);
822 break;
823 default:
824 CRETINS; /* invalid inst */
825 break;
826 } /* end case shf op */
827 break;
828
829 case LSH:
830 if (r = EaSh (inst, &va)) return r; /* decode eff addr */
831 shf_op = I_GETSHFOP (va); /* get eff op */
832 sc = va & I_SHFMSK; /* get eff count */
833 switch (shf_op) { /* case on sub-op */
834 case 00: /* left arithmetic */
835 dat = A; /* save sign */
836 if (sc > 48) sc = 48;
837 for (i = 0; i < sc; i++) { /* loop */
838 A = ((A << 1) | (B >> 23)) & DMASK;
839 B = (B << 1) & DMASK;
840 if ((A ^ dat) & SIGN) OV = 1;
841 }
842 break;
843 case 02: /* normalize */
844 if (sc > 48) sc = 48;
845 for (i = 0; i < sc; i++) { /* until max count */
846 if ((A ^ (A << 1)) & SIGN) break;
847 A = ((A << 1) | (B >> 23)) & DMASK;
848 B = (B << 1) & DMASK;
849 }
850 X = (X - i) & DMASK;
851 break;
852 case 04: /* left cycle */
853 sc = sc % 48; /* mod 48 */
854 if (sc) RotR48 (48 - sc); /* rotate */
855 break;
856 case 06: /* cycle normalize */
857 if (sc > 48) sc = 48;
858 for (i = 0; i < sc; i++) { /* until max count */
859 if ((A ^ (A << 1)) & SIGN) break;
860 old_A = A; /* cyclic shift */
861 A = ((A << 1) | (B >> 23)) & DMASK;
862 B = ((B << 1) | (old_A >> 23)) & DMASK;
863 }
864 X = (X - i) & DMASK;
865 break;
866 default:
867 CRETINS; /* invalid inst */
868 break;
869 } /* end case shf op */
870 break;
871
872 /* I/O instructions */
873
874 case MIW: case MIY:
875 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */
876 if (r = Ea (inst, &va)) return r; /* decode eff addr */
877 if (r = Read (va, &dat)) return r; /* get operand */
878 if (r = op_miwy (inst, dat)) return r; /* process inst */
879 int_reqhi = api_findreq (); /* recalc int req */
880 chan_req = chan_testact (); /* recalc chan act */
881 break;
882
883 case WIM: case YIM:
884 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */
885 if (r = Ea (inst, &va)) return r; /* decode eff addr */
886 if (r = op_wyim (inst, &dat)) return r; /* process inst */
887 if (r = Write (va, dat)) return r; /* write result */
888 int_reqhi = api_findreq (); /* recalc int req */
889 chan_req = chan_testact (); /* recalc chan act */
890 break;
891
892 case EOM: case EOD:
893 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */
894 if (r = op_eomd (inst)) return r; /* process inst */
895 int_reqhi = api_findreq (); /* recalc int req */
896 chan_req = chan_testact (); /* recalc chan act */
897 ion_defer = 1;
898 break;
899
900 case POT:
901 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */
902 if (r = Ea (inst, &va)) return r; /* decode eff addr */
903 if (r = Read (va, &dat)) return r; /* get operand */
904 if (r = op_pot (dat)) return r; /* process inst */
905 int_reqhi = api_findreq (); /* recalc int req */
906 chan_req = chan_testact (); /* recalc chan act */
907 break;
908
909 case PIN:
910 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */
911 if (r = Ea (inst, &va)) return r; /* decode eff addr */
912 if (r = op_pin (&dat)) return r; /* process inst */
913 if (r = Write (va, dat)) return r; /* write result */
914 int_reqhi = api_findreq (); /* recalc int req */
915 chan_req = chan_testact (); /* recalc chan act */
916 break;
917
918 case SKS:
919 if (!nml_mode && usr_mode) return MM_PRVINS; /* priv inst */
920 if (r = op_sks (inst, &dat)) return r; /* process inst */
921 if (dat) P = (P + 1) & VA_MASK;
922 break;
923
924 default:
925 if (!nml_mode && usr_mode) return MM_PRVINS; /* usr? priv viol */
926 CRETINS; /* invalid inst */
927 break;
928 }
929
930 return SCPE_OK;
931 }
932
933 /* Effective address calculation */
934
935 t_stat Ea (uint32 inst, uint32 *addr)
936 {
937 int32 i;
938 uint32 wd = inst; /* homeable */
939 uint32 va = wd & XVA_MASK; /* initial va */
940 t_stat r;
941
942 for (i = 0; i < ind_lim; i++) { /* count indirects */
943 if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK);
944 *addr = va;
945 if ((wd & I_IND) == 0) { /* end of ind chain? */
946 if (hst_lnt) hst[hst_p].ea = *addr; /* record */
947 return SCPE_OK;
948 }
949 if (r = Read (va, &wd)) return r; /* read ind; fails? */
950 va = (va & VA_USR) | (wd & XVA_MASK);
951 }
952 return STOP_INDLIM; /* too many indirects */
953 }
954
955 /* Effective address calculation for shifts - direct indexing is 9b */
956
957 t_stat EaSh (uint32 inst, uint32 *addr)
958 {
959 int32 i;
960 uint32 wd = inst; /* homeable */
961 uint32 va = wd & XVA_MASK; /* initial va */
962 t_stat r;
963
964 for (i = 0; i < ind_lim; i++) { /* count indirects */
965 if ((wd & I_IND) == 0) { /* end of ind chain? */
966 if (wd & I_IDX) *addr = (va & (VA_MASK & ~I_SHFMSK)) |
967 ((va + X) & I_SHFMSK); /* 9b indexing */
968 else *addr = va & VA_MASK;
969 if (hst_lnt) hst[hst_p].ea = *addr; /* record */
970 return SCPE_OK;
971 }
972 if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK);
973 if (r = Read (va, &wd)) return r; /* read ind; fails? */
974 va = (va & VA_USR) | (wd & XVA_MASK);
975 }
976 return STOP_INDLIM; /* too many indirects */
977 }
978
979 /* Read word from virtual address */
980
981 t_stat Read (uint32 va, uint32 *dat)
982 {
983 uint32 pgn, map, pa;
984
985 if (nml_mode) { /* normal? */
986 va = va & VA_MASK; /* ignore user */
987 if (va < 020000) pa = va; /* first 8K: 1 for 1 */
988 else if (va < 030000) pa = va + em2_dyn; /* next 4K: ext EM2 */
989 else pa = va + em3_dyn; /* next 4K: ext EM3 */
990 }
991 else if (usr_mode || (va & VA_USR)) { /* user mapping? */
992 pgn = VA_GETPN (va); /* get page no */
993 map = usr_map[pgn]; /* get map entry */
994 if (map == MAP_PROT) return MM_NOACC; /* prot? no access */
995 pa = (map & ~MAP_PROT) | (va & VA_POFF); /* map address */
996 }
997 else {
998 pgn = VA_GETPN (va); /* mon, get page no */
999 map = mon_map[pgn]; /* get map entry */
1000 if (map & MAP_PROT) return MM_NOACC; /* prot? no access */
1001 pa = map | (va & VA_POFF); /* map address */
1002 }
1003 *dat = M[pa]; /* return word */
1004 return SCPE_OK;
1005 }
1006
1007 /* Write word to virtual address */
1008
1009 t_stat Write (uint32 va, uint32 dat)
1010 {
1011 uint32 pgn, map, pa;
1012
1013 if (nml_mode) { /* normal? */
1014 va = va & VA_MASK; /* ignore user */
1015 if (va < 020000) pa = va; /* first 8K: 1 for 1 */
1016 else if (va < 030000) pa = va + em2_dyn; /* next 4K: ext EM2 */
1017 else pa = va + em3_dyn; /* next 4K: ext EM3 */
1018 }
1019 else if (usr_mode || (va & VA_USR)) { /* user mapping? */
1020 pgn = VA_GETPN (va); /* get page no */
1021 map = usr_map[pgn]; /* get map entry */
1022 if (map & MAP_PROT) { /* protected page? */
1023 if (map == MAP_PROT) return MM_NOACC; /* zero? no access */
1024 else return MM_WRITE; /* else, write prot */
1025 }
1026 pa = map | (va & VA_POFF); /* map address */
1027 }
1028 else {
1029 pgn = VA_GETPN (va); /* mon, get page no */
1030 map = mon_map[pgn]; /* get map entry */
1031 if (map & MAP_PROT) return MM_NOACC; /* prot? no access */
1032 pa = map | (va & VA_POFF); /* map address */
1033 }
1034 if (MEM_ADDR_OK (pa)) M[pa] = dat;
1035 return SCPE_OK;
1036 }
1037
1038 /* Relocate addr for console access */
1039
1040 uint32 RelocC (int32 va, int32 sw)
1041 {
1042 uint32 nml = nml_mode, usr = usr_mode;
1043 uint32 pa, pgn, map;
1044
1045 if (sw & SWMASK ('N')) nml = 1; /* -n: normal */
1046 else if (sw & SWMASK ('X')) nml = usr = 0; /* -x: mon */
1047 else if (sw & SWMASK ('U')) nml = 0, usr = 1; /* -u: user */
1048 else if (!(sw & SWMASK ('V'))) return va; /* -v: curr */
1049 set_dyn_map ();
1050 if (nml) { /* normal? */
1051 if (va < 020000) pa = va; /* first 8K: 1 for 1 */
1052 else if (va < 030000) pa = va + em2_dyn; /* next 4K: ext EM2 */
1053 else pa = va + em3_dyn; /* next 4K: ext EM3 */
1054 }
1055 else {
1056 pgn = VA_GETPN (va); /* get page no */
1057 map = usr? usr_map[pgn]: mon_map[pgn]; /* get map entry */
1058 if (map == MAP_PROT) return MAXMEMSIZE + 1; /* no access page? */
1059 pa = (map & ~MAP_PROT) | (va & VA_POFF); /* map address */
1060 }
1061 return pa;
1062 }
1063
1064 /* Arithmetic routines */
1065
1066 uint32 Add24 (uint32 s1, uint32 s2, uint32 cin)
1067 {
1068 uint32 t = s1 + s2 + cin; /* add with carry in */
1069 if (t > DMASK) X = X | SIGN; /* carry to X<0> */
1070 else X = X & ~SIGN;
1071 if (((s1 ^ ~s2) & (s1 ^ t)) & SIGN) OV = 1; /* overflow */
1072 return t & DMASK;
1073 }
1074
1075 uint32 AddM24 (uint32 s1, uint32 s2)
1076 {
1077 uint32 t = s1 + s2; /* add */
1078 if (((s1 ^ ~s2) & (s1 ^ t)) & SIGN) OV = 1; /* overflow */
1079 return t & DMASK;
1080 }
1081
1082 void Mul48 (uint32 s1, uint32 s2)
1083 {
1084 uint32 a = ABS (s1);
1085 uint32 b = ABS (s2);
1086 uint32 hi, md, lo, t, u;
1087
1088 if ((a == 0) || (b == 0)) { /* ops zero? */
1089 A = B = 0;
1090 return;
1091 }
1092 t = a >> 12; /* split op1 */
1093 a = a & 07777;
1094 u = b >> 12; /* split op2 */
1095 b = b & 07777;
1096 md = (a * u) + (b * t); /* cross product */
1097 lo = (a * b) + ((md & 07777) << 12); /* low result */
1098 hi = (t * u) + (md >> 12) + (lo >> 24); /* hi result */
1099 A = ((hi << 1) & DMASK) | ((lo & DMASK) >> 23);
1100 B = (lo << 1) & DMASK;
1101 if ((s1 ^ s2) & SIGN) {
1102 B = ((B ^ DMASK) + 1) & DMASK;
1103 A = ((A ^ DMASK) + (B == 0)) & DMASK;
1104 }
1105 else if (A & SIGN) OV = 1;
1106 return;
1107 }
1108
1109 /* Divide - the SDS 940 uses a non-restoring divide. The algorithm
1110 runs even for overflow cases. Hence it must be emulated precisely
1111 to give the right answers for diagnostics. If the dividend is
1112 negative, AB are 2's complemented starting at B<22>, and B<23>
1113 is unchanged. */
1114
1115 void Div48 (uint32 ar, uint32 br, uint32 m)
1116 {
1117 int32 i;
1118 uint32 quo = 0; /* quotient */
1119 uint32 dvdh = ar, dvdl = br; /* dividend */
1120 uint32 dvr = ABS (m); /* make dvr pos */
1121
1122 if (TSTS (dvdh)) { /* dvd < 0? */
1123 dvdl = (((dvdl ^ DMASK) + 2) & (DMASK & ~1)) | /* 23b negate */
1124 (dvdl & 1); /* low bit unch */
1125 dvdh = ((dvdh ^ DMASK) + (dvdl <= 1)) & DMASK;
1126 }
1127 if ((dvdh > dvr) || /* divide fail? */
1128 ((dvdh == dvr) && dvdl) ||
1129 ((dvdh == dvr) && !TSTS (ar ^ m))) OV = 1;
1130 dvdh = (dvdh - dvr) & DMASK; /* initial sub */
1131 for (i = 0; i < 23; i++) { /* 23 iterations */
1132 quo = (quo << 1) | ((dvdh >> 23) ^ 1); /* quo bit = ~sign */
1133 dvdh = ((dvdh << 1) | (dvdl >> 23)) & DMASK; /* shift divd */
1134 dvdl = (dvdl << 1) & DMASK;
1135 if (quo & 1) /* test ~sign */
1136 dvdh = (dvdh - dvr) & DMASK; /* sign was +, sub */
1137 else dvdh = (dvdh + dvr) & DMASK; /* sign was -, add */
1138 }
1139 quo = quo << 1; /* shift quo */
1140 if (dvdh & SIGN) dvdh = (dvdh + dvr) & DMASK; /* last op -? restore */
1141 else quo = quo | 1; /* +, set quo bit */
1142 if (TSTS (ar ^ m)) A = NEG (quo); /* sign of quo */
1143 else A = quo; /* A = quo */
1144 if (TSTS (ar)) B = NEG (dvdh); /* sign of rem */
1145 else B = dvdh; /* B = rem */
1146 return;
1147 }
1148
1149 void RotR48 (uint32 sc)
1150 {
1151 uint32 t = A;
1152
1153 if (sc >= 24) {
1154 sc = sc - 24;
1155 A = ((B >> sc) | (A << (24 - sc))) & DMASK;
1156 B = ((t >> sc) | (B << (24 - sc))) & DMASK;
1157 }
1158 else {
1159 A = ((A >> sc) | (B << (24 - sc))) & DMASK;
1160 B = ((B >> sc) | (t << (24 - sc))) & DMASK;
1161 }
1162 return;
1163 }
1164
1165 void ShfR48 (uint32 sc, uint32 sgn)
1166 {
1167 if (sc >= 48) A = B = sgn;
1168 if (sc >= 24) {
1169 sc = sc - 24;
1170 B = ((A >> sc) | (sgn << (24 - sc))) & DMASK;
1171 A = sgn;
1172 }
1173 else {
1174 B = ((B >> sc) | (A << (24 - sc)) & DMASK);
1175 A = ((A >> sc) | (sgn << (24 - sc))) & DMASK;
1176 }
1177 return;
1178 }
1179
1180 /* POT routines for RL1, RL2, RL4 */
1181
1182 t_stat pot_RL1 (uint32 num, uint32 *dat)
1183 {
1184 RL1 = *dat;
1185 set_dyn_map ();
1186 return SCPE_OK;
1187 }
1188
1189 t_stat pot_RL2 (uint32 num, uint32 *dat)
1190 {
1191 RL2 = *dat;
1192 set_dyn_map ();
1193 return SCPE_OK;
1194 }
1195
1196 t_stat pot_RL4 (uint32 num, uint32 *dat)
1197 {
1198 RL4 = (*dat) & 03737;
1199 set_dyn_map ();
1200 return SCPE_OK;
1201 }
1202
1203 /* Map EM2, EM3, RL1, RL2, RL4 to dynamic forms
1204
1205 EM2, EM3 - left shifted 12, base virtual address subtracted
1206 RL1, RL2 - page left shifted 11
1207 RL3 - filled in as 1 to 1 map
1208 RL4 - EM2 or page left shifted 11, PROT bit inserted
1209 */
1210
1211 void set_dyn_map (void)
1212 {
1213 em2_dyn = ((EM2 & 07) << 12) - 020000;
1214 em3_dyn = ((EM3 & 07) << 12) - 030000;
1215 usr_map[0] = (RL1 >> 7) & (MAP_PROT | MAP_PAGE);
1216 usr_map[1] = (RL1 >> 1) & (MAP_PROT | MAP_PAGE);
1217 usr_map[2] = (RL1 << 5) & (MAP_PROT | MAP_PAGE);
1218 usr_map[3] = (RL1 << 11) & (MAP_PROT | MAP_PAGE);
1219 usr_map[4] = (RL2 >> 7) & (MAP_PROT | MAP_PAGE);
1220 usr_map[5] = (RL2 >> 1) & (MAP_PROT | MAP_PAGE);
1221 usr_map[6] = (RL2 << 5) & (MAP_PROT | MAP_PAGE);
1222 usr_map[7] = (RL2 << 11) & (MAP_PROT | MAP_PAGE);
1223 mon_map[0] = (0 << VA_V_PN);
1224 mon_map[1] = (1 << VA_V_PN);
1225 mon_map[2] = (2 << VA_V_PN);
1226 mon_map[3] = (3 << VA_V_PN);
1227 mon_map[4] = ((EM2 & 07) << 12);
1228 mon_map[5] = ((EM2 & 07) << 12) + (1 << VA_V_PN);
1229 mon_map[6] = (RL4 << 5) & MAP_PAGE;
1230 mon_map[7] = (RL4 << 11) & MAP_PAGE;
1231 if (mon_map[6] == 0) mon_map[6] = MAP_PROT;
1232 if (mon_map[7] == 0) mon_map[7] = MAP_PROT;
1233 return;
1234 }
1235
1236 /* Recalculate api requests */
1237
1238 uint32 api_findreq (void)
1239 {
1240 uint32 i, t;
1241
1242 t = (int_req & ~1) & api_mask[api_lvlhi]; /* unmasked int */
1243 for (i = 31; t && (i > 0); i--) { /* find highest */
1244 if ((t >> i) & 1) return i;
1245 }
1246 return 0; /* none */
1247 }
1248
1249 /* Dismiss highest priority interrupt */
1250
1251 void api_dismiss (void)
1252 {
1253 uint32 i, t;
1254
1255 t = 1u << api_lvlhi; /* highest active */
1256 int_req = int_req & ~t; /* clear int req */
1257 api_lvl = api_lvl & ~t; /* clear api level */
1258 api_lvlhi = 0; /* assume all clear */
1259 for (i = 31; api_lvl && (i > 0); i--) { /* find highest api */
1260 if ((api_lvl >> i) & 1) { /* bit set? */
1261 api_lvlhi = i; /* record level */
1262 break; /* done */
1263 }
1264 }
1265 int_reqhi = api_findreq (); /* recalc intreq */
1266 return;
1267 }
1268
1269 /* Reset routine */
1270
1271 t_stat cpu_reset (DEVICE *dptr)
1272 {
1273 OV = 0;
1274 EM2 = 2;
1275 EM3 = 3;
1276 RL1 = RL2 = RL4 = 0;
1277 ion = ion_defer = 0;
1278 nml_mode = 1;
1279 usr_mode = 0;
1280 mon_usr_trap = 0;
1281 int_req = 0;
1282 int_reqhi = 0;
1283 api_lvl = 0;
1284 api_lvlhi = 0;
1285 alert = 0;
1286 pcq_r = find_reg ("PCQ", NULL, dptr);
1287 if (pcq_r) pcq_r->qptr = 0;
1288 else return SCPE_IERR;
1289 sim_brk_types = sim_brk_dflt = SWMASK ('E');
1290 return SCPE_OK;
1291 }
1292
1293 /* Memory examine */
1294
1295 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
1296 {
1297 uint32 pa;
1298
1299 pa = RelocC (addr, sw);
1300 if (pa > MAXMEMSIZE) return SCPE_REL;
1301 if (pa >= MEMSIZE) return SCPE_NXM;
1302 if (vptr != NULL) *vptr = M[pa] & DMASK;
1303 return SCPE_OK;
1304 }
1305
1306 /* Memory deposit */
1307
1308 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
1309 {
1310 uint32 pa;
1311
1312 pa = RelocC (addr, sw);
1313 if (pa > MAXMEMSIZE) return SCPE_REL;
1314 if (pa >= MEMSIZE) return SCPE_NXM;
1315 M[pa] = val & DMASK;
1316 return SCPE_OK;
1317 }
1318
1319 /* Set memory size */
1320
1321 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
1322 {
1323 int32 mc = 0;
1324 uint32 i;
1325
1326 if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 037777) != 0))
1327 return SCPE_ARG;
1328 for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
1329 if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
1330 return SCPE_OK;
1331 MEMSIZE = val;
1332 for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
1333 return SCPE_OK;
1334 }
1335
1336 /* Set system type (1 = Genie, 0 = standard) */
1337
1338 t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc)
1339 {
1340 extern t_stat drm_reset (DEVICE *dptr);
1341 extern DEVICE drm_dev, mux_dev, muxl_dev;
1342 extern UNIT drm_unit, mux_unit;
1343 extern DIB mux_dib;
1344
1345 if ((cpu_unit.flags & UNIT_GENIE) == (uint32) val) return SCPE_OK;
1346 if ((drm_unit.flags & UNIT_ATT) || /* attached? */
1347 (mux_unit.flags & UNIT_ATT)) return SCPE_NOFNC; /* can't do it */
1348 if (val) { /* Genie? */
1349 drm_dev.flags = drm_dev.flags & ~DEV_DIS; /* enb drum */
1350 mux_dev.flags = mux_dev.flags & ~DEV_DIS; /* enb mux */
1351 muxl_dev.flags = muxl_dev.flags & ~DEV_DIS;
1352 mux_dib.dev = DEV3_GMUX; /* Genie mux */
1353 }
1354 else {
1355 drm_dev.flags = drm_dev.flags | DEV_DIS; /* dsb drum */
1356 mux_dib.dev = DEV3_SMUX; /* std mux */
1357 return drm_reset (&drm_dev);
1358 }
1359 return SCPE_OK;
1360 }
1361
1362 /* The real time clock runs continuously; therefore, it only has
1363 a unit service routine and a reset routine. The service routine
1364 sets an interrupt that invokes the clock counter. The clock counter
1365 is a "one instruction interrupt", and only MIN/SKR are valid.
1366 */
1367
1368 t_stat rtc_svc (UNIT *uptr)
1369 {
1370 if (rtc_pie) int_req = int_req | INT_RTCP; /* set pulse intr */
1371 sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps, TMR_RTC)); /* reactivate */
1372 return SCPE_OK;
1373 }
1374
1375 /* Clock interrupt instruction */
1376
1377 t_stat rtc_inst (uint32 inst)
1378 {
1379 uint32 op, dat, val, va;
1380 t_stat r;
1381
1382 op = I_GETOP (inst); /* get opcode */
1383 if (op == MIN) val = 1; /* incr */
1384 else if (op == SKR) val = DMASK; /* decr */
1385 else return STOP_RTCINS; /* can't do it */
1386 if (r = Ea (inst, &va)) return r; /* decode eff addr */
1387 if (r = Read (va, &dat)) return r; /* get operand */
1388 dat = AddM24 (dat, val); /* mem +/- 1 */
1389 if (r = Write (va, dat)) return r; /* rewrite */
1390 if (dat == 0) int_req = int_req | INT_RTCS; /* set clk sync int */
1391 return SCPE_OK;
1392 }
1393
1394 /* Clock reset */
1395
1396 t_stat rtc_reset (DEVICE *dptr)
1397 {
1398 rtc_pie = 0; /* disable pulse */
1399 sim_activate (&rtc_unit, rtc_unit.wait); /* activate unit */
1400 return SCPE_OK;
1401 }
1402
1403 /* Set frequency */
1404
1405 t_stat rtc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
1406 {
1407 if (cptr) return SCPE_ARG;
1408 if ((val != 50) && (val != 60)) return SCPE_IERR;
1409 rtc_tps = val;
1410 return SCPE_OK;
1411 }
1412
1413 /* Show frequency */
1414
1415 t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
1416 {
1417 fprintf (st, (rtc_tps == 50)? "50Hz": "60Hz");
1418 return SCPE_OK;
1419 }
1420
1421 /* Record history */
1422
1423 void inst_hist (uint32 ir, uint32 pc, uint32 tp)
1424 {
1425 hst_p = (hst_p + 1); /* next entry */
1426 if (hst_p >= hst_lnt) hst_p = 0;
1427 hst[hst_p].typ = tp | (OV << 4);
1428 hst[hst_p].pc = pc;
1429 hst[hst_p].ir = ir;
1430 hst[hst_p].a = A;
1431 hst[hst_p].b = B;
1432 hst[hst_p].x = X;
1433 hst[hst_p].ea = HIST_NOEA;
1434 return;
1435 }
1436
1437 /* Set history */
1438
1439 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
1440 {
1441 int32 i, lnt;
1442 t_stat r;
1443
1444 if (cptr == NULL) {
1445 for (i = 0; i < hst_lnt; i++) hst[i].typ = 0;
1446 hst_p = 0;
1447 return SCPE_OK;
1448 }
1449 lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
1450 if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
1451 hst_p = 0;
1452 if (hst_lnt) {
1453 free (hst);
1454 hst_lnt = 0;
1455 hst = NULL;
1456 }
1457 if (lnt) {
1458 hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));
1459 if (hst == NULL) return SCPE_MEM;
1460 hst_lnt = lnt;
1461 }
1462 return SCPE_OK;
1463 }
1464
1465 /* Show history */
1466
1467 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
1468 {
1469 int32 ov, k, di, lnt;
1470 char *cptr = (char *) desc;
1471 t_stat r;
1472 t_value sim_eval;
1473 InstHistory *h;
1474 extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
1475 UNIT *uptr, int32 sw);
1476 static char *cyc[] = { " ", " ", "INT", "TRP" };
1477
1478 if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
1479 if (cptr) {
1480 lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
1481 if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG;
1482 }
1483 else lnt = hst_lnt;
1484 di = hst_p - lnt; /* work forward */
1485 if (di < 0) di = di + hst_lnt;
1486 fprintf (st, "CYC PC OV A B X EA IR\n\n");
1487 for (k = 0; k < lnt; k++) { /* print specified */
1488 h = &hst[(++di) % hst_lnt]; /* entry pointer */
1489 if (h->typ) { /* instruction? */
1490 ov = (h->typ >> 4) & 1; /* overflow */
1491 fprintf (st, "%s %05o %o %08o %08o %08o ", cyc[h->typ & 3],
1492 h->pc, ov, h->a, h->b, h->x);
1493 if (h->ea & HIST_NOEA) fprintf (st, " ");
1494 else fprintf (st, "%05o ", h->ea);
1495 sim_eval = h->ir;
1496 if ((fprint_sym (st, h->pc, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
1497 fprintf (st, "(undefined) %08o", h->ir);
1498 fputc ('\n', st); /* end line */
1499 } /* end else instruction */
1500 } /* end for */
1501 return SCPE_OK;
1502 }