/* 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 10000 | |
#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 = | |
{ UDATA(rtc_srv, UNIT_BINK | MODEL(CPU_7090) | MEMAMOUNT(4), | |
MAXMEMSIZE/2 ), 120 }; | |
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 first_rdwr = 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: | |
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; | |
while (reason == 0) { /* loop until halted */ | |
if (exe_KEYS) { | |
SR = KEYS; | |
hltinst = 1; | |
exe_KEYS = 0; | |
goto next_xec; | |
} | |
#ifdef I7090 /* I704 did not have interrupts */ | |
hltloop: | |
#endif | |
/* 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 (itrap && ihold == 0 && iowait == 0 && ioflags != 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 */ | |
hltinst = 0; | |
temp = (((t_uint64) bcore & 3) << 31) | | |
(((t_uint64) f) << 18) | (IC & memmask); | |
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\n", | |
shiftcnt + 'A' - 1, f, 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; | |
} | |
} | |
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 */ | |
hltinst = 0; | |
temp = (((t_uint64) bcore & 3) << 31) | (IC & memmask) | | |
(relo_mode << 21); | |
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; | |
if (CPU_MODEL == CPU_704) { | |
reason = STOP_HALT; | |
break; | |
} | |
/* Hold out until all channels have idled out */ | |
sim_interval = 0; | |
sim_process_event(); | |
chan_proc(); | |
f = chan_active(0); | |
for (shiftcnt = 1; shiftcnt < NUM_CHAN; shiftcnt++) { | |
f |= chan_active(shiftcnt); | |
/* CRC *//* Trap *//* EOF */ | |
/* Wait until channel stops to trigger interupts */ | |
if (ioflags & mask) { | |
if (mask & AMASK & ioflags) { | |
if (chan_stat(shiftcnt, CHS_EOF)) | |
f = 1; /* We have a EOF */ | |
if (iotraps & (1 << shiftcnt)) | |
f = 1; /* We have a IOCT/IORT/IOST */ | |
} | |
if (mask & DMASK & ioflags && chan_stat(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) { | |
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 (bcore & 4) | |
goto prottrap; | |
if (CPU_MODEL != CPU_704) { | |
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; | |
if (opcode == OP_HTR) | |
IC = MA; | |
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)(MQ = SR); | |
sim_debug(DEBUG_DETAIL, &drm_dev, | |
"set address %06o\n", drum_addr); | |
MQ <<= 1; | |
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; | |
itrap = 1; | |
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; | |
/* Don't wait if EOF or Error is pending but hold if trap */ | |
temp = 00000001000001LL; | |
for (shiftcnt = 1; shiftcnt < NUM_CHAN; shiftcnt++) { | |
if (chan_active(shiftcnt) == 0) { | |
if (temp & ioflags & AMASK && | |
iotraps & 1 << shiftcnt) | |
break; | |
if ((temp & ioflags & AMASK && | |
chan_test(shiftcnt, CHS_EOF)) || | |
(temp & ioflags & DMASK && | |
chan_test(shiftcnt, CHS_ERR))) { | |
ihold = 0; | |
break; | |
} | |
} | |
temp <<= 1; | |
} | |
break; | |
#endif | |
case OP_RDS: /* Read select */ | |
if (CPU_MODEL == CPU_704) | |
MQ = 0; | |
else if (first_rdwr == 0) { | |
iotraps &= ~(1 << ((MA >> 9) & 017)); | |
first_rdwr = 1; | |
} | |
opcode = IO_RDS; | |
goto docmd; | |
case OP_WRS: /* Write select */ | |
if (CPU_MODEL != CPU_704 && first_rdwr == 0) { | |
first_rdwr = 1; | |
} | |
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: | |
ihold = 1; /* Hold interupts for one cycle */ | |
first_rdwr = 0; | |
break; | |
case SCPE_IOERR: | |
iocheck = 1; | |
first_rdwr = 0; | |
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 */ | |
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 */ | |
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; | |
} | |