38c2e804b3a5235e646bb9360e40f0f380848eee
1 /* sds_cpu.c: SDS 940 CPU simulator
3 Copyright (c) 2001-2007, Robert M. Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
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
35 The system state for the SDS 940 is:
39 X<0:23> X (index) register
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
51 The SDS 940 has three instruction format -- memory reference, register change,
52 and I/O. The memory reference format is:
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
59 U force user mode addressing (monitor mode only)
61 P opcode is a programmed operator
63 IN indirect addressing
64 address virtual address
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.
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
76 The register change format is:
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
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.
97 1. Reasons to stop. The simulator can be stopped by:
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
109 2. Interrupts. The interrupt structure consists of the following:
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)
116 ion_defer interrupt defer (one instruction)
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.
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.
127 5. Adding I/O devices. These modules must be modified:
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
134 #include "sds_defs.h"
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)
142 #define HIST_XCT 1 /* instruction */
143 #define HIST_INT 2 /* interrupt cycle */
144 #define HIST_TRP 3 /* trap cycle */
146 #define HIST_MAX 65536
147 #define HIST_NOEA 0x40000000
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 */
197 extern int32 sim_int_char
;
198 extern uint32 sim_brk_types
, sim_brk_dflt
, sim_brk_summ
; /* breakpoint info */
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
);
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
);
236 /* CPU data structures
238 cpu_dev CPU device descriptor
239 cpu_unit CPU unit descriptor
240 cpu_reg CPU register list
241 cpu_mod CPU modifiers list
244 UNIT cpu_unit
= { UDATA (NULL
, UNIT_FIX
+ UNIT_BINK
, MAXMEMSIZE
) };
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) },
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
},
296 "CPU", &cpu_unit
, cpu_reg
, cpu_mod
,
298 &cpu_ex
, &cpu_dep
, &cpu_reset
,
303 /* Clock data structures
305 rtc_dev RTC device descriptor
307 rtc_reg RTC register list
310 UNIT rtc_unit
= { UDATA (&rtc_svc
, 0, 0), 16000 };
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
},
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
},
330 "RTC", &rtc_unit
, rtc_reg
, rtc_mod
,
332 NULL
, NULL
, &rtc_reset
,
336 /* Interrupt tables */
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
349 static const uint32 int_vec
[32] = {
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
360 t_stat
sim_instr (void)
362 extern int32 sim_interval
;
363 uint32 inst
, tinst
, pa
, save_P
, save_mode
;
366 /* Restore register state */
368 if (io_init ()) return SCPE_STOP
; /* init IO; conflict? */
370 xfr_req
= xfr_req
& ~1; /* <0> reserved */
371 int_req
= int_req
& ~1; /* <0> reserved */
372 api_lvl
= api_lvl
& ~1; /* <0> reserved */
373 set_dyn_map (); /* set up mapping */
374 int_reqhi
= api_findreq (); /* recalc int req */
375 chan_req
= chan_testact (); /* recalc chan act */
377 /* Main instruction fetch/decode loop */
379 while (reason
== 0) { /* loop until halted */
381 if (cpu_astop
) { /* debug stop? */
386 if (sim_interval
<= 0) { /* event queue? */
387 if (reason
= sim_process_event ()) break; /* process */
388 int_reqhi
= api_findreq (); /* recalc int req */
389 chan_req
= chan_testact (); /* recalc chan act */
392 if (chan_req
) { /* channel request? */
393 if (reason
= chan_process ()) break; /* process */
394 int_reqhi
= api_findreq (); /* recalc int req */
395 chan_req
= chan_testact (); /* recalc chan act */
398 sim_interval
= sim_interval
- 1; /* count down */
399 if (ion
&& !ion_defer
&& int_reqhi
) { /* int request? */
400 pa
= int_vec
[int_reqhi
]; /* get vector */
401 if (pa
== 0) { /* bad value? */
402 reason
= STOP_ILLVEC
;
405 tinst
= ReadP (pa
); /* get inst */
406 save_mode
= usr_mode
; /* save mode */
407 usr_mode
= 0; /* switch to mon */
408 if (hst_lnt
) inst_hist (tinst
, P
, HIST_INT
); /* record inst */
409 if (pa
!= VEC_RTCP
) { /* normal intr? */
410 tr
= one_inst (tinst
, P
, save_mode
); /* exec intr inst */
411 if (tr
) { /* stop code? */
412 usr_mode
= save_mode
; /* restore mode */
413 reason
= (tr
> 0)? tr
: STOP_MMINT
;
416 api_lvl
= api_lvl
| (1u << int_reqhi
); /* set level active */
417 api_lvlhi
= int_reqhi
; /* elevate api */
419 else { /* clock intr */
420 tr
= rtc_inst (tinst
); /* exec RTC inst */
421 usr_mode
= save_mode
; /* restore mode */
422 if (tr
) { /* stop code? */
423 reason
= (tr
> 0)? tr
: STOP_MMINT
;
426 int_req
= int_req
& ~INT_RTCP
; /* clr clkp intr */
428 int_reqhi
= api_findreq (); /* recalc int req */
430 else { /* normal instr */
431 if (sim_brk_summ
&& sim_brk_test (P
, SWMASK ('E'))) { /* breakpoint? */
432 reason
= STOP_IBKPT
; /* stop simulation */
435 reason
= Read (save_P
= P
, &inst
); /* get instr */
436 P
= (P
+ 1) & VA_MASK
; /* incr PC */
437 if (reason
== SCPE_OK
) { /* fetch ok? */
438 ion_defer
= 0; /* clear ion */
439 if (hst_lnt
) inst_hist (inst
, save_P
, HIST_XCT
);
440 reason
= one_inst (inst
, save_P
, usr_mode
); /* exec inst */
441 if (reason
> 0) { /* stop code? */
442 if (reason
!= STOP_HALT
) P
= save_P
;
443 if (reason
== STOP_IONRDY
) reason
= 0;
445 } /* end if r == 0 */
446 if (reason
< 0) { /* mm (fet or ex)? */
447 pa
= -reason
; /* get vector */
448 reason
= 0; /* defang */
449 tinst
= ReadP (pa
); /* get inst */
450 if (I_GETOP (tinst
) != BRM
) { /* not BRM? */
451 reason
= STOP_TRPINS
; /* fatal err */
454 save_mode
= usr_mode
; /* save mode */
455 usr_mode
= 0; /* switch to mon */
457 if (hst_lnt
) inst_hist (tinst
, save_P
, HIST_TRP
);
458 tr
= one_inst (tinst
, save_P
, save_mode
); /* trap inst */
459 if (tr
) { /* stop code? */
460 usr_mode
= save_mode
; /* restore mode */
461 P
= save_P
; /* restore PC */
462 reason
= (tr
> 0)? tr
: STOP_MMTRP
;
465 } /* end if reason */
469 /* Simulation halted */
471 pcq_r
->qptr
= pcq_p
; /* update pc q ptr */
475 /* Simulate one instruction */
477 t_stat
one_inst (uint32 inst
, uint32 pc
, uint32 mode
)
479 uint32 op
, shf_op
, va
, dat
;
480 uint32 old_A
, old_B
, old_X
;
481 int32 i
, exu_cnt
, sc
;
484 exu_cnt
= 0; /* init EXU count */
486 op
= I_GETOP (inst
); /* get opcode */
487 if (inst
& I_POP
) { /* POP? */
488 dat
= (EM3
<< 18) | (EM2
<< 15) | I_IND
| pc
; /* data to save */
489 if (nml_mode
) { /* normal mode? */
490 dat
= (OV
<< 23) | dat
; /* ov in <0> */
493 else if (usr_mode
) { /* user mode? */
494 if (inst
& I_USR
) { /* SYSPOP? */
495 dat
= I_USR
| (OV
<< 21) | dat
; /* ov in <2> */
497 usr_mode
= 0; /* set mon mode */
499 else { /* normal POP */
500 dat
= (OV
<< 23) | dat
; /* ov in <0> */
501 if (r
= Write (0, dat
)) return r
;
504 else { /* mon mode */
505 dat
= (OV
<< 21) | dat
; /* ov in <2> */
506 WriteP (0, dat
); /* store return */
508 PCQ_ENTRY
; /* save PC */
509 P
= 0100 | op
; /* new PC */
510 OV
= 0; /* clear ovflo */
511 return SCPE_OK
; /* end POP */
514 switch (op
) { /* case on opcode */
516 /* Loads and stores */
519 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
520 if (r
= Read (va
, &A
)) return r
; /* get operand */
524 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
525 if (r
= Read (va
, &B
)) return r
; /* get operand */
529 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
530 if (r
= Read (va
, &X
)) return r
; /* get operand */
534 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
535 if (r
= Write (va
, A
)) return r
; /* write operand */
539 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
540 if (r
= Write (va
, B
)) return r
; /* write operand */
544 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
545 if (r
= Write (va
, X
)) return r
; /* write operand */
549 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
550 if (nml_mode
|| usr_mode
) /* normal or user? */
551 X
= (X
& ~VA_MASK
) | (va
& VA_MASK
); /* only 14b */
552 else X
= (X
& ~XVA_MASK
) | (va
& XVA_MASK
); /* mon, 15b */
556 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
557 if (r
= Read (va
, &dat
)) return r
; /* get operand */
558 if (r
= Write (va
, A
)) return r
; /* write A */
559 A
= dat
; /* load A */
562 /* Arithmetic and logical */
565 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
566 if (r
= Read (va
, &dat
)) return r
; /* get operand */
567 A
= Add24 (A
, dat
, 0); /* add */
571 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
572 if (r
= Read (va
, &dat
)) return r
; /* get operand */
573 OV
= 0; /* clear overflow */
574 A
= Add24 (A
, dat
, X
>> 23); /* add with carry */
578 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
579 if (r
= Read (va
, &dat
)) return r
; /* get operand */
580 A
= Add24 (A
, dat
^ DMASK
, 1); /* subtract */
584 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
585 if (r
= Read (va
, &dat
)) return r
; /* get operand */
586 OV
= 0; /* clear overflow */
587 A
= Add24 (A
, dat
^ DMASK
, X
>> 23); /* sub with carry */
591 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
592 if (r
= Read (va
, &dat
)) return r
; /* get operand */
593 dat
= AddM24 (dat
, A
); /* mem + A */
594 if (r
= Write (va
, dat
)) return r
; /* rewrite */
598 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
599 if (r
= Read (va
, &dat
)) return r
; /* get operand */
600 dat
= AddM24 (dat
, 1); /* mem + 1 */
601 if (r
= Write (va
, dat
)) return r
; /* rewrite */
605 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
606 if (r
= Read (va
, &dat
)) return r
; /* get operand */
607 Mul48 (A
, dat
); /* multiply */
611 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
612 if (r
= Read (va
, &dat
)) return r
; /* get operand */
613 Div48 (A
, B
, dat
); /* divide */
617 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
618 if (r
= Read (va
, &dat
)) return r
; /* get operand */
619 A
= A
& dat
; /* and */
623 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
624 if (r
= Read (va
, &dat
)) return r
; /* get operand */
625 A
= A
| dat
; /* or */
629 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
630 if (r
= Read (va
, &dat
)) return r
; /* get operand */
631 A
= A
^ dat
; /* xor */
637 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
638 if (r
= Read (va
, &dat
)) return r
; /* get operand */
639 if (A
== dat
) P
= (P
+ 1) & VA_MASK
; /* if A = op, skip */
643 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
644 if (r
= Read (va
, &dat
)) return r
; /* get operand */
645 if (SXT (A
) > SXT (dat
)) P
= (P
+ 1) & VA_MASK
; /* if A > op, skip */
649 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
650 if (r
= Read (va
, &dat
)) return r
; /* get operand */
651 if (((A
^ dat
) & B
) == 0) P
= (P
+ 1) & VA_MASK
; /* if A = op masked */
655 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
656 if (r
= Read (va
, &dat
)) return r
; /* get operand */
657 if ((A
& dat
) == 0) P
= (P
+ 1) & VA_MASK
; /* if !(A & op), skip */
661 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
662 if (r
= Read (va
, &dat
)) return r
; /* get operand */
663 if ((B
& dat
) == 0) P
= (P
+ 1) & VA_MASK
; /* if !(B & op), skip */
667 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
668 if (r
= Read (va
, &dat
)) return r
; /* get operand */
669 if (dat
& SIGN
) P
= (P
+ 1) & VA_MASK
; /* if op < 0, skip */
673 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
674 if (r
= Read (va
, &dat
)) return r
; /* get operand */
675 dat
= AddM24 (dat
, DMASK
); /* decr operand */
676 if (r
= Write (va
, dat
)) return r
; /* rewrite operand */
677 if (dat
& SIGN
) P
= (P
+ 1) & VA_MASK
; /* if op < 0, skip */
681 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
682 if (r
= Read (va
, &dat
)) return r
; /* get operand */
683 if (SXT_EXP (B
) < SXT_EXP (dat
)) { /* B < dat? */
684 X
= (dat
- B
) & DMASK
; /* X = dat - B */
685 P
= (P
+ 1) & VA_MASK
; /* skip */
687 else X
= (B
- dat
) & DMASK
; /* X = B - dat */
696 if (!nml_mode
&& usr_mode
) return MM_PRVINS
; /* priv inst */
697 return STOP_HALT
; /* halt CPU */
700 exu_cnt
= exu_cnt
+ 1; /* count chained EXU */
701 if (exu_cnt
> exu_lim
) return STOP_EXULIM
; /* too many? */
702 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
703 if (r
= Read (va
, &dat
)) return r
; /* get operand */
708 if (nml_mode
&& (inst
& I_IND
)) api_dismiss (); /* normal BRU*, dism */
709 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
710 if (r
= Read (va
, &dat
)) return r
; /* test dest access */
712 P
= va
& VA_MASK
; /* branch */
716 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
717 X
= (X
+ 1) & DMASK
; /* incr X */
718 if (X
& I_IND
) { /* bit 9 set? */
719 if (r
= Read (va
, &dat
)) return r
; /* test dest access */
721 P
= va
& VA_MASK
; /* branch */
726 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
727 dat
= (EM3
<< 18) | (EM2
<< 15) | pc
; /* form return word */
728 if (!nml_mode
&& !usr_mode
) /* monitor mode? */
729 dat
= dat
| (mode
<< 23) | (OV
<< 21);
730 else dat
= dat
| (OV
<< 23); /* normal or user */
731 if (r
= Write (va
, dat
)) return r
; /* write ret word */
733 P
= (va
+ 1) & VA_MASK
; /* branch */
737 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
738 if (r
= Read (va
, &dat
)) return r
; /* get operand */
740 P
= (dat
+ 1) & VA_MASK
; /* branch */
741 if (!nml_mode
&& !usr_mode
) { /* monitor mode? */
742 OV
= OV
| ((dat
>> 21) & 1); /* restore OV */
743 if ((va
& VA_USR
) | (dat
& I_USR
)) { /* mode change? */
745 if (mon_usr_trap
) return MM_MONUSR
;
748 else OV
= OV
| ((dat
>> 23) & 1); /* restore OV */
752 if (!nml_mode
&& usr_mode
) return MM_PRVINS
; /* priv inst */
753 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
754 if (r
= Read (va
, &dat
)) return r
; /* get operand */
755 api_dismiss (); /* dismiss hi api */
757 P
= dat
& VA_MASK
; /* branch */
758 if (!nml_mode
) { /* monitor mode? */
759 OV
= (dat
>> 21) & 1; /* restore OV */
760 if ((va
& VA_USR
) | (dat
& I_USR
)) { /* mode change? */
762 if (mon_usr_trap
) return MM_MONUSR
;
765 else OV
= (dat
>> 23) & 1; /* restore OV */
768 /* Register change (microprogrammed) */
771 old_A
= A
; /* save orig reg */
774 if (inst
& 000001211) { /* A change? */
775 if (inst
& 01000) dat
= (~old_A
+ 1) & DMASK
; /* CNA */
777 if (inst
& 00200) dat
= dat
| old_X
;
778 if (inst
& 00010) dat
= dat
| old_B
;
779 if (inst
& 00100) A
= (A
& ~EXPMASK
) | (dat
& EXPMASK
);
782 if (inst
& 000000046) { /* B change? */
783 if (inst
& 00040) dat
= old_X
;
785 if (inst
& 00004) dat
= dat
| old_A
;
786 if (inst
& 00100) B
= (B
& ~EXPMASK
) | (dat
& EXPMASK
);
789 if (inst
& 020000420) { /* X change? */
790 if (inst
& 00400) dat
= old_A
;
792 if (inst
& 00020) dat
= dat
| old_B
;
793 if (inst
& 00100) X
= SXT_EXP (dat
) & DMASK
;
798 /* Overflow instruction */
801 if ((inst
& 0100) & OV
) P
= (P
+ 1) & VA_MASK
;
802 if (inst
& 0001) OV
= 0;
803 if ((inst
& 0010) && (((X
>> 1) ^ X
) & EXPS
)) OV
= 1;
809 if (r
= EaSh (inst
, &va
)) return r
; /* decode eff addr */
810 shf_op
= I_GETSHFOP (va
); /* get eff op */
811 sc
= va
& I_SHFMSK
; /* get eff count */
812 switch (shf_op
) { /* case on sub-op */
813 case 00: /* right arithmetic */
814 if (sc
) ShfR48 (sc
, (A
& SIGN
)? DMASK
: 0);
816 case 04: /* right cycle */
817 sc
= sc
% 48; /* mod 48 */
820 case 05: /* right logical */
821 if (sc
) ShfR48 (sc
, 0);
824 CRETINS
; /* invalid inst */
826 } /* end case shf op */
830 if (r
= EaSh (inst
, &va
)) return r
; /* decode eff addr */
831 shf_op
= I_GETSHFOP (va
); /* get eff op */
832 sc
= va
& I_SHFMSK
; /* get eff count */
833 switch (shf_op
) { /* case on sub-op */
834 case 00: /* left arithmetic */
835 dat
= A
; /* save sign */
836 if (sc
> 48) sc
= 48;
837 for (i
= 0; i
< sc
; i
++) { /* loop */
838 A
= ((A
<< 1) | (B
>> 23)) & DMASK
;
839 B
= (B
<< 1) & DMASK
;
840 if ((A
^ dat
) & SIGN
) OV
= 1;
843 case 02: /* normalize */
844 if (sc
> 48) sc
= 48;
845 for (i
= 0; i
< sc
; i
++) { /* until max count */
846 if ((A
^ (A
<< 1)) & SIGN
) break;
847 A
= ((A
<< 1) | (B
>> 23)) & DMASK
;
848 B
= (B
<< 1) & DMASK
;
852 case 04: /* left cycle */
853 sc
= sc
% 48; /* mod 48 */
854 if (sc
) RotR48 (48 - sc
); /* rotate */
856 case 06: /* cycle normalize */
857 if (sc
> 48) sc
= 48;
858 for (i
= 0; i
< sc
; i
++) { /* until max count */
859 if ((A
^ (A
<< 1)) & SIGN
) break;
860 old_A
= A
; /* cyclic shift */
861 A
= ((A
<< 1) | (B
>> 23)) & DMASK
;
862 B
= ((B
<< 1) | (old_A
>> 23)) & DMASK
;
867 CRETINS
; /* invalid inst */
869 } /* end case shf op */
872 /* I/O instructions */
875 if (!nml_mode
&& usr_mode
) return MM_PRVINS
; /* priv inst */
876 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
877 if (r
= Read (va
, &dat
)) return r
; /* get operand */
878 if (r
= op_miwy (inst
, dat
)) return r
; /* process inst */
879 int_reqhi
= api_findreq (); /* recalc int req */
880 chan_req
= chan_testact (); /* recalc chan act */
884 if (!nml_mode
&& usr_mode
) return MM_PRVINS
; /* priv inst */
885 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
886 if (r
= op_wyim (inst
, &dat
)) return r
; /* process inst */
887 if (r
= Write (va
, dat
)) return r
; /* write result */
888 int_reqhi
= api_findreq (); /* recalc int req */
889 chan_req
= chan_testact (); /* recalc chan act */
893 if (!nml_mode
&& usr_mode
) return MM_PRVINS
; /* priv inst */
894 if (r
= op_eomd (inst
)) return r
; /* process inst */
895 int_reqhi
= api_findreq (); /* recalc int req */
896 chan_req
= chan_testact (); /* recalc chan act */
901 if (!nml_mode
&& usr_mode
) return MM_PRVINS
; /* priv inst */
902 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
903 if (r
= Read (va
, &dat
)) return r
; /* get operand */
904 if (r
= op_pot (dat
)) return r
; /* process inst */
905 int_reqhi
= api_findreq (); /* recalc int req */
906 chan_req
= chan_testact (); /* recalc chan act */
910 if (!nml_mode
&& usr_mode
) return MM_PRVINS
; /* priv inst */
911 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
912 if (r
= op_pin (&dat
)) return r
; /* process inst */
913 if (r
= Write (va
, dat
)) return r
; /* write result */
914 int_reqhi
= api_findreq (); /* recalc int req */
915 chan_req
= chan_testact (); /* recalc chan act */
919 if (!nml_mode
&& usr_mode
) return MM_PRVINS
; /* priv inst */
920 if (r
= op_sks (inst
, &dat
)) return r
; /* process inst */
921 if (dat
) P
= (P
+ 1) & VA_MASK
;
925 if (!nml_mode
&& usr_mode
) return MM_PRVINS
; /* usr? priv viol */
926 CRETINS
; /* invalid inst */
933 /* Effective address calculation */
935 t_stat
Ea (uint32 inst
, uint32
*addr
)
938 uint32 wd
= inst
; /* homeable */
939 uint32 va
= wd
& XVA_MASK
; /* initial va */
942 for (i
= 0; i
< ind_lim
; i
++) { /* count indirects */
943 if (wd
& I_IDX
) va
= (va
& VA_USR
) | ((va
+ X
) & VA_MASK
);
945 if ((wd
& I_IND
) == 0) { /* end of ind chain? */
946 if (hst_lnt
) hst
[hst_p
].ea
= *addr
; /* record */
949 if (r
= Read (va
, &wd
)) return r
; /* read ind; fails? */
950 va
= (va
& VA_USR
) | (wd
& XVA_MASK
);
952 return STOP_INDLIM
; /* too many indirects */
955 /* Effective address calculation for shifts - direct indexing is 9b */
957 t_stat
EaSh (uint32 inst
, uint32
*addr
)
960 uint32 wd
= inst
; /* homeable */
961 uint32 va
= wd
& XVA_MASK
; /* initial va */
964 for (i
= 0; i
< ind_lim
; i
++) { /* count indirects */
965 if ((wd
& I_IND
) == 0) { /* end of ind chain? */
966 if (wd
& I_IDX
) *addr
= (va
& (VA_MASK
& ~I_SHFMSK
)) |
967 ((va
+ X
) & I_SHFMSK
); /* 9b indexing */
968 else *addr
= va
& VA_MASK
;
969 if (hst_lnt
) hst
[hst_p
].ea
= *addr
; /* record */
972 if (wd
& I_IDX
) va
= (va
& VA_USR
) | ((va
+ X
) & VA_MASK
);
973 if (r
= Read (va
, &wd
)) return r
; /* read ind; fails? */
974 va
= (va
& VA_USR
) | (wd
& XVA_MASK
);
976 return STOP_INDLIM
; /* too many indirects */
979 /* Read word from virtual address */
981 t_stat
Read (uint32 va
, uint32
*dat
)
985 if (nml_mode
) { /* normal? */
986 va
= va
& VA_MASK
; /* ignore user */
987 if (va
< 020000) pa
= va
; /* first 8K: 1 for 1 */
988 else if (va
< 030000) pa
= va
+ em2_dyn
; /* next 4K: ext EM2 */
989 else pa
= va
+ em3_dyn
; /* next 4K: ext EM3 */
991 else if (usr_mode
|| (va
& VA_USR
)) { /* user mapping? */
992 pgn
= VA_GETPN (va
); /* get page no */
993 map
= usr_map
[pgn
]; /* get map entry */
994 if (map
== MAP_PROT
) return MM_NOACC
; /* prot? no access */
995 pa
= (map
& ~MAP_PROT
) | (va
& VA_POFF
); /* map address */
998 pgn
= VA_GETPN (va
); /* mon, get page no */
999 map
= mon_map
[pgn
]; /* get map entry */
1000 if (map
& MAP_PROT
) return MM_NOACC
; /* prot? no access */
1001 pa
= map
| (va
& VA_POFF
); /* map address */
1003 *dat
= M
[pa
]; /* return word */
1007 /* Write word to virtual address */
1009 t_stat
Write (uint32 va
, uint32 dat
)
1011 uint32 pgn
, map
, pa
;
1013 if (nml_mode
) { /* normal? */
1014 va
= va
& VA_MASK
; /* ignore user */
1015 if (va
< 020000) pa
= va
; /* first 8K: 1 for 1 */
1016 else if (va
< 030000) pa
= va
+ em2_dyn
; /* next 4K: ext EM2 */
1017 else pa
= va
+ em3_dyn
; /* next 4K: ext EM3 */
1019 else if (usr_mode
|| (va
& VA_USR
)) { /* user mapping? */
1020 pgn
= VA_GETPN (va
); /* get page no */
1021 map
= usr_map
[pgn
]; /* get map entry */
1022 if (map
& MAP_PROT
) { /* protected page? */
1023 if (map
== MAP_PROT
) return MM_NOACC
; /* zero? no access */
1024 else return MM_WRITE
; /* else, write prot */
1026 pa
= map
| (va
& VA_POFF
); /* map address */
1029 pgn
= VA_GETPN (va
); /* mon, get page no */
1030 map
= mon_map
[pgn
]; /* get map entry */
1031 if (map
& MAP_PROT
) return MM_NOACC
; /* prot? no access */
1032 pa
= map
| (va
& VA_POFF
); /* map address */
1034 if (MEM_ADDR_OK (pa
)) M
[pa
] = dat
;
1038 /* Relocate addr for console access */
1040 uint32
RelocC (int32 va
, int32 sw
)
1042 uint32 nml
= nml_mode
, usr
= usr_mode
;
1043 uint32 pa
, pgn
, map
;
1045 if (sw
& SWMASK ('N')) nml
= 1; /* -n: normal */
1046 else if (sw
& SWMASK ('X')) nml
= usr
= 0; /* -x: mon */
1047 else if (sw
& SWMASK ('U')) nml
= 0, usr
= 1; /* -u: user */
1048 else if (!(sw
& SWMASK ('V'))) return va
; /* -v: curr */
1050 if (nml
) { /* normal? */
1051 if (va
< 020000) pa
= va
; /* first 8K: 1 for 1 */
1052 else if (va
< 030000) pa
= va
+ em2_dyn
; /* next 4K: ext EM2 */
1053 else pa
= va
+ em3_dyn
; /* next 4K: ext EM3 */
1056 pgn
= VA_GETPN (va
); /* get page no */
1057 map
= usr
? usr_map
[pgn
]: mon_map
[pgn
]; /* get map entry */
1058 if (map
== MAP_PROT
) return MAXMEMSIZE
+ 1; /* no access page? */
1059 pa
= (map
& ~MAP_PROT
) | (va
& VA_POFF
); /* map address */
1064 /* Arithmetic routines */
1066 uint32
Add24 (uint32 s1
, uint32 s2
, uint32 cin
)
1068 uint32 t
= s1
+ s2
+ cin
; /* add with carry in */
1069 if (t
> DMASK
) X
= X
| SIGN
; /* carry to X<0> */
1071 if (((s1
^ ~s2
) & (s1
^ t
)) & SIGN
) OV
= 1; /* overflow */
1075 uint32
AddM24 (uint32 s1
, uint32 s2
)
1077 uint32 t
= s1
+ s2
; /* add */
1078 if (((s1
^ ~s2
) & (s1
^ t
)) & SIGN
) OV
= 1; /* overflow */
1082 void Mul48 (uint32 s1
, uint32 s2
)
1084 uint32 a
= ABS (s1
);
1085 uint32 b
= ABS (s2
);
1086 uint32 hi
, md
, lo
, t
, u
;
1088 if ((a
== 0) || (b
== 0)) { /* ops zero? */
1092 t
= a
>> 12; /* split op1 */
1094 u
= b
>> 12; /* split op2 */
1096 md
= (a
* u
) + (b
* t
); /* cross product */
1097 lo
= (a
* b
) + ((md
& 07777) << 12); /* low result */
1098 hi
= (t
* u
) + (md
>> 12) + (lo
>> 24); /* hi result */
1099 A
= ((hi
<< 1) & DMASK
) | ((lo
& DMASK
) >> 23);
1100 B
= (lo
<< 1) & DMASK
;
1101 if ((s1
^ s2
) & SIGN
) {
1102 B
= ((B
^ DMASK
) + 1) & DMASK
;
1103 A
= ((A
^ DMASK
) + (B
== 0)) & DMASK
;
1105 else if (A
& SIGN
) OV
= 1;
1109 /* Divide - the SDS 940 uses a non-restoring divide. The algorithm
1110 runs even for overflow cases. Hence it must be emulated precisely
1111 to give the right answers for diagnostics. If the dividend is
1112 negative, AB are 2's complemented starting at B<22>, and B<23>
1115 void Div48 (uint32 ar
, uint32 br
, uint32 m
)
1118 uint32 quo
= 0; /* quotient */
1119 uint32 dvdh
= ar
, dvdl
= br
; /* dividend */
1120 uint32 dvr
= ABS (m
); /* make dvr pos */
1122 if (TSTS (dvdh
)) { /* dvd < 0? */
1123 dvdl
= (((dvdl
^ DMASK
) + 2) & (DMASK
& ~1)) | /* 23b negate */
1124 (dvdl
& 1); /* low bit unch */
1125 dvdh
= ((dvdh
^ DMASK
) + (dvdl
<= 1)) & DMASK
;
1127 if ((dvdh
> dvr
) || /* divide fail? */
1128 ((dvdh
== dvr
) && dvdl
) ||
1129 ((dvdh
== dvr
) && !TSTS (ar
^ m
))) OV
= 1;
1130 dvdh
= (dvdh
- dvr
) & DMASK
; /* initial sub */
1131 for (i
= 0; i
< 23; i
++) { /* 23 iterations */
1132 quo
= (quo
<< 1) | ((dvdh
>> 23) ^ 1); /* quo bit = ~sign */
1133 dvdh
= ((dvdh
<< 1) | (dvdl
>> 23)) & DMASK
; /* shift divd */
1134 dvdl
= (dvdl
<< 1) & DMASK
;
1135 if (quo
& 1) /* test ~sign */
1136 dvdh
= (dvdh
- dvr
) & DMASK
; /* sign was +, sub */
1137 else dvdh
= (dvdh
+ dvr
) & DMASK
; /* sign was -, add */
1139 quo
= quo
<< 1; /* shift quo */
1140 if (dvdh
& SIGN
) dvdh
= (dvdh
+ dvr
) & DMASK
; /* last op -? restore */
1141 else quo
= quo
| 1; /* +, set quo bit */
1142 if (TSTS (ar
^ m
)) A
= NEG (quo
); /* sign of quo */
1143 else A
= quo
; /* A = quo */
1144 if (TSTS (ar
)) B
= NEG (dvdh
); /* sign of rem */
1145 else B
= dvdh
; /* B = rem */
1149 void RotR48 (uint32 sc
)
1155 A
= ((B
>> sc
) | (A
<< (24 - sc
))) & DMASK
;
1156 B
= ((t
>> sc
) | (B
<< (24 - sc
))) & DMASK
;
1159 A
= ((A
>> sc
) | (B
<< (24 - sc
))) & DMASK
;
1160 B
= ((B
>> sc
) | (t
<< (24 - sc
))) & DMASK
;
1165 void ShfR48 (uint32 sc
, uint32 sgn
)
1167 if (sc
>= 48) A
= B
= sgn
;
1170 B
= ((A
>> sc
) | (sgn
<< (24 - sc
))) & DMASK
;
1174 B
= ((B
>> sc
) | (A
<< (24 - sc
)) & DMASK
);
1175 A
= ((A
>> sc
) | (sgn
<< (24 - sc
))) & DMASK
;
1180 /* POT routines for RL1, RL2, RL4 */
1182 t_stat
pot_RL1 (uint32 num
, uint32
*dat
)
1189 t_stat
pot_RL2 (uint32 num
, uint32
*dat
)
1196 t_stat
pot_RL4 (uint32 num
, uint32
*dat
)
1198 RL4
= (*dat
) & 03737;
1203 /* Map EM2, EM3, RL1, RL2, RL4 to dynamic forms
1205 EM2, EM3 - left shifted 12, base virtual address subtracted
1206 RL1, RL2 - page left shifted 11
1207 RL3 - filled in as 1 to 1 map
1208 RL4 - EM2 or page left shifted 11, PROT bit inserted
1211 void set_dyn_map (void)
1213 em2_dyn
= ((EM2
& 07) << 12) - 020000;
1214 em3_dyn
= ((EM3
& 07) << 12) - 030000;
1215 usr_map
[0] = (RL1
>> 7) & (MAP_PROT
| MAP_PAGE
);
1216 usr_map
[1] = (RL1
>> 1) & (MAP_PROT
| MAP_PAGE
);
1217 usr_map
[2] = (RL1
<< 5) & (MAP_PROT
| MAP_PAGE
);
1218 usr_map
[3] = (RL1
<< 11) & (MAP_PROT
| MAP_PAGE
);
1219 usr_map
[4] = (RL2
>> 7) & (MAP_PROT
| MAP_PAGE
);
1220 usr_map
[5] = (RL2
>> 1) & (MAP_PROT
| MAP_PAGE
);
1221 usr_map
[6] = (RL2
<< 5) & (MAP_PROT
| MAP_PAGE
);
1222 usr_map
[7] = (RL2
<< 11) & (MAP_PROT
| MAP_PAGE
);
1223 mon_map
[0] = (0 << VA_V_PN
);
1224 mon_map
[1] = (1 << VA_V_PN
);
1225 mon_map
[2] = (2 << VA_V_PN
);
1226 mon_map
[3] = (3 << VA_V_PN
);
1227 mon_map
[4] = ((EM2
& 07) << 12);
1228 mon_map
[5] = ((EM2
& 07) << 12) + (1 << VA_V_PN
);
1229 mon_map
[6] = (RL4
<< 5) & MAP_PAGE
;
1230 mon_map
[7] = (RL4
<< 11) & MAP_PAGE
;
1231 if (mon_map
[6] == 0) mon_map
[6] = MAP_PROT
;
1232 if (mon_map
[7] == 0) mon_map
[7] = MAP_PROT
;
1236 /* Recalculate api requests */
1238 uint32
api_findreq (void)
1242 t
= (int_req
& ~1) & api_mask
[api_lvlhi
]; /* unmasked int */
1243 for (i
= 31; t
&& (i
> 0); i
--) { /* find highest */
1244 if ((t
>> i
) & 1) return i
;
1246 return 0; /* none */
1249 /* Dismiss highest priority interrupt */
1251 void api_dismiss (void)
1255 t
= 1u << api_lvlhi
; /* highest active */
1256 int_req
= int_req
& ~t
; /* clear int req */
1257 api_lvl
= api_lvl
& ~t
; /* clear api level */
1258 api_lvlhi
= 0; /* assume all clear */
1259 for (i
= 31; api_lvl
&& (i
> 0); i
--) { /* find highest api */
1260 if ((api_lvl
>> i
) & 1) { /* bit set? */
1261 api_lvlhi
= i
; /* record level */
1265 int_reqhi
= api_findreq (); /* recalc intreq */
1271 t_stat
cpu_reset (DEVICE
*dptr
)
1276 RL1
= RL2
= RL4
= 0;
1277 ion
= ion_defer
= 0;
1286 pcq_r
= find_reg ("PCQ", NULL
, dptr
);
1287 if (pcq_r
) pcq_r
->qptr
= 0;
1288 else return SCPE_IERR
;
1289 sim_brk_types
= sim_brk_dflt
= SWMASK ('E');
1293 /* Memory examine */
1295 t_stat
cpu_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1299 pa
= RelocC (addr
, sw
);
1300 if (pa
> MAXMEMSIZE
) return SCPE_REL
;
1301 if (pa
>= MEMSIZE
) return SCPE_NXM
;
1302 if (vptr
!= NULL
) *vptr
= M
[pa
] & DMASK
;
1306 /* Memory deposit */
1308 t_stat
cpu_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
1312 pa
= RelocC (addr
, sw
);
1313 if (pa
> MAXMEMSIZE
) return SCPE_REL
;
1314 if (pa
>= MEMSIZE
) return SCPE_NXM
;
1315 M
[pa
] = val
& DMASK
;
1319 /* Set memory size */
1321 t_stat
cpu_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1326 if ((val
<= 0) || (val
> MAXMEMSIZE
) || ((val
& 037777) != 0))
1328 for (i
= val
; i
< MEMSIZE
; i
++) mc
= mc
| M
[i
];
1329 if ((mc
!= 0) && (!get_yn ("Really truncate memory [N]?", FALSE
)))
1332 for (i
= MEMSIZE
; i
< MAXMEMSIZE
; i
++) M
[i
] = 0;
1336 /* Set system type (1 = Genie, 0 = standard) */
1338 t_stat
cpu_set_type (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1340 extern t_stat
drm_reset (DEVICE
*dptr
);
1341 extern DEVICE drm_dev
, mux_dev
, muxl_dev
;
1342 extern UNIT drm_unit
, mux_unit
;
1345 if ((cpu_unit
.flags
& UNIT_GENIE
) == (uint32
) val
) return SCPE_OK
;
1346 if ((drm_unit
.flags
& UNIT_ATT
) || /* attached? */
1347 (mux_unit
.flags
& UNIT_ATT
)) return SCPE_NOFNC
; /* can't do it */
1348 if (val
) { /* Genie? */
1349 drm_dev
.flags
= drm_dev
.flags
& ~DEV_DIS
; /* enb drum */
1350 mux_dev
.flags
= mux_dev
.flags
& ~DEV_DIS
; /* enb mux */
1351 muxl_dev
.flags
= muxl_dev
.flags
& ~DEV_DIS
;
1352 mux_dib
.dev
= DEV3_GMUX
; /* Genie mux */
1355 drm_dev
.flags
= drm_dev
.flags
| DEV_DIS
; /* dsb drum */
1356 mux_dib
.dev
= DEV3_SMUX
; /* std mux */
1357 return drm_reset (&drm_dev
);
1362 /* The real time clock runs continuously; therefore, it only has
1363 a unit service routine and a reset routine. The service routine
1364 sets an interrupt that invokes the clock counter. The clock counter
1365 is a "one instruction interrupt", and only MIN/SKR are valid.
1368 t_stat
rtc_svc (UNIT
*uptr
)
1370 if (rtc_pie
) int_req
= int_req
| INT_RTCP
; /* set pulse intr */
1371 sim_activate (&rtc_unit
, sim_rtcn_calb (rtc_tps
, TMR_RTC
)); /* reactivate */
1375 /* Clock interrupt instruction */
1377 t_stat
rtc_inst (uint32 inst
)
1379 uint32 op
, dat
, val
, va
;
1382 op
= I_GETOP (inst
); /* get opcode */
1383 if (op
== MIN
) val
= 1; /* incr */
1384 else if (op
== SKR
) val
= DMASK
; /* decr */
1385 else return STOP_RTCINS
; /* can't do it */
1386 if (r
= Ea (inst
, &va
)) return r
; /* decode eff addr */
1387 if (r
= Read (va
, &dat
)) return r
; /* get operand */
1388 dat
= AddM24 (dat
, val
); /* mem +/- 1 */
1389 if (r
= Write (va
, dat
)) return r
; /* rewrite */
1390 if (dat
== 0) int_req
= int_req
| INT_RTCS
; /* set clk sync int */
1396 t_stat
rtc_reset (DEVICE
*dptr
)
1398 rtc_pie
= 0; /* disable pulse */
1399 sim_activate (&rtc_unit
, rtc_unit
.wait
); /* activate unit */
1405 t_stat
rtc_set_freq (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1407 if (cptr
) return SCPE_ARG
;
1408 if ((val
!= 50) && (val
!= 60)) return SCPE_IERR
;
1413 /* Show frequency */
1415 t_stat
rtc_show_freq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1417 fprintf (st
, (rtc_tps
== 50)? "50Hz": "60Hz");
1421 /* Record history */
1423 void inst_hist (uint32 ir
, uint32 pc
, uint32 tp
)
1425 hst_p
= (hst_p
+ 1); /* next entry */
1426 if (hst_p
>= hst_lnt
) hst_p
= 0;
1427 hst
[hst_p
].typ
= tp
| (OV
<< 4);
1433 hst
[hst_p
].ea
= HIST_NOEA
;
1439 t_stat
cpu_set_hist (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1445 for (i
= 0; i
< hst_lnt
; i
++) hst
[i
].typ
= 0;
1449 lnt
= (int32
) get_uint (cptr
, 10, HIST_MAX
, &r
);
1450 if ((r
!= SCPE_OK
) || (lnt
&& (lnt
< HIST_MIN
))) return SCPE_ARG
;
1458 hst
= (InstHistory
*) calloc (lnt
, sizeof (InstHistory
));
1459 if (hst
== NULL
) return SCPE_MEM
;
1467 t_stat
cpu_show_hist (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1469 int32 ov
, k
, di
, lnt
;
1470 char *cptr
= (char *) desc
;
1474 extern t_stat
fprint_sym (FILE *ofile
, t_addr addr
, t_value
*val
,
1475 UNIT
*uptr
, int32 sw
);
1476 static char *cyc
[] = { " ", " ", "INT", "TRP" };
1478 if (hst_lnt
== 0) return SCPE_NOFNC
; /* enabled? */
1480 lnt
= (int32
) get_uint (cptr
, 10, hst_lnt
, &r
);
1481 if ((r
!= SCPE_OK
) || (lnt
== 0)) return SCPE_ARG
;
1484 di
= hst_p
- lnt
; /* work forward */
1485 if (di
< 0) di
= di
+ hst_lnt
;
1486 fprintf (st
, "CYC PC OV A B X EA IR\n\n");
1487 for (k
= 0; k
< lnt
; k
++) { /* print specified */
1488 h
= &hst
[(++di
) % hst_lnt
]; /* entry pointer */
1489 if (h
->typ
) { /* instruction? */
1490 ov
= (h
->typ
>> 4) & 1; /* overflow */
1491 fprintf (st
, "%s %05o %o %08o %08o %08o ", cyc
[h
->typ
& 3],
1492 h
->pc
, ov
, h
->a
, h
->b
, h
->x
);
1493 if (h
->ea
& HIST_NOEA
) fprintf (st
, " ");
1494 else fprintf (st
, "%05o ", h
->ea
);
1496 if ((fprint_sym (st
, h
->pc
, &sim_eval
, &cpu_unit
, SWMASK ('M'))) > 0)
1497 fprintf (st
, "(undefined) %08o", h
->ir
);
1498 fputc ('\n', st
); /* end line */
1499 } /* end else instruction */