| /* 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; | |
| (void)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; | |
| } | |