blob: e47547a4469db042a9ec30db9a9718e678ecabaa [file] [log] [blame] [raw]
/* i7090_cpu.c: IBM 7090 CPU simulator
Copyright (c) 2005-2016, Richard Cornwell
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
RICHARD CORNWELL 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.
cpu 7094 central processor
rtc real time clock
The IBM 7090 was first introduced as the IBM 704. This led to the 709,
7090, 7094, 7040 and 7044. All where 36 bit signed magnitude machines.
They were single address machines and had 3 or more index registers.
These were the first machines to include indexing. Also first machines
to impliment indirect addressing, built in floating point, first Fortran
compiler, first TimeShareing Sytem CTSS.
IBM 704: Announced May 7, 1954 withdrawn April 7, 1960.
First floating point.
First index addressing.
Memory to 32k words.
IBM 709: Announced January 2, 1957 withdrawn April 7, 1960.
First indirect addressing.
First I/O channel.
Added indicator register.
IBM 7090: Announced Decemeber 30, 1958 withdrawn July 14, 1969.
Transister version of 709.
IBM 7094 & IBM 7094/II: Announced January 15, 1962 withdrawn July 14, 1969.
Added double precision floating point.
Added up to 7 index registers.
IBM 7040 Announced April 1961.
Transisterize 704, with channel.
Character operate instructions.
Currently not implmented in simulator.
IBM 7044 Announced 1961
Enhanced verion of 7040.
Currently not implmented in simulator.
The system state for the IBM 7090 is:
AC<S,P,Q,1:35> AC register
MQ<S,1:35> MQ register
XR<0:15>[8] XR index registers register
IC<0:15> program counter
SSW<0:5> sense switches
SLT<0:3> sense lights
ID<S:36> indicators lights
ACOVF AC overflow
MQOVF MQ overflow
DVC divide check
IOC I/O check
TM transfer trap mode
CTM copy trap mode (for 709 compatibility)
FTM floating trap mode (off is 704 compatibility)
STM select trap mode
NMODE storage nullifcation mode
MTM multi-tag mode (7090 compatibility)
CTSS required a set of special features: memory extension (to 65K),
protection, and relocation. Additional state:
INST_BASE instruction memory select (A vs B core)
DATA_BASE data memory select (A vs B core)
BASE<0:6> start address block
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:
iotraps[0..7] flags for channels A..H
ioflags channel trap enables
itrap channel trap inhibit due to trap (cleared by RCT)
ihold channel trap inhibit due to XEC, ENAB, RCT, RDS,
or WDS (cleared after one instruction)
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_chan.c add channel subsystem
i7094_sys.c add sim_devices table entry
*/
#include "i7090_defs.h"
#include "sim_timer.h"
#include <math.h>
#include <time.h>
#ifdef CPANEL
#include "cpanel.h"
#endif
#define UNIT_V_MSIZE (UNIT_V_UF + 0)
#define UNIT_MSIZE (7 << UNIT_V_MSIZE)
#define UNIT_V_CPUMODEL (UNIT_V_UF + 4)
#define UNIT_MODEL (0x3 << UNIT_V_CPUMODEL)
#define CPU_MODEL ((cpu_unit.flags >> UNIT_V_CPUMODEL) & 0x3)
#define MODEL(x) (x << UNIT_V_CPUMODEL)
#define MEMAMOUNT(x) (x << UNIT_V_MSIZE)
#define UNIT_DUALCORE (1 << (UNIT_V_CPUMODEL + 2))
#define UNIT_FASTIO (1 << (UNIT_V_CPUMODEL + 3))
#define OPTION_EFP (1 << (UNIT_V_CPUMODEL + 4))
#define OPTION_TIMER (1 << (UNIT_V_CPUMODEL + 5))
#define OPTION_FPSM (1 << (UNIT_V_UF_31))
#define CPU_704 0
#define CPU_709 1
#define CPU_7090 2
#define CPU_7094 3
#define TMR_RTC 0
#define HIST_XCT 1 /* instruction */
#define HIST_INT 2 /* interrupt cycle */
#define HIST_TRP 3 /* trap cycle */
#define HIST_MIN 64
#define HIST_MAX 1000000
#define HIST_NOEA 0x40000000
#define HIST_PC 0x10000
struct InstHistory
{
t_int64 ac;
t_int64 mq;
t_int64 op;
t_int64 sr;
uint32 ic;
uint16 ea;
uint16 xr1;
uint16 xr2;
uint16 xr4;
};
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_size(UNIT * uptr, int32 val, CONST char *cptr,
void *desc);
t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val,
CONST void *desc);
t_stat cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr,
void *desc);
uint32 cpu_cmd(UNIT * uptr, uint16 cmd, uint16 dev);
t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr);
const char *cpu_description (DEVICE *dptr);
/* Interval timer option */
t_stat rtc_srv(UNIT * uptr);
t_stat rtc_reset(DEVICE * dptr);
int32 rtc_tps = 60;
t_uint64 M[MAXMEMSIZE] = { 0 }; /* memory */
t_uint64 AC, MQ; /* registers */
uint16 XR[8]; /* Index registers */
uint16 IC; /* program counter */
uint16 IR; /* Instruction register */
uint16 MA; /* Memory Address resister */
t_uint64 ID; /* Indicator registers */
t_uint64 SR; /* Internal temp register */
t_uint64 KEYS; /* Console Keys */
uint8 SL; /* Sense lights */
uint16 SW = 0; /* Sense switch */
uint8 MTM; /* Multi Index mode */
uint8 TM; /* Trap mode */
uint8 STM; /* Special trap mode */
uint8 CTM; /* Copy trap mode */
uint8 FTM; /* Floating trap mode */
uint8 nmode; /* Storage null mode */
uint8 smode; /* Signifigance mode */
uint8 itrap; /* Can take io traps */
uint8 dcheck; /* Divide check */
uint8 acoflag; /* AC Overflow */
uint8 mqoflag; /* MQ Overflow */
uint8 ihold = 0; /* Hold interrupts */
uint8 interval_irq = 0; /* Interval timer IRQ */
uint16 iotraps; /* IO trap flags */
t_uint64 ioflags = 0; /* Trap enable flags */
uint8 iocheck;
uint8 prot_pend; /* Protection mode pending */
uint8 relo_mode; /* Relocation mode */
uint8 relo_pend; /* Relocation mode pending */
uint8 hltinst; /* Executed halt instruction */
uint8 iowait; /* Waiting on io */
uint16 relocaddr = 0; /* Relocation. */
uint16 baseaddr = 0; /* Base Address. */
uint16 limitaddr = 077777; /* High limit */
uint16 memmask = 077777; /* Mask for memory access */
uint8 bcore; /* Access to B core memory */
/* 00 - Execute A Core, Eff A */
/* 01 - Execute A core, Eff B */
/* 10 - Execute B core, Eff A */
/* 11 - Execute B core, Eff B */
/* 1xx - Protection mode */
/* 1xxx - Relocation mode */
uint8 dualcore; /* Set to true if dual core in
use */
uint16 dev_pulse[NUM_CHAN]; /* SPRA device pulses */
int cycle_time = 12; /* Cycle time in 100ns */
uint8 exe_KEYS = 0; /* Execute one instruction
from KEYS, used by CPANEL */
/* History information */
int32 hst_p = 0; /* History pointer */
int32 hst_lnt = 0; /* History length */
struct InstHistory *hst = NULL; /* History stack */
extern uint32 drum_addr;
#define DP_FLOAT 1
#define CHANNEL 2
#define MULTIIX 4
#define TIMER 7
#define INDICATORS 16
#define PROTECT 32
#define DUALCORE 64
/* CPU data structures
cpu_dev CPU device descriptor
cpu_unit CPU unit descriptor
cpu_reg CPU register list
cpu_mod CPU modifiers list
*/
UNIT cpu_unit =
#ifdef I7090
{ UDATA(rtc_srv, UNIT_BINK | MODEL(CPU_7090) | MEMAMOUNT(4),
MAXMEMSIZE/2 ), 120 };
#else
{ UDATA(rtc_srv, UNIT_BINK | MODEL(CPU_704) | MEMAMOUNT(4),
MAXMEMSIZE/2 ), 120 };
#endif
REG cpu_reg[] = {
{ORDATAD(IC, IC, 15, "Instruction Counter"), REG_FIT},
{ORDATAD(IR, IR, 10, "Instruction Register"), REG_FIT},
{ORDATAD(AC, AC, 38, "Accumulator"), REG_FIT},
{ORDATAD(MQ, MQ, 36, "Multiplier Quotent"), REG_FIT},
{BRDATAD(XR, XR, 8, 15, 8, "Index registers"), REG_FIT},
{ORDATAD(ID, ID, 36, "Indicator Register")},
{ORDATAD(MA, MA, 15, "Memory Address Register"), REG_FIT},
#ifdef EXTRA_SL
{ORDATAD(SL, SL, 8, "Sense Lights"), REG_FIT},
#else
{ORDATAD(SL, SL, 4, "Sense Lights"), REG_FIT},
#endif
#ifdef EXTRA_SW
{ORDATAD(SW, SW, 12, "Sense Switches"), REG_FIT},
#else
{ORDATAD(SW, SW, 6, "Sense Switches"), REG_FIT},
#endif
{FLDATA(SW1, SW, 0), REG_FIT},
{FLDATA(SW2, SW, 1), REG_FIT},
{FLDATA(SW3, SW, 2), REG_FIT},
{FLDATA(SW4, SW, 3), REG_FIT},
{FLDATA(SW5, SW, 4), REG_FIT},
{FLDATA(SW6, SW, 5), REG_FIT},
#ifdef EXTRA_SW
{FLDATA(SW7, SW, 6), REG_FIT},
{FLDATA(SW8, SW, 7), REG_FIT},
{FLDATA(SW9, SW, 8), REG_FIT},
{FLDATA(SW10, SW, 9), REG_FIT},
{FLDATA(SW11, SW, 10), REG_FIT},
{FLDATA(SW12, SW, 11), REG_FIT},
#endif
{ORDATAD(KEYS, KEYS, 36, "Console Key Register"), REG_FIT},
{ORDATAD(MTM, MTM, 1, "Multi Index registers"), REG_FIT},
{ORDATAD(TM, TM, 1, "Trap mode"), REG_FIT},
{ORDATAD(STM, STM, 1, "Select trap mode"), REG_FIT},
{ORDATAD(CTM, CTM, 1, "Copy Trap Mode"), REG_FIT},
{ORDATAD(FTM, FTM, 1, "Floating trap mode"), REG_FIT},
{ORDATAD(NMODE, nmode, 1, "Storage null mode"), REG_FIT},
{ORDATAD(ACOVF, acoflag, 1, "AC Overflow Flag"), REG_FIT},
{ORDATAD(MQOVF, mqoflag, 1, "MQ Overflow Flag"), REG_FIT},
{ORDATAD(IOC, iocheck, 1, "I/O Check flag"), REG_FIT},
{ORDATAD(DVC, dcheck, 1, "Divide Check flag"), REG_FIT},
{ORDATAD(RELOC, relocaddr, 14, "Relocation offset"), REG_FIT},
{ORDATAD(BASE, baseaddr, 14, "Relocation base"), REG_FIT},
{ORDATAD(LIMIT, limitaddr, 14, "Relocation limit"), REG_FIT},
{ORDATAD(ENB, ioflags, 36, "I/O Trap Flags"), REG_FIT},
{FLDATA(INST_BASE, bcore, 0), REG_FIT},
{FLDATA(DATA_BASE, bcore, 1), REG_FIT},
{NULL}
};
MTAB cpu_mod[] = {
{UNIT_MODEL, MODEL(CPU_704), "704", "704", NULL, NULL, NULL},
#ifdef I7090
{UNIT_MODEL, MODEL(CPU_709), "709", "709", NULL, NULL, NULL},
{UNIT_MODEL, MODEL(CPU_7090), "7090", "7090", NULL, NULL, NULL},
{UNIT_MODEL, MODEL(CPU_7094), "7094", "7094", NULL, NULL, NULL},
#endif
{UNIT_MSIZE, MEMAMOUNT(0), "4K", "4K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(1), "8K", "8K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(2), "16K", "16K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(4), "32K", "32K", &cpu_set_size},
#ifdef I7090
{UNIT_FASTIO, 0, NULL, "TRUEIO", NULL, NULL, NULL,
"True I/O mode"},
{UNIT_FASTIO, UNIT_FASTIO, "FASTIO", "FASTIO", NULL, NULL, NULL,
"Fast I/O mode"},
{OPTION_EFP, 0, NULL, "NOEFP", NULL, NULL, NULL},
{OPTION_EFP, OPTION_EFP, "EFP", "EFP", NULL, NULL, NULL, "Extended FP"},
{OPTION_FPSM, 0, NULL, "NOFPSM", NULL, NULL, NULL},
{OPTION_FPSM, OPTION_FPSM, "FPSM", "FPSM", NULL, NULL, NULL, "Signfigance mode"},
{OPTION_TIMER, 0, NULL, "NOCLOCK", NULL, NULL, NULL},
{OPTION_TIMER, OPTION_TIMER, "CLOCK", "CLOCK", NULL, NULL, NULL},
{UNIT_DUALCORE, 0, NULL, "STANDARD", NULL, NULL, NULL},
{UNIT_DUALCORE, UNIT_DUALCORE, "CTSS", "CTSS", NULL, NULL, NULL, "CTSS support"},
#endif
{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, 16, 1, 8, 36,
&cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
NULL, DEV_DEBUG, 0, dev_debug,
NULL, NULL, &cpu_help, NULL, NULL, &cpu_description
};
#define T_B 0x0001 /* Do load with indirection */
#define T_D 0x0002 /* Do ea, but no indirection */
#define T_F 0x0004 /* Ea = Y, no indirection */
#define T_T 0x0008 /* Do ea with indirection, no load */
#define S_B 0x0010 /* Do ea, but store at end */
#define S_F 0x0020 /* Ea = Y, no indirection, store */
#define S_X 0x0040 /* Store index registers with SR */
#define T_N 0x0100 /* Nop op addressing, but instruct */
#define I_9 0x0200 /* 709 and up */
#define I_94 0x0400 /* 7094 only */
#define I_D 0x0800 /* Need dual core */
#define X_T 0x1000 /* Trap if in io trap mode or protection */
#define X_P 0x2000 /* Trap if in protection enabled */
#define X_C 0x4000 /* Trap if in copy trap mode or protection */
#define N 0x0000 /* No instruction */
/*
Opcode flags, and execution.
T_B T_D T_T T_F S_B S_X S_F
* * * * SR <- MA <- Y - xr
* * * SR <- MA <- [MA] if ind
* * * SR <- [MA]
* * [MA] <- SR
* xr <- SR
*/
/* Positive opcodes */
uint16 pos_opcode_flags[01000] = {
/* 0 1 2 3 4 5 6 7 */
/*HTR*/
/* 0000 */ T_T, N, N, N, N, N, N, N,
/* 0010 */ N, N, N, N, N, N, N, N,
/*TRA TTR TRCA TRCC TRCE TRCG */
/* 0020 */ T_T, T_T, X_T|T_T,N, X_T|T_T,N, X_T|T_T,X_T|T_T,
/* TEFA TEFC TEFE TEFG */
/* 0030 */ X_T|T_T, X_T|T_T,X_T|T_T,X_T|T_T, N, N, N, N,
/* TLQ IIA TIO OAI PAI TIF */
/* 0040 */ T_T, I_9, I_9|T_T,I_9, I_9, N, I_9|T_T, N,
/* IIR RFT SIR RNT RIR */
/* 0050 */ N, I_9, N, N, I_9, I_9, I_9, I_9,
/* TCOA TCOB TCOC TCOD TCOE TCOF TCOG TCOH */
/* 0060 */ X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,
/* TSX */
/* 0070 */ N, N, N, N, S_X, N, N, N,
/* TZE TIA */
/* 0100 */ T_T, I_D|X_P|T_T,N, N, N, N, N, N,
/* CVR CVR+100*/
/* 0110 */ N, N, N, N, I_9, I_9, I_9, I_9,
/* TPL */
/* 0120 */ T_T, N, N, N, N, N, N, N,
/* XCA */
/* 0130 */ N, I_9|T_N, N, N, N, N, N, N,
/* TOV */
/* 0140 */ T_T, N, N, N, N, N, N, N,
/* 0150 */ N, N, N, N, N, N, N, N,
/* TQO TQP */
/* 0160 */ N, T_T, T_T, N, N, N, N, N,
/* 0170 */ N, N, N, N, N, N, N, N,
/* MPY VLM VLM + 100 */
/* 0200 */ T_B, N, N, N, I_9|T_B, I_9|T_B,N, N,
/* 0210 */ N, N, N, N, N, N, N, N,
/* DVH DVP VDH VDP VDH+200 VDP+200 */
/* 0220 */ T_B, T_B, N, N, I_9|T_B,I_9|T_B,I_9|T_B,I_9|T_B,
/* 0230 */ N, N, N, N, N, N, N, N,
/* FDH FDP*/
/* 0240 */ T_B, T_B, N, N, N, N, N, N,
/* 0250 */ N, N, N, N, N, N, N, N,
/* FMP DFMP */
/* 0260 */ T_B, I_94|T_B,N, N, N, N, N, N,
/* 0270 */ N, N, N, N, N, N, N, N,
/* FAD DFAD FSB DFSB FAM DFAM FSM DFSM */
/* 0300 */ T_B, I_94|T_B, T_B, I_94|T_B, I_9|T_B,I_94|T_B,I_9|T_B,I_94|T_B,
/* 0310 */ N, N, N, N, N, N, N, N,
/* ANS ERA */
/* 0320 */ T_B|S_B,N, I_9|T_B, N, N, N, N, N,
/* 0330 */ N, N, N, N, N, N, N, N,
/* CAS */
/* 0340 */ T_B, N, N, N, N, N, N, N,
/* 0350 */ N, N, N, N, N, N, N, N,
/* ACL */
/* 0360 */ N, T_B, N, N, N, N, N, N,
/* 0370 */ N, N, N, N, N, N, N, N,
/* ADD ADM SUB */
/* 0400 */ T_B, T_B, T_B, N, N, N, N, N,
/* 0410 */ N, N, N, N, N, N, N, N,
/* HPR */
/* 0420 */ T_N, N, N, N, N, N, N, N,
/* 0430 */ N, N, N, N, N, N, N, N,
/* IIS LDI OSI DLD OFT RIS ONT */
/* 0440 */I_9|T_B,I_9|T_B,I_9|T_B,I_94|T_B,I_9|T_B,I_9|T_B,I_9|T_B, N,
/* 0450 */ N, N, N, N, N, N, N, N,
/* LDA */
/* 0460 */X_C|T_B,N, N, N, N, N, N, N,
/* 0470 */ N, N, N, N, N, N, N, N,
/* CLA CLS */
/* 0500 */ T_B, N, T_B, N, N, N, N, N,
/* 0510 */ N, N, N, N, N, N, N, N,
/* ZET XEC */
/* 0520 */ T_B, N, I_9|T_B, N, N, N, N, N,
/* LXA LAC */
/* 0530 */ N, N, N, N, S_X|T_F,T_F|S_X,N, N,
/* RSCA RSCC RSCE RSCG STCA STCC STCE STCG */
/* 0540 */ X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,
/* 0550 */ N, N, N, N, N, N, N, N,
/* LDQ ECA LRI ENB */
/* 0560 */ T_B, T_B|S_B,I_D|X_P|T_B,N, I_9|T_B,N, N, N,
/* 0570 */ N, N, N, N, N, N, N, N,
/* STZ STO SLW STI*/
/* 0600 */ S_B, S_B, S_B, N, I_9|S_B,N, N, N,
/* 0610 */ N, N, N, N, N, N, N, N,
/* STA STD STT */
/* 0620 */ N, T_B|S_B, T_B|S_B,N, N, T_B|S_B,N, N,
/* STP SXA SCA */
/* 0630 */ T_B|S_B,N, N, N, I_9|S_F, N, I_9|S_F,N,
/* SCHA SCHC SCHE SCHG SCDA SCDC SCDE SCDG */
/* 0640 */ T_T, T_T, T_T, T_T, X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,
/* 0650 */ N, N, N, N, N, N, N, N,
/* 0660 */ N, N, N, N, N, N, N, N,
/* ELD EAD EDP EMP */
/* 0670 */ T_B, T_B, T_B, T_B, N, N, N, N,
/* CPY */
/* 0700 */ X_C|T_B,N, N, N, N, N, N, N,
/* 0710 */ N, N, N, N, N, N, N, N,
/* 0720 */ N, N, N, N, N, N, N, N,
/* PAX PAC */
/* 0730 */ N, N, N, N, S_X, N, N, S_X|I_9,
/* 0740 */ N, N, N, N, N, N, N, N,
/* PXA PCA */
/* 0750 */ N, N, N, N, T_N, N, T_N, N,
/* PSE NOP RDS LLS BSR LRS WRS ALS */
/* 0760 */ T_D, T_N, X_T|T_D, T_D, X_T|T_D, T_D, X_T|T_D, T_D,
/* WEF ARS REW AXT DRS SDN */
/* 0770 */ X_T|T_D,T_D, X_T|T_D, N, S_X, X_T|T_D,X_T|T_D, N
};
/* Negative opcodes */
uint16 neg_opcode_flags[01000] = {
/* 4000 */ N, N, N, N, N, N, N, N,
/* 4010 */ N, N, N, N, N, N, N, N,
/* ESNT TRCB TRCD TRCF TRCH */
/* 4020 */ N, I_9|T_T,X_T|T_T,N, X_T|T_T,N, X_T|T_T,X_T|T_T,
/* TEFB TEFD TEFF TEFH */
/* 4030 */ X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,N, N, N, N,
/* RIA PIA */
/* 4040 */ N, N, I_9, N, N, N, I_9, N,
/* IIL LFT SIL LNT RIL */
/* 4050 */ N, I_9, N, N, I_9, I_9, I_9, I_9,
/* TCNA TCNB TCNC TNCD TNCE TNCF TNCG TNCH */
/* 4060 */X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,
/* 4070 */ N, N, N, N, N, N, N, N,
/* TNZ TIB */
/* 4100 */ T_T,I_D|X_P|T_T, N, N, N, N, N, N,
/* CAQ CAQ +100 */
/* 4110 */ N, N, N, N, I_9, I_9, I_9, I_9,
/* TMI */
/* 4120 */ T_T, N, N, N, N, N, N, N,
/* XCL */
/* 4130 */I_9|T_N, N, N, N, N, N, N, N,
/* TNO */
/* 4140 */ T_T, N, N, N, N, N, N, N,
/* CRQ CRQ+100 */
/* 4150 */ N, N, N, N, I_9, I_9, I_9, I_9,
/* 4160 */ N, N, N, N, N, N, N, N,
/* 4170 */ N, N, N, N, N, N, N, N,
/* MPR */
/* 4200 */ T_B, N, N, N, N, N, N, N,
/* 4210 */ N, N, N, N, N, N, N, N,
/* 4220 */ N, N, N, N, N, N, N, N,
/* 4230 */ N, N, N, N, N, N, N, N,
/* DFDH DFDP */
/* 4240 */ I_94|T_B, I_94|T_B,N,N, N, N, N, N,
/* 4250 */ N, N, N, N, N, N, N, N,
/* UFM DUFM */
/* 4260 */ T_B, I_94|T_B, N, N, N, N, N, N,
/* 4270 */ N, N, N, N, N, N, N, N,
/* UFA DUFA UFS DUFS UAM DUAM USM DUSM */
/* 4300 */ T_B, I_94|T_B, T_B, I_94|T_B, I_9|T_B, I_94|T_B, I_9|T_B, I_94|T_B,
/* 4310 */ N, N, N, N, N, N, N, N,
/* ANA */
/* 4320 */ T_B, N, N, N, N, N, N, N,
/* 4330 */ N, N, N, N, N, N, N, N,
/* LAS */
/* 4340 */ I_9|T_B,N, N, N, N, N, N, N,
/* 4350 */ N, N, N, N, N, N, N, N,
/* 4360 */ N, N, N, N, N, N, N, N,
/* 4370 */ N, N, N, N, N, N, N, N,
/* SBM */
/* 4400 */ T_B, N, N, N, N, N, N, N,
/* 4410 */ N, N, N, N, N, N, N, N,
/* 4420 */ N, N, N, N, N, N, N, N,
/* 4430 */ N, N, N, N, N, N, N, N,
/* 4440 */ N, N, N, N, N, N, N, N,
/* 4450 */ N, N, N, N, N, N, N, N,
/* 4460 */ N, N, N, N, N, N, N, N,
/* 4470 */ N, N, N, N, N, N, N, N,
/* CAL ORA */
/* 4500 */ T_B, T_B, N, N, N, N, N, N,
/* 4510 */ N, N, N, N, N, N, N, N,
/* NZT */
/* 4520 */ I_9|T_B, N, N, N, N, N, N, N,
/* LXD LDC */
/* 4530 */ N, N, N, N, T_F|S_X,I_9|T_F|S_X, N, N,
/* RSCB RSCD RSCF RSCH STCB STCD STCF STCH */
/* 4540 */ X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,
/* 4550 */ N, N, N, N, N, N, N, N,
/* ECQ LPI */
/* 4560 */ N, S_B|T_B,N, N,I_D|X_P|T_B, N, N, N,
/* 4570 */ N, N, N, N, N, N, N, N,
/* STQ SRI ORS DST SPI*/
/* 4600 */ S_B, I_D|S_B, T_B|S_B,I_94|S_B,I_D|S_B,N,N, N,
/* 4610 */ N, N, N, N, N, N, N, N,
/* SLQ STL */
/* 4620 */ S_B|T_B,N, N, N, N, T_B|I_9|S_B,N, N,
/* SXD SCD */
/* 4630 */ N, N, N, N, S_F, N, S_F, N,
/* SCHB SCHD SCHF SCHH SCDB SCDD SCDF SCDH */
/* 4640 */ T_T, T_T, T_T, T_T,X_T|T_T,X_T|T_T,X_T|T_T,X_T|T_T,
/* 4650 */ N, N, N, N, N, N, N, N,
/* 4660 */ N, N, N, N, N, N, N, N,
/* ESB EUA EST */
/* 4670 */ N, T_B, T_B, T_B|S_B,N, N, N, N,
/* CAD */
/* 4700 */ X_C|T_B,N, N, N, N, N, N, N,
/* 4710 */ N, N, N, N, N, N, N, N,
/* 4720 */ N, N, N, N, N, N, N, N,
/* PDX PDC */
/* 4730 */ N, N, N, N, S_X, N, N, S_X,
/* 4740 */ N, N, N, N, N, N, N, N,
/* PXD PCD */
/* 4750 */ N, N, N, N, S_X, N, S_X, N,
/* MSE SPOPS LGL BSF LGR */
/* 4760 */ T_D, T_D, N, T_D, X_T|T_D, T_D, N, N,
/* RUN RQL AXC TRS */
/* 4770 */ N, N, X_T|T_D,T_D, S_X, X_T|T_D,N, N
};
#define CORE_B 0100000 /* Core B base address. */
#define do_trapmode \
if (TM) { \
sim_interval = sim_interval - 1; /* count down */ \
M[0] &= ~AMASK; \
M[0] |= (IC - 1) & memmask; \
ihold = 1; \
}
#define do_transfer(new_pc) IC = (TM)? 1 :(new_pc)
#define update_xr(t, v) \
if ((t)) { \
if (MTM) { \
if ((t)&04) XR[4] = (uint16)(v); \
if ((t)&02) XR[2] = (uint16)(v); \
if ((t)&01) XR[1] = (uint16)(v); \
} else { \
XR[(t)] = (uint16)(v); \
} \
}
#define get_xr(t) \
(((t)) ? ((MTM) ? (XR[(t)&04] | XR[(t)&02] | XR[(t)&01]) : XR[(t)]) : 0)
#define ReadMem(ind, reg) \
/* In address nulify mode, half address */ \
MA &= memmask; \
if (bcore & 10) /* Relocation enabled? adjust address */ \
MA = AMASK & (MA + relocaddr); \
if (bcore & 4) { /* Protection enabled? check address */ \
if (((MA & 077400) < baseaddr) || ((MA & 077400) >limitaddr)) { \
/* Trap to A core */ \
/* bcore to D3,4, IC=ADDR MA is going to DECR */ \
M[032] = (((t_uint64)bcore & 3) << 31) | (((t_uint64)MA) << 18) | IC;\
/* store 32, IC = 33 */ \
IC = 033; \
bcore = 0; \
prot_pend = 0; \
tbase = 0; \
goto next_exe; \
} \
} \
if ((ind) == 0 && bcore & 1) /* Data in B core */ \
MA |= CORE_B; \
if ((ind) == 1 && bcore & 2) /* Code in B core */ \
MA |= CORE_B; \
sim_interval = sim_interval - 1; /* count down */ \
reg = ReadP(MA);
#define WriteMem() \
/* In address nulify mode, half address */ \
MA &= memmask; \
if (bcore & 10) /* Relocation enabled? adjust address */ \
MA = AMASK & (MA + relocaddr); \
if (bcore & 4) { /* Protection enabled? check address */ \
if (((MA & 077400) < baseaddr) || ((MA & 077400) >limitaddr)) { \
/* Trap to A core */ \
/* bcore to D3,4, IC=ADDR MA is going to DECR */ \
M[032] = (((t_uint64)bcore & 3) << 31) | (((t_uint64)MA) << 18) | IC;\
/* store 32, IC = 33 */ \
IC = 033; \
bcore = 0; \
prot_pend = 0; \
tbase = 0; \
goto next_exe; \
} \
} \
if (bcore & 1) /* Data in B core */ \
MA |= CORE_B; \
sim_interval = sim_interval - 1; /* count down */ \
WriteP(MA, SR);
t_stat
sim_instr(void)
{
t_stat reason;
t_uint64 temp = 0LL;
#ifdef I7090
t_uint64 ibr;
#endif
uint16 opcode;
uint8 tag;
uint16 decr;
uint16 xr;
uint16 opinfo;
int fptemp, fptemp2;
uint8 f;
uint16 tbase;
int xeccnt = 15;
int shiftcnt;
int stopnext = 0;
int instr_count = 0; /* Number of instructions to execute */
if (sim_step != 0) {
instr_count = sim_step;
sim_cancel_step();
}
/* Set cycle time for delays */
switch(CPU_MODEL) {
case CPU_704: cycle_time = 50; break; /* Needed to allow SAP to work */
case CPU_709: cycle_time = 120; break; /* 83,333 cycles per second */
default:
case CPU_7090: cycle_time = 22; break; /* 454,545 cycles per second */
case CPU_7094: cycle_time = 18; break; /* 555,555 cycles per second */
}
reason = 0;
hltinst = 0;
/* Enable timer if option set */
if (cpu_unit.flags & OPTION_TIMER) {
sim_activate(&cpu_unit, 10000);
}
interval_irq = 0;
/* Main instruction fetch/decode loop */
tbase = 0;
if (bcore & 010)
tbase = relocaddr;
if (bcore & 2)
tbase |= CORE_B;
iowait = 0;
ihold = 0;
while (reason == 0) { /* loop until halted */
if (exe_KEYS) {
SR = KEYS;
hltinst = 1;
exe_KEYS = 0;
goto next_xec;
}
hltloop:
/* If doing fast I/O don't sit in idle loop */
if (iowait && (cpu_unit.flags & UNIT_FASTIO))
sim_interval = 0;
if (iowait == 0 && stopnext)
return SCPE_STEP;
if (sim_interval <= 0) { /* event queue? */
reason = sim_process_event();
if (reason != SCPE_OK) {
if (reason == SCPE_STEP && iowait)
stopnext = 1;
else
break; /* process */
}
}
#if defined(CPANEL)
if (cpanel_interval > 0) {
if (cpanel_interval > 1) {
cpanel_interval--;
} else {
reason = ControlPanel_Refresh_CPU_Running();
/* do control panel refresh and user clicks event processing */
if (reason != SCPE_OK)
break;
}
}
#endif
if (iowait == 0 && sim_brk_summ &&
sim_brk_test(((bcore & 2)? CORE_B:0)|IC, SWMASK('E'))) {
reason = STOP_IBKPT;
break;
}
/* Check if we need to take any traps */
#ifdef I7090 /* I704 did not have interrupts */
if (CPU_MODEL != CPU_704 && itrap && ihold == 0 && iowait == 0 && ioflags != 0 && instr_count == 0) {
t_uint64 mask = 00000001000001LL;
MA = 012;
f = 0;
for (shiftcnt = 1; shiftcnt < NUM_CHAN; shiftcnt++) {
/* CRC *//* Trap *//* EOF */
/* Wait until channel stops to trigger interupts */
if (ioflags & mask) {
f = 0;
if (mask & AMASK & ioflags) {
if (chan_stat(shiftcnt, CHS_EOF))
f |= 4; /* We have a EOF */
if (iotraps & (1 << shiftcnt)) {
f |= 1; /* We have a IOCT/IORT/IOST */
iotraps &= ~(1 << shiftcnt);
}
}
if (mask & DMASK & ioflags && chan_stat(shiftcnt, CHS_ERR))
f |= 2; /* We have device error */
/* check if we need to perform a trap */
if (f) {
/* HTR/HPR behave like wait if protected */
if (hltinst)
temp = (((t_uint64) bcore & 3) << 31) |
(((t_uint64) f) << 18) | (fptemp & memmask);
else
temp = (((t_uint64) bcore & 3) << 31) |
(((t_uint64) f) << 18) | (IC & memmask);
hltinst = 0;
sim_interval = sim_interval - 1; /* count down */
WriteP(MA, temp);
if (nmode) {
memmask <<= 1;
memmask |= 1;
nmode = 0;
}
MA++;
tbase = 0;
prot_pend = itrap = bcore = iowait = 0;
ihold = 1;
sim_interval = sim_interval - 1; /* count down */
SR = ReadP(MA);
sim_debug(DEBUG_TRAP, &cpu_dev,
"Doing trap chan %c %o >%012llo loc %o %012llo IC=%06o\n",
shiftcnt + 'A' - 1, f, temp, MA, SR, IC);
if (hst_lnt) { /* history enabled? */
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt)
hst_p = 0;
hst[hst_p].ic = MA | HIST_PC | (bcore << 18);
hst[hst_p].ea = 0;
hst[hst_p].op = SR;
hst[hst_p].ac = AC;
hst[hst_p].mq = MQ;
hst[hst_p].xr1 = XR[1];
hst[hst_p].xr2 = XR[2];
hst[hst_p].xr4 = XR[4];
hst[hst_p].sr = 0;
}
goto next_xec;
}
}
MA += 2;
mask <<= 1;
}
/* Interval timer has lower priority then I/O traps */
if (interval_irq && (ioflags & 0400000)) {
/* HTR/HPR behave like wait if protected */
if (hltinst)
temp = (((t_uint64) bcore & 3) << 31) |
(fptemp & memmask) | (relo_mode << 21);
else
temp = (((t_uint64) bcore & 3) << 31) |
(IC & memmask) | (relo_mode << 21);
hltinst = 0;
sim_interval = sim_interval - 1; /* count down */
MA = 6;
WriteP(MA, temp);
if (nmode) {
memmask <<= 1;
memmask |= 1;
nmode = 0;
}
MA++;
prot_pend = 0;
interval_irq = prot_pend = itrap = bcore = iowait = 0;
ihold = 1;
sim_interval = sim_interval - 1; /* count down */
SR = ReadP(MA);
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Doing timer trap >%012llo loc %o %012llo\n", temp,
MA, SR);
if (hst_lnt) { /* history enabled? */
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt)
hst_p = 0;
hst[hst_p].ic = MA | HIST_PC | (bcore << 18);
hst[hst_p].ea = 0;
hst[hst_p].op = SR;
hst[hst_p].ac = AC;
hst[hst_p].mq = MQ;
hst[hst_p].xr1 = XR[1];
hst[hst_p].xr2 = XR[2];
hst[hst_p].xr4 = XR[4];
hst[hst_p].sr = 0;
}
goto next_xec;
}
}
if (hltinst) {
t_uint64 mask = 00000001000001LL;
/* Hold out until all channels have idled out */
sim_interval = sim_interval - 1; /* count down */
chan_proc();
f = chan_active(0);
for (shiftcnt = 1; f == 0 && shiftcnt < NUM_CHAN; shiftcnt++) {
f = chan_active(shiftcnt);
/* CRC *//* Trap *//* EOF */
/* Wait until channel stops to trigger interrupts */
if (itrap) {
/* Check for EOF or IOCT/IORT/IOST */
if (mask & AMASK & ioflags &&
(chan_test(shiftcnt, CHS_EOF) || iotraps & (1 << shiftcnt)))
f = 1;
if (mask & DMASK & ioflags && chan_test(shiftcnt, CHS_ERR))
f = 1; /* We have device error */
}
}
/* If all channels idle and not in protected mode, real halt */
if (f == 0 && (bcore & 4) == 0) {
reason = STOP_HALT;
break;
}
goto hltloop;
}
#else /* Handle halt on 704 */
if (hltinst) {
sim_interval = sim_interval - 1; /* count down */
chan_proc();
if (chan_active(0))
goto hltloop;
reason = STOP_HALT;
break;
}
#endif
/* Split out current instruction */
next_exe:
if (iowait) {
/* If we are awaiting I/O complete, don't fetch. */
sim_interval--;
SR = temp;
iowait = 0;
} else {
xeccnt = 15;
MA = IC;
ReadMem(1, SR);
temp = SR;
if (hst_lnt) { /* history enabled? */
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt)
hst_p = 0;
hst[hst_p].ic = MA | HIST_PC | (bcore << 18);
hst[hst_p].ea = 0;
hst[hst_p].op = SR;
hst[hst_p].ac = AC;
hst[hst_p].mq = MQ;
hst[hst_p].xr1 = XR[1];
hst[hst_p].xr2 = XR[2];
hst[hst_p].xr4 = XR[4];
hst[hst_p].sr = 0;
}
IC = memmask & (IC + 1);
}
if (ihold != 0)
ihold--;
else if (relo_pend || prot_pend) {
bcore = (bcore & 3) | (relo_pend << 3) | (prot_pend << 2);
relo_pend = 0;
prot_pend = 0;
}
next_xec:
opcode = (uint16)(SR >> 24);
IR = opcode;
if (hst_lnt) { /* history enabled? */
hst[hst_p].op = SR;
}
MA = (uint16)(SR & AMASK);
tag = (uint8)(SR >> 15) & 07;
decr = (uint16)((SR >> 18) & AMASK);
/* Set flags to D to start with */
xr = get_xr(tag);
iowait = 0; /* Kill iowait */
sim_interval--; /* one cycle for execute */
switch (opcode & 07000) {
case (OP_TXI << 9): /* Transfer and inc XR[T] += D, IC <- Y */
do_trapmode;
decr &= memmask;
xr += decr;
xr &= memmask;
if (hst_lnt) { /* history enabled? */
hst[hst_p].ea = decr;
hst[hst_p].sr = xr;
}
/* Save register */
update_xr(tag, xr);
do_transfer(MA);
break;
case (OP_TXH << 9): /* Transfer on High Index XR[T] > D, IC <- Y */
do_trapmode;
if (hst_lnt) { /* history enabled? */
hst[hst_p].ea = decr;
hst[hst_p].sr = xr;
}
xr &= memmask;
decr &= memmask;
if (tag && xr > decr)
do_transfer(MA);
break;
case (OP_TNX << 9): /* Transfer No index XR[T] */
do_trapmode;
if (hst_lnt) { /* history enabled? */
hst[hst_p].ea = decr;
hst[hst_p].sr = xr;
}
xr &= memmask;
decr &= memmask;
if (tag && xr > decr) {
xr = AMASK & (xr - decr);
update_xr(tag, xr);
} else {
do_transfer(MA);
}
break;
case (OP_TXL << 9): /* Transfer on Low Index XR[T] <= D, IC <- Y */
do_trapmode;
if (hst_lnt) { /* history enabled? */
hst[hst_p].ea = decr;
hst[hst_p].sr = xr;
}
xr &= memmask;
decr &= memmask;
if (tag == 0 || xr <= decr)
do_transfer(MA);
break;
case (OP_TIX << 9): /* Transfer and Index XR */
do_trapmode;
if (hst_lnt) { /* history enabled? */
hst[hst_p].ea = decr;
hst[hst_p].sr = xr;
}
xr &= memmask;
decr &= memmask;
if (tag && xr > decr) {
xr = AMASK & (xr - decr);
update_xr(tag, xr);
do_transfer(MA);
}
break;
case (OP_STR << 9):
M[tbase] &= ~AMASK;
M[tbase] |= IC & memmask;
if (hst_lnt) /* history enabled? */
hst[hst_p].ea = tbase;
IC = 2;
break;
case (4 << 9): /* Neg opcodes */
opinfo = neg_opcode_flags[opcode & 0777];
goto proc_op;
case 0: /* Pos opcodes */
opinfo = pos_opcode_flags[opcode];
proc_op:
/* If proc does not support this opcode, just skip it */
if (opinfo & I_9 && CPU_MODEL == CPU_704)
break;
if (opinfo & I_94 && CPU_MODEL != CPU_7094)
break;
if (opinfo & (X_P|X_T) && (bcore & 4)) {
/* Trap to 0 and drop out of B core */
prottrap:
MA = 032;
if (nmode) {
memmask <<= 1;
memmask |= 1;
}
temp = ((t_uint64) (bcore & 3) << 31) | IC;
tbase = 0;
prot_pend = nmode = bcore = STM = CTM = 0;
WriteP(MA, temp);
IC = MA + 1;
break;
}
/* Check for traping conditions */
/* Check for protection mode */
if (opinfo & X_T && STM) {
/* Trap to 40001 */
MA = MEMSIZE >> 1;
if (nmode) {
memmask <<= 1;
memmask |= 1;
}
temp = ((t_uint64) (bcore & 3) << 31) | IC;
tbase = 0;
prot_pend = nmode = bcore = STM = CTM = 0;
WriteP(MA, temp);
IC = MA + 1;
break;
}
/* Check for protection mode */
if (opinfo & X_C && CTM) {
/* Trap to 40002 */
MA = MEMSIZE >> 1;
if (nmode) {
memmask <<= 1;
memmask |= 1;
}
temp = ((t_uint64) (bcore & 3) << 31) | IC;
tbase = 0;
prot_pend = nmode = bcore = STM = CTM = 0;
WriteP(MA, temp);
IC = MA + 2;
break;
}
/* Merge in index register if needed */
if (opinfo & (T_B | T_D | T_T | S_B))
MA = memmask & (MA - xr);
decr &= 077; /* Set flags to D to start with */
/* If indirect flag and indirect instruction do memory access */
if ((CPU_MODEL != CPU_704) && ((decr & 060) == 060) &&
(opinfo & (T_B | T_T | S_B))) {
ReadMem(1, SR);
tag = (uint8)((SR >> 15) & 07);
xr = get_xr(tag);
MA = (uint16)(memmask & (SR - xr));
}
MA &= memmask;
if (opinfo & (T_B | T_F | S_F)) {
ReadMem(opcode == OP_XEC, SR);
}
if (hst_lnt) { /* history enabled? */
hst[hst_p].ea = MA;
hst[hst_p].sr = SR;
}
switch (opcode) {
case 0760: /* PSE */
/* Positive 0760 opcodes */
switch (MA) {
#ifdef I7090 /* Not on 704 */
case OP_RDCA: /* Reset data channel */
case OP_RDCB:
case OP_RDCC:
case OP_RDCD:
case OP_RDCE:
case OP_RDCF:
case OP_RDCG:
case OP_RDCH:
if (CPU_MODEL == CPU_704)
break;
if ((bcore & 4) || STM)
goto seltrap;
f = (MA >> 9) & 017;
chan_rst(f, 1);
break;
case OP_RICA: /* Reset channel */
case OP_RICB:
case OP_RICC:
case OP_RICD:
case OP_RICE:
case OP_RICF:
case OP_RICG:
case OP_RICH:
if (CPU_MODEL == CPU_704)
break;
if ((bcore & 4) || STM)
goto seltrap;
chan_rst((MA >> 9) & 017, 0);
break;
/* Not great coding, but keeps multiple copys out of code */
#endif
seltrap:
/* Trap to 40000 or 0 depending on mode */
if (bcore & 4)
MA = 032;
else
MA = MEMSIZE >> 1;
if (nmode) {
memmask <<= 1;
memmask |= 1;
}
temp = ((t_uint64) (bcore & 3) << 31) | IC;
tbase = 0;
prot_pend = nmode = bcore = STM = CTM = 0;
WriteP(MA, temp);
IC = MA + 1;
break;
case OP_BTTA: /* Skip BOT */
case OP_BTTB: /* Skip BOT */
case OP_BTTC: /* Skip BOT */
case OP_BTTD: /* Skip BOT */
case OP_BTTE: /* Skip BOT */
case OP_BTTF: /* Skip BOT */
case OP_BTTG: /* Skip BOT */
case OP_BTTH: /* Skip BOT */
if (CPU_MODEL == CPU_704)
break;
if ((bcore & 4) || STM)
goto seltrap;
if (chan_stat((MA >> 9) & 017, CHS_BOT) == 0)
IC++;
break;
case OP_SLF:
SL = 0;
break;
case OP_SLN1:
case OP_SLN2:
case OP_SLN3:
case OP_SLN4:
#ifdef EXTRA_SL
case OP_SLN5:
case OP_SLN6:
case OP_SLN7:
case OP_SLN8:
#endif
SL |= 1 << (MA - OP_SLN1);
break;
case OP_SWT1:
case OP_SWT2:
case OP_SWT3:
case OP_SWT4:
case OP_SWT5:
case OP_SWT6:
if (SW & (1 << (MA - OP_SWT1)))
IC++;
break;
case OP_LBT:
if (AC & 1)
IC++;
break;
case OP_CLM:
AC &= AMSIGN;
break;
case OP_CHS:
AC ^= AMSIGN;
break;
case OP_SSP:
AC &= AMMASK;
break;
case OP_COM:
AC ^= AMMASK;
break;
case OP_ENK:
MQ = KEYS;
break;
case OP_IOT: /* Skip & clear ioready */
if (iocheck == 0)
IC++;
iocheck = 0;
break;
case OP_ETM:
if (bcore & 4)
goto prottrap;
TM = 1;
break;
case OP_RND:
if (MQ & ONEBIT) {
SR = 1;
goto iadd;
}
break;
case OP_FRN:
/* Extract AC char */
temp = 0;
if (MQ & FPNBIT) {
/* Save everything but characterist, +1 to fraction */
SR = (AC & (FPMMASK | AMSIGN | AQSIGN | APSIGN)) + 1;
/* If overflow, normalize */
if (SR & FPOBIT) {
SR >>= 1; /* Move right one bit */
if ((AC & (AQSIGN | APSIGN | FPCMASK)) ==
FPCMASK) {
temp = FPOVERR | FPACERR;
}
AC += FPOBIT; /* Fix characteristic */
/* Fix the sign */
AC &= AMMASK;
AC |= (SR & AQSIGN) << 1; /* Fix sign */
}
/* Restore fixed ac */
AC &= ~FPMMASK;
AC |= SR & FPMMASK;
if (temp != 0)
goto dofptrap;
}
break;
case OP_DCT:
if (dcheck == 0)
IC++;
dcheck = 0;
break;
#ifdef I7090 /* Not on 704 */
case OP_RCT:
if (CPU_MODEL != CPU_704) {
if (bcore & 4)
goto prottrap;
sim_debug(DEBUG_TRAP, &cpu_dev, "RCT %012llo\n", ioflags);
if ((bcore & 4) || STM)
goto seltrap;
itrap = 1;
if (CPU_MODEL == CPU_709)
ihold = 1;
else
ihold = 2;
}
break;
case OP_LMTM:
if (CPU_MODEL != CPU_704)
MTM = 0;
break;
#endif
default:
if ((bcore & 4) || STM)
goto seltrap;
f = MA >> 9;
if (f < 11) {
MA &= 0777;
if (MA >= 0341 && MA <= 0372) {
MA -= 0341;
if (MA < PUNCH_M) {
dev_pulse[f] |= 1 << MA;
} else {
MA -= 13;
if (MA == 2) {
if (dev_pulse[f] & PRINT_I)
IC++;
dev_pulse[f] &= ~PRINT_I;
} else {
dev_pulse[f] |= 1 << MA;
}
}
}
}
break;
}
break;
case 04760: /* MSE */
/* Negative 04760 opcodes */
switch (MA) {
case OP_ETTA: /* Transfer on EOT */
case OP_ETTB: /* Transfer on EOT */
case OP_ETTC: /* Transfer on EOT */
case OP_ETTD: /* Transfer on EOT */
case OP_ETTE: /* Transfer on EOT */
case OP_ETTF: /* Transfer on EOT */
case OP_ETTG: /* Transfer on EOT */
case OP_ETTH: /* Transfer on EOT */
if ((bcore & 4) || STM)
goto seltrap;
if (chan_stat((MA >> 9) & 017, CHS_EOT) == 0)
IC++;
break;
case OP_PBT:
if (AC & APSIGN)
IC++;
break;
case OP_EFTM:
if (CPU_MODEL != CPU_704)
FTM = 1;
break;
case OP_SSM:
AC |= AMSIGN;
break;
#ifdef I7090 /* Not on 704 */
case OP_LFTM:
if (bcore & 4)
goto prottrap;
if (CPU_MODEL != CPU_704)
acoflag = mqoflag = FTM = 0;
break;
case OP_ESTM:
if (bcore & 4)
goto prottrap;
if (CPU_MODEL != CPU_704)
STM = 1;
break;
case OP_ECTM:
if (bcore & 4)
goto prottrap;
if (CPU_MODEL != CPU_704)
CTM = 1;
break;
case OP_EMTM:
if (CPU_MODEL != CPU_704)
MTM = 1;
break;
#endif
case OP_LTM:
if (bcore & 4)
goto prottrap;
TM = 0;
break;
case OP_LSNM:
if (nmode) {
memmask <<= 1;
memmask |= 1;
}
nmode = 0;
break;
case OP_ETT:
if ((bcore & 4) || STM)
goto seltrap;
if (chan_stat(0, CHS_EOT) == 0)
IC++;
break;
case OP_RTT:
if ((bcore & 4) || STM)
goto seltrap;
/* Check ERR on channel 0 */
if (chan_stat(0, CHS_ERR) == 0)
IC++;
break;
case OP_SLT1:
case OP_SLT2:
case OP_SLT3:
case OP_SLT4:
#ifdef EXTRA_SL
case OP_SLT5:
case OP_SLT6:
case OP_SLT7:
case OP_SLT8:
#endif
f = 1 << (MA - OP_SLN1);
if (SL & f)
IC++;
SL &= ~f;
break;
#ifdef EXTRA_SW
case OP_SWT7:
case OP_SWT8:
case OP_SWT9:
case OP_SWT10:
case OP_SWT11:
case OP_SWT12:
if (SW & (1 << (6 + MA - OP_SWT7)))
IC++;
break;
#endif
default:
break;
}
break;
/* Transfer opcodes */
case OP_HTR:
/* Stop at HTR instruction if trapped */
IC--;
/* Fall through */
case OP_HPR:
halt:
hltinst = 1;
ihold = 0; /* Kill any hold on traps now */
if (opcode == OP_HTR) {
fptemp = IC-1;
IC = MA;
} else
fptemp = IC;
break;
case OP_XEC:
opcode = (uint16)(SR >> 24);
if (opcode != OP_XEC) {
xeccnt = 15;
goto next_xec;
}
if (xeccnt-- != 0) {
iowait = 1;
goto next_xec;
}
reason = STOP_XECLIM;
break;
case OP_NOP:
break;
case OP_TTR:
IC = MA;
break;
case OP_TLQ:
do_trapmode;
/* Is AC - and MQ + */
if ((MQ & MSIGN) == 0 && (AC & AMSIGN) != 0)
break;
/* Same sign, compare magintudes */
if (((MQ & MSIGN) == 0 && (AC & AMSIGN) == 0)) {
SR = (MQ & PMASK) - (AC & AQMASK);
if ((SR & AMSIGN) == 0)
break;
} else if (((MQ & MSIGN) != 0 && (AC & AMSIGN) != 0)) {
SR = (AC & AQMASK) - (MQ & PMASK);
if ((SR & AMSIGN) == 0)
break;
}
/* Nope, MQ bigger, so take branch */
do_transfer(MA);
break;
case OP_TRA:
do_trapmode;
do_transfer(MA);
break;
case OP_TSX:
do_trapmode;
/* Exchange SR and IC */
SR = AMASK & (-(IC - 1));
do_transfer(MA);
break;
case OP_TZE:
f = (AC & AMMASK) == 0;
branch:
do_trapmode;
if (f) {
do_transfer(MA);
}
break;
case OP_TOV:
f = acoflag;
acoflag = 0;
goto branch;
case OP_TQP:
f = ((MQ & MSIGN) == 0);
goto branch;
case OP_TQO:
if ((CPU_MODEL == CPU_704) || FTM == 0) {
f = mqoflag;
mqoflag = 0;
goto branch;
}
break;
case OP_TPL:
f = ((AC & AMSIGN) == 0);
goto branch;
case OP_TNZ:
f = ((AC & AMMASK) != 0);
goto branch;
case OP_TMI:
f = ((AC & AMSIGN) != 0);
goto branch;
case OP_TNO:
f = !acoflag;
acoflag = 0;
goto branch;
case OP_NZT:
if ((SR & PMASK) != 0)
IC++;
break;
case OP_ZET:
if ((SR & PMASK) == 0)
IC++;
break;
case OP_ESNT:
IC = MA;
if (!nmode)
memmask >>= 1;
nmode = 1;
break;
#ifdef I7090 /* Not on 704 */
/* Indicator opcodes */
case OP_IIA:
ID ^= AC & AQMASK;
break;
case OP_IIS:
ID ^= SR;
break;
case OP_IIR:
ID ^= SR & RMASK;
break;
case OP_IIL:
ID ^= (SR & RMASK) << 18;
break;
case OP_OAI:
ID |= AC & AQMASK;
break;
case OP_OSI:
ID |= SR;
break;
case OP_SIR:
ID |= (SR & RMASK);
break;
case OP_SIL:
ID |= (SR & RMASK) << 18;
break;
case OP_RIA:
ID &= ~AC;
break;
case OP_RIS:
ID &= ~SR;
break;
case OP_RIR:
ID &= ~(SR & RMASK);
break;
case OP_RIL:
ID &= ~((SR & RMASK) << 18);
break;
case OP_PIA:
AC = ID & AQMASK;
break;
case OP_PAI:
ID = AC & AQMASK;
break;
case OP_LDI:
ID = SR;
break;
case OP_STI:
SR = ID;
break;
case OP_ONT:
if ((ID & SR) == SR)
IC++;
break;
case OP_OFT:
if ((ID & SR) == 0)
IC++;
break;
case OP_RFT:
if (0 == (SR & ID & RMASK))
IC++;
break;
case OP_LFT:
if (0 == (((SR & RMASK) << 18) & ID))
IC++;
break;
case OP_RNT:
if ((SR & RMASK) == (SR & ID & RMASK))
IC++;
break;
case OP_LNT:
if ((SR & RMASK) == (SR & (ID >> 18) & RMASK))
IC++;
break;
case OP_TIO:
do_trapmode;
if ((ID & AC) == (AC & AQMASK))
do_transfer(MA);
break;
case OP_TIF:
do_trapmode;
if ((ID & AC) == 0)
do_transfer(MA);
break;
#endif
/* General index and load store opcodes */
case OP_XCA:
SR = (AC & (PMASK));
if (AC & AMSIGN)
SR |= MSIGN;
AC = MQ;
if (AC & APSIGN)
AC ^= AMSIGN | APSIGN;
MQ = SR;
break;
case OP_XCL:
SR = AC & AQMASK;
AC = MQ & AQMASK;
MQ = SR;
break;
case OP_AXC:
SR = (t_uint64)(-(t_int64)SR);
break;
case OP_AXT:
break;
case OP_LXA:
SR &= memmask;
break;
case OP_LAC:
SR = (t_uint64)(-(t_int64)SR);
SR &= memmask;
break;
case OP_LDQ:
MQ = SR;
break;
case OP_LXD:
SR >>= 18;
SR &= memmask;
break;
case OP_LDC:
SR >>= 18;
SR = (t_uint64)(-(t_int64)SR);
SR &= memmask;
break;
case OP_CLA:
AC = ((SR & MSIGN) << 2) | (SR & PMASK);
break;
case OP_CLS:
AC = (((SR & MSIGN) ^ MSIGN) << 2) | (SR & PMASK);
break;
case OP_CAL:
AC = SR;
break;
case OP_STQ:
SR = MQ;
break;
case OP_ECA:
temp = AC;
AC = SR;
SR = temp;
break;
case OP_ECQ:
temp = MQ;
MQ = SR;
SR = temp;
break;
case OP_SLQ:
SR = (SR & RMASK) | (MQ & LMASK);
break;
case OP_STL:
SR &= ~AMASK;
SR |= IC & memmask;
break;
case OP_STZ:
SR = 0;
break;
case OP_STO:
SR = AC & PMASK;
if (AC & AMSIGN)
SR |= MSIGN;
break;
case OP_SLW:
SR = AC & AQMASK;
break;
case OP_STA:
SR &= ~AMASK;
SR |= AC & AMASK;
break;
case OP_STD:
SR &= ~DMASK;
SR |= AC & DMASK;
break;
case OP_STT:
SR &= ~TMASK;
SR |= AC & TMASK;
break;
case OP_STP:
SR &= ~PREMASK;
SR |= AC & PREMASK;
break;
case OP_SXA:
SR &= ~AMASK;
SR |= memmask & xr;
update_xr(tag, xr);
break;
case OP_SCA:
SR &= ~AMASK;
SR |= memmask & (-xr);
update_xr(tag, xr);
break;
case OP_SCD:
SR &= ~DMASK;
temp = (-xr) & memmask;
temp &= AMASK;
temp <<= 18;
SR |= temp;
update_xr(tag, xr);
break;
case OP_SXD:
SR &= ~DMASK;
temp = xr & memmask;
temp &= AMASK;
temp <<= 18;
SR |= temp;
update_xr(tag, xr);
break;
case OP_PDX:
SR = memmask & (AC >> 18);
break;
case OP_PDC:
SR = (t_uint64)(memmask & (-(t_int64)(AC >> 18)));
break;
case OP_PXD:
SR = AC = xr & memmask;
AC <<= 18;
break;
case OP_PCD:
AC = (-xr) & memmask;
AC <<= 18;
SR = xr & memmask;
break;
case OP_PAX:
SR = memmask & AC;
break;
case OP_PAC:
SR = (t_uint64)(memmask & (-(t_int64)AC));
break;
case OP_PXA:
AC = memmask & xr;
SR = xr & memmask;
break;
case OP_PCA:
AC = AMASK & (-xr);
SR = xr & AMASK;
break;
/* Integer math */
case OP_CAS:
if (AC & AMSIGN) {
if (SR & MSIGN) {
if ((AC & AMMASK) == (SR & PMASK))
IC++;
else if (((SR & PMASK) - (AC & AMMASK)) & AMSIGN)
IC += 2;
} else
IC += 2;
} else {
if ((SR & MSIGN) == 0) {
if ((AC & AMMASK) == (SR & PMASK))
IC++;
else if (((AC & AMMASK) - (SR & PMASK)) & AMSIGN)
IC += 2;
}
}
break;
case OP_LAS:
SR = (AC & AMMASK) - SR;
if (SR == 0)
IC++;
if ((SR & AMSIGN))
IC += 2;
break;
case OP_ACL:
ladd:
SR += (AC & AQMASK);
if (SR & AQSIGN)
SR++;
AC = (AC & (AMSIGN | AQSIGN)) | (SR & AQMASK);
break;
case OP_SBM:
SR |= MSIGN;
goto iadd;
case OP_ADM:
SR &= PMASK;
goto iadd;
case OP_SUB:
SR ^= MSIGN;
/* Fall through */
case OP_ADD:
iadd:
f = 0;
/* Make AC Positive */
if (AC & AMSIGN) {
f = 2;
AC &= AMMASK;
}
if (AC & APSIGN)
f |= 8;
/* Check signes of SR & AC */
if (((SR & MSIGN) && ((f & 2) == 0)) ||
(((SR & MSIGN) == 0) && ((f & 2) != 0))) {
AC ^= AMMASK; /* One's compliment */
f |= 1;
}
AC = AC + (SR & PMASK);
/* Check carry from Q */
if (f & 1) { /* Check if signs were not same */
if (AC & AMSIGN) {
f ^= 2;
AC++;
if (((AC & APSIGN) != 0) != ((f & 8) != 0))
acoflag = 1;
} else {
AC ^= AMMASK; /* One's compliment */
}
} else {
if (((AC & APSIGN) != 0) != ((f & 8) != 0))
acoflag = 1;
}
/* Restore sign to AC */
AC &= AMMASK;
if (f & 2)
AC |= AMSIGN;
break;
case OP_MPY:
case OP_MPR:
decr = 043;
/* Fall through */
case OP_VLM + 1:
case OP_VLM:
shiftcnt = decr;
if (shiftcnt == 0)
break;
f = 0;
/* Save sign */
if (MQ & MSIGN)
f |= 1;
if (SR & MSIGN)
f |= 2;
SR &= PMASK;
MQ &= PMASK;
AC = 0; /* Clear AC */
if (SR == 0) {
MQ = 0;
} else {
while (shiftcnt-- > 0) {
if (MQ & 1)
AC += SR;
MQ >>= 1;
if (AC & 1)
MQ |= ONEBIT;
AC >>= 1;
}
}
if (opcode == OP_MPR && MQ & ONEBIT)
AC++;
if (f & 2)
f ^= 1;
if (f & 1) {
MQ |= MSIGN;
AC |= AMSIGN;
}
break;
case OP_DVH:
case OP_DVP:
decr = 043;
/* Fall through */
case OP_VDH + 2:
case OP_VDH:
case OP_VDP + 2:
case OP_VDP:
shiftcnt = decr;
if (shiftcnt == 0)
break;
/* Save sign */
if (SR & MSIGN) {
SR &= PMASK;
f = 1;
} else
f = 0;
if (AC & AMSIGN)
f |= 2;
/* Check if SR less then AC */
if (((SR - (AC & AMMASK)) & AMSIGN) ||
(SR == (AC & AMMASK))) {
dcheck = 1;
if (CPU_MODEL < CPU_7090) {
MQ &= PMASK;
if (f == 2 || f == 1)
MQ |= MSIGN;
}
if (opcode == OP_DVH || opcode == OP_VDH
|| opcode == (OP_VDH + 2)) {
goto halt;
}
break;
}
/* Clear signs */
MQ &= PMASK;
AC &= AMMASK;
sim_interval = sim_interval - shiftcnt;
/* Do divide operation */
do {
AC <<= 1;
AC &= AMMASK;
MQ <<= 1;
if (MQ & MSIGN) {
MQ ^= MSIGN;
AC |= 1;
}
if (SR <= AC) {
AC -= SR;
MQ |= 1;
}
} while (--shiftcnt != 0);
switch (f) {
case 0:
break;
case 3:
AC |= AMSIGN;
break;
case 2:
AC |= AMSIGN;
/* FALL THRU */
case 1:
MQ |= MSIGN;
break;
}
break;
/* Floating point */
case OP_USM:
case OP_FSM:
SR |= MSIGN;
goto fpadd;
case OP_FSB:
case OP_UFS:
SR ^= MSIGN; /* Reverse sign */
goto fpadd;
case OP_FAM:
case OP_UAM:
SR &= PMASK; /* Clear SR sign */
case OP_FAD:
case OP_UFA:
fpadd:
temp = 0; /* Steal temp for errors */
MQ = 0;
f = 0;
/* Extract AC char */
shiftcnt = (int)(AC >> 27) & 01777; /* Include P&Q */
/* Diff SR char */
shiftcnt -= (int)((SR >> 27) & 0377);
if (shiftcnt > 0) { /* AC Bigger */
/* Exchange AC & SR */
AC ^= SR;
SR ^= AC;
AC ^= SR;
/* Fix up signs */
if (SR & AMSIGN)
SR |= MSIGN;
AC &= AMMASK;
if (AC & APSIGN)
AC ^= (AMSIGN | APSIGN);
} else /* SR Bigger then AC, AC Smaller */
shiftcnt = -shiftcnt; /* Change sign */
fptemp = (int)((SR >> 27) & 0377); /* Get exponent */
/* Save AC & SR signs */
if (AC & AMSIGN)
f |= 1;
if (SR & MSIGN)
f |= 2;
/* Clear sign */
SR &= PMASK;
AC &= FPMMASK; /* Clear char and sign */
shiftcnt &= 0377;
if (shiftcnt >= 0 && shiftcnt < 077) {
sim_interval--;
while (shiftcnt > 0) {
MQ >>= 1;
if (AC & 1)
MQ |= FPNBIT;
AC >>= 1;
shiftcnt--;
}
} else
AC = 0;
sim_interval--;
/* Do add */
if (f == 2 || f == 1) {
AC -= (SR & FPMMASK);
/* If AC < 0 then SR was larger */
if (AC & AMSIGN) {
AC = ~AC;
if ((MQ & FPMMASK) != 0) {
MQ ^= FPMMASK;
MQ++;
} else
AC++;
} else
f ^= 2; /* Change sign of AC */
} else
AC += SR & FPMMASK;
/* Check for overflow */
if (AC & FPOBIT) {
if (AC & 1)
MQ |= FPOBIT;
AC >>= 1;
MQ >>= 1;
/* OV check */
if (fptemp == 0377)
temp |= FPACERR | FPOVERR;
fptemp++;
}
/* Are we normalizing */
if (smode == 0 &&
(opcode == OP_FAD || opcode == OP_FSB ||
opcode == OP_FAM || opcode == OP_FSM)) {
sim_interval--;
while ((AC & FPNBIT) == 0 &&
((AC & FPMMASK) != 0 || (MQ & FPMMASK) != 0)) {
/* 704 does not check MQ when normalizing */
if (CPU_MODEL == CPU_704 && (AC & FPMMASK) == 0)
break;
MQ <<= 1;
AC <<= 1;
if (MQ & FPOBIT) {
AC |= 1;
MQ &= ~FPOBIT;
}
if (fptemp == 0 && (temp & FPOVERR) == 0)
temp |= FPACERR;
fptemp--; /* UF Check */
}
if (AC == 0 && MQ == 0) {
fptemp = 0;
f |= f << 1;
}
}
/* Handle signifigance mode */
if (smode && MQ & FPNBIT &&
(opcode == OP_FAD || opcode == OP_FSB ||
opcode == OP_FAM || opcode == OP_FSM)) {
sim_interval--; /* Extra cycle */
/* If overflow, normalize */
AC++;
if (AC & FPOBIT) {
AC >>= 1; /* Move right one bit */
/* OV check */
if (fptemp == 0377)
temp |= FPACERR | FPOVERR;
fptemp++;
}
}
/* Put pieces back together */
AC &= FPMMASK;
MQ &= FPMMASK;
AC |= ((t_uint64) (fptemp & 01777)) << 27;
if (AC != 0) {
if (fptemp < 27 && (temp & FPOVERR) == 0)
temp |= FPMQERR;
fptemp -= 27;
MQ |= ((t_uint64) (fptemp & 0377)) << 27;
}
if (f & 2) {
AC |= AMSIGN;
MQ |= MSIGN;
}
if (temp == 0)
break;
dofptrap:
if (CPU_MODEL != CPU_704 && FTM) {
sim_interval = sim_interval - 1; /* count down */
M[0] &= ~(AMASK | DMASK);
M[0] |= temp | (IC & memmask);
IC = 010;
} else {
if (temp & FPMQERR)
mqoflag = 1;
if (temp & FPACERR)
acoflag = 1;
}
break;
case OP_UFM:
case OP_FMP:
AC = 0;
temp = 0;
/* Quick out for times 0 */
if (SR == 0) {
MQ &= MSIGN;
if (MQ & MSIGN)
AC |= AMSIGN;
break;
}
/* Result sign */
if ((MQ & MSIGN) != (SR & MSIGN))
f = 1;
else
f = 0;
/* 7090 checks MQ for zero before multipling */
if (CPU_MODEL == CPU_7090 && (MQ & PMASK) == 0) {
if (f)
AC |= AMSIGN;
break;
}
/* Handle signifigance mode */
if (smode) {
/* Find larger operand and move to MQ */
if ((MQ & FPMMASK) < (SR & FPMMASK)) {
MQ ^= SR;
SR ^= MQ;
MQ ^= SR;
}
/* Now normalize number in MQ */
fptemp = (int)(MQ >> 27) & 0377;
MQ &= FPMMASK;
while ((MQ & FPNBIT) == 0 && MQ != 0) {
fptemp--;
MQ <<= 1;
}
/* If zero time zero, fix exponent */
if (MQ == 0 && (SR & FPMMASK) == 0) {
fptemp -= 27;
MQ = FPNBIT;
}
} else
/* Extract characteristic */
fptemp = (int)(MQ >> 27) & 0377;
fptemp += (int)(SR >> 27) & 0377;
fptemp -= 128;
MQ &= FPMMASK;
SR &= FPMMASK;
/* Do multiply */
shiftcnt = 27;
while (shiftcnt-- > 0) {
if (MQ & 1)
AC += SR;
MQ >>= 1;
if (AC & 1)
MQ |= FPNBIT;
AC >>= 1;
AC &= FPMMASK;
}
/* Normalize the result */
if (opcode == OP_FMP) {
if ((AC & FPNBIT) == 0) {
MQ <<= 1;
AC <<= 1;
if (MQ & FPOBIT)
AC |= 1;
MQ &= FPMMASK;
fptemp--;
if (smode && (AC & FPNBIT) == 0 &&
(AC & (FPNBIT >> 1)) == 0) {
MQ <<= 1;
AC <<= 1;
if (MQ & FPOBIT)
AC |= 1;
MQ &= FPMMASK;
fptemp--;
}
}
if (smode && MQ & FPNBIT) {
sim_interval--; /* Extra cycle */
/* If overflow, normalize */
AC++;
if (AC & FPOBIT) {
AC >>= 1; /* Move right one bit */
fptemp++;
}
}
if (AC == 0)
fptemp = 0;
}
if (AC != 0 || opcode == OP_UFM || smode) {
if (fptemp < 0)
temp |= FPACERR;
else if (fptemp > 0377)
temp |= FPOVERR | FPACERR;
AC |= ((t_uint64) (fptemp & 01777)) << 27;
fptemp -= 27;
if (fptemp < 0)
temp |= FPMQERR;
else if (fptemp > 0377)
temp |= FPOVERR | FPMQERR;
MQ |= ((t_uint64) (fptemp & 0377)) << 27; /* UF Check */
}
if (f & 1) {
MQ |= MSIGN;
AC |= AMSIGN;
}
if (temp != 0)
goto dofptrap;
break;
case OP_FDH:
case OP_FDP:
/* Sign of SR => MQ */
if ((SR & MSIGN) != ((AC >> 2) & MSIGN))
f = 1;
else
f = 0;
if (AC & AMSIGN)
f |= 2;
if (CPU_MODEL != CPU_704)
MQ = 0;
shiftcnt = 27;
/* Handle signifigance mode */
if (smode) {
/* Divide check if 0 divisor */
if ((SR & FPMMASK) == 0) {
dcheck = 1;
if (f & 1)
MQ |= MSIGN;
if (opcode == OP_FDH)
goto halt;
}
fptemp2 = (int)(AC >> 27) & 0377;
AC &= FPMMASK;
/* If dividend 0, adjust exponent */
if (AC == 0) {
while ((SR & FPNBIT) == 0) {
SR <<= 1;
fptemp2--;
}
if (fptemp2 < 0)
temp |= FPSPERR | FPMQERR;
AC = ((t_uint64) (fptemp2 & 01777)) << 27;
if (FTM && CPU_MODEL != CPU_704 && fptemp2 < 27)
temp |= FPSPERR | FPACERR;
fptemp2 -= 27;
MQ = ((t_uint64) (fptemp2 & 0377)) << 27;
/* Fix signs */
if (f & 1)
MQ |= MSIGN;
if (f & 2) /* Sign does not change */
AC |= AMSIGN;
break;
}
fptemp = (int)(SR >> 27) & 0377;
SR &= FPMMASK;
/* Normalize dividend if larger fraction */
if (AC > (SR & FPMMASK)) {
while ((AC & FPOBIT) == 0) {
fptemp2--;
AC <<= 1;
}
/* Normalize SR, denomalize AC */
/* We checked before for SR==0 */
while ((SR & FPOBIT) == 0) {
SR <<= 1;
fptemp2--;
AC >>= 1;
fptemp++;
}
} else if (AC < (SR & FPMMASK)) {
/* Normalize SR, denomalize AC */
/* We checked before for SR==0 */
while ((SR & FPOBIT) == 0) {
SR <<= 1;
fptemp--;
AC >>= 1;
fptemp2++;
}
}
if ((SR & (FPOBIT >> 1)) == 0)
shiftcnt--;
goto fpdivide;
}
/* Begin common FDP/FDH code */
temp = (AC & FPMMASK) - ((SR & FPMMASK) << 1);
if ((temp & AMSIGN) == 0 || (SR & FPMMASK) == 0) {
dcheck = 1;
if (f & 1)
MQ |= MSIGN;
if (opcode == OP_FDH)
goto halt;
break;
}
temp = 0;
/* Check for divide by 0 */
if ((AC & FPMMASK) == 0) {
AC = 0;
if (CPU_MODEL != CPU_704)
f &= 1;
} else {
/* Split appart fraction and charateristics */
fptemp2 = (int)(AC >> 27) & 0377;
fptemp = (int)(SR >> 27) & 0377;
AC &= FPMMASK;
SR &= FPMMASK;
fpdivide:
/* Precheck SR less then AC */
if (((AC - SR) & AMSIGN) == 0) {
if (AC & 1)
MQ |= FPNBIT;
AC >>= 1;
fptemp2++;
}
/* Do actual divide */
do {
AC <<= 1;
MQ <<= 1;
if (MQ & FPOBIT) {
MQ &= ~FPOBIT;
AC |= 1;
}
if (SR <= AC) {
AC -= SR;
MQ |= 1;
}
} while (--shiftcnt != 0);
/* Compute new characteristic */
AC &= FPMMASK;
fptemp = (fptemp2 - fptemp) + 128; /* UF check */
if (fptemp > 0377)
temp |= FPSPERR | FPOVERR | FPMQERR;
else if (fptemp < 0)
temp |= FPSPERR | FPMQERR;
MQ |= ((t_uint64) (fptemp & 0377)) << 27;
if (FTM && CPU_MODEL != CPU_704 && fptemp2 < 27)
temp |= FPSPERR | FPACERR;
fptemp2 -= 27;
AC |= ((t_uint64) (fptemp2 & 01777)) << 27; /* UF check */
}
/* Fix signs on results */
if (f & 1)
MQ |= MSIGN;
if (f & 2) /* Sign does not change */
AC |= AMSIGN;
if (temp != 0)
goto dofptrap;
if (smode) {
sim_interval = sim_interval - 1; /* count down */
M[0] &= ~(AMASK | DMASK);
M[0] |= (IC & memmask);
IC = 011;
}
break;
#ifdef I7090 /* Not on 704 */
/* Double precision floating point */
case OP_DFSM:
case OP_DUSM:
SR |= MSIGN;
goto dfpadd;
case OP_DFSB:
case OP_DUFS:
SR ^= MSIGN; /* Reverse sign */
goto dfpadd;
case OP_DFAM:
case OP_DUAM:
SR &= PMASK; /* Clear SR sign */
case OP_DFAD:
case OP_DUFA:
dfpadd:
temp = 0; /* Steal temp for errors */
if (MA & 1 && FTM) {
temp = FPDPERR;
goto dofptrap;
}
shiftcnt = (int)(AC >> 27) & 01777; /* Include P&Q */
shiftcnt -= (int)(SR >> 27) & 0377;
f = 0;
/* Save AC & ID signs */
if (AC & AMSIGN)
f |= 1;
if (SR & MSIGN)
f |= 2;
MA |= 1; /* Point to second word */
if (shiftcnt > 0) { /* AC Bigger */
fptemp = (int)(AC >> 27) & 0377;
if (shiftcnt <= 0100) {
ID = AC;
if (f & 1) /* Copy sign */
ID |= MSIGN;
}
f = (f >> 1) | ((1 & f) << 1); /* Exchange signs */
if (shiftcnt > 077) {
if ((AC & FPNBIT) == 0)
ID = AC;
goto dpfnorm;
} else {
t_uint64 t;
AC &= ~FPMMASK;
AC |= SR & FPMMASK;
SR &= ~FPMMASK;
SR |= MQ & FPMMASK;
MQ &= ~FPMMASK;
ReadMem(0, t);
MQ |= t & FPMMASK;
}
/* AC=c, MQ=d SR=b, ID=a */
} else { /* ID Bigger then AC, AC Smaller */
t_uint64 t;
shiftcnt = -shiftcnt; /* Change sign */
fptemp = (int)(SR >> 27) & 0377;
if (shiftcnt > 077) {
if (SR & FPNBIT) {
/* Early exit */
AC = SR;
fptemp = (int)(AC >> 27) & 0377;
ID = (SR & (~FPMMASK)) | (MQ & FPMMASK);
ReadMem(0, MQ);
goto dpdone;
}
MQ &= ~FPMMASK;
AC &= ~FPMMASK;
}
ID = SR;
SR &= ~FPMMASK;
ReadMem(0, t);
SR |= t & FPMMASK;
}
/* Clear sign */
AC &= FPMMASK; /* Clear char and sign */
MQ &= FPMMASK;
shiftcnt &= 0377;
if (shiftcnt >= 0 && shiftcnt < 0177) {
sim_interval--;
while (shiftcnt > 0) {
MQ >>= 1;
if (AC & 1)
MQ |= FPNBIT;
AC >>= 1;
shiftcnt--;
}
} else {
AC = 0;
MQ = 0;
}
sim_interval--;
/* Do add */
if (f == 2 || f == 1) {
/* Ones compliment AC/MQ */
MQ ^= FPMMASK;
AC ^= FPMMASK;
/* Form 2's compliment */
MQ++;
if (MQ & FPOBIT) {
AC++;
MQ ^= FPOBIT;
}
/* Subract ID/SR */
MQ += (SR & FPMMASK);
if (MQ & FPOBIT) {
AC++;
MQ ^= FPOBIT;
}
AC += (ID & FPMMASK);
/* If AC,MQ < 0 then ID,SR was larger */
if (AC & FPOBIT)
AC ^= FPOBIT;
else {
f ^= 2; /* Change sign of AC */
MQ ^= FPMMASK;
AC ^= FPMMASK;
MQ++;
if (MQ & FPOBIT) {
AC++;
MQ ^= FPOBIT;
}
}
} else {
MQ += SR & FPMMASK;
/* Propegate carry */
if (MQ & FPOBIT) {
AC++;
MQ ^= FPOBIT;
}
AC += ID & FPMMASK;
}
/* Check for overflow */
if (AC & FPOBIT) {
if (AC & 1)
MQ |= FPOBIT;
AC >>= 1;
MQ >>= 1;
/* OV check */
if (fptemp == 0377)
temp |= FPACERR | FPOVERR;
fptemp++;
}
dpfnorm:
/* Are we normalizing */
if (opcode == OP_DFAD || opcode == OP_DFSB ||
opcode == OP_DFAM || opcode == OP_DFSM) {
sim_interval--;
/* Preshift before we normalize */
if ((AC & FPMMASK) == 0 && (MQ & FPMMASK) != 0) {
AC |= MQ & FPMMASK;
MQ &= ~FPMMASK;
if (fptemp < 27)
temp |= FPACERR;
fptemp -= 27;
}
while ((AC & FPNBIT) == 0 && (AC & FPMMASK) != 0) {
MQ <<= 1;
AC <<= 1;
if (MQ & FPOBIT) {
AC |= 1;
MQ &= ~FPOBIT;
}
if (fptemp == 0 && (temp & FPOVERR) == 0)
temp |= FPACERR;
fptemp--; /* UF Check */
}
if (AC == 0 && MQ == 0) {
fptemp = 0;
f |= f << 1;
}
}
dpdone:
/* Put pieces back together */
AC &= FPMMASK;
MQ &= FPMMASK;
AC |= ((t_uint64) (fptemp & 01777)) << 27;
if (AC != 0) {
if (fptemp < 27 && (temp & FPOVERR) == 0)
temp |= FPMQERR;
fptemp -= 27;
MQ |= ((t_uint64) (fptemp & 0377)) << 27;
}
if (f & 2)
AC |= AMSIGN;
if (f & 2)
MQ |= MSIGN;
if (temp != 0)
goto dofptrap;
break;
case OP_DFMP:
case OP_DUFM:
temp = 0;
if (MA & 1) {
temp |= FPDPERR;
if (FTM)
goto dofptrap;
}
/* Quick out for zero result. */
fptemp = (int)(SR >> 27) & 0377;
if ((SR & PMASK) == 0) {
AC = MQ = 0;
break;
}
/* Compute exponent */
fptemp += (int)(AC >> 27) & 0377;
fptemp -= 128;
/* Figure out sign */
if (((AC & AMSIGN) != 0) != (0 != (SR & MSIGN)))
f = 1;
else
f = 0;
/* Prepare for first multiply */
MQ &= FPMMASK; /* B */
ID = AC & FPMMASK; /* A */
if (AC == 0 && MQ == 0) {
ID = SR & (MSIGN | FPCMASK);
AC = (f) ? AMSIGN : 0;
MQ = (f) ? MSIGN : 0;
if (temp != 0)
goto dofptrap;
break;
}
AC = 0;
/* First multiply B * C */
if ((SR & FPMMASK) != 0 && MQ != 0) {
SR &= FPMMASK;
shiftcnt = 27;
while (shiftcnt-- > 0) {
if (MQ & 1)
AC += SR;
MQ >>= 1;
if (AC & 1)
MQ |= FPNBIT;
AC >>= 1;
AC &= FPMMASK;
}
}
/* Adjust registers for second multiply */
/* ID:A=xxx-0, MQ:b =0 SR:c = xx:xx d=xx:xxx */
ID ^= SR; /* A, C */
SR ^= ID;
ID ^= SR; /* C, A */
MA |= 1;
ReadMem(0, MQ); /* D */
if (MQ == 0 || (SR & FPMMASK) == 0) {
/* Early out two. */
if ((SR & FPMMASK) == 0 && opcode == OP_DFMP) {
AC = (f) ? AMSIGN : 0;
MQ = (f) ? MSIGN : 0;
if (temp != 0)
goto dofptrap;
break;
}
MQ = SR; /* A */
SR = ID; /* C */
/* Early out three. */
if ((SR & FPMMASK) == 0 && opcode == OP_DFMP) {
AC = (f) ? AMSIGN : 0;
MQ = (f) ? MSIGN : 0;
ID &= FPMMASK;
if (temp != 0)
goto dofptrap;
break;
}
ID &= ~FPMMASK;
ID |= FPMMASK & AC; /* BC */
} else {
ibr = AC & FPMMASK; /* BC */
MQ &= FPMMASK;
AC = 0;
/* Second multiply A * D */
shiftcnt = 27;
while (shiftcnt-- > 0) {
if (MQ & 1)
AC += SR;
MQ >>= 1;
if (AC & 1)
MQ |= FPNBIT;
AC >>= 1;
AC &= FPMMASK;
}
MQ = SR; /* A */
SR = ID; /* C */
ID = FPMMASK & ibr; /* BC */
AC += ibr; /* AD + BC */
}
SR &= FPMMASK;
/* AC:A=220-77, MQ:b =0 SR:c = 220-77 d=0 mq = 7601 */
/* third multiply high * high */
if (MQ == 0 || SR == 0) {
/* MQ == A, AC = AD + BC, ID = BC, SR = C */
MQ = AC;
AC = 0;
if (opcode == OP_DFMP && SR == 0)
ID &= FPMMASK;
} else {
MQ &= FPMMASK; /* Just to be sure */
ID &= FPMMASK; /* Clear char */
shiftcnt = 27;
while (shiftcnt-- > 0) {
if (MQ & 1)
AC += SR;
MQ >>= 1;
if (AC & 1)
MQ |= FPNBIT;
AC >>= 1;
AC &= FPMMASK;
}
}
/* Normalize if DFMP */
if (opcode == OP_DFMP) {
/* Check for true zero result */
if (MQ == 0 && AC == 0) {
fptemp = 0;
} else if ((AC & FPNBIT) == 0 && (AC & FPMMASK) != 0) {
MQ <<= 1;
AC <<= 1;
if (MQ & FPOBIT)
AC |= 1;
MQ &= FPMMASK;
fptemp--; /* UF check */
}
}
/* Fix exponents and check for over/underflow */
if (fptemp != 0) {
if (fptemp < 0)
temp |= FPACERR | FPMQERR;
else if (fptemp < 27)
temp |= FPMQERR;
else if (fptemp > 0377)
temp |= FPOVERR | FPACERR;
AC |= ((t_uint64) (fptemp & 01777)) << 27;
fptemp -= 27;
if (fptemp > 0377)
temp |= FPOVERR | FPMQERR;
MQ |= ((t_uint64) (fptemp & 0377)) << 27; /* UF Check */
}
/* Restore signs */
if (f) {
MQ |= MSIGN;
AC |= AMSIGN;
}
/* Handle trapping */
if (temp != 0)
goto dofptrap;
break;
case OP_DFDH:
case OP_DFDP:
if (MA & 1) {
temp = FPDPERR;
if (FTM)
goto dofptrap;
}
/* Sign of SR => MQ */
temp = (AC & FPMMASK) - ((SR & FPMMASK) << 1);
if ((temp & AMSIGN) == 0 || (SR & FPMMASK) == 0) {
dcheck = 1;
if (opcode == OP_DFDH)
goto halt;
break;
}
/* Result sign */
if (((AC & AMSIGN) != 0) != (0 != (SR & MSIGN)))
f = 1;
else
f = 0;
if (AC & AMSIGN) /* Sign A+B */
f |= 2;
if (SR & MSIGN) /* Sign C+D */
f |= 4;
/* Check for divide by 0 */
if ((MQ & FPMMASK) == 0 && (AC & FPMMASK) == 0) {
/* Divide check by 0 */
ID = MQ = (f & 1) ? MSIGN : 0;
AC = (f & 1) ? AMSIGN : 0;
break;
}
/* Split appart fraction and charateristics */
fptemp2 = (int)(AC >> 27) & 01777;
fptemp = (int)(SR >> 27) & 0377;
fptemp = fptemp2 - fptemp;
fptemp += 0200;
ID = SR & FPMMASK; /* ID = C */
AC &= FPMMASK; /* A */
MQ &= FPMMASK; /* B */
SR &= FPMMASK; /* C */
MA |= 1;
ReadMem(0, ibr);
ibr &= FPMMASK; /* D */
/* Precheck SR less then AC */
if (((AC - SR) & AMSIGN) == 0) {
if (AC & 1)
MQ |= FPOBIT;
MQ >>= 1;
AC >>= 1;
f |= 16; /* Q>1 trigger */
}
/* Divide AB / C => AC=R, MQ=Q1 */
shiftcnt = 27;
do {
AC <<= 1;
MQ <<= 1;
if (MQ & FPOBIT) {
MQ &= ~FPOBIT;
AC |= 1;
}
if (SR <= AC) {
AC -= SR;
MQ |= 1;
}
} while (--shiftcnt != 0);
/* ID=xxx.0, SR=C, ibr=D, AC=R1, MQ=Q1 */
/* Set up for multiply */
SR = MQ; /* SR <- Q1' */
MQ = ibr; /* MQ <- D */
ibr = AC; /* ibr <- R1 */
AC = 0;
/* ID=xxx.C, SR=Q1, ibr=R1, AC=0, MQ=D */
/* Multiply Q1*D => AC,MQ */
shiftcnt = 27;
while (shiftcnt-- > 0) {
if (MQ & 1)
AC += SR;
MQ >>= 1;
if (AC & 1)
MQ |= FPNBIT;
AC >>= 1;
AC &= FPMMASK;
}
/* ID=C.C, SR=Q1, ibr=R1, AC=Q1Dh, MQ=Q1Dl */
/* AC <- R1 - Q1D */
if (ibr < AC) {
AC = AC - ibr;
f |= 8; /* Sign R1 - Q1D */
} else
AC = ibr - AC;
MQ = 0; /* MQ <- 0 */
ID ^= SR; /* SR<>ID Q1<>C */
SR ^= ID;
ID ^= SR;
/* Divide R1 - Q1D / C => AC=R, MQ=Q */
if (f & 16)
fptemp++;
/* Adjust ID register to correct exponent */
ID |= ((t_uint64) (fptemp & 0377)) << 27;
if (f & 1)
ID |= MSIGN;
/* Check before final divide */
temp = AC - (SR << 1);
if ((temp & AMSIGN) == 0 || SR == 0) {
if ((f & 0xa) == 2 || (f & 0xa) == 8) {
MQ |= MSIGN;
AC |= AMSIGN;
}
dcheck = 1;
if (opcode == OP_DFDH)
goto halt;
break;
}
/* Check Quotient > 1 */
if (((AC - SR) & AMSIGN) == 0) {
if (AC & 1)
MQ |= FPNBIT;
MQ >>= 1;
AC >>= 1;
f |= 32; /* Q2>1 trigger */
}
/* Actual divide (R1-Q1D/C) => AC=R2, MQ=Q2 */
shiftcnt = 27;
do {
AC <<= 1;
MQ <<= 1;
if (MQ & FPOBIT) {
MQ &= ~FPOBIT;
AC |= 1;
}
if (SR <= AC) {
AC -= SR;
MQ |= 1;
}
} while (--shiftcnt != 0);
/* ID=Q1, SR=C, ibr=R1, AC=R1-Q1D/C, MQ=Q2 */
AC = 0;
if (f & 32) {
MQ <<= 1;
if (MQ & FPOBIT) {
AC |= 1;
MQ ^= FPOBIT;
}
}
/* MQ = Q2, ID=Q1, SR=C, ibr=R1, AC=xxx */
/* Sign Q2 = sign C+D, sign Q1 = sign R1-Q1D */
temp = (MA & 1) ? FPDPERR : 0; /* Restore errors */
SR = ID & FPMMASK; /* SR <- Q1 */
if ((f & 8)) {
AC = SR - AC;
MQ ^= FPMMASK;
MQ++;
if (MQ & FPOBIT) {
MQ &= FPMMASK;
} else {
AC--;
}
} else {
AC += SR;
}
/* Check for overflow */
if (AC & FPOBIT) {
if (AC & 1)
MQ |= FPOBIT;
AC >>= 1;
MQ >>= 1;
/* OV check */
if (fptemp == 0377)
temp |= FPACERR | FPOVERR;
fptemp++;
}
/* Normalize results */
while ((AC & FPNBIT) == 0 &&
((AC & FPMMASK) != 0 || (MQ & FPMMASK) != 0)) {
MQ <<= 1;
AC <<= 1;
if (MQ & FPOBIT) {
AC |= 1;
MQ ^= FPOBIT;
}
if (fptemp == 0 && (temp & FPOVERR) == 0)
temp |= FPACERR;
fptemp--; /* UF Check */
}
MQ &= FPMMASK;
if (AC == 0 && MQ == 0)
fptemp = 0;
/* Compute new characteristic */
if (fptemp > 0377)
temp |= FPOVERR | FPACERR;
else if (fptemp < 0)
temp |= FPACERR | FPMQERR;
else if (fptemp < 27)
temp |= FPMQERR;
AC |= ((t_uint64) (fptemp & 01777)) << 27;
fptemp -= 27;
if (fptemp > 0377)
temp |= FPOVERR | FPMQERR;
MQ |= ((t_uint64) (fptemp & 0377)) << 27;
/* Fix signs on results */
if (f & 1) { /* Sign does not change */
MQ |= MSIGN;
AC |= AMSIGN;
}
if (temp != 0)
goto dofptrap;
break;
case OP_DLD:
AC = ((SR & MSIGN) << 2) | (SR & PMASK);
f = MA & 1;
MA |= 1;
ReadMem(0, MQ);
if (f) {
temp = FPDPERR;
if (FTM) {
goto dofptrap;
}
}
break;
case OP_DST:
SR = (AC & (APSIGN - 1));
if (AC & AMSIGN)
SR |= MSIGN;
WriteMem();
MA = (MA + 1);
SR = MQ;
break;
#endif
/* Logic operations */
case OP_ORA:
AC |= SR & AQMASK;
break;
case OP_ORS:
SR |= AC;
SR &= AQMASK;
break;
case OP_ANA:
AC &= SR;
AC &= AQMASK;
break;
case OP_ANS:
SR &= AC;
SR &= AQMASK;
break;
case OP_ERA:
AC ^= SR;
AC &= AQMASK; /* Clear S & Q */
break;
#ifdef I7090 /* Not on 704 */
/* Conversion */
case OP_CVR + 3:
case OP_CVR + 2:
case OP_CVR + 1:
case OP_CVR:
shiftcnt = (int)(SR >> 18L) & 0377;
if (AC & AMSIGN) {
f = 1;
AC &= AMMASK;
} else
f = 0;
while (shiftcnt != 0) {
MA += (uint16)(AC & 077);
ReadMem(0, SR);
MA = (uint16)(AMASK & SR);
AC >>= 6;
AC |= SR & (077LL << 30);
shiftcnt--;
}
/* Save XR if tag set */
if (tag & 1)
XR[1] = (uint16)(MA & AMASK);
/* restore sign */
if (f)
AC |= AMSIGN;
break;
case OP_CAQ + 3:
case OP_CAQ + 2:
case OP_CAQ + 1:
case OP_CAQ:
shiftcnt = (int)(SR >> 18L) & 0377;
while (shiftcnt != 0) {
MA += (uint16)(MQ >> 30) & 077;
ReadMem(0, SR);
MA = (uint16)(AMASK & SR);
MQ <<= 6;
MQ |= (MQ >> 36) & 077;
MQ &= WMASK;
AC += SR;
AC &= AMMASK;
shiftcnt--;
}
if (tag & 1)
XR[1] = (uint16)(MA & AMASK);
break;
case OP_CRQ + 3:
case OP_CRQ + 2:
case OP_CRQ + 1:
case OP_CRQ:
shiftcnt = (int)(SR >> 18L) & 0377;
while (shiftcnt != 0) {
MA += (uint16)(MQ >> 30) & 077;
ReadMem(0, SR);
MA = (uint16)(AMASK & SR);
MQ <<= 6;
MQ &= (WMASK ^ 077);
MQ |= (SR >> 30) & 077;
shiftcnt--;
}
if (tag & 1)
XR[1] = (uint16)(MA & AMASK);
break;
#endif
/* Shift */
case OP_LLS:
shiftcnt = MA & 0377;
sim_interval = sim_interval - (shiftcnt >> 6);
/* Save sign */
if (MQ & MSIGN)
f = 1;
else
f = 0;
/* Clear it for now */
AC &= AQMASK;
while (shiftcnt-- > 0) {
MQ <<= 1;
AC <<= 1;
if (MQ & MSIGN)
AC |= 1;
if (AC & APSIGN)
acoflag = 1;
}
/* Restore sign when done */
AC &= AMMASK;
MQ &= PMASK;
if (f) {
AC |= AMSIGN;
MQ |= MSIGN;
}
break;
case OP_LRS:
shiftcnt = MA & 0377;
sim_interval = sim_interval - (shiftcnt >> 6);
/* Save sign */
if (AC & AMSIGN)
f = 1;
else
f = 0;
/* Clear it for now */
AC &= AMMASK;
MQ &= PMASK;
while (shiftcnt-- > 0) {
if (AC & 1)
MQ |= MSIGN;;
MQ >>= 1;
AC >>= 1;
}
/* Restore sign when done */
AC &= AMMASK;
if (f) {
AC |= AMSIGN;
MQ |= MSIGN;
}
break;
case OP_ALS:
shiftcnt = MA & 0377;
sim_interval = sim_interval - (shiftcnt >> 6);
/* Save sign */
if (AC & AMSIGN)
f = 1;
else
f = 0;
/* Clear it for now */
AC &= AQMASK;
while (shiftcnt-- > 0) {
AC <<= 1;
if (AC & APSIGN)
acoflag = 1;
}
/* Restore sign and overflow when done */
AC &= AMMASK;
if (f)
AC |= AMSIGN;
break;
case OP_ARS:
shiftcnt = MA & 0377;
sim_interval = sim_interval - (shiftcnt >> 6);
/* Save sign */
if (AC & AMSIGN)
f = 1;
else
f = 0;
/* Clear it for now */
AC &= AMMASK;
AC >>= shiftcnt;
/* Restore sign when done */
if (f)
AC |= AMSIGN;
break;
case OP_LGL:
shiftcnt = MA & 0377;
sim_interval = sim_interval - (shiftcnt >> 6);
/* Save sign */
if (AC & AMSIGN)
f = 1;
else
f = 0;
/* Clear it for now */
AC &= AMMASK;
while (shiftcnt-- > 0) {
AC <<= 1;
if (MQ & MSIGN)
AC |= 1;
MQ <<= 1;
if (AC & APSIGN)
acoflag = 1;
}
/* Restore sign when done */
AC &= AMMASK;
MQ &= WMASK;
if (f)
AC |= AMSIGN;
break;
case OP_LGR:
shiftcnt = MA & 0377;
sim_interval = sim_interval - (shiftcnt >> 6);
/* Save sign */
if (AC & AMSIGN)
f = 1;
else
f = 0;
/* Clear it for now */
AC &= AMMASK;
while (shiftcnt-- > 0) {
MQ >>= 1;
if (AC & 1)
MQ |= MSIGN;
AC >>= 1;
}
/* Restore sign when done */
AC &= AMMASK;
if (f)
AC |= AMSIGN;
break;
case OP_RQL:
shiftcnt = MA & 0377;
sim_interval = sim_interval - (shiftcnt >> 6);
while (shiftcnt-- > 0) {
MQ <<= 1;
if (MQ & AQSIGN)
MQ |= 1;
MQ &= WMASK;
}
break;
/* 704 Input output Instructions */
case OP_LDA:
if (chan_select(0)) {
extern DEVICE drm_dev;
drum_addr = (uint32)(SR);
sim_debug(DEBUG_DETAIL, &drm_dev,
"set address %06o\n", drum_addr);
chan_clear(0, DEV_FULL); /* In case we read something
before we got here */
} else
iocheck = 1;
break;
case OP_CPY:
case OP_CAD:
/* If no channel, set Iocheck and treat as nop */
if (chan_unit[0].flags & UNIT_DIS) {
iocheck = 1;
break;
}
/* If device disconnecting, just wait */
if (chan_test(0, DEV_DISCO)) {
iowait = 1;
break;
}
/* Instruct is NOP first time */
/* Incomplete last word leaves result in MQ */
if (chan_select(0)) {
extern uint8 bcnt[NUM_CHAN];
chan_set(0, STA_ACTIVE);
switch (chan_flags[0] & (DEV_WRITE | DEV_FULL)) {
case DEV_WRITE | DEV_FULL:
case 0:
/* On EOR skip 1, on EOF skip two */
if (chan_test(0, CHS_EOF|CHS_EOT|DEV_REOR))
chan_set(0, DEV_DISCO);
iowait = 1;
break;
case DEV_WRITE:
MQ = assembly[0] = SR;
bcnt[0] = 6;
chan_set(0, DEV_FULL);
if (opcode == OP_CAD)
goto ladd;
break;
case DEV_FULL:
SR = MQ;
WriteP(MA, MQ);
bcnt[0] = 6;
chan_clear(0, DEV_FULL);
if (opcode == OP_CAD)
goto ladd;
break;
}
} else {
/* If channel not active, turn on io-check */
if (chan_test(0, STA_ACTIVE) == 0) {
iocheck = 1;
break;
}
if (chan_stat(0, CHS_EOF|CHS_EOT)) {
IC++;
/* On EOR skip two */
} else if (chan_stat(0, DEV_REOR)) {
IC += 2;
/* Advance 1 on Error and set iocheck */
} else if (chan_stat(0, CHS_ERR)) {
iocheck = 1;
IC++;
}
chan_clear(0, STA_ACTIVE|DEV_REOR|CHS_ERR);
break;
}
break;
#ifdef I7090 /* Not on 704 */
/* Input/Output Instuctions */
case OP_ENB:
ioflags = SR;
if (SR)
itrap = 1;
else
itrap = 0;
sim_debug(DEBUG_TRAP, &cpu_dev, "ENB %012llo\n", ioflags);
ihold = 1;
/*
* IBSYS can't have an trap right after ENB or it will hang
* on a TTR * in IBNUC.
*/
if (CPU_MODEL >= CPU_7090)
break;
temp = 00000001000001LL;
for (shiftcnt = 1; shiftcnt < NUM_CHAN; shiftcnt++) {
if ((temp & ioflags & DMASK) == 0)
chan_clear(shiftcnt, CHS_ERR);
else if (chan_test(shiftcnt,CHS_ERR))
ihold = 0;
if ((temp & ioflags & AMASK) == 0)
chan_clear(shiftcnt, CHS_EOF);
else if (chan_test(shiftcnt,CHS_EOF))
ihold = 0;
temp <<= 1;
}
break;
#endif
case OP_RDS: /* Read select */
opcode = IO_RDS;
goto docmd;
case OP_WRS: /* Write select */
opcode = IO_WRS;
goto docmd;
case OP_WEF: /* Write EOF */
opcode = IO_WEF;
goto docmd;
case OP_BSR: /* Backspace */
opcode = IO_BSR;
goto docmd;
case OP_BSF: /* Backspace File */
opcode = IO_BSF;
goto docmd;
case OP_REW: /* Rewind */
opcode = IO_REW;
goto docmd;
case OP_RUN: /* Rewind unload */
opcode = IO_RUN;
goto docmd;
case OP_SDN: /* Set density */
opcode = (MA & 020) ? IO_SDH: IO_SDL;
goto docmd;
case OP_DRS: /* Drop ready status */
opcode = IO_DRS;
docmd:
switch (chan_cmd(MA, opcode)) {
case SCPE_BUSY:
iowait = 1; /* Channel is active, hold */
break;
case SCPE_OK:
if (((MA >> 9) & 017) == 0) {
if (opcode==IO_RDS)
MQ = 0;
chan_clear(0, CHS_EOF|CHS_EOT|DEV_REOR);
}
ihold = 1; /* Hold interupts for one cycle */
iotraps &= ~(1 << ((MA >> 9) & 017));
break;
case SCPE_IOERR:
iocheck = 1;
break;
case SCPE_NODEV:
reason = STOP_IOCHECK;
break;
}
break;
case OP_TRS: /* Test ready status */
switch (chan_cmd(MA, IO_TRS)) {
case SCPE_BUSY:
iowait = 1; /* Channel is active, hold */
break;
case SCPE_OK: /* Ready, skip one */
IC++;
ihold = 2; /* Hold interupts for two */
case SCPE_IOERR: /* Not ready, just return */
break;
case SCPE_NODEV:
reason = STOP_IOCHECK;
break;
}
break;
#ifdef I7090 /* Not on 704 */
case OP_TRCA: /* Transfer on Redundancy check */
ihold = 2;
if ((1LL << 18) & ioflags)
break;
f = chan_stat(1, CHS_ERR);
goto branch;
case OP_TRCB: /* Transfer on Redundancy check */
if ((1LL << 19) & ioflags)
break;
f = chan_stat(2, CHS_ERR);
goto branch;
case OP_TRCC:
if ((1LL << 20) & ioflags)
break;
f = chan_stat(3, CHS_ERR);
goto branch;
case OP_TRCD:
if ((1LL << 21) & ioflags)
break;
f = chan_stat(4, CHS_ERR);
goto branch;
case OP_TRCE:
if ((1LL << 22) & ioflags)
break;
f = chan_stat(5, CHS_ERR);
goto branch;
case OP_TRCF:
if ((1LL << 23) & ioflags)
break;
f = chan_stat(6, CHS_ERR);
goto branch;
case OP_TRCG:
if ((1LL << 24) & ioflags)
break;
f = chan_stat(7, CHS_ERR);
goto branch;
case OP_TRCH:
if ((1LL << 25) & ioflags)
break;
f = chan_stat(8, CHS_ERR);
goto branch;
#endif
case OP_TEFA: /* Transfer on channel EOF */
ihold = 2;
if ((1LL << 0) & ioflags)
break;
f = chan_stat(1, CHS_EOF);
goto branch;
#ifdef I7090 /* Not on 704 */
case OP_TEFB: /* Transfer on EOF */
if ((1LL << 1) & ioflags)
break;
f = chan_stat(2, CHS_EOF);
goto branch;
case OP_TEFC:
if ((1LL << 2) & ioflags)
break;
f = chan_stat(3, CHS_EOF);
goto branch;
case OP_TEFD:
if ((1LL << 3) & ioflags)
break;
f = chan_stat(4, CHS_EOF);
goto branch;
case OP_TEFE:
if ((1LL << 4) & ioflags)
break;
f = chan_stat(5, CHS_EOF);
goto branch;
case OP_TEFF:
if ((1LL << 5) & ioflags)
break;
f = chan_stat(6, CHS_EOF);
goto branch;
case OP_TEFG:
if ((1LL << 6) & ioflags)
break;
f = chan_stat(7, CHS_EOF);
goto branch;
case OP_TEFH:
if ((1LL << 7) & ioflags)
break;
f = chan_stat(8, CHS_EOF);
goto branch;
case OP_TCOA: /* Transfer if channel in operation */
case OP_TCOB:
case OP_TCOC:
case OP_TCOD:
case OP_TCOE:
case OP_TCOF:
case OP_TCOG:
case OP_TCOH:
f = chan_active((opcode & 017) + 1);
/* Check if TCOx * */
if ((cpu_unit.flags & UNIT_FASTIO) && f && MA == (IC - 1))
iowait = 1;
goto branch;
case OP_TCNA: /* Transfer on channel not in operation */
case OP_TCNB:
case OP_TCNC:
case OP_TCND:
case OP_TCNE:
case OP_TCNF:
case OP_TCNG:
case OP_TCNH:
f = !chan_active((opcode & 017) + 1);
goto branch;
case OP_RSCA: /* Reset and load channel */
f = 1;
goto chanrst;
case OP_RSCB: /* Reset and load channel */
f = 2;
goto chanrst;
case OP_RSCC:
f = 3;
goto chanrst;
case OP_RSCD:
f = 4;
goto chanrst;
case OP_RSCE:
f = 5;
goto chanrst;
case OP_RSCF:
f = 6;
goto chanrst;
case OP_RSCG:
f = 7;
goto chanrst;
case OP_RSCH:
f = 8;
chanrst:
/* 7607 channel, start imedately */
/* 7909 channel, wait until channel not active */
if (bcore & 1)
MA |= CORE_B;
switch (chan_start(f, MA)) {
case SCPE_IOERR:
iocheck = 1;
break;
case SCPE_BUSY:
iowait = 1;
break;
case SCPE_OK:
ihold = 1;
break;
}
break;
case OP_STCA: /* Load channel, 7909 Start NEA */
f = 1;
goto chanst;
case OP_STCB:
f = 2;
goto chanst;
case OP_STCC:
f = 3;
goto chanst;
case OP_STCD:
f = 4;
goto chanst;
case OP_STCE:
f = 5;
goto chanst;
case OP_STCF:
f = 6;
goto chanst;
case OP_STCG:
f = 7;
goto chanst;
case OP_STCH:
f = 8;
chanst:
/* 7907 channel, set new address */
/* 7909 channel, wait until channel idle, and start */
if (bcore & 1)
MA |= CORE_B;
switch (chan_load(f, MA)) {
case SCPE_IOERR:
iocheck = 1;
break;
case SCPE_BUSY:
iowait = 1;
case SCPE_OK:
break;
}
break;
case OP_SCHA: /* Store data channel */
if (bcore & 1)
MA |= CORE_B;
chan_store(1, MA);
break;
case OP_SCHB:
if (bcore & 1)
MA |= CORE_B;
chan_store(2, MA);
break;
case OP_SCHC:
if (bcore & 1)
MA |= CORE_B;
chan_store(3, MA);
break;
case OP_SCHD:
if (bcore & 1)
MA |= CORE_B;
chan_store(4, MA);
break;
case OP_SCHE:
if (bcore & 1)
MA |= CORE_B;
chan_store(5, MA);
break;
case OP_SCHF:
if (bcore & 1)
MA |= CORE_B;
chan_store(6, MA);
break;
case OP_SCHG:
if (bcore & 1)
MA |= CORE_B;
chan_store(7, MA);
break;
case OP_SCHH:
if (bcore & 1)
MA |= CORE_B;
chan_store(8, MA);
break;
case OP_SCDA: /* Store channel diags 7909 */
if (bcore & 1)
MA |= CORE_B;
chan_store_diag(1, MA);
break;
case OP_SCDB:
if (bcore & 1)
MA |= CORE_B;
chan_store_diag(2, MA);
break;
case OP_SCDC:
if (bcore & 1)
MA |= CORE_B;
chan_store_diag(3, MA);
break;
case OP_SCDD:
if (bcore & 1)
MA |= CORE_B;
chan_store_diag(4, MA);
break;
case OP_SCDE:
if (bcore & 1)
MA |= CORE_B;
chan_store_diag(5, MA);
break;
case OP_SCDF:
if (bcore & 1)
MA |= CORE_B;
chan_store_diag(6, MA);
break;
case OP_SCDG:
if (bcore & 1)
MA |= CORE_B;
chan_store_diag(7, MA);
break;
case OP_SCDH:
if (bcore & 1)
MA |= CORE_B;
chan_store_diag(8, MA);
break;
/* Optional RPQ instructions */
/* Extended precision floating point */
case OP_ESB:
SR ^= MSIGN; /* Reverse sign */
case OP_EAD:
case OP_EUA:
if ((cpu_unit.flags & OPTION_EFP) == 0)
break;
temp = 0; /* Steal temp for errors */
f = 0;
/* Extract AC char */
fptemp = (int)(AC >> 18) & AMASK; /* Include P&Q? */
/* Diff SR char */
fptemp -= (int)(SR >> 18) & AMASK;
if (AC & AMSIGN)
f |= 2;
if (SR & MSIGN)
f |= 1;
/* Get mem frac */
MA = (MA + 1);
ReadMem(0, ibr);
if (fptemp >= 0) { /* AC Bigger */
/* Exchange MQ and ibr */
SR = MQ;
MQ = ibr;
} else { /* ibr Bigger then MQ, MQ Smaller */
fptemp = -fptemp; /* Change sign */
/* Set exponent of result */
AC &= ~DMASK;
AC |= SR & DMASK;
SR = ibr;
f = ((f >> 1) & 1) | ((f & 1) << 1);
}
AC &= DMASK;
/* Clear sign */
MQ &= PMASK;
/* Adjust smaller number */
if (fptemp >= 0 && fptemp < 044) {
sim_interval--;
shiftcnt = fptemp;
while (shiftcnt > 0) {
MQ >>= 1;
shiftcnt--;
}
} else
MQ = 0;
sim_interval--;
/* Check signes of SR & AC */
if (f == 2 || f == 1) {
MQ ^= PMASK;
MQ += SR & PMASK;
/* If MQ < 0 then SR was larger */
if (MQ & MSIGN) {
MQ++;
MQ &= PMASK;
} else {
MQ ^= PMASK;
if (MQ != 0)
f ^= 2; /* Change sign of Result */
}
} else
MQ += SR & PMASK;
/* Check for overflow */
temp = 0;
if (MQ & MSIGN) {
MQ >>= 1;
AC += 00000001000000LL;
/* OV check */
if (AC & APSIGN)
temp |= FPSPERR | FPACERR | FPOVERR;
}
/* Are we normalizing */
if (opcode == OP_EAD || opcode == OP_ESB) {
sim_interval--;
while ((MQ & ONEBIT) == 0 && ((MQ & PMASK) != 0)) {
MQ <<= 1;
AC -= 00000001000000LL;
}
if (MQ == 0) {
AC = 0;
}
}
/* Check underflow */
if (AC & AMSIGN) {
temp |= FPSPERR | FPMQERR;
if (AC & APSIGN)
temp |= FPSPERR | FPOVERR | FPACERR;
} else if (AC & (AQSIGN | PREMASK))
temp |= FPOVERR | FPACERR;
AC &= AMMASK;
/* Set signs */
if (f & 2) {
MQ |= MSIGN;
AC |= AMSIGN;
}
if (temp != 0) {
doefptrap:
if (FTM && CPU_MODEL != CPU_704) {
sim_interval = sim_interval - 1; /* count down */
temp &= ~(FPMQERR | FPACERR);
M[0] &= ~(AMASK | DMASK);
M[0] |= temp | (IC & memmask);
IC = 010;
} else {
if (temp & FPMQERR)
mqoflag = 1;
if (temp & FPACERR)
acoflag = 1;
}
}
break;
case OP_EMP:
if ((cpu_unit.flags & OPTION_EFP) == 0)
break;
temp = 0;
/* Result sign */
if (SR & MSIGN)
f = 1;
else
f = 0;
if (AC & AMSIGN)
f ^= 1;
MQ &= PMASK;
/* Quick out for times 0 */
if (MQ == 0) {
AC &= RMASK;
if (f) {
MQ |= MSIGN;
AC |= AMSIGN;
}
break;
}
/* Extract AC char */
fptemp = (int)(AC >> 18) & AMASK;
/* Diff SR char */
fptemp += (int)(SR >> 18) & AMASK;
fptemp -= 040000;
/* Get mem frac */
MA = MA + 1;
ReadMem(0, SR);
SR &= PMASK;
/* Quick out for times 0 */
if (SR == 0) {
MQ = 0;
AC &= RMASK;
if (f) {
MQ |= MSIGN;
AC |= AMSIGN;
}
break;
}
AC = 0;
/* Do multiply */
shiftcnt = 043;
while (shiftcnt-- > 0) {
if (MQ & 1)
AC += SR;
MQ >>= 1;
if (AC & 1)
MQ |= ONEBIT;
AC >>= 1;
}
/* Normalize result */
if ((AC & ONEBIT) == 0) {
AC <<= 1;
if (MQ & ONEBIT)
AC |= 1;
fptemp--;
}
/* Move results to MQ. */
MQ = AC;
if (MQ == 0) {
AC = 0;
} else {
/* Put exponent in place. */
AC = ((t_uint64) (fptemp)) << 18;
/* Check underflow */
if (AC & AMSIGN) {
temp |= FPSPERR | FPMQERR;
if (AC & APSIGN)
temp |= FPSPERR | FPOVERR | FPACERR;
} else if (AC & (AQSIGN | PREMASK))
temp |= FPOVERR | FPACERR;
/* Clear sign */
AC &= AMMASK;
}
if (f) {
MQ |= MSIGN;
AC |= AMSIGN;
}
if (temp != 0)
goto doefptrap;
break;
case OP_EDP:
if ((cpu_unit.flags & OPTION_EFP) == 0)
break;
/* Result sign */
if (SR & MSIGN)
f = 1;
else
f = 0;
if (AC & AMSIGN)
f ^= 1;
/* Extract AC char */
fptemp = (int)(AC >> 18) & AMASK; /* Include P&Q */
/* Extract SR char */
fptemp -= (int)(SR >> 18) & AMASK;
fptemp += 040000; /* UF check */
/* Get mem frac */
MA = MA + 1;
ReadMem(0, SR);
temp = 0;
/* Check for divide by 0 */
MQ &= PMASK;
if (MQ == 0) {
AC = MQ = 0;
} else {
SR &= PMASK;
if (((MQ - (SR << 1)) & AMSIGN) == 0 || SR == 0) {
dcheck = 1;
AC &= DMASK;
AC |= MQ & RMASK;
if (f) {
MQ |= MSIGN;
AC |= AMSIGN;
}
break;
}
/* Move MQ to AC */
AC = MQ & PMASK;
/* Clear MQ before starting */
MQ = 0;
shiftcnt = 043;
/* Precheck SR less then AC */
if (((AC - SR) & AMSIGN) == 0) {
if (AC & 1)
MQ |= ONEBIT;
AC >>= 1;
fptemp++;
f |= 2;
}
/* Do divide operation */
sim_interval = sim_interval - shiftcnt;
do {
AC <<= 1;
MQ <<= 1;
if (MQ & MSIGN) {
MQ ^= MSIGN;
AC |= 1;
}
if (SR <= AC) {
AC -= SR;
MQ |= 1;
}
} while (--shiftcnt != 0);
/* Fix things if we didn't preshifted */
if ((f & 2) == 0 && AC != 0)
MQ &= ~1;
AC = 0;
if (f & 2) {
if ((MQ & ONEBIT) == 0)
MQ <<= 1;
} else {
AC = RMASK;
}
/* Put exponent in place. */
AC |= ((t_uint64) (fptemp)) << 18;
/* Check underflow */
if (AC & AMSIGN) {
temp |= FPSPERR | FPMQERR;
if (AC & APSIGN)
temp |= FPSPERR | FPOVERR | FPACERR;
} else if (AC & (AQSIGN | PREMASK))
temp |= FPOVERR | FPACERR;
/* Clear sign */
AC &= AMMASK;
}
/* Fix signs on results */
if (f & 1) {
MQ |= MSIGN;
AC |= AMSIGN;
}
if (temp != 0)
goto doefptrap;
break;
case OP_EST:
if ((cpu_unit.flags & OPTION_EFP) == 0)
break;
SR &= RMASK;
if (AC & AMSIGN)
SR |= MSIGN;
SR |= LMASK & PMASK & AC;
/* Clear P+Q and 18-35 */
AC &= AMSIGN | (PMASK & LMASK);
WriteMem();
MA = memmask & (MA + 1);
SR = MQ;
break;
case OP_ELD:
if ((cpu_unit.flags & OPTION_EFP) == 0)
break;
AC = ((SR & MSIGN) << 2) | (SR & PMASK);
MA = memmask & (MA + 1);
ReadMem(0, MQ);
break;
/* Special CTSS modes */
case OP_TIA:
/* Regular xfer in A core, B core trap */
bcore &= ~2;
sim_debug(DEBUG_PROT, &cpu_dev, "TIA %07o %07o\n", IC, MA);
IC = MA;
tbase = (relo_mode)?relocaddr:0;
break;
case OP_TIB:
/* In A core xfer to B core, B core trap */
bcore |= 2;
sim_debug(DEBUG_PROT, &cpu_dev, "TIB %07o %07o\n", IC, MA);
IC = MA;
tbase = ((relo_mode)?relocaddr:0);
break;
case OP_LRI:
/* In B core trap, else load relocation */
relocaddr = (uint16)(SR & 077400);
relo_pend = (SR & MSIGN) ? 0: 1;
ihold = 1;
sim_debug(DEBUG_PROT, &cpu_dev, "LRI %07o %012llo\n", IC, SR);
break;
case OP_LPI:
/* In B core trap, else load protection */
baseaddr = (uint16)(SR & 077400);
limitaddr = (uint16)((SR >> 18) & 077400);
ihold = 1;
prot_pend = (SR & MSIGN)?0:1;
sim_debug(DEBUG_PROT, &cpu_dev, "LPI %07o %012llo\n", IC, SR);
break;
case OP_SRI:
/* In B core trap, else store relocation */
SR = relocaddr | ((relo_mode)? (MSIGN >> 1) : 0);
sim_debug(DEBUG_PROT, &cpu_dev, "SRI %07o %012llo\n", IC, SR);
break;
case OP_SPI:
/* In B core trap, else store protection */
SR = ((t_uint64)limitaddr) << 18 |
((t_uint64)baseaddr);
sim_debug(DEBUG_PROT, &cpu_dev, "SPI %07o %012llo\n", IC, SR);
break;
case OP_SPOP:
switch (MA) {
/* Direct data disconnect */
case 0:
/* Should do disco on channel 0 */
break;
/* Handle signifigence mode */
case OP_ESM:
if (cpu_unit.flags & OPTION_FPSM)
smode = 1;
break;
case OP_TSM:
if (cpu_unit.flags & OPTION_FPSM && smode)
IC++;
smode = 0;
break;
/* Special CTSS memory mods */
case OP_SEA:
if ((cpu_unit.flags & UNIT_DUALCORE) == 0)
break;
/* CTSS Special, set effective to A, Acore only */
if (bcore & 4)
goto prottrap;
bcore &= ~1;
ihold = 1;
break;
case OP_SEB:
if ((cpu_unit.flags & UNIT_DUALCORE) == 0)
break;
/* CTSS Special, set effective to B, Acore only */
if (bcore & 4)
goto prottrap;
bcore |= 1;
ihold = 1;
break;
case OP_IFT:
if ((cpu_unit.flags & UNIT_DUALCORE) == 0)
break;
/* CTSS Special, skip if instruction A, Acore only */
if (bcore & 4)
goto prottrap;
if ((bcore & 1) == 0)
IC++;
break;
case OP_EFT:
if ((cpu_unit.flags & UNIT_DUALCORE) == 0)
break;
/* CTSS Special, skip if effective A, Acore only */
if (bcore & 4)
goto prottrap;
if ((bcore & 2) == 0)
IC++;
break;
}
break;
#endif
default:
fprintf(stderr, "Invalid opcode %o IC=%o %012llo\n",
opcode, IC, temp);
reason = STOP_UUO;
break;
}
if (opinfo & (S_B | S_F)) {
WriteMem();
}
/* Store result into an index register */
if ((opinfo & S_X)) {
SR &= AMASK;
update_xr(tag, SR);
}
break;
}
chan_proc(); /* process any pending channel events */
if (instr_count != 0 && --instr_count == 0)
return SCPE_STEP;
} /* end while */
/* Simulation halted */
return reason;
}
/* Nothing special to do, just return true if cmd is write and we got here */
uint32 cpu_cmd(UNIT * uptr, uint16 cmd, uint16 dev)
{
if (cmd == OP_WRS)
return 1;
return -1;
}
/* Reset routine */
t_stat
cpu_reset(DEVICE * dptr)
{
int i;
AC = 0;
MQ = 0;
SR = 0;
dualcore = 0;
if (cpu_unit.flags & UNIT_DUALCORE)
dualcore = 1;
for (i = 0; i < 7; i++)
XR[i] = 0;
MTM = 1;
TM = STM = CTM = nmode = smode = 0;
FTM = 1;
itrap = 1;
iotraps = baseaddr = bcore = 0;
ioflags = 0;
interval_irq = dcheck = acoflag = mqoflag = iocheck = 0;
sim_brk_types = sim_brk_dflt = SWMASK('E');
limitaddr = 077777;
memmask = MEMMASK;
if (cpu_unit.flags & OPTION_TIMER) {
sim_rtcn_init_unit (&cpu_unit, cpu_unit.wait, TMR_RTC);
sim_activate(&cpu_unit, cpu_unit.wait);
}
return SCPE_OK;
}
/* Interval timer routines */
t_stat
rtc_srv(UNIT * uptr)
{
if (cpu_unit.flags & OPTION_TIMER) {
int32 t;
t = sim_rtcn_calb (rtc_tps, TMR_RTC);
sim_activate_after(uptr, 1000000/rtc_tps);
M[5] += 1;
if (M[5] & MSIGN)
interval_irq = 1;
}
return SCPE_OK;
}
/* Memory examine */
t_stat
cpu_ex(t_value * vptr, t_addr addr, UNIT * uptr, int32 sw)
{
if (addr >= MAXMEMSIZE)
return SCPE_NXM;
if (vptr != NULL)
*vptr = M[addr] & 0777777777777LL;
return SCPE_OK;
}
/* Memory deposit */
t_stat
cpu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw)
{
if (addr >= MAXMEMSIZE)
return SCPE_NXM;
M[addr] = val & 0777777777777LL;
return SCPE_OK;
}
t_stat
cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
t_uint64 mc = 0;
uint32 i;
int32 v;
v = val >> UNIT_V_MSIZE;
v *= 8192;
if (v == 0)
v = 4096;
if ((v < 0) || (v > MAXMEMSIZE) || ((v & 07777) != 0))
return SCPE_ARG;
for (i = v-1; i < MEMSIZE; i++)
mc |= M[i];
if ((mc != 0) && (!get_yn("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = v;
memmask = v - 1;
cpu_unit.flags &= ~UNIT_MSIZE;
cpu_unit.flags |= val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++)
M[i] = 0;
return SCPE_OK;
}
/* Handle execute history */
/* Set history */
t_stat
cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++)
hst[i].ic = 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 = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt);
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, CONST void *desc)
{
int32 k, di, lnt;
char *cptr = (char *) desc;
t_stat r;
t_value sim_eval;
struct InstHistory *h;
if (hst_lnt == 0)
return SCPE_NOFNC; /* enabled? */
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,
"IC AC MQ EA SR XR1 XR2 XR4\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->ic & HIST_PC) { /* instruction? */
fprintf(st, "%06o%c", h->ic & 077777, ((h->ic>>19)&1)?'b':' ');
switch ((h->ac & (AMSIGN | AQSIGN | APSIGN)) >> 35L) {
case (AMSIGN | AQSIGN | APSIGN) >> 35L:
fprintf(st, "-QP");
break;
case (AMSIGN | AQSIGN) >> 35L:
fprintf(st, " -Q");
break;
case (AMSIGN | APSIGN) >> 35L:
fprintf(st, " -P");
break;
case (AMSIGN) >> 35L:
fprintf(st, " -");
break;
case (AQSIGN | APSIGN) >> 35L:
fprintf(st, " QP");
break;
case (AQSIGN) >> 35L:
fprintf(st, " Q");
break;
case (APSIGN) >> 35L:
fprintf(st, " P");
break;
case 0:
fprintf(st, " ");
break;
}
fprint_val(st, h->ac & PMASK, 8, 35, PV_RZRO);
fputc(' ', st);
if (h->mq & MSIGN)
fputc('-', st);
else
fputc(' ', st);
fprint_val(st, h->mq & PMASK, 8, 35, PV_RZRO);
fputc(' ', st);
fprint_val(st, h->ea, 8, 16, PV_RZRO);
fputc(((h->ic>>18)&1)?'b':' ', st);
if (h->sr & MSIGN)
fputc('-', st);
else
fputc(' ', st);
fprint_val(st, h->sr & PMASK, 8, 35, PV_RZRO);
fputc(' ', st);
fprint_val(st, h->xr1, 8, 15, PV_RZRO);
fputc(' ', st);
fprint_val(st, h->xr2, 8, 15, PV_RZRO);
fputc(' ', st);
fprint_val(st, h->xr4, 8, 15, PV_RZRO);
fputc(' ', st);
sim_eval = h->op;
if (
(fprint_sym
(st, h->ic & AMASK, &sim_eval, &cpu_unit,
SWMASK('M'))) > 0) fprintf(st, "(undefined) %012llo", h->op);
fputc('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}
const char *
cpu_description (DEVICE *dptr)
{
#ifdef I7090
return "IBM 709x CPU";
#else
return "IBM 704 CPU";
#endif
}
t_stat
cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
#ifdef I7090
fprintf (st, "The CPU can be set to a IBM 704, IBM 709, IBM 7090 or IBM 7094\n");
fprintf (st, "The type of CPU can be set by one of the following commands\n\n");
fprintf (st, " sim> set CPU 704 sets IBM 704 emulation\n");
fprintf (st, " sim> set CPU 709 sets IBM 709 emulation\n");
fprintf (st, " sim> set CPU 7090 sets IBM 7090 emulation\n");
fprintf (st, " sim> set CPU 7094 sets IBM 7094 emulation\n\n");
#else
fprintf (st, "The CPU behaves as a IBM 704\n");
#endif
fprintf (st, "These switches are recognized when examining or depositing in CPU memory:\n\n");
fprintf (st, " -c examine/deposit characters, 6 per word\n");
fprintf (st, " -l examine/deposit half words\n");
fprintf (st, " -m examine/deposit IBM 709 instructions\n\n");
fprintf (st, "The memory of the CPU can be set in 4K incrememts from 4K to 32K with the\n\n");
fprintf (st, " sim> SET CPU xK\n\n");
#ifdef I7090
fprintf (st, "For systems like IBSYS FASTIO can be enabled. This causes the CPU to finish\n");
fprintf (st, "all outstanding I/O requests when it detects an IDLE loop. This is detected\n");
fprintf (st, "by a TCOx to itself. TRUEIO waits until the given timeout. ");
fprintf (st, "For faster\noperation FASTIO can speed up execution, by eliminating");
fprintf (st, "waits on devices.\nThe default is TRUEIO.\n\n");
fprintf (st, "For the IBM 709x the following options can be enabled\n\n");
fprintf (st, " sim> SET CPU EFP enables extended Floating Point\n");
fprintf (st, " sim> SET CPU NOEFP disables extended Floating Point\n\n");
fprintf (st, " sim> SET CPU FPSM enables significance mode Floating Point\n");
fprintf (st, " sim> SET CPU NOFPSM disables significance mode Floating Point\n\n");
fprintf (st, " sim> SET CPU CLOCK enables clock in memory location 5\n");
fprintf (st, " sim> SET CPU NOCLOCK disables the clock in memory location 5\n\n");
fprintf (st, " sim> SET CPU STANDARD sets generic IBM 709x CPU\n");
fprintf (st, " sim> SET CPU CTSS enables RPQ options, DUAL Core and extended memory for\n");
fprintf (st, " CTSS support\n\n");
#endif
fprintf (st, "The CPU can maintain a history of the most recently executed instructions.\n"
);
fprintf (st, "This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:\n\n"
);
fprintf (st, " sim> SET CPU HISTORY clear history buffer\n");
fprintf (st, " sim> SET CPU HISTORY=0 disable history\n");
fprintf (st, " sim> SET CPU HISTORY=n{:file} enable history, length = n\n");
fprintf (st, " sim> SHOW CPU HISTORY print CPU history\n");
fprint_set_help(st, dptr);
fprint_show_help(st, dptr);
return SCPE_OK;
}