mirror of
https://github.com/rcornwell/sims.git
synced 2026-01-13 15:27:04 +00:00
2686 lines
102 KiB
C
2686 lines
102 KiB
C
/* icl1900_cpu.c: ICL 1900 cpu simulator
|
||
|
||
Copyright (c) 2017, Richard Cornwell
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a
|
||
copy of this software and associated documentation files (the "Software"),
|
||
to deal in the Software without restriction, including without limitation
|
||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
and/or sell copies of the Software, and to permit persons to whom the
|
||
Software is furnished to do so, subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in
|
||
all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
The ICL1900 was a 24 bit CPU that supported either 32Kwords of memory or
|
||
4Mwords of memory, depending on model.
|
||
|
||
Level A: lacked 066, 116 and 117 instructions and 22 bit addressing.
|
||
Level B: Adds 066, 116 and 117 instructions, but lack 22 bit addressing.
|
||
Level C: All primary and 22 bit addressing.
|
||
|
||
Sub-level 1: Norm 114,115 available only if FP option.
|
||
Sub-level 2: Norm 114,115 always available.
|
||
*/
|
||
|
||
#include "icl1900_defs.h"
|
||
#include "sim_timer.h"
|
||
|
||
#define UNIT_V_MSIZE (UNIT_V_UF + 0)
|
||
#define UNIT_MSIZE (0x1ff << UNIT_V_MSIZE)
|
||
#define MEMAMOUNT(x) (x << UNIT_V_MSIZE)
|
||
#define UNIT_V_MODEL (UNIT_V_MSIZE + 9)
|
||
#define UNIT_MODEL (0x3f << UNIT_V_MODEL)
|
||
#define MODEL(x) (UNIT_MODEL & (x << UNIT_V_MODEL))
|
||
|
||
|
||
#define TMR_RTC 1
|
||
|
||
#define HIST_PC BM1
|
||
#define HIST_MAX 500000
|
||
#define HIST_MIN 64
|
||
|
||
/* Level A Primary no 066, 116, 117 15AM and DBM only */
|
||
/* Level B All Primary 15AM and DBM only */
|
||
/* Level C All Primary 15AM and 22AM, DBM and EBM */
|
||
|
||
/* Level x1, NORM when FP */
|
||
/* Level x2, NORM always */
|
||
|
||
#define MOD1 0 /* Ax OPT */
|
||
#define MOD1A 1 /* A1 OPT 04x -076 111-3 */
|
||
#define MOD1S 2 /* Ax OPT 04x -076 111-3 */
|
||
#define MOD1T 3 /* Ax OPT 04x -076 111-3 */
|
||
#define MOD2 4 /* Ax OPT 04x -076 111-3 */
|
||
#define MOD2A 5 /* B1 OPT */
|
||
#define MOD2S 6 /* B1 or C1 OPT 04x -076 111-3 */
|
||
#define MOD2T 7 /* B1 or C1 OPT 04x -076 111-3 */
|
||
#define MOD3 8 /* A1 or A2 OPT 04x -076 111-3 */
|
||
#define MOD3A 9 /* B1 or C1 OPT 04x -076 111-3 */
|
||
#define MOD3S 10 /* B1 or C1 OPT 04x -076 111-3 */
|
||
#define MOD3T 11 /* A1 or A2 OPT */
|
||
#define MOD4 12 /* A2 OPT */
|
||
#define MOD4A 13 /* C2 OPT */
|
||
#define MOD4E 14 /* C2 OPT */
|
||
#define MOD4F 15
|
||
#define MOD4S 16 /* Ax OPT */
|
||
#define MOD5 17 /* A2 FP */
|
||
#define MOD5A 18 /* Ax FP */
|
||
#define MOD5E 19 /* C2 FP */
|
||
#define MOD5F 20
|
||
#define MOD5S 21 /* Ax FP */
|
||
#define MOD6 22 /* C2 OPT */
|
||
#define MOD6A 23 /* Ax OPT 076 131 */
|
||
#define MOD6E 24 /* Ax OPT 076 */
|
||
#define MOD6F 25
|
||
#define MOD6S 26 /* Ax OPT */
|
||
#define MOD7 27 /* C2 FP */
|
||
#define MOD7A 28 /* Ax FP */
|
||
#define MOD7E 29 /* Ax FP */
|
||
#define MOD7F 30
|
||
#define MOD7S 31 /* Ax FP */
|
||
#define MOD8 32 /* Ax FP */
|
||
#define MOD8A 33 /* Ax FP */
|
||
#define MOD8S 34 /* Ax FP */
|
||
#define MOD9 35 /* A2 FP */
|
||
#define MODXF 36 /* C2 FP */
|
||
|
||
|
||
|
||
int cpu_index; /* Current running cpu */
|
||
uint32 M[MAXMEMSIZE] = { 0 }; /* memory */
|
||
uint32 RA; /* Temp register */
|
||
uint32 RB; /* Temp register */
|
||
uint32 RC; /* Instruction Code */
|
||
uint32 RD; /* Datum pointer */
|
||
uint16 RK; /* Counter */
|
||
uint8 RF; /* Function code */
|
||
uint32 RL; /* Limit register */
|
||
uint8 RG; /* General register */
|
||
uint32 RM; /* M field register */
|
||
uint32 RP; /* Temp register */
|
||
uint32 RS; /* Temp register */
|
||
uint32 RT; /* Temp register */
|
||
uint8 RX; /* X field register */
|
||
uint32 XR[8]; /* Index registers */
|
||
uint32 faccl; /* Floating point accumulator low */
|
||
uint32 facch; /* Floating point accumulator high */
|
||
uint8 fovr; /* Floating point overflow */
|
||
uint8 BCarry; /* Carry bit */
|
||
uint8 BV; /* Overflow flag */
|
||
uint8 Mode; /* Mode */
|
||
uint8 Zero; /* Zero suppression flag */
|
||
uint8 exe_mode = 1; /* Executive mode */
|
||
#define EJM 040 /* Extended jump Mode */
|
||
#define DATUM 020 /* Datum mode */
|
||
#define AM22 010 /* 22 bit addressing */
|
||
#define EXTRC 004 /* Executive trace mode */
|
||
/* 002 */ /* unused mode bit */
|
||
uint8 OIP; /* Obey instruction */
|
||
uint8 PIP; /* Pre Modify instruction */
|
||
uint8 OPIP; /* Saved Pre Modify instruction */
|
||
uint32 SR1; /* Mill timer */
|
||
uint32 SR2; /* Typewriter I/P */
|
||
uint32 SR3; /* Typewriter O/P */
|
||
uint32 SR64; /* Interrupt status */
|
||
uint32 SR65; /* Interrupt status */
|
||
uint32 adrmask; /* Mask for addressing memory */
|
||
uint32 memmask; /* Memory address range mask */
|
||
uint8 loading; /* Loading bootstrap */
|
||
|
||
|
||
struct InstHistory
|
||
{
|
||
uint32 rc;
|
||
uint32 op;
|
||
uint32 ea;
|
||
uint32 xr;
|
||
uint32 ra;
|
||
uint32 rb;
|
||
uint32 rr;
|
||
uint8 c;
|
||
uint8 v;
|
||
uint8 e;
|
||
uint8 mode;
|
||
};
|
||
|
||
struct InstHistory *hst = NULL;
|
||
int32 hst_p = 0;
|
||
int32 hst_lnt = 0;
|
||
|
||
|
||
t_stat cpu_ex(t_value * vptr, t_addr addr, UNIT * uptr,
|
||
int32 sw);
|
||
t_stat cpu_dep(t_value val, t_addr addr, UNIT * uptr,
|
||
int32 sw);
|
||
t_stat cpu_reset(DEVICE * dptr);
|
||
t_stat cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr,
|
||
void *desc);
|
||
t_stat cpu_show_size(FILE * st, UNIT * uptr, int32 val,
|
||
CONST void *desc);
|
||
t_stat cpu_set_model(UNIT * uptr, int32 val, CONST char *cptr,
|
||
void *desc);
|
||
t_stat cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr,
|
||
void *desc);
|
||
t_stat cpu_show_float(FILE * st, UNIT * uptr, int32 val,
|
||
CONST void *desc);
|
||
t_stat cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr,
|
||
void *desc);
|
||
t_stat cpu_show_mult(FILE * st, UNIT * uptr, int32 val,
|
||
CONST void *desc);
|
||
t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val,
|
||
CONST void *desc);
|
||
t_stat cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr,
|
||
void *desc);
|
||
t_stat cpu_help(FILE *, DEVICE *, UNIT *, int32, const char *);
|
||
/* Interval timer */
|
||
t_stat rtc_srv(UNIT * uptr);
|
||
void time_read(uint32 *word);
|
||
int32 rtc_tps = 60 ;
|
||
int32 tmxr_poll = 10000;
|
||
|
||
|
||
|
||
CPUMOD cpu_modtab[] = {
|
||
{ "1901", MOD1, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||
{ "1901A", MOD1A, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||
{ "1901S", MOD1S, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||
{ "1901T", MOD1T, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||
{ "1902", MOD2, TYPE_A1|FLOAT_STD|FLOAT_OPT|MULT|SV, 0, 10 },
|
||
{ "1902A", MOD2A, TYPE_C2|FLOAT_STD|FLOAT_OPT|MULT|SV, 0, 10 },
|
||
{ "1902S", MOD2S, TYPE_C1|FLOAT_STD|FLOAT_OPT|MULT|SV, EXT_IO, 10 },
|
||
{ "1902T", MOD2T, TYPE_C1|FLOAT_STD|FLOAT_OPT|MULT|SV, EXT_IO, 10 },
|
||
{ "1903", MOD3, TYPE_A2|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, 0, 10 },
|
||
{ "1903A", MOD3A, TYPE_C2|FLOAT_STD|FLOAT_OPT|MULT|SV, 0, 10 },
|
||
{ "1903S", MOD3S, TYPE_C2|FLOAT_STD|FLOAT_OPT|MULT_OPT|SV, EXT_IO, 10 },
|
||
{ "1903T", MOD3T, TYPE_A2|FLOAT_STD|FLOAT_OPT|MULT_OPT|WG, 0, 10 },
|
||
{ "1904", MOD4, TYPE_B2|FLOAT_OPT|MULT|WG, 0, 1 },
|
||
{ "1904A", MOD4A, TYPE_C2|FLOAT_OPT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1904E", MOD4E, TYPE_C2|FLOAT_OPT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1904F", MOD4F, TYPE_C2|FLOAT_OPT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1904S", MOD4S, TYPE_C2|FLOAT_OPT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1905", MOD5, TYPE_A2|FLOAT|MULT|WG, 0, 1 },
|
||
{ "1905A", MOD5A, TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
|
||
{ "1905E", MOD5E, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1905F", MOD5F, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1905S", MOD5S, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1906", MOD6, TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
|
||
{ "1906A", MOD6A, TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 100 },
|
||
{ "1906E", MOD6E, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1906F", MOD6F, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1906S", MOD6S, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 100 },
|
||
{ "1907", MOD7, TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
|
||
{ "1907A", MOD7A, TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
|
||
{ "1907E", MOD7E, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1907F", MOD7F, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1907S", MOD7S, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1908", MOD8, TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
|
||
{ "1908A", MOD8A, TYPE_A2|FLOAT|MULT|WG|SL_FLOAT, 0, 10 },
|
||
{ "1908S", MOD8S, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 10 },
|
||
{ "1909", MOD9, TYPE_C2|FLOAT|MULT|WG|SL_FLOAT, EXT_IO, 1 },
|
||
{ NULL, 0, 0, 0, 0},
|
||
};
|
||
|
||
uint16 cpu_flags = TYPE_C2|FLOAT_OPT|MULT;
|
||
uint8 io_flags = EXT_IO;
|
||
|
||
/* 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, MODEL(MOD4A)|MEMAMOUNT(7)|UNIT_IDLE, MAXMEMSIZE ), 16667 }};
|
||
|
||
REG cpu_reg[] = {
|
||
{ORDATAD(C, RC, 22, "Instruction code"), REG_FIT},
|
||
{ORDATAD(F, RF, 7, "Order Code"), REG_FIT},
|
||
{ORDATAD(G, RG, 3, "General register"), REG_FIT},
|
||
{ORDATAD(D, RD, 22, "Datum"), REG_FIT},
|
||
{ORDATAD(L, RL, 22, "Limit"), REG_FIT},
|
||
{ORDATAD(M, Mode, 7, "Mode Register"), REG_FIT},
|
||
{BRDATAD(X, XR, 8, 24, 8, "Index Register"), REG_FIT},
|
||
{NULL}
|
||
};
|
||
|
||
MTAB cpu_mod[] = {
|
||
/* Stevenage */
|
||
{UNIT_MODEL, MODEL(MOD1), "1901", "1901", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD1A), "1901A", "1901A", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD1S), "1901S", "1901S", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD1T), "1901T", "1901T", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD2), "1902", "1902", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD2A), "1902A", "1902A", &cpu_set_model, NULL, NULL}, /* C1 */
|
||
{UNIT_MODEL, MODEL(MOD2S), "1902S", "1902S", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD2T), "1902T", "1902T", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD3), "1903", "1903", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD3A), "1903A", "1903A", &cpu_set_model, NULL, NULL}, /* C1 */
|
||
{UNIT_MODEL, MODEL(MOD3S), "1903S", "1903S", &cpu_set_model, NULL, NULL},
|
||
/* West Gorton */
|
||
{UNIT_MODEL, MODEL(MOD3T), "1903T", "1903T", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD4), "1904", "1904", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD4A), "1904A", "1904A", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD4E), "1904E", "1904E", &cpu_set_model, NULL, NULL}, /* C */
|
||
{UNIT_MODEL, MODEL(MOD4F), "1904F", "1904F", &cpu_set_model, NULL, NULL}, /* C */
|
||
{UNIT_MODEL, MODEL(MOD4S), "1904S", "1904S", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD5), "1905", "1905", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD5E), "1905E", "1905E", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD5F), "1905F", "1905F", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD5S), "1905S", "1905S", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD6), "1906", "1906", &cpu_set_model, NULL, NULL}, /* C */
|
||
{UNIT_MODEL, MODEL(MOD6A), "1906A", "1906A", &cpu_set_model, NULL, NULL}, /* C */
|
||
{UNIT_MODEL, MODEL(MOD6E), "1906E", "1906E", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD6F), "1906F", "1906F", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD7), "1907", "1907", &cpu_set_model, NULL, NULL}, /* C */
|
||
{UNIT_MODEL, MODEL(MOD7E), "1907E", "1907E", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD7F), "1907F", "1907F", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD8A), "1908A", "1908A", &cpu_set_model, NULL, NULL},
|
||
{UNIT_MODEL, MODEL(MOD9), "1909", "1909", &cpu_set_model, NULL, NULL},
|
||
{MTAB_XTD|MTAB_VDV, 0, NULL, "NOFLOAT", &cpu_set_float, NULL, NULL, "Disable floating point"},
|
||
{MTAB_XTD|MTAB_VDV, 1, "FLOAT", "FLOAT", &cpu_set_float, &cpu_show_float, NULL, "Enable floating point"},
|
||
{MTAB_XTD|MTAB_VDV, 0, NULL, "NOMULT", &cpu_set_mult, NULL, NULL, "Disable hardware multiply"},
|
||
{MTAB_XTD|MTAB_VDV, 1, "MULT", "MULT", &cpu_set_mult, &cpu_show_mult, NULL, "Enable hardware multiply"},
|
||
{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(3), NULL, "16K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(7), NULL, "32K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(11), NULL, "48K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(15), NULL, "64K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(23), NULL, "96K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(31), NULL, "128K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(63), NULL, "256K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(127), NULL, "512K", &cpu_set_size},
|
||
{UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(254), NULL, "1024K", &cpu_set_size},
|
||
{MTAB_VDV, 0, "MEMORY", NULL, NULL, &cpu_show_size},
|
||
{MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
|
||
{MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
|
||
{MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_SHP, 0, "HISTORY", "HISTORY",
|
||
&cpu_set_hist, &cpu_show_hist},
|
||
{0}
|
||
};
|
||
|
||
DEVICE cpu_dev = {
|
||
"CPU", cpu_unit, cpu_reg, cpu_mod,
|
||
1, 8, 22, 1, 8, 24,
|
||
&cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
|
||
NULL, DEV_DEBUG, 0, dev_debug,
|
||
NULL, NULL, &cpu_help
|
||
};
|
||
|
||
|
||
|
||
|
||
/* Test if we can access a word */
|
||
uint8 Mem_test(uint32 addr) {
|
||
addr &= M22;
|
||
|
||
if (!exe_mode) {
|
||
if (addr < 8)
|
||
return 0;
|
||
addr = addr + RD;
|
||
} else if (addr < 8)
|
||
return 0;
|
||
|
||
if (!exe_mode && RL && (addr < RD || addr >= RL)) {
|
||
SR64 |= B1;
|
||
return 1;
|
||
}
|
||
addr &= memmask;
|
||
if (addr > MEMSIZE) {
|
||
SR64 |= B1;
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
uint8 Mem_read(uint32 addr, uint32 *data, uint8 flag) {
|
||
addr &= M22;
|
||
|
||
SR1++;
|
||
if (!exe_mode) {
|
||
if (addr < 8) {
|
||
*data = XR[addr];
|
||
return 0;
|
||
}
|
||
addr = addr + RD;
|
||
} else if (flag && (Mode & DATUM) != 0) {
|
||
addr = addr + RD;
|
||
} else if (addr < 8) {
|
||
*data = XR[addr];
|
||
return 0;
|
||
}
|
||
|
||
if (!exe_mode && RL && (addr < RD || addr >= RL)) {
|
||
SR64 |= B1;
|
||
return 1;
|
||
}
|
||
addr &= memmask;
|
||
if (addr > MEMSIZE) {
|
||
SR64 |= B1;
|
||
return 1;
|
||
}
|
||
*data = M[addr];
|
||
return 0;
|
||
}
|
||
|
||
uint8 Mem_write(uint32 addr, uint32 *data, uint8 flag) {
|
||
addr &= M22;
|
||
|
||
if (!exe_mode) {
|
||
if (addr < 8) {
|
||
XR[addr] = *data;
|
||
return 0;
|
||
}
|
||
addr = addr + RD;
|
||
} else if (flag && (Mode & DATUM) != 0) {
|
||
addr = addr + RD;
|
||
} else if (addr < 8) {
|
||
XR[addr] = *data;
|
||
return 0;
|
||
}
|
||
if (!exe_mode && RL && (addr < RD || addr >= RL)) {
|
||
SR64 |= B1;
|
||
return 1;
|
||
}
|
||
addr &= memmask;
|
||
if (addr > MEMSIZE) {
|
||
SR64 |= B1;
|
||
return 1;
|
||
}
|
||
M[addr] = *data;
|
||
return 0;
|
||
}
|
||
|
||
t_stat
|
||
sim_instr(void)
|
||
{
|
||
t_stat reason;
|
||
uint32 temp; /* Hol order code being obeyed */
|
||
int m; /* Holds index register for address modification */
|
||
int n; /* Generic short term temp register */
|
||
int e1,e2; /* Temp for exponents */
|
||
int f; /* Used to hold flags */
|
||
|
||
memmask = (CPU_TYPE < TYPE_C1) ? M15: M22;
|
||
adrmask = (Mode & AM22) ? M22 : M15;
|
||
reason = chan_set_devs();
|
||
|
||
while (reason == SCPE_OK) { /* loop until halted */
|
||
if (sim_interval <= 0) { /* event queue? */
|
||
reason = sim_process_event();
|
||
if (reason != SCPE_OK) {
|
||
break; /* process */
|
||
}
|
||
}
|
||
|
||
if (sim_brk_summ) {
|
||
if(sim_brk_test(RC, SWMASK('E'))) {
|
||
reason = SCPE_STOP;
|
||
break;
|
||
}
|
||
}
|
||
|
||
while (loading) { /* event queue? */
|
||
reason = sim_process_event();
|
||
if (reason != SCPE_OK) {
|
||
break; /* process */
|
||
}
|
||
if ((SR64 | SR65) != 0) {
|
||
loading = 0;
|
||
exe_mode = 1;
|
||
RC = 020;
|
||
}
|
||
sim_interval--;
|
||
}
|
||
|
||
intr:
|
||
if (!exe_mode && (SR64 | SR65) != 0) {
|
||
if (CPU_TYPE < TYPE_C1 && !exe_mode)
|
||
RC += RD;
|
||
exe_mode = 1;
|
||
loading = 0;
|
||
/* Store registers */
|
||
if (cpu_flags & FLOAT && cpu_flags & SL_FLOAT) {
|
||
Mem_write(RD+12, &faccl, 0);
|
||
RT = facch;
|
||
if (fovr)
|
||
RT |= B0;
|
||
Mem_write(RD+13, &RT, 0); /* Save F.P.U. */
|
||
}
|
||
RA = 0; /* Build ZSTAT */
|
||
if (cpu_flags & SV) {
|
||
Mem_read(RD+9, &RA, 0);
|
||
RA &= M15;
|
||
RA |= ((Mode|DATUM) << 16);
|
||
if (Mode & DATUM)
|
||
RA |= 1 << 16;
|
||
if (BCarry)
|
||
RA |= B1;
|
||
} else {
|
||
if (CPU_TYPE >= TYPE_C1) {
|
||
Mem_read(RD+9, &RA, 0);
|
||
RA &= M15;
|
||
if (Zero)
|
||
RA |= B3;
|
||
if (OPIP | PIP)
|
||
RA |= B2;
|
||
Mem_write(RD+9, &RA, 0);
|
||
}
|
||
}
|
||
RA = RC & memmask;
|
||
if (io_flags & EXT_IO) {
|
||
if (BCarry)
|
||
RA |= B1;
|
||
} else {
|
||
RC &= M15;
|
||
if (Zero)
|
||
RA |= B8;
|
||
}
|
||
if (BV)
|
||
RA |= B0;
|
||
Mem_write(RD+8, &RA, 0);
|
||
for (n = 0; n < 8; n++)
|
||
Mem_write(RD+n, &XR[n], 0);
|
||
BV = BCarry = Mode = Zero = 0;
|
||
adrmask = M15;
|
||
RC = 020;
|
||
PIP = 0;
|
||
}
|
||
|
||
fetch:
|
||
if (!exe_mode && (Mode & 7) == 1)
|
||
SR64 |= B2;
|
||
|
||
if (Mem_read(RC, &temp, 0)) {
|
||
if (hst_lnt) { /* history enabled? */
|
||
hst_p = (hst_p + 1); /* next entry */
|
||
if (hst_p >= hst_lnt)
|
||
hst_p = 0;
|
||
hst[hst_p].rc = RC | HIST_PC;
|
||
hst[hst_p].ea = RC;
|
||
hst[hst_p].op = 0;
|
||
hst[hst_p].xr = 0;
|
||
hst[hst_p].ra = 0;
|
||
hst[hst_p].rb = 0;
|
||
hst[hst_p].rr = 0;
|
||
hst[hst_p].c = BCarry;
|
||
hst[hst_p].v = BV;
|
||
hst[hst_p].e = exe_mode;
|
||
hst[hst_p].mode = Mode;
|
||
}
|
||
RC = (RC + 1) & ((Mode & (EJM|AM22)) ? M22: M15);
|
||
goto intr;
|
||
}
|
||
obey:
|
||
RM = temp & 037777;
|
||
RF = 0177 & (temp >> 14);
|
||
RX = 07 & (temp >> 21);
|
||
/* Check if branch opcode */
|
||
if (RF >= 050 && RF < 0100) {
|
||
RA = XR[RX];
|
||
RM = RB = temp & 077777;
|
||
/* Handle PC relative addressing */
|
||
if ((Mode & EJM) != 0 && (RF & 1) == 0) {
|
||
RB = RB | ((RB & 020000) ? 017740000 : 0); /* Sign extend RB */
|
||
RB = (RB + RC) & M22;
|
||
}
|
||
m = 0;
|
||
} else {
|
||
RA = XR[RX];
|
||
m = 03 & (RM >> 12);
|
||
RB = RM & 07777;
|
||
if (PIP)
|
||
RB = (RB + RP) & adrmask;
|
||
if (m != 0)
|
||
RB = (RB + XR[m]) & adrmask;
|
||
RS = RB;
|
||
if (RF < 050) {
|
||
if (Mem_read(RS, &RB, 1)) {
|
||
if (hst_lnt) { /* history enabled? */
|
||
hst_p = (hst_p + 1); /* next entry */
|
||
if (hst_p >= hst_lnt)
|
||
hst_p = 0;
|
||
hst[hst_p].rc = (RC - 1) | HIST_PC;
|
||
hst[hst_p].ea = RS;
|
||
hst[hst_p].op = temp;
|
||
hst[hst_p].xr = XR[RX];
|
||
hst[hst_p].ra = RA;
|
||
hst[hst_p].rb = RB;
|
||
hst[hst_p].rr = RB;
|
||
hst[hst_p].c = BCarry;
|
||
hst[hst_p].v = BV;
|
||
hst[hst_p].e = exe_mode;
|
||
hst[hst_p].mode = Mode;
|
||
}
|
||
RC = (RC + 1) & ((Mode & (EJM|AM22)) ? M22: M15);
|
||
goto intr;
|
||
}
|
||
if (RF & 010) {
|
||
uint32 t;
|
||
t = RA;
|
||
RA = RB;
|
||
RB = t;
|
||
}
|
||
}
|
||
}
|
||
OPIP = PIP;
|
||
PIP = 0;
|
||
|
||
if (hst_lnt && RC != 7) { /* history enabled? */
|
||
hst_p = (hst_p + 1); /* next entry */
|
||
if (hst_p >= hst_lnt)
|
||
hst_p = 0;
|
||
hst[hst_p].rc = RC | HIST_PC;
|
||
hst[hst_p].ea = RS;
|
||
hst[hst_p].op = temp;
|
||
hst[hst_p].xr = XR[RX];
|
||
hst[hst_p].ra = RA;
|
||
hst[hst_p].rb = RB;
|
||
hst[hst_p].rr = RB;
|
||
hst[hst_p].c = BCarry;
|
||
hst[hst_p].v = BV;
|
||
hst[hst_p].e = exe_mode;
|
||
hst[hst_p].mode = Mode;
|
||
}
|
||
|
||
/* Advance to next location, except on OBEY order */
|
||
if (RF != OP_OBEY)
|
||
RC = (RC + 1) & ((Mode & (EJM|AM22)) ? M22: M15);
|
||
OIP = 0;
|
||
|
||
switch (RF) {
|
||
case OP_LDX: /* Load to X */
|
||
case OP_LDXC: /* Load into X with carry */
|
||
case OP_LDN: /* Load direct to X */
|
||
case OP_LDNC: /* Load direct into X with carry */
|
||
case OP_STO: /* Store contents of X */
|
||
case OP_STOC: /* Store contents of X with carry */
|
||
case OP_NGS: /* Negative into Store */
|
||
case OP_NGSC: /* Negative into Store with carry */
|
||
case OP_NGN: /* Negative direct to X */
|
||
case OP_NGNC: /* Negative direct to X with carry */
|
||
case OP_NGX: /* Negative to X */
|
||
case OP_NGXC: /* Negative to X with carry */
|
||
RA = 0;
|
||
/* Fall through */
|
||
|
||
case OP_SBX: /* Subtract from X */
|
||
case OP_SBXC: /* Subtract from X with carry */
|
||
case OP_SBS: /* Subtract from store */
|
||
case OP_SBSC: /* Subtract from store with carry */
|
||
case OP_SBN: /* Subtract direct from X */
|
||
case OP_SBNC: /* Subtract direct from X with carry */
|
||
case OP_ADX: /* Add to X */
|
||
case OP_ADXC: /* Add to X with carry */
|
||
case OP_ADN: /* Add direct to X */
|
||
case OP_ADNC: /* Add direct to X with carry */
|
||
case OP_ADS: /* Add X to store */
|
||
case OP_ADSC: /* Add X to store with carry */
|
||
if (RF & 02) {
|
||
RB = RB ^ FMASK;
|
||
BCarry = !BCarry;
|
||
}
|
||
n = (RA & B0) != 0;
|
||
RA = RA + RB + BCarry;
|
||
if (RF & 04) {
|
||
if (RF & 02)
|
||
BCarry = (RA & BM1) == 0;
|
||
else
|
||
BCarry = (RA & B0) != 0;
|
||
RA &= M23;
|
||
} else {
|
||
int t2 = (RB & B0) != 0;
|
||
int tr = (RA & B0) != 0;
|
||
if ((n && t2 && !tr) || (!n && !t2 && tr)) {
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
BCarry = 0;
|
||
}
|
||
RA &= FMASK;
|
||
if (RF & 010) {
|
||
if (Mem_write(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
} else {
|
||
XR[RX] = RA;
|
||
}
|
||
break;
|
||
|
||
case OP_ANDX: /* Logical AND into X */
|
||
case OP_ANDS: /* Logical AND into store */
|
||
case OP_ANDN: /* Logical AND direct into X */
|
||
RA = RA & RB;
|
||
BCarry = 0;
|
||
if (RF & 010) {
|
||
if (Mem_write(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
} else {
|
||
XR[RX] = RA;
|
||
}
|
||
break;
|
||
|
||
case OP_ORX: /* Logical OR into X */
|
||
case OP_ORS: /* Logical OR into store */
|
||
case OP_ORN: /* Logical OR direct into X */
|
||
RA = RA | RB;
|
||
BCarry = 0;
|
||
if (RF & 010) {
|
||
if (Mem_write(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
} else {
|
||
XR[RX] = RA;
|
||
}
|
||
break;
|
||
|
||
case OP_ERX: /* Logical XOR into X */
|
||
case OP_ERS: /* Logical XOR into store */
|
||
case OP_ERN: /* Logical XOR direct into X */
|
||
RA = RA ^ RB;
|
||
BCarry = 0;
|
||
if (RF & 010) {
|
||
if (Mem_write(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
} else {
|
||
XR[RX] = RA;
|
||
}
|
||
break;
|
||
|
||
case OP_OBEY: /* Obey instruction at N */
|
||
temp = RB;
|
||
OIP = 1;
|
||
goto obey;
|
||
|
||
case OP_LDCH: /* Load Character to X */
|
||
m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
|
||
RA = RB >> (6 * (3 - m));
|
||
RA = XR[RX] = RA & 077;
|
||
BCarry = 0;
|
||
break;
|
||
|
||
case OP_LDEX: /* Load Exponent */
|
||
RA = XR[RX] = RB & M9;
|
||
BCarry = 0;
|
||
break;
|
||
|
||
case OP_TXU: /* Test X unequal */
|
||
if (RA != RB)
|
||
BCarry = 1;
|
||
break;
|
||
|
||
case OP_TXL: /* Test X Less */
|
||
RB += BCarry;
|
||
if (RB != RA)
|
||
BCarry = (RB > RA);
|
||
break;
|
||
|
||
case OP_STOZ: /* Store Zero */
|
||
/* Stevenage Machines */
|
||
if ((cpu_flags & SV) != 0 && exe_mode && RX != 0)
|
||
XR[RX] = RA;
|
||
RB = 0;
|
||
BCarry = 0;
|
||
if (Mem_write(RS, &RB, 1)) {
|
||
goto intr;
|
||
}
|
||
break;
|
||
|
||
case OP_DCH: /* Deposit Character to X */
|
||
m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
|
||
m = 6 * (3 - m);
|
||
RB = (RB & 077) << m;
|
||
RA &= ~(077 << m);
|
||
RA |= RB;
|
||
BCarry = 0;
|
||
if (Mem_write(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
break;
|
||
|
||
case OP_DEX: /* Deposit Exponent */
|
||
RA &= ~M9;
|
||
RA = RA | (RB & M9);
|
||
BCarry = 0;
|
||
if (Mem_write(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
break;
|
||
|
||
case OP_DSA: /* Deposit Short Address */
|
||
RA &= ~M12;
|
||
RA |= (RB & M12);
|
||
BCarry = 0;
|
||
if (Mem_write(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
break;
|
||
|
||
case OP_DLA: /* Deposit Long Address */
|
||
RA &= ~M15;
|
||
RA |= (RB & M15);
|
||
BCarry = 0;
|
||
if (Mem_write(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
break;
|
||
|
||
case OP_MPY: /* Multiply */
|
||
case OP_MPR: /* Multiply and Round */
|
||
case OP_MPA: /* Multiply and Accumulate */
|
||
if ((cpu_flags & MULT) == 0)
|
||
goto voluntary;
|
||
if (RA == B0 && RB == B0) {
|
||
if (RF != OP_MPA || (XR[(RX + 1) & 7] & B0) == 0) {
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
}
|
||
RP = RA;
|
||
RA = RB;
|
||
n = RP & 1;
|
||
RP >>= 1;
|
||
if (RF & 1) /* Multiply and Round */
|
||
RP |= B0;
|
||
RB = 0;
|
||
for(RK = 23; RK != 0; RK--) {
|
||
if (n)
|
||
RB += RA;
|
||
n = RP & 1;
|
||
RP >>= 1;
|
||
if (RB & 1)
|
||
RP |= B0;
|
||
if (RB & B0)
|
||
RB |= BM1;
|
||
RB >>= 1;
|
||
}
|
||
|
||
if (n) {
|
||
RB += (RA ^ FMASK) + 1;
|
||
}
|
||
n = RP & 1; /* Check for MPR */
|
||
if (n && RP & B0)
|
||
RB++;
|
||
RP >>= 1;
|
||
if (RF == OP_MPA) {
|
||
RA = XR[(RX + 1) & 7];
|
||
RP += RA;
|
||
if (RA & B0)
|
||
RB--;
|
||
else if (RP & B0)
|
||
RB++;
|
||
}
|
||
|
||
XR[RX] = RB & FMASK;
|
||
RA = XR[(RX+1) & 7] = RP & M23;
|
||
BCarry = 0;
|
||
break;
|
||
|
||
case OP_CDB: /* Convert Decimal to Binary */
|
||
m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
|
||
RB = (RB >> (6 * (3 - m))) & 077;
|
||
if (RB > 9) {
|
||
BCarry = 1;
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
|
||
case OP_CBD: /* Convert Binary to Decimal */
|
||
RT = RB;
|
||
RB = XR[(RX+1) & 7];
|
||
/* Multiply by 10 */
|
||
RB <<= 2;
|
||
RA <<= 2;
|
||
RA |= (RB >> 23) & 07;
|
||
RB &= M23;
|
||
RB += XR[(RX+1) & 7];
|
||
if (RB & B0)
|
||
RA++;
|
||
RA += XR[RX];
|
||
RB <<= 1;
|
||
RA <<= 1;
|
||
if (RB & B0)
|
||
RA++;
|
||
RB &= M23;
|
||
if (RF == OP_CDB) {
|
||
/* Add in RT */
|
||
RB += RT;
|
||
if (RB & B0)
|
||
RA++;
|
||
RB &= M23;
|
||
if (RA & ~(M23)) {
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
RA &= M23;
|
||
} else {
|
||
/* Save bits over 23 to char */
|
||
m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
|
||
m = 6 * (3 - m);
|
||
RP = (RA >> 23) & 017;
|
||
if (Zero && RP == 0)
|
||
RP = 020;
|
||
else
|
||
Zero = 0;
|
||
RA &= M23;
|
||
RT &= ~(077 << m);
|
||
RT |= (RP << m);
|
||
if (Mem_write(RS, &RT, 1)) {
|
||
goto intr;
|
||
}
|
||
}
|
||
XR[(RX+1) & 7] = RB;
|
||
XR[RX] = RA;
|
||
break;
|
||
|
||
case OP_DVD: /* Unrounded Double Length Divide */
|
||
case OP_DVR: /* Rounded Double Length Divide */
|
||
case OP_DVS: /* Single Length Divide */
|
||
if ((cpu_flags & MULT) == 0)
|
||
goto voluntary;
|
||
RP = XR[(RX+1) & 7]; /* VR */
|
||
RA = RB; /* Divisor to RA */
|
||
RB = XR[RX]; /* Dividend to RB/RP */
|
||
//fprintf(stderr, "DVD0: %08o %08o %08o - %3o C=%08o\n\r", RA, RB, RP, RF, RC);
|
||
|
||
if (RA == 0) { /* Exit on zero divisor */ /* VI */
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
BCarry = 0;
|
||
break;
|
||
}
|
||
|
||
/* Setup for specific divide order code */ /* V11 */
|
||
if (RF & 2) { /* DVS */
|
||
if (RP & B0) { /* RC22 */ /* Sign extend RB */
|
||
RB = FMASK;
|
||
} else {
|
||
RB = 0;
|
||
}
|
||
}
|
||
|
||
// {
|
||
// long int divsor;
|
||
// long int dividend;
|
||
// int sign;
|
||
//
|
||
// dividend = (((long int)(RB)) << 23) | (long int)(RP);
|
||
// if (RB & B0) {
|
||
// dividend |= 0xffff800000000000;
|
||
// }
|
||
// sign = 1;
|
||
// divsor = (long int)(RA);
|
||
// if (RA & B0) {
|
||
// divsor |= 0xffffffffff000000;
|
||
// sign = -1;
|
||
// }
|
||
//fprintf(stderr, "DVD1: %08o %08o %08o %ld (%lo) / %ld (%lo) = %ld (%lo) m %ld (%lo) %o\n\r", RA, RB, RP,
|
||
// dividend, dividend, divsor, divsor, dividend/divsor, dividend/divsor,
|
||
// sign* (dividend%divsor), sign *(dividend % divsor), BV);
|
||
//}
|
||
BCarry = 0;
|
||
if ((RB | RP) == 0)
|
||
goto dvd_zero;
|
||
RP <<= 1;
|
||
RP &= FMASK;
|
||
BCarry = 0;
|
||
|
||
/* First partial remainder */ /* V12 */
|
||
if (((RB ^ RA) & B0) == 0) {
|
||
RS = RB + (RA ^ FMASK) + 1;
|
||
RK=1;
|
||
} else {
|
||
RS = RB + RA;
|
||
RK=0;
|
||
}
|
||
/* Check if potiential overflow */
|
||
if (((RS ^ RA) & B0) != 0)
|
||
BCarry = 1;
|
||
BCarry = RK != BCarry;
|
||
/* Shift left quotent and remainder */
|
||
RP <<= 1;
|
||
if (((RS ^ RA) & B0) == 0) {
|
||
RP |= 1; /* First quotient digit */
|
||
}
|
||
RB = RS << 1;
|
||
if (RP & BM1)
|
||
RB |= 1;
|
||
RB &= FMASK;
|
||
RP &= FMASK;
|
||
//fprintf(stderr, "DVD2: %08o %08o %08o \n\r", RA, RP, RB);
|
||
|
||
/* Main divide loop */ /* V13 */
|
||
for (RK = 22; RK != 0; RK--) {
|
||
if (((RS ^ RA) & B0) == 0) {
|
||
RS = RB + (RA ^ FMASK) + 1;
|
||
} else {
|
||
RS = RB + RA;
|
||
}
|
||
RP <<= 1;
|
||
if (((RS ^ RA) & B0) == 0) {
|
||
RP |= 1;
|
||
}
|
||
RB = RS << 1;
|
||
if (RP & BM1)
|
||
RB |= 1;
|
||
RB &= FMASK;
|
||
RP &= FMASK;
|
||
//fprintf(stderr, "DVD3: %08o %08o %08o %08o \n\r", RA, RP, RB, RS);
|
||
}
|
||
|
||
/* Final product */
|
||
if (((RS ^ RA) & B0) == 0) { /* V14 */
|
||
RS = RB + (RA ^ FMASK) + 1;
|
||
} else {
|
||
RS = RB + RA;
|
||
}
|
||
RP <<= 1;
|
||
if (((RS ^ RA) & B0) == 0) {
|
||
RP |= 1;
|
||
}
|
||
RP &= FMASK;
|
||
RB = RS & FMASK;
|
||
//fprintf(stderr, "DVD4: %08o %08o %08o %08o \n\r", RA, RP, RB, RS);
|
||
/* End correction */
|
||
if ((RP & 1) == 0) {
|
||
RB = (RB + RA) & FMASK;
|
||
}
|
||
//fprintf(stderr, "DVD5: %08o %08o %08o \n\r", RA, RP, RB);
|
||
if ((RF & 1) == 0 || RB == 0) {
|
||
//fprintf(stderr, "DVD7: %08o %08o %08o \n\r", RA, RP, RB);
|
||
/* If remainder same as divisor, bump quotent zero remainder */
|
||
if (RB == RA) {
|
||
RT = RP;
|
||
RP++;
|
||
if ((RT & B0) != (RP & B0))
|
||
BCarry = !BCarry;
|
||
RB = 0;
|
||
}
|
||
} else { /* DVR */
|
||
RT = RB + (RA ^ FMASK) + 1;
|
||
//fprintf(stderr, "DVDA: %08o %08o %08o %08o \n\r", RA, RP, RB, RT);
|
||
RA = RB;
|
||
if ((((RT + RA) ^ RA) & B0) == 0) {
|
||
RB = RT & FMASK;
|
||
//fprintf(stderr, "DVD6: %08o %08o %08o \n\r", RA, RP, RB);
|
||
RT = RP;
|
||
RP++;
|
||
if ((RT ^ RP) & B0)
|
||
BCarry = !BCarry;
|
||
if (RP & BM1)
|
||
BCarry = 1;
|
||
}
|
||
}
|
||
dvd_zero:
|
||
/* Set overflow if BCarry still set */
|
||
if (BCarry) {
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
BCarry = 0;
|
||
// {
|
||
// int32 a;
|
||
// int32 b;
|
||
//
|
||
// a = RB;
|
||
// if (RB & B0)
|
||
// a |= 0xff000000;
|
||
// b = RP;
|
||
// if (RP & B0)
|
||
// b |= 0xff000000;
|
||
//fprintf(stderr, "DVD8: q=%08o(%d) r=%08o(%d) %d %d %d\n\r", RP, b, RB, a, BV);
|
||
//}
|
||
XR[RX] = RB & FMASK;
|
||
XR[(RX+1) & 7] = RP & FMASK;
|
||
break;
|
||
|
||
case OP_BZE: /* Branch if X is Zero */
|
||
case OP_BZE1:
|
||
BCarry = 0;
|
||
if (RA == 0)
|
||
goto branch;
|
||
break;
|
||
|
||
case OP_BNZ: /* Branch if X is not Zero */
|
||
case OP_BNZ1:
|
||
BCarry = 0;
|
||
if (RA != 0)
|
||
goto branch;
|
||
break;
|
||
|
||
case OP_BPZ: /* Branch if X is Positive or zero */
|
||
case OP_BPZ1:
|
||
BCarry = 0;
|
||
if ((RA & B0) == 0)
|
||
goto branch;
|
||
break;
|
||
|
||
case OP_BNG: /* Branch if X is Negative */
|
||
case OP_BNG1:
|
||
BCarry = 0;
|
||
if ((RA & B0) != 0)
|
||
goto branch;
|
||
break;
|
||
|
||
case OP_BUX: /* Branch on Unit indexing */
|
||
case OP_BUX1:
|
||
BCarry = 0;
|
||
if (Mode & AM22) {
|
||
RA = ((RA+1) & M22) | (RA & CMASK);
|
||
XR[RX] = RA;
|
||
goto branch;
|
||
} else {
|
||
RS = CNTMSK + RA; /* Actualy a subtract 1 */
|
||
RS &= CNTMSK;
|
||
RA = ((RA + 1) & M15) | RS;
|
||
}
|
||
XR[RX] = RA;
|
||
if (RS != 0)
|
||
goto branch;
|
||
break;
|
||
|
||
case OP_BDX: /* Branch on Double Indexing */
|
||
case OP_BDX1:
|
||
BCarry = 0;
|
||
if (Mode & AM22) {
|
||
RA = ((RA+2) & M22) | (RA & CMASK);
|
||
XR[RX] = RA;
|
||
goto branch;
|
||
} else {
|
||
RS = CNTMSK + RA; /* Actualy a subtract 1 */
|
||
RS &= CNTMSK;
|
||
RA = ((RA + 2) & M15) | RS;
|
||
}
|
||
XR[RX] = RA;
|
||
if (RS != 0)
|
||
goto branch;
|
||
break;
|
||
|
||
case OP_BCHX: /* Branch on Character Indexing */
|
||
case OP_BCHX1:
|
||
BCarry = 0;
|
||
RA += B1;
|
||
n = (RA & BM1) != 0;
|
||
if (Mode & AM22) {
|
||
RA = ((RA + n) & M22) | (RA & CMASK);
|
||
XR[RX] = RA;
|
||
goto branch;
|
||
} else {
|
||
RS = CHCMSK + RA; /* Actually a subtract 1 */
|
||
RS &= CHCMSK;
|
||
RA = ((RA + n) & M15) | RS | (RA & CMASK);
|
||
}
|
||
XR[RX] = RA;
|
||
if (RS != 0)
|
||
goto branch;
|
||
break;
|
||
|
||
/* Not on A */
|
||
case OP_BCT: /* Branch on Count - BC */
|
||
case OP_BCT1:
|
||
BCarry = 0;
|
||
if (Mode & AM22) {
|
||
RA = ((RA-1) & M22) | (RA & CMASK);
|
||
RS = RA & M22;
|
||
} else {
|
||
RA = ((RA - 1) & M15) | (CNTMSK & RA);
|
||
RS = RA & M15;
|
||
}
|
||
XR[RX] = RA;
|
||
if (RS != 0)
|
||
goto branch;
|
||
break;
|
||
|
||
case OP_CALL: /* Call Subroutine */
|
||
case OP_CALL1:
|
||
RA = RC;
|
||
if ((Mode & (AM22|EJM)) == 0) {
|
||
RA &= adrmask;
|
||
if (Zero)
|
||
RA |= B8;
|
||
} else {
|
||
if (Zero)
|
||
RA |= B1;
|
||
}
|
||
if (BV)
|
||
RA |= B0;
|
||
BV = 0;
|
||
BCarry = 0;
|
||
XR[RX] = RA;
|
||
branch:
|
||
/* Monitor mode 3 -> int */
|
||
if (!exe_mode && (Mode & 7) == 3) {
|
||
SR64 |= B2;
|
||
break;
|
||
}
|
||
/* Handle replace jump */
|
||
if ((Mode & EJM) != 0 && (RF & 1) != 0) {
|
||
RB &= 037777;
|
||
if (Mem_read(RB, &RB, 0)) {
|
||
goto intr;
|
||
}
|
||
}
|
||
/* Handle SMO */
|
||
if (OPIP)
|
||
RB = (RB + RP) & adrmask;
|
||
if (hst_lnt) { /* history enabled? */
|
||
hst[hst_p].ea = RB;
|
||
}
|
||
/* Don't transfer if address not valid */
|
||
if (Mem_test(RB))
|
||
goto intr;
|
||
/* Monitor mode 2 -> Exec Mon */
|
||
/* Read address to store from location 262. */
|
||
/* Store address transfer address at location, increment 262 mod 128 */
|
||
if (!exe_mode && (Mode & 7) == 2) {
|
||
temp = M[262];
|
||
M[temp & adrmask] = RB;
|
||
M[262] = (temp & ~ 0177) + ((temp + 1) & 0177);
|
||
}
|
||
if ((Mode & (EJM|AM22)) == 0)
|
||
RB &= M15;
|
||
else
|
||
RB &= M22;
|
||
RC = RB;
|
||
break;
|
||
|
||
case OP_EXIT: /* Exit Subroutine */
|
||
case OP_EXIT1:
|
||
if (RA & B0) {
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
Zero = 0;
|
||
if ((Mode & (AM22|EJM)) == 0) {
|
||
if (RA & B8)
|
||
Zero = 1;
|
||
} else {
|
||
if (RA & B1)
|
||
Zero = 1;
|
||
}
|
||
BCarry = 0;
|
||
RM = RM | ((RM & 040000) ? 017740000 : 0); /* Sign extend RM */
|
||
RA = RA + RM;
|
||
if (OPIP)
|
||
RA = RA + RP;
|
||
if (hst_lnt) { /* history enabled? */
|
||
hst[hst_p].ea = RA;
|
||
}
|
||
if ((Mode & (EJM|AM22)) == 0)
|
||
RA &= M15;
|
||
else
|
||
RA &= M22;
|
||
if (Mem_test(RA)) { /* Verify memory location accessable */
|
||
goto intr;
|
||
}
|
||
RC = RA;
|
||
break;
|
||
|
||
case OP_BRN: /* Branch unconditional */
|
||
case OP_BRN1:
|
||
/* If priorit mode -> 164 */
|
||
switch(RX) {
|
||
case 0: /* BRN */
|
||
goto branch;
|
||
|
||
case 1: /* BVS */
|
||
if (BV)
|
||
goto branch;
|
||
break;
|
||
|
||
case 2: /* BVSR */
|
||
n = BV;
|
||
BV = 0;
|
||
if (n)
|
||
goto branch;
|
||
break;
|
||
|
||
case 3: /* BVC */
|
||
if (BV == 0)
|
||
goto branch;
|
||
break;
|
||
|
||
case 4: /* BVCR */
|
||
if (BV == 0)
|
||
goto branch;
|
||
BV = 0;
|
||
break;
|
||
|
||
case 5: /* BCS */
|
||
n = BCarry;
|
||
BCarry = 0;
|
||
if (n)
|
||
goto branch;
|
||
break;
|
||
|
||
case 6: /* BCC */
|
||
n = BCarry;
|
||
BCarry = 0;
|
||
if (!n)
|
||
goto branch;
|
||
break;
|
||
|
||
case 7: /* BVC */
|
||
n = BV;
|
||
BV = !BV;
|
||
if (!exe_mode && (Mode & 7) == 4 && BV)
|
||
SR64 |= B2;
|
||
if (n == 0)
|
||
goto branch;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
/* B with Floating or C */
|
||
case OP_BFP: /* Branch state of floating point accumulator */
|
||
case OP_BFP1:
|
||
if ((cpu_flags & FLOAT) == 0)
|
||
goto voluntary;
|
||
if ((RX & 04) == 0 && fovr)
|
||
BV = 1;
|
||
switch (RX & 06) {
|
||
default:
|
||
case 0: n = (faccl | facch) != 0; break;
|
||
case 2: n = (faccl & B0) != 0; break;
|
||
case 4: n = fovr; break;
|
||
case 6: SR64 |= B1; goto intr;
|
||
}
|
||
if (n == (RX & 1))
|
||
goto branch;
|
||
break;
|
||
|
||
case OP_SLL: /* Shift Left */
|
||
m = (RB >> 10) & 03;
|
||
RK = RB & 01777;
|
||
BCarry = 0;
|
||
while (RK != 0) {
|
||
n = 0;
|
||
switch (m) {
|
||
case 0: n = (RA & B0) != 0; break;
|
||
case 1: break;
|
||
case 2:
|
||
case 3: temp = RA & B0;
|
||
}
|
||
RA <<= 1;
|
||
RA |= n;
|
||
if ((m & 2) && temp != (RA & B0)) {
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
RA &= FMASK;
|
||
RK--;
|
||
}
|
||
XR[RX] = RA;
|
||
break;
|
||
|
||
case OP_SLD: /* Shift Left Double */
|
||
m = (RB >> 10) & 03;
|
||
RK = RB & 01777;
|
||
BCarry = 0;
|
||
RB = XR[(RX+1) & 07];
|
||
while (RK != 0) {
|
||
switch (m) {
|
||
case 0:
|
||
RB <<= 1;
|
||
RA <<= 1;
|
||
if (RA & BM1)
|
||
RB |= 1;
|
||
if (RB & BM1)
|
||
RA |= 1;
|
||
break;
|
||
case 1:
|
||
RB <<= 1;
|
||
RA <<= 1;
|
||
if (RB & BM1)
|
||
RA |= 1;
|
||
break;
|
||
case 2:
|
||
case 3:
|
||
RB <<= 1;
|
||
RA <<= 1;
|
||
if (RB & B0)
|
||
RA |= 1;
|
||
RB &= M23;
|
||
n = (RA & B0) != 0;
|
||
temp = (RA & BM1) != 0;
|
||
if ((uint32)n != temp) {
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
}
|
||
RA &= FMASK;
|
||
RB &= FMASK;
|
||
RK--;
|
||
}
|
||
XR[RX] = RA;
|
||
XR[(RX+1) & 07] = RB;
|
||
break;
|
||
|
||
case OP_SRL: /* Shift Right */
|
||
m = (RB >> 10) & 03;
|
||
RK = RB & 01777;
|
||
RT = RA & B0;
|
||
BCarry = 0;
|
||
switch(m) {
|
||
case 0: break;
|
||
case 1: RT = 0; break;
|
||
case 2: break;
|
||
case 3: if (BV) {
|
||
RT = B0 ^ RT;
|
||
BV = 0;
|
||
}
|
||
}
|
||
while (RK != 0) {
|
||
if (m == 0)
|
||
RT = (RA & 1) ? B0 : 0;
|
||
temp = RA & 1;
|
||
RA >>= 1;
|
||
RA |= RT;
|
||
RK--;
|
||
}
|
||
if (m > 1 && temp == 1)
|
||
RA = (RA + 1) & FMASK;
|
||
XR[RX] = RA;
|
||
break;
|
||
|
||
case OP_SRD: /* Shift Right Double */
|
||
m = (RB >> 10) & 03;
|
||
RK = RB & 01777;
|
||
RB = XR[(RX+1) & 07];
|
||
BCarry = 0;
|
||
RT = RA & B0;
|
||
if (m == 3 && RK != 0 && BV) {
|
||
RT = B0^RT;
|
||
BV = 0;
|
||
}
|
||
while (RK != 0) {
|
||
switch (m) {
|
||
case 0:
|
||
if (RA & 1)
|
||
RB |= BM1;
|
||
if (RB & 1)
|
||
RA |= BM1;
|
||
RA >>= 1;
|
||
RB >>= 1;
|
||
break;
|
||
case 1:
|
||
RB >>= 1;
|
||
if (RA & 1)
|
||
RB |= B0;
|
||
RA >>= 1;
|
||
break;
|
||
case 2:
|
||
case 3:
|
||
RB >>= 1;
|
||
if (RA & 1)
|
||
RB |= B1;
|
||
RA >>= 1;
|
||
RA |= RT;
|
||
}
|
||
RK--;
|
||
}
|
||
XR[RX] = RA;
|
||
XR[(RX+1) & 07] = RB;
|
||
break;
|
||
|
||
case OP_NORM: /* Nomarlize Single -2 +FP */
|
||
case OP_NORMD: /* Normalize Double -2 +FP */
|
||
if ((cpu_flags & NORM_OP) == 0)
|
||
goto voluntary;
|
||
RT = RB;
|
||
RB = (RF & 1) ? XR[(RX+1) & 07] & M23 : 0;
|
||
//fprintf(stderr, "Norm0: %08o %08o %08o\n\r", RA, RB, RT);
|
||
if (RT & 04000) {
|
||
RT = 0;
|
||
} else {
|
||
RT &= 01777;
|
||
}
|
||
if (RT == 0) {
|
||
RA = RB = 0;
|
||
} else if (BV) {
|
||
RT++;
|
||
RP = (RA & B0) ^ B0;
|
||
if (RA & 1 && RF & 1)
|
||
RB |= B0;
|
||
RB >>= 1;
|
||
RA >>= 1;
|
||
RA |= RP;
|
||
if ((RF & 1) == 0) {
|
||
RB = RT;
|
||
goto norm3;
|
||
}
|
||
//fprintf(stderr, "Norm1: %08o %08o %08o\n\r", RA, RB, RT);
|
||
} else if (RA != 0 || RB != 0) {
|
||
/* Shift left until sign and B1 not same */
|
||
//fprintf(stderr, "Norm2: %08o %08o %08o\n\r", RA, RB, RT);
|
||
while ((((RA >> 1) ^ RA) & B1) == 0) {
|
||
RT--;
|
||
RA <<= 1;
|
||
if (RB & B1)
|
||
RA |= 1;
|
||
RB <<= 1;
|
||
RA &= FMASK;
|
||
RB &= M23;
|
||
}
|
||
//fprintf(stderr, "Norm3: %08o %08o %08o\n\r", RA, RB, RT);
|
||
/* Check for overflow */
|
||
if (RT & B0) { /* < 0 */
|
||
RA = RB = 0;
|
||
goto norm1;
|
||
}
|
||
if (RT > M9) /* NO Round if overflow */
|
||
goto norm2;
|
||
} else
|
||
RT = 0;
|
||
if (RF & 1) { /* Round only on NORMD order codes */
|
||
//fprintf(stderr, "Norm4: %08o %08o %08o\n\r", RA, RB, RT);
|
||
/* Round RB if needed */
|
||
RP = RB;
|
||
RB += 0400;
|
||
//fprintf(stderr, "Norm4a: %08o %08o %08o\n\r", RA, RB, RT);
|
||
if (RB & B0 && RT <= M9) {
|
||
RB = RP;
|
||
if (((RA & M23) + 1) & B0)
|
||
RA = RB = 0;
|
||
}
|
||
}
|
||
norm2:
|
||
RB = (RB & (MMASK|B0)) | (RT & M9);
|
||
norm3:
|
||
BV = 0;
|
||
if (RT > M9) { /* Exponent overlfow */
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
norm1:
|
||
//fprintf(stderr, "Norm5: %08o %08o %08o\n\r", RA, RB, RT);
|
||
XR[(RX+1) & 07] = RB;
|
||
XR[RX] = RA;
|
||
break;
|
||
|
||
/* Not on A*/
|
||
case OP_MVCH: /* Move Characters - BC */
|
||
if (CPU_TYPE < TYPE_B1)
|
||
goto voluntary;
|
||
RK = RB;
|
||
RB = XR[(RX+1) & 07];
|
||
do {
|
||
if (Mem_read(RA & adrmask, &RT, 1)) {
|
||
goto intr;
|
||
}
|
||
m = (RA >> 22) & 3;
|
||
RT = (RT >> (6 * (3 - m))) & 077;
|
||
if (Mem_read(RB & adrmask, &RS, 1)) {
|
||
goto intr;
|
||
}
|
||
m = (RB >> 22) & 3;
|
||
m = 6 * (3 - m);
|
||
RS &= ~(077 << m);
|
||
RS |= (RT & 077) << m;
|
||
if (Mem_write(RB & adrmask, &RS, 1)) {
|
||
goto intr;
|
||
}
|
||
RA += 020000000;
|
||
m = (RA & BM1) != 0;
|
||
RA = ((RA + m) & M22) | (RA & CMASK);
|
||
RB += 020000000;
|
||
m = (RB & BM1) != 0;
|
||
RB = ((RB + m) & M22) | (RB & CMASK);
|
||
RK = (RK - 1) & 0777;
|
||
} while (RK != 0);
|
||
XR[RX] = RA;
|
||
XR[(RX+1)&07] = RB;
|
||
break;
|
||
|
||
/* Not on A*/
|
||
case OP_SMO: /* Supplementary Modifier - BC */
|
||
if (CPU_TYPE < TYPE_C1)
|
||
goto voluntary;
|
||
if (OPIP) { /* Error */
|
||
SR64 |= B1;
|
||
goto intr;
|
||
}
|
||
if (Mem_read(RS, &RP, 1)) {
|
||
goto intr;
|
||
}
|
||
PIP = 1;
|
||
goto fetch;
|
||
|
||
case OP_NULL: /* No Operation */
|
||
if (!exe_mode && RX == 7 && (Mode & 7) > 0 && (Mode & 7) < 5)
|
||
SR64 |= B2;
|
||
break;
|
||
|
||
case OP_LDCT: /* Load Count */
|
||
RA = CNTMSK & (RB << 15);
|
||
XR[RX] = RA;
|
||
break;
|
||
|
||
case OP_MODE: /* Set Mode */
|
||
/* Stevenage Machines */
|
||
if ((cpu_flags & SV) != 0 && exe_mode) {
|
||
if (RX == 0) {
|
||
/* Remap modes settings */
|
||
Mode = 0;
|
||
if (RB & 02)
|
||
Mode |= DATUM;
|
||
if (RB & 020)
|
||
Mode |= AM22;
|
||
if (RB & 0100)
|
||
Mode |= EJM;
|
||
if (RB & 0200)
|
||
BCarry = 1;
|
||
} else if (RX == 1) {
|
||
temp = RB; /* Set interrupt enable mode */
|
||
}
|
||
} else if (exe_mode)
|
||
Mode = RB & 076;
|
||
Zero = RB & 1;
|
||
adrmask = (Mode & AM22) ? M22 : M15;
|
||
break;
|
||
|
||
case OP_MOVE: /* Copy N words */
|
||
if (CPU_TYPE < TYPE_B1)
|
||
goto voluntary;
|
||
RK = RB;
|
||
RA &= adrmask;
|
||
RB = XR[(RX+1) & 07] & adrmask;
|
||
do {
|
||
if (Mem_read(RA, &RT, 1)) {
|
||
goto intr;
|
||
}
|
||
if (Mem_write(RB, &RT, 1)) {
|
||
goto intr;
|
||
}
|
||
RA++;
|
||
RB++;
|
||
RK = (RK - 1) & 0777;
|
||
} while (RK != 0);
|
||
break;
|
||
|
||
case OP_SUM: /* Sum N words */
|
||
if (CPU_TYPE < TYPE_B1)
|
||
goto voluntary;
|
||
RK = RB;
|
||
RB = XR[(RX+1) & 07] & adrmask;
|
||
RA = 0;
|
||
do {
|
||
if (Mem_read(RB, &RT, 1)) {
|
||
goto intr;
|
||
}
|
||
RA = (RA + RT) & FMASK;
|
||
RB++;
|
||
RK = (RK - 1) & 0777;
|
||
} while (RK != 0);
|
||
XR[RX] = RA;
|
||
break;
|
||
|
||
/* B or C with Floating Point */
|
||
case OP_FLOAT: /* Convert Fixed to Float +FP */
|
||
if ((cpu_flags & FLOAT) == 0)
|
||
goto voluntary;
|
||
if (Mem_read(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
RS++;
|
||
if (Mem_read(RS, &RB, 1)) {
|
||
goto intr;
|
||
}
|
||
faccl = RA;
|
||
facch = RB;
|
||
fovr = (RB & B0) != 0;
|
||
e1 = 23;
|
||
//fprintf(stderr, "FLOAT: %08o %08o %08o %o\n\r", faccl, facch, RC, RX);
|
||
RX = 0;
|
||
goto fn;
|
||
case OP_FIX: /* Convert Float to Fixed +FP */
|
||
if ((cpu_flags & FLOAT) == 0)
|
||
goto voluntary;
|
||
RA = faccl;
|
||
RB = facch & MMASK;
|
||
e1 = 279 - (facch & M9);
|
||
//fprintf(stderr, "FIX: %08o %08o %08o %o %d\n\r", faccl, facch, RC, RX, e1);
|
||
if (e1 < 46) {
|
||
while (e1 > 0) {
|
||
if (RA & 1)
|
||
RB |= B0;
|
||
if (RA & B0)
|
||
RA |= BM1;
|
||
RA >>= 1;
|
||
RB >>= 1;
|
||
e1--;
|
||
}
|
||
while (e1 < 0) {
|
||
RA <<= 1;
|
||
if (RB & B1)
|
||
RA |= 1;
|
||
RB <<= 1;
|
||
RA &= FMASK;
|
||
RB &= M23;
|
||
e1++;
|
||
}
|
||
} else {
|
||
RB = RA = 0;
|
||
e1 = 0;
|
||
}
|
||
if (e1 != 0 || fovr) {
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
//fprintf(stderr, "FIX1: %08o %08o %08o %o %d\n\r", RA, RB, RC, RX, e1);
|
||
if (Mem_write(RS, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
RS++;
|
||
if (Mem_write(RS, &RB, 1)) {
|
||
goto intr;
|
||
}
|
||
break;
|
||
|
||
case OP_FAD: /* Floating Point Add +FP */
|
||
case OP_FSB: /* Floating Point Subtract +FP */
|
||
if ((cpu_flags & FLOAT) == 0)
|
||
goto voluntary;
|
||
if (Mem_read(RS, &RA, 1)) { /* Read lower */
|
||
goto intr;
|
||
}
|
||
RS++;
|
||
if (Mem_read(RS, &RB, 1)) { /* Read high + exp */
|
||
goto intr;
|
||
}
|
||
//fprintf(stderr, "FAD0: %08o %08o %08o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RX);
|
||
fovr |= (RB & B0) != 0;
|
||
RB &= M23;
|
||
if (RX & 4) { /* See if we should swap operands */
|
||
RT = facch;
|
||
facch = RB;
|
||
RB = RT;
|
||
RT = faccl;
|
||
faccl = RA;
|
||
RA = RT;
|
||
//fprintf(stderr, "FAD1: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
|
||
}
|
||
if (RF == OP_FSB) { /* If subtract invert RA&RB */
|
||
RA ^= FMASK;
|
||
RB ^= MMASK;
|
||
RB += 01000;
|
||
if (RB & B0)
|
||
RA = (RA + 1) & FMASK;
|
||
RB &= M23;
|
||
//fprintf(stderr, "FAD2: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
|
||
}
|
||
/* Extract exponents and numbers */
|
||
e1 = ((facch & M9)) - 256;
|
||
facch &= MMASK;
|
||
e2 = ((RB & M9)) - 256;
|
||
RB &= MMASK;
|
||
n = e1 - e2;
|
||
//fprintf(stderr, "FAD3: %08o %08o %08o %08o %08o %d %d %d\n\r", RA, RB, RC, faccl, facch, e1, e2, n);
|
||
/* Align mantissa's to add */
|
||
if (n < 0) {
|
||
e1 = e2;
|
||
if (n < -37) { /* See if more then 37 bits difference */
|
||
faccl = RA;
|
||
facch = RB;
|
||
goto fn;
|
||
}
|
||
while(n < 0) {
|
||
if (faccl & B0)
|
||
faccl |= BM1;
|
||
if (faccl & 1)
|
||
facch |= B0;
|
||
facch >>= 1;
|
||
faccl >>= 1;
|
||
n++;
|
||
//fprintf(stderr, "FAD4a: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
|
||
}
|
||
} else if (n > 0) {
|
||
if (n > 37) { /* See if more then 37 bits difference */
|
||
goto fn;
|
||
}
|
||
while(n > 0) {
|
||
if (RA & B0)
|
||
RA |= BM1;
|
||
if (RA & 1)
|
||
RB |= B0;
|
||
RA >>= 1;
|
||
RB >>= 1;
|
||
n--;
|
||
//fprintf(stderr, "FAD4b: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
|
||
}
|
||
}
|
||
//fprintf(stderr, "FAD5: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
|
||
/* Add the numbers */
|
||
n = (faccl & B0) != 0; /* Save signs */
|
||
if (RA & B0)
|
||
n |= 2;
|
||
faccl += RA;
|
||
facch += RB;
|
||
if (facch & B0) {
|
||
facch &= M23;
|
||
faccl ++;
|
||
}
|
||
/* Sign of result */
|
||
if ((faccl & B0) != 0)
|
||
n |= 4;
|
||
//fprintf(stderr, "FAD6: %08o %08o %08o %o\n\r", faccl, facch, RC, n);
|
||
/* Result sign not equal same sign as addens */
|
||
if (n == 3 || n == 4) {
|
||
if (faccl & 1)
|
||
facch |= B0;
|
||
faccl >>= 1;
|
||
facch >>= 1;
|
||
facch &= MMASK;
|
||
if ((n & 4) == 0)
|
||
faccl |= B0; /* Set sign */
|
||
e1++;
|
||
//fprintf(stderr, "FAD6a: %08o %08o %08o\n\r", faccl, facch, RC);
|
||
}
|
||
if (n == 7) /* Handle minus with overflow */
|
||
e1--;
|
||
fn:
|
||
/* Common normalize routine */
|
||
faccl &= FMASK;
|
||
//fprintf(stderr, "FAD7: %08o %08o %08o %03o %d\n\r", faccl, facch, RC, e1, e1);
|
||
if ((facch | faccl) == 0)
|
||
break;
|
||
//fprintf(stderr, "FAD8: %08o %08o %08o %o\n\r",faccl, facch, RC, RX );
|
||
/* Shift left until sign and B1 not same */
|
||
if ((RX & 2) == 0 ) {
|
||
while ((((faccl >> 1) ^ faccl) & B1) == 0) {
|
||
e1--;
|
||
facch <<= 1;
|
||
faccl <<= 1;
|
||
if (facch & B0)
|
||
faccl |= 1;
|
||
faccl &= FMASK;
|
||
facch &= M23;
|
||
//fprintf(stderr, "FAD9: %08o %08o %08o %03o %d\n\r", faccl, facch, RC, e1, e1);
|
||
}
|
||
}
|
||
/* Do rounding if needed */
|
||
if ((RX & 1) == 0 && (facch & B16) != 0) {
|
||
facch += B16;
|
||
if (facch & B0)
|
||
faccl ++;
|
||
facch &= M23;
|
||
faccl &= FMASK;
|
||
/* renormalize if things changed */
|
||
if ((RX & 2) == 0 && (((faccl >> 1) ^ faccl) & B1) == 0) {
|
||
e1--;
|
||
facch <<= 1;
|
||
faccl <<= 1;
|
||
if (facch & B0)
|
||
faccl |= 1;
|
||
faccl &= FMASK;
|
||
facch &= M23;
|
||
//fprintf(stderr, "FADr: %08o %08o %08o %03o %d\n\r", faccl, facch, RC, e1, e1);
|
||
}
|
||
//fprintf(stderr, "FADR: %08o %08o %08o %03o\n\r", faccl, facch, RC, e1);
|
||
}
|
||
faccl &= FMASK;
|
||
facch &= MMASK;
|
||
/* Check if exponent in range */
|
||
if (e1 < -256) {
|
||
facch = faccl = 0;
|
||
e1 = -256;
|
||
}
|
||
if (e1 > 255) {
|
||
fovr = 1;
|
||
e1 = (- e1);
|
||
}
|
||
if (fovr == 0 && ((faccl & FMASK) | (facch & MMASK)) == 0)
|
||
facch = faccl = 0;
|
||
else
|
||
facch |= (e1 + 256) & M9;
|
||
RA = faccl;
|
||
//fprintf(stderr, "FADA: %08o %08o %08o %03o %o\n\r", faccl, facch, RC, e1, fovr);
|
||
break;
|
||
|
||
case OP_FMPY: /* Floating Point Multiply +FP */
|
||
if ((cpu_flags & FLOAT) == 0)
|
||
goto voluntary;
|
||
if (Mem_read(RS, &RA, 1)) { /* Read lower */
|
||
goto intr;
|
||
}
|
||
RS++;
|
||
if (Mem_read(RS, &RB, 1)) { /* Read high + exp */
|
||
goto intr;
|
||
}
|
||
//fprintf(stderr, "FMP0: %08o %08o %08o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RX);
|
||
fovr |= (RB & B0) != 0;
|
||
RB &= M23;
|
||
/* Not really needed for Multiply */
|
||
if (RX & 4) { /* See if we should swap operands */
|
||
RT = facch;
|
||
facch = RB;
|
||
RB = RT;
|
||
RT = faccl;
|
||
faccl = RA;
|
||
RA = RT;
|
||
//fprintf(stderr, "FMP1: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
|
||
}
|
||
/* Extract exponents and mantissa's */
|
||
e1 = ((facch & M9)) - 256;
|
||
facch &= MMASK;
|
||
e2 = ((RB & M9)) - 256;
|
||
RB &= MMASK;
|
||
e1 += e2; /* Exponent is sum of exponents */
|
||
/* Make both numbers positive and compute final size */
|
||
f = 0;
|
||
if (faccl & B0) {
|
||
f = 1;
|
||
faccl ^= FMASK;
|
||
facch ^= MMASK;
|
||
facch += B15;
|
||
if (facch & B0) {
|
||
faccl += 1;
|
||
faccl &= FMASK;
|
||
facch &= MMASK;
|
||
}
|
||
}
|
||
if (RA & B0) {
|
||
f = !f;
|
||
RA ^= FMASK;
|
||
RB ^= MMASK;
|
||
RB += B15;
|
||
if (RB & B0) {
|
||
RA += 1;
|
||
RA &= FMASK;
|
||
RB &= MMASK;
|
||
}
|
||
}
|
||
//fprintf(stderr, "FMP2: %08o %08o %08o %08o %08o %03o %d %o\n\r", RA, RB, RC, faccl, facch, e1, e1, f);
|
||
RT = faccl;
|
||
RP = facch;
|
||
faccl = facch = 0; /* Clear product */
|
||
/* Do actual multiply */
|
||
|
||
for(RK = 37; RK != 0; RK--) {
|
||
/* If High order bit one, add in RB,RA */
|
||
if (RP & B15) {
|
||
facch += RB;
|
||
faccl += RA;
|
||
if (facch & B0)
|
||
faccl++;
|
||
facch &= M23;
|
||
}
|
||
/* Shift faccl,fach,RT,t right one */
|
||
if (RT & 1)
|
||
RP |= B0;
|
||
if (facch & 1)
|
||
RT |= B0;
|
||
if (faccl & 1)
|
||
facch |= B0;
|
||
RP >>= 1;
|
||
RT >>= 1;
|
||
facch >>= 1;
|
||
faccl >>= 1;
|
||
//fprintf(stderr, "FMP3: %08o %08o %08o %08o %08o %08o %08o %02o\n\r", RA, RB, RC, faccl, facch, RT, RP, RK);
|
||
}
|
||
/* Check if still negative multiplican */
|
||
if (RP & B15) {
|
||
facch += RB;
|
||
faccl += RA;
|
||
if (facch & B0)
|
||
faccl++;
|
||
facch &= M23;
|
||
}
|
||
|
||
/* Check if underflow */
|
||
if ((RX & 2) == 0 && faccl == 0 && facch != 0) {
|
||
while ((faccl & B1) == 0) {
|
||
e1--;
|
||
RP <<= 1;
|
||
RT <<= 1;
|
||
facch <<= 1;
|
||
faccl <<= 1;
|
||
if (RP & B0)
|
||
RT |= 1;
|
||
if (RT & B0)
|
||
facch |= 1;
|
||
if (facch & B0)
|
||
faccl |= 1;
|
||
faccl &= FMASK;
|
||
facch &= M23;
|
||
RT &= M23;
|
||
RP &= M23;
|
||
}
|
||
}
|
||
/* Fix up if over flow */
|
||
if (faccl & B0) {
|
||
if (faccl & 1)
|
||
facch |= B0;
|
||
faccl >>= 1;
|
||
facch >>= 1;
|
||
facch &= MMASK;
|
||
e1++;
|
||
}
|
||
|
||
//fprintf(stderr, "FMP4: %08o %08o\n\r", faccl, facch);
|
||
/* Fix sign */
|
||
if (f) {
|
||
faccl ^= FMASK;
|
||
facch ^= M23;
|
||
facch ++;
|
||
if (facch & B0) {
|
||
faccl ++;
|
||
faccl &= FMASK;
|
||
facch &= MMASK;
|
||
}
|
||
}
|
||
//fprintf(stderr, "FMP5: %08o %08o\n\r", faccl, facch);
|
||
/* Go normalize and round */
|
||
goto fn;
|
||
|
||
case OP_FDVD: /* Floating Point Divide +FP */
|
||
if ((cpu_flags & FLOAT) == 0)
|
||
goto voluntary;
|
||
if (Mem_read(RS, &RA, 1)) { /* Read lower */
|
||
goto intr;
|
||
}
|
||
RS++;
|
||
if (Mem_read(RS, &RB, 1)) { /* Read high + exp */
|
||
goto intr;
|
||
}
|
||
//fprintf(stderr, "FDV0: %08o %08o %08o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RX);
|
||
fovr |= (RB & B0) != 0;
|
||
RB &= M23;
|
||
if (RX & 4) { /* See if we should swap operands */
|
||
RT = facch;
|
||
facch = RB;
|
||
RB = RT;
|
||
RT = faccl;
|
||
faccl = RA;
|
||
RA = RT;
|
||
//fprintf(stderr, "FDV1: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch);
|
||
}
|
||
/* Extract exponents and mantissas */
|
||
e1 = ((facch & M9)) - 256;
|
||
facch &= MMASK;
|
||
e2 = ((RB & M9)) - 256;
|
||
RB &= MMASK;
|
||
e1 -= e2; /* Final exponent is difference of terms */
|
||
/* Make both positive and comupte final sign */
|
||
f = 0;
|
||
if (faccl & B0) {
|
||
f = 1;
|
||
faccl ^= FMASK;
|
||
facch ^= MMASK;
|
||
facch += B15;
|
||
if (facch & B0) {
|
||
faccl += 1;
|
||
faccl &= FMASK;
|
||
facch &= MMASK;
|
||
}
|
||
}
|
||
if ((RA & B0) != 0){
|
||
f = !f;
|
||
RA ^= FMASK;
|
||
RB ^= MMASK;
|
||
RB += B15;
|
||
if (RB & B0) {
|
||
RA += 1;
|
||
RA &= FMASK;
|
||
RB &= MMASK;
|
||
}
|
||
}
|
||
/* Handle zero divide */
|
||
if ((RA | RB) == 0) {
|
||
faccl = 0;
|
||
facch = 0400;
|
||
fovr=1;
|
||
break;
|
||
}
|
||
RA ^= M23; /* precompliment */
|
||
RB ^= M23;
|
||
RP = faccl; /* Set dividend into upper half */
|
||
RT = facch;
|
||
faccl = 0;
|
||
facch = 0;
|
||
n = 0;
|
||
/* DO actual divide */
|
||
for (RK=46; RK != 0; RK--) {
|
||
uint32 t0, t1;
|
||
t0 = RT + RB + 1;
|
||
t1 = RP + RA;
|
||
if (t0 & B0)
|
||
t1++;
|
||
if (n || (t1 & B0)) {
|
||
RT = t0;
|
||
RP = t1;
|
||
facch |= 1;
|
||
}
|
||
facch <<= 1;
|
||
faccl <<= 1;
|
||
RT <<= 1;
|
||
RP <<= 1;
|
||
if (facch & B0)
|
||
faccl |= 1;
|
||
if (RT & B0)
|
||
RP |= 1;
|
||
n = (RP & B0) != 0;
|
||
RT &= M23;
|
||
RP &= M23;
|
||
facch &= M23;
|
||
//fprintf(stderr, "FDV3: %08o %08o %08o %08o %08o %08o %08o %02o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RP, RT, RK,t1, t0, n);
|
||
}
|
||
/* If rounding and positive and negative result, adjust */
|
||
if (((RX & 2) == 0 || f == 0) && faccl & B0) {
|
||
if (faccl & 1)
|
||
facch |= B0;
|
||
faccl >>= 1;
|
||
facch >>= 1;
|
||
e1++;
|
||
}
|
||
/* Fix sign */
|
||
if (f) {
|
||
if (faccl & B0 && (RX & 2)) {
|
||
if (faccl != B0)
|
||
e1++;
|
||
facch = (e1 + 256) & M9;
|
||
faccl = B0;
|
||
fovr=1;
|
||
break;
|
||
} else {
|
||
faccl ^= FMASK;
|
||
facch ^= M23;
|
||
facch ++;
|
||
if (facch & B0)
|
||
faccl ++;
|
||
faccl &= FMASK;
|
||
facch &= M23;
|
||
if (faccl == B0)
|
||
fovr=1;
|
||
}
|
||
}
|
||
//fprintf(stderr, "FDV4: %08o %08o %o\n\r", faccl, facch, f);
|
||
goto fn;
|
||
|
||
case OP_LFP: /* Load Floating Point +FP */
|
||
if ((cpu_flags & FLOAT) == 0)
|
||
goto voluntary;
|
||
if (RX & 1) {
|
||
faccl = facch = fovr = 0;
|
||
//fprintf(stderr, "LFPZ: %08o %08o %o\n\r", faccl, facch, RX);
|
||
break;
|
||
}
|
||
if (Mem_read(RB, &RA, 1)) { /* Read low order */
|
||
goto intr;
|
||
}
|
||
RB++;
|
||
if (Mem_read(RB, &RS, 1)) { /* Read high order + exp */
|
||
goto intr;
|
||
}
|
||
faccl = RA;
|
||
facch = RS & M23;
|
||
fovr = (RS & B0) != 0;
|
||
//fprintf(stderr, "LFP: %08o %08o %08o %o\n\r", faccl, facch, RC, fovr);
|
||
break;
|
||
|
||
case OP_SFP: /* Store Floating Point +FP */
|
||
//fprintf(stderr, "SFP: %08o %08o %o\n\r", faccl, facch, fovr);
|
||
if ((cpu_flags & FLOAT) == 0)
|
||
goto voluntary;
|
||
if (Mem_write(RB, &faccl, 1)) {
|
||
goto intr;
|
||
}
|
||
RA = facch;
|
||
if (fovr) {
|
||
RA |= B0;
|
||
BV = 1;
|
||
if (!exe_mode && (Mode & 7) == 4)
|
||
SR64 |= B2;
|
||
}
|
||
RB++;
|
||
if (Mem_write(RB, &RA, 1)) {
|
||
goto intr;
|
||
}
|
||
if (RX & 1)
|
||
faccl = facch = fovr = 0;
|
||
break;
|
||
|
||
case 0160: /* Stevenage machines */ /* Load accumulators */
|
||
if ((cpu_flags & SV) != 0 && exe_mode) {
|
||
/* Restore registers */
|
||
for (n = 0; n < 8; n++) /* Restore user mode registers */
|
||
Mem_read(RB+n, &XR[n], 0);
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
|
||
case 0161: /* Stevenage machines */ /* Store accumulators */
|
||
if ((cpu_flags & SV) != 0 && exe_mode) {
|
||
/* Dump registers */
|
||
for (n = 0; n < 8; n++) /* Restore user mode registers */
|
||
Mem_write(RB+n, &XR[n], 0);
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
|
||
case 0162: /* Stevenage machines */
|
||
case 0163: /* Stevenage machines */ /* Stop and Display */
|
||
case 0164: /* Stevenage machines */ /* Search List N for Word X */
|
||
if ((cpu_flags & SV) != 0 && exe_mode) {
|
||
RK = RB;
|
||
RB = XR[(RX+1) & 07] & adrmask;
|
||
do {
|
||
if (Mem_read(RA, &RT, 1)) {
|
||
goto intr;
|
||
}
|
||
RB++;
|
||
if (RA == RT)
|
||
BCarry = 1;
|
||
RK = (RK - 1) & 0777;
|
||
} while (RA != RT && RK != 0);
|
||
XR[(RX+1) & 07] = RB;
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
|
||
case 0165: /* Stevenage machines */ /* Parity Search */
|
||
if ((cpu_flags & SV) != 0 && exe_mode) {
|
||
RK = RB;
|
||
RB = XR[(RX+1) & 07] & adrmask;
|
||
do {
|
||
if (Mem_read(RA, &RT, 1)) {
|
||
goto intr;
|
||
}
|
||
RA++;
|
||
RB++;
|
||
RK = (RK - 1) & 0777;
|
||
} while (RK != 0);
|
||
XR[RX] = RA;
|
||
XR[(RX+1) & 07] = RB;
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
|
||
case 0166: /* Stevenage machines */ /* Test X unequal */
|
||
if ((cpu_flags & SV) != 0 && exe_mode) {
|
||
if (RA != RB)
|
||
BCarry = 1;
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
|
||
case 0167: /* Stevenage machines */ /* Test X Less */
|
||
if ((cpu_flags & SV) != 0 && exe_mode) {
|
||
RB += BCarry;
|
||
if (RB != RA)
|
||
BCarry = (RB > RA);
|
||
break;
|
||
}
|
||
|
||
/* If we get here and not in executive mode do volintary */
|
||
if (exe_mode) {
|
||
reason = SCPE_STOP;
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
|
||
case 0170: /* Read special register */
|
||
if (exe_mode) {
|
||
RA = 0;
|
||
switch(RB) {
|
||
case 0: /* Time of day clock */
|
||
time_read(&RA);
|
||
break;
|
||
case 1: RA = SR1; SR1 = 0; break;
|
||
case 64: RA = SR64; SR64 &= 003777777; break;
|
||
case 65: RA = SR65; break;
|
||
default: if (RB < 64)
|
||
chan_nsi_status(RB, &RA);
|
||
break;
|
||
}
|
||
XR[RX] = RA;
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
case 0171: /* Write special register */
|
||
if (exe_mode) {
|
||
//fprintf(stderr, "WR SR %o %08o\n\r", RB, RA);
|
||
if (RB < 64)
|
||
chan_nsi_cmd(RB, RA);
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
case 0172: /* Exit from executive */
|
||
case 0173: /* Load Datum limit and G */
|
||
if (exe_mode) {
|
||
if (CPU_TYPE < TYPE_C1) {
|
||
/* For non extended address processors. */
|
||
Mem_read(RB, &RA, 0);
|
||
RG = RA & 077;
|
||
RD = RA & 077700;
|
||
RL = (RA >> 9) & 077700;
|
||
} else {
|
||
Mem_read(RB, &RA, 0); /* Read datum */
|
||
RD = RA & (M22 & ~077);
|
||
RG = (RA & 17) << 3;
|
||
Mem_read(RB+1, &RA, 0); /* Read Limit */
|
||
RL = RA & (M22 & ~077);
|
||
RG |= (RA & 07);
|
||
Mode = RA & 077;
|
||
}
|
||
adrmask = (Mode & (AM22)) ? M22 : M15;
|
||
//fprintf(stderr, "Load C=%08o limit: %08o D:=%08o %02o\n\r", RC, RL, RD, Mode);
|
||
if (RF & 1) /* Check if 172 or 173 order code */
|
||
break;
|
||
/* Restore registers */
|
||
for (n = 0; n < 8; n++) /* Restore user mode registers */
|
||
Mem_read(RD+n, &XR[n], 0);
|
||
Mem_read(RD+9, &RA, 0); /* Read ZStatus and mode */
|
||
Mem_read(RD+8, &RC, 0); /* Restore C register */
|
||
//fprintf(stderr, "Load PC: %08o D:=%08o z=%08o\n\r", RC, RD, RA);
|
||
BV = (RC & B0) != 0;
|
||
BCarry = (RC & B1) != 0;
|
||
Zero = 0;
|
||
/* Type A & B */
|
||
if (CPU_TYPE < TYPE_C1) {
|
||
if (RC & B8)
|
||
Zero = 1;
|
||
RC &= M15;
|
||
RC -= RD;
|
||
} else {
|
||
if (RA & B3)
|
||
Zero = 1;
|
||
}
|
||
RC &= (Mode & (EJM|AM22)) ? M22 : M15;
|
||
if (cpu_flags & FLOAT && cpu_flags & SL_FLOAT) {
|
||
/* Restore floating point ACC from D12/D13 */
|
||
Mem_read(RD+12, &faccl, 0); /* Restore F.P.U. */
|
||
Mem_read(RD+13, &facch, 0); /* Restore F.P.U. */
|
||
fovr = (facch & B0) != 0;
|
||
facch &= M23;
|
||
}
|
||
exe_mode = 0;
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
case 0174: /* Send control character to peripheral */
|
||
if (exe_mode) {
|
||
chan_send_cmd(RB, RA & 07777, &RT);
|
||
//fprintf(stderr, "CMD C=%08o %04o %04o %08o\n\r", RC, RT, RB, RA);
|
||
m = (m == 0) ? 3 : (XR[m] >> 22) & 3;
|
||
m = 6 * (3 - m);
|
||
RT = (RT & 077) << m;
|
||
RA &= ~(077 << m);
|
||
RA |= RT;
|
||
XR[RX] = RA;
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
case 0175: /* Null operation in Executive mode */
|
||
if (exe_mode) {
|
||
//fprintf(stderr, "CMD 175 C=%08o %04o %08o\n\r", RC, RB, RA);
|
||
break;
|
||
}
|
||
case 0176:
|
||
if (exe_mode) {
|
||
//fprintf(stderr, "CMD 176 C=%08o %04o %08o\n\r", RC, RB, RA);
|
||
break;
|
||
}
|
||
/* Fall through */
|
||
case 0177: /* Test Datum and Limit */
|
||
if (exe_mode) {
|
||
if (RA < RD || RA >= RL)
|
||
BCarry = 1;
|
||
break;
|
||
}
|
||
case 0140:
|
||
case 0141:
|
||
case 0142:
|
||
case 0143:
|
||
case 0144:
|
||
case 0145:
|
||
case 0146:
|
||
case 0147:
|
||
case 0150:
|
||
case 0151:
|
||
case 0152:
|
||
case 0153:
|
||
case 0154:
|
||
case 0155:
|
||
case 0156:
|
||
case 0157:
|
||
default:
|
||
/* Voluntary entry to executive */
|
||
voluntary:
|
||
if (exe_mode) {
|
||
reason = SCPE_STOP;
|
||
break;
|
||
}
|
||
if ((CPU_TYPE < TYPE_C1) && !exe_mode)
|
||
RC += RD;
|
||
exe_mode = 1;
|
||
if (cpu_flags & FLOAT && cpu_flags & SL_FLOAT) {
|
||
/* Store registers */
|
||
Mem_write(RD+12, &faccl, 0);
|
||
RT = facch;
|
||
if (fovr)
|
||
RT |= B0;
|
||
Mem_write(RD+13, &RT, 0); /* Save F.P.U. */
|
||
}
|
||
if (CPU_TYPE >= TYPE_C1) {
|
||
Mem_read(RD+9, &RT, 0);
|
||
RT &= M15;
|
||
/* Build ZSTAT and ASTAT */
|
||
if (Zero)
|
||
RT |= B3;
|
||
if (OPIP)
|
||
RT |= B2;
|
||
Mem_write(RD+9, &RT, 0);
|
||
}
|
||
RT = RC;
|
||
if (BV)
|
||
RT |= B0;
|
||
if (BCarry)
|
||
RT |= B1;
|
||
/* Type A & B */
|
||
if (CPU_TYPE < TYPE_C1 && Zero)
|
||
RT |= B8;
|
||
Mem_write(RD+8, &RT, 0);
|
||
for (n = 0; n < 8; n++)
|
||
Mem_write(RD+n, &XR[n], 0);
|
||
Zero = Mode = 0;
|
||
BCarry = BV = 0;
|
||
adrmask = M15;
|
||
if ((cpu_flags & SV) != 0) {
|
||
if ((RF & 0170) == 0140 || (RF & 0170) == 0110)
|
||
XR[1] = RD+RX;
|
||
XR[2] = RB;
|
||
XR[3] = RF & 07;
|
||
RC = 020 + ((RF >> 3) & 017);
|
||
} else {
|
||
XR[1] = RB;
|
||
XR[2] = temp;
|
||
RC = 040;
|
||
}
|
||
break;
|
||
}
|
||
|
||
if (hst_lnt) { /* history enabled? */
|
||
hst[hst_p].rr = RA;
|
||
}
|
||
sim_interval--;
|
||
} /* end while */
|
||
|
||
/* Simulation halted */
|
||
|
||
return reason;
|
||
}
|
||
|
||
/* Interval timer routines */
|
||
t_stat
|
||
rtc_srv(UNIT * uptr)
|
||
{
|
||
(void)sim_rtcn_calb(rtc_tps, TMR_RTC);
|
||
sim_activate_after(uptr, 1000000/rtc_tps);
|
||
SR64 |= B3;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
int
|
||
bcd_2d(int n)
|
||
{
|
||
uint8 d1, d2;
|
||
|
||
d1 = n / 10;
|
||
d2 = n % 10;
|
||
return (d1 << 4) | d2;
|
||
}
|
||
|
||
void
|
||
time_read(uint32 *word)
|
||
{
|
||
time_t curtim;
|
||
struct tm *tptr;
|
||
|
||
curtim = sim_get_time(NULL);/* get time */
|
||
tptr = localtime(&curtim); /* decompose */
|
||
if (tptr == NULL)
|
||
return; /* error? */
|
||
|
||
/* Convert and fill buffer */
|
||
*word = bcd_2d(tptr->tm_sec);
|
||
*word |= bcd_2d(tptr->tm_min) << 7;
|
||
*word |= bcd_2d(tptr->tm_hour) << 14;
|
||
return;
|
||
}
|
||
/* Reset routine */
|
||
|
||
t_stat
|
||
cpu_reset(DEVICE * dptr)
|
||
{
|
||
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) ;
|
||
SR64 = SR65 = 0;
|
||
|
||
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) {
|
||
if (addr < 010)
|
||
*vptr = (t_value)XR[addr];
|
||
else
|
||
*vptr = (t_value)M[addr];
|
||
}
|
||
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;
|
||
if (addr < 010)
|
||
XR[addr] = val;
|
||
else
|
||
M[addr] = val;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cpu_show_size(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||
{
|
||
fprintf(st, "%dK", MEMSIZE/1024);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
uint32 mc = 0;
|
||
uint32 i;
|
||
|
||
cpu_unit[0].flags &= ~UNIT_MSIZE;
|
||
cpu_unit[0].flags |= val;
|
||
val >>= UNIT_V_MSIZE;
|
||
val = (val + 1) * 4096;
|
||
if ((val < 0) || (val > MAXMEMSIZE))
|
||
return SCPE_ARG;
|
||
for (i = val - 1; 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;
|
||
}
|
||
|
||
t_stat
|
||
cpu_set_model(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
CPUMOD *ptr;
|
||
|
||
val >>= UNIT_V_MODEL;
|
||
for(ptr = &cpu_modtab[0]; ptr->name != NULL; ptr++) {
|
||
if (ptr->mod_num == val) {
|
||
cpu_flags = ptr->cpu_flags;
|
||
io_flags = ptr->io_flags;
|
||
rtc_tps = ptr->ticker;
|
||
cpu_unit[0].flags &= ~(UNIT_MODEL);
|
||
cpu_unit[0].flags |= MODEL(val);
|
||
return SCPE_OK;
|
||
}
|
||
}
|
||
return SCPE_ARG;
|
||
}
|
||
|
||
t_stat
|
||
cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
int32 oval = val;
|
||
cpu_flags &= ~FLOAT;
|
||
if (val)
|
||
cpu_flags |= FLOAT;
|
||
if (oval != val)
|
||
return SCPE_ARG;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cpu_show_float(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||
{
|
||
fprintf(st, "%s", (cpu_flags & FLOAT) ? "FLOAT":"NOFLOAT");
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
int32 oval = val;
|
||
cpu_flags &= ~MULT;
|
||
if (val)
|
||
cpu_flags |= MULT;
|
||
if (oval != val)
|
||
return SCPE_ARG;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
cpu_show_mult(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||
{
|
||
fprintf(st, "%s", (cpu_flags & MULT) ? "MULT":"NOMULT");
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Handle execute history */
|
||
|
||
/* Set history */
|
||
t_stat
|
||
cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
int32 lnt;
|
||
t_stat r;
|
||
|
||
if (cptr == NULL) {
|
||
hst_p = 0;
|
||
return SCPE_OK;
|
||
}
|
||
lnt = (int32) get_uint(cptr, 10, HIST_MAX, &r);
|
||
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
|
||
return SCPE_ARG;
|
||
hst_p = 0;
|
||
if (hst_lnt) {
|
||
free(hst);
|
||
hst_lnt = 0;
|
||
hst = NULL;
|
||
}
|
||
if (lnt) {
|
||
hst = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt);
|
||
|
||
if (hst == NULL)
|
||
return SCPE_MEM;
|
||
hst_lnt = lnt;
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Show history */
|
||
|
||
t_stat
|
||
cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc)
|
||
{
|
||
int32 k, di, lnt;
|
||
const char *cptr = (const char *) desc;
|
||
t_stat r;
|
||
t_value v[1];
|
||
struct InstHistory *h;
|
||
|
||
if (hst_lnt == 0)
|
||
return SCPE_NOFNC; /* enabled? */
|
||
if (cptr) {
|
||
lnt = (int32) get_uint(cptr, 10, hst_lnt, &r);
|
||
if ((r != SCPE_OK) || (lnt == 0))
|
||
return SCPE_ARG;
|
||
} else
|
||
lnt = hst_lnt;
|
||
di = hst_p - lnt; /* work forward */
|
||
if (di < 0)
|
||
di = di + hst_lnt;
|
||
fprintf(st, " C EA XR A B Result c v e M Op\n\n");
|
||
for (k = 0; k < lnt; k++) { /* print specified */
|
||
h = &hst[(++di) % hst_lnt]; /* entry pointer */
|
||
|
||
if (h->rc & HIST_PC) { /* instruction? */
|
||
fprintf(st, " %07o %08o %08o %08o %08o %08o %o %o %o %02o ",
|
||
h->rc & M22 , h->ea, h->xr, h->ra, h->rb, h->rr,
|
||
h->c, h->v, h->e, h->mode);
|
||
v[0] = h->op;
|
||
(void)fprint_sym(st, h->rc & M22, v, &cpu_unit[0], SWMASK('M'));
|
||
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, "ICL1900 CPU\n\n");
|
||
fprintf(st, "The ICL1900 \n");
|
||
fprint_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
return SCPE_OK;
|
||
}
|