The B5500 simulator supports the following peripherals. Two CPUs with between 4K and 32K of memory. The second CPU can be enabled with "set cpu1 enable". "set cpu1 disable" disables the second CPU. Up to 4 floating IO channels. Individual channels can be enabled with "set io# enable", or "set io# disable". There are two card readers. The second reader is disabled by default. There is one Card Punch. The Card reader and Card Punch support the following options: set cr format= auto - will automatically determine the format based on the text it recieves. text Text based cards. Tabs are converted to the correct number of spaces. A record of ~raw octal will enter a binary card. ~eor will enter a 7/8/9 punch in column 1. ~eof will enter a 6/7/9 punch in column 1. ~eoi will enter a 6/7/8/9 punch in column 1. ~~ will enter a ~ as the first character. bin Binary Card format: Each record 160 characters. First characters 6789---- Second character 21012345 111 Top 4 bits of second character are 0. It is unlikely that any other format could look like this. bcd BCD Format: Each record variable length (80 chars or less). Record mark has bit 7 set. Bit 6 is even parity. Bits 5-0 are character. cbn CBN Format: Each record 160 charaters. First char has bit 7 set. Rest set to 0. Bit 6 is odd parity. Bit 5-0 of first character are top 6 bits of card. Bit 5-0 of second character are lower 6 bits of card. For punch format of auto if the card can't be converted to text it is output as a raw record. There are two line printers, the second one is disabled by default. The LP supports the option "set lp# linesperpage=#" which determines when the printer will force out a page break. There are up to 16 mag tape drives, the format is controlled by the standard simh format control for tapes. These are 6 bit tapes, 1 character per record with parity. Units 8-16 are disabled by default. There are up to two drum units DR0 and DR1. These can either be attached to a file or set to AUXMEM. Setting to AUXMEM causes them to exist only during the given simh run. Setting back to DRUM will clear whatever was stored on the drum. To enable use of DRUM on XV the following options should be turned on "DRA,DRB,CODEOLAY,DATAOLAY". MCP will then use the drum as a overlay device instead of the disk system. Disks can be attached to the various ESU's, ESU0-9 are on DKA by default, ESU10-19 are on DKB. If "set dk1 dfx" is set, then ESU10-19 are not used and the disks are shared by both DKA and DKB. To use more then 10 ESU's in a non shared mode, a new version of MCP must be created. MCP must be compiled with DFX option set to false. For MCP XV DKBNODFX must also be set to true. ESU units can be set to MODI or MODIB. MODIB will double the size of the drive. The DTC can be attached to a telnet port with "attach dtc #" to enable dialup access to the sim. The loader card for the card reader is: ~raw0104441100204231524012004000004444550211002041317700000000000024045303040243 00050000006501004131011041310055005500000062005042310000006600304231000000720010 42310000007675610165001002310010413100040107202500440106202533554061256520252265 20251765202514655355536117650000004401062025155522610165225572610465044101160500 4131 This card should be all in one line.
3903 lines
125 KiB
C
3903 lines
125 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.
|
||
|
||
*/
|
||
|
||
#include "b5500_defs.h"
|
||
#include "sim_timer.h"
|
||
#include <math.h>
|
||
#include <time.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 1
|
||
|
||
#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 */
|
||
uint8 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 */
|
||
|
||
|
||
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_set_size(UNIT * uptr, int32 val, char *cptr,
|
||
void *desc);
|
||
t_stat cpu_show_size(FILE * st, UNIT * uptr, int32 val,
|
||
void *desc);
|
||
t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val,
|
||
void *desc);
|
||
t_stat cpu_set_hist(UNIT * uptr, int32 val, 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), 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(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,9,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")},
|
||
{FLDATA(HALT, HALT, 0)},
|
||
{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_VDV, 0, "MEMORY", NULL, NULL, &cpu_show_size},
|
||
{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, 0, dev_debug,
|
||
NULL, 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_V) & CORE))
|
||
#define CF(x) ((uint16)((x) & CORE))
|
||
#define LF(x) ((uint8)(((x) & RL) >> RL_V) & 03)
|
||
#define RF(x) (uint16)(((x) & RFIELD) >> RFIELD_V)
|
||
|
||
#define toF(x) (((t_uint64)((x) & CORE)) << FFIELD_V)
|
||
#define toC(x) ((t_uint64)((x) & CORE))
|
||
#define toL(x) (((t_uint64)(x)) << RL_V)
|
||
#define toR(x) (((t_uint64)(x)) << RFIELD_V)
|
||
|
||
#define replF(y, x) ((y & ~FFIELD) | toF(x))
|
||
#define replC(y, x) ((y & ~CORE) | toC(x))
|
||
|
||
#define next_addr(x) (x = (x + 1) & CORE)
|
||
#define prev_addr(x) (x = (x - 1) & CORE)
|
||
|
||
/* 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 (exp_b != 0) {
|
||
B = 0;
|
||
return 1;
|
||
}
|
||
}
|
||
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;
|
||
t_uint64 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;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* 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 = (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 = 0;
|
||
hltf[0] = 0;
|
||
hltf[1] = 0;
|
||
P1_run = 1;
|
||
|
||
while (reason == 0) { /* loop until halted */
|
||
if (P1_run == 0)
|
||
return SCPE_STOP;
|
||
while (loading) {
|
||
sim_interval = -1;
|
||
reason = sim_process_event();
|
||
if (reason != SCPE_OK) {
|
||
break; /* process */
|
||
}
|
||
}
|
||
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 (cpu_index == 0 && P2_run == 1) {
|
||
cpu_index = 1;
|
||
/* Check if interrupt pending. */
|
||
if (TROF == 0 && NCSF && ((Q != 0) || HLTF))
|
||
/* Force a SFI */
|
||
storeInterrupt(1,0);
|
||
} else {
|
||
cpu_index = 0;
|
||
|
||
/* Check if interrupt pending. */
|
||
if (TROF == 0 && NCSF && ((Q != 0) ||
|
||
(IAR != 0)))
|
||
/* Force a SFI */
|
||
storeInterrupt(1,0);
|
||
}
|
||
if (TROF == 0)
|
||
next_prog();
|
||
|
||
/* TODO: Add support to detect IDLE loop */
|
||
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;
|
||
if (A & FLAG) {
|
||
if ((A & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
GH = 0;
|
||
} else {
|
||
GH = (A >> 12) & 070;
|
||
}
|
||
Ma = CF(A);
|
||
break;
|
||
|
||
case CMOP_RDA: /* Recall Destination Address */
|
||
if (BROF)
|
||
memory_cycle(013);
|
||
S = (F - field) & CORE;
|
||
memory_cycle(3);
|
||
BROF = 0;
|
||
if (B & FLAG) {
|
||
if ((B & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
KV = 0;
|
||
} else {
|
||
KV = (B >> 12) & 070;
|
||
}
|
||
S = CF(B);
|
||
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;
|
||
break;
|
||
}
|
||
C = CF(B);
|
||
L = 0;
|
||
} else {
|
||
C = CF(B);
|
||
L = RF(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 = (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 = (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 = CF(FF(B) - field);
|
||
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);
|
||
S = (F - field) & CORE;
|
||
memory_cycle(013); /* Store B in S */
|
||
S = CF(B);
|
||
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);
|
||
Ma = (F - field) & CORE;
|
||
memory_cycle(015); /* Store B in Ma */
|
||
Ma = CF(B);
|
||
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(CF(A) - field);
|
||
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 = toC(Ma) | PRESENT | FLAG;
|
||
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 = toC(Ma) | FLAG | PRESENT;
|
||
}
|
||
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 {
|
||
/* False IRQ */
|
||
break;
|
||
}
|
||
sim_debug(DEBUG_DETAIL, &cpu_dev, "IAR=%05o Q=%03o\n\r",
|
||
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\r");
|
||
/* 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\r");
|
||
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\r");
|
||
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 = toC(Ma) | FLAG | PRESENT;
|
||
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);
|
||
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);
|
||
if (B & FLAG) {
|
||
if ((B & PRESENT) == 0) {
|
||
if (NCSF)
|
||
Q |= PRES_BIT;
|
||
break;
|
||
}
|
||
KV = 0;
|
||
} else {
|
||
KV = (uint8)((B >> (FFIELD_V - 3)) & 070);
|
||
}
|
||
S = CF(B);
|
||
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;
|
||
|
||
sim_brk_types = sim_brk_dflt = SWMASK('E') | SWMASK('A') | SWMASK('B');
|
||
hst_p = 0;
|
||
|
||
sim_register_clock_unit (&cpu_unit[0]);
|
||
sim_rtcn_init (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_show_size(FILE *st, UNIT *uptr, int32 val, void *desc)
|
||
{
|
||
fprintf(st, "%dK", MEMSIZE/1024);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cpu_set_size(UNIT * uptr, int32 val, char *cptr, void *desc)
|
||
{
|
||
t_uint64 mc = 0;
|
||
uint32 i;
|
||
|
||
cpu_unit[0].flags &= ~UNIT_MSIZE;
|
||
cpu_unit[0].flags |= val;
|
||
cpu_unit[1].flags &= ~UNIT_MSIZE;
|
||
cpu_unit[1].flags |= val;
|
||
val >>= UNIT_V_MSIZE;
|
||
val = (val + 1) * 4096;
|
||
if ((val < 0) || (val > MAXMEMSIZE))
|
||
return SCPE_ARG;
|
||
for (i = val; i < MEMSIZE; i++)
|
||
mc |= M[i];
|
||
if ((mc != 0) && (!get_yn("Really truncate memory [N]?", FALSE)))
|
||
return SCPE_OK;
|
||
MEMSIZE = val;
|
||
for (i = MEMSIZE; i < MAXMEMSIZE; i++)
|
||
M[i] = 0;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Handle execute history */
|
||
|
||
/* Set history */
|
||
t_stat
|
||
cpu_set_hist(UNIT * uptr, int32 val, 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 = 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, void *desc)
|
||
{
|
||
int32 k, di, lnt;
|
||
char *cptr = (char *) desc;
|
||
t_stat r;
|
||
t_value sim_eval;
|
||
struct InstHistory *h;
|
||
extern void print_opcode(FILE * ofile, t_value val, t_opcode *);
|
||
extern t_opcode word_ops[1], char_ops[1];
|
||
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;
|
||
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;
|
||
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) ? char_ops : word_ops));
|
||
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_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
return SCPE_OK;
|
||
}
|