/* pdp10_cpu.c: PDP-10 CPU simulator | |
Copyright (c) 1993-2008, Robert M. Supnik | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the "Software"), | |
to deal in the Software without restriction, including without limitation | |
the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
and/or sell copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
Except as contained in this notice, the name of Robert M Supnik shall not be | |
used in advertising or otherwise to promote the sale, use or other dealings | |
in this Software without prior written authorization from Robert M Supnik. | |
cpu KS10 central processor | |
17-Jul-07 RMS Fixed non-portable usage in SHOW HISTORY | |
28-Apr-07 RMS Removed clock initialization | |
22-Sep-05 RMS Fixed declarations (from Sterling Garwood) | |
Fixed warning in MOVNI | |
16-Aug-05 RMS Fixed C++ declaration and cast problems | |
10-Nov-04 RMS Added instruction history | |
08-Oct-02 RMS Revised to build dib_tab dynamically | |
Added SHOW IOSPACE | |
30-Dec-01 RMS Added old PC queue | |
25-Dec-01 RMS Cleaned up sim_inst declarations | |
07-Dec-01 RMS Revised to use new breakpoint package | |
21-Nov-01 RMS Implemented ITS 1-proceed hack | |
31-Aug-01 RMS Changed int64 to t_int64 for Windoze | |
10-Aug-01 RMS Removed register in declarations | |
17-Jul-01 RMS Moved function prototype | |
19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug | |
29-Apr-01 RMS Fixed modifier naming conflict | |
Fixed XCTR/XCTRI, UMOVE/UMOVEM, BLTUB/BLTBU for ITS | |
Added CLRCSH for ITS | |
The 36b system family had six different implementions: PDP-6, KA10, KI10, | |
L10, KL10 extended, and KS10. This simulator implements the KS10. | |
The register state for the KS10 is: | |
AC[8][16] accumulators | |
PC program counter | |
flags<0:11> state flags | |
pi_enb<1:7> enabled PI levels | |
pi_act<1:7> active PI levels | |
pi_prq<1:7> program PI requests | |
apr_enb<0:7> enabled system flags | |
apr_flg<0:7> system flags | |
ebr executive base register | |
ubr user base register | |
hsb halt status block address | |
spt SPT base | |
cst CST base | |
pur process use register | |
cstm CST mask | |
The PDP-10 had just two instruction formats: memory reference | |
and I/O. | |
000000000 0111 1 1111 112222222222333333 | |
012345678 9012 3 4567 890123456789012345 | |
+---------+----+-+----+------------------+ | |
| opcode | ac |i| idx| address | memory reference | |
+---------+----+-+----+------------------+ | |
000 0000000 111 1 1111 112222222222333333 | |
012 3456789 012 3 4567 890123456789012345 | |
+---+-------+---+-+----+------------------+ | |
|111|device |iop|i| idx| address | I/O | |
+---+-------+---+-+----+------------------+ | |
This routine is the instruction decode routine for the PDP-10. | |
It is called from the simulator control program to execute | |
instructions in simulated memory, starting at the simulated PC. | |
It runs until an abort occurs. | |
General notes: | |
1. Reasons to stop. The simulator can be stopped by: | |
HALT instruction | |
MUUO instruction in executive mode | |
pager error in interrupt sequence | |
invalid vector table in interrupt sequence | |
illegal instruction in interrupt sequence | |
breakpoint encountered | |
nested indirects exceeding limit | |
nested XCT's exceeding limit | |
I/O error in I/O simulator | |
2. Interrupts. PDP-10's have a seven level priority interrupt | |
system. Interrupt requests can come from internal sources, | |
such as APR program requests, or external sources, such as | |
I/O devices. The requests are stored in pi_prq for program | |
requests, pi_apr for other internal flags, and pi_ioq for | |
I/O device flags. Internal and device (but not program) | |
interrupts must be enabled on a level by level basis. When | |
an interrupt is granted on a level, interrupts at that level | |
and below are masked until the interrupt is dismissed. | |
The I/O device interrupt system is taken from the PDP-11. | |
int_req stores the interrupt requests for Unibus I/O devices. | |
Routines in the Unibus adapter map requests in int_req to | |
PDP-10 levels. The Unibus adapter also calculates which | |
device to get a vector from when a PDP-10 interrupt is granted. | |
3. Arithmetic. The PDP-10 is a 2's complement system. | |
4. Adding I/O devices. These modules must be modified: | |
pdp10_defs.h add device address and interrupt definitions | |
pdp10_sys.c add sim_devices table entry | |
A note on ITS 1-proceed. The simulator follows the implementation | |
on the KS10, keeping 1-proceed as a side flag (its_1pr) rather than | |
as flags<8>. This simplifies the flag saving instructions, which | |
don't have to clear flags<8> before saving it. Instead, the page | |
fail and interrupt code must restore flags<8> from its_1pr. Unlike | |
the KS10, the simulator will not lose the 1-proceed trap if the | |
1-proceeded instructions clears 1-proceed. | |
*/ | |
#include "pdp10_defs.h" | |
#include <setjmp.h> | |
#define PCQ_SIZE 64 /* must be 2**n */ | |
#define PCQ_MASK (PCQ_SIZE - 1) | |
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC | |
#define HIST_PC 0x40000000 | |
#define HIST_MIN 64 | |
#define HIST_MAX 65536 | |
typedef struct { | |
a10 pc; | |
a10 ea; | |
d10 ir; | |
d10 ac; | |
} InstHistory; | |
d10 *M = NULL; /* memory */ | |
d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */ | |
d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */ | |
a10 epta, upta; /* proc tbl addr (dyn) */ | |
a10 saved_PC = 0; /* scp: saved PC */ | |
d10 pager_word = 0; /* pager: error word */ | |
a10 pager_PC = 0; /* pager: saved PC */ | |
int32 pager_flags = 0; /* pager: trap flags */ | |
t_bool pager_pi = FALSE; /* pager: in pi seq */ | |
t_bool pager_tc = FALSE; /* pager: trap cycle */ | |
d10 ebr = 0; /* exec base reg */ | |
d10 ubr = 0; /* user base reg */ | |
d10 hsb = 0; /* halt status block */ | |
d10 spt = 0; /* TOPS20 paging regs */ | |
d10 cst = 0; | |
d10 pur = 0; | |
d10 cstm = 0; | |
a10 dbr1 = 0; /* ITS paging regs */ | |
a10 dbr2 = 0; | |
a10 dbr3 = 0; | |
a10 dbr4 = 0; | |
d10 pcst = 0; /* ITS PC sampling */ | |
int32 pi_on = 0; /* pi system enable */ | |
int32 pi_enb = 0; /* pi enabled levels */ | |
int32 pi_act = 0; /* pi active levels */ | |
int32 pi_ioq = 0; /* pi io requests */ | |
int32 pi_apr = 0; /* pi apr requests */ | |
int32 pi_prq = 0; /* pi prog requests */ | |
int32 apr_enb = 0; /* apr enables */ | |
int32 apr_flg = 0; /* apr flags */ | |
int32 apr_lvl = 0; /* apr level */ | |
int32 qintr = 0; /* interrupt pending */ | |
int32 flags = 0; /* flags */ | |
int32 its_1pr = 0; /* ITS 1-proceed */ | |
int32 stop_op0 = 0; /* stop on 0 */ | |
int32 rlog = 0; /* extend fixup log */ | |
int32 ind_max = 32; /* nested ind limit */ | |
int32 xct_max = 32; /* nested XCT limit */ | |
int32 t20_idlelock = 0; /* TOPS-20 idle lock */ | |
a10 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ | |
int32 pcq_p = 0; /* PC queue ptr */ | |
REG *pcq_r = NULL; /* PC queue reg ptr */ | |
jmp_buf save_env; | |
int32 hst_p = 0; /* history pointer */ | |
int32 hst_lnt = 0; /* history length */ | |
InstHistory *hst = NULL; /* instruction history */ | |
extern int32 sim_int_char; | |
extern int32 sim_interval; | |
extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ | |
/* Forward and external declarations */ | |
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); | |
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); | |
t_stat cpu_reset (DEVICE *dptr); | |
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); | |
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); | |
d10 adjsp (d10 val, a10 ea); | |
void ibp (a10 ea, int32 pflgs); | |
d10 ldb (a10 ea, int32 pflgs); | |
void dpb (d10 val, a10 ea, int32 pflgs); | |
void adjbp (int32 ac, a10 ea, int32 pflgs); | |
d10 add (d10 val, d10 mb); | |
d10 sub (d10 val, d10 mb); | |
void dadd (int32 ac, d10 *rs); | |
void dsub (int32 ac, d10 *rs); | |
int32 jffo (d10 val); | |
d10 lsh (d10 val, a10 ea); | |
d10 rot (d10 val, a10 ea); | |
d10 ash (d10 val, a10 ea); | |
void lshc (int32 ac, a10 ea); | |
void rotc (int32 ac, a10 ea); | |
void ashc (int32 ac, a10 ea); | |
void circ (int32 ac, a10 ea); | |
void blt (int32 ac, a10 ea, int32 pflgs); | |
void bltu (int32 ac, a10 ea, int32 pflgs, int dir); | |
a10 calc_ea (d10 inst, int32 prv); | |
a10 calc_ioea (d10 inst, int32 prv); | |
d10 calc_jrstfea (d10 inst, int32 pflgs); | |
void pi_dismiss (void); | |
void set_newflags (d10 fl, t_bool jrst); | |
extern t_bool aprid (a10 ea, int32 prv); | |
t_bool wrpi (a10 ea, int32 prv); | |
t_bool rdpi (a10 ea, int32 prv); | |
t_bool czpi (a10 ea, int32 prv); | |
t_bool copi (a10 ea, int32 prv); | |
t_bool wrapr (a10 ea, int32 prv); | |
t_bool rdapr (a10 ea, int32 prv); | |
t_bool czapr (a10 ea, int32 prv); | |
t_bool coapr (a10 ea, int32 prv); | |
int32 pi_eval (void); | |
int32 test_int (void); | |
void set_ac_display (d10 *acbase); | |
extern t_stat build_dib_tab (void); | |
extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc); | |
extern d10 Read (a10 ea, int32 prv); /* read, read check */ | |
extern d10 ReadM (a10 ea, int32 prv); /* read, write check */ | |
extern d10 ReadE (a10 ea); /* read, exec */ | |
extern d10 ReadP (a10 ea); /* read, physical */ | |
extern void Write (a10 ea, d10 val, int32 prv); /* write */ | |
extern void WriteE (a10 ea, d10 val); /* write, exec */ | |
extern void WriteP (a10 ea, d10 val); /* write, physical */ | |
extern t_bool AccViol (a10 ea, int32 prv, int32 mode); /* access check */ | |
extern void set_dyn_ptrs (void); | |
extern a10 conmap (a10 ea, int32 mode, int32 sw); | |
extern void fe_intr (); | |
extern void dfad (int32 ac, d10 *rs, int32 inv); | |
extern void dfmp (int32 ac, d10 *rs); | |
extern void dfdv (int32 ac, d10 *rs); | |
extern void dmul (int32 ac, d10 *rs); | |
extern void ddiv (int32 ac, d10 *rs); | |
extern void fix (int32 ac, d10 mb, t_bool rnd); | |
extern d10 fad (d10 val, d10 mb, t_bool rnd, int32 inv); | |
extern d10 fmp (d10 val, d10 mb, t_bool rnd); | |
extern t_bool fdv (d10 val, d10 mb, d10 *rs, t_bool rnd); | |
extern d10 fsc (d10 val, a10 ea); | |
extern d10 fltr (d10 mb); | |
extern int xtend (int32 ac, a10 ea, int32 pflgs); | |
extern void xtcln (int32 rlog); | |
extern d10 map (a10 ea, int32 prv); | |
extern d10 imul (d10 val, d10 mb); | |
extern t_bool idiv (d10 val, d10 mb, d10 *rs); | |
extern void mul (d10 val, d10 mb, d10 *rs); | |
extern t_bool divi (int32 ac, d10 mb, d10 *rs); | |
extern t_bool io710 (int32 ac, a10 ea); | |
extern t_bool io711 (int32 ac, a10 ea); | |
extern d10 io712 (a10 ea); | |
extern void io713 (d10 val, a10 ea); | |
extern void io714 (d10 val, a10 ea); | |
extern void io715 (d10 val, a10 ea); | |
extern t_bool io720 (int32 ac, a10 ea); | |
extern t_bool io721 (int32 ac, a10 ea); | |
extern d10 io722 (a10 ea); | |
extern void io723 (d10 val, a10 ea); | |
extern void io724 (d10 val, a10 ea); | |
extern void io725 (d10 val, a10 ea); | |
extern t_bool clrcsh (a10 ea, int32 prv); | |
extern t_bool clrpt (a10 ea, int32 prv); | |
extern t_bool wrubr (a10 ea, int32 prv); | |
extern t_bool wrebr (a10 ea, int32 prv); | |
extern t_bool wrhsb (a10 ea, int32 prv); | |
extern t_bool wrspb (a10 ea, int32 prv); | |
extern t_bool wrcsb (a10 ea, int32 prv); | |
extern t_bool wrpur (a10 ea, int32 prv); | |
extern t_bool wrcstm (a10 ea, int32 prv); | |
extern t_bool ldbr1 (a10 ea, int32 prv); | |
extern t_bool ldbr2 (a10 ea, int32 prv); | |
extern t_bool ldbr3 (a10 ea, int32 prv); | |
extern t_bool ldbr4 (a10 ea, int32 prv); | |
extern t_bool rdubr (a10 ea, int32 prv); | |
extern t_bool rdebr (a10 ea, int32 prv); | |
extern t_bool rdhsb (a10 ea, int32 prv); | |
extern t_bool rdspb (a10 ea, int32 prv); | |
extern t_bool rdcsb (a10 ea, int32 prv); | |
extern t_bool rdpur (a10 ea, int32 prv); | |
extern t_bool rdcstm (a10 ea, int32 prv); | |
extern t_bool sdbr1 (a10 ea, int32 prv); | |
extern t_bool sdbr2 (a10 ea, int32 prv); | |
extern t_bool sdbr3 (a10 ea, int32 prv); | |
extern t_bool sdbr4 (a10 ea, int32 prv); | |
extern t_bool rdtim (a10 ea, int32 prv); | |
extern t_bool rdint (a10 ea, int32 prv); | |
extern t_bool wrtim (a10 ea, int32 prv); | |
extern t_bool wrint (a10 ea, int32 prv); | |
extern t_bool rdpcst (a10 ea, int32 prv); | |
extern t_bool wrpcst (a10 ea, int32 prv); | |
extern t_bool spm (a10 ea, int32 prv); | |
extern t_bool lpmr (a10 ea, int32 prv); | |
extern int32 pi_ub_vec (int32 lvl, int32 *uba); | |
extern t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc); | |
/* CPU data structures | |
cpu_dev CPU device descriptor | |
cpu_unit CPU unit | |
cpu_reg CPU register list | |
cpu_mod CPU modifier list | |
*/ | |
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MAXMEMSIZE) }; | |
REG cpu_reg[] = { | |
{ ORDATA (PC, saved_PC, VASIZE) }, | |
{ ORDATA (FLAGS, flags, 18) }, | |
{ ORDATA (AC0, acs[0], 36) }, /* addr in memory */ | |
{ ORDATA (AC1, acs[1], 36) }, /* modified at exit */ | |
{ ORDATA (AC2, acs[2], 36) }, /* to SCP */ | |
{ ORDATA (AC3, acs[3], 36) }, | |
{ ORDATA (AC4, acs[4], 36) }, | |
{ ORDATA (AC5, acs[5], 36) }, | |
{ ORDATA (AC6, acs[6], 36) }, | |
{ ORDATA (AC7, acs[7], 36) }, | |
{ ORDATA (AC10, acs[10], 36) }, | |
{ ORDATA (AC11, acs[11], 36) }, | |
{ ORDATA (AC12, acs[12], 36) }, | |
{ ORDATA (AC13, acs[13], 36) }, | |
{ ORDATA (AC14, acs[14], 36) }, | |
{ ORDATA (AC15, acs[15], 36) }, | |
{ ORDATA (AC16, acs[16], 36) }, | |
{ ORDATA (AC17, acs[17], 36) }, | |
{ ORDATA (PFW, pager_word, 36) }, | |
{ ORDATA (EBR, ebr, EBR_N_EBR) }, | |
{ FLDATA (PGON, ebr, EBR_V_PGON) }, | |
{ FLDATA (T20P, ebr, EBR_V_T20P) }, | |
{ ORDATA (UBR, ubr, 36) }, | |
{ GRDATA (CURAC, ubr, 8, 3, UBR_V_CURAC), REG_RO }, | |
{ GRDATA (PRVAC, ubr, 8, 3, UBR_V_PRVAC) }, | |
{ ORDATA (SPT, spt, 36) }, | |
{ ORDATA (CST, cst, 36) }, | |
{ ORDATA (PUR, pur, 36) }, | |
{ ORDATA (CSTM, cstm, 36) }, | |
{ ORDATA (HSB, hsb, 36) }, | |
{ ORDATA (DBR1, dbr1, PASIZE) }, | |
{ ORDATA (DBR2, dbr2, PASIZE) }, | |
{ ORDATA (DBR3, dbr3, PASIZE) }, | |
{ ORDATA (DBR4, dbr4, PASIZE) }, | |
{ ORDATA (PCST, pcst, 36) }, | |
{ ORDATA (PIENB, pi_enb, 7) }, | |
{ FLDATA (PION, pi_on, 0) }, | |
{ ORDATA (PIACT, pi_act, 7) }, | |
{ ORDATA (PIPRQ, pi_prq, 7) }, | |
{ ORDATA (PIIOQ, pi_ioq, 7), REG_RO }, | |
{ ORDATA (PIAPR, pi_apr, 7), REG_RO }, | |
{ ORDATA (APRENB, apr_enb, 8) }, | |
{ ORDATA (APRFLG, apr_flg, 8) }, | |
{ ORDATA (APRLVL, apr_lvl, 3) }, | |
{ ORDATA (RLOG, rlog, 10) }, | |
{ FLDATA (F1PR, its_1pr, 0) }, | |
{ BRDATA (PCQ, pcq, 8, VASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, | |
{ ORDATA (PCQP, pcq_p, 6), REG_HRO }, | |
{ DRDATA (INDMAX, ind_max, 8), PV_LEFT + REG_NZ }, | |
{ DRDATA (XCTMAX, xct_max, 8), PV_LEFT + REG_NZ }, | |
{ ORDATA (WRU, sim_int_char, 8) }, | |
{ FLDATA (STOP_ILL, stop_op0, 0) }, | |
{ BRDATA (REG, acs, 8, 36, AC_NUM * AC_NBLK) }, | |
{ NULL } | |
}; | |
MTAB cpu_mod[] = { | |
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, "TOPS-10", "TOPS-10", &tim_set_mod }, | |
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, NULL , "TOPS10", &tim_set_mod }, | |
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, "TOPS-20", "TOPS-20", &tim_set_mod }, | |
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, NULL, "TOPS20", &tim_set_mod }, | |
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_ITS, "ITS", "ITS", &tim_set_mod }, | |
{ UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_KLAD, "diagnostic mode", "KLAD", &tim_set_mod }, | |
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, | |
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, | |
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, | |
NULL, &show_iospace }, | |
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", | |
&cpu_set_hist, &cpu_show_hist }, | |
{ 0 } | |
}; | |
DEVICE cpu_dev = { | |
"CPU", &cpu_unit, cpu_reg, cpu_mod, | |
1, 8, PASIZE, 1, 8, 36, | |
&cpu_ex, &cpu_dep, &cpu_reset, | |
NULL, NULL, NULL | |
}; | |
/* Data arrays */ | |
const int32 pi_l2bit[8] = { | |
0, 0100, 0040, 0020, 0010, 0004, 0002, 0001 | |
}; | |
const int32 pi_m2lvl[128] = { | |
0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, | |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 | |
}; | |
const d10 bytemask[64] = { 0, | |
01, 03, 07, 017, 037, 077, | |
0177, 0377, 0777, 01777, 03777, 07777, | |
017777, 037777, 077777, | |
0177777, 0377777, 0777777, | |
01777777, 03777777, 07777777, | |
017777777, 037777777, 077777777, | |
0177777777, 0377777777, 0777777777, | |
01777777777, 03777777777, 07777777777, | |
017777777777, 037777777777, 077777777777, | |
0177777777777, 0377777777777, 0777777777777, | |
ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, | |
ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, | |
ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES | |
}; | |
static t_bool (*io700d[16])() = { | |
&aprid, NULL, NULL, NULL, &wrapr, &rdapr, &czapr, &coapr, | |
NULL, NULL, NULL, NULL, &wrpi, &rdpi, &czpi, &copi | |
}; | |
static t_bool (*io701d[16])() = { | |
NULL, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, | |
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL | |
}; | |
static t_bool (*io702d[16])() = { | |
&rdspb, &rdcsb, &rdpur, &rdcstm, &rdtim, &rdint, &rdhsb, NULL, | |
&wrspb, &wrcsb, &wrpur, &wrcstm, &wrtim, &wrint, &wrhsb, NULL | |
}; | |
#define io700i io700d | |
static t_bool (*io701i[16])() = { | |
&clrcsh, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, | |
NULL, &rdpcst, NULL, &wrpcst, NULL, NULL, NULL, NULL | |
}; | |
static t_bool (*io702i[16])() = { | |
&sdbr1, &sdbr2, &sdbr3, &sdbr4, &rdtim, &rdint, &rdhsb, &spm, | |
&ldbr1, &ldbr2, &ldbr3, &ldbr4, &wrtim, &wrint, &wrhsb, &lpmr | |
}; | |
/* JRST classes and validation table */ | |
#define JRST_U 1 /* ok anywhere */ | |
#define JRST_E 2 /* ok exec mode */ | |
#define JRST_UIO 3 /* ok user I/O mode */ | |
static t_stat jrst_tab[16] = { | |
JRST_U, JRST_U, JRST_U, 0, JRST_E, JRST_U, JRST_E, JRST_E, | |
JRST_UIO, 0, JRST_UIO, 0, JRST_E, JRST_U, 0, 0 | |
}; | |
/* Address operations */ | |
#define IM ((d10) ea) | |
#define IMS (((d10) ea) << 18) | |
#define JUMP(x) PCQ_ENTRY, PC = ((a10) (x)) & AMASK | |
#define SUBJ(x) CLRF (F_AFI | F_FPD | F_TR); JUMP (x) | |
#define INCPC PC = INCA (PC) | |
/* AC operations */ | |
#define AOBAC AC(ac) = AOB (AC(ac)) | |
#define SOBAC AC(ac) = SOB (AC(ac)) | |
#define G2AC rs[0] = AC(ac), rs[1] = AC(P1) | |
#define S1AC AC(ac) = rs[0] | |
#define S2AC S1AC, AC(P1) = rs[1] | |
#define LAC if (ac) AC(ac) = mb | |
/* Memory operations */ | |
#define RD mb = Read (ea, MM_OPND) | |
#define RDAC AC(ac) = Read (ea, MM_OPND) | |
#define RM mb = ReadM (ea, MM_OPND) | |
#define RMAC AC(ac) = ReadM (ea, MM_OPND) | |
#define RDP mb = Read (((a10) AC(ac)) & AMASK, MM_BSTK) | |
#define RD2 rs[0] = Read (ea, MM_OPND); \ | |
rs[1] = Read (INCA (ea), MM_OPND) | |
#define WR Write (ea, mb, MM_OPND) | |
#define WRAC Write (ea, AC(ac), MM_OPND) | |
#define WRP(x) Write (((a10) INCA (AC(ac))), (x), MM_BSTK) | |
#define WR1 Write (ea, rs[0], MM_OPND) | |
#define WR2 ReadM (INCA (ea), MM_OPND); \ | |
Write (ea, rs[0], MM_OPND); \ | |
Write (INCA (ea), rs[1], MM_OPND) | |
/* Tests and compares */ | |
#define TL(a) (TSTS (a) != 0) | |
#define TE(a) ((a) == 0) | |
#define TLE(a) (TL (a) || TE (a)) | |
#define TGE(a) (TSTS (a) == 0) | |
#define TN(a) ((a) != 0) | |
#define TG(a) (TGE (a) && TN (a)) | |
#define CL(a) ((TSTS (AC(ac) ^ a))? (a < AC(ac)): (AC(ac) < a)) | |
#define CE(a) (AC(ac) == a) | |
#define CLE(a) (CL (a) || CE (a)) | |
#define CGE(a) (!CL (a)) | |
#define CN(a) (AC(ac) != a) | |
#define CG(a) (CGE (a) && CN (a)) | |
/* Word assemblies */ | |
#define FLPC XWD (flags, PC) | |
#define UUOWORD (((d10) op) << INST_V_OP) | (((d10) ac) << INST_V_AC) | ea | |
#define APRHWORD ((apr_flg << APR_V_FLG) | (apr_lvl & APR_M_LVL) | \ | |
((apr_flg & apr_enb)? APR_IRQ: 0)) | |
#define APRWORD ((apr_enb << (APR_V_FLG + 18)) | APRHWORD) | |
#define PIHWORD ((pi_act << PI_V_ACT) | (pi_on << PI_V_ON) | \ | |
(pi_enb << PI_V_ENB)) | |
#define PIWORD ((pi_prq << PI_V_PRQ) | PIHWORD) | |
/* Instruction operations */ | |
#define CIBP if (!TSTF (F_FPD)) { ibp (ea, pflgs); SETF (F_FPD); } | |
#define LDB AC(ac) = ldb (ea, pflgs) | |
#define DPB dpb (AC(ac), ea, pflgs) | |
#define FAD(s) fad (AC(ac), s, FALSE, 0) | |
#define FADR(s) fad (AC(ac), s, TRUE, 0) | |
#define FSB(s) fad (AC(ac), s, FALSE, 1) | |
#define FSBR(s) fad (AC(ac), s, TRUE, 1) | |
#define FMP(s) fmp (AC(ac), s, FALSE) | |
#define FMPR(s) fmp (AC(ac), s, TRUE) | |
#define FDV(s) fdv (AC(ac), s, rs, FALSE) | |
#define FDVR(s) fdv (AC(ac), s, rs, TRUE) | |
#define MOVN(s) NEG (s); MOVNF(s) | |
#define MOVM(s) ABS (s); MOVMF(s) | |
#define ADD(s) add (AC(ac), s) | |
#define SUB(s) sub (AC(ac), s) | |
#define IMUL(s) imul (AC(ac), s) | |
#define IDIV(s) idiv (AC(ac), s, rs) | |
#define MUL(s) mul (AC(ac), s, rs) | |
#define DIV(s) divi (ac, s, rs) | |
#define AOJ AC(ac) = INC (AC(ac)); INCF (AC(ac)) | |
#define AOS RM; mb = INC (mb); WR; INCF (mb); LAC | |
#define SOJ AC(ac) = DEC (AC(ac)); DECF (AC(ac)) | |
#define SOS RM; mb = DEC (mb); WR; DECF (mb); LAC | |
#define SETCA(s) ~AC(ac) & DMASK | |
#define SETCM(s) ~(s) & DMASK; | |
#define AND(s) AC(ac) & (s) | |
#define ANDCA(s) ~AC(ac) & (s) | |
#define ANDCM(s) AC(ac) & ~(s) | |
#define ANDCB(s) (~AC(ac) & ~(s)) & DMASK | |
#define IOR(s) AC(ac) | (s) | |
#define ORCA(s) (~AC(ac) | (s)) & DMASK | |
#define ORCM(s) (AC(ac) | ~(s)) & DMASK | |
#define ORCB(s) (~AC(ac) | ~(s)) & DMASK | |
#define XOR(s) AC(ac) ^ (s) | |
#define EQV(s) (~(AC(ac) ^ (s))) & DMASK | |
#define LL(s,d) ((s) & LMASK) | ((d) & RMASK) | |
#define RL(s,d) (((s) << 18) & LMASK) | ((d) & RMASK) | |
#define RR(s,d) ((s) & RMASK) | ((d) & LMASK) | |
#define LR(s,d) (((s) >> 18) & RMASK) | ((d) & LMASK) | |
#define LLO(s) ((s) & LMASK) | RMASK | |
#define RLO(s) (((s) << 18) & LMASK) | RMASK | |
#define RRO(s) ((s) & RMASK) | LMASK | |
#define LRO(s) (((s) >> 18) & RMASK) | LMASK | |
#define LLE(s) ((s) & LMASK) | (((s) & LSIGN)? RMASK: 0) | |
#define RLE(s) (((s) << 18) & LMASK) | (((s) & RSIGN)? RMASK: 0) | |
#define RRE(s) ((s) & RMASK) | (((s) & RSIGN)? LMASK: 0) | |
#define LRE(s) (((s) >> 18) & RMASK) | (((s) & LSIGN)? LMASK: 0) | |
#define TD_ RD | |
#define TS_ RD; mb = SWP (mb) | |
#define TL_ mb = IMS | |
#define TR_ mb = IM | |
#define T_Z AC(ac) = AC(ac) & ~mb | |
#define T_O AC(ac) = AC(ac) | mb | |
#define T_C AC(ac) = AC(ac) ^ mb | |
#define T__E if ((AC(ac) & mb) == 0) INCPC | |
#define T__N if ((AC(ac) & mb) != 0) INCPC | |
#define T__A INCPC | |
#define IOC if (TSTF (F_USR) && !TSTF (F_UIO)) goto MUUO; | |
#define IO7(x,y) IOC; fptr = ((Q_ITS)? x[ac]: y[ac]); \ | |
if (fptr == NULL) goto MUUO; \ | |
if (fptr (ea, MM_OPND)) INCPC; break; | |
#define IOA IOC; if (!Q_ITS) ea = calc_ioea (inst, pflgs) | |
#define IOAM IOC; ea = ((Q_ITS)? ((a10) Read (ea, MM_OPND)): \ | |
calc_ioea (inst, pflgs)) | |
/* Flag tests */ | |
#define MOVNF(x) if ((x) == MAXNEG) SETF (F_C1 | F_AOV | F_T1); \ | |
else if ((x) == 0) SETF (F_C0 | F_C1) | |
#define MOVMF(x) if ((x) == MAXNEG) SETF (F_C1 | F_AOV | F_T1) | |
#define INCF(x) if ((x) == 0) SETF (F_C0 | F_C1); \ | |
else if ((x) == MAXNEG) SETF (F_C1 | F_AOV | F_T1) | |
#define DECF(x) if ((x) == MAXPOS) SETF (F_C0 | F_AOV | F_T1); \ | |
else if ((x) != ONES) SETF (F_C0 | F_C1) | |
#define PUSHF if (LRZ (AC(ac)) == 0) SETF (F_T2) | |
#define POPF if (LRZ (AC(ac)) == RMASK) SETF (F_T2) | |
#define DMOVNF if (rs[1] == 0) { MOVNF (rs[0]); } | |
t_stat sim_instr (void) | |
{ | |
a10 PC; /* set by setjmp */ | |
int abortval = 0; /* abort value */ | |
t_stat r; | |
/* Restore register state */ | |
if ((r = build_dib_tab ()) != SCPE_OK) /* build, chk dib_tab */ | |
return r; | |
pager_PC = PC = saved_PC & AMASK; /* load local PC */ | |
set_dyn_ptrs (); /* set up local ptrs */ | |
pager_tc = FALSE; /* not in trap cycle */ | |
pager_pi = FALSE; /* not in pi sequence */ | |
rlog = 0; /* not in extend */ | |
pi_eval (); /* eval pi system */ | |
if (!Q_ITS) /* ~ITS, clr 1-proc */ | |
its_1pr = 0; | |
t20_idlelock = 0; /* clr T20 idle lock */ | |
/* Abort handling | |
Aborts may come from within the simulator to stop simulation (values > 0), | |
for page fails (values < 0), or for an interrupt check (value = 0). | |
*/ | |
abortval = setjmp (save_env); /* set abort hdlr */ | |
if ((abortval > 0) || pager_pi) { /* stop or pi err? */ | |
if (pager_pi && (abortval == PAGE_FAIL)) | |
abortval = STOP_PAGINT; /* stop for pi err */ | |
saved_PC = pager_PC & AMASK; /* failing instr PC */ | |
set_ac_display (ac_cur); /* set up AC display */ | |
pcq_r->qptr = pcq_p; /* update pc q ptr */ | |
return abortval; /* return to SCP */ | |
} | |
/* Page fail - checked against KS10 ucode | |
All state variables MUST be declared global for GCC optimization to work | |
*/ | |
else if (abortval == PAGE_FAIL) { /* page fail */ | |
d10 mb; | |
if (rlog) /* clean up extend */ | |
xtcln (rlog); | |
rlog = 0; /* clear log */ | |
if (pager_tc) /* trap? get flags */ | |
flags = pager_flags; | |
if (T20PAG) { /* TOPS-20 paging? */ | |
WriteP (upta + UPT_T20_PFL, pager_word); /* write page fail wd */ | |
WriteP (upta + UPT_T20_OFL, XWD (flags, 0)); | |
WriteP (upta + UPT_T20_OPC, pager_PC); | |
mb = ReadP (upta + UPT_T20_NPC); | |
} | |
else { | |
a10 ea; /* TOPS-10 or ITS */ | |
if (Q_ITS) { /* ITS? */ | |
ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3); | |
if (its_1pr) /* store 1-proc */ | |
flags = flags | F_1PR; | |
its_1pr = 0; /* clear 1-proc */ | |
} | |
else ea = upta + UPT_T10_PAG; | |
WriteP (ea, pager_word); /* write page fail wd */ | |
WriteP (ADDA (ea, 1), XWD (flags, pager_PC)); | |
mb = ReadP (ADDA (ea, 2)); | |
} | |
JUMP (mb); /* set new PC */ | |
set_newflags (mb, FALSE); /* set new flags */ | |
pi_eval (); /* eval pi system */ | |
} | |
else PC = pager_PC; /* intr, restore PC */ | |
/* Main instruction fetch/decode loop: check clock queue, intr, trap, bkpt */ | |
for ( ;; ) { /* loop until ABORT */ | |
int32 op, ac, i, st, xr, xct_cnt, its_2pr, pflgs; | |
a10 ea; | |
d10 inst, mb, indrct, rs[2]; | |
t_bool (*fptr)(); | |
pager_PC = PC; /* update pager PC */ | |
pager_tc = FALSE; /* not in trap cycle */ | |
pflgs = 0; /* not in PXCT */ | |
xct_cnt = 0; /* count XCT's */ | |
if (sim_interval <= 0) { /* check clock queue */ | |
if (i = sim_process_event ()) /* error? stop sim */ | |
ABORT (i); | |
pi_eval (); /* eval pi system */ | |
} | |
/* PI interrupt (Unibus or system flags). | |
On the KS10, only JSR and XPCW are allowed as interrupt instructions. | |
Because of exec mode addressing, and unconditional processing of flags, | |
they are explicitly emulated here. | |
*/ | |
if (qintr) { | |
int32 vec, uba; | |
pager_pi = TRUE; /* flag in pi seq */ | |
if (vec = pi_ub_vec (qintr, &uba)) { /* Unibus interrupt? */ | |
mb = ReadP (epta + EPT_UBIT + uba); /* get dispatch table */ | |
if (mb == 0) /* invalid? stop */ | |
ABORT (STOP_ZERINT); | |
inst = ReadE ((((a10) mb) + (vec / 4)) & AMASK); | |
if (inst == 0) | |
ABORT (STOP_ZERINT); | |
} | |
else inst = ReadP (epta + EPT_PIIT + (2 * qintr)); | |
op = GET_OP (inst); /* get opcode */ | |
ac = GET_AC (inst); /* get ac */ | |
if (its_1pr && Q_ITS) { /* 1-proc set? */ | |
flags = flags | F_1PR; /* store 1-proc */ | |
its_1pr = 0; /* clear 1-proc */ | |
} | |
if (op == OP_JSR) { /* JSR? */ | |
ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */ | |
WriteE (ea, FLPC); /* save flags+PC, exec */ | |
JUMP (INCA (ea)); /* PC = ea + 1 */ | |
set_newflags (0, FALSE); /* set new flags */ | |
} | |
else if ((op == OP_JRST) && (ac == AC_XPCW)) { /* XPCW? */ | |
ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */ | |
WriteE (ea, XWD (flags, 0)); /* write flags, exec */ | |
WriteE (ADDA (ea, 1), PC); /* write PC, exec */ | |
rs[0] = ReadE (ADDA (ea, 2)); /* read new flags */ | |
rs[1] = ReadE (ADDA (ea, 3)); /* read new PC */ | |
JUMP (rs[1]); /* set new PC */ | |
set_newflags (rs[0], FALSE); /* set new flags */ | |
} | |
else ABORT (STOP_ILLINT); /* invalid instr */ | |
pi_act = pi_act | pi_l2bit[qintr]; /* set level active */ | |
pi_eval (); /* eval pi system */ | |
pager_pi = FALSE; /* end of sequence */ | |
if (sim_interval) /* charge for instr */ | |
sim_interval--; | |
continue; | |
} /* end if interrupt */ | |
/* Traps fetch and execute an instruction from the current mode process table. | |
On the KS10, the fetch of the next instruction has started, and a page fail | |
trap on the instruction fetch takes precedence over the trap. During a trap, | |
flags are cleared before the execute, but if the execute aborts, they must | |
be restored. Also, the MUUO processor needs to know whether we are in a | |
trap sequence. Hence, trap in progress is recorded in pflgs, and the | |
traps for pager restoration are recorded in pager_flags. | |
*/ | |
if (TSTF (F_T1 | F_T2) && PAGING) { | |
Read (pager_PC = PC, MM_CUR); /* test fetch */ | |
pager_tc = TRUE; /* in a trap sequence */ | |
pager_flags = flags; /* save flags */ | |
ea = (TSTF (F_USR)? upta + UPT_TRBASE: epta + EPT_TRBASE) | |
+ GET_TRAPS (flags); | |
inst = ReadP (ea); /* get trap instr */ | |
CLRF (F_T1 | F_T2); /* clear flags */ | |
} | |
/* Test for instruction breakpoint */ | |
else { | |
if (sim_brk_summ && | |
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ | |
ABORT (STOP_IBKPT); /* stop simulation */ | |
} | |
/* Ready (at last) to get an instruction */ | |
inst = Read (pager_PC = PC, MM_CUR); /* get instruction */ | |
INCPC; | |
sim_interval = sim_interval - 1; | |
} | |
its_2pr = its_1pr; /* save 1-proc flag */ | |
/* Execute instruction. XCT and PXCT also return here. */ | |
XCT: | |
op = GET_OP (inst); /* get opcode */ | |
ac = GET_AC (inst); /* get AC */ | |
for (indrct = inst, i = 0; i < ind_max; i++) { /* calc eff addr */ | |
ea = GET_ADDR (indrct); | |
xr = GET_XR (indrct); | |
if (xr) | |
ea = (ea + ((a10) XR (xr, MM_EA))) & AMASK; | |
if (TST_IND (indrct)) | |
indrct = Read (ea, MM_EA); | |
else break; | |
} | |
if (i >= ind_max) | |
ABORT (STOP_IND); /* too many ind? stop */ | |
if (hst_lnt) { /* history enabled? */ | |
hst_p = (hst_p + 1); /* next entry */ | |
if (hst_p >= hst_lnt) | |
hst_p = 0; | |
hst[hst_p].pc = pager_PC | HIST_PC; | |
hst[hst_p].ea = ea; | |
hst[hst_p].ir = inst; | |
hst[hst_p].ac = AC(ac); | |
} | |
switch (op) { /* case on opcode */ | |
/* UUO's (0000 - 0077) - checked against KS10 ucode */ | |
case 0000: if (stop_op0) { | |
ABORT (STOP_ILLEG); | |
} | |
goto MUUO; | |
case 0001: /* local UUO's */ | |
case 0002: | |
case 0003: | |
case 0004: | |
case 0005: | |
case 0006: | |
case 0007: | |
case 0010: | |
case 0011: | |
case 0012: | |
case 0013: | |
case 0014: | |
case 0015: | |
case 0016: | |
case 0017: | |
case 0020: | |
case 0021: | |
case 0022: | |
case 0023: | |
case 0024: | |
case 0025: | |
case 0026: | |
case 0027: | |
case 0030: | |
case 0031: | |
case 0032: | |
case 0033: | |
case 0034: | |
case 0035: | |
case 0036: | |
case 0037: Write (040, UUOWORD, MM_CUR); /* store op, ac, ea */ | |
inst = Read (041, MM_CUR); /* get new instr */ | |
goto XCT; | |
/* case 0040 - 0077: MUUO's, handled by default at end of case */ | |
/* Floating point, bytes, multiple precision (0100 - 0177) */ | |
/* case 0100: MUUO /* UJEN */ | |
/* case 0101: MUUO /* unassigned */ | |
case 0102: if (Q_ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */ | |
inst = Read (ea, MM_OPND); | |
pflgs = pflgs | ac; | |
goto XCT; | |
} | |
goto MUUO; | |
case 0103: if (Q_ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) */ | |
inst = Read (ea, MM_OPND); | |
pflgs = pflgs | ac; | |
goto XCT; | |
} | |
goto MUUO; | |
/* case 0104: MUUO /* JSYS (T20) */ | |
case 0105: AC(ac) = adjsp (AC(ac), ea); break; /* ADJSP */ | |
/* case 0106: MUUO /* GFMP (KL)*/ | |
/* case 0107: MUUO /* GFDV (KL) */ | |
case 0110: RD2; dfad (ac, rs, 0); break; /* DFAD */ | |
case 0111: RD2; dfad (ac, rs, 1); break; /* DFSB */ | |
case 0112: RD2; dfmp (ac, rs); break; /* DFMP */ | |
case 0113: RD2; dfdv (ac, rs); break; /* DFDV */ | |
case 0114: RD2; dadd (ac, rs); break; /* DADD */ | |
case 0115: RD2; dsub (ac, rs); break; /* DSUB */ | |
case 0116: RD2; dmul (ac, rs); break; /* DMUL */ | |
case 0117: RD2; ddiv (ac, rs); break; /* DDIV */ | |
case 0120: RD2; S2AC; break; /* DMOVE */ | |
case 0121: RD2; DMOVN (rs); S2AC; DMOVNF; break; /* DMOVN */ | |
case 0122: RD; fix(ac, mb, 0); break; /* FIX */ | |
case 0123: st = xtend (ac, ea, pflgs); /* EXTEND */ | |
rlog = 0; /* clear log */ | |
switch (st) { | |
case XT_SKIP: | |
INCPC; | |
case XT_NOSK: | |
break; | |
default: | |
goto MUUO; | |
} | |
break; | |
case 0124: G2AC; WR2; break; /* DMOVEM */ | |
case 0125: G2AC; DMOVN (rs); WR2; DMOVNF; break; /* DMOVNM */ | |
case 0126: RD; fix (ac, mb, 1); break; /* FIXR */ | |
case 0127: RD; AC(ac) = fltr (mb); break; /* FLTR */ | |
/* case 0130: MUUO /* UFA */ | |
/* case 0131: MUUO /* DFN */ | |
case 0132: AC(ac) = fsc (AC(ac), ea); break; /* FSC */ | |
case 0133: if (!ac) /* IBP */ | |
ibp (ea, pflgs); | |
else adjbp (ac, ea, pflgs); break; | |
case 0134: CIBP; LDB; CLRF (F_FPD); break; /* ILBP */ | |
case 0135: LDB; break; /* LDB */ | |
case 0136: CIBP; DPB; CLRF (F_FPD); break; /* IDBP */ | |
case 0137: DPB; break; /* DPB */ | |
case 0140: RD; AC(ac) = FAD (mb); break; /* FAD */ | |
/* case 0141: MUUO /* FADL */ | |
case 0142: RM; mb = FAD (mb); WR; break; /* FADM */ | |
case 0143: RM; AC(ac) = FAD (mb); WRAC; break; /* FADB */ | |
case 0144: RD; AC(ac) = FADR (mb); break; /* FADR */ | |
case 0145: AC(ac) = FADR (IMS); break; /* FADRI */ | |
case 0146: RM; mb = FADR (mb); WR; break; /* FADRM */ | |
case 0147: RM; AC(ac) = FADR (mb); WRAC; break; /* FADRB */ | |
case 0150: RD; AC(ac) = FSB (mb); break; /* FSB */ | |
/* case 0151: MUUO /* FSBL */ | |
case 0152: RM; mb = FSB (mb); WR; break; /* FSBM */ | |
case 0153: RM; AC(ac) = FSB (mb); WRAC; break; /* FSBB */ | |
case 0154: RD; AC(ac) = FSBR (mb); break; /* FSBR */ | |
case 0155: AC(ac) = FSBR (IMS); break; /* FSBRI */ | |
case 0156: RM; mb = FSBR (mb); WR; break; /* FSBRM */ | |
case 0157: RM; AC(ac) = FSBR (mb); WRAC; break; /* FSBRB */ | |
case 0160: RD; AC(ac) = FMP (mb); break; /* FMP */ | |
/* case 0161: MUUO /* FMPL */ | |
case 0162: RM; mb = FMP (mb); WR; break; /* FMPM */ | |
case 0163: RM; AC(ac) = FMP (mb); WRAC; break; /* FMPB */ | |
case 0164: RD; AC(ac) = FMPR (mb); break; /* FMPR */ | |
case 0165: AC(ac) = FMPR (IMS); break; /* FMPRI */ | |
case 0166: RM; mb = FMPR (mb); WR; break; /* FMPRM */ | |
case 0167: RM; AC(ac) = FMPR (mb); WRAC; break; /* FMPRB */ | |
case 0170: RD; if (FDV (mb)) S1AC; break; /* FDV */ | |
/* case 0171: MUUO /* FDVL */ | |
case 0172: RM; if (FDV (mb)) WR1; break; /* FDVM */ | |
case 0173: RM; if (FDV (mb)) { S1AC; WRAC; } break; /* FDVB */ | |
case 0174: RD; if (FDVR (mb)) S1AC; break; /* FDVR */ | |
case 0175: if (FDVR (IMS)) S1AC; break; /* FDVRI */ | |
case 0176: RM; if (FDVR (mb)) WR1; break; /* FDVRM */ | |
case 0177: RM; if (FDVR (mb)) { S1AC; WRAC; } break; /* FDVRB */ | |
/* Move, arithmetic, shift, and jump (0200 - 0277) | |
Note that instructions which modify the flags and store a | |
result in memory must prove the writeability of the result | |
location before modifying the flags. Also, 0247 and 0257, | |
if not implemented, are nops, not MUUO's. | |
*/ | |
case 0200: RDAC; break; /* MOVE */ | |
case 0201: AC(ac) = ea; break; /* MOVEI */ | |
case 0202: WRAC; break; /* MOVEM */ | |
case 0203: RM; LAC; break; /* MOVES */ | |
case 0204: RD; AC(ac) = SWP (mb); break; /* MOVS */ | |
case 0205: AC(ac) = IMS; break; /* MOVSI */ | |
case 0206: mb = SWP (AC(ac)); WR; break; /* MOVSM */ | |
case 0207: RM; mb = SWP (mb); WR; LAC; break; /* MOVSS */ | |
case 0210: RD; AC(ac) = MOVN (mb); break; /* MOVN */ | |
case 0211: AC(ac) = NEG (IM); /* MOVNI */ | |
if (AC(ac) == 0) SETF (F_C0 | F_C1); | |
break; | |
case 0212: RM; mb = MOVN (AC(ac)); WR; break; /* MOVNM */ | |
case 0213: RM; mb = MOVN (mb); WR; LAC; break; /* MOVNS */ | |
case 0214: RD; AC(ac) = MOVM (mb); break; /* MOVM */ | |
case 0215: AC(ac) = ea; break; /* MOVMI */ | |
case 0216: RM; mb = MOVM (AC(ac)); WR; break; /* MOVMM */ | |
case 0217: RM; mb = MOVM (mb); WR; LAC; break; /* MOVMS */ | |
case 0220: RD; AC(ac) = IMUL (mb); break; /* IMUL */ | |
case 0221: AC(ac) = IMUL (IM); break; /* IMULI */ | |
case 0222: RM; mb = IMUL (mb); WR; break; /* IMULM */ | |
case 0223: RM; AC(ac) = IMUL (mb); WRAC; break; /* IMULB */ | |
case 0224: RD; MUL (mb); S2AC; break; /* MUL */ | |
case 0225: MUL (IM); S2AC; break; /* MULI */ | |
case 0226: RM; MUL (mb); WR1; break; /* MULM */ | |
case 0227: RM; MUL (mb); WR1; S2AC; break; /* MULB */ | |
case 0230: RD; if (IDIV (mb)) S2AC; break; /* IDIV */ | |
case 0231: if (IDIV (IM)) S2AC; break; /* IDIVI */ | |
case 0232: RM; if (IDIV (mb)) WR1; break; /* IDIVM */ | |
case 0233: RM; if (IDIV (mb)) { WR1; S2AC; } break; /* IDIVB */ | |
case 0234: RD; if (DIV (mb)) S2AC; break; /* DIV */ | |
case 0235: if (DIV (IM)) S2AC; break; /* DIVI */ | |
case 0236: RM; if (DIV (mb)) WR1; break; /* DIVM */ | |
case 0237: RM; if (DIV (mb)) { WR1; S2AC; } break; /* DIVB */ | |
case 0240: AC(ac) = ash (AC(ac), ea); break; /* ASH */ | |
case 0241: AC(ac) = rot (AC(ac), ea); break; /* ROT */ | |
case 0242: AC(ac) = lsh (AC(ac), ea); break; /* LSH */ | |
case 0243: AC(P1) = jffo (AC(ac)); /* JFFO */ | |
if (AC(ac)) JUMP (ea); | |
break; | |
case 0244: ashc (ac, ea); break; /* ASHC */ | |
case 0245: rotc (ac, ea); break; /* ROTC */ | |
case 0246: lshc (ac, ea); break; /* LSHC */ | |
case 0247: if (Q_ITS) circ (ac, ea); break; /* (ITS) CIRC */ | |
case 0250: RM; WRAC; AC(ac) = mb; break; /* EXCH */ | |
case 0251: blt (ac, ea, pflgs); break; /* BLT */ | |
case 0252: AOBAC; if (TGE (AC(ac))) JUMP (ea); break; /* AOBJP */ | |
case 0253: AOBAC; if (TL (AC(ac))) JUMP (ea); break; /* AOBJN */ | |
/* case 0254: /* shown later /* JRST */ | |
case 0255: if (flags & (ac << 14)) { /* JFCL */ | |
JUMP (ea); | |
CLRF (ac << 14); | |
} | |
break; | |
case 0256: if (xct_cnt++ >= xct_max) /* XCT */ | |
ABORT (STOP_XCT); | |
inst = Read (ea, MM_OPND); | |
if (ac && !TSTF (F_USR) && !Q_ITS) | |
pflgs = pflgs | ac; | |
goto XCT; | |
case 0257: if (Q_ITS) goto MUUO; /* MAP */ | |
AC(ac) = map (ea, MM_OPND); | |
break; | |
case 0260: WRP (FLPC); AOBAC; /* PUSHJ */ | |
SUBJ (ea); PUSHF; break; | |
case 0261: RD; WRP (mb); AOBAC; PUSHF; break; /* PUSH */ | |
case 0262: RDP; WR; SOBAC; POPF; break; /* POP */ | |
case 0263: RDP; JUMP (mb); SOBAC; POPF; break; /* POPJ */ | |
case 0264: Write (ea, FLPC, MM_OPND); /* JSR */ | |
SUBJ (INCR (ea)); break; | |
case 0265: AC(ac) = FLPC; SUBJ (ea); break; /* JSP */ | |
case 0266: WRAC; AC(ac) = XWD (ea, PC); /* JSA */ | |
JUMP (INCR (ea)); break; | |
case 0267: AC(ac) = Read ((a10) LRZ (AC(ac)), MM_OPND);/* JRA */ | |
JUMP (ea); break; | |
case 0270: RD; AC(ac) = ADD (mb); break; /* ADD */ | |
case 0271: AC(ac) = ADD (IM); break; /* ADDI */ | |
case 0272: RM; mb = ADD (mb); WR; break; /* ADDM */ | |
case 0273: RM; AC(ac) = ADD (mb); WRAC; break; /* ADDB */ | |
case 0274: RD; AC(ac) = SUB (mb); break; /* SUB */ | |
case 0275: AC(ac) = SUB (IM); break; /* SUBI */ | |
case 0276: RM; mb = SUB (mb); WR; break; /* SUBM */ | |
case 0277: RM; AC(ac) = SUB (mb); WRAC; break; /* SUBB */ | |
/* Compare, jump, skip instructions (0300 - 0377) - checked against KS10 ucode */ | |
case 0300: break; /* CAI */ | |
case 0301: if (CL (IM)) INCPC; break; /* CAIL */ | |
case 0302: if (CE (IM)) INCPC; break; /* CAIE */ | |
case 0303: if (CLE (IM)) INCPC; break; /* CAILE */ | |
case 0304: INCPC; break; /* CAIA */ | |
case 0305: if (CGE (IM)) INCPC; break; /* CAIGE */ | |
case 0306: if (CN (IM)) INCPC; break; /* CAIN */ | |
case 0307: if (CG (IM)) INCPC; break; /* CAIG */ | |
case 0310: RD; break; /* CAM */ | |
case 0311: RD; if (CL (mb)) INCPC; break; /* CAML */ | |
case 0312: RD; if (CE (mb)) INCPC; break; /* CAME */ | |
case 0313: RD; if (CLE (mb)) INCPC; break; /* CAMLE */ | |
case 0314: RD; INCPC; break; /* CAMA */ | |
case 0315: RD; if (CGE (mb)) INCPC; break; /* CAMGE */ | |
case 0316: RD; if (CN (mb)) INCPC; break; /* CAMN */ | |
case 0317: RD; if (CG (mb)) INCPC; break; /* CAMG */ | |
case 0320: break; /* JUMP */ | |
case 0321: if (TL (AC(ac))) JUMP (ea); break; /* JUMPL */ | |
case 0322: if (TE (AC(ac))) JUMP (ea); break; /* JUMPE */ | |
case 0323: if (TLE( AC(ac))) JUMP (ea); break; /* JUMPLE */ | |
case 0324: JUMP (ea); break; /* JUMPA */ | |
case 0325: if (TGE (AC(ac))) JUMP (ea); break; /* JUMPGE */ | |
case 0326: if (TN (AC(ac))) JUMP (ea); break; /* JUMPN */ | |
case 0327: if (TG (AC(ac))) JUMP (ea); break; /* JUMPG */ | |
case 0330: RD; LAC; break; /* SKIP */ | |
case 0331: RD; LAC; if (TL (mb)) INCPC; break; /* SKIPL */ | |
case 0332: RD; LAC; if (TE (mb)) INCPC; break; /* SKIPE */ | |
case 0333: RD; LAC; if (TLE (mb)) INCPC; break; /* SKIPLE */ | |
case 0334: RD; LAC; INCPC; break; /* SKIPA */ | |
case 0335: RD; LAC; if (TGE (mb)) INCPC; break; /* SKIPGE */ | |
case 0336: RD; LAC; if (TN (mb)) INCPC; break; /* SKIPN */ | |
case 0337: RD; LAC; if (TG (mb)) INCPC; break; /* SKIPG */ | |
case 0340: AOJ; break; /* AOJ */ | |
case 0341: AOJ; if (TL (AC(ac))) JUMP (ea); break; /* AOJL */ | |
case 0342: AOJ; if (TE (AC(ac))) JUMP (ea); break; /* AOJE */ | |
case 0343: AOJ; if (TLE (AC(ac))) JUMP (ea); break; /* AOJLE */ | |
case 0344: AOJ; JUMP(ea); /* AOJA */ | |
if (Q_ITS && Q_IDLE && /* ITS idle? */ | |
TSTF (F_USR) && (pager_PC == 017) && /* user mode, loc 17? */ | |
(ac == 0) && (ea == 017)) /* AOJA 0,17? */ | |
sim_idle (0, FALSE); | |
break; | |
case 0345: AOJ; if (TGE (AC(ac))) JUMP (ea); break; /* AOJGE */ | |
case 0346: AOJ; if (TN (AC(ac))) JUMP (ea); break; /* AOJN */ | |
case 0347: AOJ; if (TG (AC(ac))) JUMP (ea); break; /* AOJG */ | |
case 0350: AOS; break; /* AOS */ | |
case 0351: AOS; if (TL (mb)) INCPC; break; /* AOSL */ | |
case 0352: AOS; if (TE (mb)) INCPC; break; /* AOSE */ | |
case 0353: AOS; if (TLE (mb)) INCPC; break; /* AOSLE */ | |
case 0354: AOS; INCPC; break; /* AOSA */ | |
case 0355: AOS; if (TGE (mb)) INCPC; break; /* AOSGE */ | |
case 0356: AOS; if (TN (mb)) INCPC; break; /* AOSN */ | |
case 0357: AOS; if (TG (mb)) INCPC; break; /* AOSG */ | |
case 0360: SOJ; break; /* SOJ */ | |
case 0361: SOJ; if (TL (AC(ac))) JUMP (ea); break; /* SOJL */ | |
case 0362: SOJ; if (TE (AC(ac))) JUMP (ea); break; /* SOJE */ | |
case 0363: SOJ; if (TLE (AC(ac))) JUMP (ea); break; /* SOJLE */ | |
case 0364: SOJ; JUMP(ea); break; /* SOJA */ | |
case 0365: SOJ; if (TGE (AC(ac))) JUMP (ea); break; /* SOJGE */ | |
case 0366: SOJ; if (TN (AC(ac))) JUMP (ea); break; /* SOJN */ | |
case 0367: SOJ; if (TG (AC(ac))) JUMP (ea); /* SOJG */ | |
if ((ea == pager_PC) && Q_IDLE) { /* to self, idle enab? */ | |
extern int32 tmr_poll; | |
if ((ac == 6) && (ea == 1) && /* SOJG 6,1? */ | |
TSTF (F_USR) && Q_T10) /* T10, user mode? */ | |
sim_idle (0, FALSE); | |
else if (!t20_idlelock && /* interlock off? */ | |
(ac == 2) && (ea == 3) && /* SOJG 2,3? */ | |
!TSTF (F_USR) && Q_T20 && /* T20, mon mode? */ | |
(sim_interval > (tmr_poll >> 1))) { /* >= half clock? */ | |
t20_idlelock = 1; /* set interlock */ | |
if (sim_os_ms_sleep (1)) /* sleep 1ms */ | |
sim_interval = 0; /* if ok, sched event */ | |
} | |
} | |
break; | |
case 0370: SOS; break; /* SOS */ | |
case 0371: SOS; if (TL (mb)) INCPC; break; /* SOSL */ | |
case 0372: SOS; if (TE (mb)) INCPC; break; /* SOSE */ | |
case 0373: SOS; if (TLE (mb)) INCPC; break; /* SOSLE */ | |
case 0374: SOS; INCPC; break; /* SOSA */ | |
case 0375: SOS; if (TGE (mb)) INCPC; break; /* SOSGE */ | |
case 0376: SOS; if (TN (mb)) INCPC; break; /* SOSN */ | |
case 0377: SOS; if (TG (mb)) INCPC; break; /* SOSG */ | |
/* Boolean instructions (0400 - 0477) - checked against KS10 ucode | |
Note that for boolean B, the initial read checks writeability of | |
the memory operand; hence, it is safe to modify the AC. | |
*/ | |
case 0400: AC(ac) = 0; break; /* SETZ */ | |
case 0401: AC(ac) = 0; break; /* SETZI */ | |
case 0402: mb = 0; WR; break; /* SETZM */ | |
case 0403: mb = 0; WR; AC(ac) = 0; break; /* SETZB */ | |
case 0404: RD; AC(ac) = AND (mb); break; /* AND */ | |
case 0405: AC(ac) = AND (IM); break; /* ANDI */ | |
case 0406: RM; mb = AND (mb); WR; break; /* ANDM */ | |
case 0407: RM; AC(ac) = AND (mb); WRAC; break; /* ANDB */ | |
case 0410: RD; AC(ac) = ANDCA (mb); break; /* ANDCA */ | |
case 0411: AC(ac) = ANDCA (IM); break; /* ANDCAI */ | |
case 0412: RM; mb = ANDCA (mb); WR; break; /* ANDCAM */ | |
case 0413: RM; AC(ac) = ANDCA (mb); WRAC; break; /* ANDCAB */ | |
case 0414: RDAC; break; /* SETM */ | |
case 0415: AC(ac) = ea; break; /* SETMI */ | |
case 0416: RM; WR; break; /* SETMM */ | |
case 0417: RMAC; WRAC; break; /* SETMB */ | |
case 0420: RD; AC(ac) = ANDCM (mb); break; /* ANDCM */ | |
case 0421: AC(ac) = ANDCM (IM); break; /* ANDCMI */ | |
case 0422: RM; mb = ANDCM (mb); WR; break; /* ANDCMM */ | |
case 0423: RM; AC(ac) = ANDCM (mb); WRAC; break; /* ANDCMB */ | |
case 0424: break; /* SETA */ | |
case 0425: break; /* SETAI */ | |
case 0426: WRAC; break; /* SETAM */ | |
case 0427: WRAC; break; /* SETAB */ | |
case 0430: RD; AC(ac) = XOR (mb); break; /* XOR */ | |
case 0431: AC(ac) = XOR (IM); break; /* XORI */ | |
case 0432: RM; mb = XOR (mb); WR; break; /* XORM */ | |
case 0433: RM; AC(ac) = XOR (mb); WRAC; break; /* XORB */ | |
case 0434: RD; AC(ac) = IOR (mb); break; /* IOR */ | |
case 0435: AC(ac) = IOR (IM); break; /* IORI */ | |
case 0436: RM; mb = IOR (mb); WR; break; /* IORM */ | |
case 0437: RM; AC(ac) = IOR (mb); WRAC; break; /* IORB */ | |
case 0440: RD; AC(ac) = ANDCB (mb); break; /* ANDCB */ | |
case 0441: AC(ac) = ANDCB (IM); break; /* ANDCBI */ | |
case 0442: RM; mb = ANDCB (mb); WR; break; /* ANDCBM */ | |
case 0443: RM; AC(ac) = ANDCB (mb); WRAC; break; /* ANDCBB */ | |
case 0444: RD; AC(ac) = EQV (mb); break; /* EQV */ | |
case 0445: AC(ac) = EQV (IM); break; /* EQVI */ | |
case 0446: RM; mb = EQV (mb); WR; break; /* EQVM */ | |
case 0447: RM; AC(ac) = EQV (mb); WRAC; break; /* EQVB */ | |
case 0450: RD; AC(ac) = SETCA (mb); break; /* SETCA */ | |
case 0451: AC(ac) = SETCA (IM); break; /* SETCAI */ | |
case 0452: RM; mb = SETCA (mb); WR; break; /* SETCAM */ | |
case 0453: RM; AC(ac) = SETCA (mb); WRAC; break; /* SETCAB */ | |
case 0454: RD; AC(ac) = ORCA (mb); break; /* ORCA */ | |
case 0455: AC(ac) = ORCA (IM); break; /* ORCAI */ | |
case 0456: RM; mb = ORCA (mb); WR; break; /* ORCAM */ | |
case 0457: RM; AC(ac) = ORCA (mb); WRAC; break; /* ORCAB */ | |
case 0460: RD; AC(ac) = SETCM (mb); break; /* SETCM */ | |
case 0461: AC(ac) = SETCM (IM); break; /* SETCMI */ | |
case 0462: RM; mb = SETCM (mb); WR; break; /* SETCMM */ | |
case 0463: RM; AC(ac) = SETCM (mb); WRAC; break; /* SETCMB */ | |
case 0464: RD; AC(ac) = ORCM (mb); break; /* ORCM */ | |
case 0465: AC(ac) = ORCM (IM); break; /* ORCMI */ | |
case 0466: RM; mb = ORCM (mb); WR; break; /* ORCMM */ | |
case 0467: RM; AC(ac) = ORCM (mb); WRAC; break; /* ORCMB */ | |
case 0470: RD; AC(ac) = ORCB (mb); break; /* ORCB */ | |
case 0471: AC(ac) = ORCB (IM); break; /* ORCBI */ | |
case 0472: RM; mb = ORCB (mb); WR; break; /* ORCBM */ | |
case 0473: RM; AC(ac) = ORCB (mb); WRAC; break; /* ORCBB */ | |
case 0474: AC(ac) = ONES; break; /* SETO */ | |
case 0475: AC(ac) = ONES; break; /* SETOI */ | |
case 0476: mb = ONES; WR; break; /* SETOM */ | |
case 0477: mb = ONES; WR; AC(ac) = ONES; break; /* SETOB */ | |
/* Halfword instructions (0500 - 0577) - checked against KS10 ucode */ | |
case 0500: RD; AC(ac) = LL (mb, AC(ac)); break; /* HLL */ | |
case 0501: AC(ac) = LL (IM, AC(ac)); break; /* HLLI */ | |
case 0502: RM; mb = LL (AC(ac), mb); WR; break; /* HLLM */ | |
case 0503: RM; mb = LL (mb, mb); WR; LAC; break; /* HLLS */ | |
case 0504: RD; AC(ac) = RL (mb, AC(ac)); break; /* HRL */ | |
case 0505: AC(ac) = RL (IM, AC(ac)); break; /* HRLI */ | |
case 0506: RM; mb = RL (AC(ac), mb); WR; break; /* HRLM */ | |
case 0507: RM; mb = RL (mb, mb); WR; LAC; break; /* HRLS */ | |
case 0510: RD; AC(ac) = LLZ (mb); break; /* HLLZ */ | |
case 0511: AC(ac) = LLZ (IM); break; /* HLLZI */ | |
case 0512: mb = LLZ (AC(ac)); WR; break; /* HLLZM */ | |
case 0513: RM; mb = LLZ (mb); WR; LAC; break; /* HLLZS */ | |
case 0514: RD; AC(ac) = RLZ (mb); break; /* HRLZ */ | |
case 0515: AC(ac) = RLZ (IM); break; /* HRLZI */ | |
case 0516: mb = RLZ (AC(ac)); WR; break; /* HRLZM */ | |
case 0517: RM; mb = RLZ (mb); WR; LAC; break; /* HRLZS */ | |
case 0520: RD; AC(ac) = LLO (mb); break; /* HLLO */ | |
case 0521: AC(ac) = LLO (IM); break; /* HLLOI */ | |
case 0522: mb = LLO (AC(ac)); WR; break; /* HLLOM */ | |
case 0523: RM; mb = LLO (mb); WR; LAC; break; /* HLLOS */ | |
case 0524: RD; AC(ac) = RLO (mb); break; /* HRLO */ | |
case 0525: AC(ac) = RLO (IM); break; /* HRLOI */ | |
case 0526: mb = RLO (AC(ac)); WR; break; /* HRLOM */ | |
case 0527: RM; mb = RLO (mb); WR; LAC; break; /* HRLOS */ | |
case 0530: RD; AC(ac) = LLE (mb); break; /* HLLE */ | |
case 0531: AC(ac) = LLE (IM); break; /* HLLEI */ | |
case 0532: mb = LLE (AC(ac)); WR; break; /* HLLEM */ | |
case 0533: RM; mb = LLE (mb); WR; LAC; break; /* HLLES */ | |
case 0534: RD; AC(ac) = RLE (mb); break; /* HRLE */ | |
case 0535: AC(ac) = RLE (IM); break; /* HRLEI */ | |
case 0536: mb = RLE (AC(ac)); WR; break; /* HRLEM */ | |
case 0537: RM; mb = RLE (mb); WR; LAC; break; /* HRLES */ | |
case 0540: RD; AC(ac) = RR (mb, AC(ac)); break; /* HRR */ | |
case 0541: AC(ac) = RR (IM, AC(ac)); break; /* HRRI */ | |
case 0542: RM; mb = RR (AC(ac), mb); WR; break; /* HRRM */ | |
case 0543: RM; mb = RR (mb, mb); WR; LAC; break; /* HRRS */ | |
case 0544: RD; AC(ac) = LR (mb, AC(ac)); break; /* HLR */ | |
case 0545: AC(ac) = LR (IM, AC(ac)); break; /* HLRI */ | |
case 0546: RM; mb = LR (AC(ac), mb); WR; break; /* HLRM */ | |
case 0547: RM; mb = LR (mb, mb); WR; LAC; break; /* HLRS */ | |
case 0550: RD; AC(ac) = RRZ (mb); break; /* HRRZ */ | |
case 0551: AC(ac) = RRZ (IM); break; /* HRRZI */ | |
case 0552: mb = RRZ (AC(ac)); WR; break; /* HRRZM */ | |
case 0553: RM; mb = RRZ(mb); WR; LAC; break; /* HRRZS */ | |
case 0554: RD; AC(ac) = LRZ (mb); break; /* HLRZ */ | |
case 0555: AC(ac) = LRZ (IM); break; /* HLRZI */ | |
case 0556: mb = LRZ (AC(ac)); WR; break; /* HLRZM */ | |
case 0557: RM; mb = LRZ (mb); WR; LAC; break; /* HLRZS */ | |
case 0560: RD; AC(ac) = RRO (mb); break; /* HRRO */ | |
case 0561: AC(ac) = RRO (IM); break; /* HRROI */ | |
case 0562: mb = RRO (AC(ac)); WR; break; /* HRROM */ | |
case 0563: RM; mb = RRO (mb); WR; LAC; break; /* HRROS */ | |
case 0564: RD; AC(ac) = LRO (mb); break; /* HLRO */ | |
case 0565: AC(ac) = LRO (IM); break; /* HLROI */ | |
case 0566: mb = LRO (AC(ac)); WR; break; /* HLROM */ | |
case 0567: RM; mb = LRO (mb); WR; LAC; break; /* HLROS */ | |
case 0570: RD; AC(ac) = RRE (mb); break; /* HRRE */ | |
case 0571: AC(ac) = RRE (IM); break; /* HRREI */ | |
case 0572: mb = RRE (AC(ac)); WR; break; /* HRREM */ | |
case 0573: RM; mb = RRE (mb); WR; LAC; break; /* HRRES */ | |
case 0574: RD; AC(ac) = LRE (mb); break; /* HLRE */ | |
case 0575: AC(ac) = LRE (IM); break; /* HLREI */ | |
case 0576: mb = LRE (AC(ac)); WR; break; /* HLREM */ | |
case 0577: RM; mb = LRE (mb); WR; LAC; break; /* HLRES */ | |
/* Test instructions (0600 - 0677) - checked against KS10 ucode | |
In the KS10 ucode, TDN and TSN do not fetch an operand; the Processor | |
Reference Manual describes them as NOPs that reference memory. | |
*/ | |
case 0600: break; /* TRN */ | |
case 0601: break; /* TLN */ | |
case 0602: TR_; T__E; break; /* TRNE */ | |
case 0603: TL_; T__E; break; /* TLNE */ | |
case 0604: T__A; break; /* TRNA */ | |
case 0605: T__A; break; /* TLNA */ | |
case 0606: TR_; T__N; break; /* TRNN */ | |
case 0607: TL_; T__N; break; /* TLNN */ | |
case 0610: TD_; break; /* TDN */ | |
case 0611: TS_; break; /* TSN */ | |
case 0612: TD_; T__E; break; /* TDNE */ | |
case 0613: TS_; T__E; break; /* TSNE */ | |
case 0614: TD_; T__A; break; /* TDNA */ | |
case 0615: TS_; T__A; break; /* TSNA */ | |
case 0616: TD_; T__N; break; /* TDNN */ | |
case 0617: TS_; T__N; break; /* TSNN */ | |
case 0620: TR_; T_Z; break; /* TRZ */ | |
case 0621: TL_; T_Z; break; /* TLZ */ | |
case 0622: TR_; T__E; T_Z; break; /* TRZE */ | |
case 0623: TL_; T__E; T_Z; break; /* TLZE */ | |
case 0624: TR_; T__A; T_Z; break; /* TRZA */ | |
case 0625: TL_; T__A; T_Z; break; /* TLZA */ | |
case 0626: TR_; T__N; T_Z; break; /* TRZN */ | |
case 0627: TL_; T__N; T_Z; break; /* TLZN */ | |
case 0630: TD_; T_Z; break; /* TDZ */ | |
case 0631: TS_; T_Z; break; /* TSZ */ | |
case 0632: TD_; T__E; T_Z; break; /* TDZE */ | |
case 0633: TS_; T__E; T_Z; break; /* TSZE */ | |
case 0634: TD_; T__A; T_Z; break; /* TDZA */ | |
case 0635: TS_; T__A; T_Z; break; /* TSZA */ | |
case 0636: TD_; T__N; T_Z; break; /* TDZN */ | |
case 0637: TS_; T__N; T_Z; break; /* TSZN */ | |
case 0640: TR_; T_C; break; /* TRC */ | |
case 0641: TL_; T_C; break; /* TLC */ | |
case 0642: TR_; T__E; T_C; break; /* TRCE */ | |
case 0643: TL_; T__E; T_C; break; /* TLCE */ | |
case 0644: TR_; T__A; T_C; break; /* TRCA */ | |
case 0645: TL_; T__A; T_C; break; /* TLCA */ | |
case 0646: TR_; T__N; T_C; break; /* TRCN */ | |
case 0647: TL_; T__N; T_C; break; /* TLCN */ | |
case 0650: TD_; T_C; break; /* TDC */ | |
case 0651: TS_; T_C; break; /* TSC */ | |
case 0652: TD_; T__E; T_C; break; /* TDCE */ | |
case 0653: TS_; T__E; T_C; break; /* TSCE */ | |
case 0654: TD_; T__A; T_C; break; /* TDCA */ | |
case 0655: TS_; T__A; T_C; break; /* TSCA */ | |
case 0656: TD_; T__N; T_C; break; /* TDCN */ | |
case 0657: TS_; T__N; T_C; break; /* TSCN */ | |
case 0660: TR_; T_O; break; /* TRO */ | |
case 0661: TL_; T_O; break; /* TLO */ | |
case 0662: TR_; T__E; T_O; break; /* TROE */ | |
case 0663: TL_; T__E; T_O; break; /* TLOE */ | |
case 0664: TR_; T__A; T_O; break; /* TROA */ | |
case 0665: TL_; T__A; T_O; break; /* TLOA */ | |
case 0666: TR_; T__N; T_O; break; /* TRON */ | |
case 0667: TL_; T__N; T_O; break; /* TLON */ | |
case 0670: TD_; T_O; break; /* TDO */ | |
case 0671: TS_; T_O; break; /* TSO */ | |
case 0672: TD_; T__E; T_O; break; /* TDOE */ | |
case 0673: TS_; T__E; T_O; break; /* TSOE */ | |
case 0674: TD_; T__A; T_O; break; /* TDOA */ | |
case 0675: TS_; T__A; T_O; break; /* TSOA */ | |
case 0676: TD_; T__N; T_O; break; /* TDON */ | |
case 0677: TS_; T__N; T_O; break; /* TSON */ | |
/* I/O instructions (0700 - 0777) | |
Only the defined I/O instructions have explicit case labels; | |
the rest default to unimplemented (monitor UUO). Note that | |
710-715 and 720-725 have different definitions under ITS and | |
use normal effective addresses instead of the special address | |
calculation required by TOPS-10 and TOPS-20. | |
*/ | |
case 0700: IO7 (io700i, io700d); break; /* I/O 0 */ | |
case 0701: IO7 (io701i, io701d); break; /* I/O 1 */ | |
case 0702: IO7 (io702i, io702d); break; /* I/O 2 */ | |
case 0704: IOC; AC(ac) = Read (ea, OPND_PXCT); break; /* UMOVE */ | |
case 0705: IOC; Write (ea, AC(ac), OPND_PXCT); break; /* UMOVEM */ | |
case 0710: IOA; if (io710 (ac, ea)) INCPC; break; /* TIOE, IORDI */ | |
case 0711: IOA; if (io711 (ac, ea)) INCPC; break; /* TION, IORDQ */ | |
case 0712: IOAM; AC(ac) = io712 (ea); break; /* RDIO, IORD */ | |
case 0713: IOAM; io713 (AC(ac), ea); break; /* WRIO, IOWR */ | |
case 0714: IOA; io714 (AC(ac), ea); break; /* BSIO, IOWRI */ | |
case 0715: IOA; io715 (AC(ac), ea); break; /* BCIO, IOWRQ */ | |
case 0716: IOC; bltu (ac, ea, pflgs, 0); break; /* BLTBU */ | |
case 0717: IOC; bltu (ac, ea, pflgs, 1); break; /* BLTUB */ | |
case 0720: IOA; if (io720 (ac, ea)) INCPC; break; /* TIOEB, IORDBI */ | |
case 0721: IOA; if (io721 (ac, ea)) INCPC; break; /* TIONB, IORDBQ */ | |
case 0722: IOAM; AC(ac) = io722 (ea); break; /* RDIOB, IORDB */ | |
case 0723: IOAM; io723 (AC(ac), ea); break; /* WRIOB, IOWRB */ | |
case 0724: IOA; io724 (AC(ac), ea); break; /* BSIOB, IOWRBI */ | |
case 0725: IOA; io725 (AC(ac), ea); break; /* BCIOB, IOWRBQ */ | |
/* If undefined, monitor UUO - checked against KS10 ucode | |
The KS10 implements a much more limited version of MUUO flag handling. | |
In the KS10, the trap ucode checks for opcodes 000-077. If the opcode | |
is in that range, the trap flags are not cleared. Instead, the MUUO | |
microcode stores the flags with traps cleared, and uses the trap flags | |
to determine how to vector. Thus, MUUO's >= 100 will vector incorrectly. | |
*/ | |
default: | |
MUUO: | |
its_2pr = 0; /* clear trap */ | |
if (T20PAG) { /* TOPS20 paging? */ | |
int32 tf = (op << (INST_V_OP - 18)) | (ac << (INST_V_AC - 18)); | |
WriteP (upta + UPT_MUUO, XWD ( /* store flags,,op+ac */ | |
flags & ~(F_T2 | F_T1), tf)); /* traps clear */ | |
WriteP (upta + UPT_MUPC, PC); /* store PC */ | |
WriteP (upta + UPT_T20_UEA, ea); /* store eff addr */ | |
WriteP (upta + UPT_T20_CTX, UBRWORD); /* store context */ | |
} | |
else { /* TOPS10/ITS */ | |
WriteP (upta + UPT_MUUO, UUOWORD); /* store instr word */ | |
WriteP (upta + UPT_MUPC, XWD ( /* store flags,,PC */ | |
flags & ~(F_T2 | F_T1), PC)); /* traps clear */ | |
WriteP (upta + UPT_T10_CTX, UBRWORD); /* store context */ | |
} | |
ea = upta + (TSTF (F_USR)? UPT_UNPC: UPT_ENPC) + | |
(pager_tc? UPT_NPCT: 0); /* calculate vector */ | |
mb = ReadP (ea); /* new flags, PC */ | |
JUMP (mb); /* set new PC */ | |
if (TSTF (F_USR)) /* set PCU */ | |
mb = mb | XWD (F_UIO, 0); | |
set_newflags (mb, FALSE); /* set new flags */ | |
break; | |
/* JRST - checked against KS10 ucode | |
Differences from the KS10: the KS10 | |
- (JRSTF, JEN) refetches the base instruction from PC - 1 | |
- (XJEN) dismisses interrupt before reading the new flags and PC | |
- (XPCW) writes the old flags and PC before reading the new | |
ITS microcode includes extended JRST's, although they are not used | |
*/ | |
case 0254: /* JRST */ | |
i = jrst_tab[ac]; /* get subop flags */ | |
if ((i == 0) || ((i == JRST_E) && TSTF (F_USR)) || | |
((i == JRST_UIO) && TSTF (F_USR) && !TSTF (F_UIO))) | |
goto MUUO; /* not legal */ | |
switch (ac) { /* case on subopcode */ | |
case 000: /* JRST 0 = jump */ | |
case 001: /* JRST 1 = portal */ | |
JUMP (ea); | |
break; | |
case 002: /* JRST 2 = JRSTF */ | |
mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */ | |
JUMP (ea); /* set new PC */ | |
set_newflags (mb, TRUE); /* set new flags */ | |
break; | |
case 004: /* JRST 4 = halt */ | |
JUMP (ea); /* old_PC = halt + 1 */ | |
pager_PC = PC; /* force right PC */ | |
ABORT (STOP_HALT); /* known to be exec */ | |
break; | |
case 005: /* JRST 5 = XJRSTF */ | |
RD2; /* read doubleword */ | |
JUMP (rs[1]); /* set new PC */ | |
set_newflags (rs[0], TRUE); /* set new flags */ | |
break; | |
case 006: /* JRST 6 = XJEN */ | |
RD2; /* read doubleword */ | |
pi_dismiss (); /* page ok, dismiss */ | |
JUMP (rs[1]); /* set new PC */ | |
set_newflags (rs[0], FALSE); /* known to be exec */ | |
break; | |
case 007: /* JRST 7 = XPCW */ | |
ea = ADDA (i = ea, 2); /* new flags, PC */ | |
RD2; /* read, test page fail */ | |
ReadM (INCA (i), MM_OPND); /* test PC write */ | |
Write (i, XWD (flags, 0), MM_OPND); /* write flags */ | |
Write (INCA (i), PC, MM_OPND); /* write PC */ | |
JUMP (rs[1]); /* set new PC */ | |
set_newflags (rs[0], FALSE); /* known to be exec */ | |
break; | |
case 010: /* JRST 10 = dismiss */ | |
pi_dismiss (); /* dismiss int */ | |
JUMP (ea); /* set new PC */ | |
break; | |
case 012: /* JRST 12 = JEN */ | |
mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */ | |
JUMP (ea); /* set new PC */ | |
set_newflags (mb, TRUE); /* set new flags */ | |
pi_dismiss (); /* dismiss int */ | |
break; | |
case 014: /* JRST 14 = SFM */ | |
Write (ea, XWD (flags, 0), MM_OPND); | |
break; | |
case 015: /* JRST 15 = XJRST */ | |
if (!T20PAG) /* only in TOPS20 paging */ | |
goto MUUO; | |
JUMP (Read (ea, MM_OPND)); /* jump to M[ea] */ | |
break; | |
} /* end case subop */ | |
break; | |
} /* end case op */ | |
if (its_2pr) { /* 1-proc trap? */ | |
its_1pr = its_2pr = 0; /* clear trap */ | |
if (Q_ITS) { /* better be ITS */ | |
WriteP (upta + UPT_1PO, FLPC); /* wr old flgs, PC */ | |
mb = ReadP (upta + UPT_1PN); /* rd new flgs, PC */ | |
JUMP (mb); /* set PC */ | |
set_newflags (mb, TRUE); /* set new flags */ | |
} | |
} /* end if 2-proc */ | |
} /* end for */ | |
/* Should never get here */ | |
ABORT (STOP_UNKNOWN); | |
} | |
/* Single word integer routines */ | |
/* Integer add | |
Truth table for integer add | |
case a b r flags | |
1 + + + none | |
2 + + - AOV + C1 | |
3 + - + C0 + C1 | |
4 + - - - | |
5 - + + C0 + C1 | |
6 - + - - | |
7 - - + AOV + C0 | |
8 - - - C0 + C1 | |
*/ | |
d10 add (d10 a, d10 b) | |
{ | |
d10 r; | |
r = (a + b) & DMASK; | |
if (TSTS (a & b)) { /* cases 7,8 */ | |
if (TSTS (r)) /* case 8 */ | |
SETF (F_C0 | F_C1); | |
else SETF (F_C0 | F_AOV | F_T1); /* case 7 */ | |
return r; | |
} | |
if (!TSTS (a | b)) { /* cases 1,2 */ | |
if (TSTS (r)) /* case 2 */ | |
SETF (F_C1 | F_AOV | F_T1); | |
return r; /* case 1 */ | |
} | |
if (!TSTS (r)) /* cases 3,5 */ | |
SETF (F_C0 | F_C1); | |
return r; | |
} | |
/* Integer subtract - actually ac + ~op + 1 */ | |
d10 sub (d10 a, d10 b) | |
{ | |
d10 r; | |
r = (a - b) & DMASK; | |
if (TSTS (a & ~b)) { /* cases 7,8 */ | |
if (TSTS (r)) /* case 8 */ | |
SETF (F_C0 | F_C1); | |
else SETF (F_C0 | F_AOV | F_T1); /* case 7 */ | |
return r; | |
} | |
if (!TSTS (a | ~b)) { /* cases 1,2 */ | |
if (TSTS (r)) /* case 2 */ | |
SETF (F_C1 | F_AOV | F_T1); | |
return r; /* case 1 */ | |
} | |
if (!TSTS (r)) /* cases 3,5 */ | |
SETF (F_C0 | F_C1); | |
return r; | |
} | |
/* Logical shift */ | |
d10 lsh (d10 val, a10 ea) | |
{ | |
int32 sc = LIT8 (ea); | |
if (sc > 35) | |
return 0; | |
if (ea & RSIGN) | |
return (val >> sc); | |
return ((val << sc) & DMASK); | |
} | |
/* Rotate */ | |
d10 rot (d10 val, a10 ea) | |
{ | |
int32 sc = LIT8 (ea) % 36; | |
if (sc == 0) | |
return val; | |
if (ea & RSIGN) | |
sc = 36 - sc; | |
return (((val << sc) | (val >> (36 - sc))) & DMASK); | |
} | |
/* Double word integer instructions */ | |
/* Double add - see case table for single add */ | |
void dadd (int32 ac, d10 *rs) | |
{ | |
d10 r; | |
int32 p1 = ADDAC (ac, 1); | |
AC(p1) = CLRS (AC(p1)) + CLRS (rs[1]); /* add lo */ | |
r = (AC(ac) + rs[0] + (TSTS (AC(p1))? 1: 0)) & DMASK; /* add hi+cry */ | |
if (TSTS (AC(ac) & rs[0])) { /* cases 7,8 */ | |
if (TSTS (r)) /* case 8 */ | |
SETF (F_C0 | F_C1); | |
else SETF (F_C0 | F_AOV | F_T1); /* case 7 */ | |
} | |
else if (!TSTS (AC(ac) | rs[0])) { /* cases 1,2 */ | |
if (TSTS (r)) /* case 2 */ | |
SETF (F_C1 | F_AOV | F_T1); | |
} | |
else if (!TSTS (r)) /* cases 3,5 */ | |
SETF (F_C0 | F_C1); | |
AC(ac) = r; | |
AC(p1) = TSTS (r)? SETS (AC(p1)): CLRS (AC(p1)); | |
return; | |
} | |
/* Double subtract - see comments for single subtract */ | |
void dsub (int32 ac, d10 *rs) | |
{ | |
d10 r; | |
int32 p1 = ADDAC (ac, 1); | |
AC(p1) = CLRS (AC(p1)) - CLRS (rs[1]); /* sub lo */ | |
r = (AC(ac) - rs[0] - (TSTS (AC(p1))? 1: 0)) & DMASK; /* sub hi,borrow */ | |
if (TSTS (AC(ac) & ~rs[0])) { /* cases 7,8 */ | |
if (TSTS (r)) /* case 8 */ | |
SETF (F_C0 | F_C1); | |
else SETF (F_C0 | F_AOV | F_T1); /* case 7 */ | |
} | |
else if (!TSTS (AC(ac) | ~rs[0])) { /* cases 1,2 */ | |
if (TSTS (r)) /* case 2 */ | |
SETF (F_C1 | F_AOV | F_T1); | |
} | |
else if (!TSTS (r)) /* cases 3,5 */ | |
SETF (F_C0 | F_C1); | |
AC(ac) = r; | |
AC(p1) = (TSTS (r)? SETS (AC(p1)): CLRS (AC(p1))) & DMASK; | |
return; | |
} | |
/* Logical shift combined */ | |
void lshc (int32 ac, a10 ea) | |
{ | |
int32 p1 = ADDAC (ac, 1); | |
int32 sc = LIT8 (ea); | |
if (sc > 71) | |
AC(ac) = AC(p1) = 0; | |
else if (ea & RSIGN) { | |
if (sc >= 36) { | |
AC(p1) = AC(ac) >> (sc - 36); | |
AC(ac) = 0; | |
} | |
else { | |
AC(p1) = ((AC(p1) >> sc) | (AC(ac) << (36 - sc))) & DMASK; | |
AC(ac) = AC(ac) >> sc; | |
} | |
} | |
else { | |
if (sc >= 36) { | |
AC(ac) = (AC(p1) << (sc - 36)) & DMASK; | |
AC(p1) = 0; | |
} | |
else { | |
AC(ac) = ((AC(ac) << sc) | (AC(p1) >> (36 - sc))) & DMASK; | |
AC(p1) = (AC(p1) << sc) & DMASK; | |
} | |
} | |
return; | |
} | |
/* Rotate combined */ | |
void rotc (int32 ac, a10 ea) | |
{ | |
int32 p1 = ADDAC (ac, 1); | |
int32 sc = LIT8 (ea) % 72; | |
d10 t = AC(ac); | |
if (sc == 0) | |
return; | |
if (ea & RSIGN) | |
sc = 72 - sc; | |
if (sc >= 36) { | |
AC(ac) = ((AC(p1) << (sc - 36)) | (t >> (72 - sc))) & DMASK; | |
AC(p1) = ((t << (sc - 36)) | (AC(p1) >> (72 - sc))) & DMASK; | |
} | |
else { | |
AC(ac) = ((t << sc) | (AC(p1) >> (36 - sc))) & DMASK; | |
AC(p1) = ((AC(p1) << sc) | (t >> (36 - sc))) & DMASK; | |
} | |
return; | |
} | |
/* Arithmetic shifts */ | |
d10 ash (d10 val, a10 ea) | |
{ | |
int32 sc = LIT8 (ea); | |
d10 sign = TSTS (val); | |
d10 fill = sign? ONES: 0; | |
d10 so; | |
if (sc == 0) | |
return val; | |
if (sc > 35) /* cap sc at 35 */ | |
sc = 35; | |
if (ea & RSIGN) | |
return (((val >> sc) | (fill << (36 - sc))) & DMASK); | |
so = val >> (35 - sc); /* bits lost left + sign */ | |
if (so != (sign? bytemask[sc + 1]: 0)) | |
SETF (F_AOV | F_T1); | |
return (sign | ((val << sc) & MMASK)); | |
} | |
void ashc (int32 ac, a10 ea) | |
{ | |
int32 sc = LIT8 (ea); | |
int32 p1 = ADDAC (ac, 1); | |
d10 sign = TSTS (AC(ac)); | |
d10 fill = sign? ONES: 0; | |
d10 so; | |
if (sc == 0) | |
return; | |
if (sc > 70) /* cap sc at 70 */ | |
sc = 70; | |
AC(ac) = CLRS (AC(ac)); /* clear signs */ | |
AC(p1) = CLRS (AC(p1)); | |
if (ea & RSIGN) { | |
if (sc >= 35) { /* right 36..70 */ | |
AC(p1) = ((AC(ac) >> (sc - 35)) | (fill << (70 - sc))) & DMASK; | |
AC(ac) = fill; | |
} | |
else { | |
AC(p1) = sign | /* right 1..35 */ | |
(((AC(p1) >> sc) | (AC(ac) << (35 - sc))) & MMASK); | |
AC(ac) = ((AC(ac) >> sc) | (fill << (35 - sc))) & DMASK; | |
} | |
} | |
else { | |
if (sc >= 35) { /* left 36..70 */ | |
so = AC(p1) >> (70 - sc); /* bits lost left */ | |
if ((AC(ac) != (sign? MMASK: 0)) || | |
(so != (sign? bytemask[sc - 35]: 0))) | |
SETF (F_AOV | F_T1); | |
AC(ac) = sign | ((AC(p1) << (sc - 35)) & MMASK); | |
AC(p1) = sign; | |
} | |
else { | |
so = AC(ac) >> (35 - sc); /* bits lost left */ | |
if (so != (sign? bytemask[sc]: 0)) | |
SETF (F_AOV | F_T1); | |
AC(ac) = sign | | |
(((AC(ac) << sc) | (AC(p1) >> (35 - sc))) & MMASK); | |
AC(p1) = sign | ((AC(p1) << sc) & MMASK); | |
} | |
} | |
return; | |
} | |
/* Effective address routines */ | |
/* Calculate effective address - used by byte instructions, extended | |
instructions, and interrupts to get a different mapping context from | |
the main loop. prv is either EABP_PXCT or MM_CUR. | |
*/ | |
a10 calc_ea (d10 inst, int32 prv) | |
{ | |
int32 i, ea, xr; | |
d10 indrct; | |
for (indrct = inst, i = 0; i < ind_max; i++) { | |
ea = GET_ADDR (indrct); | |
xr = GET_XR (indrct); | |
if (xr) | |
ea = (ea + ((a10) XR (xr, prv))) & AMASK; | |
if (TST_IND (indrct)) | |
indrct = Read (ea, prv); | |
else break; | |
} | |
if (i >= ind_max) | |
ABORT (STOP_IND); | |
return ea; | |
} | |
/* Calculate I/O effective address. Cases: | |
- No index or indirect, return addr from instruction | |
- Index only, index >= 0, return 36b sum of addr + index | |
- Index only, index <= 0, return 18b sum of addr + index | |
- Indirect, calculate 18b sum of addr + index, return | |
entire word fetch (single level) | |
*/ | |
a10 calc_ioea (d10 inst, int32 pflgs) | |
{ | |
int32 xr; | |
a10 ea; | |
xr = GET_XR (inst); | |
ea = GET_ADDR (inst); | |
if (TST_IND (inst)) { /* indirect? */ | |
if (xr) | |
ea = (ea + ((a10) XR (xr, MM_EA))) & AMASK; | |
ea = (a10) Read (ea, MM_EA); | |
} | |
else if (xr) { /* direct + idx? */ | |
ea = ea + ((a10) XR (xr, MM_EA)); | |
if (TSTS (XR (xr, MM_EA))) | |
ea = ea & AMASK; | |
} | |
return ea; | |
} | |
/* Calculate JRSTF effective address. This routine preserves | |
the left half of the effective address, to be the new flags. | |
*/ | |
d10 calc_jrstfea (d10 inst, int32 pflgs) | |
{ | |
int32 i, xr; | |
d10 mb; | |
for (i = 0; i < ind_max; i++) { | |
mb = inst; | |
xr = GET_XR (inst); | |
if (xr) | |
mb = (mb & AMASK) + XR (xr, MM_EA); | |
if (TST_IND (inst)) | |
inst = Read (((a10) mb) & AMASK, MM_EA); | |
else break; | |
} | |
if (i >= ind_max) | |
ABORT (STOP_IND); | |
return (mb & DMASK); | |
} | |
/* Byte pointer routines */ | |
/* Increment byte pointer - checked against KS10 ucode */ | |
void ibp (a10 ea, int32 pflgs) | |
{ | |
int32 p, s; | |
d10 bp; | |
bp = ReadM (ea, MM_OPND); /* get byte ptr */ | |
p = GET_P (bp); /* get P and S */ | |
s = GET_S (bp); | |
p = p - s; /* adv P */ | |
if (p < 0) { /* end of word? */ | |
bp = (bp & LMASK) | (INCR (bp)); /* incr addr */ | |
p = (36 - s) & 077; /* reset P */ | |
} | |
bp = PUT_P (bp, p); /* store new P */ | |
Write (ea, bp, MM_OPND); /* store byte ptr */ | |
return; | |
} | |
/* Load byte */ | |
d10 ldb (a10 ea, int32 pflgs) | |
{ | |
a10 ba; | |
int32 p, s; | |
d10 bp, wd; | |
bp = Read (ea, MM_OPND); /* get byte ptr */ | |
p = GET_P (bp); /* get P and S */ | |
s = GET_S (bp); | |
ba = calc_ea (bp, MM_EABP); /* get addr of byte */ | |
wd = Read (ba, MM_BSTK); /* read word */ | |
wd = (wd >> p); /* align byte */ | |
wd = wd & bytemask[s]; /* mask to size */ | |
return wd; | |
} | |
/* Deposit byte - must use read and write to get page fail correct */ | |
void dpb (d10 val, a10 ea, int32 pflgs) | |
{ | |
a10 ba; | |
int32 p, s; | |
d10 bp, wd, mask; | |
bp = Read (ea, MM_OPND); /* get byte ptr */ | |
p = GET_P (bp); /* get P and S */ | |
s = GET_S (bp); | |
ba = calc_ea (bp, MM_EABP); /* get addr of byte */ | |
wd = Read (ba, MM_BSTK); /* read word */ | |
mask = bytemask[s] << p; /* shift mask, val */ | |
val = val << p; | |
wd = (wd & ~mask) | (val & mask); /* insert byte */ | |
Write (ba, wd & DMASK, MM_BSTK); | |
return; | |
} | |
/* Adjust byte pointer - checked against KS10 ucode | |
The KS10 divide checks if the bytes per word = 0, which is a simpler | |
formulation of the processor reference manual check. | |
*/ | |
void adjbp (int32 ac, a10 ea, int32 pflgs) | |
{ | |
int32 p, s; | |
d10 bp, newby, left, byadj, bywrd, val, wdadj; | |
val = AC(ac); /* get adjustment */ | |
bp = Read (ea, MM_OPND); /* get byte pointer */ | |
p = GET_P (bp); /* get p */ | |
s = GET_S (bp); /* get s */ | |
if (s) { | |
left = (36 - p) / s; /* bytes to left of p */ | |
bywrd = left + (p / s); /* bytes per word */ | |
if (bywrd == 0) { /* zero bytes? */ | |
SETF (F_AOV | F_T1 | F_DCK); /* set flags */ | |
return; /* abort operation */ | |
} | |
newby = left + SXT (val); /* adjusted byte # */ | |
wdadj = newby / bywrd; /* word adjustment */ | |
byadj = (newby >= 0)? newby % bywrd: -((-newby) % bywrd); | |
if (byadj <= 0) { | |
byadj = byadj + bywrd; /* make adj positive */ | |
wdadj = wdadj - 1; | |
} | |
p = (36 - ((int32) byadj) * s) - ((36 - p) % s); /* new p */ | |
bp = (PUT_P (bp, p) & LMASK) | ((bp + wdadj) & RMASK); | |
} | |
AC(ac) = bp; | |
return; | |
} | |
/* Block transfer - checked against KS10 ucode | |
The KS10 uses instruction specific recovery code in page fail | |
to set the AC properly for restart. Lacking this mechanism, | |
the simulator must test references in advance. | |
The clocking test guarantees forward progress under single step. | |
*/ | |
void blt (int32 ac, a10 ea, int32 pflgs) | |
{ | |
a10 srca = (a10) LRZ (AC(ac)); | |
a10 dsta = (a10) RRZ (AC(ac)); | |
a10 lnt = ea - dsta + 1; | |
d10 srcv; | |
int32 flg, t; | |
AC(ac) = XWD (srca + lnt, dsta + lnt); | |
for (flg = 0; dsta <= ea; flg++) { /* loop */ | |
if (flg && (t = test_int ())) { /* timer event? */ | |
AC(ac) = XWD (srca, dsta); /* AC for intr */ | |
ABORT (t); | |
} | |
if (AccViol (srca & AMASK, MM_BSTK, PTF_RD)) { /* src access viol? */ | |
AC(ac) = XWD (srca, dsta); /* AC for page fail */ | |
Read (srca & AMASK, MM_BSTK); /* force trap */ | |
} | |
if (AccViol (dsta & AMASK, MM_OPND, PTF_WR)) { /* dst access viol? */ | |
AC(ac) = XWD (srca, dsta); /* AC for page fail */ | |
ReadM (dsta & AMASK, MM_OPND); /* force trap */ | |
} | |
srcv = Read (srca & AMASK, MM_BSTK); /* read */ | |
Write (dsta & AMASK, srcv, MM_OPND); /* write */ | |
srca = srca + 1; /* incr addr */ | |
dsta = dsta + 1; | |
} | |
return; | |
} | |
/* I/O block transfers - byte to Unibus (0) and Unibus to byte (1) */ | |
#define BYTE1 0776000000000 | |
#define BYTE2 0001774000000 | |
#define BYTE3 0000003770000 | |
#define BYTE4 0000000007760 | |
/* unused 0000000000017 */ | |
void bltu (int32 ac, a10 ea, int32 pflgs, int dir) | |
{ | |
a10 srca = (a10) LRZ (AC(ac)); | |
a10 dsta = (a10) RRZ (AC(ac)); | |
a10 lnt = ea - dsta + 1; | |
d10 srcv, dstv; | |
int32 flg, t; | |
AC(ac) = XWD (srca + lnt, dsta + lnt); | |
for (flg = 0; dsta <= ea; flg++) { /* loop */ | |
if (flg && (t = test_int ())) { /* timer event? */ | |
AC(ac) = XWD (srca, dsta); /* AC for intr */ | |
ABORT (t); | |
} | |
if (AccViol (srca & AMASK, MM_BSTK, PTF_RD)) { /* src access viol? */ | |
AC(ac) = XWD (srca, dsta); /* AC for page fail */ | |
Read (srca & AMASK, MM_BSTK); /* force trap */ | |
} | |
if (AccViol (dsta & AMASK, MM_OPND, PTF_WR)) { /* dst access viol? */ | |
AC(ac) = XWD (srca, dsta); /* AC for page fail */ | |
ReadM (dsta & AMASK, MM_OPND); /* force trap */ | |
} | |
srcv = Read (srca & AMASK, MM_BSTK); /* read */ | |
if (dir) dstv = ((srcv << 10) & BYTE1) | ((srcv >> 6) & BYTE2) | | |
((srcv << 12) & BYTE3) | ((srcv >> 4) & BYTE4); | |
else dstv = ((srcv & BYTE1) >> 10) | ((srcv & BYTE2) << 6) | | |
((srcv & BYTE3) >> 12) | ((srcv & BYTE4) << 4); | |
Write (dsta & AMASK, dstv, MM_OPND); /* write */ | |
srca = srca + 1; /* incr addr */ | |
dsta = dsta + 1; | |
} | |
return; | |
} | |
/* Utility routine to test for I/O event and interrupt */ | |
int32 test_int (void) | |
{ | |
int32 t; | |
if (sim_interval <= 0) { /* check queue */ | |
if (t = sim_process_event ()) /* IO event? */ | |
return t; | |
if (pi_eval ()) /* interrupt? */ | |
return (INTERRUPT); | |
} | |
else sim_interval--; /* count clock */ | |
return 0; | |
} | |
/* Adjust stack pointer | |
The reference manual says to trap on: | |
1) E < 0, left changes from + to - | |
2) E >= 0, left changes from - to + | |
This is the same as trap on: | |
1) E and left result have same signs | |
2) initial value and left result have different signs | |
*/ | |
d10 adjsp (d10 val, a10 ea) | |
{ | |
d10 imm = ea; | |
d10 left, right; | |
left = ADDL (val, imm); | |
right = ADDR (val, imm); | |
if (TSTS ((val ^ left) & (~left ^ RLZ (imm)))) | |
SETF (F_T2); | |
return (left | right); | |
} | |
/* Jump if find first ones | |
Takes advantage of 7 bit find first table for priority interrupts. | |
*/ | |
int32 jffo (d10 val) | |
{ | |
int32 i, by; | |
if ((val & DMASK) == 0) | |
return 0; | |
for (i = 0; i <= 28; i = i + 7) { /* scan five bytes */ | |
by = (int32) ((val >> (29 - i)) & 0177); | |
if (by) | |
return (pi_m2lvl[by] + i - 1); | |
} | |
return 35; /* must be bit 35 */ | |
} | |
/* Circulate - ITS only instruction | |
Bits rotated out of AC are rotated into the opposite end of AC+1 - why? | |
No attempt is made to optimize this instruction. | |
*/ | |
void circ (int32 ac, int32 ea) | |
{ | |
int32 sc = LIT8 (ea) % 72; | |
int32 p1 = ADDAC (ac,1); | |
int32 i; | |
d10 val; | |
if (sc == 0) /* any shift? */ | |
return; | |
if (ea & RSIGN) /* if right, make left */ | |
sc = 72 - sc; | |
for (i = 0; i < sc; i++) { /* one bit at a time */ | |
val = TSTS (AC(ac)); /* shift out */ | |
AC(ac) = ((AC(ac) << 1) | (AC(p1) & 1)) & DMASK; | |
AC(p1) = (AC(p1) >> 1) | val; /* shift in */ | |
} | |
return; | |
} | |
/* Arithmetic processor (APR) | |
The APR subsystem includes miscellaneous interrupts that are individually | |
maskable but which interrupt on a single, selectable level | |
Instructions for the arithmetic processor: | |
APRID read system id | |
WRAPR (CONO APR) write system flags | |
RDAPR (CONI APR) read system flags | |
(CONSO APR) test system flags | |
(CONSZ APR) test system flags | |
*/ | |
t_bool aprid (a10 ea, int32 prv) | |
{ | |
Write (ea, (Q_ITS)? UC_AIDITS: UC_AIDDEC, prv); | |
return FALSE; | |
} | |
/* Checked against KS10 ucode */ | |
t_bool wrapr (a10 ea, int32 prv) | |
{ | |
int32 bits = APR_GETF (ea); | |
apr_lvl = ea & APR_M_LVL; | |
if (ea & APR_SENB) /* set enables? */ | |
apr_enb = apr_enb | bits; | |
if (ea & APR_CENB) /* clear enables? */ | |
apr_enb = apr_enb & ~bits; | |
if (ea & APR_CFLG) /* clear flags? */ | |
apr_flg = apr_flg & ~bits; | |
if (ea & APR_SFLG) /* set flags? */ | |
apr_flg = apr_flg | bits; | |
if (apr_flg & APRF_ITC) { /* interrupt console? */ | |
fe_intr (); /* explicit callout */ | |
apr_flg = apr_flg & ~APRF_ITC; /* interrupt clears */ | |
} | |
pi_eval (); /* eval pi system */ | |
return FALSE; | |
} | |
t_bool rdapr (a10 ea, int32 prv) | |
{ | |
Write (ea, (d10) APRWORD, prv); | |
return FALSE; | |
} | |
t_bool czapr (a10 ea, int32 prv) | |
{ | |
return ((APRHWORD & ea)? FALSE: TRUE); | |
} | |
t_bool coapr (a10 ea, int32 prv) | |
{ | |
return ((APRHWORD & ea)? TRUE: FALSE); | |
} | |
/* Routine to change the processor flags, called from JRST, MUUO, interrupt. | |
If jrst is TRUE, must munge flags for executive security. | |
Because the KS10 lacks the public flag, these checks are simplified. | |
*/ | |
void set_newflags (d10 newf, t_bool jrst) | |
{ | |
int32 fl = (int32) LRZ (newf); | |
if (jrst && TSTF (F_USR)) { /* if in user now */ | |
fl = fl | F_USR; /* can't clear user */ | |
if (!TSTF (F_UIO)) /* if !UIO, can't set */ | |
fl = fl & ~F_UIO; | |
} | |
if (Q_ITS && (fl & F_1PR)) { /* ITS 1-proceed? */ | |
its_1pr = 1; /* set flag */ | |
fl = fl & ~F_1PR; /* vanish bit */ | |
} | |
flags = fl & F_MASK; /* set new flags */ | |
set_dyn_ptrs (); /* set new ptrs */ | |
return; | |
} | |
/* Priority interrupt system (PI) | |
The priority interrupt system has three sources of requests | |
(pi_apr) system flags - synthesized on the fly | |
(pi_ioq) I/O interrupts - synthesized on the fly | |
pi_prq program requests | |
APR and I/O requests are masked with the PI enable mask; the program | |
requests are not. If priority interrupts are enabled, and there is | |
a request at a level exceeding the currently active level, then an | |
interrupt occurs. | |
Instructions for the priority interrupt system: | |
WRPI (CONO PI) write pi system | |
RDPI (CONI PI) read pi system | |
(CONSO PI) test pi system | |
(CONSZ PI) test pi system | |
Routines for the priority interrupt system: | |
pi_eval return level number of highest interrupt | |
pi_dismiss dismiss highest outstanding interrupt | |
Checked against KS10 ucode - KS10 UUO's if <18:21> are non-zero | |
*/ | |
t_bool wrpi (a10 ea, int32 prv) | |
{ | |
int32 lvl = ea & PI_M_LVL; | |
if (ea & PI_INIT) | |
pi_on = pi_enb = pi_act = pi_prq = 0; | |
if (ea & PI_CPRQ) /* clear prog reqs? */ | |
pi_prq = pi_prq & ~lvl; | |
if (ea & PI_SPRQ) /* set prog reqs? */ | |
pi_prq = pi_prq | lvl; | |
if (ea & PI_SENB) /* enable levels? */ | |
pi_enb = pi_enb | lvl; | |
if (ea & PI_CENB) /* disable levels? */ | |
pi_enb = pi_enb & ~lvl; | |
if (ea & PI_SON) /* enable pi? */ | |
pi_on = 1; | |
if (ea & PI_CON) /* disable pi? */ | |
pi_on = 0; | |
pi_eval (); /* eval pi system */ | |
return FALSE; | |
} | |
t_bool rdpi (a10 ea, int32 prv) | |
{ | |
Write (ea, (d10) PIWORD, prv); | |
return FALSE; | |
} | |
t_bool czpi (a10 ea, int32 prv) | |
{ | |
return ((PIHWORD & ea)? FALSE: TRUE); | |
} | |
t_bool copi (a10 ea, int32 prv) | |
{ | |
return ((PIHWORD & ea)? TRUE: FALSE); | |
} | |
/* Priority interrupt evaluation | |
The Processor Reference Manuals says that program interrupt | |
requests occur whether the corresponding level is enabled or | |
not. However, the KS10, starting with microcode edit 47, | |
masked program requests under the enable mask, just like APR | |
and I/O requests. This is not formally documented but appears | |
to be necessary for the TOPS20 console port to run correclty. | |
*/ | |
int32 pi_eval (void) | |
{ | |
int32 reqlvl, actlvl; | |
extern int32 pi_ub_eval (); | |
qintr = 0; | |
if (pi_on) { | |
pi_apr = (apr_flg & apr_enb)? pi_l2bit[apr_lvl]: 0; | |
pi_ioq = pi_ub_eval (); | |
reqlvl = pi_m2lvl[((pi_apr | pi_ioq | pi_prq) & pi_enb)]; | |
actlvl = pi_m2lvl[pi_act]; | |
if ((actlvl == 0) || (reqlvl < actlvl)) | |
qintr = reqlvl; | |
} | |
return qintr; | |
} | |
void pi_dismiss (void) | |
{ | |
pi_act = pi_act & ~pi_l2bit[pi_m2lvl[pi_act]]; /* clr left most bit */ | |
pi_eval (); /* eval pi system */ | |
return; | |
} | |
/* Reset routine */ | |
t_stat cpu_reset (DEVICE *dptr) | |
{ | |
flags = 0; /* clear flags */ | |
its_1pr = 0; /* clear 1-proceed */ | |
ebr = ubr = 0; /* clear paging */ | |
pi_enb = pi_act = pi_prq = 0; /* clear PI */ | |
apr_enb = apr_flg = apr_lvl = 0; /* clear APR */ | |
pcst = 0; /* clear PC samp */ | |
rlog = 0; /* clear reg log */ | |
hsb = (Q_ITS)? UC_HSBITS: UC_HSBDEC; /* set HSB */ | |
set_dyn_ptrs (); | |
set_ac_display (ac_cur); | |
pi_eval (); | |
if (M == NULL) | |
M = (d10 *) calloc (MAXMEMSIZE, sizeof (d10)); | |
if (M == NULL) | |
return SCPE_MEM; | |
pcq_r = find_reg ("PCQ", NULL, dptr); | |
if (pcq_r) | |
pcq_r->qptr = 0; | |
else return SCPE_IERR; | |
sim_brk_types = sim_brk_dflt = SWMASK ('E'); | |
return SCPE_OK; | |
} | |
/* Memory examine */ | |
t_stat cpu_ex (t_value *vptr, t_addr ea, UNIT *uptr, int32 sw) | |
{ | |
if (vptr == NULL) | |
return SCPE_ARG; | |
if (ea < AC_NUM) | |
*vptr = AC(ea) & DMASK; | |
else { | |
if (sw & SWMASK ('V')) { | |
ea = conmap (ea, PTF_CON, sw); | |
if (ea >= MAXMEMSIZE) | |
return SCPE_REL; | |
} | |
if (ea >= MEMSIZE) | |
return SCPE_NXM; | |
*vptr = M[ea] & DMASK; | |
} | |
return SCPE_OK; | |
} | |
/* Memory deposit */ | |
t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw) | |
{ | |
if (ea < AC_NUM) | |
AC(ea) = val & DMASK; | |
else { | |
if (sw & SWMASK ('V')) { | |
ea = conmap (ea, PTF_CON | PTF_WR, sw); | |
if (ea >= MAXMEMSIZE) | |
return SCPE_REL; | |
} | |
if (ea >= MEMSIZE) | |
return SCPE_NXM; | |
M[ea] = val & DMASK; | |
} | |
return SCPE_OK; | |
} | |
/* Set current AC pointers for SCP */ | |
void set_ac_display (d10 *acbase) | |
{ | |
extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr); | |
REG *rptr; | |
int i; | |
rptr = find_reg ("AC0", NULL, &cpu_dev); | |
if (rptr == NULL) | |
return; | |
for (i = 0; i < AC_NUM; i++, rptr++) | |
rptr->loc = (void *) (acbase + i); | |
return; | |
} | |
/* Set history */ | |
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) | |
{ | |
int32 i, lnt; | |
t_stat r; | |
if (cptr == NULL) { | |
for (i = 0; i < hst_lnt; i++) | |
hst[i].pc = 0; | |
hst_p = 0; | |
return SCPE_OK; | |
} | |
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); | |
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) | |
return SCPE_ARG; | |
hst_p = 0; | |
if (hst_lnt) { | |
free (hst); | |
hst_lnt = 0; | |
hst = NULL; | |
} | |
if (lnt) { | |
hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); | |
if (hst == NULL) | |
return SCPE_MEM; | |
hst_lnt = lnt; | |
} | |
return SCPE_OK; | |
} | |
/* Show history */ | |
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) | |
{ | |
int32 k, di, lnt; | |
char *cptr = (char *) desc; | |
t_stat r; | |
t_value sim_eval; | |
InstHistory *h; | |
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, | |
UNIT *uptr, int32 sw); | |
if (hst_lnt == 0) /* enabled? */ | |
return SCPE_NOFNC; | |
if (cptr) { | |
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); | |
if ((r != SCPE_OK) || (lnt == 0)) | |
return SCPE_ARG; | |
} | |
else lnt = hst_lnt; | |
di = hst_p - lnt; /* work forward */ | |
if (di < 0) | |
di = di + hst_lnt; | |
fprintf (st, "PC AC EA IR\n\n"); | |
for (k = 0; k < lnt; k++) { /* print specified */ | |
h = &hst[(++di) % hst_lnt]; /* entry pointer */ | |
if (h->pc & HIST_PC) { /* instruction? */ | |
fprintf (st, "%06o ", h->pc & AMASK); | |
fprint_val (st, h->ac, 8, 36, PV_RZRO); | |
fputs (" ", st); | |
fprintf (st, "%06o ", h->ea); | |
sim_eval = h->ir; | |
if ((fprint_sym (st, h->pc & AMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0) { | |
fputs ("(undefined) ", st); | |
fprint_val (st, h->ir, 8, 36, PV_RZRO); | |
} | |
fputc ('\n', st); /* end line */ | |
} /* end else instruction */ | |
} /* end for */ | |
return SCPE_OK; | |
} |