4050 lines
131 KiB
C
4050 lines
131 KiB
C
/* b5500_cpu.c: burroughs 5500 cpu simulator
|
||
|
||
Copyright (c) 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.
|
||
|
||
The Burroughs 5500 was a unique machine, first introduced in 1961 as the
|
||
B5000. Later advanced to the B5500 (1964) adding disks and finally the B5700
|
||
(1971) adding solid state drum. It was the first computer to use the stack
|
||
as it's only means of accessing data. The machine could access at most
|
||
32k words of memory.
|
||
|
||
The machine used 48 bit numbers, all of which were considered to be floating
|
||
point numbers, integers were represented by a zero exponent. A word could
|
||
also be used to hold up to 8 6-bit characters.
|
||
|
||
The differences between the various models were minor. The 5500 added
|
||
the LLL, TUS, FBS and XRT instructions to improve performance of the OS. The
|
||
5700 added a core memory drum instead of spinning disk.
|
||
|
||
The 5500 series tagged memory to assist in controlling access.
|
||
|
||
The 5000 series did not have many programer accessible registers, all
|
||
operations were done on the stack. It had two modes of operation, character
|
||
and word mode.
|
||
|
||
A register 48 bits, held the top of stack.
|
||
AROF flag indicated whether A was full or not.
|
||
B register 48 bits, held the second element of the stack.
|
||
BROF flag indicated whether B was full or not.
|
||
|
||
S register 15 bits held a pointer to the top of stack in memory.
|
||
F register 15 bits held the Frame pointer.
|
||
R register 15 bits held a pointer to the per process procedures and
|
||
variables.
|
||
C register 15 bits together with the L register (2 bits) held the
|
||
pointer to the current executing sylable.
|
||
|
||
When in character mode the registers changed meaning a bit.
|
||
|
||
A held the Source word. GH two 3 bit registers held the character,bit
|
||
offset in the word.
|
||
B held the Destination word. KV two 3 bit registers held the
|
||
character and bit offset in the word.
|
||
|
||
The M register used to access memory held the address of the source
|
||
characters.
|
||
The S register held the address of the destination characters.
|
||
The R register held a count register refered to as TALLY.
|
||
The F register held the info need to return back to word mode.
|
||
|
||
The generic data word was: Flag = 0.
|
||
|
||
11111111112222222222333333333344444444
|
||
0 1 2 345678 901234567890123456789012345678901234567
|
||
+-+-+-+------+---------------------------------------+
|
||
|F|M|E|Exp | Mantissa |
|
||
|l|s|s|in | |
|
||
|a|i|i|octant| |
|
||
|g|g|g| | |
|
||
| |n|n| | |
|
||
+-+-+-+------+---------------------------------------+
|
||
|
||
Also 8 6 bit characters could be used.
|
||
|
||
With the Flag bit 1 various data pointers could be constructed.
|
||
|
||
11111111 112222222222333 333333344444444
|
||
0 1 2 345 678901234567 890123456789012 345678901234567
|
||
+-+-+-+---+------------+---------------+---------------+
|
||
|F|D|P|f | Word count | F Field | Address |
|
||
|l|f|r|l | R Field | | |
|
||
|a|l|e|a | | | |
|
||
|g|a|s|g | | | |
|
||
| |g| |s | | | |
|
||
+-+-+-+---+------------+---------------+---------------+
|
||
|
||
*/
|
||
|
||
#include "b5500_defs.h"
|
||
#include "sim_timer.h"
|
||
#include <math.h>
|
||
|
||
#define UNIT_V_MSIZE (UNIT_V_UF + 0)
|
||
#define UNIT_MSIZE (7 << UNIT_V_MSIZE)
|
||
#define MEMAMOUNT(x) (x << UNIT_V_MSIZE)
|
||
|
||
#define TMR_RTC 0
|
||
|
||
#define HIST_MAX 5000
|
||
#define HIST_MIN 64
|
||
|
||
t_uint64 bit_mask[64] = {
|
||
00000000000000001LL,
|
||
00000000000000002LL,
|
||
00000000000000004LL,
|
||
00000000000000010LL,
|
||
00000000000000020LL,
|
||
00000000000000040LL,
|
||
00000000000000100LL,
|
||
00000000000000200LL,
|
||
00000000000000400LL,
|
||
00000000000001000LL,
|
||
00000000000002000LL,
|
||
00000000000004000LL,
|
||
00000000000010000LL,
|
||
00000000000020000LL,
|
||
00000000000040000LL,
|
||
00000000000100000LL,
|
||
00000000000200000LL,
|
||
00000000000400000LL,
|
||
00000000001000000LL,
|
||
00000000002000000LL,
|
||
00000000004000000LL,
|
||
00000000010000000LL,
|
||
00000000020000000LL,
|
||
00000000040000000LL,
|
||
00000000100000000LL,
|
||
00000000200000000LL,
|
||
00000000400000000LL,
|
||
00000001000000000LL,
|
||
00000002000000000LL,
|
||
00000004000000000LL,
|
||
00000010000000000LL,
|
||
00000020000000000LL,
|
||
00000040000000000LL,
|
||
00000100000000000LL,
|
||
00000200000000000LL,
|
||
00000400000000000LL,
|
||
00001000000000000LL,
|
||
00002000000000000LL,
|
||
00004000000000000LL,
|
||
00010000000000000LL,
|
||
00020000000000000LL,
|
||
00040000000000000LL,
|
||
00100000000000000LL,
|
||
00200000000000000LL,
|
||
00400000000000000LL,
|
||
01000000000000000LL,
|
||
02000000000000000LL,
|
||
04000000000000000LL,
|
||
0
|
||
};
|
||
|
||
uint8 bit_number[64] = {
|
||
/* 00 01 02 03 04 05 06 07 */
|
||
47, 46, 45, 44, 43, 42, 42, 42, /* 00 */
|
||
41, 40, 39, 38, 37, 36, 36, 36, /* 10 */
|
||
35, 34, 33, 32, 31, 30, 30, 30, /* 20 */
|
||
29, 28, 27, 26, 25, 24, 24, 24, /* 30 */
|
||
23, 22, 21, 20, 19, 18, 18, 18, /* 40 */
|
||
17, 16, 15, 14, 13, 12, 12, 12, /* 50 */
|
||
11, 10, 9, 8, 7, 6, 6, 6, /* 60 */
|
||
5, 4, 3, 2, 1, 0, 0, 0, /* 70 */
|
||
};
|
||
|
||
uint8 rank[64] = {
|
||
/* 00 01 02 03 04 05 06 07 */
|
||
53, 54, 55, 56, 57, 58, 59, 60, /* 00 */
|
||
/* 8 9 # @ ? : > ge */
|
||
61, 62, 19, 20, 63, 21, 22, 23, /* 10 */
|
||
/* + A B C D E F G */
|
||
24, 25, 26, 27, 28, 29, 30, 31, /* 20 */
|
||
/* H I . [ & ( < ar */
|
||
32, 33, 1, 2, 6, 3, 4, 5, /* 30 */
|
||
/* ti J K L M N O P */
|
||
34, 35, 36, 37, 38, 39, 40, 41, /* 40 */
|
||
/* Q R $ * - ) ; le */
|
||
42, 43, 7, 8, 12, 9, 10, 11, /* 50 */
|
||
/* bl / S T U V W X */
|
||
0, 13, 45, 46, 47, 48, 49, 50, /* 60 */
|
||
/* Y Z , % ne = ] " */
|
||
51, 52, 14, 15, 44, 16, 17, 18, /* 70 */
|
||
};
|
||
|
||
|
||
int cpu_index; /* Current running cpu */
|
||
t_uint64 M[MAXMEMSIZE] = { 0 }; /* memory */
|
||
t_uint64 a_reg[2]; /* A register */
|
||
t_uint64 b_reg[2]; /* B register */
|
||
t_uint64 x_reg[2]; /* extension to B */
|
||
t_uint64 y_reg[2]; /* extension to A not original */
|
||
uint8 arof_reg[2]; /* True if A full */
|
||
uint8 brof_reg[2]; /* True if B full */
|
||
uint8 gh_reg[2]; /* G & H source char selectors */
|
||
uint8 kv_reg[2]; /* K & V dest char selectors */
|
||
uint16 ma_reg[2]; /* M memory address regiser */
|
||
uint16 s_reg[2]; /* S Stack pointer */
|
||
uint16 f_reg[2]; /* F MCSV pointer */
|
||
uint16 r_reg[2]; /* R PRT pointer */
|
||
t_uint64 p_reg[2]; /* P insruction buffer */
|
||
uint8 prof_reg[2]; /* True if P valid */
|
||
uint16 t_reg[2]; /* T current instruction */
|
||
uint8 trof_reg[2]; /* True if T valid */
|
||
uint16 c_reg[2]; /* C program counter */
|
||
uint16 l_reg[2]; /* L current syllable pointer */
|
||
uint8 ncsf_reg[2]; /* True if normal state */
|
||
uint8 salf_reg[2]; /* True if subrogram mode */
|
||
uint8 cwmf_reg[2]; /* True if character mode */
|
||
uint16 hltf[2]; /* True if processor halted */
|
||
uint8 msff_reg[2]; /* Mark stack flag Word mode */
|
||
#define TFFF MSFF /* True state in Char mode */
|
||
uint8 varf_reg[2]; /* Variant Flag */
|
||
uint8 q_reg[2]; /* Holds error code */
|
||
uint16 IAR; /* Interrupt register */
|
||
uint32 iostatus; /* Hold status of devices */
|
||
uint8 RTC; /* Real time clock counter */
|
||
uint8 loading; /* Set when loading */
|
||
uint8 HALT; /* Set when halt requested */
|
||
uint8 P1_run; /* Run flag for P1 */
|
||
uint8 P2_run; /* Run flag for P2 */
|
||
uint16 idle_addr = 0; /* Address of idle loop */
|
||
|
||
|
||
struct InstHistory
|
||
{
|
||
uint16 c;
|
||
uint16 op;
|
||
uint16 s;
|
||
uint16 f;
|
||
uint16 r;
|
||
uint16 ma;
|
||
t_uint64 a_reg;
|
||
t_uint64 b_reg;
|
||
t_uint64 x_reg;
|
||
uint8 flags;
|
||
uint8 gh;
|
||
uint8 kv;
|
||
uint16 l;
|
||
uint8 q;
|
||
uint8 cpu;
|
||
uint16 iar;
|
||
};
|
||
|
||
struct InstHistory *hst = NULL;
|
||
int32 hst_p = 0;
|
||
int32 hst_lnt = 0;
|
||
|
||
#define F_AROF 00001
|
||
#define F_BROF 00002
|
||
#define F_CWMF 00004
|
||
#define F_NCSF 00010
|
||
#define F_SALF 00020
|
||
#define F_MSFF 00040
|
||
#define F_VARF 00100
|
||
#define HIST_PC 0100000
|
||
|
||
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_msize(UNIT *up, int32 v, CONST char *cp, void *dp);
|
||
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);
|
||
t_stat cpu_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||
/* Interval timer */
|
||
t_stat rtc_srv(UNIT * uptr);
|
||
|
||
int32 rtc_tps = 60 ;
|
||
|
||
|
||
/* 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, MEMAMOUNT(7)|UNIT_IDLE|UNIT_FIX, MAXMEMSIZE ), 16667 },
|
||
{ UDATA(0, UNIT_DISABLE|UNIT_DIS, 0 ), 0 }};
|
||
|
||
REG cpu_reg[] = {
|
||
{BRDATAD(C, c_reg, 8,15,2, "Instruction pointer"), REG_FIT},
|
||
{BRDATAD(L, l_reg, 8,2,2, "Sylable pointer")},
|
||
{BRDATA(A, a_reg, 8,48,2), REG_FIT},
|
||
{BRDATA(B, b_reg, 8,48,2), REG_FIT},
|
||
{BRDATA(X, x_reg, 8,39,2), REG_FIT},
|
||
{BRDATA(Y, x_reg, 8,39,2), REG_FIT},
|
||
{BRDATA(GH, gh_reg, 8,6,2)},
|
||
{BRDATA(KV, kv_reg, 8,6,2)},
|
||
{BRDATAD(MA, ma_reg, 8,15,2, "Memory address")},
|
||
{BRDATAD(S, s_reg, 8,15,2, "Stack pointer")},
|
||
{BRDATAD(F, f_reg, 8,15,2, "Frame pointer")},
|
||
{BRDATAD(R, r_reg, 8,15,2, "PRT pointer/Tally")},
|
||
{BRDATAD(P, p_reg, 8,48,2, "Last code word cache")},
|
||
{BRDATAD(T, t_reg, 8,12,2, "Current instruction")},
|
||
{BRDATAD(Q, q_reg, 8,8,2, "Error condition")},
|
||
{BRDATA(AROF, arof_reg, 2,1,2)},
|
||
{BRDATA(BROF, brof_reg, 2,1,2)},
|
||
{BRDATA(PROF, prof_reg, 2,1,2)},
|
||
{BRDATA(TROF, trof_reg, 2,1,2)},
|
||
{BRDATA(NCSF, ncsf_reg, 2,1,2)},
|
||
{BRDATA(SALF, salf_reg, 2,1,2)},
|
||
{BRDATA(CWMF, cwmf_reg, 2,1,2)},
|
||
{BRDATA(MSFF, msff_reg, 2,1,2)},
|
||
{BRDATA(VARF, varf_reg, 2,1,2)},
|
||
{BRDATA(HLTF, hltf, 2,1,2)},
|
||
{ORDATAD(IAR, IAR, 15, "Interrupt pending")},
|
||
{ORDATAD(TUS, iostatus, 32, "Perpherial ready status"), REG_RO},
|
||
{FLDATA(HALT, HALT, 0)},
|
||
{FLDATA(P1RUN, P1_run, 0), REG_HRO},
|
||
{FLDATA(P2RUN, P2_run, 0), REG_HRO},
|
||
{DRDATA(IDLE_ENAB, sim_idle_enab, 4), REG_HRO},
|
||
{ORDATAD(RTC, RTC, 8, "Real Time Counter"), REG_HRO},
|
||
{NULL}
|
||
};
|
||
|
||
MTAB cpu_mod[] = {
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(0), NULL, "4K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(1), NULL, "8K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(2), NULL, "12K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(3), NULL, "16K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(4), NULL, "20K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(5), NULL, "24K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(6), NULL, "28K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(7), NULL, "32K", &cpu_set_size},
|
||
{MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
|
||
{MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
|
||
{MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_SHP, 0, "HISTORY", "HISTORY",
|
||
&cpu_set_hist, &cpu_show_hist},
|
||
{0}
|
||
};
|
||
|
||
DEVICE cpu_dev = {
|
||
"CPU", cpu_unit, cpu_reg, cpu_mod,
|
||
2, 8, 15, 1, 8, 48,
|
||
&cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
|
||
NULL, DEV_DEBUG|DEV_DYNM, 0, dev_debug,
|
||
cpu_msize, NULL, &cpu_help
|
||
};
|
||
|
||
|
||
|
||
/* Define registers */
|
||
#define A a_reg[cpu_index]
|
||
#define B b_reg[cpu_index]
|
||
#define C c_reg[cpu_index]
|
||
#define L l_reg[cpu_index]
|
||
#define X x_reg[cpu_index]
|
||
#define Y y_reg[cpu_index]
|
||
#define Q q_reg[cpu_index]
|
||
#define GH gh_reg[cpu_index]
|
||
#define KV kv_reg[cpu_index]
|
||
#define Ma ma_reg[cpu_index]
|
||
#define S s_reg[cpu_index]
|
||
#define F f_reg[cpu_index]
|
||
#define R r_reg[cpu_index]
|
||
#define P p_reg[cpu_index]
|
||
#define T t_reg[cpu_index]
|
||
#define AROF arof_reg[cpu_index]
|
||
#define BROF brof_reg[cpu_index]
|
||
#define PROF prof_reg[cpu_index]
|
||
#define TROF trof_reg[cpu_index]
|
||
#define NCSF ncsf_reg[cpu_index]
|
||
#define SALF salf_reg[cpu_index]
|
||
#define CWMF cwmf_reg[cpu_index]
|
||
#define MSFF msff_reg[cpu_index]
|
||
#define VARF varf_reg[cpu_index]
|
||
#define HLTF hltf[cpu_index]
|
||
|
||
/* Definitions to help extract fields */
|
||
#define FF(x) (uint16)(((x) & FFIELD) >> FFIELD_V)
|
||
#define CF(x) (uint16) ((x) & CORE)
|
||
#define LF(x) (uint16)(((x) & RL) >> RL_V)
|
||
#define RF(x) (uint16)(((x) & RFIELD) >> RFIELD_V)
|
||
|
||
#define toF(x) ((((t_uint64)(x)) << FFIELD_V) & FFIELD)
|
||
#define toC(x) (((t_uint64)(x)) & CORE)
|
||
#define toL(x) ((((t_uint64)(x)) << RL_V) & RL)
|
||
#define toR(x) ((((t_uint64)(x)) << RFIELD_V) & RFIELD)
|
||
|
||
#define replF(y, x) ((y & ~FFIELD) | toF(x))
|
||
#define replC(y, x) ((y & ~CORE) | toC(x))
|
||
|
||
#define next_addr(x) (x = (x + 1) & 077777)
|
||
#define prev_addr(x) (x = (x - 1) & 077777)
|
||
|
||
/* Definitions to handle building of control words */
|
||
#define MSCW (FLAG | DFLAG | toR(R) | toF(F) | \
|
||
((MSFF)?SMSFF:0) | ((SALF)?SSALF:0))
|
||
#define ICW (FLAG | DFLAG | toR(R) | ((VARF)?SVARF:0) | \
|
||
((MSFF)?SMSFF:0) | ((SALF)?SSALF:0)) | toC(Ma)
|
||
#define Pointer(x) ((t_uint64)((((x) & 070) >> 3) | ((x & 07) << 8)))
|
||
#define RCW(x) (FLAG | DFLAG | toF(F) | toC(C) | toL(L) | \
|
||
(Pointer(GH) << RGH_V) | (Pointer(KV) << RKV_V)) | \
|
||
((x)?PRESENT:0)
|
||
#define LCW(f, x) toF(f) | toC(C) | toL(L) | \
|
||
(((t_uint64)(x) << REPFLD_V) & REPFLD)
|
||
#define VARIANT(x) ((x) >> 6)
|
||
|
||
|
||
/* E
|
||
2 A = M[S]
|
||
3 B = M[S]
|
||
4 A = M[Ma]
|
||
5 B = M[Ma]
|
||
6 Ma = M[Ma]<18:32>
|
||
10 M[S] = A 1010
|
||
11 M[S] = B 1011
|
||
12 M[Ma] = A 1100
|
||
13 M[Ma] = B 1101
|
||
|
||
1 B/A
|
||
2 S
|
||
4 Ma
|
||
8 Write/Read
|
||
16 Fetch
|
||
*/
|
||
|
||
int memory_cycle(uint8 E) {
|
||
uint16 addr = 0;
|
||
|
||
sim_interval--;
|
||
if (E & 2)
|
||
addr = S;
|
||
if (E & 4)
|
||
addr = Ma;
|
||
if (E & 020)
|
||
addr = C;
|
||
if (addr > MEMSIZE) {
|
||
Q |= INVALID_ADDR;
|
||
return 1;
|
||
}
|
||
if (NCSF && addr < 01000) {
|
||
Q |= INVALID_ADDR;
|
||
return 1;
|
||
}
|
||
if (E & 020) {
|
||
P = M[addr];
|
||
PROF = 1;
|
||
return 0;
|
||
}
|
||
if (E & 010) {
|
||
if (E & 1)
|
||
M[addr] = B;
|
||
else
|
||
M[addr] = A;
|
||
} else {
|
||
if (E == 6) {
|
||
B = M[addr];
|
||
Ma = FF(B);
|
||
} else if (E & 1) {
|
||
B = M[addr];
|
||
BROF = 1;
|
||
} else {
|
||
A = M[addr];
|
||
AROF = 1;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* Set registers based on MSCW */
|
||
void set_via_MSCW(t_uint64 word) {
|
||
F = FF(word);
|
||
R = RF(word);
|
||
MSFF = (word & SMSFF) != 0;
|
||
SALF = (word & SSALF) != 0;
|
||
}
|
||
|
||
/* Set registers based on RCW.
|
||
if no_set_lc is non-zero don't set LC from RCW.
|
||
if no_bits is non-zero don't set GH and KV,
|
||
return BROF flag */
|
||
int set_via_RCW(t_uint64 word, int no_set_lc, int no_bits) {
|
||
if (!no_set_lc) {
|
||
L = LF(word);
|
||
C = CF(word);
|
||
PROF = 0;
|
||
}
|
||
F = FF(word);
|
||
if (!no_bits) {
|
||
uint16 t;
|
||
t = (uint16)((word & RGH) >> RGH_V);
|
||
GH = ((t << 3) & 070) | ((t >> 8) & 07);
|
||
t = (uint16)((word & RKV) >> RKV_V);
|
||
KV = ((t << 3) & 070) | ((t >> 8) & 07);
|
||
}
|
||
return (word & PRESENT) != 0;
|
||
}
|
||
|
||
/* Set the stack pointer from INCW */
|
||
void set_via_INCW(t_uint64 word) {
|
||
S = CF(word);
|
||
CWMF = (word & SCWMF) != 0;
|
||
}
|
||
|
||
/* Set registers from ICW */
|
||
void set_via_ICW(t_uint64 word) {
|
||
Ma = CF(word);
|
||
MSFF = (word & SMSFF) != 0;
|
||
SALF = (word & SSALF) != 0;
|
||
VARF = (word & SVARF) != 0;
|
||
R = RF(word);
|
||
}
|
||
|
||
/* Make sure that B is empty */
|
||
void B_empty() {
|
||
if (BROF) {
|
||
next_addr(S);
|
||
if (NCSF && (S & 077700) == R) {
|
||
Q |= STK_OVERFL; /* Stack fault */
|
||
return;
|
||
}
|
||
memory_cycle(013); /* Save B */
|
||
BROF = 0;
|
||
}
|
||
}
|
||
|
||
/* Make sure A is empty, push to B if not */
|
||
void A_empty() {
|
||
if (AROF) {
|
||
B_empty();
|
||
B = A;
|
||
AROF = 0;
|
||
BROF = 1;
|
||
}
|
||
}
|
||
|
||
/* Make sure both A and B are empty */
|
||
void AB_empty() {
|
||
B_empty();
|
||
if (AROF) {
|
||
next_addr(S);
|
||
if (NCSF && (S & 077700) == R) {
|
||
Q |= STK_OVERFL; /* Stack fault */
|
||
return;
|
||
}
|
||
memory_cycle(012); /* Save A */
|
||
AROF = 0;
|
||
}
|
||
}
|
||
|
||
/* Make sure that A is valid, copy from B or memory */
|
||
void A_valid() {
|
||
if (!AROF) {
|
||
if (BROF) { /* Transfer B to A */
|
||
A = B;
|
||
AROF = 1;
|
||
BROF = 0;
|
||
} else {
|
||
if (NCSF && (S & 077700) == R) {
|
||
Q |= STK_OVERFL; /* Stack fault */
|
||
return;
|
||
}
|
||
memory_cycle(2); /* Read A */
|
||
prev_addr(S);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Make sure both A and B are valid */
|
||
void AB_valid() {
|
||
A_valid();
|
||
if (!BROF) {
|
||
if (NCSF && (S & 077700) == R) {
|
||
Q |= STK_OVERFL; /* Stack fault */
|
||
return;
|
||
}
|
||
memory_cycle(3); /* Read B */
|
||
prev_addr(S);
|
||
}
|
||
}
|
||
|
||
/* Make sure A is empty and B is valid */
|
||
void B_valid() {
|
||
A_empty();
|
||
if (!BROF) {
|
||
if (NCSF && (S & 077700) == R) {
|
||
Q |= STK_OVERFL; /* Stack fault */
|
||
return;
|
||
}
|
||
memory_cycle(3); /* Read B */
|
||
prev_addr(S);
|
||
}
|
||
}
|
||
|
||
/* Make sure B is valid, don't care about A */
|
||
void B_valid_and_A() {
|
||
if (!BROF) {
|
||
if (NCSF && (S & 077700) == R) {
|
||
Q |= STK_OVERFL; /* Stack fault */
|
||
return;
|
||
}
|
||
memory_cycle(3); /* Read B */
|
||
prev_addr(S);
|
||
}
|
||
}
|
||
|
||
/* Saves the top word on the stack into MA */
|
||
void save_tos() {
|
||
if (AROF) {
|
||
memory_cycle(014); /* Store A in Ma */
|
||
AROF = 0;
|
||
} else if (BROF) {
|
||
memory_cycle(015); /* Store B in Ma */
|
||
BROF = 0;
|
||
} else { /* Fetch B then Store */
|
||
A_valid(); /* Use A register since it is quicker */
|
||
memory_cycle(014);
|
||
AROF = 0;
|
||
}
|
||
}
|
||
|
||
/* Enter a subroutine, flag true for descriptor, false for opdc */
|
||
void enterSubr(int flag) {
|
||
/* Program descriptor */
|
||
if ((A & ARGF) != 0 && MSFF == 0) {
|
||
return;
|
||
}
|
||
if ((A & MODEF) != 0 && (A & ARGF) == 0) {
|
||
return;
|
||
}
|
||
B_empty();
|
||
/* Check if accidental entry */
|
||
if ((A & ARGF) == 0) {
|
||
B = MSCW;
|
||
BROF = 1;
|
||
B_empty();
|
||
F = S;
|
||
}
|
||
B = RCW(flag);
|
||
BROF = 1;
|
||
B_empty();
|
||
C = CF(A);
|
||
L = 0;
|
||
if ((A & ARGF) == 0) {
|
||
F = FF(A);
|
||
} else {
|
||
F = S;
|
||
}
|
||
AROF = 0;
|
||
BROF = 0;
|
||
SALF = 1;
|
||
MSFF = 0;
|
||
PROF = 0;
|
||
if (A & MODEF) {
|
||
CWMF = 1;
|
||
R = 0;
|
||
X = toF(S);
|
||
S = 0;
|
||
}
|
||
}
|
||
|
||
/* Make B register into an integer, return 1 if failed */
|
||
int mkint() {
|
||
int exp_b;
|
||
int last_digit;
|
||
int f = 0;
|
||
|
||
/* Extract exponent */
|
||
exp_b = (B & EXPO) >> EXPO_V;
|
||
if (exp_b == 0)
|
||
return 0;
|
||
if (B & ESIGN)
|
||
exp_b = -exp_b;
|
||
if (B & MSIGN)
|
||
f = 1;
|
||
B &= MANT;
|
||
/* Adjust if exponent less then zero */
|
||
last_digit = 0;
|
||
if (exp_b < 0) {
|
||
while (exp_b < 0 && B != 0) {
|
||
last_digit = B & 7;
|
||
B >>= 3;
|
||
exp_b++;
|
||
}
|
||
if (exp_b != 0) {
|
||
B = 0;
|
||
return 0;
|
||
}
|
||
if (f ? (last_digit > 4) : (last_digit >= 4))
|
||
B++;
|
||
} else {
|
||
/* Now handle when exponent plus */
|
||
while(exp_b > 0) {
|
||
if ((B & NORM) != 0)
|
||
return 1;
|
||
B <<= 3;
|
||
exp_b--;
|
||
}
|
||
}
|
||
if (f && B != 0)
|
||
B |= MSIGN;
|
||
return 0;
|
||
}
|
||
|
||
/* Compute an index word return true if failed. */
|
||
int indexWord() {
|
||
if (A & WCOUNT) {
|
||
B_valid_and_A();
|
||
if (mkint()) {
|
||
if (NCSF)
|
||
Q |= INT_OVER;
|
||
return 1;
|
||
}
|
||
if (B & MSIGN && (B & MANT) != 0) {
|
||
if (NCSF)
|
||
Q |= INDEX_ERROR;
|
||
return 1;
|
||
}
|
||
if ((B & 01777) >= ((A & WCOUNT) >> WCOUNT_V)) {
|
||
if (NCSF)
|
||
Q |= INDEX_ERROR;
|
||
return 1;
|
||
}
|
||
Ma = (A + (B & 01777)) & CORE;
|
||
A &= ~(WCOUNT|CORE);
|
||
A |= Ma;
|
||
BROF = 0;
|
||
} else {
|
||
Ma = CF(A);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* Character mode helper routines */
|
||
|
||
/* Adjust source bit pointers to point to char */
|
||
void adjust_source() {
|
||
if (GH & 07) {
|
||
GH &= 070;
|
||
GH += 010;
|
||
if (GH > 077) {
|
||
AROF = 0;
|
||
GH = 0;
|
||
next_addr(Ma);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Adjust destination bit pointers to point to char */
|
||
void adjust_dest() {
|
||
if (KV & 07) {
|
||
KV &= 070;
|
||
KV += 010;
|
||
if (KV > 075) {
|
||
if (BROF)
|
||
memory_cycle(013);
|
||
BROF = 0;
|
||
KV = 0;
|
||
next_addr(S);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Advance to next destination bit/char */
|
||
void next_dest(int bit) {
|
||
if (bit)
|
||
KV += 1;
|
||
else
|
||
KV |= 7;
|
||
if ((KV & 07) > 5) {
|
||
KV &= 070;
|
||
KV += 010;
|
||
}
|
||
if (KV > 075) {
|
||
if (BROF)
|
||
memory_cycle(013);
|
||
BROF = 0;
|
||
KV = 0;
|
||
next_addr(S);
|
||
}
|
||
}
|
||
|
||
/* Advance to previous destination bit/char */
|
||
void prev_dest(int bit) {
|
||
if (bit) {
|
||
if ((KV & 07) == 0) {
|
||
if (KV == 0) {
|
||
if (BROF)
|
||
memory_cycle(013);
|
||
BROF = 0;
|
||
prev_addr(S);
|
||
KV = 076;
|
||
} else {
|
||
KV = ((KV - 010) & 070) | 06;
|
||
}
|
||
}
|
||
KV -= 1;
|
||
} else {
|
||
KV &= 070;
|
||
if (KV == 0) {
|
||
if (BROF)
|
||
memory_cycle(013);
|
||
BROF = 0;
|
||
prev_addr(S);
|
||
KV = 070;
|
||
} else
|
||
KV -= 010;
|
||
}
|
||
}
|
||
|
||
/* Make sure destination have valid data */
|
||
void fill_dest() {
|
||
if (BROF == 0) {
|
||
memory_cycle(3);
|
||
BROF = 1;
|
||
}
|
||
}
|
||
|
||
/* Advance source to next bit/char */
|
||
void next_src(int bit) {
|
||
if (bit)
|
||
GH += 1;
|
||
else
|
||
GH |= 7;
|
||
if ((GH & 07) > 5) {
|
||
GH &= 070;
|
||
GH += 010;
|
||
}
|
||
if (GH > 075) {
|
||
AROF = 0;
|
||
GH = 0;
|
||
next_addr(Ma);
|
||
}
|
||
}
|
||
|
||
/* Advance source to previous bit/char */
|
||
void prev_src(int bit) {
|
||
if (bit) {
|
||
if ((GH & 07) == 0) {
|
||
if (GH == 0) {
|
||
AROF = 0;
|
||
prev_addr(Ma);
|
||
GH = 076;
|
||
} else {
|
||
GH = ((GH - 010) & 070) | 06;
|
||
}
|
||
}
|
||
GH -= 1;
|
||
} else {
|
||
GH &= 070;
|
||
if (GH == 0) {
|
||
AROF = 0;
|
||
prev_addr(Ma);
|
||
GH = 070;
|
||
} else
|
||
GH -= 010;
|
||
}
|
||
}
|
||
|
||
/* Make sure source has valid data */
|
||
void fill_src() {
|
||
if (AROF == 0) {
|
||
memory_cycle(4);
|
||
AROF = 1;
|
||
}
|
||
}
|
||
|
||
|
||
/* Helper routines for managing processor */
|
||
|
||
/* Fetch next program sylable */
|
||
void next_prog() {
|
||
if (!PROF)
|
||
memory_cycle(020);
|
||
T = (P >> ((3 - L) * 12)) & 07777;
|
||
if ( L++ == 3) {
|
||
C++;
|
||
L = 0;
|
||
PROF = 0;
|
||
}
|
||
TROF = 1;
|
||
}
|
||
|
||
/* Initiate a processor, A must contain the ICW */
|
||
void initiate() {
|
||
int brflg, arflg, temp;
|
||
|
||
set_via_INCW(A); /* Set up Stack */
|
||
AROF = 0;
|
||
memory_cycle(3); /* Fetch IRCW from stack */
|
||
prev_addr(S);
|
||
brflg = set_via_RCW(B, 0, 0);
|
||
memory_cycle(3); /* Fetch ICW from stack */
|
||
prev_addr(S);
|
||
set_via_ICW(B);
|
||
BROF = 0; /* Note memory_cycle set this */
|
||
if (CWMF) {
|
||
memory_cycle(3); /* Fetch LCW from stack */
|
||
prev_addr(S);
|
||
arflg = (B & PRESENT) != 0;
|
||
X = B & MANT;
|
||
if (brflg) {
|
||
memory_cycle(3); /* Load B via S */
|
||
prev_addr(S);
|
||
}
|
||
if (arflg) {
|
||
memory_cycle(2); /* Load A via S */
|
||
prev_addr(S);
|
||
}
|
||
AROF = arflg;
|
||
BROF = brflg;
|
||
temp = S;
|
||
S = FF(X);
|
||
X = replF(X, temp);
|
||
}
|
||
NCSF = 1;
|
||
PROF = 0;
|
||
TROF = 0;
|
||
}
|
||
|
||
/* Save processor state in case of error or halt */
|
||
void storeInterrupt(int forced, int test) {
|
||
int f;
|
||
uint16 temp;
|
||
|
||
if (forced || test)
|
||
NCSF = 0;
|
||
f = BROF;
|
||
if (CWMF) {
|
||
int i = AROF;
|
||
temp = S;
|
||
S = FF(X);
|
||
X = replF(X, temp);
|
||
if (AROF || test) { /* Push A First */
|
||
next_addr(S);
|
||
memory_cycle(10);
|
||
}
|
||
if (BROF || test) { /* Push B second */
|
||
next_addr(S);
|
||
memory_cycle(11);
|
||
}
|
||
/* Make ILCW */
|
||
B = X | ((i)? PRESENT : 0) | FLAG | DFLAG;
|
||
next_addr(S); /* Save B */
|
||
memory_cycle(11);
|
||
} else {
|
||
if (BROF || test) { /* Push B First */
|
||
next_addr(S);
|
||
memory_cycle(11);
|
||
}
|
||
if (AROF || test) { /* Push A Second */
|
||
next_addr(S);
|
||
memory_cycle(10);
|
||
}
|
||
}
|
||
AROF = 0;
|
||
B = ICW; /* Set ICW into B */
|
||
next_addr(S); /* Save B */
|
||
memory_cycle(11);
|
||
B = RCW(f); /* Save IRCW */
|
||
next_addr(S); /* Save B */
|
||
memory_cycle(11);
|
||
if (CWMF) {
|
||
/* Get the correct value of R */
|
||
Ma = F;
|
||
memory_cycle(6); /* Load B via Ma, Indirect */
|
||
memory_cycle(5); /* Load B via Ma */
|
||
R = RF(B);
|
||
B = FLAG|DFLAG|SCWMF|toC(S);
|
||
} else {
|
||
B = FLAG|DFLAG|toC(S);
|
||
}
|
||
B |= ((t_uint64)Q) << 35;
|
||
Ma = R | 010;
|
||
memory_cycle(015); /* Store B in Ma */
|
||
R = 0;
|
||
BROF = 0;
|
||
MSFF = 0;
|
||
SALF = 0;
|
||
F = S;
|
||
if (forced || test)
|
||
CWMF = 0;
|
||
PROF = 0;
|
||
if (test) {
|
||
Ma = 0;
|
||
memory_cycle(5); /* Load location 0 to B. */
|
||
BROF = 0;
|
||
C = CF(B);
|
||
L = 0;
|
||
KV = 0;
|
||
GH = 0;
|
||
} else if (forced) {
|
||
if (cpu_index) {
|
||
P2_run = 0; /* Clear halt flag */
|
||
hltf[1] = 0;
|
||
cpu_index = 0;
|
||
} else {
|
||
T = WMOP_ITI;
|
||
TROF = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Check if in idle loop.
|
||
assume that current instruction is ITI */
|
||
/* Typical idle loop for MCP is:
|
||
|
||
-1 ITI 0211
|
||
+0 TUS 2431
|
||
+1 OPDC address1 xxx2
|
||
+2 LOR 0215
|
||
+3 OPDC address2 xxx2
|
||
+4 NEQ 0425
|
||
+5 LITC 010 LITC 1 0040 0004
|
||
+6 BBC LBC 0131 2131
|
||
|
||
*/
|
||
|
||
int check_idle() {
|
||
static uint16 loop_data[7] = {
|
||
WMOP_TUS, WMOP_OPDC, WMOP_LOR, WMOP_OPDC,
|
||
WMOP_NEQ, WMOP_LITC, WMOP_BBC };
|
||
static uint16 loop_mask[7] = {
|
||
07777, 00003, 07777, 00003,
|
||
07777, 07733, 05777};
|
||
t_uint64 data;
|
||
uint16 addr = C;
|
||
int l = (3 - L) * 12;
|
||
uint16 word;
|
||
int i;
|
||
|
||
/* Quick check to see if not correct location */
|
||
if (idle_addr != 0 && idle_addr != addr)
|
||
return 0;
|
||
/* If address same, then idle loop */
|
||
if (idle_addr == addr)
|
||
return 1;
|
||
|
||
/* Not set, see if this could be loop */
|
||
data = M[addr];
|
||
for (i = 0; i < 7; i++) {
|
||
word = (uint16)(data >> l) & 07777;
|
||
if ((word & loop_mask[i]) != loop_data[i])
|
||
return 0;
|
||
if (l == 0) {
|
||
addr++;
|
||
l = 3 * 12;
|
||
data = M[addr];
|
||
} else {
|
||
l -= 12;
|
||
}
|
||
}
|
||
idle_addr = C;
|
||
return 1;
|
||
}
|
||
|
||
|
||
/* Math helper routines. */
|
||
|
||
/* Compare A and B,
|
||
return 1 if B = A.
|
||
return 2 if B > A
|
||
return 4 if B < A
|
||
*/
|
||
uint8 compare() {
|
||
int sign_a, sign_b;
|
||
int exp_a, exp_b;
|
||
t_uint64 ma, mb;
|
||
|
||
sign_a = (A & MSIGN) != 0;
|
||
sign_b = (B & MSIGN) != 0;
|
||
|
||
/* next grab exponents and mantissa */
|
||
ma = A & MANT;
|
||
mb = B & MANT;
|
||
if (ma == 0) {
|
||
if (mb == 0)
|
||
return 1;
|
||
return (sign_b ? 2 : 4);
|
||
} else {
|
||
/* Extract exponent */
|
||
exp_a = (A & EXPO) >> EXPO_V;
|
||
if (A & ESIGN)
|
||
exp_a = -exp_a;
|
||
}
|
||
if (mb == 0) {
|
||
return (sign_a ? 4 : 2);
|
||
} else {
|
||
exp_b = (B & EXPO) >> EXPO_V;
|
||
if (B & ESIGN)
|
||
exp_b = -exp_b;
|
||
}
|
||
|
||
/* If signs are different return differnce */
|
||
if (sign_a != sign_b)
|
||
return (sign_b ? 2 : 4);
|
||
|
||
/* Normalize both */
|
||
while((ma & NORM) == 0 && exp_a != exp_b) {
|
||
ma <<= 3;
|
||
exp_a--;
|
||
}
|
||
|
||
while((mb & NORM) == 0 && exp_a != exp_b) {
|
||
mb <<= 3;
|
||
exp_b--;
|
||
}
|
||
|
||
/* Check exponents first */
|
||
if (exp_a != exp_b) {
|
||
if (exp_b > exp_a) {
|
||
return (sign_b ? 2 : 4);
|
||
} else {
|
||
return (sign_b ? 4 : 2);
|
||
}
|
||
}
|
||
|
||
/* Exponents same, check mantissa */
|
||
if (ma != mb) {
|
||
if (mb > ma) {
|
||
return (sign_b ? 2 : 4);
|
||
} else if (mb != ma) {
|
||
return (sign_b ? 4 : 2);
|
||
}
|
||
}
|
||
|
||
/* Ok, must be identical */
|
||
return 1;
|
||
}
|
||
|
||
/* Handle addition instruction.
|
||
A & B valid. */
|
||
void add(int opcode) {
|
||
int exp_a, exp_b;
|
||
int sa, sb;
|
||
int rnd;
|
||
|
||
AB_valid();
|
||
if (opcode == WMOP_SUB) /* Subtract */
|
||
A ^= MSIGN;
|
||
AROF = 0;
|
||
X = 0;
|
||
/* Check if Either argument already zero */
|
||
if ((A & MANT) == 0) {
|
||
if ((B & MANT) == 0)
|
||
B = 0;
|
||
return;
|
||
}
|
||
if ((B & MANT) == 0) {
|
||
B = A;
|
||
return;
|
||
}
|
||
|
||
/* Extract exponent */
|
||
exp_a = (A & EXPO) >> EXPO_V;
|
||
exp_b = (B & EXPO) >> EXPO_V;
|
||
if (A & ESIGN)
|
||
exp_a = -exp_a;
|
||
if (B & ESIGN)
|
||
exp_b = -exp_b;
|
||
/* Larger exponent to A */
|
||
if (exp_b > exp_a) {
|
||
t_uint64 temp;
|
||
temp = A;
|
||
A = B;
|
||
B = temp;
|
||
sa = exp_a;
|
||
exp_a = exp_b;
|
||
exp_b = sa;
|
||
}
|
||
/* Extract signs, clear upper bits */
|
||
sa = (A & MSIGN) != 0;
|
||
A &= MANT;
|
||
sb = (B & MSIGN) != 0;
|
||
B &= MANT;
|
||
/* While the exponents are not equal, adjust */
|
||
while(exp_a != exp_b && (A & NORM) == 0) {
|
||
A <<= 3;
|
||
exp_a--;
|
||
}
|
||
while(exp_a != exp_b && B != 0) {
|
||
X |= (B & 07) << EXPO_V;
|
||
X >>= 3;
|
||
B >>= 3;
|
||
exp_b++;
|
||
}
|
||
if (exp_a != exp_b) {
|
||
exp_b = exp_a;
|
||
B = 0;
|
||
X = 0;
|
||
}
|
||
if (sa) { /* A is negative. */
|
||
A ^= FWORD;
|
||
A++;
|
||
}
|
||
if (sb) { /* B is negative */
|
||
X ^= MANT;
|
||
B ^= FWORD;
|
||
X++;
|
||
if (X & EXPO) {
|
||
B++;
|
||
X &= MANT;
|
||
}
|
||
}
|
||
B = A + B; /* Do final math. */
|
||
if (B & MSIGN) { /* Result is negative, switch */
|
||
sb = 1;
|
||
X ^= MANT;
|
||
B ^= FWORD;
|
||
X++;
|
||
if (X & EXPO) {
|
||
B++;
|
||
X &= MANT;
|
||
}
|
||
} else
|
||
sb = 0;
|
||
if (B & EXPO) { /* Handle overflow */
|
||
rnd = B & 07;
|
||
B >>= 3;
|
||
exp_b++;
|
||
} else if ((B & NORM) == 0) {
|
||
if ((X & NORM) == 0) {
|
||
rnd = 0;
|
||
} else {
|
||
X <<= 3;
|
||
B <<= 3;
|
||
B |= (X >> EXPO_V) & 07;
|
||
X &= MANT;
|
||
rnd = X >> (EXPO_V - 3);
|
||
exp_b--;
|
||
}
|
||
} else {
|
||
rnd = X >> (EXPO_V - 3);
|
||
}
|
||
if (rnd >= 4 && B != MANT) {
|
||
B++;
|
||
}
|
||
|
||
B &= MANT;
|
||
if ((exp_b != 0) && (exp_b < -64) && (B & NORM) == 0) {
|
||
B <<= 3;
|
||
exp_b--;
|
||
}
|
||
if (B == 0)
|
||
return;
|
||
if (exp_b < 0) { /* Handle underflow */
|
||
if (exp_b < -64 && NCSF)
|
||
Q |= EXPO_UNDER;
|
||
exp_b = ((-exp_b) & 077)|0100;
|
||
} else {
|
||
if (exp_b > 64 && NCSF)
|
||
Q |= EXPO_OVER;
|
||
exp_b &= 077;
|
||
}
|
||
B = (B & MANT) | ((t_uint64)(exp_b & 0177) << EXPO_V) |
|
||
((sb) ? MSIGN: 0);
|
||
}
|
||
|
||
/*
|
||
* Perform a 40 bit multiply on A and B, result into B,X
|
||
*/
|
||
void mult_step(t_uint64 a, t_uint64 *b, t_uint64 *x) {
|
||
t_uint64 u0,u1,v0,v1,t,w1,w2,w3,k;
|
||
|
||
/* Split into 32 bit and 8 bit */
|
||
u0 = a >> 32; u1 = a & 0xffffffff;
|
||
v0 = *b >> 32; v1 = *b & 0xffffffff;
|
||
/* Multiply lower halfs to 64 bits */
|
||
t = u1*v1;
|
||
/* Lower 32 bits to w3. */
|
||
w3 = t & 0xffffffff;
|
||
/* Upper 32 bits to k */
|
||
k = t >> 32;
|
||
/* Add in partial product of upper & lower */
|
||
t = u0*v1 + k;
|
||
w2 = t & 0xffffffff;
|
||
w1 = t >> 32;
|
||
t = u1*v0 + w2;
|
||
k = t >> 32;
|
||
/* Put result back together */
|
||
*b = u0*v0 + w1 + k;
|
||
*x = (t << 32) + w3;
|
||
/* Put into 2 40 bit numbers */
|
||
*b <<= 25;
|
||
*b |= (*x >> EXPO_V);
|
||
*x &= MANT;
|
||
}
|
||
|
||
/* Do multiply instruction */
|
||
void multiply() {
|
||
int exp_a, exp_b;
|
||
int f;
|
||
int int_f;
|
||
|
||
AB_valid();
|
||
AROF = 0;
|
||
/* Check if Either argument already zero */
|
||
if ((A & MANT) == 0 || (B & MANT) == 0) {
|
||
B = 0;
|
||
return;
|
||
}
|
||
|
||
/* Extract exponent */
|
||
exp_a = (A & EXPO) >> EXPO_V;
|
||
exp_b = (B & EXPO) >> EXPO_V;
|
||
if (A & ESIGN)
|
||
exp_a = -exp_a;
|
||
if (B & ESIGN)
|
||
exp_b = -exp_b;
|
||
/* Extract signs, clear upper bits */
|
||
f = (A & MSIGN) != 0;
|
||
A &= MANT;
|
||
f ^= ((B & MSIGN) != 0);
|
||
B &= MANT;
|
||
/* Flag if both exponents zero */
|
||
int_f = (exp_a == 0) & (exp_b == 0);
|
||
if (int_f == 0) {
|
||
while ((A & NORM) == 0) {
|
||
A <<= 3;
|
||
exp_a--;
|
||
}
|
||
while ((B & NORM) == 0) {
|
||
B <<= 3;
|
||
exp_b--;
|
||
}
|
||
}
|
||
|
||
mult_step(A, &B, &X);
|
||
|
||
/* If integer and B is zero */
|
||
if (int_f && B == 0) {
|
||
B = X;
|
||
X = 0;
|
||
exp_b = 0;
|
||
} else {
|
||
exp_b = exp_a + exp_b + 13;
|
||
while ((B & NORM) == 0) {
|
||
if (exp_b < -64)
|
||
break;
|
||
B <<= 3;
|
||
X <<= 3;
|
||
B |= (X >> EXPO_V) & 07;
|
||
X &= MANT;
|
||
exp_b--;
|
||
}
|
||
}
|
||
/* After B is normalize, check high order digit of X */
|
||
if (X & ROUND) {
|
||
B++;
|
||
if (B & EXPO) {
|
||
B >>= 3;
|
||
exp_b++;
|
||
}
|
||
}
|
||
/* Check for over/underflow */
|
||
if (exp_b < 0) {
|
||
if (exp_b < -64) {
|
||
if (NCSF)
|
||
Q |= EXPO_UNDER;
|
||
B = 0;
|
||
return;
|
||
}
|
||
exp_b = ((-exp_b) & 077) | 0100;
|
||
} else {
|
||
if (exp_b > 64) {
|
||
if (NCSF)
|
||
Q |= EXPO_OVER;
|
||
}
|
||
exp_b &= 077;
|
||
}
|
||
/* Put the pieces back together */
|
||
B = (B & MANT) | ((t_uint64)(exp_b & 0177) << EXPO_V) | (f? MSIGN: 0);
|
||
}
|
||
|
||
|
||
/* Do divide instruction */
|
||
void divide(int op) {
|
||
int exp_a, exp_b, q, sa, sb;
|
||
t_uint64 t;
|
||
|
||
AB_valid();
|
||
AROF = 0;
|
||
t = B;
|
||
|
||
if ((A & MANT) == 0) { /* if A mantissa is zero */
|
||
if (NCSF) /* and we're in Normal State */
|
||
Q |= DIV_ZERO;
|
||
return;
|
||
}
|
||
|
||
if ((B & MANT) == 0) { /* otherwise, if B is zero, */
|
||
A = B = 0; /* result is all zeroes */
|
||
return;
|
||
}
|
||
|
||
/* Extract exponent */
|
||
exp_a = (A & EXPO) >> EXPO_V;
|
||
exp_b = (B & EXPO) >> EXPO_V;
|
||
if (A & ESIGN)
|
||
exp_a = -exp_a;
|
||
if (B & ESIGN)
|
||
exp_b = -exp_b;
|
||
|
||
/* Extract signs, clear upper bits */
|
||
sb = (B & MSIGN) != 0;
|
||
sa = (A & MSIGN) != 0;
|
||
A &= MANT;
|
||
B &= MANT;
|
||
/* Normalize A and B */
|
||
while ((A & NORM) == 0) {
|
||
A <<= 3;
|
||
exp_a--;
|
||
}
|
||
while ((B & NORM) == 0) {
|
||
B <<= 3;
|
||
exp_b--;
|
||
}
|
||
|
||
if (op != WMOP_DIV && exp_a > exp_b) { /* Divisor has greater magnitude */
|
||
/* Quotent is < 1, so set result to zero */
|
||
A = 0;
|
||
B = (op == WMOP_RDV)? (t & FWORD) : 0;
|
||
return;
|
||
}
|
||
|
||
if (op != WMOP_RDV)
|
||
sb ^= sa; /* positive if signs are same, negative if different */
|
||
X = 0;
|
||
/* Now we step through the development of the quotient one octade at a time,
|
||
tallying the shifts in n until the high-order octade of X is non-zero
|
||
(i.e., normalized). The divisor is in ma and the dividend (which becomes
|
||
the remainder) is in mb. Since the operands are normalized, this will
|
||
take either 13 or 14 shifts. We do the X shift at the top of the loop so
|
||
that the 14th (rounding) digit will be available in q at the end.
|
||
The initial shift has no effect, as it operates using zero values for X
|
||
and q. */
|
||
do {
|
||
q = 0; /* initialize the quotient digit */
|
||
while (B >= A) {
|
||
++q; /* bump the quotient digit */
|
||
B -= A; /* subtract divisor from reAinder */
|
||
}
|
||
|
||
if (op == WMOP_DIV) {
|
||
if ((X & NORM) != 0) {
|
||
break; /* quotient has become normalized */
|
||
} else {
|
||
B <<= 3; /* shift the remainder left one octade */
|
||
X = (X<<3) + (t_uint64)q; /* shift quotient digit into the
|
||
working quotient */
|
||
--exp_b;
|
||
}
|
||
} else {
|
||
X = (X<<3) + (t_uint64)q; /* shift quotient digit into the
|
||
working quotient */
|
||
if ((X & NORM) != 0) {
|
||
break; /* quotient has become normalized */
|
||
} else if (exp_a >= exp_b) {
|
||
break;
|
||
} else {
|
||
B <<= 3; /* shift the remainder left one octade */
|
||
--exp_b; /* decrement the B exponent */
|
||
}
|
||
}
|
||
} while (1);
|
||
|
||
if (op == WMOP_DIV) {
|
||
exp_b -= exp_a - 1; /* compute the exponent, accounting for the shifts*/
|
||
|
||
/* Round the result (it's already normalized) */
|
||
if (q >= 4) { /* if high-order bit of last quotient digit is 1 */
|
||
if (X < MANT) { /* if the rounding would not cause overflow */
|
||
++X; /* round up the result */
|
||
}
|
||
}
|
||
} else if (op == WMOP_IDV) {
|
||
if (exp_a == exp_b) {
|
||
exp_b = 0; /* integer result developed */
|
||
} else {
|
||
if (NCSF) /* integer overflow result */
|
||
Q |= INT_OVER;
|
||
exp_b -= exp_a;
|
||
}
|
||
} else {
|
||
X = B; /* Result in B */
|
||
if (exp_a == exp_b) { /* integer result developed */
|
||
if (X == 0) /* if B mantissa is zero, then */
|
||
exp_b = sb = 0; /* assure result will be all zeroes */
|
||
} else {
|
||
if (NCSF) /* integer overflow result */
|
||
Q |= INT_OVER;
|
||
X = exp_b = sb = 0; /* result in B will be all zeroes */
|
||
}
|
||
}
|
||
|
||
/* Check for exponent under/overflow */
|
||
if (exp_b > 63) {
|
||
exp_b &= 077;
|
||
if (NCSF) {
|
||
Q |= EXPO_OVER;
|
||
}
|
||
} else if (exp_b < 0) {
|
||
if (exp_b < -63) {
|
||
if (NCSF)
|
||
Q |= EXPO_UNDER;
|
||
}
|
||
exp_b = ((-exp_b) & 077) | 0100;
|
||
}
|
||
|
||
/* Put the pieces back together */
|
||
B = (X & MANT) | ((t_uint64)(exp_b & 0177) << EXPO_V) | (sb? MSIGN: 0);
|
||
}
|
||
|
||
|
||
/* Double precision addition.
|
||
A & Y (not in real B5500) have operand 1.
|
||
B & X have operand 2 */
|
||
void double_add(int opcode) {
|
||
int exp_a, exp_b;
|
||
int sa, sb;
|
||
int ld;
|
||
t_uint64 temp;
|
||
|
||
AB_valid();
|
||
X = A; /* Save registers. X = H, Y=L*/
|
||
Y = B;
|
||
AROF = BROF = 0;
|
||
AB_valid(); /* Grab other operand */
|
||
temp = A; /* Oprands A,Y and B,X */
|
||
A = X;
|
||
X = B;
|
||
B = temp;
|
||
|
||
if (opcode == WMOP_DLS) /* Double Precision Subtract */
|
||
A ^= MSIGN;
|
||
/* Extract exponent */
|
||
exp_a = (A & EXPO) >> EXPO_V;
|
||
exp_b = (B & EXPO) >> EXPO_V;
|
||
if (A & ESIGN)
|
||
exp_a = -exp_a;
|
||
if (B & ESIGN)
|
||
exp_b = -exp_b;
|
||
/* Larger exponent to A */
|
||
if (exp_b > exp_a) {
|
||
t_uint64 temp;
|
||
temp = A;
|
||
A = B;
|
||
B = temp;
|
||
temp = Y;
|
||
Y = X;
|
||
X = temp;
|
||
sa = exp_a;
|
||
exp_a = exp_b;
|
||
exp_b = sa;
|
||
}
|
||
/* Extract signs, clear upper bits */
|
||
sa = (A & MSIGN) != 0;
|
||
A &= MANT;
|
||
Y &= MANT;
|
||
sb = (B & MSIGN) != 0;
|
||
B &= MANT;
|
||
X &= MANT;
|
||
ld = 0;
|
||
/* While the exponents are not equal, adjust */
|
||
while(exp_a != exp_b) {
|
||
if ((A & NORM) == 0) {
|
||
A <<= 3;
|
||
Y <<= 3;
|
||
A |= (Y >> EXPO_V) & 07;
|
||
Y &= MANT;
|
||
exp_a--;
|
||
} else {
|
||
X |= (B & 07) << EXPO_V;
|
||
ld = (X & 07);
|
||
X >>= 3;
|
||
B >>= 3;
|
||
exp_b++;
|
||
if (B == 0 && X == 0)
|
||
break;
|
||
}
|
||
}
|
||
if (exp_a != exp_b) {
|
||
exp_b = exp_a;
|
||
B = 0;
|
||
X = 0;
|
||
}
|
||
if (sa) { /* A is negative. */
|
||
Y ^= MANT;
|
||
A ^= FWORD;
|
||
Y++;
|
||
if (Y & EXPO) {
|
||
Y &= MANT;
|
||
A++;
|
||
}
|
||
}
|
||
if (sb) { /* B is negative */
|
||
X ^= MANT;
|
||
B ^= FWORD;
|
||
X++;
|
||
if (X & EXPO) {
|
||
X &= MANT;
|
||
B++;
|
||
}
|
||
}
|
||
X = Y + X;
|
||
B = A + B; /* Do final math. */
|
||
if (X & EXPO) {
|
||
B += X >> (EXPO_V);
|
||
X &= MANT;
|
||
}
|
||
|
||
if (B & MSIGN) { /* Result is negative, switch */
|
||
sb = 1;
|
||
X ^= MANT;
|
||
B ^= FWORD;
|
||
X++;
|
||
if (X & EXPO) {
|
||
X &= MANT;
|
||
B++;
|
||
}
|
||
} else {
|
||
sb = 0;
|
||
}
|
||
|
||
while (B & EXPO) { /* Handle overflow */
|
||
X |= (B & 07) << EXPO_V;
|
||
ld = X & 07;
|
||
B >>= 3;
|
||
X >>= 3;
|
||
exp_b++;
|
||
}
|
||
|
||
if (ld >= 4 && X != MANT && B != MANT) {
|
||
X++;
|
||
if (X & EXPO) {
|
||
X &= MANT;
|
||
B++;
|
||
}
|
||
}
|
||
|
||
while(exp_b > -63 && (B & NORM) == 0) {
|
||
B <<= 3;
|
||
X <<= 3;
|
||
B |= (X >> EXPO_V) & 07;
|
||
X &= MANT;
|
||
exp_b--;
|
||
}
|
||
|
||
B &= MANT;
|
||
X &= MANT;
|
||
if (exp_b < 0) { /* Handle underflow */
|
||
if (exp_b < -64 && NCSF)
|
||
Q |= EXPO_UNDER;
|
||
exp_b = ((-exp_b) & 077)|0100;
|
||
} else {
|
||
if (exp_b > 64 && NCSF)
|
||
Q |= EXPO_OVER;
|
||
exp_b &= 077;
|
||
}
|
||
A = (B & MANT) | ((t_uint64)(exp_b & 0177) << EXPO_V) |
|
||
(sb ? MSIGN: 0);
|
||
B = X;
|
||
}
|
||
|
||
/* Double precision multiply.
|
||
A & Y (not in real B5500) have operand 1.
|
||
B & X have operand 2 */
|
||
void double_mult() {
|
||
int exp_a, exp_b;
|
||
int f;
|
||
int ld;
|
||
t_uint64 m7, m6;
|
||
|
||
AB_valid();
|
||
X = A; /* Save registers. X = H, Y=L*/
|
||
Y = B;
|
||
AROF = BROF = 0;
|
||
AB_valid(); /* Grab other operand */
|
||
m7 = A; /* Oprands A,Y and B,X */
|
||
A = X;
|
||
X = B;
|
||
B = m7;
|
||
|
||
/* Extract exponent */
|
||
exp_a = (A & EXPO) >> EXPO_V;
|
||
exp_b = (B & EXPO) >> EXPO_V;
|
||
if (A & ESIGN)
|
||
exp_a = -exp_a;
|
||
if (B & ESIGN)
|
||
exp_b = -exp_b;
|
||
/* Extract signs, clear upper bits */
|
||
f = (A & MSIGN) != 0;
|
||
A &= MANT;
|
||
Y &= MANT;
|
||
f ^= ((B & MSIGN) != 0);
|
||
B &= MANT;
|
||
X &= MANT;
|
||
|
||
/* Normalize the operands */
|
||
for(ld = 0; (B & NORM) == 0 && ld < 13 ; ld++) {
|
||
B <<= 3;
|
||
B |= (X >> 36) & 07;
|
||
X <<= 3;
|
||
X &= MANT;
|
||
exp_b--;
|
||
}
|
||
|
||
for(ld = 0; (A & NORM) == 0 && ld < 13 ; ld++) {
|
||
A <<= 3;
|
||
A |= (Y >> 36) & 07;
|
||
Y <<= 3;
|
||
Y &= MANT;
|
||
exp_a--;
|
||
}
|
||
|
||
if ((X == 0 && B == 0) || (Y == 0 && A == 0)) {
|
||
A = B = 0;
|
||
return;
|
||
}
|
||
exp_b += exp_a + 13;
|
||
/* A = M3, Y = m3 */
|
||
/* B = M4, X = m4 */
|
||
/* B * Y => M6(Y),m6(m6) */
|
||
/* A * X => M7(X) m7(m7) */
|
||
/* Add m6(m7) + m7(m6) save High order digit of m7 */
|
||
/* X = M7(X) + M6(Y) */
|
||
/* A * B => Mx(B),mx(m6) */
|
||
/* Add M7 to mx => M8 + m8 */
|
||
/* Add M6 to m8 => M9(M8) + m9 */
|
||
/* M6 m6 = M4 * m3 */
|
||
mult_step(B, &Y, &m6); /* Y = M6, m6 = m6 */
|
||
/* M7 m7 = (M3 * m4) */
|
||
mult_step(A, &X, &m7); /* X = M7, m7 = m7 */
|
||
m6 += m7;
|
||
ld = m6 >> (EXPO_V-3); /* High order digit */
|
||
/* M8 m8 = (M4 * M3) */
|
||
mult_step(A, &B, &m6); /* B = M8, m6 = m8 */
|
||
/* M8 m8 = (M4 * M3) + M7 + M6 */
|
||
m6 += X + Y;
|
||
/* M9 m9 = M8 + (m8 + M6) */
|
||
/* M10m10= M9 + m9 + (high order digit of m7) */
|
||
A = B + (m6 >> EXPO_V);
|
||
B = m6 & MANT;
|
||
|
||
if ((A & EXPO) != 0) {
|
||
ld = B&7;
|
||
B |= (A & 07) << EXPO_V;
|
||
B >>= 3;
|
||
A >>= 3;
|
||
exp_b ++;
|
||
}
|
||
if ((A & NORM) == 0) {
|
||
A <<= 3;
|
||
A |= (B >> 36) & 07;
|
||
B <<= 3;
|
||
B += ld;
|
||
ld = 0;;
|
||
B &= MANT;
|
||
exp_b --;
|
||
}
|
||
if (ld >= 4 && A != MANT && B != MANT) {
|
||
B++;
|
||
if (B & EXPO) {
|
||
B &= MANT;
|
||
A++;
|
||
}
|
||
}
|
||
|
||
if (exp_b < 0) { /* Handle underflow */
|
||
if (exp_b < -64 && NCSF)
|
||
Q |= EXPO_UNDER;
|
||
exp_b = ((-exp_b) & 077)|0100;
|
||
} else {
|
||
if (exp_b > 64 && NCSF)
|
||
Q |= EXPO_OVER;
|
||
exp_b &= 077;
|
||
}
|
||
A = (A & MANT) | ((t_uint64)(exp_b & 0177) << EXPO_V) |
|
||
(f ? MSIGN: 0);
|
||
}
|
||
|
||
/* Double precision divide.
|
||
A & Y (not in real B5500) have operand 1.
|
||
B & X have operand 2 */
|
||
void double_divide() {
|
||
int exp_a, exp_b;
|
||
int f;
|
||
int n;
|
||
int q;
|
||
t_uint64 Q1, q1;
|
||
|
||
AB_valid();
|
||
X = A; /* Save registers. X = H, Y=L*/
|
||
Y = B;
|
||
AROF = BROF = 0;
|
||
AB_valid(); /* Grab other operand */
|
||
Q1 = A; /* Oprands A,Y and B,X */
|
||
A = X;
|
||
X = B;
|
||
B = Q1;
|
||
|
||
/* Extract exponent */
|
||
exp_a = (A & EXPO) >> EXPO_V;
|
||
if (A & ESIGN)
|
||
exp_a = -exp_a;
|
||
/* Extract signs, clear upper bits */
|
||
f = (A & MSIGN) != 0;
|
||
A &= MANT;
|
||
Y &= MANT;
|
||
/* Normalize A */
|
||
for(n = 0; (A & NORM) == 0 && n < 13 ; n++) {
|
||
A <<= 3;
|
||
A |= (Y >> 36) & 07;
|
||
Y <<= 3;
|
||
Y &= MANT;
|
||
exp_a--;
|
||
}
|
||
|
||
/* Extract B */
|
||
exp_b = (B & EXPO) >> EXPO_V;
|
||
if (B & ESIGN)
|
||
exp_b = -exp_b;
|
||
f ^= ((B & MSIGN) != 0);
|
||
B &= MANT;
|
||
X &= MANT;
|
||
for(n = 0; (B & NORM) == 0 && n < 13 ; n++) {
|
||
B <<= 3;
|
||
B |= (X >> 36) & 07;
|
||
X <<= 3;
|
||
X &= MANT;
|
||
exp_b--;
|
||
}
|
||
|
||
/* Check for divisor of 0 */
|
||
if ((B == 0) && (X == 0)) {
|
||
A = 0;
|
||
return;
|
||
}
|
||
|
||
/* Check for divide by 0 */
|
||
if ((A == 0) && (Y == 0)) {
|
||
if (NCSF)
|
||
Q |= DIV_ZERO;
|
||
A = B;
|
||
B = X;
|
||
return;
|
||
}
|
||
|
||
exp_b = exp_b - exp_a + 1;
|
||
/* B,X = M4,m4 A,Y = M3,m3 */
|
||
|
||
/* Divide M4,m4 by M3 resulting in Q1, R1 */
|
||
do {
|
||
q = 0; /* initialize the quotient digit */
|
||
while (B >= A) {
|
||
++q; /* bump the quotient digit */
|
||
B -= A; /* subtract divisor from reAinder */
|
||
}
|
||
|
||
B <<= 3; /* shift the remainder left one octade */
|
||
X = (X<<3) + (t_uint64)q; /* shift quotient digit into the
|
||
working quotient */
|
||
--exp_b;
|
||
n++;
|
||
} while (n < 13);
|
||
|
||
if (exp_b < 0) { /* Handle underflow */
|
||
if (exp_b < -64 && NCSF)
|
||
Q |= EXPO_UNDER;
|
||
exp_b = ((-exp_b) & 077)|0100;
|
||
} else {
|
||
if (exp_b > 64 && NCSF)
|
||
Q |= EXPO_OVER;
|
||
exp_b &= 077;
|
||
}
|
||
|
||
/* Save Q1 in x R1 in B */
|
||
Q1 = (X & MANT) | ((t_uint64)(exp_b & 0177) << EXPO_V) |
|
||
(f ? MSIGN: 0);
|
||
X = 0;
|
||
/* Now divide R1 by M3 resulting in q1, R2 */
|
||
/* A=M3, B=R1, X=q1, B=R2 */
|
||
for (n = 0; n < 13; n++) {
|
||
q = 0; /* initialize the quotient digit */
|
||
while (B >= A) {
|
||
++q; /* bump the quotient digit */
|
||
B -= A; /* subtract divisor from reAinder */
|
||
}
|
||
|
||
B <<= 3; /* shift the remainder left one octade */
|
||
X = (X<<3) + (t_uint64)q; /* shift quotient digit into the
|
||
working quotient */
|
||
}
|
||
|
||
q1 = X;
|
||
B = Y;
|
||
Y = X;
|
||
X = 0;
|
||
/* Now divide m3 by M3 resulting in q2, R3 */
|
||
/* q2 in X, R3 in B */
|
||
for (n = 0; n < 13; n++) {
|
||
q = 0; /* initialize the quotient digit */
|
||
while (B >= A) {
|
||
++q; /* bump the quotient digit */
|
||
B -= A; /* subtract divisor from reAinder */
|
||
}
|
||
|
||
B <<= 3; /* shift the remainder left one octade */
|
||
X = (X<<3) + (t_uint64)q; /* shift quotient digit into the
|
||
working quotient */
|
||
}
|
||
|
||
if (X == 0) {
|
||
A = Q1;
|
||
B = q1;
|
||
} else {
|
||
/* Load in Q1,q1 into B */
|
||
A = 01157777777777777;
|
||
Y = MANT ^ X; /* Load q2 into A */
|
||
B = Q1;
|
||
X = q1;
|
||
double_mult();
|
||
}
|
||
}
|
||
|
||
void relativeAddr(int store) {
|
||
uint16 base = R;
|
||
uint16 addr = (uint16)(A & 01777);
|
||
|
||
if (SALF) {
|
||
switch ((addr >> 7) & 7) {
|
||
case 0:
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
default: /* To avoid compiler warnings */
|
||
break;
|
||
|
||
case 4:
|
||
case 5:
|
||
addr &= 0377;
|
||
if (MSFF) {
|
||
Ma = R+7;
|
||
memory_cycle(4);
|
||
base = FF(A);
|
||
} else
|
||
base = F;
|
||
break;
|
||
|
||
case 6:
|
||
addr &= 0177;
|
||
base = (store)? R : ((L) ? C : C-1);
|
||
break;
|
||
|
||
case 7:
|
||
addr = -(addr & 0177);
|
||
if (MSFF) {
|
||
Ma = R+7;
|
||
memory_cycle(4);
|
||
base = FF(A);
|
||
} else
|
||
base = F;
|
||
break;
|
||
}
|
||
}
|
||
Ma = (base + addr) & CORE;
|
||
}
|
||
|
||
t_stat
|
||
sim_instr(void)
|
||
{
|
||
t_stat reason;
|
||
t_uint64 temp = 0LL;
|
||
uint16 atemp;
|
||
uint8 opcode;
|
||
uint8 field;
|
||
int bit_a;
|
||
int bit_b;
|
||
int f;
|
||
int i;
|
||
int j;
|
||
|
||
reason = SCPE_OK;
|
||
hltf[0] = 0;
|
||
hltf[1] = 0;
|
||
P1_run = 1;
|
||
|
||
while (reason == 0) { /* loop until halted */
|
||
if (P1_run == 0)
|
||
return SCPE_STOP;
|
||
/* System is booting, wait until finished loading */
|
||
while (loading) {
|
||
reason = sim_process_event();
|
||
if (reason != SCPE_OK)
|
||
break; /* process */
|
||
sim_interval--;
|
||
}
|
||
/* Passed time quantum */
|
||
if (sim_interval <= 0) { /* event queue? */
|
||
reason = sim_process_event();
|
||
if (reason != SCPE_OK)
|
||
break; /* process */
|
||
}
|
||
|
||
if (sim_brk_summ) {
|
||
if(sim_brk_test((C << 3) | L, SWMASK('E'))) {
|
||
reason = SCPE_STOP;
|
||
break;
|
||
}
|
||
|
||
if (sim_brk_test((c_reg[0] << 3) | l_reg[0],
|
||
SWMASK('A'))) {
|
||
reason = SCPE_STOP;
|
||
break;
|
||
}
|
||
|
||
if (sim_brk_test((c_reg[1] << 3) | l_reg[1],
|
||
SWMASK('B'))) {
|
||
reason = SCPE_STOP;
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Toggle between two CPU's. */
|
||
if (TROF == 0 && NCSF) {
|
||
if (Q != 0 || ((cpu_index)? HLTF : IAR) != 0)
|
||
storeInterrupt(1,0);
|
||
}
|
||
|
||
if (cpu_index == 0 && P2_run == 1) {
|
||
cpu_index = 1;
|
||
} else {
|
||
cpu_index = 0;
|
||
}
|
||
if (TROF == 0)
|
||
next_prog();
|
||
|
||
crf_loop:
|
||
opcode = T & 077;
|
||
field = (T >> 6) & 077;
|
||
TROF = 0;
|
||
|
||
if (hst_lnt) { /* history enabled? */
|
||
/* Ignore idle loop when recording history */
|
||
/* DCMCP XIII */
|
||
/* if ((C & 077774) != 01140) { */
|
||
/* DCMCP XV */
|
||
/* if ((C & 077774) != 01254) { */
|
||
/* TSMCP XV */
|
||
/* if ((C & 077774) != 01324) { */
|
||
hst_p = (hst_p + 1); /* next entry */
|
||
if (hst_p >= hst_lnt) {
|
||
hst_p = 0;
|
||
}
|
||
hst[hst_p].c = (C) | HIST_PC;
|
||
hst[hst_p].op = T;
|
||
hst[hst_p].s = S;
|
||
hst[hst_p].f = F;
|
||
hst[hst_p].r = R;
|
||
hst[hst_p].ma = Ma;
|
||
hst[hst_p].a_reg = A;
|
||
hst[hst_p].b_reg = B;
|
||
hst[hst_p].x_reg = X;
|
||
hst[hst_p].gh = GH;
|
||
hst[hst_p].kv = KV;
|
||
hst[hst_p].l = L;
|
||
hst[hst_p].q = Q;
|
||
hst[hst_p].cpu = cpu_index;
|
||
hst[hst_p].iar = IAR;
|
||
hst[hst_p].flags = ((AROF)? F_AROF : 0) | \
|
||
((BROF)? F_BROF : 0) | \
|
||
((CWMF)? F_CWMF : 0) | \
|
||
((NCSF)? F_NCSF : 0) | \
|
||
((SALF)? F_SALF : 0) | \
|
||
((MSFF)? F_MSFF : 0) | \
|
||
((VARF)? F_VARF : 0);
|
||
/* } */
|
||
}
|
||
|
||
/* Check if Character or Word Mode */
|
||
if (CWMF) {
|
||
/* Character mode source word in A
|
||
addressed by M,G,H.
|
||
destination in B
|
||
addressed by S,K,V.
|
||
R = tally.
|
||
X = loop control.
|
||
F = return control word
|
||
*/
|
||
switch(opcode) {
|
||
case CMOP_EXC: /* EXIT char mode */
|
||
if (BROF) {
|
||
memory_cycle(013);
|
||
}
|
||
S = F;
|
||
AROF = 0;
|
||
memory_cycle(3); /* Load B from S */
|
||
if ((B & FLAG) == 0) {
|
||
if (NCSF)
|
||
Q |= FLAG_BIT;
|
||
break;
|
||
}
|
||
f = set_via_RCW(B, (field & 1), 0);
|
||
S = F;
|
||
memory_cycle(3); /* Load MSW from S to B */
|
||
set_via_MSCW(B);
|
||
prev_addr(S);
|
||
CWMF = 0;
|
||
if (MSFF && SALF) {
|
||
Ma = F;
|
||
do {
|
||
/* B = M[FIELD], Ma = B[FIELD]; */
|
||
memory_cycle(6); /* Grab previous MCSW */
|
||
} while(B & SMSFF);
|
||
Ma = R | 7;
|
||
memory_cycle(015); /* Store B in Ma */
|
||
}
|
||
BROF = 0;
|
||
X = 0;
|
||
if ((field & 1) == 0)
|
||
PROF = 0;
|
||
break;
|
||
|
||
case CMOP_BSD: /* Skip Bit Destiniation */
|
||
if (BROF) {
|
||
memory_cycle(013);
|
||
}
|
||
while(field > 0) {
|
||
field--;
|
||
next_dest(1);
|
||
}
|
||
break;
|
||
|
||
case CMOP_SRS: /* Skip Reverse Source */
|
||
adjust_source();
|
||
while(field > 0) {
|
||
field--;
|
||
prev_src(0);
|
||
}
|
||
break;
|
||
|
||
case CMOP_SFS: /* Skip Forward Source */
|
||
adjust_source();
|
||
while(field > 0) {
|
||
field--;
|
||
next_src(0);
|
||
}
|
||
break;
|
||
|
||
case CMOP_BSS: /* SKip Bit Source */
|
||
while(field > 0) {
|
||
field--;
|
||
next_src(1);
|
||
}
|
||
break;
|
||
|
||
case CMOP_SFD: /* Skip Forward Destination */
|
||
adjust_dest();
|
||
while(field > 0) {
|
||
field--;
|
||
next_dest(0);
|
||
}
|
||
break;
|
||
|
||
case CMOP_SRD: /* Skip Reverse Destination */
|
||
adjust_dest();
|
||
while(field > 0) {
|
||
field--;
|
||
prev_dest(0);
|
||
}
|
||
break;
|
||
|
||
case CMOP_RSA: /* Recall Source Address */
|
||
Ma = (F - field) & CORE;
|
||
memory_cycle(4);
|
||
AROF = 0;
|
||
Ma = CF(A);
|
||
GH = 0;
|
||
if ((A & FLAG) == 0)
|
||
GH = (A >> 12) & 070;
|
||
else if ((A & PRESENT) == 0 && NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
|
||
case CMOP_RDA: /* Recall Destination Address */
|
||
if (BROF)
|
||
memory_cycle(013);
|
||
S = (F - field) & CORE;
|
||
memory_cycle(3);
|
||
BROF = 0;
|
||
S = CF(B);
|
||
KV = 0;
|
||
if ((B & FLAG) == 0)
|
||
KV = (B >> 12) & 070;
|
||
else if ((B & PRESENT) == 0 && NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
|
||
case CMOP_RCA: /* Recall Control Address */
|
||
AROF = BROF;
|
||
A = B; /* Save B temporarly */
|
||
atemp = S; /* Save S */
|
||
S = (F - field) & CORE;
|
||
memory_cycle(3);/* Load word in B */
|
||
S = atemp; /* Restore S */
|
||
if (B & FLAG) {
|
||
if ((B & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
} else {
|
||
C = CF(B);
|
||
L = 0;
|
||
}
|
||
} else {
|
||
C = CF(B);
|
||
L = LF(B) + 1;
|
||
if (L > 3) {
|
||
L = 0;
|
||
next_addr(C);
|
||
}
|
||
}
|
||
B = A;
|
||
BROF = AROF;
|
||
AROF = 0;
|
||
PROF = 0;
|
||
break;
|
||
|
||
case CMOP_SED: /* Set Destination Address */
|
||
if (BROF)
|
||
memory_cycle(013);
|
||
S = (F - field) & CORE;
|
||
KV = 0;
|
||
BROF = 0;
|
||
break;
|
||
|
||
case CMOP_SES: /* Set Source Address */
|
||
Ma = (F - field) & CORE;
|
||
GH = 0;
|
||
AROF = 0;
|
||
break;
|
||
|
||
case CMOP_TSA: /* Transfer Source Address */
|
||
if (BROF)
|
||
memory_cycle(013);
|
||
BROF = 0;
|
||
adjust_source();
|
||
field = 3;
|
||
while(field > 0) {
|
||
fill_src();
|
||
i = (A >> bit_number[GH | 07]) & 077;
|
||
B <<= 6;
|
||
B |= i;
|
||
next_src(0);
|
||
field--;
|
||
}
|
||
B &= FLAG|FWORD;
|
||
GH = (uint8)((B >> 12) & 070);
|
||
Ma = CF(B);
|
||
break;
|
||
|
||
case CMOP_TDA: /* Transfer Destination Address */
|
||
if (BROF)
|
||
memory_cycle(013);
|
||
BROF = 0;
|
||
adjust_dest();
|
||
field = 3;
|
||
temp = 0;
|
||
while(field > 0) {
|
||
fill_dest();
|
||
i = (B >> bit_number[KV | 07]) & 077;
|
||
temp <<= 6;
|
||
temp |= i;
|
||
next_dest(0);
|
||
field--;
|
||
}
|
||
BROF = 0;
|
||
KV = (uint8)((temp >> 12) & 070);
|
||
S = CF(temp);
|
||
break;
|
||
|
||
case CMOP_SCA: /* Store Control Address */
|
||
A = B;
|
||
AROF = BROF;
|
||
B = toF(F) | toL(L) | toC(C);
|
||
F = S;
|
||
S = FF(B);
|
||
S = (S - field) & CORE;
|
||
memory_cycle(013); /* Store B in S */
|
||
S = F;
|
||
F = FF(B);
|
||
B = A;
|
||
BROF = AROF;
|
||
AROF = 0;
|
||
break;
|
||
|
||
case CMOP_SDA: /* Store Destination Address */
|
||
adjust_dest();
|
||
A = B;
|
||
AROF = BROF;
|
||
B = ((t_uint64)(KV & 070) << (FFIELD_V - 3)) | toC(S);
|
||
atemp = S;
|
||
S = (F - field) & CORE;
|
||
memory_cycle(013); /* Store B in S */
|
||
S = atemp;
|
||
B = A;
|
||
BROF = AROF;
|
||
AROF = 0;
|
||
break;
|
||
|
||
case CMOP_SSA: /* Store Source Address */
|
||
adjust_source();
|
||
A = B;
|
||
AROF = BROF;
|
||
B = ((t_uint64)(GH & 070) << (FFIELD_V - 3)) | toC(Ma);
|
||
atemp = Ma;
|
||
Ma = (F - field) & CORE;
|
||
memory_cycle(015); /* Store B in Ma */
|
||
Ma = atemp;
|
||
B = A;
|
||
BROF = AROF;
|
||
AROF = 0;
|
||
break;
|
||
|
||
case CMOP_TRW: /* Transfer Words */
|
||
if (BROF) {
|
||
memory_cycle(013);
|
||
BROF = 0;
|
||
}
|
||
if (GH != 0) {
|
||
next_addr(Ma);
|
||
GH = 0;
|
||
AROF = 0;
|
||
}
|
||
if (KV != 0) {
|
||
next_addr(S);
|
||
KV = 0;
|
||
}
|
||
while(field > 0) {
|
||
field--;
|
||
memory_cycle(4);
|
||
memory_cycle(012);
|
||
next_addr(Ma);
|
||
next_addr(S);
|
||
}
|
||
BROF = 0;
|
||
AROF = 0;
|
||
break;
|
||
|
||
case CMOP_TEQ: /* Test for Equal 24 */
|
||
case CMOP_TNE: /* Test for Not-Equal 25 */
|
||
case CMOP_TEG: /* Test for Greater Or Equal 26 */
|
||
case CMOP_TGR: /* Test For Greater 27 */
|
||
case CMOP_TEL: /* Test For Equal or Less 34 */
|
||
case CMOP_TLS: /* Test For Less 35 */
|
||
case CMOP_TAN: /* Test for Alphanumeric 36 */
|
||
adjust_source();
|
||
fill_src();
|
||
i = rank[(A >> bit_number[GH | 07]) & 077];
|
||
j = rank[field];
|
||
if (i == j)
|
||
f = 1;
|
||
else if (i < j)
|
||
f = 2;
|
||
else
|
||
f = 4;
|
||
switch(opcode) {
|
||
case CMOP_TEQ: /* Test for Equal 24 */
|
||
TFFF = (f == 1); break;
|
||
case CMOP_TNE: /* Test for Not-Equal 25 */
|
||
TFFF = (f != 1); break;
|
||
case CMOP_TEG: /* Test for Greater Or Equal 26 */
|
||
TFFF = ((f & 5) != 0); break;
|
||
case CMOP_TGR: /* Test For Greater 27 */
|
||
TFFF = (f == 4); break;
|
||
case CMOP_TEL: /* Test For Equal or Less 34 */
|
||
TFFF = ((f & 3) != 0); break;
|
||
case CMOP_TLS: /* Test For Less 35 */
|
||
TFFF = (f == 2); break;
|
||
case CMOP_TAN: /* Test for Alphanumeric 36 */
|
||
if (f & 4) {
|
||
TFFF = !((i == 34) | (i == 44));
|
||
} else {
|
||
TFFF = f & 1;
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CMOP_BIS: /* Set Bit */
|
||
case CMOP_BIR: /* Reet Bit */
|
||
while(field > 0) {
|
||
field--;
|
||
fill_dest();
|
||
temp = bit_mask[bit_number[KV]];
|
||
if (opcode & 1)
|
||
B &= ~temp;
|
||
else
|
||
B |= temp;
|
||
next_dest(1);
|
||
}
|
||
break;
|
||
|
||
case CMOP_BIT: /* Test Bit */
|
||
fill_src();
|
||
i = (A >> bit_number[GH]) & 01;
|
||
TFFF = (i == (field & 1));
|
||
break;
|
||
|
||
case CMOP_INC: /* Increase Tally */
|
||
R = (R + (field<<6)) & 07700;
|
||
break;
|
||
|
||
case CMOP_STC: /* Store Tally */
|
||
if (BROF)
|
||
memory_cycle(11);
|
||
AROF = 0;
|
||
BROF = 0;
|
||
A = toC(F);
|
||
B = R >> 6;
|
||
F = S;
|
||
S = CF(A);
|
||
S = (S - field) & CORE;
|
||
memory_cycle(11);
|
||
S = F;
|
||
F = CF(A);
|
||
break;
|
||
|
||
case CMOP_SEC: /* Set Tally */
|
||
R = T & 07700;
|
||
break;
|
||
|
||
case CMOP_CRF: /* Call repeat Field */
|
||
/* Save B in A */
|
||
AROF = BROF;
|
||
A = B;
|
||
/* Save F in B */
|
||
atemp = F;
|
||
/* Exchange S & F */
|
||
F = S;
|
||
/* Decrement S */
|
||
S = (atemp - field) & CORE;
|
||
/* Read value to B, S <= F, F <= B */
|
||
memory_cycle(3);
|
||
/* field = B & 077 */
|
||
field = B & 077;
|
||
/* Restore B */
|
||
S = F;
|
||
F = atemp;
|
||
B = A;
|
||
BROF = AROF;
|
||
AROF = 0;
|
||
/* fetch_next; */
|
||
next_prog();
|
||
/* If field == 0, opcode |= 4; field = T */
|
||
if (field == 0) {
|
||
T &= 07700;
|
||
T |= CMOP_JFW;
|
||
} else {
|
||
T &= 077;
|
||
T |= field << 6;
|
||
}
|
||
/* Goto crf_loop */
|
||
goto crf_loop;
|
||
|
||
case CMOP_JNC: /* Jump Out Of Loop Conditional */
|
||
if (TFFF)
|
||
break;
|
||
|
||
/* Fall through */
|
||
case CMOP_JNS: /* Jump out of loop unconditional */
|
||
/* Read Loop/Return control word */
|
||
atemp = S;
|
||
S = FF(X);
|
||
memory_cycle(2); /* Load S to A */
|
||
AROF = 0;
|
||
X = (A & MANT);
|
||
S = atemp;
|
||
if (field > 0) {
|
||
i = (C << 2) | L; /* Make into syllable pointer */
|
||
i += field;
|
||
L = i & 3; /* Convert back to pointer */
|
||
C = (i >> 2) & CORE;
|
||
PROF = 0;
|
||
}
|
||
break;
|
||
|
||
case CMOP_JFC: /* Jump Forward Conditional */
|
||
case CMOP_JRC: /* Jump Reverse Conditional */
|
||
if (TFFF != 0)
|
||
break;
|
||
|
||
/* Fall through */
|
||
case CMOP_JFW: /* Jump Forward Unconditional */
|
||
case CMOP_JRV: /* Jump Reverse Unconditional */
|
||
i = (C << 2) | L; /* Make into syllable pointer */
|
||
if (opcode & 010) { /* Forward */
|
||
i -= field;
|
||
} else { /* Backward */
|
||
i += field;
|
||
}
|
||
L = i & 3; /* Convert back to pointer */
|
||
C = (i >> 2) & CORE;
|
||
PROF = 0;
|
||
break;
|
||
|
||
case CMOP_ENS: /* End Loop */
|
||
A = B;
|
||
AROF = BROF;
|
||
B = X;
|
||
field = (uint8)((B & REPFLD) >> REPFLD_V);
|
||
if (field) {
|
||
X &= ~REPFLD;
|
||
X |= ((t_uint64)(field - 1) << REPFLD_V) & REPFLD;
|
||
L = LF(B);
|
||
C = CF(B);
|
||
PROF = 0;
|
||
memory_cycle(020);
|
||
} else {
|
||
atemp = S;
|
||
S = FF(X);
|
||
memory_cycle(3); /* Load B */
|
||
X = B & MANT;
|
||
S = atemp;
|
||
}
|
||
B = A;
|
||
BROF = AROF;
|
||
AROF = 0;
|
||
break;
|
||
|
||
case CMOP_BNS: /* Begin Loop */
|
||
A = B; /* Save B */
|
||
AROF = BROF;
|
||
B = X | FLAG | DFLAG;
|
||
if (field != 0)
|
||
field--;
|
||
atemp = S;
|
||
S = FF(B);
|
||
next_addr(S);
|
||
memory_cycle(013);
|
||
X = LCW(S, field);
|
||
S = atemp;
|
||
B = A;
|
||
BROF = AROF;
|
||
AROF = 0;
|
||
break;
|
||
|
||
case CMOP_OCV: /* Output Convert */
|
||
adjust_dest();
|
||
if (BROF) {
|
||
memory_cycle(013);
|
||
BROF = 0;
|
||
}
|
||
/* Adjust source to word boundry */
|
||
if (GH) {
|
||
GH = 0;
|
||
next_addr(Ma);
|
||
AROF = 0;
|
||
}
|
||
|
||
if (field == 0)
|
||
break;
|
||
|
||
/* Load word into A */
|
||
fill_src();
|
||
next_addr(Ma);
|
||
AROF = 0;
|
||
B = 0;
|
||
temp = 0;
|
||
f = (A & MSIGN) != 0;
|
||
TFFF = 1;
|
||
A &= MANT;
|
||
if (A == 0)
|
||
f = 0;
|
||
i = 39;
|
||
/* We loop over the bit in A and add one to B
|
||
each time we have the msb of A set. For each
|
||
step we BCD double the number in B */
|
||
while(i > 0) {
|
||
/* Compute carry to next digit */
|
||
temp = (B + 0x33333333LL) & 0x88888888LL;
|
||
B <<= 1; /* Double it */
|
||
/* Add 6 from every digit that overflowed */
|
||
temp = (temp >> 1) | (temp >> 2);
|
||
B += temp;
|
||
/* Lastly Add in new digit */
|
||
j = (A & ROUND) != 0;
|
||
A &= ~ROUND;
|
||
B += (t_uint64)j;
|
||
A <<= 1;
|
||
i--;
|
||
}
|
||
A = B;
|
||
field = field & 07;
|
||
if (field == 0)
|
||
field = 8;
|
||
/* Now we put each digit into the destination string */
|
||
for(i = 8; i >= 0; i--) {
|
||
j = (A >> (i * 4)) & 0xF;
|
||
if (i >= field) {
|
||
if (j != 0)
|
||
TFFF = 0;
|
||
} else {
|
||
fill_dest();
|
||
temp = 077LL << bit_number[KV | 07];
|
||
B &= ~temp;
|
||
if (i == 0 && f)
|
||
j |= 040;
|
||
B |= ((t_uint64)j) << bit_number[KV | 07];
|
||
BROF = 1;
|
||
next_dest(0);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case CMOP_ICV: /* Input Convert */
|
||
adjust_source();
|
||
if (BROF) {
|
||
memory_cycle(013);
|
||
BROF = 0;
|
||
}
|
||
/* Align result to word boundry */
|
||
if (KV) {
|
||
KV = 0;
|
||
next_addr(S);
|
||
}
|
||
|
||
if (field == 0)
|
||
break;
|
||
B = 0;
|
||
temp = 0;
|
||
f = 0;
|
||
/* Collect the source field into a string of BCD digits */
|
||
while(field > 0) {
|
||
fill_src();
|
||
i = (int)(A >> bit_number[GH | 07]);
|
||
B = (B << 4) | (i & 017);
|
||
f = (i & 060) == 040; /* Keep sign */
|
||
field = (field - 1) & 07;
|
||
next_src(0);
|
||
}
|
||
/* We loop over the BCD number in B, dividing it by 2
|
||
each cycle, while shifting the lsb into the top of
|
||
the A register */
|
||
field = 28;
|
||
A = 0;
|
||
while(field > 0) {
|
||
A >>= 1;
|
||
if (B & 1)
|
||
A |= ((t_uint64)1) << 27;
|
||
/* BCD divide by 2 */
|
||
temp = B & 0x0011111110LL;
|
||
temp = (temp >> 4) | (temp >> 3);
|
||
B = (B >> 1) - temp;
|
||
field--;
|
||
}
|
||
if (f && A != 0)
|
||
A |= MSIGN;
|
||
memory_cycle(012);
|
||
AROF = 0;
|
||
next_addr(S);
|
||
break;
|
||
|
||
case CMOP_CEQ: /* Compare Equal 60 */
|
||
case CMOP_CNE: /* COmpare for Not Equal 61 */
|
||
case CMOP_CEG: /* Compare For Greater Or Equal 62 */
|
||
case CMOP_CGR: /* Compare For Greater 63 */
|
||
case CMOP_CEL: /* Compare For Equal or Less 70 */
|
||
case CMOP_CLS: /* Compare for Less 71 */
|
||
case CMOP_FSU: /* Field Subtract 72 */
|
||
case CMOP_FAD: /* Field Add 73 */
|
||
adjust_source();
|
||
adjust_dest();
|
||
TFFF = 1; /* flag to show greater */
|
||
f = 1; /* Still comparaing */
|
||
while(field > 0) {
|
||
fill_src();
|
||
fill_dest();
|
||
if (f) {
|
||
i = (A >> bit_number[GH | 07]) & 077;
|
||
j = (B >> bit_number[KV | 07]) & 077;
|
||
if (i != j) {
|
||
switch(opcode) {
|
||
case CMOP_FSU: /* Field Subtract */
|
||
case CMOP_FAD: /* Field Add */
|
||
/* Do numeric compare */
|
||
i &= 017;
|
||
j &= 017;
|
||
if (i != j)
|
||
f = 0; /* Different, so stop check */
|
||
if (i < j)
|
||
TFFF = 0;
|
||
break;
|
||
case CMOP_CEQ: /* Compare Equal 60 */
|
||
case CMOP_CNE: /* Compare for Not Equal 61 */
|
||
case CMOP_CEG: /* Compare For Greater Or Equal 62 */
|
||
case CMOP_CGR: /* Compare For Greater 63 */
|
||
case CMOP_CEL: /* Compare For Equal or Less 70 */
|
||
case CMOP_CLS: /* Compare for Less 71 */
|
||
f = 0; /* No need to continue; */
|
||
if (rank[i] < rank[j])
|
||
TFFF = 0;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
next_src(0);
|
||
next_dest(0);
|
||
field--;
|
||
}
|
||
/* If F = 1, fields are equal.
|
||
If F = 0 and TFFF = 0 S < D.
|
||
If F = 0 and TFFF = 1 S > D.
|
||
*/
|
||
switch(opcode) {
|
||
case CMOP_FSU: /* Field Subtract */
|
||
case CMOP_FAD: /* Field Add */
|
||
{
|
||
int ss, sd, sub;
|
||
int c;
|
||
/* Back up one location */
|
||
prev_src(0);
|
||
prev_dest(0);
|
||
fill_src();
|
||
fill_dest();
|
||
field = (T >> 6) & 077;
|
||
i = (A >> bit_number[GH | 07]) & 077;
|
||
j = (B >> bit_number[KV | 07]) & 077;
|
||
/* Compute Sign */
|
||
ss = (i & 060) == 040; /* S */
|
||
sd = (j & 060) == 040; /* D */
|
||
sub = (ss == sd) ^ (opcode == CMOP_FAD);
|
||
/*
|
||
ss sd sub f=1 TFFF=0 TFFF=1
|
||
add 0 0 0 0 0 0
|
||
add 1 0 1 0 0 1
|
||
add 0 1 1 0 1 0
|
||
add 1 1 0 1 1 1
|
||
sub 0 0 1 0 0 1
|
||
sub 1 0 0 0 0 0
|
||
sub 0 1 0 1 1 1
|
||
sub 1 1 1 0 1 0
|
||
*/
|
||
f = (f & sd & ss & (!sub)) |
|
||
(f & sd & (!ss) & (!sub)) |
|
||
((!f) & (!TFFF) & sd) |
|
||
((!f) & TFFF & (ss ^ (opcode == CMOP_FSU)));
|
||
c = 0;
|
||
if (sub) {
|
||
c = 1;
|
||
if (TFFF) { /* If S < D */
|
||
ss = 0;
|
||
sd = 1;
|
||
} else {
|
||
ss = 1;
|
||
sd = 0;
|
||
}
|
||
} else {
|
||
sd = ss = 0;
|
||
}
|
||
/* Do the bulk of adding. */
|
||
i &= 017;
|
||
j &= 017;
|
||
while (field > 0) {
|
||
i = (ss ? 9-i : i ) + (sd ? 9-j : j) + c;
|
||
if (i < 10) {
|
||
c = 0;
|
||
} else {
|
||
c = 1;
|
||
i -= 10;
|
||
}
|
||
if (f) {
|
||
i += 040;
|
||
f = 0;
|
||
}
|
||
temp = 077LL << bit_number[KV | 07];
|
||
B &= ~temp;
|
||
B |= ((t_uint64)i) << bit_number[KV | 07];
|
||
prev_src(0);
|
||
prev_dest(0);
|
||
fill_src();
|
||
fill_dest();
|
||
i = (A >> bit_number[GH | 07]) & 017;
|
||
j = (B >> bit_number[KV | 07]) & 017;
|
||
field--;
|
||
}
|
||
/* Set overflow flag */
|
||
TFFF = sub ^ c;
|
||
}
|
||
/* Lastly back to end of field. */
|
||
field = (T >> 6) & 077;
|
||
next_src(0);
|
||
next_dest(0);
|
||
while (field > 0) {
|
||
next_src(0);
|
||
next_dest(0);
|
||
field--;
|
||
}
|
||
break;
|
||
case CMOP_CEQ: /* Compare Equal 60 */
|
||
TFFF = f;
|
||
break;
|
||
case CMOP_CNE: /* Compare for Not Equal 61 */
|
||
TFFF = !f;
|
||
break;
|
||
case CMOP_CEG: /* Compare For Greater Or Equal 62 */
|
||
TFFF |= f;
|
||
break;
|
||
case CMOP_CGR: /* Compare For Greater 63 */
|
||
TFFF &= !f;
|
||
break;
|
||
case CMOP_CEL: /* Compare For Equal or Less 70 */
|
||
TFFF = !TFFF;
|
||
TFFF |= f;
|
||
break;
|
||
case CMOP_CLS: /* Compare for Less 71 */
|
||
TFFF = !TFFF;
|
||
TFFF &= !f;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case CMOP_TRP: /* Transfer Program Characters 74 */
|
||
adjust_dest();
|
||
while(field > 0) {
|
||
fill_dest();
|
||
if (!TROF)
|
||
next_prog();
|
||
if (field & 1) {
|
||
i = T & 077;
|
||
TROF = 0;
|
||
} else {
|
||
i = (T >> 6) & 077;
|
||
}
|
||
temp = 077LL << bit_number[KV | 07];
|
||
B &= ~temp;
|
||
B |= ((t_uint64)i) << bit_number[KV | 07];
|
||
next_dest(0);
|
||
field--;
|
||
}
|
||
TROF = 0;
|
||
break;
|
||
|
||
case CMOP_TRN: /* Transfer Numeric 75 */
|
||
case CMOP_TRZ: /* Transfer Zones 76 */
|
||
case CMOP_TRS: /* Transfer Source Characters 77 */
|
||
adjust_source();
|
||
adjust_dest();
|
||
while(field > 0) {
|
||
fill_dest();
|
||
fill_src();
|
||
i = (int)(A >> bit_number[GH | 07]);
|
||
if (opcode == CMOP_TRS) {
|
||
i &= 077;
|
||
temp = 077LL << bit_number[KV | 07];
|
||
} else if (opcode == CMOP_TRN) {
|
||
if (field == 1) {
|
||
if ((i & 060) == 040)
|
||
TFFF = 1;
|
||
else
|
||
TFFF = 0;
|
||
}
|
||
i &= 017;
|
||
temp = 077LL << bit_number[KV | 07];
|
||
} else {
|
||
i &= 060;
|
||
temp = 060LL << bit_number[KV | 07];
|
||
}
|
||
B &= ~temp;
|
||
B |= ((t_uint64)i) << bit_number[KV | 07];
|
||
next_src(0);
|
||
next_dest(0);
|
||
field--;
|
||
}
|
||
break;
|
||
|
||
case CMOP_TBN: /* Transfer Blanks for Non-Numerics 12 */
|
||
adjust_dest();
|
||
TFFF = 1;
|
||
while(field > 0) {
|
||
fill_dest();
|
||
i = (B >> bit_number[KV | 07]) & 077;
|
||
if (i > 0 && i <= 9) {
|
||
TFFF = 0;
|
||
break;
|
||
}
|
||
B &= ~(077LL << bit_number[KV | 07]);
|
||
B |= 060LL << bit_number[KV | 07];
|
||
next_dest(0);
|
||
field--;
|
||
}
|
||
break;
|
||
|
||
case 0011:
|
||
goto control;
|
||
}
|
||
} else {
|
||
/* Word mode opcodes */
|
||
switch(opcode & 03) {
|
||
case WMOP_LITC: /* Load literal */
|
||
A_empty();
|
||
A = toC(T >> 2);
|
||
AROF = 1;
|
||
break;
|
||
|
||
case WMOP_OPDC: /* Load operand */
|
||
A_empty();
|
||
A = toC(T >> 2);
|
||
relativeAddr(0);
|
||
memory_cycle(4);
|
||
SALF |= VARF;
|
||
VARF = 0;
|
||
opdc:
|
||
if (A & FLAG) {
|
||
/* Check if it is a control word. */
|
||
if ((A & DFLAG) != 0 && (A & PROGF) == 0) {
|
||
break;
|
||
}
|
||
/* Check if descriptor present */
|
||
if ((A & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
/* Program Descriptor */
|
||
if ((A & (DFLAG|PROGF)) == (DFLAG|PROGF)) {
|
||
enterSubr(0);
|
||
} else {
|
||
if (indexWord())
|
||
break;
|
||
memory_cycle(4);
|
||
if (NCSF && (A & FLAG))
|
||
Q |= FLAG_BIT;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case WMOP_DESC: /* Load Descriptor */
|
||
A_empty();
|
||
A = toC(T >> 2);
|
||
relativeAddr(0);
|
||
memory_cycle(4);
|
||
SALF |= VARF;
|
||
VARF = 0;
|
||
desc:
|
||
if (A & FLAG) {
|
||
/* Check if it is a control word. */
|
||
if ((A & DFLAG) != 0 && (A & PROGF) == 0) {
|
||
A = FLAG | PRESENT | toC(Ma);
|
||
break;
|
||
}
|
||
/* Check if descriptor present */
|
||
if ((A & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
/* Data descriptor */
|
||
if ((A & (DFLAG|PROGF)) == (DFLAG|PROGF)) {
|
||
enterSubr(1);
|
||
} else {
|
||
if (indexWord())
|
||
break;
|
||
A |= FLAG | PRESENT;
|
||
}
|
||
} else {
|
||
A = FLAG | PRESENT | toC(Ma);
|
||
}
|
||
break;
|
||
|
||
case WMOP_OPR: /* All other operators */
|
||
switch(opcode) {
|
||
case 0001:
|
||
switch(field) {
|
||
case VARIANT(WMOP_SUB): /* Subtract */
|
||
case VARIANT(WMOP_ADD): /* Add */
|
||
add(T);
|
||
break;
|
||
case VARIANT(WMOP_MUL): /* Multiply */
|
||
multiply();
|
||
break;
|
||
case VARIANT(WMOP_DIV): /* Divide */
|
||
case VARIANT(WMOP_IDV): /* Integer Divide Integer */
|
||
case VARIANT(WMOP_RDV): /* Remainder Divide */
|
||
divide(T);
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 0005:
|
||
switch(field) {
|
||
case VARIANT(WMOP_DLS): /* Double Precision Subtract */
|
||
case VARIANT(WMOP_DLA): /* Double Precision Add */
|
||
double_add(T);
|
||
break;
|
||
case VARIANT(WMOP_DLM): /* Double Precision Multiply */
|
||
double_mult();
|
||
break;
|
||
case VARIANT(WMOP_DLD): /* Double Precision Divide */
|
||
double_divide();
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 0011:
|
||
/* Control functions same as Character mode,
|
||
although most operators do not make sense in
|
||
Character mode. */
|
||
control:
|
||
switch(field) {
|
||
/* Different in Character mode */
|
||
case VARIANT(WMOP_SFT): /* Store for Test */
|
||
storeInterrupt(0,1);
|
||
break;
|
||
|
||
case VARIANT(WMOP_SFI): /* Store for Interrupt */
|
||
storeInterrupt(0,0);
|
||
break;
|
||
|
||
case VARIANT(WMOP_ITI): /* Interrogate interrupt */
|
||
if (NCSF) /* Nop in normal state */
|
||
break;
|
||
|
||
if (q_reg[0] & MEM_PARITY) {
|
||
C = PARITY_ERR;
|
||
q_reg[0] &= ~MEM_PARITY;
|
||
} else if (q_reg[0] & INVALID_ADDR) {
|
||
C = INVADR_ERR;
|
||
q_reg[0] &= ~INVALID_ADDR;
|
||
} else if (IAR) {
|
||
uint16 x;
|
||
C = INTER_TIME;
|
||
for(x = 1; (IAR & x) == 0; x <<= 1)
|
||
C++;
|
||
/* Release the channel after we got it */
|
||
if (C >= IO1_FINISH && C <= IO4_FINISH)
|
||
chan_release(C - IO1_FINISH);
|
||
IAR &= ~x;
|
||
} else if ((q_reg[0] & 0170) != 0) {
|
||
C = 060 + (q_reg[0] >> 3);
|
||
q_reg[0] &= 07;
|
||
} else if (q_reg[0] & STK_OVERFL) {
|
||
C = STK_OVR_LOC;
|
||
q_reg[0] &= ~STK_OVERFL;
|
||
} else if (P2_run == 0 && q_reg[1] != 0) {
|
||
if (q_reg[1] & MEM_PARITY) {
|
||
C = PARITY_ERR2;
|
||
q_reg[1] &= ~MEM_PARITY;
|
||
} else if (q_reg[1] & INVALID_ADDR) {
|
||
C = INVADR_ERR2;
|
||
q_reg[1] &= ~INVALID_ADDR;
|
||
} else if ((q_reg[1] & 0170) != 0) {
|
||
C = 040 + (q_reg[1] >> 3);
|
||
q_reg[1] &= 07;
|
||
} else if (q_reg[1] & STK_OVERFL) {
|
||
C = STK_OVR_LOC2;
|
||
q_reg[1] &= ~STK_OVERFL;
|
||
}
|
||
} else {
|
||
/* Could be an idle loop, if P2 running, continue */
|
||
if (P2_run)
|
||
break;
|
||
if (sim_idle_enab) {
|
||
/* Check if possible idle loop */
|
||
if (check_idle())
|
||
sim_idle (TMR_RTC, FALSE);
|
||
}
|
||
break;
|
||
}
|
||
sim_debug(DEBUG_DETAIL, &cpu_dev, "IAR=%05o Q=%03o\n",
|
||
IAR,Q);
|
||
L = 0;
|
||
S = 0100;
|
||
CWMF = 0;
|
||
PROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_IOR): /* I/O Release */
|
||
if (NCSF) /* Nop in normal state */
|
||
break;
|
||
|
||
/* Fall through */
|
||
case VARIANT(WMOP_PRL): /* Program Release */
|
||
A_valid();
|
||
if ((A & FLAG) == 0) {
|
||
relativeAddr(1);
|
||
} else if (A & PRESENT) {
|
||
Ma = CF(A);
|
||
} else {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
memory_cycle(4); /* Read Ma to A */
|
||
if (NCSF) { /* Can't occur for IOR */
|
||
Q |= (A & CONTIN) ? CONT_BIT : PROG_REL;
|
||
A = toC(Ma);
|
||
Ma = R | 9;
|
||
} else {
|
||
if (field == VARIANT(WMOP_PRL))
|
||
A &= ~PRESENT;
|
||
else
|
||
A |= PRESENT;
|
||
}
|
||
memory_cycle(014); /* Store A to Ma */
|
||
AROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_RTR): /* Read Timer */
|
||
if (!NCSF) {
|
||
A_empty();
|
||
A = RTC;
|
||
if (IAR & IRQ_0)
|
||
A |= 0100;
|
||
AROF = 1;
|
||
}
|
||
break;
|
||
|
||
case VARIANT(WMOP_COM): /* Communication operator */
|
||
if (NCSF) {
|
||
Ma = R|9;
|
||
save_tos();
|
||
Q |= COM_OPR;
|
||
}
|
||
break;
|
||
|
||
case VARIANT(WMOP_ZP1): /* Conditional Halt */
|
||
if (NCSF)
|
||
break;
|
||
if (!HLTF)
|
||
break;
|
||
if (!HALT)
|
||
break;
|
||
hltf[0] = 1;
|
||
P1_run = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_HP2): /* Halt P2 */
|
||
/* Control state only */
|
||
if (NCSF)
|
||
break;
|
||
/* If CPU 2 is not running, or disabled nop */
|
||
if (P2_run == 0 || (cpu_unit[1].flags & UNIT_DIS)) {
|
||
break;
|
||
}
|
||
sim_debug(DEBUG_DETAIL, &cpu_dev, "HALT P2\n");
|
||
/* Flag P2 to stop */
|
||
hltf[1] = 1;
|
||
TROF = 1; /* Reissue until CPU2 stopped */
|
||
break;
|
||
|
||
case VARIANT(WMOP_IP1): /* Initiate P1 */
|
||
if (NCSF)
|
||
break;
|
||
A_valid(); /* Load ICW */
|
||
sim_debug(DEBUG_DETAIL, &cpu_dev, "INIT P1\n");
|
||
initiate();
|
||
break;
|
||
|
||
case VARIANT(WMOP_IP2): /* Initiate P2 */
|
||
if (NCSF)
|
||
break;
|
||
Ma = 010;
|
||
save_tos();
|
||
/* If CPU is operating, or disabled, return busy */
|
||
if (P2_run != 0 || (cpu_unit[1].flags & UNIT_DIS)) {
|
||
IAR |= IRQ_11; /* Set CPU 2 Busy */
|
||
break;
|
||
}
|
||
/* Ok we are going to initiate B.
|
||
load the initiate word from 010. */
|
||
hltf[1] = 0;
|
||
P2_run = 1;
|
||
cpu_index = 1; /* To CPU 2 */
|
||
Ma = 010;
|
||
memory_cycle(4);
|
||
sim_debug(DEBUG_DETAIL, &cpu_dev, "INIT P2\n");
|
||
initiate();
|
||
break;
|
||
|
||
case VARIANT(WMOP_IIO): /* Initiate I/O */
|
||
if (NCSF)
|
||
break;
|
||
Ma = 010;
|
||
save_tos();
|
||
start_io(); /* Start an I/O channel */
|
||
break;
|
||
|
||
/* Currently not implimented. */
|
||
case VARIANT(WMOP_IFT): /* Test Initiate */
|
||
/* Supports the ablity to start operand during any
|
||
cycle, since this simulator does not function the
|
||
same as the original hardware, this function can't
|
||
really be implemented.
|
||
It is currently only used in diagnostics. */
|
||
/* Halt execution if this instruction attempted */
|
||
reason = SCPE_NOFNC;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 0015:
|
||
switch(field) {
|
||
case VARIANT(WMOP_LNG): /* Logical Negate */
|
||
A_valid();
|
||
A = (A ^ FWORD);
|
||
break;
|
||
|
||
case VARIANT(WMOP_LOR): /* Logical Or */
|
||
AB_valid();
|
||
A = (A & FWORD) | B;
|
||
BROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_LND): /* Logical And */
|
||
AB_valid();
|
||
A = (A & B & FWORD) | (B & FLAG);
|
||
BROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_LQV): /* Logical Equivalence */
|
||
AB_valid();
|
||
B = ((~(A ^ B) & FWORD)) | (B & FLAG);
|
||
AROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_MOP): /* Reset Flag bit */
|
||
A_valid();
|
||
A &= ~FLAG;
|
||
break;
|
||
|
||
case VARIANT(WMOP_MDS): /* Set Flag Bit */
|
||
A_valid();
|
||
A |= FLAG;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 0021:
|
||
switch(field) {
|
||
case VARIANT(WMOP_CID): /* 01 Conditional Integer Store Destructive */
|
||
case VARIANT(WMOP_CIN): /* 02 Conditional Integer Store non-destructive */
|
||
case VARIANT(WMOP_ISD): /* 41 Interger Store Destructive */
|
||
case VARIANT(WMOP_ISN): /* 42 Integer Store Non-Destructive */
|
||
case VARIANT(WMOP_STD): /* 04 B Store Destructive */
|
||
case VARIANT(WMOP_SND): /* 10 B Store Non-destructive */
|
||
AB_valid();
|
||
if (A & FLAG) {
|
||
if ((A & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
Ma = CF(A);
|
||
} else {
|
||
relativeAddr(1);
|
||
}
|
||
SALF |= VARF;
|
||
VARF = 0;
|
||
if ((field & 03) != 0) { /* Integer store */
|
||
if ((B & EXPO) != 0) {
|
||
/* Check if force to integer */
|
||
if ((A & INTEGR) != 0 || (field & 040) != 0) {
|
||
if (mkint()) {
|
||
/* Fail if not an integer */
|
||
if (NCSF)
|
||
Q |= INT_OVER;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
AROF = 0;
|
||
memory_cycle(015); /* Store B in Ma */
|
||
if (field & 5) /* Destructive store */
|
||
BROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_LOD): /* Load */
|
||
A_valid();
|
||
if (A & FLAG) {
|
||
if ((A & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
Ma = CF(A);
|
||
} else {
|
||
relativeAddr(0);
|
||
}
|
||
SALF |= VARF;
|
||
VARF = 0;
|
||
memory_cycle(4); /* Read Ma to A */
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 0025:
|
||
switch(field) {
|
||
case VARIANT(WMOP_GEQ): /* B greater than or equal to A */
|
||
case VARIANT(WMOP_GTR): /* B Greater than A */
|
||
case VARIANT(WMOP_NEQ): /* B Not equal to A */
|
||
case VARIANT(WMOP_LEQ): /* B Less Than or Equal to A */
|
||
case VARIANT(WMOP_LSS): /* B Less Than A */
|
||
case VARIANT(WMOP_EQL): /* B Equal A */
|
||
AB_valid();
|
||
f = 0;
|
||
i = compare();
|
||
switch(field) {
|
||
case VARIANT(WMOP_GEQ):
|
||
if ((i & 5) != 0) {
|
||
f = 1;
|
||
}
|
||
break;
|
||
case VARIANT(WMOP_GTR):
|
||
if (i == 4) {
|
||
f = 1;
|
||
}
|
||
break;
|
||
case VARIANT(WMOP_NEQ):
|
||
if (i != 1) {
|
||
f = 1;
|
||
}
|
||
break;
|
||
case VARIANT(WMOP_LEQ):
|
||
if ((i & 3) != 0) {
|
||
f = 1;
|
||
}
|
||
break;
|
||
case VARIANT(WMOP_LSS):
|
||
if (i == 2) {
|
||
f = 1;
|
||
}
|
||
break;
|
||
case VARIANT(WMOP_EQL):
|
||
if (i == 1) {
|
||
f = 1;
|
||
}
|
||
break;
|
||
}
|
||
B = f;
|
||
AROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_XCH): /* Exchange */
|
||
AB_valid();
|
||
temp = A;
|
||
A = B;
|
||
B = temp;
|
||
break;
|
||
|
||
case VARIANT(WMOP_FTF): /* Transfer F Field to F Field */
|
||
AB_valid();
|
||
B &= ~FFIELD;
|
||
B |= (A & FFIELD);
|
||
AROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_FTC): /* Transfer F Field to Core Field */
|
||
AB_valid();
|
||
B &= ~CORE;
|
||
B |= (A & FFIELD) >> FFIELD_V;
|
||
AROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_CTC): /* Transfer Core Field to Core Field */
|
||
AB_valid();
|
||
B &= ~CORE;
|
||
B |= (A & CORE);
|
||
AROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_CTF): /* Transfer Core Field to F Field */
|
||
AB_valid();
|
||
B &= ~FFIELD;
|
||
B |= FFIELD & (A << FFIELD_V);
|
||
AROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_DUP): /* Duplicate */
|
||
if (AROF && BROF) {
|
||
B_empty();
|
||
B = A;
|
||
BROF = 1;
|
||
} else if (AROF || BROF) {
|
||
if (AROF)
|
||
B = A;
|
||
else
|
||
A = B;
|
||
AROF = BROF = 1;
|
||
} else {
|
||
A_valid(); /* Make A Valid */
|
||
B = A;
|
||
BROF = 1;
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 0031:
|
||
switch(field) {
|
||
case VARIANT(WMOP_BFC): /* Branch Forward Conditional 0231 */
|
||
case VARIANT(WMOP_BBC): /* Branch Backward Conditional 0131 */
|
||
case VARIANT(WMOP_LFC): /* Word Branch Forward Conditional 2231 */
|
||
case VARIANT(WMOP_LBC): /* Word Branch Backward Conditional 2131 */
|
||
AB_valid();
|
||
BROF = 0;
|
||
if (B & 1) {
|
||
AROF = 0;
|
||
break;
|
||
}
|
||
|
||
/* Fall through */
|
||
case VARIANT(WMOP_BFW): /* Branch Forward Unconditional 4231 */
|
||
case VARIANT(WMOP_BBW): /* Banch Backward Unconditional 4131 */
|
||
case VARIANT(WMOP_LFU): /* Word Branch Forward Unconditional 6231*/
|
||
case VARIANT(WMOP_LBU): /* Word Branch Backward Unconditional 6131 */
|
||
A_valid();
|
||
if (A & FLAG) {
|
||
if ((A & PRESENT) == 0) {
|
||
if (L == 0) /* Back up to branch word */
|
||
prev_addr(C);
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
if (field & 020)
|
||
BROF = 1;
|
||
break;
|
||
}
|
||
C = CF(A);
|
||
L = 0;
|
||
} else {
|
||
if (L == 0) { /* Back up to branch op */
|
||
prev_addr(C);
|
||
L = 3;
|
||
} else {
|
||
L--;
|
||
}
|
||
/* Follow logic based on real hardware */
|
||
if ((field & 020) == 0) { /* Syllable branch */
|
||
if (field & 02) { /* Forward */
|
||
if (A & 1) { /* N = 0 */
|
||
L++; C += (L >> 2); L &= 3;
|
||
}
|
||
A >>= 1;
|
||
if (A & 1) { /* Bump L by 2 */
|
||
L+=2; C += (L >> 2); L &= 3;
|
||
}
|
||
A >>= 1;
|
||
} else { /* Backward */
|
||
if (A & 1) { /* N = 0 */
|
||
if (L == 0) {
|
||
C--; L = 3;
|
||
} else {
|
||
L--;
|
||
}
|
||
}
|
||
A >>= 1;
|
||
if (A & 1) { /* N = 1 */
|
||
if (L < 2) {
|
||
C--; L += 2;
|
||
} else {
|
||
L -= 2;
|
||
}
|
||
}
|
||
A >>= 1;
|
||
}
|
||
/* Fix up for backward step */
|
||
if (L == 3) { /* N = 3 */
|
||
C++; L = 0;
|
||
} else {
|
||
L++;
|
||
}
|
||
} else {
|
||
L = 0;
|
||
}
|
||
if (field & 02) { /* Forward */
|
||
C += A & 01777;
|
||
} else { /* Backward */
|
||
C -= A & 01777;
|
||
}
|
||
C &= CORE;
|
||
}
|
||
AROF = 0;
|
||
PROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_SSN): /* Set Sign Bit */
|
||
A_valid();
|
||
A |= MSIGN;
|
||
break;
|
||
|
||
case VARIANT(WMOP_CHS): /* Change sign bit */
|
||
A_valid();
|
||
A ^= MSIGN;
|
||
break;
|
||
|
||
case VARIANT(WMOP_SSP): /* Reset Sign Bit */
|
||
A_valid();
|
||
A &= ~MSIGN;
|
||
break;
|
||
|
||
case VARIANT(WMOP_TOP): /* Test Flag Bit */
|
||
B_valid(); /* Move result to B */
|
||
if (B & FLAG)
|
||
A = 0;
|
||
else
|
||
A = 1;
|
||
AROF = 1;
|
||
break;
|
||
|
||
case VARIANT(WMOP_TUS): /* Interrogate Peripheral Status */
|
||
A_empty();
|
||
A = iostatus;
|
||
AROF = 1;
|
||
break;
|
||
|
||
case VARIANT(WMOP_TIO): /* Interrogate I/O Channels */
|
||
A_empty();
|
||
A = find_chan();
|
||
AROF = 1;
|
||
break;
|
||
|
||
case VARIANT(WMOP_FBS): /* Flag Bit Search */
|
||
A_valid();
|
||
Ma = CF(A);
|
||
memory_cycle(4); /* Read A */
|
||
while((A & FLAG) == 0) {
|
||
next_addr(Ma);
|
||
memory_cycle(4);
|
||
}
|
||
A = FLAG | PRESENT | toC(Ma);
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 0035:
|
||
switch(field) {
|
||
case VARIANT(WMOP_BRT): /* Branch Return */
|
||
B_valid();
|
||
if ((B & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
f = set_via_RCW(B, 0, 1); /* Restore registers */
|
||
L = 0;
|
||
S = F;
|
||
memory_cycle(3); /* Read B */
|
||
prev_addr(S);
|
||
set_via_MSCW(B);
|
||
BROF = 0;
|
||
PROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_RTN): /* Return normal 02 */
|
||
case VARIANT(WMOP_RTS): /* Return Special 12 */
|
||
A_valid();
|
||
if (A & FLAG) {
|
||
if ((A & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Fall through */
|
||
case VARIANT(WMOP_XIT): /* Exit 04 */
|
||
if (field & 04)
|
||
AROF = 0;
|
||
BROF = 0;
|
||
PROF = 0;
|
||
if ((field & 010) == 0) /* normal return & XIT */
|
||
S = F;
|
||
memory_cycle(3); /* Restore RCW to B*/
|
||
if ((B & FLAG) == 0) {
|
||
if (NCSF)
|
||
Q |= FLAG_BIT;
|
||
break;
|
||
}
|
||
f = set_via_RCW(B, 0, 0); /* Restore registers */
|
||
S = F;
|
||
BROF = 0;
|
||
memory_cycle(3); /* Read B */
|
||
prev_addr(S);
|
||
set_via_MSCW(B);
|
||
if (MSFF && SALF) {
|
||
Ma = F;
|
||
do {
|
||
/* B = M[FIELD], Ma = B[FIELD]; */
|
||
memory_cycle(6); /* Grab previous MCSW */
|
||
} while(B & SMSFF);
|
||
Ma = R | 7;
|
||
memory_cycle(015); /* Store B in Ma */
|
||
}
|
||
BROF = 0;
|
||
if (field & 2) { /* RTS and RTN */
|
||
if (f)
|
||
goto desc;
|
||
else
|
||
goto opdc;
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 0041:
|
||
A_valid();
|
||
switch(field) {
|
||
case VARIANT(WMOP_INX): /* Index */
|
||
AB_valid();
|
||
A = (A & (~CORE)) | ((A + B) & CORE);
|
||
BROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_COC): /* Construct Operand Call */
|
||
case VARIANT(WMOP_CDC): /* Construct descriptor call */
|
||
AB_valid();
|
||
temp = A;
|
||
A = B | FLAG;
|
||
B = temp;
|
||
if (field & 010) /* COC or CDC */
|
||
goto desc;
|
||
else
|
||
goto opdc;
|
||
/* Not reached */
|
||
break;
|
||
|
||
case VARIANT(WMOP_SSF): /* Set or Store S or F registers */
|
||
AB_valid();
|
||
switch( A & 03) {
|
||
case 0: /* F => B */
|
||
B = replF(B, F);
|
||
break;
|
||
case 1: /* S => B */
|
||
B = replC(B, S);
|
||
break;
|
||
case 2:
|
||
F = FF(B);
|
||
SALF = 1;
|
||
BROF = 0;
|
||
break;
|
||
case 3:
|
||
S = CF(B);
|
||
BROF = 0;
|
||
break;
|
||
}
|
||
AROF = 0;
|
||
break;
|
||
|
||
case VARIANT(WMOP_LLL): /* Link List Look-up */
|
||
AB_valid();
|
||
A = MANT ^ A;
|
||
do {
|
||
Ma = CF(B);
|
||
memory_cycle(5);
|
||
if (sim_interval <= 0) { /* event queue? */
|
||
reason = sim_process_event();
|
||
if (reason != SCPE_OK) {
|
||
break; /* process */
|
||
}
|
||
}
|
||
temp = (B & MANT) + (A & MANT);
|
||
} while ((temp & EXPO) == 0);
|
||
A = FLAG | PRESENT | toC(Ma);
|
||
break;
|
||
|
||
case VARIANT(WMOP_CMN): /* Enter Character Mode In Line */
|
||
A_valid(); /* Make sure TOS is in A. */
|
||
AB_empty(); /* Force A&B to stack */
|
||
B = RCW(0); /* Build RCW word */
|
||
BROF = 1;
|
||
B_empty(); /* Save return control word */
|
||
CWMF = 1;
|
||
SALF = 1;
|
||
MSFF = 0;
|
||
B = A; /* A still had copy of TOS */
|
||
AROF = 0;
|
||
BROF = 0;
|
||
R = 0;
|
||
F = S; /* Set F and X */
|
||
X = toF(S);
|
||
S = CF(B);
|
||
KV = 0;
|
||
if ((B & FLAG) == 0)
|
||
KV = (uint8)((B >> (FFIELD_V - 3)) & 070);
|
||
else if ((B & PRESENT) == 0 && NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
|
||
case VARIANT(WMOP_MKS): /* Mark Stack */
|
||
AB_empty();
|
||
B = MSCW;
|
||
BROF = 1;
|
||
B_empty();
|
||
F = S;
|
||
if (!MSFF && SALF) {
|
||
Ma = R | 7;
|
||
memory_cycle(015); /* Store B in Ma */
|
||
}
|
||
MSFF = 1;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case 0051: /* Conditional bit field */
|
||
if ((field & 074) == 0) { /* DEL Operator */
|
||
if (AROF)
|
||
AROF = 0;
|
||
else if (BROF)
|
||
BROF = 0;
|
||
else
|
||
prev_addr(S);
|
||
break;
|
||
}
|
||
AB_valid();
|
||
f = 0;
|
||
bit_b = bit_number[GH];
|
||
if (field & 2)
|
||
BROF = 0;
|
||
for (i = (field >> 2) & 017; i > 0; i--) {
|
||
if (B & bit_mask[bit_b-i])
|
||
f = 1;
|
||
}
|
||
if (f) {
|
||
T = (field & 1) ? WMOP_BBW : WMOP_BFW;
|
||
TROF = 1;
|
||
} else {
|
||
AROF = 0;
|
||
}
|
||
break;
|
||
|
||
case WMOP_DIA: /* Dial A XX */
|
||
if (field != 0)
|
||
GH = field;
|
||
break;
|
||
|
||
case WMOP_DIB: /* Dial B XX Upper 6 not Zero */
|
||
if (field != 0)
|
||
KV = field;
|
||
else { /* Set Variant */
|
||
VARF |= SALF;
|
||
SALF = 0;
|
||
}
|
||
break;
|
||
|
||
case WMOP_ISO: /* Variable Field Isolate XX */
|
||
A_valid();
|
||
if ((field & 070) != 0) {
|
||
bit_a = bit_number[GH | 07]; /* First Character */
|
||
X = A >> bit_a; /* Get first char */
|
||
X &= 077LL >> (GH & 07); /* Mask first character */
|
||
GH &= 070; /* Clear H */
|
||
while(field > 017) { /* Transfer chars. */
|
||
bit_a -= 6;
|
||
X = (X << 6) | ((A >> bit_a) & 077);
|
||
field -= 010;
|
||
GH += 010; /* Bump G for each char */
|
||
GH &= 070;
|
||
}
|
||
X >>= (field & 07); /* Align with remaining bits. */
|
||
A = X & MANT; /* Max is 39 bits */
|
||
}
|
||
break;
|
||
|
||
case WMOP_TRB: /* Transfer Bits XX */
|
||
case WMOP_FCL: /* Compare Field Low XX */
|
||
case WMOP_FCE: /* Compare Field Equal XX */
|
||
AB_valid();
|
||
f = 1;
|
||
bit_a = bit_number[GH];
|
||
bit_b = bit_number[KV];
|
||
for(; field > 0 && bit_a >= 0 && bit_b >= 0;
|
||
field--, bit_a--, bit_b--) {
|
||
int ba, bb;
|
||
ba = (bit_mask[bit_a] & A) != 0;
|
||
switch(opcode) {
|
||
case WMOP_TRB: /* Just copy bit */
|
||
B &= ~bit_mask[bit_b];
|
||
if (ba)
|
||
B |= bit_mask[bit_b];
|
||
break;
|
||
case WMOP_FCL: /* Loop until unequal */
|
||
case WMOP_FCE:
|
||
bb = (bit_mask[bit_b] & B) != 0;
|
||
if (ba != bb) {
|
||
if (opcode == WMOP_FCL)
|
||
f = ba;
|
||
else
|
||
f = 0;
|
||
i = field;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
if (opcode != WMOP_TRB) {
|
||
A = f;
|
||
} else {
|
||
AROF = 0;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
} /* end while */
|
||
/* Simulation halted */
|
||
|
||
return reason;
|
||
}
|
||
|
||
/* Interval timer routines */
|
||
t_stat
|
||
rtc_srv(UNIT * uptr)
|
||
{
|
||
int32 t;
|
||
|
||
t = sim_rtcn_calb(rtc_tps, TMR_RTC);
|
||
sim_activate_after(uptr, 1000000/rtc_tps);
|
||
tmxr_poll = t;
|
||
RTC++;
|
||
if (RTC & 0100) {
|
||
IAR |= IRQ_0;
|
||
}
|
||
RTC &= 077;
|
||
return SCPE_OK;
|
||
}
|
||
/* Reset routine */
|
||
|
||
t_stat
|
||
cpu_reset(DEVICE * dptr)
|
||
{
|
||
/* Reset CPU 2 first */
|
||
cpu_index = 1;
|
||
C = 020;
|
||
S = F = R = T = 0;
|
||
L = 0;
|
||
A = B = X = P = 0;
|
||
AROF = BROF = TROF = PROF = NCSF = SALF = CWMF = MSFF = VARF = 0;
|
||
GH = KV = Q = 0;
|
||
hltf[1] = 0;
|
||
P2_run = 0;
|
||
/* Reset CPU 1 now */
|
||
cpu_index = 0;
|
||
C = 020;
|
||
S = F = R = T = IAR = 0;
|
||
L = 0;
|
||
A = B = X = P = 0;
|
||
AROF = BROF = TROF = PROF = NCSF = SALF = CWMF = MSFF = VARF = 0;
|
||
GH = KV = Q = 0;
|
||
hltf[0] = 0;
|
||
P1_run = 0;
|
||
IAR = 0;
|
||
HALT = 0;
|
||
|
||
idle_addr = 0;
|
||
sim_brk_types = sim_brk_dflt = SWMASK('E') | SWMASK('A') | SWMASK('B');
|
||
hst_p = 0;
|
||
|
||
sim_rtcn_init_unit (&cpu_unit[0], cpu_unit[0].wait, TMR_RTC);
|
||
sim_activate(&cpu_unit[0], cpu_unit[0].wait) ;
|
||
|
||
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 = (t_value)(M[addr] & (FLAG|FWORD));
|
||
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 & (FLAG|FWORD);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cpu_msize(UNIT *uptr, int32 v, CONST char *cptr, void *dptr)
|
||
{
|
||
int32 val;
|
||
if ((v < 0) || (v > MAXMEMSIZE))
|
||
return SCPE_ARG;
|
||
val = ((v / 4096) - 1) << UNIT_V_MSIZE;
|
||
cpu_unit[0].flags &= ~UNIT_MSIZE;
|
||
cpu_unit[0].flags |= val;
|
||
cpu_unit[1].flags &= ~UNIT_MSIZE;
|
||
cpu_unit[1].flags |= val;
|
||
MEMSIZE = v;
|
||
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 = (v + 1) * 4096;
|
||
if ((v < 0) || (v > MAXMEMSIZE))
|
||
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;
|
||
cpu_unit[0].flags &= ~UNIT_MSIZE;
|
||
cpu_unit[0].flags |= val;
|
||
cpu_unit[1].flags &= ~UNIT_MSIZE;
|
||
cpu_unit[1].flags |= val;
|
||
MEMSIZE = v;
|
||
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].c = 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;
|
||
const char *cptr = (const char *) desc;
|
||
t_stat r;
|
||
t_value sim_eval;
|
||
struct InstHistory *h;
|
||
CONST static char flags[] = "ABCNSMV";
|
||
|
||
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, "P CL A B "
|
||
" X S F R M GH KV Flags"
|
||
" Q Intruction IAR\n\n");
|
||
for (k = 0; k < lnt; k++) { /* print specified */
|
||
h = &hst[(++di) % hst_lnt]; /* entry pointer */
|
||
if (h->c & HIST_PC) { /* instruction? */
|
||
int i;
|
||
fprintf(st, "%o %05o%o ", h->cpu, h->c & 077777, h->l);
|
||
sim_eval = (t_value)h->a_reg;
|
||
(void)fprint_sym(st, 0, &sim_eval, &cpu_unit[0], SWMASK('B'));
|
||
fputc((h->flags & F_AROF) ? '^': ' ', st);
|
||
fputc(' ', st);
|
||
sim_eval = (t_value)h->b_reg;
|
||
(void)fprint_sym(st, 0, &sim_eval, &cpu_unit[0], SWMASK('B'));
|
||
fputc((h->flags & F_BROF) ? '^': ' ', st);
|
||
fputc(' ', st);
|
||
fprint_val(st, (t_value)h->x_reg, 8, 39, PV_RZRO);
|
||
fputc(' ', st);
|
||
fprint_val(st, h->s, 8, 15, PV_RZRO);
|
||
fputc(' ', st);
|
||
fprint_val(st, h->f, 8, 15, PV_RZRO);
|
||
fputc(' ', st);
|
||
fprint_val(st, h->r, 8, 15, PV_RZRO);
|
||
fputc(' ', st);
|
||
fprint_val(st, h->ma, 8, 15, PV_RZRO);
|
||
fputc(' ', st);
|
||
fprint_val(st, h->gh, 8, 6, PV_RZRO);
|
||
fputc(' ', st);
|
||
fprint_val(st, h->kv, 8, 6, PV_RZRO);
|
||
fputc(' ', st);
|
||
for(i = 2; i < 8; i++) {
|
||
fputc (((1 << i) & h->flags) ? flags[i] : ' ', st);
|
||
}
|
||
fprint_val(st, h->q, 8, 9, PV_RZRO);
|
||
fputc(' ', st);
|
||
fprint_val(st, h->op, 8, 12, PV_RZRO);
|
||
fputc(' ', st);
|
||
print_opcode(st, h->op, ((h->flags & F_CWMF) != 0));
|
||
fputc(' ', st);
|
||
fprint_val(st, h->iar, 8, 16, PV_RZRO);
|
||
fputc('\n', st); /* end line */
|
||
} /* end else instruction */
|
||
} /* end for */
|
||
return SCPE_OK;
|
||
}
|
||
|
||
|
||
t_stat cpu_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf(st, "B5500 CPU\n\n");
|
||
fprintf(st, "The B5500 could support up to two CPU's the second CPU is disabled by\n");
|
||
fprintf(st, "default. Use:\n");
|
||
fprintf(st, " sim> SET CPU1 ENABLE enable second CPU\n");
|
||
fprintf(st, "The primary CPU can't be disabled. Memory is shared between the two\n");
|
||
fprintf(st, "CPU's. Memory can be configured in 4K increments up to 32K total.\n");
|
||
fprint_reg_help (st, dptr);
|
||
fprint_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
return SCPE_OK;
|
||
}
|