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