/* i7094_cpu.c: IBM 7094 CPU simulator | |
Copyright (c) 2003-2010, 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 7094 central processor | |
16-Jul-10 RMS Fixed PSE, MSE user mode protection (found by Dave Pitts) | |
Fixed issues in storage nullification mode | |
28-Apr-07 RMS Removed clock initialization | |
29-Oct-06 RMS Added additional expanded core instructions | |
17-Oct-06 RMS Fixed the fix in halt IO wait loop | |
16-Jun-06 RMS Fixed bug in halt IO wait loop | |
The register state for the 7094 is: | |
AC<S,Q,P,1:35> accumulator | |
MQ<S,1:35> multiplier-quotient register | |
SI<S,1:35> storage indicators | |
KEYS<0:35> front panel keys (switches) | |
IC<0:14> instruction counter (called PC here) | |
XR<0:14>[8] index registers (XR[0] is always 0) | |
SSW<0:5> sense switches | |
SLT<0:3> sense lights | |
OVF AC overflow | |
MQO MQ overflow | |
DVC divide check | |
IOC I/O check | |
TTRAP transfer trap mode | |
CTRAP copy trap mode (for 709 compatibility) | |
FTRAP floating trap mode (off is 704 compatibility) | |
STRAP select trap mode | |
STORN storage nullifcation mode | |
MULTI multi-tag mode (7090 compatibility) | |
CTSS required a set of special features: memory extension (to 65K), | |
protection, and relocation. Additional state: | |
USER user mode | |
INST_BASE instruction memory select (A vs B core) | |
DATA_BASE data memory select (A vs B core) | |
IND_RELOC<0:6> relocation value (block number) | |
IND_START<0:6> start address block | |
IND_LIMIT<0:6> limit address block | |
The 7094 had five instruction formats: memory reference, | |
memory reference with count, convert, decrement, and immediate. | |
00000000011 11 1111 112 222222222333333 | |
S12345678901 23 4567 890 123456789012345 | |
+------------+--+----+---+---------------+ | |
| opcode |ND|0000|tag| address | memory reference | |
+------------+--+----+---+---------------+ | |
00000000011 111111 112 222222222333333 | |
S12345678901 234567 890 123456789012345 | |
+------------+------+---+---------------+ | |
| opcode | count|tag| address | memory reference | |
+------------+------+---+---------------+ with count | |
000000000 11111111 11 2 222222222333333 | |
S123456789 01234567 89 0 123456789012345 | |
+----------+--------+--+-+---------------+ | |
| opcode | count |00|X| address | convert | |
+----------+--------+--+-+---------------+ | |
00 000000011111111 112 222222222333333 | |
S12 345678901234567 890 123456789012345 | |
+---+---------------+---+---------------+ | |
|opc| decrement |tag| address | decrement | |
+---+---------------+---+---------------+ | |
00000000011 111111 112222222222333333 | |
S12345678901 234567 890123456789012345 | |
+------------+------+------------------+ | |
| opcode |000000| immediate | immediate | |
+------------+------+------------------+ | |
This routine is the instruction decode routine for the 7094. | |
It is called from the simulator control program to execute | |
instructions in simulated memory, starting at the simulated PC. | |
It runs until a stop condition occurs. | |
General notes: | |
1. Reasons to stop. The simulator can be stopped by: | |
HALT instruction | |
illegal instruction | |
illegal I/O operation for device | |
illegal I/O operation for channel | |
breakpoint encountered | |
nested XEC's exceeding limit | |
divide check | |
I/O error in I/O simulator | |
2. Data channel traps. The 7094 is a channel-based system. | |
Channels can generate traps for errors and status conditions. | |
Channel trap state: | |
ch_flags[0..7] flags for channels A..H | |
chtr_enab channel trap enables | |
chtr_inht channel trap inhibit due to trap (cleared by RCT) | |
chtr_inhi channel trap inhibit due to XEC, ENAB, RCT, RDS, | |
or WDS (cleared after one instruction) | |
Channel traps are summarized in variable chtr_pend. | |
3. Arithmetic. The 7094 uses signed magnitude arithmetic for | |
integer and floating point calculations, and 2's complement | |
arithmetic for indexing calculations. | |
4. Adding I/O devices. These modules must be modified: | |
i7094_defs.h add device definitions | |
i7094_io.c add device address mapping | |
i7094_sys.c add sim_devices table entry | |
*/ | |
#include "i7094_defs.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 | inst_base) | |
#define HIST_MIN 64 | |
#define HIST_MAX (2 << 18) | |
#define HIST_CH_C 1 /* include channel */ | |
#define HIST_CH_I 2 /* include IO */ | |
#define HALT_IO_LIMIT ((2 << 18) + 1) /* max wait to stop */ | |
#define EAMASK (mode_storn? A704_MASK: AMASK) /* eff addr mask */ | |
t_uint64 *M = NULL; /* memory */ | |
t_uint64 AC = 0; /* AC */ | |
t_uint64 MQ = 0; /* MQ */ | |
t_uint64 SI = 0; /* indicators */ | |
t_uint64 KEYS = 0; /* storage keys */ | |
uint32 PC = 0; /* PC (IC) */ | |
uint32 oldPC = 0; /* prior PC */ | |
uint32 XR[8] = { 0 }; /* index registers */ | |
uint32 SSW = 0; /* sense switches */ | |
uint32 SLT = 0; /* sense lights */ | |
uint32 ch_req = 0; /* channel requests */ | |
uint32 chtr_pend = 0; /* chan trap pending */ | |
uint32 chtr_inht = 0; /* chan trap inhibit trap */ | |
uint32 chtr_inhi = 0; /* chan trap inhibit inst */ | |
uint32 chtr_enab = 0; /* chan trap enables */ | |
uint32 mode_ttrap = 0; /* transfer trap mode */ | |
uint32 mode_ctrap = 0; /* copy trap mode */ | |
uint32 mode_strap = 0; /* select trap mode */ | |
uint32 mode_ftrap = 0; /* floating trap mode */ | |
uint32 mode_storn = 0; /* storage nullification */ | |
uint32 mode_multi = 0; /* multi-index mode */ | |
uint32 ind_ovf = 0; /* overflow */ | |
uint32 ind_mqo = 0; /* MQ overflow */ | |
uint32 ind_dvc = 0; /* divide check */ | |
uint32 ind_ioc = 0; /* IO check */ | |
uint32 cpu_model = I_9X|I_94; /* CPU type */ | |
uint32 mode_user = 0; /* (CTSS) user mode */ | |
uint32 ind_reloc = 0; /* (CTSS) relocation */ | |
uint32 ind_start = 0; /* (CTSS) prot start */ | |
uint32 ind_limit = 0; /* (CTSS) prot limit */ | |
uint32 inst_base = 0; /* (CTSS) inst A/B sel */ | |
uint32 data_base = 0; /* (CTSS) data A/B sel */ | |
uint32 xec_max = 16; /* XEC chain limit */ | |
uint32 ht_pend = 0; /* HTR pending */ | |
uint32 ht_addr = 0; /* HTR address */ | |
uint32 stop_illop = 1; /* stop on ill op */ | |
uint32 cpu_astop = 0; /* address stop */ | |
uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ | |
int32 pcq_p = 0; /* PC queue ptr */ | |
REG *pcq_r = NULL; /* PC queue reg ptr */ | |
int32 hst_p = 0; /* history pointer */ | |
int32 hst_lnt = 0; /* history length */ | |
uint32 hst_ch = 0; /* channel history */ | |
InstHistory *hst = NULL; /* instruction history */ | |
extern uint32 ch_sta[NUM_CHAN]; | |
extern uint32 ch_flags[NUM_CHAN]; | |
extern DEVICE mt_dev[NUM_CHAN]; | |
extern DEVICE ch_dev[NUM_CHAN]; | |
extern FILE *sim_deb; | |
extern int32 sim_int_char; | |
extern int32 sim_interval; | |
extern int32 sim_switches; | |
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_model (UNIT *uptr, int32 val, char *cptr, void *desc); | |
t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); | |
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); | |
t_bool ReadI (uint32 va, t_uint64 *dat); | |
t_bool Read (uint32 va, t_uint64 *dat); | |
t_bool Write (uint32 va, t_uint64 dat); | |
void WriteTA (uint32 pa, uint32 addr); | |
void WriteTAD (uint32 pa, uint32 addr, uint32 decr); | |
void TrapXfr (uint32 newpc); | |
t_bool fp_trap (uint32 spill); | |
t_bool prot_trap (uint32 decr); | |
t_bool sel_trap (uint32 va); | |
t_bool cpy_trap (uint32 va); | |
uint32 get_xri (uint32 tag); | |
uint32 get_xrx (uint32 tag); | |
void put_xr (uint32 tag, uint32 dat); | |
t_stat cpu_fprint_one_inst (FILE *st, uint32 pc, uint32 rpt, uint32 ea, | |
t_uint64 ir, t_uint64 ac, t_uint64 mq, t_uint64 si, t_uint64 opnd); | |
extern uint32 chtr_eval (uint32 *decr); | |
extern void op_add (t_uint64 sr); | |
extern void op_mpy (t_uint64 ac, t_uint64 sr, uint32 sc); | |
extern t_bool op_div (t_uint64 sr, uint32 sc); | |
extern uint32 op_fad (t_uint64 sr, t_bool norm); | |
extern uint32 op_fmp (t_uint64 sr, t_bool norm); | |
extern uint32 op_fdv (t_uint64); | |
extern uint32 op_dfad (t_uint64 shi, t_uint64 slo, t_bool norm); | |
extern uint32 op_dfmp (t_uint64 shi, t_uint64 slo, t_bool norm); | |
extern uint32 op_dfdv (t_uint64 shi, t_uint64 slo); | |
extern void op_als (uint32 ea); | |
extern void op_ars (uint32 ea); | |
extern void op_lls (uint32 ea); | |
extern void op_lrs (uint32 ea); | |
extern void op_lgl (uint32 ea); | |
extern void op_lgr (uint32 ea); | |
extern t_stat op_pse (uint32 ea); | |
extern t_stat op_mse (uint32 ea); | |
extern t_stat ch_op_ds (uint32 ch, uint32 ds, uint32 unit); | |
extern t_stat ch_op_nds (uint32 ch, uint32 ds, uint32 unit); | |
extern t_stat ch_op_start (uint32 ch, uint32 clc, t_bool reset); | |
extern t_stat ch_op_store (uint32 ch, t_uint64 *dat); | |
extern t_stat ch_op_store_diag (uint32 ch, t_uint64 *dat); | |
extern t_stat ch_proc (uint32 ch); | |
/* 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+UNIT_BINK, STDMEMSIZE) }; | |
REG cpu_reg[] = { | |
{ ORDATA (PC, PC, ASIZE) }, | |
{ ORDATA (AC, AC, 38) }, | |
{ ORDATA (MQ, MQ, 36) }, | |
{ ORDATA (SI, SI, 36) }, | |
{ ORDATA (KEYS, KEYS, 36) }, | |
{ ORDATA (XR1, XR[1], 15) }, | |
{ ORDATA (XR2, XR[2], 15) }, | |
{ ORDATA (XR3, XR[3], 15) }, | |
{ ORDATA (XR4, XR[4], 15) }, | |
{ ORDATA (XR5, XR[5], 15) }, | |
{ ORDATA (XR6, XR[6], 15) }, | |
{ ORDATA (XR7, XR[7], 15) }, | |
{ FLDATA (SS1, SSW, 5) }, | |
{ FLDATA (SS2, SSW, 4) }, | |
{ FLDATA (SS3, SSW, 3) }, | |
{ FLDATA (SS4, SSW, 2) }, | |
{ FLDATA (SS5, SSW, 1) }, | |
{ FLDATA (SS6, SSW, 0) }, | |
{ FLDATA (SL1, SLT, 3) }, | |
{ FLDATA (SL2, SLT, 2) }, | |
{ FLDATA (SL3, SLT, 1) }, | |
{ FLDATA (SL4, SLT, 0) }, | |
{ FLDATA (OVF, ind_ovf, 0) }, | |
{ FLDATA (MQO, ind_mqo, 0) }, | |
{ FLDATA (DVC, ind_dvc, 0) }, | |
{ FLDATA (IOC, ind_ioc, 0) }, | |
{ FLDATA (TTRAP, mode_ttrap, 0) }, | |
{ FLDATA (CTRAP, mode_ctrap, 0) }, | |
{ FLDATA (STRAP, mode_strap, 0) }, | |
{ FLDATA (FTRAP, mode_ftrap, 0) }, | |
{ FLDATA (STORN, mode_storn, 0) }, | |
{ FLDATA (MULTI, mode_multi, 0) }, | |
{ ORDATA (CHREQ, ch_req, NUM_CHAN) }, | |
{ FLDATA (CHTR_PEND, chtr_pend, 0) }, | |
{ FLDATA (CHTR_INHT, chtr_inht, 0) }, | |
{ FLDATA (CHTR_INHI, chtr_inhi, 0) }, | |
{ ORDATA (CHTR_ENAB, chtr_enab, 30) }, | |
{ FLDATA (USERM, mode_user, 0) }, | |
{ FLDATA (IMEM, inst_base, BCORE_V) }, | |
{ FLDATA (DMEM, data_base, BCORE_V) }, | |
{ GRDATA (RELOC, ind_reloc, 8, VA_N_BLK, VA_V_BLK) }, | |
{ GRDATA (START, ind_start, 8, VA_N_BLK, VA_V_BLK) }, | |
{ GRDATA (LIMIT, ind_limit, 8, VA_N_BLK, VA_V_BLK) }, | |
{ ORDATA (OLDPC, oldPC, ASIZE), REG_RO }, | |
{ BRDATA (PCQ, pcq, 8, ASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, | |
{ ORDATA (PCQP, pcq_p, 6), REG_HRO }, | |
{ FLDATA (HTPEND, ht_pend, 0) }, | |
{ ORDATA (HTADDR, ht_addr, ASIZE) }, | |
{ DRDATA (XECMAX, xec_max, 8), PV_LEFT + REG_NZ }, | |
{ ORDATA (WRU, sim_int_char, 8) }, | |
{ FLDATA (STOP_ILL, stop_illop, 0) }, | |
{ ORDATA (MODEL, cpu_model, 4), REG_HRO }, | |
{ NULL } | |
}; | |
MTAB cpu_mod[] = { | |
{ MTAB_XTD | MTAB_VDV, I_9X|I_94|I_CT, "MODEL", "CTSS", | |
&cpu_set_model, &cpu_show_model, NULL }, | |
{ MTAB_XTD | MTAB_VDV, I_9X|I_94, NULL, "7094", | |
&cpu_set_model, NULL, NULL }, | |
{ MTAB_XTD | MTAB_VDV, I_9X, NULL, "7090", | |
&cpu_set_model, NULL, NULL }, | |
{ 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, | |
NULL, DEV_DEBUG | |
}; | |
/* Instruction decode table */ | |
const uint8 op_flags[1024] = { | |
I_XN , 0 , 0 , 0 , /* +000 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XN , I_XN|I_9X , I_XN , 0 , /* +020 */ | |
I_XN , 0 , I_XN , I_XN , | |
I_XN , I_XN , I_XN , I_XN , | |
0 , 0 , 0 , 0 , | |
I_XN|I_9X , I_9X , I_XN|I_9X , I_9X , /* +040 */ | |
I_9X , 0 , I_XN|I_9X , 0 , | |
0 , I_9X , 0 , 0 , | |
I_9X , I_9X , I_9X , I_9X , | |
I_XN , I_XN , I_XN , I_XN , /* +060 */ | |
I_XN , I_XN , I_XN , I_XN , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XN , I_XN|I_CT , 0 , 0 , /* +100 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_9X , I_9X , I_9X , I_9X , | |
I_XN , 0 , 0 , 0 , /* +120 */ | |
0 , 0 , 0 , 0 , | |
0 , I_9X , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XN , 0 , 0 , 0 , /* +140 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , I_XN|I_9X , I_XN|I_9X , 0 , /* +160 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , 0 , 0 , 0 , /* +200 */ | |
I_XNR , I_XNR , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR|I_9X, I_XNR , 0 , 0 , /* +220 */ | |
I_XNR|I_9X, I_XNR , I_XNR|I_9X, I_XNR , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR|I_9X, I_XNR , 0 , 0 , /* +240 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , I_XND|I_94, 0 , 0 , /* +260 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , I_XND|I_94, I_XNR , I_XND|I_94, /* +300 */ | |
I_XNR|I_9X, I_XND|I_94, I_XNR|I_9X, I_XND|I_94, | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR|I_9X, 0 , I_XNR|I_9X, 0 , /* +320 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , 0 , 0 , 0 , /* +340 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , I_XNR , 0 , 0 , /* +360 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , I_XNR|I_9X, I_XNR , 0 , /* +400 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* +420 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR|I_9X, I_XNR|I_9X, I_XNR|I_9X, I_XNR|I_94, /* +440 */ | |
I_XNR|I_9X, I_XNR|I_9X, I_XNR|I_9X, 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_9X , 0 , 0 , 0 , /* +460 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR|I_9X, 0 , I_XNR , 0 , /* +500 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , 0 , I_XNR , 0 , /* +520 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_R , I_R , 0 , 0 , | |
I_XN , I_XN , I_XN , I_XN , /* +540 */ | |
I_XN , I_XN , I_XN , I_XN , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , 0 , I_XNR|I_CT, 0 , /* +560 */ | |
I_XNR , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XN , I_XN , I_XN , 0 , /* +600 */ | |
I_XN|I_9X , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , I_XNR , I_XNR , 0 , /* +620 */ | |
0 , I_XNR|I_9X, 0 , 0 , | |
I_XNR|I_9X, 0 , 0 , 0 , | |
I_R , 0 , I_R|I_94 , 0 , | |
I_XN , I_XN , I_XN , I_XN , /* +640 */ | |
I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* +660 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_9X , 0 , 0 , 0 , /* +700 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* +720 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* +740 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , I_94 , 0 , | |
I_X , 0 , I_X , I_X , /* +760 */ | |
I_X , I_X , I_X , I_X , | |
I_X , I_X , I_X , 0 , | |
0 , 0 , 0 , 0 , | |
I_XN , 0 , 0 , 0 , /* -000 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XN , I_XN|I_9X , I_XN , 0 , /* -020 */ | |
I_XN , 0 , I_XN , I_XN , | |
I_XN , I_XN , I_XN , I_XN , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -040 */ | |
0 , 0 , I_9X , 0 , | |
0 , I_9X , 0 , 0 , | |
I_9X , I_9X , I_9X , I_9X , | |
I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , /* -060 */ | |
I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XN , I_XN|I_CT , 0 , 0 , /* -100 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_9X , I_9X , I_9X , I_9X , | |
I_XN , 0 , 0 , 0 , /* -120 */ | |
0 , 0 , 0 , 0 , | |
I_9X , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XN|I_9X , 0 , 0 , 0 , /* -140 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_9X , I_9X , I_9X , I_9X , | |
0 , 0 , 0 , 0 , /* -160 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR|I_9X, 0 , 0 , 0 , /* -200 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -220 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XND|I_94, I_XND|I_94, 0 , 0 , /* -240 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , I_XND|I_94, 0 , 0 , /* -260 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , I_XND|I_94, I_XNR , I_XND|I_94, /* -300 */ | |
I_XNR|I_9X, I_XND|I_94, I_XNR|I_9X, I_XND|I_94, | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , 0 , 0 , 0 , /* -320 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , 0 , 0 , 0 , /* -340 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -360 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR|I_9X, 0 , 0 , 0 , /* -400 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -420 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -440 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -460 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR , I_XNR , 0 , 0 , /* -500 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR|I_9X, 0 , 0 , 0 , /* -520 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_R , I_R , 0 , 0 , | |
I_XN , I_XN , I_XN , I_XN , /* -540 */ | |
I_XN , I_XN , I_XNR , I_XN , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -560 */ | |
I_XNR|I_CT, 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XN , 0 , I_XNR|I_9X, I_XN|I_94 , /* -600 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_XNR|I_9X, 0 , 0 , 0 , /* -620 */ | |
0 , I_XNR , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_R , 0 , I_R|I_94 , 0 , | |
I_XN , I_XN , I_XN , I_XN , /* -640 */ | |
I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -660 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
I_9X , 0 , 0 , 0 , /* -700 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -720 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , /* -740 */ | |
0 , 0 , 0 , 0 , | |
0 , 0 , 0 , 0 , | |
0 , 0 , I_94 , 0 , | |
I_X , I_X|I_CT , 0 , I_X , /* -760 */ | |
0 , I_X , 0 , 0 , | |
0 , 0 , I_X , I_X , | |
I_9X , 0 , 0 , 0 | |
}; | |
/* Instruction execution routine */ | |
t_stat sim_instr (void) | |
{ | |
t_stat reason = SCPE_OK; | |
t_uint64 IR, SR, t, t1, t2, sr1; | |
uint32 op, fl, tag, tagi, addr, ea; | |
uint32 ch, dec, xr, xec_cnt, trp; | |
uint32 i, j, sc, s1, s2, spill; | |
t_bool tracing; | |
/* Restore register state */ | |
ch_set_map (); /* set dispatch map */ | |
if (!(cpu_model & (I_94|I_CT))) /* ~7094? MTM always on */ | |
mode_multi = 1; | |
inst_base = inst_base & ~AMASK; /* A/B sel is 1b */ | |
data_base = data_base & ~AMASK; | |
ind_reloc = ind_reloc & VA_BLK; /* canonical form */ | |
ind_start = ind_start & VA_BLK; | |
ind_limit = (ind_limit & VA_BLK) | VA_OFF; | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
tracing = ((hst_lnt != 0) || DEBUG_PRS (cpu_dev)); | |
if (ht_pend) { /* HTR pending? */ | |
oldPC = (PC - 1) & AMASK; | |
ht_pend = 0; /* clear flag */ | |
PCQ_ENTRY; | |
if (mode_ttrap) { /* trap? */ | |
WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ | |
TrapXfr (TRAP_TRA_PC); /* trap */ | |
} | |
else PC = ht_addr; /* branch */ | |
} | |
/* Main instruction fetch/decode loop */ | |
while (reason == SCPE_OK) { /* loop until error */ | |
if (cpu_astop) { /* debug stop? */ | |
cpu_astop = 0; | |
reason = SCPE_STOP; | |
break; | |
} | |
if (sim_interval <= 0) { /* intv cnt expired? */ | |
if (reason = sim_process_event ()) /* process events */ | |
break; | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
} | |
for (i = 0; ch_req && (i < NUM_CHAN); i++) { /* loop thru channels */ | |
if (ch_req & REQ_CH (i)) { /* channel request? */ | |
if (reason = ch_proc (i)) | |
break; | |
} | |
chtr_pend = chtr_eval (NULL); | |
if (reason) /* error? */ | |
break; | |
} | |
if (chtr_pend) { /* channel trap? */ | |
addr = chtr_eval (&trp); /* get trap info, clr */ | |
chtr_inht = 1; /* inhibit traps */ | |
chtr_pend = 0; /* no trap pending */ | |
WriteTAD (addr, PC, trp); /* wr trap addr,flag */ | |
IR = ReadP (addr + 1); /* get trap instr */ | |
oldPC = PC; /* save current PC */ | |
} | |
else { | |
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ | |
reason = STOP_IBKPT; /* stop simulation */ | |
break; | |
} | |
if (chtr_inhi) { /* 1 cycle inhibit? */ | |
chtr_inhi = 0; /* clear */ | |
chtr_pend = chtr_eval (NULL); /* re-evaluate */ | |
} | |
oldPC = PC; /* save current PC */ | |
PC = (PC + 1) & EAMASK; /* increment PC */ | |
if (!ReadI (oldPC, &IR)) /* get inst; trap? */ | |
continue; | |
} | |
sim_interval = sim_interval - 1; | |
xec_cnt = 0; /* clear XEC cntr */ | |
XEC: | |
tag = GET_TAG (IR); /* get tag */ | |
addr = (uint32) IR & EAMASK; /* get base addr */ | |
/* Decrement format instructions */ | |
if (IR & INST_T_DEC) { /* decrement type? */ | |
op = GET_OPD (IR); /* get opcode */ | |
dec = GET_DEC (IR); /* get decrement */ | |
xr = get_xrx (tag); /* get xr, upd MTM */ | |
if (tracing) { /* trace or history? */ | |
if (hst_lnt) /* history enabled? */ | |
cpu_ent_hist (oldPC|HIST_PC, xr, IR, 0); | |
if (DEBUG_PRS (cpu_dev)) | |
cpu_fprint_one_inst (sim_deb, oldPC|HIST_PC, 0, xr, | |
IR, AC, MQ, SI, 0); | |
} | |
switch (op) { | |
case 01: /* TXI */ | |
put_xr (tag, xr + dec); /* xr += decr */ | |
PCQ_ENTRY; | |
if (mode_ttrap) { /* trap? */ | |
WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ | |
TrapXfr (TRAP_TRA_PC); /* trap */ | |
} | |
else PC = addr; /* branch */ | |
break; | |
case 02: /* TIX */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (xr > dec) { /* if xr > decr */ | |
put_xr (tag, xr - dec); /* xr -= decr */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = addr; /* branch */ | |
} | |
break; | |
case 03: /* TXH */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (xr > dec) { /* if xr > decr */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = addr; /* branch */ | |
} | |
break; | |
case 05: /* STR */ | |
WriteTA (TRAP_STD_SAV, PC); /* save inst+1 */ | |
PCQ_ENTRY; | |
PC = TRAP_STR_PC; /* branch to 2 */ | |
break; | |
case 06: /* TNX */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (xr > dec) /* if xr > decr */ | |
put_xr (tag, xr - dec); | |
else { /* xr -= decr */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = addr; /* branch */ | |
} | |
break; | |
case 07: /* TXL */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (xr <= dec) { /* if xr <= decr */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = addr; /* branch */ | |
} | |
break; | |
} | |
} /* end if */ | |
/* Normal format instructions */ | |
else { | |
op = GET_OPC (IR); /* get opcode */ | |
fl = op_flags[op]; /* get flags */ | |
if (fl & I_MODEL & ~cpu_model) { /* invalid for model? */ | |
if (stop_illop) /* possible stop */ | |
reason = STOP_ILLEG; | |
continue; | |
} | |
if (tag && (fl & I_X)) /* tag and indexable? */ | |
ea = (addr - get_xri (tag)) & EAMASK; /* do indexing */ | |
else ea = addr; | |
if (TST_IND (IR) && (fl & I_N)) { /* indirect? */ | |
if (!ReadI (ea, &SR)) /* get ind; trap? */ | |
continue; | |
addr = (uint32) SR & EAMASK; /* get address */ | |
tagi = GET_TAG (SR); /* get tag */ | |
if (tagi) /* tag? */ | |
ea = (addr - get_xri (tagi)) & EAMASK; /* do indexing */ | |
else ea = addr; | |
} | |
if ((fl & I_R) && !Read (ea, &SR)) /* read opnd; trap? */ | |
continue; | |
else if (fl & I_D) { /* double prec? */ | |
if ((ea & 1) && fp_trap (TRAP_F_ODD)) | |
continue; | |
if (!Read (ea, &SR)) /* SR gets high */ | |
continue; | |
if (!Read (ea | 1, &sr1)) /* "sr1" gets low */ | |
continue; | |
} | |
if (tracing) { /* tracing or history? */ | |
if (hst_lnt) /* history enabled? */ | |
cpu_ent_hist (oldPC|HIST_PC, ea, IR, SR); | |
if (DEBUG_PRS (cpu_dev)) | |
cpu_fprint_one_inst (sim_deb, oldPC|HIST_PC, 0, ea, | |
IR, AC, MQ, SI, SR); | |
} | |
switch (op) { /* case on opcode */ | |
/* Positive instructions */ | |
case 00000: /* HTR */ | |
case 01000: /* also -HTR */ | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ht_pend = 1; /* transfer pending */ | |
ht_addr = ea; /* save address */ | |
reason = STOP_HALT; /* halt if I/O done */ | |
break; | |
case 00020: /* TRA */ | |
case 01020: /* also -TRA */ | |
PCQ_ENTRY; | |
if (mode_ttrap) { /* trap? */ | |
WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ | |
TrapXfr (TRAP_TRA_PC); /* trap */ | |
} | |
else PC = ea; /* branch */ | |
break; | |
case 00021: /* TTR */ | |
PCQ_ENTRY; | |
PC = ea; /* branch, no trap */ | |
break; | |
case 00040: /* TLQ */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
s1 = (AC & AC_S)? 1: 0; /* get AC, MQ sign, */ | |
s2 = (MQ & SIGN)? 1: 0; /* magnitude */ | |
t1 = AC & AC_MMASK; | |
t2 = MQ & MMASK; /* signs differ? */ | |
if ((s1 != s2)? s2: /* y, br if MQ- */ | |
((t1 != t2) && (s2 ^ (t1 > t2)))) { /* n, br if sgn-^AC>MQ */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 00041: /* IIA */ | |
SI = SI ^ (AC & DMASK); | |
break; | |
case 00042: /* TIO */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if ((SI & AC) == (AC & DMASK)) { /* if ind on */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 00043: /* OAI */ | |
SI = SI | (AC & DMASK); | |
break; | |
case 00044: /* PAI */ | |
SI = AC & DMASK; | |
break; | |
case 00046: /* TIF */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if ((SI & AC) == 0) { /* if ind off */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 00051: /* IIR */ | |
SI = SI ^ (IR & RMASK); | |
break; | |
case 00054: /* RFT */ | |
t = IR & RMASK; | |
if ((SI & t) == 0) /* if ind off, skip */ | |
PC = (PC + 1) & EAMASK; | |
break; | |
case 00055: /* SIR */ | |
SI = SI | (IR & RMASK); | |
break; | |
case 00056: /* RNT */ | |
t = IR & RMASK; | |
if ((SI & t) == t) /* if ind on, skip */ | |
PC = (PC + 1) & EAMASK; | |
break; | |
case 00057: /* RIR */ | |
SI = SI & ~(IR & RMASK); | |
break; | |
case 00074: /* TSX */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (tag) /* save -inst loc */ | |
put_xr (tag, ~oldPC + 1); | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
break; | |
case 00100: /* TZE */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if ((AC & AC_MMASK) == 0) { /* if AC Q,P,1-35 = 0 */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 00101: /* (CTSS) TIA */ | |
if (prot_trap (0)) /* not user mode? */ | |
break; | |
PCQ_ENTRY; | |
PC = ea; | |
inst_base = 0; | |
break; | |
case 00114: case 00115: case 00116: case 00117: /* CVR */ | |
sc = GET_CCNT (IR); | |
SR = ea; | |
while (sc) { | |
ea = (uint32) ((AC & 077) + SR) & EAMASK; | |
if (!Read (ea, &SR)) | |
break; | |
AC = (AC & AC_S) | ((AC >> 6) & 0017777777777) | | |
(SR & 0770000000000); | |
sc--; | |
} | |
if ((sc == 0) && (IR & INST_T_CXR1)) | |
put_xr (1, (uint32) SR); | |
break; | |
case 00120: /* TPL */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if ((AC & AC_S) == 0) { /* if AC + */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 00131: /* XCA */ | |
t = MQ; | |
MQ = (AC & MMASK) | ((AC & AC_S)? SIGN: 0); | |
AC = (t & MMASK) | ((t & SIGN)? AC_S: 0); | |
break; | |
case 00140: /* TOV */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (ind_ovf) { /* if overflow */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
ind_ovf = 0; /* clear overflow */ | |
} | |
break; | |
case 00161: /* TQO */ | |
if (!mode_ftrap) { /* only in 704 mode */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (ind_mqo) { /* if MQ overflow */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
ind_mqo = 0; /* clear overflow */ | |
} | |
} | |
break; | |
case 00162: /* TQP */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if ((MQ & SIGN) == 0) { /* if MQ + */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 00200: /* MPY */ | |
op_mpy (0, SR, 043); | |
break; | |
case 00204: /* VLM */ | |
case 00205: /* for diagnostic */ | |
sc = GET_VCNT (IR); | |
op_mpy (0, SR, sc); | |
break; | |
case 00220: /* DVH */ | |
if (op_div (SR, 043)) { | |
ind_dvc = 1; | |
if (!prot_trap (0)) | |
reason = STOP_DIVCHK; | |
} | |
break; | |
case 00221: /* DVP */ | |
if (op_div (SR, 043)) | |
ind_dvc = 1; | |
break; | |
case 00224: /* VDH */ | |
case 00226: /* for diagnostic */ | |
sc = GET_VCNT (IR); | |
if (op_div (SR, sc)) { | |
ind_dvc = 1; | |
if (!prot_trap (0)) | |
reason = STOP_DIVCHK; | |
} | |
break; | |
case 00225: /* VDP */ | |
case 00227: /* for diagnostic */ | |
sc = GET_VCNT (IR); | |
if (op_div (SR, sc)) | |
ind_dvc = 1; | |
break; | |
case 00240: /* FDH */ | |
spill = op_fdv (SR); | |
if (spill == TRAP_F_DVC) { | |
ind_dvc = 1; | |
if (!prot_trap (0)) | |
reason = STOP_DIVCHK; | |
} | |
else if (spill) | |
fp_trap (spill); | |
break; | |
case 00241: /* FDP */ | |
spill = op_fdv (SR); | |
if (spill == TRAP_F_DVC) | |
ind_dvc = 1; | |
else if (spill) | |
fp_trap (spill); | |
break; | |
case 00260: /* FMP */ | |
spill = op_fmp (SR, 1); /* MQ * SR */ | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00261: /* DFMP */ | |
spill = op_dfmp (SR, sr1, 1); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00300: /* FAD */ | |
spill = op_fad (SR, 1); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00301: /* DFAD */ | |
spill = op_dfad (SR, sr1, 1); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00302: /* FSB */ | |
spill = op_fad (SR ^ SIGN, 1); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00303: /* DFSB */ | |
spill = op_dfad (SR ^ SIGN, sr1, 1); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00304: /* FAM */ | |
spill = op_fad (SR & ~SIGN, 1); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00305: /* DFAM */ | |
spill = op_dfad (SR & ~SIGN, sr1, 1); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00306: /* FSM */ | |
spill = op_fad (SR | SIGN, 1); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00307: /* DFSM */ | |
spill = op_dfad (SR | SIGN, sr1, 1); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 00320: /* ANS */ | |
SR = AC & SR; | |
Write (ea, SR); | |
break; | |
case 00322: /* ERA */ | |
AC = (AC ^ SR) & DMASK; /* AC S,Q cleared */ | |
break; | |
case 00340: /* CAS */ | |
s1 = (AC & AC_S)? 1: 0; /* get AC, MQ signs, */ | |
s2 = (SR & SIGN)? 1: 0; | |
t1 = AC & AC_MMASK; /* magnitudes */ | |
t2 = SR & MMASK; | |
if (s1 ^ s2) { /* diff signs? */ | |
if (s1) /* AC < mem? skip 2 */ | |
PC = (PC + 2) & EAMASK; | |
} | |
else if (t1 == t2) /* equal? skip 1 */ | |
PC = (PC + 1) & EAMASK; | |
else if ((t1 < t2) ^ s1) /* AC < mem, AC +, or */ | |
PC = (PC + 2) & EAMASK; /* AC > mem, AC -? */ | |
break; | |
case 00361: /* ACL */ | |
t = (AC + SR) & DMASK; /* AC P,1-35 + SR */ | |
if (t < SR) /* end around carry */ | |
t = (t + 1) & DMASK; | |
AC = (AC & (AC_S | AC_Q)) | t; /* preserve AC S,Q */ | |
break; | |
case 00400: /* ADD */ | |
op_add (SR); | |
break; | |
case 00401: /* ADM */ | |
op_add (SR & MMASK); | |
break; | |
case 00402: /* SUB */ | |
op_add (SR ^ SIGN); | |
break; | |
case 00420: /* HPR */ | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
reason = STOP_HALT; /* halt if I/O done */ | |
break; | |
case 00440: /* IIS */ | |
SI = SI ^ SR; | |
break; | |
case 00441: /* LDI */ | |
SI = SR; | |
break; | |
case 00442: /* OSI */ | |
SI = SI | SR; | |
break; | |
case 00443: /* DLD */ | |
AC = (SR & MMASK) | ((SR & SIGN)? AC_S: 0); /* normal load */ | |
if (!Read (ea | 1, &SR)) /* second load */ | |
break; | |
MQ = SR; | |
if (ea & 1) /* trap after exec */ | |
fp_trap (TRAP_F_ODD); | |
break; | |
case 00444: /* OFT */ | |
if ((SI & SR) == 0) /* skip if ind off */ | |
PC = (PC + 1) & EAMASK; | |
break; | |
case 00445: /* RIS */ | |
SI = SI & ~SR; | |
break; | |
case 00446: /* ONT */ | |
if ((SI & SR) == SR) /* skip if ind on */ | |
PC = (PC + 1) & EAMASK; | |
break; | |
case 00460: /* LDA (704) */ | |
cpy_trap (PC); | |
break; | |
case 00500: /* CLA */ | |
AC = (SR & MMASK) | ((SR & SIGN)? AC_S: 0); | |
break; | |
case 00502: /* CLS */ | |
AC = (SR & MMASK) | ((SR & SIGN)? 0: AC_S); | |
break; | |
case 00520: /* ZET */ | |
if ((SR & MMASK) == 0) /* skip if M 1-35 = 0 */ | |
PC = (PC + 1) & EAMASK; | |
break; | |
case 00522: /* XEC */ | |
if (xec_cnt++ >= xec_max) { /* xec chain limit? */ | |
reason = STOP_XEC; /* stop */ | |
break; | |
} | |
IR = SR; /* operand is new inst */ | |
chtr_inhi = 1; /* delay traps */ | |
chtr_pend = 0; /* no trap now */ | |
goto XEC; /* start over */ | |
case 00534: /* LXA */ | |
if (tag) /* M addr -> xr */ | |
put_xr (tag, (uint32) SR); | |
break; | |
case 00535: /* LAC */ | |
if (tag) /* -M addr -> xr */ | |
put_xr (tag, NEG ((uint32) SR)); | |
break; | |
case 00560: /* LDQ */ | |
MQ = SR; | |
break; | |
case 00562: /* (CTSS) LRI */ | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ind_reloc = ((uint32) SR) & VA_BLK; | |
break; | |
case 00564: /* ENB */ | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
chtr_enab = (uint32) SR; /* set enables */ | |
chtr_inht = 0; /* clear inhibit */ | |
chtr_inhi = 1; /* 1 cycle delay */ | |
chtr_pend = 0; /* no traps now */ | |
break; | |
case 00600: /* STZ */ | |
Write (ea, 0); | |
break; | |
case 00601: /* STO */ | |
SR = (AC & MMASK) | ((AC & AC_S)? SIGN: 0); | |
Write (ea, SR); | |
break; | |
case 00602: /* SLW */ | |
Write (ea, AC & DMASK); | |
break; | |
case 00604: /* STI */ | |
Write (ea, SI); | |
break; | |
case 00621: /* STA */ | |
SR = (SR & ~AMASK) | (AC & AMASK); | |
Write (ea, SR); | |
break; | |
case 00622: /* STD */ | |
SR = (SR & ~XMASK) | (AC & XMASK); | |
Write (ea, SR); | |
break; | |
case 00625: /* STT */ | |
SR = (SR & ~TMASK) | (AC & TMASK); | |
Write (ea, SR); | |
break; | |
case 00630: /* STP */ | |
SR = (SR & ~PMASK) | (AC & PMASK); | |
Write (ea, SR); | |
break; | |
case 00634: /* SXA */ | |
SR = (SR & ~AMASK) | /* xr -> M addr */ | |
((t_uint64) get_xrx (tag)); | |
Write (ea, SR); | |
break; | |
case 00636: /* SCA */ | |
SR = (SR & ~AMASK) | /* -xr -> M addr */ | |
((t_uint64) (NEG (get_xrx (tag)) & AMASK)); | |
Write (ea, SR); | |
break; | |
case 00700: /* CPY (704) */ | |
cpy_trap (PC); | |
break; | |
case 00734: /* PAX */ | |
if (tag) /* AC addr -> xr */ | |
put_xr (tag, (uint32) AC); | |
break; | |
case 00737: /* PAC */ | |
if (tag) /* -AC addr -> xr */ | |
put_xr (tag, NEG ((uint32) AC)); | |
break; | |
case 00754: /* PXA */ | |
AC = get_xrx (tag); /* xr -> AC */ | |
break; | |
case 00756: /* PCA */ | |
AC = NEG (get_xrx (tag)) & AMASK; /* -xr -> AC */ | |
break; | |
case 00760: /* PSE */ | |
reason = op_pse (ea); | |
break; | |
case 00761: /* NOP */ | |
break; | |
case 00763: /* LLS */ | |
op_lls (ea); | |
break; | |
case 00765: /* LRS */ | |
op_lrs (ea); | |
break; | |
case 00767: /* ALS */ | |
op_als (ea); | |
break; | |
case 00771: /* ARS */ | |
op_ars (ea); | |
break; | |
case 00774: /* AXT */ | |
if (tag) /* IR addr -> xr */ | |
put_xr (tag, addr); | |
break; | |
/* Negative instructions */ | |
case 01021: /* ESNT */ | |
mode_storn = 1; /* enter nullification */ | |
PCQ_ENTRY; | |
PC = ea; /* branch, no trap */ | |
break; | |
case 01042: /* RIA */ | |
SI = SI & ~AC; | |
break; | |
case 01046: /* PIA */ | |
AC = SI; | |
break; | |
case 01051: /* IIL */ | |
SI = SI ^ ((IR & RMASK) << 18); | |
break; | |
case 01054: /* LFT */ | |
t = (IR & RMASK) << 18; | |
if ((SI & t) == 0) /* if ind off, skip */ | |
PC = (PC + 1) & EAMASK; | |
break; | |
case 01055: /* SIL */ | |
SI = SI | ((IR & RMASK) << 18); | |
break; | |
case 01056: /* LNT */ | |
t = (IR & RMASK) << 18; | |
if ((SI & t) == t) /* if ind on, skip */ | |
PC = (PC + 1) & EAMASK; | |
break; | |
case 01057: /* RIL */ | |
SI = SI & ~((IR & RMASK) << 18); | |
break; | |
case 01100: /* TNZ */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if ((AC & AC_MMASK) != 0) { /* if AC != 0 */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 01101: /* (CTSS) TIB */ | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
PCQ_ENTRY; | |
PC = ea; | |
mode_user = 1; | |
inst_base = BCORE_BASE; | |
break; | |
case 01114: case 01115: case 01116: case 01117: /* CAQ */ | |
sc = GET_CCNT (IR); | |
SR = ea; | |
while (sc) { | |
ea = (uint32) ((MQ >> 30) + SR) & EAMASK; | |
if (!Read (ea, &SR)) | |
break; | |
MQ = ((MQ << 6) & DMASK) | (MQ >> 30); | |
AC = (AC & AC_S) | ((AC + SR) & AC_MMASK); | |
sc--; | |
} | |
if ((sc == 0) && (IR & INST_T_CXR1)) | |
put_xr (1, (uint32) SR); | |
break; | |
case 01120: /* TMI */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if ((AC & AC_S) != 0) { /* if AC - */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 01130: /* XCL */ | |
t = MQ; | |
MQ = AC & DMASK; | |
AC = t; | |
break; | |
case 01140: /* TNO */ | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (!ind_ovf) { /* if no overflow */ | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
ind_ovf = 0; /* clear overflow */ | |
break; | |
case 01154: case 01155: case 01156: case 01157: /* CRQ */ | |
sc = GET_CCNT (IR); | |
SR = ea; | |
while (sc) { | |
ea = (uint32) ((MQ >> 30) + SR) & EAMASK; | |
if (!Read (ea, &SR)) | |
break; | |
MQ = ((MQ << 6) & DMASK) | (SR >> 30); | |
sc--; | |
} | |
if ((sc == 0) && (IR & INST_T_CXR1)) | |
put_xr (1, (uint32) SR); | |
break; | |
case 01200: /* MPR */ | |
op_mpy (0, SR, 043); | |
if (MQ & B1) | |
AC = (AC & AC_S) | ((AC + 1) & AC_MMASK); | |
break; | |
case 01240: /* DFDH */ | |
spill = op_dfdv (SR, sr1); | |
if (spill == TRAP_F_DVC) { | |
ind_dvc = 1; | |
if (!prot_trap (0)) | |
reason = STOP_DIVCHK; | |
} | |
else if (spill) | |
fp_trap (spill); | |
break; | |
case 01241: /* DFDP */ | |
spill = op_dfdv (SR, sr1); | |
if (spill == TRAP_F_DVC) | |
ind_dvc = 1; | |
else if (spill) | |
fp_trap (spill); | |
break; | |
case 01260: /* UFM */ | |
spill = op_fmp (SR, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01261: /* DUFM */ | |
spill = op_dfmp (SR, sr1, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01300: /* UFA */ | |
spill = op_fad (SR, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01301: /* DUFA */ | |
spill = op_dfad (SR, sr1, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01302: /* UFS */ | |
spill = op_fad (SR ^ SIGN, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01303: /* DUFS */ | |
spill = op_dfad (SR ^ SIGN, sr1, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01304: /* UAM */ | |
spill = op_fad (SR & ~SIGN, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01305: /* DUAM */ | |
spill = op_dfad (SR & ~SIGN, sr1, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01306: /* USM */ | |
spill = op_fad (SR | SIGN, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01307: /* DUSM */ | |
spill = op_dfad (SR | SIGN, sr1, 0); | |
if (spill) | |
fp_trap (spill); | |
break; | |
case 01320: /* ANA */ | |
AC = AC & SR; | |
break; | |
case 01340: /* LAS */ | |
t = AC & AC_MMASK; /* AC Q,P,1-35 */ | |
if (t < SR) | |
PC = (PC + 2) & EAMASK; | |
else if (t == SR) | |
PC = (PC + 1) & EAMASK; | |
break; | |
case 01400: /* SBM */ | |
op_add (SR | SIGN); | |
break; | |
case 01500: /* CAL */ | |
AC = SR; | |
break; | |
case 01501: /* ORA */ | |
AC = AC | SR; | |
break; | |
case 01520: /* NZT */ | |
if ((SR & MMASK) != 0) | |
PC = (PC + 1) & EAMASK; | |
break; | |
case 01534: /* LXD */ | |
if (tag) /* M decr -> xr */ | |
put_xr (tag, GET_DEC (SR)); | |
break; | |
case 01535: /* LDC */ | |
if (tag) /* -M decr -> xr */ | |
put_xr (tag, NEG (GET_DEC (SR))); | |
break; | |
case 01564: /* (CTSS) LPI */ | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ind_start = ((uint32) SR) & VA_BLK; | |
ind_limit = (GET_DEC (SR) & VA_BLK) | VA_OFF; | |
break; | |
case 01600: /* STQ */ | |
Write (ea, MQ); | |
break; | |
case 01602: /* ORS */ | |
SR = SR | (AC & DMASK); | |
Write (ea, SR); | |
break; | |
case 01603: /* DST */ | |
SR = (AC & MMASK) | ((AC & AC_S)? SIGN: 0); | |
if (!Write (ea, SR)) | |
break; | |
Write ((ea + 1) & EAMASK, MQ); | |
break; | |
case 01620: /* SLQ */ | |
SR = (SR & RMASK) | (MQ & LMASK); | |
Write (ea, SR); | |
break; | |
case 01625: /* STL */ | |
SR = (SR & ~AMASK) | PC; | |
Write (ea, SR); | |
break; | |
case 01634: /* SXD */ | |
SR = (SR & ~XMASK) | /* xr -> M decr */ | |
(((t_uint64) get_xrx (tag)) << INST_V_DEC); | |
Write (ea, SR); | |
break; | |
case 01636: /* SCD */ | |
SR = (SR & ~XMASK) | /* -xr -> M decr */ | |
(((t_uint64) (NEG (get_xrx (tag)) & AMASK)) << INST_V_DEC); | |
Write (ea, SR); | |
break; | |
case 01700: /* CAD (704) */ | |
cpy_trap (PC); | |
break; | |
case 01734: /* PDX */ | |
if (tag) /* AC decr -> xr */ | |
put_xr (tag, GET_DEC (AC)); | |
break; | |
case 01737: /* PDC */ | |
if (tag) /* -AC decr -> xr */ | |
put_xr (tag, NEG (GET_DEC (AC))); | |
break; | |
case 01754: /* PXD */ | |
AC = ((t_uint64) get_xrx (tag)) << INST_V_DEC; | |
break; /* xr -> AC decr */ | |
case 01756: /* PCD */ | |
AC = ((t_uint64) (NEG (get_xrx (tag)) & AMASK)) << INST_V_DEC; | |
break; /* -xr -> AC decr */ | |
case 01760: /* MSE */ | |
reason = op_mse (ea); | |
break; | |
case 01761: /* (CTSS) ext core */ | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
if (ea == 041) /* SEA? */ | |
data_base = 0; | |
else if (ea == 042) /* SEB? */ | |
data_base = BCORE_BASE; | |
else if (ea == 043) { /* IFT? */ | |
if (inst_base == 0) | |
PC = (PC + 1) & EAMASK; | |
} | |
else if (ea == 044) { /* EFT? */ | |
if (data_base == 0) | |
PC = (PC + 1) & EAMASK; | |
} | |
else if (stop_illop) | |
reason = STOP_ILLEG; | |
break; | |
case 01763: /* LGL */ | |
op_lgl (ea); | |
break; | |
case 01765: /* LGR */ | |
op_lgr (ea); | |
break; | |
case 01773: /* RQL */ | |
sc = (ea & SCMASK) % 36; | |
if (sc) | |
MQ = ((MQ << sc) | (MQ >> (36 - sc))) & DMASK; | |
break; | |
case 01774: /* AXC */ | |
if (tag) /* -IR addr -> xr */ | |
put_xr (tag, NEG (addr)); | |
break; | |
/* IO instructions */ | |
case 00022: case 00024: case 00026: /* TRCx */ | |
case 01022: case 01024: case 01026: | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ch = ((op & 077) - 00022) | ((op >> 9) & 01); | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (!BIT_TST (chtr_enab, CHTR_V_TRC + ch) && | |
(ch_flags[ch] & CHF_TRC)) { | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
ch_flags[ch] = ch_flags[ch] & ~CHF_TRC; | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
} | |
break; | |
case 00027: case 01027: | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ch = 6 + ((op >> 9) & 01); | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (!BIT_TST (chtr_enab, CHTR_V_TRC + ch) && | |
(ch_flags[ch] & CHF_TRC)) { | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
ch_flags[ch] = ch_flags[ch] & ~CHF_TRC; | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
} | |
break; | |
case 00030: case 00031: case 00032: case 00033: /* TEFx */ | |
case 01030: case 01031: case 01032: case 01033: | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ch = ((op & 03) << 1) | ((op >> 9) & 01); | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (!BIT_TST (chtr_enab, CHTR_V_CME + ch) && | |
(ch_flags[ch] & CHF_EOF)) { | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
ch_flags[ch] = ch_flags[ch] & ~CHF_EOF; | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
} | |
break; | |
case 00060: case 00061: case 00062: case 00063: /* TCOx */ | |
case 00064: case 00065: case 00066: case 00067: | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ch = op & 07; | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (ch_sta[ch] != CHXS_IDLE) { | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 01060: case 01061: case 01062: case 01063: /* TCNx */ | |
case 01064: case 01065: case 01066: case 01067: | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ch = op & 07; | |
if (mode_ttrap) | |
WriteTA (TRAP_STD_SAV, oldPC); | |
if (ch_sta[ch] == CHXS_IDLE) { | |
PCQ_ENTRY; | |
if (mode_ttrap) /* trap? */ | |
TrapXfr (TRAP_TRA_PC); | |
else PC = ea; /* branch */ | |
} | |
break; | |
case 00540: case 00541: case 00542: case 00543: /* RCHx */ | |
case 01540: case 01541: case 01542: case 01543: | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ch = ((op & 03) << 1) | ((op >> 9) & 01); | |
reason = ch_op_start (ch, ea, TRUE); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
case 00544: case 00545: case 00546: case 00547: /* LCHx */ | |
case 01544: case 01545: case 01546: case 01547: | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ch = ((op & 03) << 1) | ((op >> 9) & 01); | |
reason = ch_op_start (ch, ea, FALSE); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
case 00640: case 00641: case 00642: case 00643: /* SCHx */ | |
case 01640: case 01641: case 01642: case 01643: | |
if (prot_trap (0)) /* user mode? */ | |
break; | |
ch = ((op & 03) << 1) | ((op >> 9) & 01); | |
if ((reason = ch_op_store (ch, &SR)) == SCPE_OK) | |
Write (ea, SR); | |
break; | |
case 00644: case 00645: case 00646: case 00647: /* SCDx */ | |
case 01644: case 01645: case 01646: case 01647: | |
ch = ((op & 03) << 1) | ((op >> 9) & 01); | |
if ((reason = ch_op_store_diag (ch, &SR)) == SCPE_OK) | |
Write (ea, SR); | |
break; | |
case 00762: /* RDS */ | |
if (prot_trap (0) || sel_trap (PC)) | |
break; | |
ch = GET_U_CH (IR); | |
reason = ch_op_ds (ch, CHSL_RDS, GET_U_UNIT (ea)); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
case 00764: /* BSR */ | |
if (prot_trap (0) || sel_trap (PC)) | |
break; | |
ch = GET_U_CH (IR); | |
reason = ch_op_nds (ch, CHSL_BSR, GET_U_UNIT (ea)); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
case 00766: /* WRS */ | |
if (prot_trap (0) || sel_trap (PC)) | |
break; | |
ch = GET_U_CH (IR); | |
reason = ch_op_ds (ch, CHSL_WRS, GET_U_UNIT (ea)); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
case 00770: /* WEF */ | |
if (prot_trap (0) || sel_trap (PC)) | |
break; | |
ch = GET_U_CH (IR); | |
reason = ch_op_nds (ch, CHSL_WEF, GET_U_UNIT (ea)); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
case 00772: /* REW */ | |
if (prot_trap (0) || sel_trap (PC)) | |
break; | |
ch = GET_U_CH (IR); | |
reason = ch_op_nds (ch, CHSL_REW, GET_U_UNIT (ea)); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
case 01764: /* BSF */ | |
if (prot_trap (0) || sel_trap (PC)) | |
break; | |
ch = GET_U_CH (IR); | |
reason = ch_op_nds (ch, CHSL_BSF, GET_U_UNIT (ea)); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
case 01772: /* RUN */ | |
if (prot_trap (0) || sel_trap (PC)) | |
break; | |
ch = GET_U_CH (IR); | |
reason = ch_op_nds (ch, CHSL_RUN, GET_U_UNIT (ea)); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
case 00776: /* SDN */ | |
if (prot_trap (0) || sel_trap (PC)) | |
break; | |
ch = GET_U_CH (IR); | |
reason = ch_op_nds (ch, CHSL_SDN, GET_U_UNIT (ea)); | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
break; | |
default: | |
if (stop_illop) | |
reason = STOP_ILLEG; | |
break; | |
} | |
} /* end else */ | |
if (reason) { /* reason code? */ | |
if (reason == ERR_STALL) { /* stall? */ | |
PC = oldPC; /* back up PC */ | |
reason = 0; | |
} | |
else if (reason == STOP_HALT) { /* halt? wait for IO */ | |
t_stat r; | |
for (i = 0; (i < HALT_IO_LIMIT) && !ch_qidle (); i++) { | |
sim_interval = 0; | |
if (r = sim_process_event ()) /* process events */ | |
return r; | |
chtr_pend = chtr_eval (NULL); /* eval chan traps */ | |
while (ch_req) { /* until no ch req */ | |
for (j = 0; j < NUM_CHAN; j++) { /* loop thru channels */ | |
if (ch_req & REQ_CH (j)) { /* channel request? */ | |
if (r = ch_proc (j)) | |
return r; | |
} | |
chtr_pend = chtr_eval (NULL); | |
} | |
} /* end while ch_req */ | |
} /* end for wait */ | |
if (chtr_pend) /* trap? cancel HALT */ | |
reason = 0; | |
} /* end if HALT */ | |
} /* end if reason */ | |
} /* end while */ | |
pcq_r->qptr = pcq_p; /* update pc q ptr */ | |
return reason; | |
} | |
/* Get index register for indexing */ | |
uint32 get_xri (uint32 tag) | |
{ | |
tag = tag & INST_M_TAG; | |
if (tag) { | |
if (mode_multi) { | |
uint32 r = 0; | |
if (tag & 1) | |
r = r | XR[1]; | |
if (tag & 2) | |
r = r | XR[2]; | |
if (tag & 4) | |
r = r | XR[4]; | |
return r & EAMASK; | |
} | |
return XR[tag] & EAMASK; | |
} | |
return 0; | |
} | |
/* Get index register for instruction execution | |
Instructions which are 'executing directly' on index registers rewrite | |
the index register value. In multi-tag mode, this causes all registers | |
involved in the OR function to receive the OR'd value. */ | |
uint32 get_xrx (uint32 tag) | |
{ | |
tag = tag & INST_M_TAG; | |
if (tag) { | |
if (mode_multi) { | |
uint32 r = 0; | |
if (tag & 1) | |
r = r | XR[1]; | |
if (tag & 2) | |
r = r | XR[2]; | |
if (tag & 4) | |
r = r | XR[4]; | |
put_xr (tag, r); | |
return r & EAMASK; | |
} | |
return XR[tag] & EAMASK; | |
} | |
return 0; | |
} | |
/* Store index register */ | |
void put_xr (uint32 tag, uint32 dat) | |
{ | |
tag = tag & INST_M_TAG; | |
dat = dat & EAMASK; | |
if (tag) { | |
if (mode_multi) { | |
if (tag & 1) | |
XR[1] = dat; | |
if (tag & 2) | |
XR[2] = dat; | |
if (tag & 4) | |
XR[4] = dat; | |
} | |
else XR[tag] = dat; | |
} | |
return; | |
} | |
/* Floating point trap */ | |
t_bool fp_trap (uint32 spill) | |
{ | |
if (mode_ftrap) { | |
WriteTAD (TRAP_STD_SAV, PC, spill); | |
PCQ_ENTRY; | |
PC = TRAP_FP_PC; | |
return TRUE; | |
} | |
else { | |
if (spill & TRAP_F_AC) | |
ind_ovf = 1; | |
if (spill & TRAP_F_MQ) | |
ind_mqo = 1; | |
} | |
return FALSE; | |
} | |
/* (CTSS) Protection trap */ | |
t_bool prot_trap (uint32 decr) | |
{ | |
if (mode_user) { | |
WriteTAD (TRAP_PROT_SAV, PC, decr); | |
PCQ_ENTRY; | |
PC = TRAP_PROT_PC; | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/* Store trap address and decrement, with A/B select flags; clear A/B, user mode */ | |
void WriteTAD (uint32 pa, uint32 addr, uint32 decr) | |
{ | |
t_uint64 mem; | |
if (inst_base) | |
decr |= TRAP_F_BINST; | |
if (data_base) | |
decr |= TRAP_F_BDATA; | |
mem = ReadP (pa) & ~(XMASK | AMASK); | |
mem |= (((t_uint64) (decr & AMASK)) << INST_V_DEC) | | |
((t_uint64) (addr & AMASK)); | |
WriteP (pa, mem); | |
mode_ctrap = 0; | |
mode_strap = 0; | |
mode_storn = 0; | |
mode_user = 0; | |
inst_base = 0; | |
data_base = 0; | |
return; | |
} | |
/* Copy trap */ | |
t_bool cpy_trap (uint32 va) | |
{ | |
if (mode_ctrap) { | |
WriteTA (TRAP_704_SAV, va); | |
PCQ_ENTRY; | |
TrapXfr (TRAP_CPY_PC); | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/* Select trap */ | |
t_bool sel_trap (uint32 va) | |
{ | |
if (mode_strap) { | |
WriteTA (TRAP_704_SAV, va); | |
PCQ_ENTRY; | |
TrapXfr (TRAP_SEL_PC); | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/* Store trap address - do not alter state yet (might be TRA) */ | |
void WriteTA (uint32 pa, uint32 dat) | |
{ | |
t_uint64 mem; | |
mem = ReadP (pa) & ~AMASK; | |
mem |= (dat & AMASK); | |
WriteP (pa, mem); | |
return; | |
} | |
/* Set trap PC - second half of address-only trap */ | |
void TrapXfr (uint32 newpc) | |
{ | |
PC = newpc; | |
mode_ctrap = 0; | |
mode_strap = 0; | |
mode_storn = 0; | |
mode_user = 0; | |
inst_base = 0; | |
data_base = 0; | |
return; | |
} | |
/* Read instruction and indirect */ | |
t_bool ReadI (uint32 va, t_uint64 *val) | |
{ | |
if (mode_user) { | |
va = (va + ind_reloc) & AMASK; | |
if ((va < ind_start) || (va > ind_limit)) { | |
prot_trap (0); | |
return FALSE; | |
} | |
} | |
*val = M[va | inst_base]; | |
return TRUE; | |
} | |
/* Read */ | |
t_bool Read (uint32 va, t_uint64 *val) | |
{ | |
if (mode_user) { | |
va = (va + ind_reloc) & AMASK; | |
if ((va < ind_start) || (va > ind_limit)) { | |
prot_trap (0); | |
return FALSE; | |
} | |
} | |
*val = M[va | data_base]; | |
return TRUE; | |
} | |
/* Write */ | |
t_bool Write (uint32 va, t_uint64 dat) | |
{ | |
if (mode_user) { | |
va = (va + ind_reloc) & AMASK; | |
if ((va < ind_start) || (va > ind_limit)) { | |
prot_trap (0); | |
return FALSE; | |
} | |
} | |
M[va | data_base] = dat; | |
return TRUE; | |
} | |
/* Reset routine */ | |
t_stat cpu_reset (DEVICE *dptr) | |
{ | |
ind_ovf = 0; | |
ind_mqo = 0; | |
ind_dvc = 0; | |
ind_ioc = 0; | |
ind_reloc = 0; | |
ind_start = 0; | |
ind_limit = 0; | |
mode_ttrap = 0; | |
mode_ctrap = 0; | |
mode_strap = 0; | |
mode_ftrap = 1; | |
mode_storn = 0; | |
if (cpu_model & (I_94|I_CT)) | |
mode_multi = 0; | |
else mode_multi = 1; | |
mode_user = 0; | |
inst_base = 0; | |
data_base = 0; | |
ch_req = 0; | |
chtr_pend = chtr_enab = 0; | |
chtr_inht = chtr_inhi = 0; | |
ht_pend = 0; | |
SLT = 0; | |
XR[0] = 0; | |
if (M == NULL) | |
M = (t_uint64 *) calloc (MAXMEMSIZE, sizeof (t_uint64)); | |
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 ((sw & (SWMASK ('A') | SWMASK ('B')))? (ea > AMASK): (ea >= MEMSIZE)) | |
return SCPE_NXM; | |
if ((sw & SWMASK ('B')) || | |
((sw & SWMASK ('V')) && mode_user && inst_base)) | |
ea = ea | BCORE_BASE; | |
*vptr = M[ea] & DMASK; | |
return SCPE_OK; | |
} | |
/* Memory deposit */ | |
t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw) | |
{ | |
if ((sw & (SWMASK ('A') | SWMASK ('B')))? (ea > AMASK): (ea >= MEMSIZE)) | |
return SCPE_NXM; | |
if (sw & SWMASK ('B')) | |
ea = ea | BCORE_BASE; | |
M[ea] = val & DMASK; | |
return SCPE_OK; | |
} | |
/* Set model */ | |
t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) | |
{ | |
UNIT *chuptr = mt_dev[CHRONO_CH].units + CHRONO_UNIT; | |
extern DEVICE clk_dev; | |
cpu_model = val; | |
if (val & I_CT) { | |
uptr->capac = MAXMEMSIZE; | |
detach_unit (uptr); | |
chuptr->flags &= ~UNIT_ATTABLE; | |
clk_dev.flags &= ~DEV_DIS; | |
} | |
else { | |
uptr->capac = STDMEMSIZE; | |
chuptr->flags |= UNIT_ATTABLE; | |
} | |
if (!(cpu_model & I_94)) | |
mode_multi = 1; | |
return SCPE_OK; | |
} | |
/* Show CTSS */ | |
t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc) | |
{ | |
if (cpu_model & I_CT) | |
fputs ("CTSS", st); | |
else if (cpu_model & I_94) | |
fputs ("7094", st); | |
else fputs ("7090", st); | |
return SCPE_OK; | |
} | |
/* Insert history entry */ | |
static uint32 inst_io_tab[32] = { | |
0, 0, 0, 0, 0, 0, 0, 0, /* 0000 - 0377 */ | |
0, 0, 0, 0x000000FF, 0, 0, 0, 0x45540000, /* 0400 - 0777 */ | |
0, 0, 0, 0, 0, 0, 0, 0, /* 1000 - 1400 */ | |
0, 0, 0, 0x000000FF, 0, 0, 0, 0 /* 1400 - 1777 */ | |
}; | |
void cpu_ent_hist (uint32 pc, uint32 ea, t_uint64 ir, t_uint64 opnd) | |
{ | |
int32 prv_p; | |
if (pc & HIST_PC) { | |
if ((pc == hst[hst_p].pc) && (ir == hst[hst_p].ir)) { /* repeat last? */ | |
hst[hst_p].rpt++; | |
return; | |
} | |
prv_p = hst_p? hst_p - 1: hst_lnt - 1; | |
if ((pc == hst[prv_p].pc) && (ir == hst[prv_p].ir)) { /* 2 line loop? */ | |
hst[prv_p].rpt++; | |
return; | |
} | |
if (hst_ch & HIST_CH_I) { /* IO only? */ | |
uint32 op = GET_OPC (ir); /* get opcode */ | |
if ((ir & INST_T_DEC) || | |
!(inst_io_tab[op / 32] & (1u << (op & 037)))) | |
return; | |
} | |
} | |
hst_p = (hst_p + 1); /* next entry */ | |
if (hst_p >= hst_lnt) | |
hst_p = 0; | |
hst[hst_p].pc = pc; | |
hst[hst_p].ir = ir; | |
hst[hst_p].ac = AC; | |
hst[hst_p].mq = MQ; | |
hst[hst_p].si = SI; | |
hst[hst_p].ea = ea; | |
hst[hst_p].opnd = opnd; | |
hst[hst_p].rpt = 0; | |
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 = hst_ch = 0; | |
hst = NULL; | |
} | |
if (lnt) { | |
hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); | |
if (hst == NULL) | |
return SCPE_MEM; | |
hst_lnt = lnt; | |
if (sim_switches & SWMASK ('I')) | |
hst_ch = HIST_CH_I|HIST_CH_C; | |
else if (sim_switches & SWMASK ('C')) | |
hst_ch = HIST_CH_C; | |
else hst_ch = 0; | |
} | |
return SCPE_OK; | |
} | |
/* Print one instruction */ | |
t_stat cpu_fprint_one_inst (FILE *st, uint32 pc, uint32 rpt, uint32 ea, | |
t_uint64 ir, t_uint64 ac, t_uint64 mq, t_uint64 si, t_uint64 opnd) | |
{ | |
int32 ch; | |
t_value sim_eval; | |
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, | |
UNIT *uptr, int32 sw); | |
sim_eval = ir; | |
if (pc & HIST_PC) { /* instruction? */ | |
fputs ("CPU ", st); | |
fprintf (st, "%05o ", pc & AMASK); | |
if (rpt == 0) | |
fprintf (st, " "); | |
else if (rpt < 1000000) | |
fprintf (st, "%6d ", rpt); | |
else fprintf (st, "%5dM ", rpt / 1000000); | |
fprint_val (st, ac, 8, 38, PV_RZRO); | |
fputc (' ', st); | |
fprint_val (st, mq, 8, 36, PV_RZRO); | |
fputc (' ', st); | |
fprint_val (st, si, 8, 36, PV_RZRO); | |
fputc (' ', st); | |
if (ir & INST_T_DEC) | |
fprintf (st, " "); | |
else fprintf (st, "%05o ", ea); | |
if (fprint_sym (st, pc & AMASK, &sim_eval, &cpu_unit, SWMASK ('M')) > 0) { | |
fputs ("(undefined) ", st); | |
fprint_val (st, ir, 8, 36, PV_RZRO); | |
} | |
else if (!(ir & INST_T_DEC) && (op_flags[GET_OPC (ir)] & I_R)) { | |
fputs (" [", st); | |
fprint_val (st, opnd, 8, 36, PV_RZRO); | |
fputc (']', st); | |
} | |
fputc ('\n', st); /* end line */ | |
} /* end if instruction */ | |
else if (ch = HIST_CH (pc)) { /* channel? */ | |
fprintf (st, "CH%c ", 'A' + ch - 1); | |
fprintf (st, "%05o ", pc & AMASK); | |
fputs (" ", st); | |
fprintf (st, "%05o ", ea & AMASK); | |
if (fprint_sym (st, pc & AMASK, &sim_eval, &cpu_unit, | |
(ch_dev[ch - 1].flags & DEV_7909)? SWMASK ('N'): SWMASK ('I')) > 0) { | |
fputs ("(undefined) ", st); | |
fprint_val (st, ir, 8, 36, PV_RZRO); | |
} | |
fputc ('\n', st); /* end line */ | |
} /* end else channel */ | |
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; | |
InstHistory *h; | |
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 repeat AC MQ SI EA IR\n\n"); | |
for (k = 0; k < lnt; k++) { /* print specified */ | |
h = &hst[(++di) % hst_lnt]; /* entry pointer */ | |
cpu_fprint_one_inst (st, h->pc, h->rpt, h->ea, h->ir, h->ac, h->mq, h->si, h->opnd); | |
} /* end for */ | |
return SCPE_OK; | |
} |