1 /* sds_cpu.c: SDS 940 CPU simulator
2
3 Copyright (c) 2001-2008, 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
sim_instr(void)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 ()) /* init IO; conflict? */
369 return SCPE_STOP;
370 reason = 0;
371 xfr_req = xfr_req & ~1; /* <0> reserved */
372 int_req = int_req & ~1; /* <0> reserved */
373 api_lvl = api_lvl & ~1; /* <0> reserved */
374 set_dyn_map (); /* set up mapping */
375 int_reqhi = api_findreq (); /* recalc int req */
376 chan_req = chan_testact (); /* recalc chan act */
377
378 /* Main instruction fetch/decode loop */
379
380 while (reason == 0) { /* loop until halted */
381
382 if (cpu_astop) { /* debug stop? */
383 cpu_astop = 0;
384 return SCPE_STOP;
385 }
386
387 if (sim_interval <= 0) { /* event queue? */
388 if ((reason = sim_process_event ())) /* process */
389 break;
390 int_reqhi = api_findreq (); /* recalc int req */
391 chan_req = chan_testact (); /* recalc chan act */
392 }
393
394 if (chan_req) { /* channel request? */
395 if ((reason = chan_process ())) /* process */
396 break;
397 int_reqhi = api_findreq (); /* recalc int req */
398 chan_req = chan_testact (); /* recalc chan act */
399 }
400
401 sim_interval = sim_interval - 1; /* count down */
402 if (ion && !ion_defer && int_reqhi) { /* int request? */
403 pa = int_vec[int_reqhi]; /* get vector */
404 if (pa == 0) { /* bad value? */
405 reason = STOP_ILLVEC;
406 break;
407 }
408 tinst = ReadP (pa); /* get inst */
409 save_mode = usr_mode; /* save mode */
410 usr_mode = 0; /* switch to mon */
411 if (hst_lnt) /* record inst */
412 inst_hist (tinst, P, HIST_INT);
413 if (pa != VEC_RTCP) { /* normal intr? */
414 tr = one_inst (tinst, P, save_mode); /* exec intr inst */
415 if (tr) { /* stop code? */
416 usr_mode = save_mode; /* restore mode */
417 reason = (tr > 0)? tr: STOP_MMINT;
418 break;
419 }
420 api_lvl = api_lvl | (1u << int_reqhi); /* set level active */
421 api_lvlhi = int_reqhi; /* elevate api */
422 }
423 else { /* clock intr */
424 tr = rtc_inst (tinst); /* exec RTC inst */
425 usr_mode = save_mode; /* restore mode */
426 if (tr) { /* stop code? */
427 reason = (tr > 0)? tr: STOP_MMINT;
428 break;
429 }
430 int_req = int_req & ~INT_RTCP; /* clr clkp intr */
431 }
432 int_reqhi = api_findreq (); /* recalc int req */
433 }
434 else { /* normal instr */
435 if (sim_brk_summ && sim_brk_test (P, SWMASK ('E'))) { /* breakpoint? */
436 reason = STOP_IBKPT; /* stop simulation */
437 break;
438 }
439 reason = Read (save_P = P, &inst); /* get instr */
440 P = (P + 1) & VA_MASK; /* incr PC */
441 if (reason == SCPE_OK) { /* fetch ok? */
442 ion_defer = 0; /* clear ion */
443 if (hst_lnt)
444 inst_hist (inst, save_P, HIST_XCT);
445 reason = one_inst (inst, save_P, usr_mode); /* exec inst */
446 if (reason > 0) { /* stop code? */
447 if (reason != STOP_HALT)
448 P = save_P;
449 if (reason == STOP_IONRDY)
450 reason = 0;
451 }
452 } /* end if r == 0 */
453 if (reason < 0) { /* mm (fet or ex)? */
454 pa = -reason; /* get vector */
455 reason = 0; /* defang */
456 tinst = ReadP (pa); /* get inst */
457 if (I_GETOP (tinst) != BRM) { /* not BRM? */
458 reason = STOP_TRPINS; /* fatal err */
459 break;
460 }
461 save_mode = usr_mode; /* save mode */
462 usr_mode = 0; /* switch to mon */
463 mon_usr_trap = 0;
464 if (hst_lnt)
465 inst_hist (tinst, save_P, HIST_TRP);
466 tr = one_inst (tinst, save_P, save_mode); /* trap inst */
467 if (tr) { /* stop code? */
468 usr_mode = save_mode; /* restore mode */
469 P = save_P; /* restore PC */
470 reason = (tr > 0)? tr: STOP_MMTRP;
471 break;
472 }
473 } /* end if reason */
474 } /* end else int */
475 } /* end while */
476
477 /* Simulation halted */
478
479 pcq_r->qptr = pcq_p; /* update pc q ptr */
480 return reason;
481 }
482
483 /* Simulate one instruction */
484
one_inst(uint32 inst,uint32 pc,uint32 mode)485 t_stat one_inst (uint32 inst, uint32 pc, uint32 mode)
486 {
487 uint32 op, shf_op, va, dat;
488 uint32 old_A, old_B, old_X;
489 int32 i, exu_cnt, sc;
490 t_stat r;
491
492 exu_cnt = 0; /* init EXU count */
493 EXU_LOOP:
494 op = I_GETOP (inst); /* get opcode */
495 if (inst & I_POP) { /* POP? */
496 dat = (EM3 << 18) | (EM2 << 15) | I_IND | pc; /* data to save */
497 if (nml_mode) { /* normal mode? */
498 dat = (OV << 23) | dat; /* ov in <0> */
499 WriteP (0, dat);
500 }
501 else if (usr_mode) { /* user mode? */
502 if (inst & I_USR) { /* SYSPOP? */
503 dat = I_USR | (OV << 21) | dat; /* ov in <2> */
504 WriteP (0, dat);
505 usr_mode = 0; /* set mon mode */
506 }
507 else { /* normal POP */
508 dat = (OV << 23) | dat; /* ov in <0> */
509 if ((r = Write (0, dat)))
510 return r;
511 }
512 }
513 else { /* mon mode */
514 dat = (OV << 21) | dat; /* ov in <2> */
515 WriteP (0, dat); /* store return */
516 }
517 PCQ_ENTRY; /* save PC */
518 P = 0100 | op; /* new PC */
519 OV = 0; /* clear ovflo */
520 return SCPE_OK; /* end POP */
521 }
522
523 switch (op) { /* case on opcode */
524
525 /* Loads and stores */
526
527 case LDA:
528 if ((r = Ea (inst, &va))) /* decode eff addr */
529 return r;
530 if ((r = Read (va, &A))) /* get operand */
531 return r;
532 break;
533
534 case LDB:
535 if ((r = Ea (inst, &va))) /* decode eff addr */
536 return r;
537 if ((r = Read (va, &B))) /* get operand */
538 return r;
539 break;
540
541 case LDX:
542 if ((r = Ea (inst, &va))) /* decode eff addr */
543 return r;
544 if ((r = Read (va, &X))) /* get operand */
545 return r;
546 break;
547
548 case STA:
549 if ((r = Ea (inst, &va))) /* decode eff addr */
550 return r;
551 if ((r = Write (va, A))) /* write operand */
552 return r;
553 break;
554
555 case STB:
556 if ((r = Ea (inst, &va))) /* decode eff addr */
557 return r;
558 if ((r = Write (va, B))) /* write operand */
559 return r;
560 break;
561
562 case STX:
563 if ((r = Ea (inst, &va))) /* decode eff addr */
564 return r;
565 if ((r = Write (va, X))) /* write operand */
566 return r;
567 break;
568
569 case EAX:
570 if ((r = Ea (inst, &va))) /* decode eff addr */
571 return r;
572 if (nml_mode || usr_mode) /* normal or user? */
573 X = (X & ~VA_MASK) | (va & VA_MASK); /* only 14b */
574 else X = (X & ~XVA_MASK) | (va & XVA_MASK); /* mon, 15b */
575 break;
576
577 case XMA:
578 if ((r = Ea (inst, &va))) /* decode eff addr */
579 return r;
580 if ((r = Read (va, &dat))) /* get operand */
581 return r;
582 if ((r = Write (va, A))) /* write A */
583 return r;
584 A = dat; /* load A */
585 break;
586
587 /* Arithmetic and logical */
588
589 case ADD:
590 if ((r = Ea (inst, &va))) /* decode eff addr */
591 return r;
592 if ((r = Read (va, &dat))) /* get operand */
593 return r;
594 A = Add24 (A, dat, 0); /* add */
595 break;
596
597 case ADC:
598 if ((r = Ea (inst, &va))) /* decode eff addr */
599 return r;
600 if ((r = Read (va, &dat))) /* get operand */
601 return r;
602 OV = 0; /* clear overflow */
603 A = Add24 (A, dat, X >> 23); /* add with carry */
604 break;
605
606 case SUB:
607 if ((r = Ea (inst, &va))) /* decode eff addr */
608 return r;
609 if ((r = Read (va, &dat))) /* get operand */
610 return r;
611 A = Add24 (A, dat ^ DMASK, 1); /* subtract */
612 break;
613
614 case SUC:
615 if ((r = Ea (inst, &va))) /* decode eff addr */
616 return r;
617 if ((r = Read (va, &dat))) /* get operand */
618 return r;
619 OV = 0; /* clear overflow */
620 A = Add24 (A, dat ^ DMASK, X >> 23); /* sub with carry */
621 break;
622
623 case ADM:
624 if ((r = Ea (inst, &va))) /* decode eff addr */
625 return r;
626 if ((r = Read (va, &dat))) /* get operand */
627 return r;
628 dat = AddM24 (dat, A); /* mem + A */
629 if ((r = Write (va, dat))) /* rewrite */
630 return r;
631 break;
632
633 case MIN:
634 if ((r = Ea (inst, &va))) /* decode eff addr */
635 return r;
636 if ((r = Read (va, &dat))) /* get operand */
637 return r;
638 dat = AddM24 (dat, 1); /* mem + 1 */
639 if ((r = Write (va, dat))) /* rewrite */
640 return r;
641 break;
642
643 case MUL:
644 if ((r = Ea (inst, &va))) /* decode eff addr */
645 return r;
646 if ((r = Read (va, &dat))) /* get operand */
647 return r;
648 Mul48 (A, dat); /* multiply */
649 break;
650
651 case DIV:
652 if ((r = Ea (inst, &va))) /* decode eff addr */
653 return r;
654 if ((r = Read (va, &dat))) /* get operand */
655 return r;
656 Div48 (A, B, dat); /* divide */
657 break;
658
659 case ETR:
660 if ((r = Ea (inst, &va))) /* decode eff addr */
661 return r;
662 if ((r = Read (va, &dat))) /* get operand */
663 return r;
664 A = A & dat; /* and */
665 break;
666
667 case MRG:
668 if ((r = Ea (inst, &va))) /* decode eff addr */
669 return r;
670 if ((r = Read (va, &dat))) /* get operand */
671 return r;
672 A = A | dat; /* or */
673 break;
674
675 case EOR:
676 if ((r = Ea (inst, &va))) /* decode eff addr */
677 return r;
678 if ((r = Read (va, &dat))) /* get operand */
679 return r;
680 A = A ^ dat; /* xor */
681 break;
682
683 /* Skips */
684
685 case SKE:
686 if ((r = Ea (inst, &va))) /* decode eff addr */
687 return r;
688 if ((r = Read (va, &dat))) /* get operand */
689 return r;
690 if (A == dat) /* if A = op, skip */
691 P = (P + 1) & VA_MASK;
692 break;
693
694 case SKG:
695 if ((r = Ea (inst, &va))) /* decode eff addr */
696 return r;
697 if ((r = Read (va, &dat))) /* get operand */
698 return r;
699 if (SXT (A) > SXT (dat)) /* if A > op, skip */
700 P = (P + 1) & VA_MASK;
701 break;
702
703 case SKM:
704 if ((r = Ea (inst, &va))) /* decode eff addr */
705 return r;
706 if ((r = Read (va, &dat))) /* get operand */
707 return r;
708 if (((A ^ dat) & B) == 0) /* if A = op masked */
709 P = (P + 1) & VA_MASK;
710 break;
711
712 case SKA:
713 if ((r = Ea (inst, &va))) /* decode eff addr */
714 return r;
715 if ((r = Read (va, &dat))) /* get operand */
716 return r;
717 if ((A & dat) == 0) /* if !(A & op), skip */
718 P = (P + 1) & VA_MASK;
719 break;
720
721 case SKB:
722 if ((r = Ea (inst, &va))) /* decode eff addr */
723 return r;
724 if ((r = Read (va, &dat))) /* get operand */
725 return r;
726 if ((B & dat) == 0) /* if !(B & op), skip */
727 P = (P + 1) & VA_MASK;
728 break;
729
730 case SKN:
731 if ((r = Ea (inst, &va))) /* decode eff addr */
732 return r;
733 if ((r = Read (va, &dat))) /* get operand */
734 return r;
735 if (dat & SIGN) /* if op < 0, skip */
736 P = (P + 1) & VA_MASK;
737 break;
738
739 case SKR:
740 if ((r = Ea (inst, &va))) /* decode eff addr */
741 return r;
742 if ((r = Read (va, &dat))) /* get operand */
743 return r;
744 dat = AddM24 (dat, DMASK); /* decr operand */
745 if ((r = Write (va, dat))) /* rewrite */
746 return r;
747 if (dat & SIGN) /* if op < 0, skip */
748 P = (P + 1) & VA_MASK;
749 break;
750
751 case SKD:
752 if ((r = Ea (inst, &va))) /* decode eff addr */
753 return r;
754 if ((r = Read (va, &dat))) /* get operand */
755 return r;
756 if (SXT_EXP (B) < SXT_EXP (dat)) { /* B < dat? */
757 X = (dat - B) & DMASK; /* X = dat - B */
758 P = (P + 1) & VA_MASK; /* skip */
759 }
760 else X = (B - dat) & DMASK; /* X = B - dat */
761 break;
762
763 /* Control */
764
765 case NOP:
766 break;
767
768 case HLT:
769 if (!nml_mode && usr_mode) /* priv inst */
770 return MM_PRVINS;
771 return STOP_HALT; /* halt CPU */
772
773 case EXU:
774 exu_cnt = exu_cnt + 1; /* count chained EXU */
775 if (exu_cnt > exu_lim) /* too many? */
776 return STOP_EXULIM;
777 if ((r = Ea (inst, &va))) /* decode eff addr */
778 return r;
779 if ((r = Read (va, &dat))) /* get operand */
780 return r;
781 inst = dat;
782 goto EXU_LOOP;
783
784 case BRU:
785 if (nml_mode && (inst & I_IND)) api_dismiss (); /* normal BRU*, dism */
786 if ((r = Ea (inst, &va))) /* decode eff addr */
787 return r;
788 if ((r = Read (va, &dat))) /* get operand */
789 return r;
790 PCQ_ENTRY;
791 P = va & VA_MASK; /* branch */
792 break;
793
794 case BRX:
795 if ((r = Ea (inst, &va))) /* decode eff addr */
796 return r;
797 X = (X + 1) & DMASK; /* incr X */
798 if (X & I_IND) { /* bit 9 set? */
799 if ((r = Read (va, &dat))) /* test dest access */
800 return r;
801 PCQ_ENTRY;
802 P = va & VA_MASK; /* branch */
803 }
804 break;
805
806 case BRM:
807 if ((r = Ea (inst, &va))) /* decode eff addr */
808 return r;
809 dat = (EM3 << 18) | (EM2 << 15) | pc; /* form return word */
810 if (!nml_mode && !usr_mode) /* monitor mode? */
811 dat = dat | (mode << 23) | (OV << 21);
812 else dat = dat | (OV << 23); /* normal or user */
813 if ((r = Write (va, dat))) /* write ret word */
814 return r;
815 PCQ_ENTRY;
816 P = (va + 1) & VA_MASK; /* branch */
817 break;
818
819 case BRR:
820 if ((r = Ea (inst, &va))) /* decode eff addr */
821 return r;
822 if ((r = Read (va, &dat))) /* get operand */
823 return r;
824 PCQ_ENTRY;
825 P = (dat + 1) & VA_MASK; /* branch */
826 if (!nml_mode && !usr_mode) { /* monitor mode? */
827 OV = OV | ((dat >> 21) & 1); /* restore OV */
828 if ((va & VA_USR) | (dat & I_USR)) { /* mode change? */
829 usr_mode = 1;
830 if (mon_usr_trap)
831 return MM_MONUSR;
832 }
833 }
834 else OV = OV | ((dat >> 23) & 1); /* restore OV */
835 break;
836
837 case BRI:
838 if (!nml_mode && usr_mode) /* priv inst */
839 return MM_PRVINS;
840 if ((r = Ea (inst, &va))) /* decode eff addr */
841 return r;
842 if ((r = Read (va, &dat))) /* get operand */
843 return r;
844 api_dismiss (); /* dismiss hi api */
845 PCQ_ENTRY;
846 P = dat & VA_MASK; /* branch */
847 if (!nml_mode) { /* monitor mode? */
848 OV = (dat >> 21) & 1; /* restore OV */
849 if ((va & VA_USR) | (dat & I_USR)) { /* mode change? */
850 usr_mode = 1;
851 if (mon_usr_trap)
852 return MM_MONUSR;
853 }
854 }
855 else OV = (dat >> 23) & 1; /* restore OV */
856 break;
857
858 /* Register change (microprogrammed) */
859
860 case RCH:
861 old_A = A; /* save orig reg */
862 old_B = B;
863 old_X = X;
864 if (inst & 000001211) { /* A change? */
865 if (inst & 01000)
866 dat = (~old_A + 1) & DMASK; /* CNA */
867 else dat = 0;
868 if (inst & 00200)
869 dat = dat | old_X;
870 if (inst & 00010)
871 dat = dat | old_B;
872 if (inst & 00100)
873 A = (A & ~EXPMASK) | (dat & EXPMASK);
874 else A = dat;
875 }
876 if (inst & 000000046) { /* B change? */
877 if (inst & 00040)
878 dat = old_X;
879 else dat = 0;
880 if (inst & 00004)
881 dat = dat | old_A;
882 if (inst & 00100)
883 B = (B & ~EXPMASK) | (dat & EXPMASK);
884 else B = dat;
885 }
886 if (inst & 020000420) { /* X change? */
887 if (inst & 00400)
888 dat = old_A;
889 else dat = 0;
890 if (inst & 00020)
891 dat = dat | old_B;
892 if (inst & 00100)
893 X = SXT_EXP (dat) & DMASK;
894 else X = dat;
895 }
896 break;
897
898 /* Overflow instruction */
899
900 case OVF:
901 if ((inst & 0100) & OV)
902 P = (P + 1) & VA_MASK;
903 if (inst & 0001)
904 OV = 0;
905 if ((inst & 0010) && (((X >> 1) ^ X) & EXPS))
906 OV = 1;
907 break;
908
909 /* Shifts */
910
911 case RSH:
912 if ((r = EaSh (inst, &va))) /* decode eff addr */
913 return r;
914 shf_op = I_GETSHFOP (va); /* get eff op */
915 sc = va & I_SHFMSK; /* get eff count */
916 switch (shf_op) { /* case on sub-op */
917 case 00: /* right arithmetic */
918 if (sc)
919 ShfR48 (sc, (A & SIGN)? DMASK: 0);
920 break;
921 case 04: /* right cycle */
922 sc = sc % 48; /* mod 48 */
923 if (sc)
924 RotR48 (sc);
925 break;
926 case 05: /* right logical */
927 if (sc)
928 ShfR48 (sc, 0);
929 break;
930 default:
931 CRETINS; /* invalid inst */
932 break;
933 } /* end case shf op */
934 break;
935
936 case LSH:
937 if ((r = EaSh (inst, &va))) /* decode eff addr */
938 return r;
939 shf_op = I_GETSHFOP (va); /* get eff op */
940 sc = va & I_SHFMSK; /* get eff count */
941 switch (shf_op) { /* case on sub-op */
942 case 00: /* left arithmetic */
943 dat = A; /* save sign */
944 if (sc > 48)
945 sc = 48;
946 for (i = 0; i < sc; i++) { /* loop */
947 A = ((A << 1) | (B >> 23)) & DMASK;
948 B = (B << 1) & DMASK;
949 if ((A ^ dat) & SIGN)
950 OV = 1;
951 }
952 break;
953 case 02: /* normalize */
954 if (sc > 48)
955 sc = 48;
956 for (i = 0; i < sc; i++) { /* until max count */
957 if ((A ^ (A << 1)) & SIGN)
958 break;
959 A = ((A << 1) | (B >> 23)) & DMASK;
960 B = (B << 1) & DMASK;
961 }
962 X = (X - i) & DMASK;
963 break;
964 case 04: /* left cycle */
965 sc = sc % 48; /* mod 48 */
966 if (sc) /* rotate */
967 RotR48 (48 - sc);
968 break;
969 case 06: /* cycle normalize */
970 if (sc > 48)
971 sc = 48;
972 for (i = 0; i < sc; i++) { /* until max count */
973 if ((A ^ (A << 1)) & SIGN)
974 break;
975 old_A = A; /* cyclic shift */
976 A = ((A << 1) | (B >> 23)) & DMASK;
977 B = ((B << 1) | (old_A >> 23)) & DMASK;
978 }
979 X = (X - i) & DMASK;
980 break;
981 default:
982 CRETINS; /* invalid inst */
983 break;
984 } /* end case shf op */
985 break;
986
987 /* I/O instructions */
988
989 case MIW: case MIY:
990 if (!nml_mode && usr_mode) /* priv inst */
991 return MM_PRVINS;
992 if ((r = Ea (inst, &va))) /* decode eff addr */
993 return r;
994 if ((r = Read (va, &dat))) /* get operand */
995 return r;
996 if ((r = op_miwy (inst, dat))) /* process inst */
997 return r;
998 int_reqhi = api_findreq (); /* recalc int req */
999 chan_req = chan_testact (); /* recalc chan act */
1000 break;
1001
1002 case WIM: case YIM:
1003 if (!nml_mode && usr_mode) /* priv inst */
1004 return MM_PRVINS;
1005 if ((r = Ea (inst, &va))) /* decode eff addr */
1006 return r;
1007 if ((r = op_wyim (inst, &dat))) /* process inst */
1008 return r;
1009 if ((r = Write (va, dat)))
1010 return r; /* write result */
1011 int_reqhi = api_findreq (); /* recalc int req */
1012 chan_req = chan_testact (); /* recalc chan act */
1013 break;
1014
1015 case EOM: case EOD:
1016 if (!nml_mode && usr_mode) /* priv inst */
1017 return MM_PRVINS;
1018 if ((r = op_eomd (inst))) /* process inst */
1019 return r;
1020 int_reqhi = api_findreq (); /* recalc int req */
1021 chan_req = chan_testact (); /* recalc chan act */
1022 ion_defer = 1;
1023 break;
1024
1025 case POT:
1026 if (!nml_mode && usr_mode) /* priv inst */
1027 return MM_PRVINS;
1028 if ((r = Ea (inst, &va))) /* decode eff addr */
1029 return r;
1030 if ((r = Read (va, &dat))) /* get operand */
1031 return r;
1032 if ((r = op_pot (dat))) /* process inst */
1033 return r;
1034 int_reqhi = api_findreq (); /* recalc int req */
1035 chan_req = chan_testact (); /* recalc chan act */
1036 break;
1037
1038 case PIN:
1039 if (!nml_mode && usr_mode) /* priv inst */
1040 return MM_PRVINS;
1041 if ((r = Ea (inst, &va))) /* decode eff addr */
1042 return r;
1043 if ((r = op_pin (&dat))) /* process inst */
1044 return r;
1045 if ((r = Write (va, dat))) /* write result */
1046 return r;
1047 int_reqhi = api_findreq (); /* recalc int req */
1048 chan_req = chan_testact (); /* recalc chan act */
1049 break;
1050
1051 case SKS:
1052 if (!nml_mode && usr_mode) /* priv inst */
1053 return MM_PRVINS;
1054 if ((r = op_sks (inst, &dat))) /* process inst */
1055 return r;
1056 if (dat)
1057 P = (P + 1) & VA_MASK;
1058 break;
1059
1060 default:
1061 if (!nml_mode && usr_mode) /* priv inst */
1062 return MM_PRVINS;
1063 CRETINS; /* invalid inst */
1064 break;
1065 }
1066
1067 return SCPE_OK;
1068 }
1069
1070 /* Effective address calculation */
1071
Ea(uint32 inst,uint32 * addr)1072 t_stat Ea (uint32 inst, uint32 *addr)
1073 {
1074 int32 i;
1075 uint32 wd = inst; /* homeable */
1076 uint32 va = wd & XVA_MASK; /* initial va */
1077 t_stat r;
1078
1079 for (i = 0; i < ind_lim; i++) { /* count indirects */
1080 if (wd & I_IDX)
1081 va = (va & VA_USR) | ((va + X) & VA_MASK);
1082 *addr = va;
1083 if ((wd & I_IND) == 0) { /* end of ind chain? */
1084 if (hst_lnt) /* record */
1085 hst[hst_p].ea = *addr;
1086 return SCPE_OK;
1087 }
1088 if ((r = Read (va, &wd))) /* read ind; fails? */
1089 return r;
1090 va = (va & VA_USR) | (wd & XVA_MASK);
1091 }
1092 return STOP_INDLIM; /* too many indirects */
1093 }
1094
1095 /* Effective address calculation for shifts - direct indexing is 9b */
1096
EaSh(uint32 inst,uint32 * addr)1097 t_stat EaSh (uint32 inst, uint32 *addr)
1098 {
1099 int32 i;
1100 uint32 wd = inst; /* homeable */
1101 uint32 va = wd & XVA_MASK; /* initial va */
1102 t_stat r;
1103
1104 for (i = 0; i < ind_lim; i++) { /* count indirects */
1105 if ((wd & I_IND) == 0) { /* end of ind chain? */
1106 if (wd & I_IDX) /* 9b indexing */
1107 *addr = (va & (VA_MASK & ~I_SHFMSK)) | ((va + X) & I_SHFMSK);
1108 else *addr = va & VA_MASK;
1109 if (hst_lnt) /* record */
1110 hst[hst_p].ea = *addr;
1111 return SCPE_OK;
1112 }
1113 if (wd & I_IDX)
1114 va = (va & VA_USR) | ((va + X) & VA_MASK);
1115 if ((r = Read (va, &wd))) /* read ind; fails? */
1116 return r;
1117 va = (va & VA_USR) | (wd & XVA_MASK);
1118 }
1119 return STOP_INDLIM; /* too many indirects */
1120 }
1121
1122 /* Read word from virtual address */
1123
Read(uint32 va,uint32 * dat)1124 t_stat Read (uint32 va, uint32 *dat)
1125 {
1126 uint32 pgn, map, pa;
1127
1128 if (nml_mode) { /* normal? */
1129 va = va & VA_MASK; /* ignore user */
1130 if (va < 020000) /* first 8K: 1 for 1 */
1131 pa = va;
1132 else if (va < 030000) /* next 4K: ext EM2 */
1133 pa = va + em2_dyn;
1134 else pa = va + em3_dyn; /* next 4K: ext EM3 */
1135 }
1136 else if (usr_mode || (va & VA_USR)) { /* user mapping? */
1137 pgn = VA_GETPN (va); /* get page no */
1138 map = usr_map[pgn]; /* get map entry */
1139 if (map == MAP_PROT) /* prot? no access */
1140 return MM_NOACC;
1141 pa = (map & ~MAP_PROT) | (va & VA_POFF); /* map address */
1142 }
1143 else {
1144 pgn = VA_GETPN (va); /* mon, get page no */
1145 map = mon_map[pgn]; /* get map entry */
1146 if (map & MAP_PROT)
1147 return MM_NOACC; /* prot? no access */
1148 pa = map | (va & VA_POFF); /* map address */
1149 }
1150 *dat = M[pa]; /* return word */
1151 return SCPE_OK;
1152 }
1153
1154 /* Write word to virtual address */
1155
Write(uint32 va,uint32 dat)1156 t_stat Write (uint32 va, uint32 dat)
1157 {
1158 uint32 pgn, map, pa;
1159
1160 if (nml_mode) { /* normal? */
1161 va = va & VA_MASK; /* ignore user */
1162 if (va < 020000) /* first 8K: 1 for 1 */
1163 pa = va;
1164 else if (va < 030000) /* next 4K: ext EM2 */
1165 pa = va + em2_dyn;
1166 else pa = va + em3_dyn; /* next 4K: ext EM3 */
1167 }
1168 else if (usr_mode || (va & VA_USR)) { /* user mapping? */
1169 pgn = VA_GETPN (va); /* get page no */
1170 map = usr_map[pgn]; /* get map entry */
1171 if (map & MAP_PROT) { /* protected page? */
1172 if (map == MAP_PROT) /* zero? no access */
1173 return MM_NOACC;
1174 else return MM_WRITE; /* else, write prot */
1175 }
1176 pa = map | (va & VA_POFF); /* map address */
1177 }
1178 else {
1179 pgn = VA_GETPN (va); /* mon, get page no */
1180 map = mon_map[pgn]; /* get map entry */
1181 if (map & MAP_PROT) /* prot? no access */
1182 return MM_NOACC;
1183 pa = map | (va & VA_POFF); /* map address */
1184 }
1185 if (MEM_ADDR_OK (pa))
1186 M[pa] = dat;
1187 return SCPE_OK;
1188 }
1189
1190 /* Relocate addr for console access */
1191
RelocC(int32 va,int32 sw)1192 uint32 RelocC (int32 va, int32 sw)
1193 {
1194 uint32 nml = nml_mode, usr = usr_mode;
1195 uint32 pa, pgn, map;
1196
1197 if (sw & SWMASK ('N')) /* -n: normal */
1198 nml = 1;
1199 else if (sw & SWMASK ('X')) /* -x: mon */
1200 nml = usr = 0;
1201 else if (sw & SWMASK ('U')) { /* -u: user */
1202 nml = 0;
1203 usr = 1;
1204 }
1205 else if (!(sw & SWMASK ('V'))) /* -v: curr */
1206 return va;
1207 set_dyn_map ();
1208 if (nml) { /* normal? */
1209 if (va < 020000) /* first 8K: 1 for 1 */
1210 pa = va;
1211 else if (va < 030000) /* next 4K: ext EM2 */
1212 pa = va + em2_dyn;
1213 else pa = va + em3_dyn; /* next 4K: ext EM3 */
1214 }
1215 else {
1216 pgn = VA_GETPN (va); /* get page no */
1217 map = usr? usr_map[pgn]: mon_map[pgn]; /* get map entry */
1218 if (map == MAP_PROT) /* no access page? */
1219 return MAXMEMSIZE + 1;
1220 pa = (map & ~MAP_PROT) | (va & VA_POFF); /* map address */
1221 }
1222 return pa;
1223 }
1224
1225 /* Arithmetic routines */
1226
Add24(uint32 s1,uint32 s2,uint32 cin)1227 uint32 Add24 (uint32 s1, uint32 s2, uint32 cin)
1228 {
1229 uint32 t = s1 + s2 + cin; /* add with carry in */
1230 if (t > DMASK) /* carry to X<0> */
1231 X = X | SIGN;
1232 else X = X & ~SIGN;
1233 if (((s1 ^ ~s2) & (s1 ^ t)) /* overflow */
1234 & SIGN) OV = 1;
1235 return t & DMASK;
1236 }
1237
AddM24(uint32 s1,uint32 s2)1238 uint32 AddM24 (uint32 s1, uint32 s2)
1239 {
1240 uint32 t = s1 + s2; /* add */
1241 if (((s1 ^ ~s2) & (s1 ^ t)) & SIGN) /* overflow */
1242 OV = 1;
1243 return t & DMASK;
1244 }
1245
Mul48(uint32 s1,uint32 s2)1246 void Mul48 (uint32 s1, uint32 s2)
1247 {
1248 uint32 a = ABS (s1);
1249 uint32 b = ABS (s2);
1250 uint32 hi, md, lo, t, u;
1251
1252 if ((a == 0) || (b == 0)) { /* ops zero? */
1253 A = B = 0;
1254 return;
1255 }
1256 t = a >> 12; /* split op1 */
1257 a = a & 07777;
1258 u = b >> 12; /* split op2 */
1259 b = b & 07777;
1260 md = (a * u) + (b * t); /* cross product */
1261 lo = (a * b) + ((md & 07777) << 12); /* low result */
1262 hi = (t * u) + (md >> 12) + (lo >> 24); /* hi result */
1263 A = ((hi << 1) & DMASK) | ((lo & DMASK) >> 23);
1264 B = (lo << 1) & DMASK;
1265 if ((s1 ^ s2) & SIGN) {
1266 B = ((B ^ DMASK) + 1) & DMASK;
1267 A = ((A ^ DMASK) + (B == 0)) & DMASK;
1268 }
1269 else if (A & SIGN)
1270 OV = 1;
1271 return;
1272 }
1273
1274 /* Divide - the SDS 940 uses a non-restoring divide. The algorithm
1275 runs even for overflow cases. Hence it must be emulated precisely
1276 to give the right answers for diagnostics. If the dividend is
1277 negative, AB are 2's complemented starting at B<22>, and B<23>
1278 is unchanged. */
1279
Div48(uint32 ar,uint32 br,uint32 m)1280 void Div48 (uint32 ar, uint32 br, uint32 m)
1281 {
1282 int32 i;
1283 uint32 quo = 0; /* quotient */
1284 uint32 dvdh = ar, dvdl = br; /* dividend */
1285 uint32 dvr = ABS (m); /* make dvr pos */
1286
1287 if (TSTS (dvdh)) { /* dvd < 0? */
1288 dvdl = (((dvdl ^ DMASK) + 2) & (DMASK & ~1)) | /* 23b negate */
1289 (dvdl & 1); /* low bit unch */
1290 dvdh = ((dvdh ^ DMASK) + (dvdl <= 1)) & DMASK;
1291 }
1292 if ((dvdh > dvr) || /* divide fail? */
1293 ((dvdh == dvr) && dvdl) ||
1294 ((dvdh == dvr) && !TSTS (ar ^ m)))
1295 OV = 1;
1296 dvdh = (dvdh - dvr) & DMASK; /* initial sub */
1297 for (i = 0; i < 23; i++) { /* 23 iterations */
1298 quo = (quo << 1) | ((dvdh >> 23) ^ 1); /* quo bit = ~sign */
1299 dvdh = ((dvdh << 1) | (dvdl >> 23)) & DMASK; /* shift divd */
1300 dvdl = (dvdl << 1) & DMASK;
1301 if (quo & 1) /* test ~sign */
1302 dvdh = (dvdh - dvr) & DMASK; /* sign was +, sub */
1303 else dvdh = (dvdh + dvr) & DMASK; /* sign was -, add */
1304 }
1305 quo = quo << 1; /* shift quo */
1306 if (dvdh & SIGN) /* last op -? restore */
1307 dvdh = (dvdh + dvr) & DMASK;
1308 else quo = quo | 1; /* +, set quo bit */
1309 if (TSTS (ar ^ m)) /* sign of quo */
1310 A = NEG (quo);
1311 else A = quo; /* A = quo */
1312 if (TSTS (ar)) /* sign of rem */
1313 B = NEG (dvdh);
1314 else B = dvdh; /* B = rem */
1315 return;
1316 }
1317
RotR48(uint32 sc)1318 void RotR48 (uint32 sc)
1319 {
1320 uint32 t = A;
1321
1322 if (sc >= 24) {
1323 sc = sc - 24;
1324 A = ((B >> sc) | (A << (24 - sc))) & DMASK;
1325 B = ((t >> sc) | (B << (24 - sc))) & DMASK;
1326 }
1327 else {
1328 A = ((A >> sc) | (B << (24 - sc))) & DMASK;
1329 B = ((B >> sc) | (t << (24 - sc))) & DMASK;
1330 }
1331 return;
1332 }
1333
ShfR48(uint32 sc,uint32 sgn)1334 void ShfR48 (uint32 sc, uint32 sgn)
1335 {
1336 if (sc >= 48)
1337 A = B = sgn;
1338 if (sc >= 24) {
1339 sc = sc - 24;
1340 B = ((A >> sc) | (sgn << (24 - sc))) & DMASK;
1341 A = sgn;
1342 }
1343 else {
1344 B = ((B >> sc) | (A << (24 - sc))) & DMASK;
1345 A = ((A >> sc) | (sgn << (24 - sc))) & DMASK;
1346 }
1347 return;
1348 }
1349
1350 /* POT routines for RL1, RL2, RL4 */
1351
pot_RL1(uint32 num,uint32 * dat)1352 t_stat pot_RL1 (uint32 num, uint32 *dat)
1353 {
1354 RL1 = *dat;
1355 set_dyn_map ();
1356 return SCPE_OK;
1357 }
1358
pot_RL2(uint32 num,uint32 * dat)1359 t_stat pot_RL2 (uint32 num, uint32 *dat)
1360 {
1361 RL2 = *dat;
1362 set_dyn_map ();
1363 return SCPE_OK;
1364 }
1365
pot_RL4(uint32 num,uint32 * dat)1366 t_stat pot_RL4 (uint32 num, uint32 *dat)
1367 {
1368 RL4 = (*dat) & 03737;
1369 set_dyn_map ();
1370 return SCPE_OK;
1371 }
1372
1373 /* Map EM2, EM3, RL1, RL2, RL4 to dynamic forms
1374
1375 EM2, EM3 - left shifted 12, base virtual address subtracted
1376 RL1, RL2 - page left shifted 11
1377 RL3 - filled in as 1 to 1 map
1378 RL4 - EM2 or page left shifted 11, PROT bit inserted
1379 */
1380
set_dyn_map(void)1381 void set_dyn_map (void)
1382 {
1383 em2_dyn = ((EM2 & 07) << 12) - 020000;
1384 em3_dyn = ((EM3 & 07) << 12) - 030000;
1385 usr_map[0] = (RL1 >> 7) & (MAP_PROT | MAP_PAGE);
1386 usr_map[1] = (RL1 >> 1) & (MAP_PROT | MAP_PAGE);
1387 usr_map[2] = (RL1 << 5) & (MAP_PROT | MAP_PAGE);
1388 usr_map[3] = (RL1 << 11) & (MAP_PROT | MAP_PAGE);
1389 usr_map[4] = (RL2 >> 7) & (MAP_PROT | MAP_PAGE);
1390 usr_map[5] = (RL2 >> 1) & (MAP_PROT | MAP_PAGE);
1391 usr_map[6] = (RL2 << 5) & (MAP_PROT | MAP_PAGE);
1392 usr_map[7] = (RL2 << 11) & (MAP_PROT | MAP_PAGE);
1393 mon_map[0] = (0 << VA_V_PN);
1394 mon_map[1] = (1 << VA_V_PN);
1395 mon_map[2] = (2 << VA_V_PN);
1396 mon_map[3] = (3 << VA_V_PN);
1397 mon_map[4] = ((EM2 & 07) << 12);
1398 mon_map[5] = ((EM2 & 07) << 12) + (1 << VA_V_PN);
1399 mon_map[6] = (RL4 << 5) & MAP_PAGE;
1400 mon_map[7] = (RL4 << 11) & MAP_PAGE;
1401 if (mon_map[6] == 0)
1402 mon_map[6] = MAP_PROT;
1403 if (mon_map[7] == 0)
1404 mon_map[7] = MAP_PROT;
1405 return;
1406 }
1407
1408 /* Recalculate api requests */
1409
api_findreq(void)1410 uint32 api_findreq (void)
1411 {
1412 uint32 i, t;
1413
1414 t = (int_req & ~1) & api_mask[api_lvlhi]; /* unmasked int */
1415 for (i = 31; t && (i > 0); i--) { /* find highest */
1416 if ((t >> i) & 1)
1417 return i;
1418 }
1419 return 0; /* none */
1420 }
1421
1422 /* Dismiss highest priority interrupt */
1423
api_dismiss(void)1424 void api_dismiss (void)
1425 {
1426 uint32 i, t;
1427
1428 t = 1u << api_lvlhi; /* highest active */
1429 int_req = int_req & ~t; /* clear int req */
1430 api_lvl = api_lvl & ~t; /* clear api level */
1431 api_lvlhi = 0; /* assume all clear */
1432 for (i = 31; api_lvl && (i > 0); i--) { /* find highest api */
1433 if ((api_lvl >> i) & 1) { /* bit set? */
1434 api_lvlhi = i; /* record level */
1435 break; /* done */
1436 }
1437 }
1438 int_reqhi = api_findreq (); /* recalc intreq */
1439 return;
1440 }
1441
1442 /* Reset routine */
1443
cpu_reset(DEVICE * dptr)1444 t_stat cpu_reset (DEVICE *dptr)
1445 {
1446 OV = 0;
1447 EM2 = 2;
1448 EM3 = 3;
1449 RL1 = RL2 = RL4 = 0;
1450 ion = ion_defer = 0;
1451 nml_mode = 1;
1452 usr_mode = 0;
1453 mon_usr_trap = 0;
1454 int_req = 0;
1455 int_reqhi = 0;
1456 api_lvl = 0;
1457 api_lvlhi = 0;
1458 alert = 0;
1459 pcq_r = find_reg ("PCQ", NULL, dptr);
1460 if (pcq_r)
1461 pcq_r->qptr = 0;
1462 else return SCPE_IERR;
1463 sim_brk_types = sim_brk_dflt = SWMASK ('E');
1464 return SCPE_OK;
1465 }
1466
1467 /* Memory examine */
1468
cpu_ex(t_value * vptr,t_addr addr,UNIT * uptr,int32 sw)1469 t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
1470 {
1471 uint32 pa;
1472
1473 pa = RelocC (addr, sw);
1474 if (pa > MAXMEMSIZE)
1475 return SCPE_REL;
1476 if (pa >= MEMSIZE)
1477 return SCPE_NXM;
1478 if (vptr != NULL)
1479 *vptr = M[pa] & DMASK;
1480 return SCPE_OK;
1481 }
1482
1483 /* Memory deposit */
1484
cpu_dep(t_value val,t_addr addr,UNIT * uptr,int32 sw)1485 t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
1486 {
1487 uint32 pa;
1488
1489 pa = RelocC (addr, sw);
1490 if (pa > MAXMEMSIZE)
1491 return SCPE_REL;
1492 if (pa >= MEMSIZE)
1493 return SCPE_NXM;
1494 M[pa] = val & DMASK;
1495 return SCPE_OK;
1496 }
1497
1498 /* Set memory size */
1499
cpu_set_size(UNIT * uptr,int32 val,char * cptr,void * desc)1500 t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
1501 {
1502 int32 mc = 0;
1503 uint32 i;
1504
1505 if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 037777) != 0))
1506 return SCPE_ARG;
1507 for (i = val; i < MEMSIZE; i++)
1508 mc = mc | M[i];
1509 if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
1510 return SCPE_OK;
1511 MEMSIZE = val;
1512 for (i = MEMSIZE; i < MAXMEMSIZE; i++)
1513 M[i] = 0;
1514 return SCPE_OK;
1515 }
1516
1517 /* Set system type (1 = Genie, 0 = standard) */
1518
cpu_set_type(UNIT * uptr,int32 val,char * cptr,void * desc)1519 t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc)
1520 {
1521 extern t_stat drm_reset (DEVICE *dptr);
1522 extern DEVICE drm_dev, mux_dev, muxl_dev;
1523 extern UNIT drm_unit, mux_unit;
1524 extern DIB mux_dib;
1525
1526 if ((cpu_unit.flags & UNIT_GENIE) == (uint32) val)
1527 return SCPE_OK;
1528 if ((drm_unit.flags & UNIT_ATT) || /* attached? */
1529 (mux_unit.flags & UNIT_ATT)) /* can't do it */
1530 return SCPE_NOFNC;
1531 if (val) { /* Genie? */
1532 drm_dev.flags = drm_dev.flags & ~DEV_DIS; /* enb drum */
1533 mux_dev.flags = mux_dev.flags & ~DEV_DIS; /* enb mux */
1534 muxl_dev.flags = muxl_dev.flags & ~DEV_DIS;
1535 mux_dib.dev = DEV3_GMUX; /* Genie mux */
1536 }
1537 else {
1538 drm_dev.flags = drm_dev.flags | DEV_DIS; /* dsb drum */
1539 mux_dib.dev = DEV3_SMUX; /* std mux */
1540 return drm_reset (&drm_dev);
1541 }
1542 return SCPE_OK;
1543 }
1544
1545 /* The real time clock runs continuously; therefore, it only has
1546 a unit service routine and a reset routine. The service routine
1547 sets an interrupt that invokes the clock counter. The clock counter
1548 is a "one instruction interrupt", and only MIN/SKR are valid.
1549 */
1550
rtc_svc(UNIT * uptr)1551 t_stat rtc_svc (UNIT *uptr)
1552 {
1553 if (rtc_pie) /* set pulse intr */
1554 int_req = int_req | INT_RTCP;
1555 sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps, TMR_RTC)); /* reactivate */
1556 return SCPE_OK;
1557 }
1558
1559 /* Clock interrupt instruction */
1560
rtc_inst(uint32 inst)1561 t_stat rtc_inst (uint32 inst)
1562 {
1563 uint32 op, dat, val, va;
1564 t_stat r;
1565
1566 op = I_GETOP (inst); /* get opcode */
1567 if (op == MIN) /* incr */
1568 val = 1;
1569 else if (op == SKR) /* decr */
1570 val = DMASK;
1571 else return STOP_RTCINS; /* can't do it */
1572 if ((r = Ea (inst, &va))) /* decode eff addr */
1573 return r;
1574 if ((r = Read (va, &dat))) /* get operand */
1575 return r;
1576 dat = AddM24 (dat, val); /* mem +/- 1 */
1577 if ((r = Write (va, dat))) /* rewrite */
1578 return r;
1579 if (dat == 0) /* set clk sync int */
1580 int_req = int_req | INT_RTCS;
1581 return SCPE_OK;
1582 }
1583
1584 /* Clock reset */
1585
rtc_reset(DEVICE * dptr)1586 t_stat rtc_reset (DEVICE *dptr)
1587 {
1588 rtc_pie = 0; /* disable pulse */
1589 sim_activate (&rtc_unit, rtc_unit.wait); /* activate unit */
1590 return SCPE_OK;
1591 }
1592
1593 /* Set frequency */
1594
rtc_set_freq(UNIT * uptr,int32 val,char * cptr,void * desc)1595 t_stat rtc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
1596 {
1597 if (cptr)
1598 return SCPE_ARG;
1599 if ((val != 50) && (val != 60))
1600 return SCPE_IERR;
1601 rtc_tps = val;
1602 return SCPE_OK;
1603 }
1604
1605 /* Show frequency */
1606
rtc_show_freq(FILE * st,UNIT * uptr,int32 val,void * desc)1607 t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
1608 {
1609 fprintf (st, (rtc_tps == 50)? "50Hz": "60Hz");
1610 return SCPE_OK;
1611 }
1612
1613 /* Record history */
1614
inst_hist(uint32 ir,uint32 pc,uint32 tp)1615 void inst_hist (uint32 ir, uint32 pc, uint32 tp)
1616 {
1617 hst_p = (hst_p + 1); /* next entry */
1618 if (hst_p >= hst_lnt)
1619 hst_p = 0;
1620 hst[hst_p].typ = tp | (OV << 4);
1621 hst[hst_p].pc = pc;
1622 hst[hst_p].ir = ir;
1623 hst[hst_p].a = A;
1624 hst[hst_p].b = B;
1625 hst[hst_p].x = X;
1626 hst[hst_p].ea = HIST_NOEA;
1627 return;
1628 }
1629
1630 /* Set history */
1631
cpu_set_hist(UNIT * uptr,int32 val,char * cptr,void * desc)1632 t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
1633 {
1634 int32 i, lnt;
1635 t_stat r;
1636
1637 if (cptr == NULL) {
1638 for (i = 0; i < hst_lnt; i++)
1639 hst[i].typ = 0;
1640 hst_p = 0;
1641 return SCPE_OK;
1642 }
1643 lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
1644 if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
1645 return SCPE_ARG;
1646 hst_p = 0;
1647 if (hst_lnt) {
1648 free (hst);
1649 hst_lnt = 0;
1650 hst = NULL;
1651 }
1652 if (lnt) {
1653 hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));
1654 if (hst == NULL)
1655 return SCPE_MEM;
1656 hst_lnt = lnt;
1657 }
1658 return SCPE_OK;
1659 }
1660
1661 /* Show history */
1662
cpu_show_hist(FILE * st,UNIT * uptr,int32 val,void * desc)1663 t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
1664 {
1665 int32 ov, k, di, lnt;
1666 char *cptr = (char *) desc;
1667 t_stat r;
1668 t_value sim_eval;
1669 InstHistory *h;
1670 extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
1671 UNIT *uptr, int32 sw);
1672 static char *cyc[] = { " ", " ", "INT", "TRP" };
1673
1674 if (hst_lnt == 0) /* enabled? */
1675 return SCPE_NOFNC;
1676 if (cptr) {
1677 lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
1678 if ((r != SCPE_OK) || (lnt == 0))
1679 return SCPE_ARG;
1680 }
1681 else lnt = hst_lnt;
1682 di = hst_p - lnt; /* work forward */
1683 if (di < 0)
1684 di = di + hst_lnt;
1685 fprintf (st, "CYC PC OV A B X EA IR\n\n");
1686 for (k = 0; k < lnt; k++) { /* print specified */
1687 h = &hst[(++di) % hst_lnt]; /* entry pointer */
1688 if (h->typ) { /* instruction? */
1689 ov = (h->typ >> 4) & 1; /* overflow */
1690 fprintf (st, "%s %05o %o %08o %08o %08o ", cyc[h->typ & 3],
1691 h->pc, ov, h->a, h->b, h->x);
1692 if (h->ea & HIST_NOEA)
1693 fprintf (st, " ");
1694 else fprintf (st, "%05o ", h->ea);
1695 sim_eval = h->ir;
1696 if ((fprint_sym (st, h->pc, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
1697 fprintf (st, "(undefined) %08o", h->ir);
1698 fputc ('\n', st); /* end line */
1699 } /* end else instruction */
1700 } /* end for */
1701 return SCPE_OK;
1702 }
1703