mirror of
https://github.com/rcornwell/sims.git
synced 2026-01-23 02:47:57 +00:00
3960 lines
130 KiB
C
3960 lines
130 KiB
C
/* ka10_cpu.c: PDP-10 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.
|
|
|
|
Except as contained in this notice, the name of Richard Cornwell shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Richard Cornwell
|
|
|
|
cpu KA10 central processor
|
|
|
|
|
|
The 36b system family had six different implementions: PDP-6, KA10, KI10,
|
|
L10, KL10 extended, and KS10.
|
|
|
|
The register state for the KI10 is:
|
|
|
|
AC[16] accumulators
|
|
PC program counter
|
|
flags<0:11> state flags
|
|
pi_enb<1:7> enabled PI levels
|
|
pi_act<1:7> active PI levels
|
|
pi_prq<1:7> program PI requests
|
|
apr_enb<0:7> enabled system flags
|
|
apr_flg<0:7> system flags
|
|
|
|
The PDP-10 had just two instruction formats: memory reference
|
|
and I/O.
|
|
|
|
000000000 0111 1 1111 112222222222333333
|
|
012345678 9012 3 4567 890123456789012345
|
|
+---------+----+-+----+------------------+
|
|
| opcode | ac |i| idx| address | memory reference
|
|
+---------+----+-+----+------------------+
|
|
|
|
000 0000000 111 1 1111 112222222222333333
|
|
012 3456789 012 3 4567 890123456789012345
|
|
+---+-------+---+-+----+------------------+
|
|
|111|device |iop|i| idx| address | I/O
|
|
+---+-------+---+-+----+------------------+
|
|
|
|
This routine is the instruction decode routine for the PDP-10.
|
|
It is called from the simulator control program to execute
|
|
instructions in simulated memory, starting at the simulated PC.
|
|
It runs until an abort occurs.
|
|
|
|
General notes:
|
|
|
|
1. Reasons to stop. The simulator can be stopped by:
|
|
|
|
HALT instruction
|
|
MUUO instruction in executive mode
|
|
pager error in interrupt sequence
|
|
invalid vector table in interrupt sequence
|
|
illegal instruction in interrupt sequence
|
|
breakpoint encountered
|
|
nested indirects exceeding limit
|
|
nested XCT's exceeding limit
|
|
I/O error in I/O simulator
|
|
|
|
2. Interrupts. PDP-10's have a seven level priority interrupt
|
|
system. Interrupt requests can come from internal sources,
|
|
such as APR program requests, or external sources, such as
|
|
I/O devices. The requests are stored in pi_prq for program
|
|
requests, pi_apr for other internal flags, and pi_ioq for
|
|
I/O device flags. Internal and device (but not program)
|
|
interrupts must be enabled on a level by level basis. When
|
|
an interrupt is granted on a level, interrupts at that level
|
|
and below are masked until the interrupt is dismissed.
|
|
|
|
|
|
3. Arithmetic. The PDP-10 is a 2's complement system.
|
|
|
|
4. Adding I/O devices. These modules must be modified:
|
|
|
|
ka10_defs.h add device address and interrupt definitions
|
|
ka10_sys.c add sim_devices table entry
|
|
|
|
*/
|
|
|
|
#include "ka10_defs.h"
|
|
#include "sim_timer.h"
|
|
#include <time.h>
|
|
|
|
#define HIST_PC 0x40000000
|
|
#define HIST_PC2 0x80000000
|
|
#define HIST_MIN 64
|
|
#define HIST_MAX 500000
|
|
#define TMR_RTC 1
|
|
|
|
#define UNIT_V_MSIZE (UNIT_V_UF + 0)
|
|
#if KI10
|
|
#define UNIT_MSIZE (0177 << UNIT_V_MSIZE)
|
|
#else
|
|
#define UNIT_MSIZE (017 << UNIT_V_MSIZE)
|
|
#endif
|
|
#define UNIT_V_TWOSEG (UNIT_V_MSIZE + 8)
|
|
#define UNIT_TWOSEG (1 << UNIT_V_TWOSEG)
|
|
|
|
|
|
uint64 M[MAXMEMSIZE]; /* Memory */
|
|
#if KI
|
|
uint64 FM[64]; /* Fast memory register */
|
|
#else
|
|
uint64 FM[16]; /* Fast memory register */
|
|
#endif
|
|
uint64 AR; /* Primary work register */
|
|
uint64 MQ; /* Extension to AR */
|
|
uint64 BR; /* Secondary operand */
|
|
uint64 AD; /* Address Data */
|
|
uint64 MB; /* Memory Bufer Register */
|
|
uint32 AB; /* Memory address buffer */
|
|
uint32 PC; /* Program counter */
|
|
uint32 IR; /* Instruction register */
|
|
uint32 FLAGS; /* Flags */
|
|
uint32 AC; /* Operand accumulator */
|
|
uint64 SW; /* Switch register */
|
|
int BYF5; /* Second half of LDB/DPB instruction */
|
|
int uuo_cycle; /* Uuo cycle in progress */
|
|
int sac_inh; /* Don't store AR in AC */
|
|
int SC; /* Shift count */
|
|
int SCAD; /* Shift count extension */
|
|
int FE; /* Exponent */
|
|
#if KA | PDP6
|
|
int Pl, Ph, Rl, Rh, Pflag; /* Protection registers */
|
|
char push_ovf; /* Push stack overflow */
|
|
char mem_prot; /* Memory protection flag */
|
|
#endif
|
|
char nxm_flag; /* Non-existant memory flag */
|
|
char clk_flg; /* Clock flag */
|
|
char ov_irq; /* Trap overflow */
|
|
char fov_irq; /* Trap floating overflow */
|
|
#if PDP6
|
|
char pcchg_irq; /* PC Change flag */
|
|
#endif
|
|
char PIR; /* Current priority level */
|
|
char PIH; /* Highest priority */
|
|
char PIE; /* Priority enable mask */
|
|
char pi_enable; /* Interrupts enabled */
|
|
char parity_irq; /* Parity interupt */
|
|
char pi_pending; /* Interrupt pending. */
|
|
int pi_req; /* Current interrupt request */
|
|
int pi_enc; /* Flag for pi */
|
|
int apr_irq; /* Apr Irq level */
|
|
char clk_en; /* Enable clock interrupts */
|
|
int clk_irq; /* Clock interrupt */
|
|
char pi_restore; /* Restore previous level */
|
|
char pi_hold; /* Hold onto interrupt */
|
|
#if KI
|
|
uint64 ARX; /* Extension to AR */
|
|
uint64 BRX; /* Extension to BR */
|
|
uint64 ADX; /* Extension to AD */
|
|
uint32 ub_ptr; /* User base pointer */
|
|
uint32 eb_ptr; /* Executive base pointer */
|
|
uint8 fm_sel; /* User fast memory block */
|
|
char small_user; /* Small user flag */
|
|
char user_addr_cmp; /* User address compare flag */
|
|
char page_enable; /* Enable paging */
|
|
char page_fault; /* Page fail */
|
|
char xct_flag; /* XCT flags */
|
|
uint32 ac_stack; /* Register stack pointer */
|
|
uint32 pag_reload; /* Page reload pointer */
|
|
char inout_fail; /* In out fail flag */
|
|
int modify; /* Modify cycle */
|
|
int public_access; /* Last access from public page */
|
|
int private_page; /* Access to private page */
|
|
uint64 fault_data; /* Fault data from last fault */
|
|
int32 apr_serial = -1; /* CPU Serial number */
|
|
int trap_flag; /* Last instruction was trapped */
|
|
int last_page; /* Last page mapped */
|
|
#endif
|
|
|
|
char dev_irq[128]; /* Pending irq by device */
|
|
t_stat (*dev_tab[128])(uint32 dev, uint64 *data);
|
|
t_stat rtc_srv(UNIT * uptr);
|
|
int32 rtc_tps = 60;
|
|
int32 tmxr_poll = 10000;
|
|
|
|
typedef struct {
|
|
uint32 pc;
|
|
uint32 ea;
|
|
uint64 ir;
|
|
uint64 ac;
|
|
uint32 flags;
|
|
uint64 mb;
|
|
uint64 fmb;
|
|
} InstHistory;
|
|
|
|
int32 hst_p = 0; /* history pointer */
|
|
int32 hst_lnt = 0; /* history length */
|
|
InstHistory *hst = NULL; /* instruction history */
|
|
|
|
/* Forward and external declarations */
|
|
|
|
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_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
#if KI
|
|
t_stat cpu_set_serial (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
#endif
|
|
t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
|
const char *cptr);
|
|
const char *cpu_description (DEVICE *dptr);
|
|
void set_ac_display (uint64 *acbase);
|
|
|
|
t_bool build_dev_tab (void);
|
|
|
|
/* CPU data structures
|
|
|
|
cpu_dev CPU device descriptor
|
|
cpu_unit CPU unit
|
|
cpu_reg CPU register list
|
|
cpu_mod CPU modifier list
|
|
*/
|
|
|
|
UNIT cpu_unit = { UDATA (&rtc_srv, UNIT_FIX|UNIT_BINK|UNIT_TWOSEG, MAXMEMSIZE) };
|
|
|
|
REG cpu_reg[] = {
|
|
{ ORDATA (PC, PC, 18) },
|
|
{ ORDATA (FLAGS, FLAGS, 18) },
|
|
{ ORDATA (FM0, FM[00], 36) }, /* addr in memory */
|
|
{ ORDATA (FM1, FM[01], 36) }, /* modified at exit */
|
|
{ ORDATA (FM2, FM[02], 36) }, /* to SCP */
|
|
{ ORDATA (FM3, FM[03], 36) },
|
|
{ ORDATA (FM4, FM[04], 36) },
|
|
{ ORDATA (FM5, FM[05], 36) },
|
|
{ ORDATA (FM6, FM[06], 36) },
|
|
{ ORDATA (FM7, FM[07], 36) },
|
|
{ ORDATA (FM10, FM[010], 36) },
|
|
{ ORDATA (FM11, FM[011], 36) },
|
|
{ ORDATA (FM12, FM[012], 36) },
|
|
{ ORDATA (FM13, FM[013], 36) },
|
|
{ ORDATA (FM14, FM[014], 36) },
|
|
{ ORDATA (FM15, FM[015], 36) },
|
|
{ ORDATA (FM16, FM[016], 36) },
|
|
{ ORDATA (FM17, FM[017], 36) },
|
|
{ ORDATA (PIENB, pi_enable, 7) },
|
|
{ BRDATA (REG, FM, 8, 36, 017) },
|
|
{ ORDATAD(SW, SW, 36, "Console SW Register"), REG_FIT},
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB cpu_mod[] = {
|
|
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
|
|
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
|
|
{ UNIT_MSIZE, 1, "16K", "16K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 2, "32K", "32K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 4, "64K", "64K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 8, "128K", "128K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 12, "196K", "196K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 16, "256K", "256K", &cpu_set_size },
|
|
#if KI_22BIT
|
|
{ UNIT_MSIZE, 32, "512K", "512K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 64, "1024K", "1024K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 128, "2048K", "2048K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 256, "4096K", "4096K", &cpu_set_size },
|
|
#endif
|
|
#if KI
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "SERIAL", "SERIAL",
|
|
&cpu_set_serial, &cpu_show_serial },
|
|
#endif
|
|
#if !KI
|
|
{ UNIT_TWOSEG, 0, "ONESEG", "ONESEG", NULL, NULL, NULL},
|
|
{ UNIT_TWOSEG, UNIT_TWOSEG, "TWOSEG", "TWOSEG", NULL, NULL, NULL},
|
|
#endif
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
|
|
&cpu_set_hist, &cpu_show_hist },
|
|
{ 0 }
|
|
};
|
|
|
|
/* Simulator debug controls */
|
|
DEBTAB cpu_debug[] = {
|
|
{"IRQ", DEBUG_IRQ, "Debug IRQ requests"},
|
|
{"CONI", DEBUG_CONI, "Show coni instructions"},
|
|
{"CONO", DEBUG_CONO, "Show coni instructions"},
|
|
{"DATAIO", DEBUG_DATAIO, "Show datai and datao instructions"},
|
|
{0, 0}
|
|
};
|
|
|
|
DEVICE cpu_dev = {
|
|
"CPU", &cpu_unit, cpu_reg, cpu_mod,
|
|
1, 8, 18, 1, 8, 36,
|
|
&cpu_ex, &cpu_dep, &cpu_reset,
|
|
NULL, NULL, NULL, NULL, DEV_DEBUG, 0, cpu_debug,
|
|
NULL, NULL, &cpu_help, NULL, NULL, &cpu_description
|
|
};
|
|
|
|
/* Data arrays */
|
|
#define FCE 000001 /* Fetch memory into AR */
|
|
#define FCEPSE 000002 /* Fetch and store memory into AR */
|
|
#define SCE 000004 /* Save AR into memory */
|
|
#define FAC 000010 /* Fetch AC into AR */
|
|
#define FAC2 000020 /* Fetch AC+1 into MQ */
|
|
#define SAC 000040 /* Save AC into AR */
|
|
#define SACZ 000100 /* Save AC into AR if AC not 0 */
|
|
#define SAC2 000200 /* Save MQ into AC+1 */
|
|
#define MBR 000400 /* Load Mem to BR, AC to AR */
|
|
#define SWAR 001000 /* Swap AR */
|
|
#define FBR 002000 /* Load AC into BR */
|
|
#define FMB 004000 /* Load MB into BR */
|
|
|
|
int opflags[] = {
|
|
/* UUO00 */ /* LUUO01 */ /* LUUO02 */ /* LUUO03 */
|
|
0, 0, 0, 0,
|
|
/* LUUO04 */ /* LUUO05 */ /* LUUO06 */ /* LUUO07 */
|
|
0, 0, 0, 0,
|
|
/* LUUO10 */ /* LUUO11 */ /* LUUO12 */ /* LUUO13 */
|
|
0, 0, 0, 0,
|
|
/* LUUO14 */ /* LUUO15 */ /* LUUO16 */ /* LUUO17 */
|
|
0, 0, 0, 0,
|
|
/* LUUO20 */ /* LUUO21 */ /* LUUO22 */ /* LUUO23 */
|
|
0, 0, 0, 0,
|
|
/* LUUO24 */ /* LUUO25 */ /* LUUO26 */ /* LUUO27 */
|
|
0, 0, 0, 0,
|
|
/* LUUO30 */ /* LUUO31 */ /* LUUO32 */ /* LUUO33 */
|
|
0, 0, 0, 0,
|
|
/* LUUO34 */ /* LUUO35 */ /* LUUO36 */ /* LUUO37 */
|
|
0, 0, 0, 0,
|
|
/* MUUO40 */ /* MUUO41 */ /* MUUO42 */ /* MUUO43 */
|
|
0, 0, 0, 0,
|
|
/* MUUO44 */ /* MUUO45 */ /* MUUO46 */ /* MUUO47 */
|
|
0, 0, 0, 0,
|
|
/* MUUO50 */ /* MUUO51 */ /* MUUO52 */ /* MUUO53 */
|
|
0, 0, 0, 0,
|
|
/* MUUO54 */ /* MUUO55 */ /* MUUO56 */ /* MUUO57 */
|
|
0, 0, 0, 0,
|
|
/* MUUO60 */ /* MUUO61 */ /* MUUO62 */ /* MUUO63 */
|
|
0, 0, 0, 0,
|
|
/* MUUO64 */ /* MUUO65 */ /* MUUO66 */ /* MUUO67 */
|
|
0, 0, 0, 0,
|
|
/* MUUO70 */ /* MUUO71 */ /* MUUO72 */ /* MUUO73 */
|
|
0, 0, 0, 0,
|
|
/* MUUO74 */ /* MUUO75 */ /* MUUO76 */ /* MUUO77 */
|
|
0, 0, 0, 0,
|
|
/* UJEN */ /* UUO101 */ /* GFAD */ /* GFSB */
|
|
0, 0, 0, 0,
|
|
/* JSYS */ /* ADJSP */ /* GFMP */ /*GFDV */
|
|
0, 0, 0, 0,
|
|
#if KI
|
|
/* DFAD */ /* DFSB */ /* DFMP */ /* DFDV */
|
|
FCE|FAC|FAC2|SAC|SAC2, FCE|FAC|FAC2|SAC|SAC2,
|
|
FCE|FAC|FAC2|SAC|SAC2, FCE|FAC|FAC2|SAC|SAC2,
|
|
/* DADD */ /* DSUB */ /* DMUL */ /* DDIV */
|
|
0, 0, 0, 0,
|
|
/* DMOVE */ /* DMOVN */ /* FIX */ /* EXTEND */
|
|
FCE|SAC|SAC2, FCE|SAC|SAC2, FCE|SAC, 0,
|
|
/* DMOVEM */ /* DMOVNM */ /* FIXR */ /* FLTR */
|
|
FAC|FAC2, FAC|FAC2, FCE|SAC, FCE|SAC,
|
|
#else
|
|
/* DFAD */ /* DFSB */ /* DFMP */ /* DFDV */
|
|
0, 0, 0, 0,
|
|
/* DADD */ /* DSUB */ /* DMUL */ /* DDIV */
|
|
0, 0, 0, 0,
|
|
/* DMOVE */ /* DMOVN */ /* FIX */ /* EXTEND */
|
|
0, 0, 0, 0,
|
|
/* DMOVEM */ /* DMOVNM */ /* FIXR */ /* FLTR */
|
|
0, 0, 0, 0,
|
|
#endif
|
|
/* UFA */ /* DFN */ /* FSC */ /* IBP */
|
|
FCE|FBR, FCE|FAC|SAC, FAC|SAC, 0,
|
|
/* ILDB */ /* LDB */ /* IDPB */ /* DPB */
|
|
0, 0, 0, 0,
|
|
/* FAD */ /* FADL */ /* FADM */ /* FADB */
|
|
SAC|FBR|FCE, SAC|SAC2|FBR|FCE, FCEPSE|FBR, SAC|FBR|FCEPSE,
|
|
/* FADR */ /* FADRI */ /* FADRM */ /* FADRB */
|
|
SAC|FBR|FCE, SAC|FBR|SWAR, FCEPSE|FBR, SAC|FBR|FCEPSE,
|
|
/* FSB */ /* FSBL */ /* FSBM */ /* FSBB */
|
|
SAC|FBR|FCE, SAC|SAC2|FBR|FCE, FCEPSE|FBR, SAC|FBR|FCEPSE,
|
|
/* FSBR */ /* FSBRI */ /* FSBRM */ /* FSBRB */
|
|
SAC|FBR|FCE, SAC|FBR|SWAR, FCEPSE|FBR, SAC|FBR|FCEPSE,
|
|
/* FMP */ /* FMPL */ /* FMPM */ /* FMPB */
|
|
SAC|FBR|FCE, SAC|SAC2|FBR|FCE, FCEPSE|FBR, SAC|FBR|FCEPSE,
|
|
/* FMPR */ /* FMPRI */ /* FMPRM */ /* FMPRB */
|
|
SAC|FBR|FCE, SAC|FBR|SWAR, FCEPSE|FBR, SAC|FBR|FCEPSE,
|
|
/* FDV */ /* FDVL */ /* FDVM */ /* FDVB */
|
|
SAC|FBR|FCE, FAC2|SAC2|SAC|FBR|FCE, FCEPSE|FBR, SAC|FBR|FCEPSE,
|
|
/* FDVR */ /* FDVRI */ /* FDVRM */ /* FDVRB */
|
|
SAC|FBR|FCE, SAC|FBR|SWAR, FCEPSE|FBR, SAC|FBR|FCEPSE,
|
|
|
|
/* MOVE */ /* MOVEI */ /* MOVEM */ /* MOVES */
|
|
SAC|FCE, SAC, FAC|SCE, SACZ|FCEPSE,
|
|
/* MOVS */ /* MOVSI */ /* MOVSM */ /* MOVSS */
|
|
SWAR|SAC|FCE, SWAR|SAC, SWAR|FAC|SCE, SWAR|SACZ|FCEPSE,
|
|
/* MOVN */ /* MOVNI */ /* MOVNM */ /* MOVNS */
|
|
SAC|FCE, SAC, FAC|SCE, SACZ|FCEPSE,
|
|
/* MOVM */ /* MOVMI */ /* MOVMM */ /* MOVMS */
|
|
SAC|FCE, SAC, FAC|SCE, SACZ|FCEPSE,
|
|
/* IMUL */ /* IMULI */ /* IMULM */ /* IMULB */
|
|
SAC|FCE|FBR, SAC|FBR, FCEPSE|FBR, SAC|FCEPSE|FBR,
|
|
/* MUL */ /* MULI */ /* MULM */ /* MULB */
|
|
SAC2|SAC|FCE|FBR, SAC2|SAC|FBR, FCEPSE|FBR, SAC2|SAC|FCEPSE|FBR,
|
|
/* IDIV */ /* IDIVI */ /* IDIVM */ /* IDIVB */
|
|
SAC2|SAC|FCE|FAC, SAC2|SAC|FAC, FCEPSE|FAC, SAC2|SAC|FCEPSE|FAC,
|
|
/* DIV */ /* DIVI */ /* DIVM */ /* DIVB */
|
|
SAC2|SAC|FCE|FAC|FAC2, SAC2|SAC|FAC|FAC2,
|
|
FCEPSE|FAC|FAC2, SAC2|SAC|FCEPSE|FAC|FAC2,
|
|
/* ASH */ /* ROT */ /* LSH */ /* JFFO */
|
|
FAC|SAC, FAC|SAC, FAC|SAC, FAC,
|
|
/* ASHC */ /* ROTC */ /* LSHC */ /* UUO247 */
|
|
FAC|SAC|SAC2|FAC2, FAC|SAC|SAC2|FAC2, FAC|SAC|SAC2|FAC2, 0,
|
|
|
|
/* EXCH */ /* BLT */ /* AOBJP */ /* AOBJN */
|
|
FAC|FCEPSE, FAC, FAC|SAC, FAC|SAC,
|
|
/* JRST */ /* JFCL */ /* XCT */ /* MAP */
|
|
#if KI
|
|
0, 0, 0, SAC,
|
|
#else
|
|
0, 0, 0, 0,
|
|
#endif
|
|
/* PUSHJ */ /* PUSH */ /* POP */ /* POPJ */
|
|
FAC|SAC, FAC|FCE|SAC, FAC|SAC, FAC|SAC,
|
|
/* JSR */ /* JSP */ /* JSA */ /* JRA */
|
|
0, SAC, FBR|SCE, 0,
|
|
/* ADD */ /* ADDI */ /* ADDM */ /* ADDB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* SUB */ /* SUBI */ /* SUBM */ /* SUBB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
|
|
/* CAI */ /* CAIL */ /* CAIE */ /* CAILE */
|
|
FBR, FBR, FBR, FBR,
|
|
/* CAIA */ /* CAIGE */ /* CAIN */ /* CAIG */
|
|
FBR, FBR, FBR, FBR,
|
|
/* CAM */ /* CAML */ /* CAME */ /* CAMLE */
|
|
FBR|FCE, FBR|FCE, FBR|FCE, FBR|FCE,
|
|
/* CAMA */ /* CAMGE */ /* CAMN */ /* CAMG */
|
|
FBR|FCE, FBR|FCE, FBR|FCE, FBR|FCE,
|
|
/* JUMP */ /* JUMPL */ /* JUMPE */ /* JUMPLE */
|
|
FAC, FAC, FAC, FAC,
|
|
/* JUMPA */ /* JUMPGE */ /* JUMPN */ /* JUMPG */
|
|
FAC, FAC, FAC, FAC,
|
|
/* SKIP */ /* SKIPL */ /* SKIPE */ /* SKIPLE */
|
|
SACZ|FCE, SACZ|FCE, SACZ|FCE, SACZ|FCE,
|
|
/* SKIPA */ /* SKIPGE */ /* SKIPN */ /* SKIPG */
|
|
SACZ|FCE, SACZ|FCE, SACZ|FCE, SACZ|FCE,
|
|
/* AOJ */ /* AOJL */ /* AOJE */ /* AOJLE */
|
|
SAC|FAC, SAC|FAC, SAC|FAC, SAC|FAC,
|
|
/* AOJA */ /* AOJGE */ /* AOJN */ /* AOJG */
|
|
SAC|FAC, SAC|FAC, SAC|FAC, SAC|FAC,
|
|
/* AOS */ /* AOSL */ /* AOSE */ /* AOSLE */
|
|
SACZ|FCEPSE, SACZ|FCEPSE, SACZ|FCEPSE, SACZ|FCEPSE,
|
|
/* AOSA */ /* AOSGE */ /* AOSN */ /* AOSG */
|
|
SACZ|FCEPSE, SACZ|FCEPSE, SACZ|FCEPSE, SACZ|FCEPSE,
|
|
/* SOJ */ /* SOJL */ /* SOJE */ /* SOJLE */
|
|
SAC|FAC, SAC|FAC, SAC|FAC, SAC|FAC,
|
|
/* SOJA */ /* SOJGE */ /* SOJN */ /* SOJG */
|
|
SAC|FAC, SAC|FAC, SAC|FAC, SAC|FAC,
|
|
/* SOS */ /* SOSL */ /* SOSE */ /* SOSLE */
|
|
SACZ|FCEPSE, SACZ|FCEPSE, SACZ|FCEPSE, SACZ|FCEPSE,
|
|
/* SOSA */ /* SOSGE */ /* SOSN */ /* SOSG */
|
|
SACZ|FCEPSE, SACZ|FCEPSE, SACZ|FCEPSE, SACZ|FCEPSE,
|
|
|
|
/* SETZ */ /* SETZI */ /* SETZM */ /* SETZB */
|
|
FBR|SAC, FBR|SAC, FBR|SCE, FBR|SAC|SCE,
|
|
/* AND */ /* ANDI */ /* ANDM */ /* ANDB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* ANDCA */ /* ANDCAI */ /* ANDCAM */ /* ANDCAB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* SETM */ /* SETMI */ /* SETMM */ /* SETMB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR, FBR|SAC|FCE,
|
|
/* ANDCM */ /* ANDCMI */ /* ANDCMM */ /* ANDCMB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* SETA */ /* SETAI */ /* SETAM */ /* SETAB */
|
|
FBR|SAC, FBR|SAC, FBR|SCE, FBR|SAC|SCE,
|
|
/* XOR */ /* XORI */ /* XORM */ /* XORB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* IOR */ /* IORI */ /* IORM */ /* IORB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* ANDCB */ /* ANDCBI */ /* ANDCBM */ /* ANDCBB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* EQV */ /* EQVI */ /* EQVM */ /* EQVB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* SETCA */ /* SETCAI */ /* SETCAM */ /* SETCAB */
|
|
FBR|SAC, FBR|SAC, FBR|SCE, FBR|SAC|SCE,
|
|
/* ORCA */ /* ORCAI */ /* ORCAM */ /* ORCAB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* SETCM */ /* SETCMI */ /* SETCMM */ /* SETCMB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* ORCM */ /* ORCMI */ /* ORCMM */ /* ORCMB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* ORCB */ /* ORCBI */ /* ORCBM */ /* ORCBB */
|
|
FBR|SAC|FCE, FBR|SAC, FBR|FCEPSE, FBR|SAC|FCEPSE,
|
|
/* SETO */ /* SETOI */ /* SETOM */ /* SETOB */
|
|
FBR|SAC, FBR|SAC, FBR|SCE, FBR|SAC|SCE,
|
|
|
|
/* HLL */ /* HLLI */ /* HLLM */ /* HLLS */
|
|
FBR|SAC|FCE, FBR|SAC, FAC|FMB|FCEPSE, FMB|SACZ|FCEPSE,
|
|
/* HRL */ /* HRLI */ /* HRLM */ /* HRLS */
|
|
SWAR|FBR|SAC|FCE, SWAR|FBR|SAC, SWAR|FAC|FMB|FCEPSE, SWAR|FMB|SACZ|FCEPSE,
|
|
/* HLLZ */ /* HLLZI */ /* HLLZM */ /* HLLZS */
|
|
FBR|SAC|FCE, FBR|SAC, FAC|FMB|FCEPSE, FMB|SACZ|FCEPSE,
|
|
/* HRLZ */ /* HRLZI */ /* HRLZM */ /* HRLZS */
|
|
SWAR|FBR|SAC|FCE, SWAR|FBR|SAC, SWAR|FAC|FMB|FCEPSE, SWAR|FMB|SACZ|FCEPSE,
|
|
/* HLLO */ /* HLLOI */ /* HLLOM */ /* HLLOS */
|
|
FBR|SAC|FCE, FBR|SAC, FAC|FMB|FCEPSE, FMB|SACZ|FCEPSE,
|
|
/* HRLO */ /* HRLOI */ /* HRLOM */ /* HRLOS */
|
|
SWAR|FBR|SAC|FCE, SWAR|FBR|SAC, SWAR|FAC|FMB|FCEPSE, SWAR|FMB|SACZ|FCEPSE,
|
|
/* HLLE */ /* HLLEI */ /* HLLEM */ /* HLLES */
|
|
FBR|SAC|FCE, FBR|SAC, FAC|FMB|FCEPSE, FMB|SACZ|FCEPSE,
|
|
/* HRLE */ /* HRLEI */ /* HRLEM */ /* HRLES */
|
|
SWAR|FBR|SAC|FCE, SWAR|FBR|SAC, SWAR|FAC|FMB|FCEPSE, SWAR|FMB|SACZ|FCEPSE,
|
|
/* HRR */ /* HRRI */ /* HRRM */ /* HRRS */
|
|
FBR|SAC|FCE, FBR|SAC, FAC|FMB|FCEPSE, FMB|SACZ|FCEPSE,
|
|
/* HLR */ /* HLRI */ /* HLRM */ /* HLRS */
|
|
SWAR|FBR|SAC|FCE, SWAR|FBR|SAC, SWAR|FAC|FMB|FCEPSE, SWAR|FMB|SACZ|FCEPSE,
|
|
/* HRRZ */ /* HRRZI */ /* HRRZM */ /* HRRZS */
|
|
FBR|SAC|FCE, FBR|SAC, FAC|FMB|FCEPSE, FMB|SACZ|FCEPSE,
|
|
/* HLRZ */ /* HLRZI */ /* HLRZM */ /* HLRZS */
|
|
SWAR|FBR|SAC|FCE, SWAR|FBR|SAC, SWAR|FAC|FMB|FCEPSE, SWAR|FMB|SACZ|FCEPSE,
|
|
/* HRRO */ /* HRROI */ /* HRROM */ /* HRROS */
|
|
FBR|SAC|FCE, FBR|SAC, FAC|FMB|FCEPSE, FMB|SACZ|FCEPSE,
|
|
/* HLRO */ /* HLROI */ /* HLROM */ /* HLROS */
|
|
SWAR|FBR|SAC|FCE, SWAR|FBR|SAC, SWAR|FAC|FMB|FCEPSE, SWAR|FMB|SACZ|FCEPSE,
|
|
/* HRRE */ /* HRREI */ /* HRREM */ /* HRRES */
|
|
FBR|SAC|FCE, FBR|SAC, FAC|FMB|FCEPSE, FMB|SACZ|FCEPSE,
|
|
/* HLRE */ /* HLREI */ /* HLREM */ /* HLRES */
|
|
SWAR|FBR|SAC|FCE, SWAR|FBR|SAC, SWAR|FAC|FMB|FCEPSE, SWAR|FMB|SACZ|FCEPSE,
|
|
|
|
/* TRN */ /* TLN */ /* TRNE */ /* TLNE */
|
|
FBR, FBR|SWAR, FBR, FBR|SWAR,
|
|
/* TRNA */ /* TLNA */ /* TRNN */ /* TLNN */
|
|
FBR, FBR|SWAR, FBR, FBR|SWAR,
|
|
/* TDN */ /* TSN */ /* TDNE */ /* TSNE */
|
|
FBR|FCE, FBR|SWAR|FCE, FBR|FCE, FBR|SWAR|FCE,
|
|
/* TDNA */ /* TSNA */ /* TDNN */ /* TSNN */
|
|
FBR|FCE, FBR|SWAR|FCE, FBR|FCE, FBR|SWAR|FCE,
|
|
/* TRZ */ /* TLZ */ /* TRZE */ /* TLZE */
|
|
FBR|SAC, FBR|SAC|SWAR, FBR|SAC, FBR|SAC|SWAR,
|
|
/* TRZA */ /* TLZA */ /* TRZN */ /* TLZN */
|
|
FBR|SAC, FBR|SAC|SWAR, FBR|SAC, FBR|SAC|SWAR,
|
|
/* TDZ */ /* TSZ */ /* TDZE */ /* TSZE */
|
|
FBR|SAC|FCE, FBR|SAC|SWAR|FCE, FBR|SAC|FCE, FBR|SAC|SWAR|FCE,
|
|
/* TDZA */ /* TSZA */ /* TDZN */ /* TSZN */
|
|
FBR|SAC|FCE, FBR|SAC|SWAR|FCE, FBR|SAC|FCE, FBR|SAC|SWAR|FCE,
|
|
/* TRC */ /* TLC */ /* TRCE */ /* TLCE */
|
|
FBR|SAC, FBR|SAC|SWAR, FBR|SAC, FBR|SAC|SWAR,
|
|
/* TRCA */ /* TLCA */ /* TRCN */ /* TLCN */
|
|
FBR|SAC, FBR|SAC|SWAR, FBR|SAC, FBR|SAC|SWAR,
|
|
/* TDC */ /* TSC */ /* TDCE */ /* TSCE */
|
|
FBR|SAC|FCE, FBR|SAC|SWAR|FCE, FBR|SAC|FCE, FBR|SAC|SWAR|FCE,
|
|
/* TDCA */ /* TSCA */ /* TDCN */ /* TSCN */
|
|
FBR|SAC|FCE, FBR|SAC|SWAR|FCE, FBR|SAC|FCE, FBR|SAC|SWAR|FCE,
|
|
/* TRO */ /* TLO */ /* TROE */ /* TLOE */
|
|
FBR|SAC, FBR|SAC|SWAR, FBR|SAC, FBR|SAC|SWAR,
|
|
/* TROA */ /* TLOA */ /* TRON */ /* TLON */
|
|
FBR|SAC, FBR|SAC|SWAR, FBR|SAC, FBR|SAC|SWAR,
|
|
/* TDO */ /* TSO */ /* TDOE */ /* TSOE */
|
|
FBR|SAC|FCE, FBR|SWAR|SAC|FCE, FBR|SAC|FCE, FBR|SAC|SWAR|FCE,
|
|
/* TDOA */ /* TSOA */ /* TDON */ /* TSON */
|
|
FBR|SAC|FCE, FBR|SWAR|SAC|FCE, FBR|SAC|FCE, FBR|SAC|SWAR|FCE,
|
|
/* IOT Instructions */
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
};
|
|
|
|
#define SWAP_AR ((RMASK & AR) << 18) | ((AR >> 18) & RMASK)
|
|
#define SMEAR_SIGN(x) x = ((x) & SMASK) ? (x) | EXPO : (x) & MANT
|
|
#define GET_EXPO(x) ((((x) & SMASK) ? 0377 : 0 ) \
|
|
^ (((x) >> 27) & 0377))
|
|
#if KI
|
|
#define AOB(x) ((x + 1) & RMASK) | ((x + 01000000LL) & (C1|LMASK))
|
|
#define SOB(x) ((x + RMASK) & RMASK) | ((x + LMASK) & (C1|LMASK));
|
|
#else
|
|
#define AOB(x) (x + 01000001LL)
|
|
#define SOB(x) (x + 0777776777777LL)
|
|
#endif
|
|
|
|
/*
|
|
* Set device to interrupt on a given level 1-7
|
|
* Level 0 means that device interrupt is not enabled
|
|
*/
|
|
void set_interrupt(int dev, int lvl) {
|
|
lvl &= 07;
|
|
if (lvl) {
|
|
dev_irq[dev>>2] = 0200 >> lvl;
|
|
pi_pending = 1;
|
|
sim_debug(DEBUG_IRQ, &cpu_dev, "set irq %o %o\n", dev & 0774, lvl);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Clear the interrupt flag for a device
|
|
*/
|
|
void clr_interrupt(int dev) {
|
|
dev_irq[dev>>2] = 0;
|
|
sim_debug(DEBUG_IRQ, &cpu_dev, "clear irq %o\n", dev & 0774);
|
|
}
|
|
|
|
/*
|
|
* Check if there is any pending interrupts return 0 if none,
|
|
* else set pi_enc to highest level and return 1.
|
|
*/
|
|
int check_irq_level() {
|
|
int i, lvl;
|
|
int pi_ok, pi_t;
|
|
|
|
/* Scan all devices */
|
|
for(i = lvl = 0; i < 128; i++)
|
|
lvl |= dev_irq[i];
|
|
if (lvl == 0)
|
|
pi_pending = 0;
|
|
PIR |= (lvl & PIE);
|
|
/* Handle held interrupt requests */
|
|
pi_t = (~PIR & ~PIH) >> 1;
|
|
pi_ok = 0100 & (PIR & ~PIH);
|
|
/* Still have a valid interrupt? */
|
|
if (!pi_ok) {
|
|
/* None at level 1, check for lower level */
|
|
lvl = 0040;
|
|
for(i = 2; i <= 7; i++) {
|
|
if (lvl & pi_t) {
|
|
pi_ok |= lvl;
|
|
lvl >>= 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* We have 1 bit for each non held interrupt. */
|
|
pi_req = PIR & ~PIH & pi_ok;
|
|
if (pi_req) {
|
|
int pi_r = pi_req;
|
|
for(lvl = i = 1; i<=7; i++, lvl++) {
|
|
if (pi_r & 0100)
|
|
break;
|
|
pi_r <<= 1;
|
|
}
|
|
pi_enc = lvl;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Recover from held interrupt.
|
|
*/
|
|
void restore_pi_hold() {
|
|
int i, lvl;
|
|
|
|
if (!pi_enable)
|
|
return;
|
|
/* Compute mask for pi_ok */
|
|
lvl = 0100;
|
|
/* Clear HOLD flag for highest interrupt */
|
|
for(i = 1; i <= 7; i++) {
|
|
if (lvl & PIH) {
|
|
PIR &= ~lvl;
|
|
PIH &= ~lvl;
|
|
break;
|
|
}
|
|
lvl >>= 1;
|
|
}
|
|
pi_pending = 1;
|
|
}
|
|
|
|
/*
|
|
* Hold interrupts at the current level.
|
|
*/
|
|
void set_pi_hold() {
|
|
PIH |= 0200 >> pi_enc;
|
|
PIR &= ~(0200 >> pi_enc);
|
|
}
|
|
|
|
#if KI
|
|
static int timer_irq, timer_flg;
|
|
|
|
/*
|
|
* Page device for KI10.
|
|
*/
|
|
t_stat dev_pag(uint32 dev, uint64 *data) {
|
|
uint64 res = 0;
|
|
switch(dev & 03) {
|
|
case CONI:
|
|
/* Complement of vpn */
|
|
*data = (uint64)(pag_reload ^ 040);
|
|
*data |= ((uint64)last_page) << 8;
|
|
*data |= (uint64)((apr_serial == -1) ? DEF_SERIAL : apr_serial) << 26;
|
|
sim_debug(DEBUG_CONI, &cpu_dev, "CONI PAG %012llo\n", *data);
|
|
break;
|
|
|
|
case CONO:
|
|
/* Set Stack AC and Page Table Reload Counter */
|
|
ac_stack = (*data >> 9) & 0760;
|
|
pag_reload = (*data & 037) | (pag_reload & 040);
|
|
sim_debug(DEBUG_CONO, &cpu_dev, "CONI PAG %012llo\n", *data);
|
|
break;
|
|
|
|
case DATAO:
|
|
res = *data;
|
|
if (res & LSIGN) {
|
|
eb_ptr = (res & 017777) << 9;
|
|
page_enable = (res & 020000) != 0;
|
|
}
|
|
if (res & SMASK) {
|
|
ub_ptr = ((res >> 18) & 017777) << 9;
|
|
user_addr_cmp = (res & 00020000000000LL) != 0;
|
|
small_user = (res & 00040000000000LL) != 0;
|
|
fm_sel = (uint8)(res >> 29) & 060;
|
|
}
|
|
pag_reload = 0;
|
|
sim_debug(DEBUG_DATAIO, &cpu_dev,
|
|
"DATAO PAG %012llo ebr=%06o ubr=%06o\n",
|
|
*data, eb_ptr, ub_ptr);
|
|
break;
|
|
|
|
case DATAI:
|
|
res = (eb_ptr >> 9);
|
|
if (page_enable)
|
|
res |= 020000;
|
|
res |= ((uint64)(ub_ptr)) << 9;
|
|
if (user_addr_cmp)
|
|
res |= 00020000000000LL;
|
|
if (small_user)
|
|
res |= 00040000000000LL;
|
|
res |= ((uint64)(fm_sel)) << 29;
|
|
*data = res;
|
|
sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI PAG %012llo\n", *data);
|
|
break;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/*
|
|
* Check if the last operation caused a APR IRQ to be generated.
|
|
*/
|
|
void check_apr_irq() {
|
|
if (apr_irq) {
|
|
int flg = 0;
|
|
clr_interrupt(0);
|
|
flg |= inout_fail | nxm_flag;
|
|
if (flg)
|
|
set_interrupt(0, apr_irq);
|
|
}
|
|
if (clk_en && clk_flg)
|
|
set_interrupt(4, clk_irq);
|
|
}
|
|
|
|
|
|
/*
|
|
* APR device for KI10.
|
|
*/
|
|
t_stat dev_apr(uint32 dev, uint64 *data) {
|
|
uint64 res = 0;
|
|
switch(dev & 03) {
|
|
case CONI:
|
|
/* Read trap conditions */
|
|
res = clk_irq | (apr_irq << 3) | (nxm_flag << 6);
|
|
res |= (inout_fail << 7) | (clk_flg << 9) | (clk_en << 10);
|
|
res |= (timer_irq << 14) | (parity_irq << 15) | (timer_flg << 17);
|
|
*data = res;
|
|
sim_debug(DEBUG_CONI, &cpu_dev, "CONI APR %012llo\n", *data);
|
|
break;
|
|
|
|
case CONO:
|
|
/* Set trap conditions */
|
|
res = *data;
|
|
clk_irq = res & 07;
|
|
apr_irq = (res >> 3) & 07;
|
|
if (res & 0000100)
|
|
nxm_flag = 0;
|
|
if (res & 0000200)
|
|
inout_fail = 0;
|
|
if (res & 0001000) {
|
|
clk_flg = 0;
|
|
clr_interrupt(4);
|
|
}
|
|
if (res & 0002000)
|
|
clk_en = 1;
|
|
if (res & 0004000)
|
|
clk_en = 0;
|
|
if (res & 0040000)
|
|
timer_irq = 1;
|
|
if (res & 0100000)
|
|
timer_irq = 0;
|
|
if (res & 0200000)
|
|
reset_all(1);
|
|
if (res & 0400000)
|
|
timer_flg = 0;
|
|
check_apr_irq();
|
|
sim_debug(DEBUG_CONI, &cpu_dev, "CONO APR %012llo\n", *data);
|
|
break;
|
|
|
|
case DATAO:
|
|
sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAO APR %012llo\n", *data);
|
|
break;
|
|
|
|
case DATAI:
|
|
/* Read switches */
|
|
*data = SW;
|
|
sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI APR %012llo\n", *data);
|
|
break;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if KA
|
|
/*
|
|
* Check if the last operation caused a APR IRQ to be generated.
|
|
*/
|
|
void check_apr_irq() {
|
|
if (apr_irq) {
|
|
int flg = 0;
|
|
clr_interrupt(0);
|
|
flg |= clk_en & clk_flg;
|
|
flg |= ((FLAGS & OVR) != 0) & ov_irq;
|
|
flg |= ((FLAGS & FLTOVR) != 0) & fov_irq;
|
|
flg |= nxm_flag | mem_prot | push_ovf;
|
|
if (flg)
|
|
set_interrupt(0, apr_irq);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* APR Device for KA10.
|
|
*/
|
|
t_stat dev_apr(uint32 dev, uint64 *data) {
|
|
uint64 res = 0;
|
|
switch(dev & 03) {
|
|
case CONI:
|
|
/* Read trap conditions */
|
|
res = apr_irq | (((FLAGS & OVR) != 0) << 3) | (ov_irq << 4) ;
|
|
res |= (((FLAGS & FLTOVR) != 0) << 6) | (fov_irq << 7) ;
|
|
res |= (clk_flg << 9) | (((uint64)clk_en) << 10) | (nxm_flag << 12);
|
|
res |= (mem_prot << 13) | (((FLAGS & USERIO) != 0) << 15);
|
|
res |= (push_ovf << 16);
|
|
*data = res;
|
|
sim_debug(DEBUG_CONI, &cpu_dev, "CONI APR %012llo\n", *data);
|
|
break;
|
|
|
|
case CONO:
|
|
/* Set trap conditions */
|
|
res = *data;
|
|
clk_irq = apr_irq = res & 07;
|
|
clr_interrupt(0);
|
|
clr_interrupt(4);
|
|
if (res & 010)
|
|
FLAGS &= ~OVR;
|
|
if (res & 020)
|
|
ov_irq = 1;
|
|
if (res & 040)
|
|
ov_irq = 0;
|
|
if (res & 0100)
|
|
FLAGS &= ~FLTOVR;
|
|
if (res & 0200)
|
|
fov_irq = 1;
|
|
if (res & 0400)
|
|
fov_irq = 0;
|
|
if (res & 01000)
|
|
clk_flg = 0;
|
|
if (res & 02000)
|
|
clk_en = 1;
|
|
if (res & 04000)
|
|
clk_en = 0;
|
|
if (res & 010000)
|
|
nxm_flag = 0;
|
|
if (res & 020000)
|
|
mem_prot = 0;
|
|
if (res & 0200000) {
|
|
reset_all(1);
|
|
clk_flg = ov_irq = fov_irq = nxm_flag = mem_prot = push_ovf = 0;
|
|
}
|
|
if (res & 0400000)
|
|
push_ovf = 0;
|
|
check_apr_irq();
|
|
sim_debug(DEBUG_CONI, &cpu_dev, "CONO APR %012llo\n", *data);
|
|
break;
|
|
|
|
case DATAO:
|
|
/* Set protection registers */
|
|
Rh = 0377 & (*data >> 1);
|
|
Rl = 0377 & (*data >> 10);
|
|
Pflag = 01 & (*data >> 18);
|
|
Ph = 0377 & (*data >> 19);
|
|
Pl = 0377 & (*data >> 28);
|
|
sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAO APR %012llo\n", *data);
|
|
break;
|
|
|
|
case DATAI:
|
|
/* Read switches */
|
|
*data = SW;
|
|
sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI APR %012llo\n", *data);
|
|
break;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* PI device for KA and KI
|
|
*/
|
|
t_stat dev_pi(uint32 dev, uint64 *data) {
|
|
uint64 res = 0;
|
|
switch(dev & 3) {
|
|
case CONO:
|
|
/* Set PI flags */
|
|
res = *data;
|
|
if (res & 010000) {
|
|
PIR = PIH = PIE = 0;
|
|
pi_enable = 0;
|
|
parity_irq = 0;
|
|
}
|
|
if (res & 0200)
|
|
pi_enable = 1;
|
|
if (res & 0400)
|
|
pi_enable = 0;
|
|
if (res & 01000)
|
|
PIE &= ~(*data & 0177);
|
|
if (res & 02000)
|
|
PIE |= (*data & 0177);
|
|
if (res & 04000) {
|
|
PIR |= (*data & 0177);
|
|
pi_pending = 1;
|
|
}
|
|
if (res & 040000)
|
|
parity_irq = 1;
|
|
if (res & 0100000)
|
|
parity_irq = 0;
|
|
sim_debug(DEBUG_CONI, &cpu_dev, "CONI PI %012llo\n", *data);
|
|
break;
|
|
|
|
case CONI:
|
|
res = PIE;
|
|
res |= (pi_enable << 7);
|
|
res |= (PIH << 8);
|
|
#if KI
|
|
res |= ((uint64)(PIR) << 18);
|
|
#endif
|
|
res |= (parity_irq << 15);
|
|
*data = res;
|
|
sim_debug(DEBUG_CONO, &cpu_dev, "CONO PI %012llo\n", *data);
|
|
break;
|
|
|
|
case DATAO:
|
|
/* Set lights */
|
|
case DATAI:
|
|
break;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/*
|
|
* Non existent device
|
|
*/
|
|
t_stat null_dev(uint32 dev, uint64 *data) {
|
|
switch(dev & 3) {
|
|
case CONI:
|
|
case DATAI:
|
|
*data = 0;
|
|
break;
|
|
|
|
case CONO:
|
|
case DATAO:
|
|
break;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
#if KI
|
|
/*
|
|
* Handle page lookup on KI10
|
|
*/
|
|
int page_lookup(int addr, int flag, int *loc, int wr, int cur_context) {
|
|
uint64 data;
|
|
int base = ub_ptr;
|
|
int page = addr >> 9;
|
|
int uf = (FLAGS & USER) != 0;
|
|
|
|
if (page_fault)
|
|
return 0;
|
|
|
|
/* If fetching byte data, use write access */
|
|
if (BYF5 && (IR & 06) == 6)
|
|
wr = 1;
|
|
|
|
wr |= modify;
|
|
|
|
if (flag)
|
|
uf = 0;
|
|
else if (xct_flag != 0 && !cur_context && !uf) {
|
|
if (((xct_flag & 2) != 0 && wr != 0) ||
|
|
((xct_flag & 1) != 0 && (wr == 0 || modify))) {
|
|
uf = (FLAGS & USERIO) != 0;
|
|
}
|
|
}
|
|
|
|
if (uf) {
|
|
if (small_user && (page & 0340) != 0) {
|
|
fault_data = (((uint64)(page))<<18) | ((uint64)(uf) << 27) | 020LL;
|
|
page_fault = 1;
|
|
fprintf(stderr, " %03o small fault\n\r", page);
|
|
return 0;
|
|
}
|
|
data = M[base + (page >> 1)];
|
|
} else {
|
|
/* If paging is not enabled, address is direct */
|
|
if (!page_enable) {
|
|
*loc = addr;
|
|
return 1;
|
|
}
|
|
/* Pages 340-377 via UBR */
|
|
if ((page & 0740) == 0340) {
|
|
page += 01000 - 0340;
|
|
/* Pages 400-777 via EBR */
|
|
} else if (page & 0400) {
|
|
base = eb_ptr;
|
|
} else {
|
|
if (!flag && ((FLAGS & PUBLIC) != 0)) {
|
|
/* Handle public violation */
|
|
fault_data = (((uint64)(page))<<18) | ((uint64)(uf) << 27) | 021LL;
|
|
private_page = 1;
|
|
fprintf(stderr, " public");
|
|
}
|
|
*loc = addr;
|
|
return 1;
|
|
}
|
|
}
|
|
data = M[base + (page >> 1)];
|
|
if ((page & 1) == 0)
|
|
data >>= 18;
|
|
data &= RMASK;
|
|
*loc = ((data & 017777) << 9) + (addr & 0777);
|
|
if (!flag && ((FLAGS & PUBLIC) != 0) && ((data & 0200000) == 0)) {
|
|
/* Handle public violation */
|
|
fault_data = (((uint64)(page))<<18) | ((uint64)(uf) << 27) | 021LL;
|
|
private_page = 1;
|
|
}
|
|
if (cur_context && ((data & 0200000) != 0))
|
|
FLAGS |= PUBLIC;
|
|
if ((data & LSIGN) == 0 || (wr & ((data & 0100000) == 0))) {
|
|
fault_data = ((((uint64)(addr))<<9) | ((uint64)(uf) << 27)) & LMASK;
|
|
fault_data |= (data & 0400000) ? 010LL : 0LL; /* A */
|
|
fault_data |= (data & 0100000) ? 004LL : 0LL; /* W */
|
|
fault_data |= (data & 0040000) ? 002LL : 0LL; /* S */
|
|
fault_data |= wr;
|
|
page_fault = 1;
|
|
fprintf(stderr, "xlat %06o %03o ", addr, page >> 1);
|
|
fprintf(stderr, " %06o %03o %012llo %o", base, page, data, uf);
|
|
fprintf(stderr, " -> %06llo wr=%o PC=%06o ", fault_data, wr, PC);
|
|
fprintf(stderr, " fault\n\r");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Register access on KI 10
|
|
*/
|
|
uint64 get_reg(int reg) {
|
|
if (FLAGS & USER)
|
|
return FM[fm_sel|(reg & 017)];
|
|
else
|
|
return FM[reg & 017];
|
|
}
|
|
|
|
void set_reg(int reg, uint64 value) {
|
|
if (FLAGS & USER)
|
|
FM[fm_sel|(reg & 017)] = value;
|
|
else
|
|
FM[reg & 017] = value;
|
|
}
|
|
|
|
/*
|
|
* Read a location directly from memory.
|
|
*
|
|
* Return of 0 if successful, 1 if there was an error.
|
|
*/
|
|
int Mem_read_nopage() {
|
|
if (AB < 020) {
|
|
MB = FM[AB];
|
|
} else {
|
|
sim_interval--;
|
|
if (AB >= (int)MEMSIZE) {
|
|
nxm_flag = 1;
|
|
set_interrupt(0, apr_irq);
|
|
return 1;
|
|
}
|
|
MB = M[AB];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a directly to a location in memory.
|
|
*
|
|
* Return of 0 if successful, 1 if there was an error.
|
|
*/
|
|
int Mem_write_nopage() {
|
|
|
|
if (AB < 020) {
|
|
FM[AB] = MB;
|
|
} else {
|
|
sim_interval--;
|
|
if (AB >= (int)MEMSIZE) {
|
|
nxm_flag = 1;
|
|
set_interrupt(0, apr_irq);
|
|
return 1;
|
|
}
|
|
M[AB] = MB;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
/*
|
|
* Translation logic for KA10
|
|
*/
|
|
int page_lookup(int addr, int flag, int *loc, int wr, int cur_context) {
|
|
if (!flag && (FLAGS & USER) != 0) {
|
|
if (addr <= ((Pl << 10) + 01777))
|
|
*loc = (AB + (Rl << 10)) & RMASK;
|
|
else if (cpu_unit.flags & UNIT_TWOSEG &&
|
|
(!Pflag & wr) == wr &&
|
|
(AB & 0400000) != 0 &&
|
|
(addr <= ((Ph << 10) + 01777)))
|
|
*loc = (AB + (Rh << 10)) & RMASK;
|
|
else {
|
|
mem_prot = 1;
|
|
set_interrupt(0, apr_irq);
|
|
return 0;
|
|
}
|
|
} else {
|
|
*loc = addr;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#define get_reg(reg) FM[(reg) & 017]
|
|
#define set_reg(reg, value) FM[(reg) & 017] = value
|
|
#endif
|
|
|
|
/*
|
|
* Read a location in memory.
|
|
*
|
|
* Return of 0 if successful, 1 if there was an error.
|
|
*/
|
|
int Mem_read(int flag, int cur_context) {
|
|
int addr;
|
|
|
|
if (AB < 020) {
|
|
#if KI | KL
|
|
if (FLAGS & USER) {
|
|
MB = get_reg(AB);
|
|
return 0;
|
|
} else {
|
|
if (!cur_context && ((xct_flag & 1) != 0)) {
|
|
if (FLAGS & USERIO) {
|
|
if (fm_sel == 0)
|
|
goto read;
|
|
MB = FM[fm_sel|AB];
|
|
return 0;
|
|
}
|
|
MB = M[ub_ptr + ac_stack + AB];
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
MB = get_reg(AB);
|
|
} else {
|
|
#if KI | KL
|
|
read:
|
|
#endif
|
|
sim_interval--;
|
|
if (!page_lookup(AB, flag, &addr, 0, cur_context))
|
|
return 1;
|
|
if (addr >= (int)MEMSIZE) {
|
|
nxm_flag = 1;
|
|
set_interrupt(0, apr_irq);
|
|
return 1;
|
|
}
|
|
MB = M[addr];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a location in memory.
|
|
*
|
|
* Return of 0 if successful, 1 if there was an error.
|
|
*/
|
|
int Mem_write(int flag, int cur_context) {
|
|
int addr;
|
|
|
|
if (AB < 020) {
|
|
#if KI | KL
|
|
if (FLAGS & USER) {
|
|
set_reg(AB, MB);
|
|
return 0;
|
|
} else {
|
|
if (!cur_context &&
|
|
(((xct_flag & 1) != 0 && modify) ||
|
|
(xct_flag & 2) != 0)) {
|
|
if (FLAGS & USERIO) {
|
|
if (fm_sel == 0)
|
|
goto write;
|
|
else
|
|
FM[fm_sel|AB] = MB;
|
|
} else {
|
|
M[ub_ptr + ac_stack + AB] = MB;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
set_reg(AB, MB);
|
|
} else {
|
|
#if KI | KL
|
|
write:
|
|
#endif
|
|
sim_interval--;
|
|
if (!page_lookup(AB, flag, &addr, 1, cur_context))
|
|
return 1;
|
|
#if KI | KL
|
|
if (private_page)
|
|
return 1;
|
|
#endif
|
|
if (addr >= (int)MEMSIZE) {
|
|
nxm_flag = 1;
|
|
set_interrupt(0, apr_irq);
|
|
return 1;
|
|
}
|
|
M[addr] = MB;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Function to determine number of leading zero bits in a work
|
|
*/
|
|
int nlzero(uint64 w) {
|
|
int n = 0;
|
|
if (w == 0) return 36;
|
|
if ((w & 00777777000000LL) == 0) { n += 18; w <<= 18; }
|
|
if ((w & 00777000000000LL) == 0) { n += 9; w <<= 9; }
|
|
if ((w & 00770000000000LL) == 0) { n += 6; w <<= 6; }
|
|
if ((w & 00700000000000LL) == 0) { n += 3; w <<= 3; }
|
|
if ((w & 00600000000000LL) == 0) { n ++; w <<= 1; }
|
|
if ((w & 00400000000000LL) == 0) { n ++; }
|
|
return n;
|
|
}
|
|
|
|
t_stat sim_instr (void)
|
|
{
|
|
t_stat reason;
|
|
int i_flags; /* Instruction mode flags */
|
|
int pi_rq; /* Interrupt request */
|
|
int pi_ov; /* Overflow during PI cycle */
|
|
int pi_cycle; /* Executing an interrupt */
|
|
int ind; /* Indirect bit */
|
|
int f_load_pc; /* Load AB from PC at start of instruction */
|
|
int f_inst_fetch; /* Fetch new instruction */
|
|
int f_pc_inh; /* Inhibit PC increment after instruction */
|
|
int nrf; /* Normalize flag */
|
|
int fxu_hold_set; /* Negitive exponent */
|
|
int sac_inh; /* Inihibit saving AC after instruction */
|
|
int f; /* Temporary variables */
|
|
int flag1;
|
|
int flag3;
|
|
uint32 IA;
|
|
|
|
/* Build device table */
|
|
if ((reason = build_dev_tab ()) != SCPE_OK) /* build, chk dib_tab */
|
|
return reason;
|
|
|
|
|
|
/* Main instruction fetch/decode loop: check clock queue, intr, trap, bkpt */
|
|
f_load_pc = 1;
|
|
f_inst_fetch = 1;
|
|
ind = 0;
|
|
uuo_cycle = 0;
|
|
pi_cycle = 0;
|
|
pi_rq = 0;
|
|
pi_ov = 0;
|
|
BYF5 = 0;
|
|
#if KI | KL
|
|
private_page = 0;
|
|
page_fault = 0;
|
|
#endif
|
|
|
|
while ( reason == 0) { /* loop until ABORT */
|
|
if (sim_interval <= 0) { /* check clock queue */
|
|
if ((reason = sim_process_event()) != SCPE_OK) {/* error? stop sim */
|
|
if (reason != SCPE_STEP || !BYF5)
|
|
return reason;
|
|
}
|
|
}
|
|
|
|
if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) {
|
|
reason = STOP_IBKPT;
|
|
break;
|
|
}
|
|
|
|
|
|
/* Normal instruction */
|
|
if (f_load_pc) {
|
|
AB = PC;
|
|
uuo_cycle = 0;
|
|
#if KI | KL
|
|
xct_flag = 0;
|
|
trap_flag = 0;
|
|
modify = 0;
|
|
#endif
|
|
}
|
|
|
|
if (f_inst_fetch) {
|
|
#if !(KI | KL)
|
|
fetch:
|
|
#endif
|
|
if (Mem_read(pi_cycle | uuo_cycle, 1))
|
|
goto last;
|
|
#if KI | KL
|
|
no_fetch:
|
|
#endif
|
|
IR = (MB >> 27) & 0777;
|
|
AC = (MB >> 23) & 017;
|
|
AD = MB; /* Save for historical sake */
|
|
IA = AB;
|
|
|
|
i_flags = opflags[IR];
|
|
BYF5 = 0;
|
|
}
|
|
|
|
/* Second half of byte instruction */
|
|
if (BYF5) {
|
|
i_flags = FCE;
|
|
AB = AR & RMASK;
|
|
}
|
|
|
|
#if KI | KL
|
|
/* Handle page fault and traps */
|
|
if (page_enable && trap_flag == 0 && (FLAGS & (TRP1|TRP2))) {
|
|
AB = 0420 + ((FLAGS & (TRP1|TRP2)) >> 2);
|
|
trap_flag = FLAGS & (TRP1|TRP2);
|
|
FLAGS &= ~(TRP1|TRP2);
|
|
f_pc_inh = 1;
|
|
pi_cycle = 1;
|
|
AB += (FLAGS & USER) ? ub_ptr : eb_ptr;
|
|
Mem_read_nopage();
|
|
goto no_fetch;
|
|
}
|
|
#endif
|
|
|
|
|
|
/* Handle indirection repeat until no longer indirect */
|
|
do {
|
|
if (pi_enable & !pi_cycle & pi_pending
|
|
#if KI | KL
|
|
& !trap_flag
|
|
#endif
|
|
) {
|
|
pi_rq = check_irq_level();
|
|
}
|
|
ind = (MB & 020000000) != 0;
|
|
AR = MB;
|
|
AB = MB & RMASK;
|
|
if (MB & 017000000) {
|
|
AR = MB = (AB + get_reg((MB >> 18) & 017)) & FMASK;
|
|
AB = MB & RMASK;
|
|
}
|
|
if (IR != 0254)
|
|
AR &= RMASK;
|
|
if (ind & !pi_rq)
|
|
if (Mem_read(pi_cycle | uuo_cycle, 1))
|
|
goto last;
|
|
/* Handle events during a indirect loop */
|
|
if (sim_interval-- <= 0) {
|
|
if ((reason = sim_process_event()) != SCPE_OK) {
|
|
if (reason != SCPE_STEP || !BYF5)
|
|
return reason;
|
|
}
|
|
}
|
|
} while (ind & !pi_rq);
|
|
|
|
/* If there is a interrupt handle it. */
|
|
if (pi_rq) {
|
|
set_pi_hold(); /* Hold off all lower interrupts */
|
|
pi_cycle = 1;
|
|
pi_rq = 0;
|
|
pi_hold = 0;
|
|
pi_ov = 0;
|
|
AB = 040 | (pi_enc << 1);
|
|
#if KI | KL
|
|
xct_flag = 0;
|
|
/*
|
|
* Scan through the devices and allow KI devices to have first
|
|
* hit at a given level.
|
|
*/
|
|
for (f = 0; sim_devices[f] != NULL; f++) {
|
|
DEVICE *dptr = sim_devices[f];
|
|
DIB *dibp = (DIB *) dptr->ctxt;
|
|
if (dibp) {
|
|
if (dibp->irq) { /* Check if KI device */
|
|
int dev = dibp->dev_num >> 2;
|
|
|
|
/* Check if this device actually posted IRQ */
|
|
if (dev_irq[dev] & (0200 >> pi_enc)) {
|
|
AB = dibp->irq(dev << 2, AB);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
AB |= eb_ptr;
|
|
Mem_read_nopage();
|
|
goto no_fetch;
|
|
#else
|
|
goto fetch;
|
|
#endif
|
|
}
|
|
|
|
/* Update history */
|
|
#if KI
|
|
// if (hst_lnt && PC > 020 && (FLAGS & USER) != 0) {
|
|
if (hst_lnt && (fm_sel || PC > 020) && (PC & 0777774) != 0777040 &&
|
|
(PC & 0777700) != 023700 && (PC != 0527154)) {
|
|
#else
|
|
if (hst_lnt && PC > 020 && (PC & 0777774) != 0472174 &&
|
|
(PC & 0777700) != 023700 && (PC != 0527154)) {
|
|
#endif
|
|
hst_p = hst_p + 1;
|
|
if (hst_p >= hst_lnt) {
|
|
hst_p = 0;
|
|
// reason = STOP_IBKPT;
|
|
}
|
|
hst[hst_p].pc = HIST_PC | ((BYF5)? (HIST_PC2|PC) : IA);
|
|
hst[hst_p].ea = AB;
|
|
hst[hst_p].ir = AD;
|
|
hst[hst_p].flags = (FLAGS << 5) |(clk_flg << 2) | (nxm_flag << 1)
|
|
#if KA
|
|
| (mem_prot << 4) | (push_ovf << 3)
|
|
#endif
|
|
;
|
|
hst[hst_p].ac = get_reg(AC);
|
|
}
|
|
|
|
|
|
fetch_opr:
|
|
/* Set up to execute instruction */
|
|
f_inst_fetch = 1;
|
|
f_load_pc = 1;
|
|
nrf = 0;
|
|
fxu_hold_set = 0;
|
|
sac_inh = 0;
|
|
#if KI | KL
|
|
modify = 0;
|
|
f_pc_inh = (trap_flag != 0);
|
|
#else
|
|
f_pc_inh = 0;
|
|
#endif
|
|
/* Load pseudo registers based on flags */
|
|
if (i_flags & (FCEPSE|FCE)) {
|
|
if (Mem_read(0, 0))
|
|
goto last;
|
|
#if KI | KL
|
|
modify = 1;
|
|
#endif
|
|
AR = MB;
|
|
}
|
|
|
|
if (i_flags & FAC) {
|
|
BR = AR;
|
|
AR = get_reg(AC);
|
|
}
|
|
|
|
if (i_flags & SWAR) {
|
|
AR = SWAP_AR;
|
|
}
|
|
|
|
if (i_flags & FBR) {
|
|
BR = get_reg(AC);
|
|
}
|
|
|
|
if (i_flags & FMB) {
|
|
BR = MB;
|
|
}
|
|
|
|
if (hst_lnt) {
|
|
hst[hst_p].mb = AR;
|
|
}
|
|
|
|
if (i_flags & FAC2) {
|
|
MQ = get_reg(AC + 1);
|
|
} else if (!BYF5) {
|
|
MQ = 0;
|
|
}
|
|
|
|
/* Process the instruction */
|
|
switch (IR) {
|
|
muuo:
|
|
case 0000: /* UUO */
|
|
case 0040: case 0041: case 0042: case 0043:
|
|
case 0044: case 0045: case 0046: case 0047:
|
|
case 0050: case 0051: case 0052: case 0053:
|
|
case 0054: case 0055: case 0056: case 0057:
|
|
case 0060: case 0061: case 0062: case 0063:
|
|
case 0064: case 0065: case 0066: case 0067:
|
|
case 0070: case 0071: case 0072: case 0073:
|
|
case 0074: case 0075: case 0076: case 0077:
|
|
|
|
/* MUUO */
|
|
|
|
#if KI | KL
|
|
case 0100: case 0101: case 0102: case 0103:
|
|
case 0104: case 0105: case 0106: case 0107:
|
|
case 0123:
|
|
case 0247: /* UUO */
|
|
/* unasign: */ /* Place holder for unassigned instructions on KI */
|
|
MB = ((uint64)(IR) << 27) | ((uint64)(AC) << 23) | (uint64)(AB);
|
|
AB = ub_ptr | 0424;
|
|
Mem_write_nopage();
|
|
AB |= 1;
|
|
MB = (FLAGS << 23) | ((PC + (trap_flag == 0)) & RMASK);
|
|
Mem_write_nopage();
|
|
FLAGS &= ~ (BYTI|ADRFLT|TRP1|TRP2);
|
|
AB = ub_ptr | 0430;
|
|
if (trap_flag != 0)
|
|
AB |= 1;
|
|
if (FLAGS & PUBLIC)
|
|
AB |= 2;
|
|
if (FLAGS & USER)
|
|
AB |= 4;
|
|
Mem_read_nopage();
|
|
FLAGS = (MB >> 23) & 017777;
|
|
/* If transistioning from user to executive adjust flags */
|
|
if ((FLAGS & USER) != 0 && (AB & 4) != 0) {
|
|
FLAGS |= USERIO;
|
|
if (AB & 2)
|
|
FLAGS |= OVR;
|
|
}
|
|
PC = MB & RMASK;
|
|
f_pc_inh = 1;
|
|
trap_flag = 0;
|
|
break;
|
|
#else
|
|
uuo_cycle = 1;
|
|
#endif
|
|
|
|
/* LUUO */
|
|
case 0001: case 0002: case 0003:
|
|
case 0004: case 0005: case 0006: case 0007:
|
|
case 0010: case 0011: case 0012: case 0013:
|
|
case 0014: case 0015: case 0016: case 0017:
|
|
case 0020: case 0021: case 0022: case 0023:
|
|
case 0024: case 0025: case 0026: case 0027:
|
|
case 0030: case 0031: case 0032: case 0033:
|
|
case 0034: case 0035: case 0036: case 0037:
|
|
MB = ((uint64)(IR) << 27) | ((uint64)(AC) << 23) | (uint64)(AB);
|
|
#if KI | KL
|
|
if ((FLAGS & USER) == 0) {
|
|
AB = eb_ptr + 040;
|
|
Mem_write_nopage();
|
|
AB += 1;
|
|
Mem_read_nopage();
|
|
uuo_cycle = 1;
|
|
goto no_fetch;
|
|
}
|
|
#endif
|
|
AB = 040;
|
|
Mem_write(uuo_cycle, 1);
|
|
AB += 1;
|
|
f_load_pc = 0;
|
|
f_pc_inh = 1;
|
|
break;
|
|
|
|
#if KI | KL
|
|
|
|
case 0110: /* DFAD */
|
|
case 0111: /* DFSB */
|
|
/* On Load AR,MQ has memory operand */
|
|
/* AR,MQ = AC BR,MB = mem */
|
|
/* AR High */
|
|
AB = (AB + 1) & RMASK;
|
|
if (Mem_read(0, 0))
|
|
goto last;
|
|
SC = GET_EXPO(BR);
|
|
SMEAR_SIGN(BR);
|
|
BR <<= 35;
|
|
BR |= MB & CMASK;
|
|
FE = GET_EXPO(AR);
|
|
SMEAR_SIGN(AR);
|
|
AR <<= 35;
|
|
AR |= (MQ & CMASK);
|
|
if (IR & 01) {
|
|
BR = (DFMASK ^ BR) + 1;
|
|
}
|
|
SCAD = SC - FE;
|
|
if (SCAD < 0) {
|
|
AD = AR;
|
|
AR = BR;
|
|
BR = AD;
|
|
SCAD = FE;
|
|
FE = SC;
|
|
SC = SCAD;
|
|
SCAD = SC - FE;
|
|
}
|
|
if (SCAD > 0) {
|
|
while (SCAD > 0) {
|
|
AR = (AR & (DSMASK|DNMASK)) | (AR >> 1);
|
|
SCAD--;
|
|
}
|
|
}
|
|
AD = (AR + BR);
|
|
flag1 = 0;
|
|
if ((AR & DSMASK) ^ (BR & DSMASK)) {
|
|
if (AD & DSMASK) {
|
|
AD = (DCMASK ^ AD) + 1;
|
|
flag1 = 1;
|
|
}
|
|
} else {
|
|
if (AR & DSMASK) {
|
|
AD = (DCMASK ^ AD) + 1;
|
|
flag1 = 1;
|
|
}
|
|
if (AD & DNMASK) {
|
|
AD ++;
|
|
AD = (AD & DSMASK) | (AD >> 1);
|
|
SC++;
|
|
}
|
|
}
|
|
AR = AD;
|
|
|
|
while (AR != 0 && ((AR & DXMASK) == 0)) {
|
|
AR <<= 1;
|
|
SC--;
|
|
fxu_hold_set = 1;
|
|
}
|
|
dpnorm:
|
|
if (AR == 0)
|
|
flag1 = 0;
|
|
ARX = AR & CMASK;
|
|
AR >>= 35;
|
|
AR &= MMASK;
|
|
if (flag1) {
|
|
ARX = (ARX ^ CMASK) + 1;
|
|
AR = (AR ^ MMASK) + ((ARX & SMASK) != 0);
|
|
ARX &= CMASK;
|
|
AR &= MMASK;
|
|
AR |= SMASK;
|
|
}
|
|
if (((SC & 0400) != 0) && !pi_cycle) {
|
|
FLAGS |= OVR|FLTOVR|TRP1;
|
|
if (fxu_hold_set) {
|
|
FLAGS |= FLTUND;
|
|
}
|
|
}
|
|
SCAD = SC ^ ((AR & SMASK) ? 0377 : 0);
|
|
AR &= SMASK|MMASK;
|
|
if (AR != 0)
|
|
AR |= ((uint64)(SCAD & 0377)) << 27;
|
|
|
|
MQ = ARX;
|
|
break;
|
|
|
|
case 0112: /* DFMP */
|
|
/* On Load AR,MQ has memory operand */
|
|
/* AR,MQ = AC BR,MB = mem */
|
|
/* AR High */
|
|
AB = (AB + 1) & RMASK;
|
|
if (Mem_read(0, 0))
|
|
goto last;
|
|
SC = GET_EXPO(AR);
|
|
SMEAR_SIGN(AR);
|
|
AR <<= 35;
|
|
AR |= (MQ & CMASK);
|
|
FE = GET_EXPO(BR);
|
|
SMEAR_SIGN(BR);
|
|
BR <<= 35;
|
|
BR |= MB & CMASK;
|
|
flag1 = 0;
|
|
if (AR & DSMASK) {
|
|
AR = (DFMASK ^ AR) + 1;
|
|
flag1 = 1;
|
|
}
|
|
if (BR & DSMASK) {
|
|
BR = (DFMASK ^ BR) + 1;
|
|
flag1 = !flag1;
|
|
}
|
|
SC = SC + FE - 0201;
|
|
if (SC < 0)
|
|
fxu_hold_set = 1;
|
|
AD = (AR >> 30) * (BR >> 30);
|
|
AD += ((AR >> 30) * (BR & PMASK)) >> 30;
|
|
AD += ((AR & PMASK) * (BR >> 30)) >> 30;
|
|
AR = AD >> 1;
|
|
if (AR & DNMASK) {
|
|
AR >>= 1;
|
|
SC++;
|
|
}
|
|
goto dpnorm;
|
|
|
|
case 0113: /* DFDV */
|
|
/* On Load AR,MQ has memory operand */
|
|
/* AR,MQ = AC BR,MB = mem */
|
|
/* AR High */
|
|
AB = (AB + 1) & RMASK;
|
|
if (Mem_read(0, 0))
|
|
goto last;
|
|
SC = GET_EXPO(AR);
|
|
SMEAR_SIGN(AR);
|
|
AR <<= 35;
|
|
AR |= (MQ & CMASK);
|
|
FE = GET_EXPO(BR);
|
|
SMEAR_SIGN(BR);
|
|
BR <<= 35;
|
|
BR |= MB & CMASK;
|
|
flag1 = 0;
|
|
if (AR & DSMASK) {
|
|
AR = (DFMASK ^ AR) + 1;
|
|
flag1 = 1;
|
|
}
|
|
if (BR & DSMASK) {
|
|
BR = (DFMASK ^ BR) + 1;
|
|
flag1 = !flag1;
|
|
}
|
|
if (AR >= (BR << 1)) {
|
|
if (!pi_cycle)
|
|
FLAGS |= OVR|FLTOVR|NODIV|TRP1;
|
|
AR = 0; /* For clean history */
|
|
sac_inh = 1;
|
|
break;
|
|
}
|
|
|
|
if (AR == 0) {
|
|
sac_inh = 1;
|
|
break;
|
|
}
|
|
SC = SC - FE + 0201;
|
|
if (AR < BR) {
|
|
AR <<= 1;
|
|
SC--;
|
|
}
|
|
if (SC < 0)
|
|
fxu_hold_set = 1;
|
|
AD = 0;
|
|
for (FE = 0; FE < 62; FE++) {
|
|
AD <<= 1;
|
|
if (AR >= BR) {
|
|
AR = AR - BR;
|
|
AD |= 1;
|
|
}
|
|
AR <<= 1;
|
|
}
|
|
AR = AD;
|
|
goto dpnorm;
|
|
|
|
case 0114: /* DADD */
|
|
case 0115: /* DSUB */
|
|
case 0116: /* DMUL */
|
|
case 0117: /* DDIV */
|
|
goto unasign;
|
|
|
|
case 0120: /* DMOVE */
|
|
AB = (AB + 1) & RMASK;
|
|
modify = 0;
|
|
if (Mem_read(0, 0))
|
|
goto last;
|
|
MQ = MB;
|
|
break;
|
|
|
|
case 0121: /* DMOVN */
|
|
AB = (AB + 1) & RMASK;
|
|
modify = 0;
|
|
if (Mem_read(0, 0))
|
|
goto last;
|
|
MQ = ((MB & CMASK) ^ CMASK) + 1; /* Low */
|
|
/* High */
|
|
AR = (CM(AR) + ((MQ & SMASK) != 0)) & FMASK;
|
|
MQ &= CMASK;
|
|
break;
|
|
|
|
case 0124: /* DMOVEM */
|
|
/* Handle each half as seperate instruction */
|
|
if ((FLAGS & BYTI) == 0) {
|
|
MB = AR;
|
|
if (Mem_write(0, 0))
|
|
goto last;
|
|
FLAGS |= BYTI;
|
|
#if KI /* KL does this in one shot */
|
|
f_pc_inh = 1;
|
|
break;
|
|
#endif
|
|
}
|
|
if ((FLAGS & BYTI)) {
|
|
AB = (AB + 1) & RMASK;
|
|
MB = MQ;
|
|
if (Mem_write(0, 0))
|
|
goto last;
|
|
FLAGS &= ~BYTI;
|
|
}
|
|
break;
|
|
|
|
case 0125: /* DMOVNM */
|
|
/* Handle each half as seperate instruction */
|
|
if ((FLAGS & BYTI) == 0) {
|
|
BR = AR = CM(AR);
|
|
BR = (BR + 1);
|
|
MQ = (((MQ & CMASK) ^ CMASK) + 1);
|
|
if (MQ & SMASK)
|
|
AR = BR;
|
|
AR &= FMASK;
|
|
MB = AR;
|
|
if (Mem_write(0, 0))
|
|
goto last;
|
|
FLAGS |= BYTI;
|
|
#if KI
|
|
f_pc_inh = 1;
|
|
break;
|
|
#endif
|
|
}
|
|
if ((FLAGS & BYTI)) {
|
|
MQ = (CM(MQ) + 1) & CMASK;
|
|
AB = (AB + 1) & RMASK;
|
|
MB = MQ;
|
|
if (Mem_write(0, 0))
|
|
goto last;
|
|
FLAGS &= ~BYTI;
|
|
}
|
|
break;
|
|
|
|
case 0122: /* FIX */
|
|
case 0126: /* FIXR */
|
|
MQ = 0;
|
|
SC = ((((AR & SMASK) ? 0377 : 0 )
|
|
^ ((AR >> 27) & 0377)) + 0600) & 0777;
|
|
flag1 = 0;
|
|
if ((AR & SMASK) != 0) {
|
|
AR ^= MMASK;
|
|
AR++;
|
|
AR &= MMASK;
|
|
flag1 = 1;
|
|
} else {
|
|
AR &= MMASK;
|
|
}
|
|
SC -= 27;
|
|
SC &= 0777;
|
|
if (SC < 9) {
|
|
/* 0 < N < 8 */
|
|
AR = (AR << SC) & FMASK;
|
|
} else if ((SC & 0400) != 0) {
|
|
/* -27 < N < 0 */
|
|
SC = 01000 - SC;
|
|
MQ = (AR << (36 - SC)) - flag1 ;
|
|
AR = (AR >> SC);
|
|
if ((IR & 04) && (MQ & SMASK) != 0)
|
|
AR ++;
|
|
} else {
|
|
if (!pi_cycle)
|
|
FLAGS |= OVR|TRP1; /* OV & T1 */
|
|
sac_inh = 1;
|
|
}
|
|
if (flag1)
|
|
AR = (CM(AR) + 1) & FMASK;
|
|
break;
|
|
|
|
case 0127: /* FLTR */
|
|
if (AR & SMASK) {
|
|
flag1 = 1;
|
|
AR = (CM(AR) + 1) & CMASK;
|
|
} else
|
|
flag1 = 0;
|
|
AR <<= 19;
|
|
SC = 163;
|
|
goto fnorm;
|
|
#else
|
|
/* MUUO */
|
|
case 0100: case 0101: case 0102: case 0103:
|
|
case 0104: case 0105: case 0106: case 0107:
|
|
case 0110: case 0111: case 0112: case 0113:
|
|
case 0114: case 0115: case 0116: case 0117:
|
|
case 0120: case 0121: case 0122: case 0123:
|
|
case 0124: case 0125: case 0126: case 0127:
|
|
case 0247: /* UUO */
|
|
unasign:
|
|
MB = ((uint64)(IR) << 27) | ((uint64)(AC) << 23) | (uint64)(AB);
|
|
AB = 060;
|
|
uuo_cycle = 1;
|
|
Mem_write(uuo_cycle, 0);
|
|
AB += 1;
|
|
f_load_pc = 0;
|
|
f_pc_inh = 1;
|
|
break;
|
|
#endif
|
|
|
|
case 0133: /* IBP/ADJBP */
|
|
case 0134: /* ILDB */
|
|
case 0136: /* IDPB */
|
|
if ((FLAGS & BYTI) == 0) { /* BYF6 */
|
|
#if KI | KL
|
|
modify = 1;
|
|
#endif
|
|
if (Mem_read(0, 1))
|
|
goto last;
|
|
AR = MB;
|
|
SC = (AR >> 24) & 077;
|
|
SCAD = (((AR >> 30) & 077) + (0777 ^ SC) + 1) & 0777;
|
|
if (SCAD & 0400) {
|
|
SC = ((0777 ^ ((AR >> 24) & 077)) + 044 + 1) & 0777;
|
|
#if KI | KL
|
|
AR = (AR & LMASK) | ((AR + 1) & RMASK);
|
|
#else
|
|
AR = (AR + 1) & FMASK;
|
|
#endif
|
|
} else
|
|
SC = SCAD;
|
|
AR &= PMASK;
|
|
AR |= (uint64)(SC & 077) << 30;
|
|
MB = AR;
|
|
if (Mem_write(0, 1))
|
|
goto last;
|
|
if ((IR & 04) == 0)
|
|
break;
|
|
}
|
|
|
|
case 0135:/* LDB */
|
|
case 0137:/* DPB */
|
|
if (((FLAGS & BYTI) == 0) | !BYF5) {
|
|
if (Mem_read(0, 1))
|
|
goto last;
|
|
AR = MB;
|
|
SC = (AR >> 30) & 077;
|
|
MQ = (uint64)(1) << ( 077 & (AR >> 24));
|
|
MQ -= 1;
|
|
SC = ((0777 ^ SC) + 1) & 0777;
|
|
f_load_pc = 0;
|
|
f_inst_fetch = 0;
|
|
f_pc_inh = 1;
|
|
FLAGS |= BYTI; /* BYF6 */
|
|
BYF5 = 1;
|
|
break;
|
|
}
|
|
if ((IR & 06) == 4) {
|
|
AR = MB;
|
|
while(SC != 0) {
|
|
AR >>= 1;
|
|
SC = (SC + 1) & 0777;
|
|
}
|
|
AR &= MQ;
|
|
set_reg(AC, AR);
|
|
} else {
|
|
BR = MB;
|
|
AR = get_reg(AC) & MQ;
|
|
while(SC != 0) {
|
|
AR <<= 1;
|
|
MQ <<= 1;
|
|
SC = (SC + 1) & 0777;
|
|
}
|
|
BR &= CM(MQ);
|
|
AR &= FMASK;
|
|
BR |= AR & MQ;
|
|
MB = BR;
|
|
Mem_write(0, 0);
|
|
}
|
|
FLAGS &= ~BYTI; /* BYF6 */
|
|
BYF5 = 0;
|
|
break;
|
|
|
|
#if !PDP6
|
|
case 0131:/* DFN */
|
|
AD = (CM(BR) + 1) & FMASK;
|
|
SC = (BR >> 27) & 0777;
|
|
BR = AR;
|
|
AR = AD;
|
|
AD = (CM(BR) + ((AD & MANT) == 0)) & FMASK;
|
|
AR &= MANT;
|
|
AR |= ((uint64)(SC & 0777)) << 27;
|
|
BR = AR;
|
|
AR = AD;
|
|
MB = BR;
|
|
if (Mem_write(0, 0))
|
|
goto last;
|
|
break;
|
|
#endif
|
|
|
|
case 0132:/* FSC */
|
|
SC = ((AB & LSIGN) ? 0400 : 0) | (AB & 0377);
|
|
SCAD = GET_EXPO(AR);
|
|
SC = (SCAD + SC) & 0777;
|
|
|
|
if (AR & SMASK) {
|
|
AR = CM(AR) + 1;
|
|
flag1 = 1;
|
|
} else {
|
|
flag1 = 0;
|
|
}
|
|
AR &= MMASK;
|
|
if (AR != 0) {
|
|
if ((AR & 00000777770000LL) == 0) { SC -= 12; AR <<= 12; }
|
|
if ((AR & 00000777000000LL) == 0) { SC -= 6; AR <<= 6; }
|
|
if ((AR & 00000740000000LL) == 0) { SC -= 4; AR <<= 4; }
|
|
if ((AR & 00000600000000LL) == 0) { SC -= 2; AR <<= 2; }
|
|
if ((AR & 00000400000000LL) == 0) { SC -= 1; AR <<= 1; }
|
|
} else if (flag1) {
|
|
AR = BIT9;
|
|
SC++;
|
|
}
|
|
if (((SC & 0400) != 0) ^ ((SC & 0200) != 0))
|
|
fxu_hold_set = 1;
|
|
if ((SC & 0400) != 0 && !pi_cycle) {
|
|
FLAGS |= OVR|FLTOVR|TRP1;
|
|
if (!fxu_hold_set)
|
|
FLAGS |= FLTUND;
|
|
check_apr_irq();
|
|
}
|
|
if (flag1) {
|
|
AR = SMASK | ((CM(AR) + 1) & MMASK);
|
|
SC ^= 0377;
|
|
} else if (AR == 0)
|
|
SC = 0;
|
|
AR |= ((uint64)((SC) & 0377)) << 27;
|
|
break;
|
|
|
|
|
|
case 0150: /* FSB */
|
|
case 0151: /* FSBL */
|
|
case 0152: /* FSBM */
|
|
case 0153: /* FSBB */
|
|
case 0154: /* FSBR */
|
|
case 0155: /* FSBRI */
|
|
case 0156: /* FSBRM */
|
|
case 0157: /* FSBRB */
|
|
AD = (CM(AR) + 1) & FMASK;
|
|
AR = BR;
|
|
BR = AD;
|
|
|
|
case 0130: /* UFA */
|
|
case 0140: /* FAD */
|
|
case 0141: /* FADL */
|
|
case 0142: /* FADM */
|
|
case 0143: /* FADB */
|
|
case 0144: /* FADR */
|
|
case 0145: /* FADRI */
|
|
case 0146: /* FADRM */
|
|
case 0147: /* FADRB */
|
|
SC = ((BR >> 27) & 0777);
|
|
if ((BR & SMASK) == (AR & SMASK)) {
|
|
SCAD = SC + (((AR >> 27) & 0777) ^ 0777) + 1;
|
|
} else {
|
|
SCAD = SC + ((AR >> 27) & 0777);
|
|
}
|
|
SCAD &= 0777;
|
|
if (((BR & SMASK) != 0) == ((SCAD & 0400) != 0)) {
|
|
AD = AR;
|
|
AR = BR;
|
|
BR = AD;
|
|
}
|
|
if ((SCAD & 0400) == 0) {
|
|
if ((AR & SMASK) == (BR & SMASK))
|
|
SCAD = ((SCAD ^ 0777) + 1) & 0777;
|
|
else
|
|
SCAD = (SCAD ^ 0777);
|
|
} else {
|
|
if ((AR & SMASK) != (BR & SMASK))
|
|
SCAD = (SCAD + 1) & 0777;
|
|
}
|
|
|
|
/* Get exponent */
|
|
SC = GET_EXPO(AR);
|
|
/* Smear the signs */
|
|
SMEAR_SIGN(BR);
|
|
SMEAR_SIGN(AR);
|
|
AR <<= 27;
|
|
BR <<= 27;
|
|
if (SCAD & 0400) {
|
|
SCAD = 01000 - SCAD;
|
|
if (SCAD < 28) {
|
|
AD = (BR & (SMASK<<27))? (FMASK<<27|MMASK) : 0;
|
|
BR = (BR >> SCAD) | (AD << (54 - SCAD));
|
|
} else {
|
|
BR = 0;
|
|
}
|
|
}
|
|
/* Do the addition now */
|
|
AR = (AR + BR);
|
|
|
|
/* Set flag1 to sign and make positive */
|
|
if (AR & FPSMASK) {
|
|
AR = (AR ^ FPFMASK) + 1;
|
|
flag1 = 1;
|
|
} else {
|
|
flag1 = 0;
|
|
}
|
|
fnorm:
|
|
if (AR != 0) {
|
|
fxnorm:
|
|
if ((AR & FPNMASK) != 0) { SC += 1; AR >>= 1; }
|
|
if (((SC & 0400) != 0) ^ ((SC & 0200) != 0))
|
|
fxu_hold_set = 1;
|
|
if (IR != 0130) { /* !UFA */
|
|
if ((AR & 00777777777000000000LL) == 0) { SC -= 27; AR <<= 27; }
|
|
if ((AR & 00777760000000000000LL) == 0) { SC -= 14; AR <<= 14; }
|
|
if ((AR & 00777000000000000000LL) == 0) { SC -= 9; AR <<= 9; }
|
|
if ((AR & 00770000000000000000LL) == 0) { SC -= 6; AR <<= 6; }
|
|
if ((AR & 00740000000000000000LL) == 0) { SC -= 4; AR <<= 4; }
|
|
if ((AR & 00600000000000000000LL) == 0) { SC -= 2; AR <<= 2; }
|
|
if ((AR & 00400000000000000000LL) == 0) { SC -= 1; AR <<= 1; }
|
|
if (!nrf && !flag1 &&
|
|
((IR & 04) != 0) && ((AR & BIT9) != 0)) {
|
|
AR += BIT8;
|
|
nrf = 1;
|
|
goto fxnorm;
|
|
}
|
|
}
|
|
if (flag1) {
|
|
AR = (AR ^ FPCMASK) + 1;
|
|
}
|
|
MQ = AR & MMASK;
|
|
AR >>= 27;
|
|
if (flag1) {
|
|
AR |= SMASK;
|
|
MQ |= SMASK;
|
|
}
|
|
} else if (flag1) {
|
|
AR = BIT9 | SMASK;
|
|
MQ = SMASK;
|
|
SC++;
|
|
} else {
|
|
AR = MQ = 0;
|
|
SC = 0;
|
|
}
|
|
if (((SC & 0400) != 0) && !pi_cycle) {
|
|
FLAGS |= OVR|FLTOVR|TRP1;
|
|
if (!fxu_hold_set) {
|
|
FLAGS |= FLTUND;
|
|
}
|
|
check_apr_irq();
|
|
}
|
|
SCAD = SC ^ ((AR & SMASK) ? 0377 : 0);
|
|
AR &= SMASK|MMASK;
|
|
AR |= ((uint64)(SCAD & 0377)) << 27;
|
|
/* FADL FSBL FMPL */
|
|
if ((IR & 07) == 1) {
|
|
SC = (SC + (0777 ^ 26)) & 0777;
|
|
if (MQ != 0) {
|
|
MQ &= MMASK;
|
|
SC ^= (SC & SMASK) ? 0377 : 0;
|
|
MQ |= ((uint64)(SC & 0377)) << 27;
|
|
}
|
|
}
|
|
|
|
/* Handle UFA */
|
|
if (IR == 0130) {
|
|
set_reg(AC + 1, AR);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 0160: /* FMP */
|
|
case 0161: /* FMPL */
|
|
case 0162: /* FMPM */
|
|
case 0163: /* FMPB */
|
|
case 0164: /* FMPR */
|
|
case 0165: /* FMPRI */
|
|
case 0166: /* FMPRM */
|
|
case 0167: /* FMPRB */
|
|
/* Compute exponent */
|
|
SC = (((BR & SMASK) ? 0777 : 0) ^ (BR >> 27)) & 0777;
|
|
SC += (((AR & SMASK) ? 0777 : 0) ^ (AR >> 27)) & 0777;
|
|
SC += 0600;
|
|
SC &= 0777;
|
|
/* Make positive and compute result sign */
|
|
flag1 = 0;
|
|
if (AR & SMASK) {
|
|
AR = CM(AR) + 1;
|
|
flag1 = 1;
|
|
}
|
|
if (BR & SMASK) {
|
|
BR = CM(BR) + 1;
|
|
flag1 = !flag1;
|
|
}
|
|
AR &= MMASK;
|
|
BR &= MMASK;
|
|
AR = (AR * BR);
|
|
goto fnorm;
|
|
|
|
case 0170: /* FDV */
|
|
case 0172: /* FDVM */
|
|
case 0173: /* FDVB */
|
|
case 0174: /* FDVR */
|
|
case 0175: /* FDVRI */
|
|
case 0176: /* FDVRM */
|
|
case 0177: /* FDVRB */
|
|
flag1 = 0;
|
|
SC = (int)((((BR & SMASK) ? 0777 : 0) ^ (BR >> 27)) & 0777);
|
|
SC += (int)((((AR & SMASK) ? 0 : 0777) ^ (AR >> 27)) & 0777);
|
|
SC = (SC + 0201) & 0777;
|
|
if (BR & SMASK) {
|
|
BR = CM(BR) + 1;
|
|
flag1 = 1;
|
|
}
|
|
if (AR & SMASK) {
|
|
AR = CM(AR) + 1;
|
|
flag1 = !flag1;
|
|
}
|
|
/* Clear exponents */
|
|
AR &= MMASK;
|
|
BR &= MMASK;
|
|
/* Check if we need to fix things */
|
|
if (BR >= (AR << 1)) {
|
|
if (!pi_cycle)
|
|
FLAGS |= OVR|NODIV|FLTOVR|TRP1;
|
|
check_apr_irq();
|
|
sac_inh = 1;
|
|
break; /* Done */
|
|
}
|
|
BR = (BR << 27) + MQ;
|
|
MB = AR;
|
|
AR = BR / AR;
|
|
if (AR != 0) {
|
|
if (IR & 04) {
|
|
AR ++;
|
|
}
|
|
if ((AR & BIT8) != 0) {
|
|
SC += 1;
|
|
AR >>= 1;
|
|
}
|
|
if (SC >= 0600)
|
|
fxu_hold_set = 1;
|
|
if (flag1) {
|
|
AR = (AR ^ MMASK) + 1;
|
|
AR |= SMASK;
|
|
}
|
|
} else if (flag1) {
|
|
AR = SMASK | BIT9;
|
|
SC++;
|
|
} else {
|
|
AR = 0;
|
|
SC = 0;
|
|
}
|
|
if (((SC & 0400) != 0) && !pi_cycle) {
|
|
FLAGS |= OVR|FLTOVR|TRP1;
|
|
if (!fxu_hold_set) {
|
|
FLAGS |= FLTUND;
|
|
}
|
|
check_apr_irq();
|
|
}
|
|
SCAD = SC ^ ((AR & SMASK) ? 0377 : 0);
|
|
AR &= SMASK|MMASK;
|
|
AR |= ((uint64)(SCAD & 0377)) << 27;
|
|
break;
|
|
|
|
case 0171: /* FDVL */
|
|
flag1 = 0;
|
|
SC = (int)((((BR & SMASK) ? 0777 : 0) ^ (BR >> 27)) & 0777);
|
|
SC += (int)((((AR & SMASK) ? 0 : 0777) ^ (AR >> 27)) & 0777);
|
|
SC = (SC + 0201) & 0777;
|
|
FE = (int)((((BR & SMASK) ? 0777 : 0) ^ (BR >> 27)) & 0777) - 26;
|
|
if (BR & SMASK) {
|
|
MQ = (CM(MQ) + 1) & MMASK;
|
|
BR = CM(BR);
|
|
if (MQ == 0)
|
|
BR = BR + 1;
|
|
flag1 = 1;
|
|
}
|
|
MQ &= MMASK;
|
|
if (AR & SMASK) {
|
|
AR = CM(AR) + 1;
|
|
flag1 = !flag1;
|
|
}
|
|
/* Clear exponents */
|
|
AR &= MMASK;
|
|
BR &= MMASK;
|
|
/* Check if we need to fix things */
|
|
if (BR >= (AR << 1)) {
|
|
if (!pi_cycle)
|
|
FLAGS |= OVR|NODIV|FLTOVR|TRP1;
|
|
check_apr_irq();
|
|
sac_inh = 1;
|
|
break; /* Done */
|
|
}
|
|
BR = (BR << 27) + MQ;
|
|
MB = AR;
|
|
AR <<= 27;
|
|
AD = 0;
|
|
if (BR < AR) {
|
|
BR <<= 1;
|
|
SC--;
|
|
}
|
|
for (SCAD = 0; SCAD < 27; SCAD++) {
|
|
AD <<= 1;
|
|
if (BR >= AR) {
|
|
BR = BR - AR;
|
|
AD |= 1;
|
|
}
|
|
BR <<= 1;
|
|
}
|
|
MQ = BR >> 28;
|
|
AR = AD;
|
|
SC++;
|
|
if (AR != 0) {
|
|
if ((AR & BIT8) != 0) {
|
|
SC += 1;
|
|
AR >>= 1;
|
|
}
|
|
if (SC >= 0600)
|
|
fxu_hold_set = 1;
|
|
if (flag1) {
|
|
AR = (AR ^ MMASK) + 1;
|
|
AR |= SMASK;
|
|
}
|
|
} else if (flag1) {
|
|
AR = SMASK | BIT9;
|
|
SC++;
|
|
} else {
|
|
AR = 0;
|
|
SC = 0;
|
|
}
|
|
if (((SC & 0400) != 0) && !pi_cycle) {
|
|
FLAGS |= OVR|FLTOVR|TRP1;
|
|
if (!fxu_hold_set) {
|
|
FLAGS |= FLTUND;
|
|
}
|
|
check_apr_irq();
|
|
}
|
|
SCAD = SC ^ ((AR & SMASK) ? 0377 : 0);
|
|
AR &= SMASK|MMASK;
|
|
AR |= ((uint64)(SCAD & 0377)) << 27;
|
|
|
|
if (MQ != 0) {
|
|
MQ &= MMASK;
|
|
if (SC & 0400) {
|
|
FE--;
|
|
}
|
|
FE ^= (AR & SMASK) ? 0377 : 0;
|
|
MQ |= ((uint64)(FE & 0377)) << 27;
|
|
}
|
|
break;
|
|
|
|
/* FWT */
|
|
case 0200: /* MOVE */
|
|
case 0201: /* MOVEI */
|
|
case 0202: /* MOVEM */
|
|
case 0203: /* MOVES */
|
|
case 0204: /* MOVS */
|
|
case 0205: /* MOVSI */
|
|
case 0206: /* MOVSM */
|
|
case 0207: /* MOVSS */
|
|
break;
|
|
|
|
case 0214: /* MOVM */
|
|
case 0215: /* MOVMI */
|
|
case 0216: /* MOVMM */
|
|
case 0217: /* MOVMS */
|
|
if ((AR & SMASK) == 0)
|
|
break;
|
|
|
|
case 0210: /* MOVN */
|
|
case 0211: /* MOVNI */
|
|
case 0212: /* MOVNM */
|
|
case 0213: /* MOVNS */
|
|
flag1 = flag3 = 0;
|
|
FLAGS &= 01777;
|
|
if ((((AR & CMASK) ^ CMASK) + 1) & SMASK) {
|
|
FLAGS |= CRY1;
|
|
flag1 = 1;
|
|
}
|
|
AD = CM(AR) + 1;
|
|
if (AD & C1) {
|
|
FLAGS |= CRY0;
|
|
flag3 = 1;
|
|
}
|
|
if (flag1 != flag3 && !pi_cycle) {
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
#if KI | KL
|
|
if (AR == SMASK && !pi_cycle)
|
|
FLAGS |= TRP1;
|
|
#endif
|
|
AR = AD & FMASK;
|
|
break;
|
|
|
|
case 0220: /* IMUL */
|
|
case 0221: /* IMULI */
|
|
case 0222: /* IMULM */
|
|
case 0223: /* IMULB */
|
|
case 0224: /* MUL */
|
|
case 0225: /* MULI */
|
|
case 0226: /* MULM */
|
|
case 0227: /* MULB */
|
|
flag3 = 0;
|
|
if (AR & SMASK) {
|
|
AR = (CM(AR) + 1) & FMASK;
|
|
flag3 = 1;
|
|
}
|
|
if (BR & SMASK) {
|
|
BR = (CM(BR) + 1) & FMASK;
|
|
flag3 = !flag3;
|
|
}
|
|
|
|
if ((AR == 0) || (BR == 0)) {
|
|
AR = MQ = 0;
|
|
break;
|
|
}
|
|
#if KA
|
|
if (BR == SMASK) /* Handle special case */
|
|
flag3 = !flag3;
|
|
#endif
|
|
MQ = AR * (BR & RMASK); /* 36 * low 18 = 54 bits */
|
|
AR = AR * ((BR >> 18) & RMASK); /* 36 * high 18 = 54 bits */
|
|
MQ += (AR << 18) & LMASK; /* low order bits */
|
|
AR >>= 18;
|
|
AR = (AR << 1) + (MQ >> 35);
|
|
MQ &= CMASK;
|
|
if ((IR & 4) == 0) { /* IMUL */
|
|
if (AR > flag3 && !pi_cycle) {
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
if (flag3) {
|
|
MQ ^= CMASK;
|
|
MQ++;
|
|
MQ |= SMASK;
|
|
}
|
|
AR = MQ;
|
|
break;
|
|
}
|
|
if ((AR & SMASK) != 0 && !pi_cycle) {
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
if (flag3) {
|
|
AR ^= FMASK;
|
|
MQ ^= CMASK;
|
|
MQ += 1;
|
|
if ((MQ & SMASK) != 0) {
|
|
AR += 1;
|
|
MQ &= CMASK;
|
|
}
|
|
}
|
|
AR &= FMASK;
|
|
MQ = (MQ & ~SMASK) | (AR & SMASK);
|
|
break;
|
|
|
|
case 0230: /* IDIV */
|
|
case 0231: /* IDIVI */
|
|
case 0232: /* IDIVM */
|
|
case 0233: /* IDIVB */
|
|
flag1 = 0;
|
|
flag3 = 0;
|
|
if (BR & SMASK) {
|
|
BR = (CM(BR) + 1) & FMASK;
|
|
flag1 = !flag1;
|
|
}
|
|
|
|
if (BR == 0) { /* Check for overflow */
|
|
FLAGS |= OVR|NODIV; /* Overflow and No Divide */
|
|
sac_inh=1; /* Don't touch AC */
|
|
check_apr_irq();
|
|
break; /* Done */
|
|
}
|
|
|
|
if (AR & SMASK) {
|
|
AR = (CM(AR) + 1) & FMASK;
|
|
flag1 = !flag1;
|
|
flag3 = 1;
|
|
}
|
|
|
|
MQ = AR % BR;
|
|
AR = AR / BR;
|
|
if (flag1)
|
|
AR = (CM(AR) + 1) & FMASK;
|
|
if (flag3)
|
|
MQ = (CM(MQ) + 1) & FMASK;
|
|
break;
|
|
|
|
case 0234: /* DIV */
|
|
case 0235: /* DIVI */
|
|
case 0236: /* DIVM */
|
|
case 0237: /* DIVB */
|
|
flag1 = 0;
|
|
flag3 = 0;
|
|
if (AR & SMASK) {
|
|
AD = (CM(MQ) + 1) & FMASK;
|
|
MQ = AR;
|
|
AR = AD;
|
|
AD = (CM(MQ)) & FMASK;
|
|
MQ = AR;
|
|
AR = AD;
|
|
if ((MQ & CMASK) == 0)
|
|
AR = (AR + 1) & FMASK;
|
|
flag1 = 1;
|
|
}
|
|
|
|
if (BR & SMASK)
|
|
AD = (AR + BR) & FMASK;
|
|
else
|
|
AD = (AR + CM(BR) + 1) & FMASK;
|
|
MQ = (MQ << 1) & FMASK;
|
|
MQ |= (AD & SMASK) != 0;
|
|
SC = 35;
|
|
if ((AD & SMASK) == 0) {
|
|
FLAGS |= OVR|NODIV; /* Overflow and No Divide */
|
|
sac_inh=1;
|
|
check_apr_irq();
|
|
break; /* Done */
|
|
}
|
|
|
|
while (SC != 0) {
|
|
if (((BR & SMASK) != 0) ^ ((MQ & 01) != 0))
|
|
AD = (AR + CM(BR) + 1);
|
|
else
|
|
AD = (AR + BR);
|
|
AR = (AD << 1) | ((MQ & SMASK) ? 1 : 0);
|
|
AR &= FMASK;
|
|
MQ = (MQ << 1) & FMASK;
|
|
MQ |= (AD & SMASK) == 0;
|
|
SC--;
|
|
}
|
|
if (((BR & SMASK) != 0) ^ ((MQ & 01) != 0))
|
|
AD = (AR + CM(BR) + 1);
|
|
else
|
|
AD = (AR + BR);
|
|
AR = AD & FMASK;
|
|
MQ = (MQ << 1) & FMASK;
|
|
MQ |= (AD & SMASK) == 0;
|
|
if (AR & SMASK) {
|
|
if (BR & SMASK)
|
|
AD = (AR + CM(BR) + 1) & FMASK;
|
|
else
|
|
AD = (AR + BR) & FMASK;
|
|
AR = AD;
|
|
}
|
|
|
|
if (flag1)
|
|
AR = (CM(AR) + 1) & FMASK;
|
|
if (flag1 ^ ((BR & SMASK) != 0)) {
|
|
AD = (CM(MQ) + 1) & FMASK;
|
|
MQ = AR;
|
|
AR = AD;
|
|
} else {
|
|
AD = MQ;
|
|
MQ = AR;
|
|
AR = AD;
|
|
}
|
|
break;
|
|
|
|
/* Shift */
|
|
case 0240: /* ASH */
|
|
SC = ((AB & LSIGN) ? (0377 ^ AB) + 1 : AB) & 0377;
|
|
if (SC == 0)
|
|
break;
|
|
AD = (AR & SMASK) ? FMASK : 0;
|
|
if (AB & LSIGN) {
|
|
if (SC < 35)
|
|
AR = ((AR >> SC) | (AD << (36 - SC))) & FMASK;
|
|
else
|
|
AR = AD;
|
|
} else {
|
|
if (((AD << SC) & ~CMASK) != ((AR << SC) & ~CMASK)) {
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
AR = ((AR << SC) & CMASK) | (AR & SMASK);
|
|
}
|
|
break;
|
|
|
|
case 0241: /* ROT */
|
|
#if KI | KL
|
|
SC = (AB & LSIGN) ?
|
|
((AB & 0377) ? (((0377 ^ AB) + 1) & 0377) : 0400) : (AB & 0377);
|
|
#else
|
|
SC = ((AB & LSIGN) ? (0377 ^ AB) + 1 : AB) & 0377;
|
|
#endif
|
|
if (SC == 0)
|
|
break;
|
|
SC = SC % 36;
|
|
if (AB & LSIGN)
|
|
SC = 36 - SC;
|
|
AR = ((AR << SC) | (AR >> (36 - SC))) & FMASK;
|
|
break;
|
|
|
|
case 0242: /* LSH */
|
|
SC = ((AB & LSIGN) ? (0377 ^ AB) + 1 : AB) & 0777;
|
|
if (SC == 0)
|
|
break;
|
|
if (AB & LSIGN) {
|
|
AR = AR >> SC;
|
|
} else {
|
|
AR = (AR << SC) & FMASK;
|
|
}
|
|
break;
|
|
|
|
case 0243: /* JFFO */
|
|
#if !PDP6
|
|
SC = 0;
|
|
if (AR != 0) {
|
|
PC = AB;
|
|
f_pc_inh = 1;
|
|
SC = nlzero(AR);
|
|
}
|
|
set_reg(AC + 1, SC);
|
|
#endif
|
|
break;
|
|
|
|
case 0244: /* ASHC */
|
|
SC = ((AB & LSIGN) ? (0377 ^ AB) + 1 : AB) & 0377;
|
|
if (SC == 0)
|
|
break;
|
|
if (SC > 70)
|
|
SC = 70;
|
|
AD = (AR & SMASK) ? FMASK : 0;
|
|
AR &= CMASK;
|
|
MQ &= CMASK;
|
|
if (AB & LSIGN) {
|
|
if (SC >= 35) {
|
|
MQ = ((AR >> (SC - 35)) | (AD << (70 - SC))) & FMASK;
|
|
AR = AD;
|
|
} else {
|
|
MQ = (AD & SMASK) | (MQ >> SC) |
|
|
((AR << (35 - SC)) & CMASK);
|
|
AR = ((AD & SMASK) |
|
|
((AR >> SC) | (AD << (35 - SC)))) & FMASK;
|
|
}
|
|
} else {
|
|
if (SC >= 35) {
|
|
if (((AD << SC) & ~CMASK) != ((AR << SC) & ~CMASK)) {
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
AR = (AD & SMASK) | ((AR << (SC - 35)) & CMASK);
|
|
MQ = (AD & SMASK);
|
|
} else {
|
|
if ((((AD & CMASK) << SC) & ~CMASK) != ((AR << SC) & ~CMASK)) {
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
AR = (AD & SMASK) | ((AR << SC) & CMASK) |
|
|
(MQ >> (35 - SC));
|
|
MQ = (AD & SMASK) | ((MQ << SC) & CMASK);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0245: /* ROTC */
|
|
#if KI | KL
|
|
SC = (AB & LSIGN) ?
|
|
((AB & 0377) ? (((0377 ^ AB) + 1) & 0377) : 0400) : (AB & 0377);
|
|
#else
|
|
SC = ((AB & LSIGN) ? (0777 ^ AB) + 1 : AB) & 0777;
|
|
#endif
|
|
if (SC == 0)
|
|
break;
|
|
SC = SC % 72;
|
|
if (AB & LSIGN)
|
|
SC = 72 - SC;
|
|
if (SC >= 36) {
|
|
AD = MQ;
|
|
MQ = AR;
|
|
AR = AD;
|
|
SC -= 36;
|
|
}
|
|
AD = ((AR << SC) | (MQ >> (36 - SC))) & FMASK;
|
|
MQ = ((MQ << SC) | (AR >> (36 - SC))) & FMASK;
|
|
AR = AD;
|
|
break;
|
|
|
|
case 0246: /* LSHC */
|
|
SC = ((AB & LSIGN) ? (0377 ^ AB) + 1 : AB) & 0377;
|
|
if (SC == 0)
|
|
break;
|
|
if (SC > 71) {
|
|
AR = 0;
|
|
MQ = 0;
|
|
} else {
|
|
if (SC > 36) {
|
|
if (AB & LSIGN) {
|
|
AR = MQ;
|
|
MQ = 0;
|
|
} else {
|
|
MQ = AR;
|
|
AR = 0;
|
|
}
|
|
SC -= 36;
|
|
}
|
|
if (AB & LSIGN) {
|
|
MQ = ((MQ >> SC) | (AR << (36 - SC))) & FMASK;
|
|
AR = AR >> SC;
|
|
} else {
|
|
AR = ((AR << SC) | (MQ >> (36 - SC))) & FMASK;
|
|
MQ = (MQ << SC) & FMASK;
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* Branch */
|
|
case 0250: /* EXCH */
|
|
set_reg(AC, BR);
|
|
break;
|
|
|
|
case 0251: /* BLT */
|
|
BR = AB;
|
|
do {
|
|
if (sim_interval <= 0) {
|
|
sim_process_event();
|
|
}
|
|
/* Allow for interrupt */
|
|
if (pi_enable && pi_pending) {
|
|
pi_rq = check_irq_level();
|
|
if (pi_rq) {
|
|
f_pc_inh = 1;
|
|
f_load_pc = 0;
|
|
f_inst_fetch = 0;
|
|
set_reg(AC, AR);
|
|
break;
|
|
}
|
|
}
|
|
AB = (AR >> 18) & RMASK;
|
|
if (Mem_read(0, 0)) {
|
|
f_pc_inh = 1;
|
|
set_reg(AC, AR);
|
|
goto last;
|
|
}
|
|
AB = (AR & RMASK);
|
|
if (Mem_write(0, 0)) {
|
|
f_pc_inh = 1;
|
|
set_reg(AC, AR);
|
|
goto last;
|
|
}
|
|
AD = (AR & RMASK) + CM(BR) + 1;
|
|
AR = AOB(AR);
|
|
} while ((AD & C1) == 0);
|
|
break;
|
|
|
|
case 0252: /* AOBJP */
|
|
AR = AOB(AR);
|
|
if ((AR & SMASK) == 0) {
|
|
PC = AB;
|
|
f_pc_inh = 1;
|
|
}
|
|
AR &= FMASK;
|
|
break;
|
|
|
|
case 0253: /* AOBJN */
|
|
AR = AOB(AR);
|
|
if ((AR & SMASK) != 0) {
|
|
PC = AB;
|
|
f_pc_inh = 1;
|
|
}
|
|
AR &= FMASK;
|
|
break;
|
|
|
|
case 0254: /* JRST */ /* AR Frm PC */
|
|
if (uuo_cycle | pi_cycle) {
|
|
FLAGS &= ~USER; /* Clear USER */
|
|
}
|
|
/* JEN */
|
|
if (AC & 010) { /* Restore interrupt level. */
|
|
#if KI | KL
|
|
if ((FLAGS & (USER|USERIO)) == USER ||
|
|
(FLAGS & (USER|PUBLIC)) == PUBLIC) {
|
|
#else
|
|
if ((FLAGS & (USER|USERIO)) == USER) {
|
|
#endif
|
|
goto muuo;
|
|
} else {
|
|
pi_restore = 1;
|
|
}
|
|
}
|
|
/* HALT */
|
|
if (AC & 04) {
|
|
#if KI | KL
|
|
if ((FLAGS & (USER|USERIO)) == USER ||
|
|
(FLAGS & (USER|PUBLIC)) == PUBLIC) {
|
|
#else
|
|
if ((FLAGS & (USER|USERIO)) == USER) {
|
|
#endif
|
|
goto muuo;
|
|
} else {
|
|
reason = STOP_HALT;
|
|
}
|
|
}
|
|
PC = AR & RMASK;
|
|
/* JRSTF */
|
|
if (AC & 02) {
|
|
FLAGS &= ~(OVR|NODIV|FLTUND|BYTI|FLTOVR|CRY1|CRY0);
|
|
AR >>= 23; /* Move into position */
|
|
/* If executive mode, copy USER and UIO */
|
|
if ((FLAGS & (PUBLIC|USER)) == 0)
|
|
FLAGS |= AR & (USER|USERIO|PUBLIC);
|
|
/* Can always clear UIO */
|
|
if ((AR & USERIO) == 0)
|
|
FLAGS &= ~USERIO;
|
|
FLAGS |= AR & (OVR|NODIV|FLTUND|BYTI|FLTOVR|CRY1|CRY0|\
|
|
TRP1|TRP2|PUBLIC);
|
|
check_apr_irq();
|
|
|
|
}
|
|
if (AC & 01) { /* Enter User Mode */
|
|
#if KI | KL
|
|
FLAGS &= ~PUBLIC;
|
|
private_page = 0;
|
|
#else
|
|
FLAGS |= USER;
|
|
#endif
|
|
}
|
|
f_pc_inh = 1;
|
|
break;
|
|
|
|
case 0255: /* JFCL */
|
|
if ((FLAGS >> 9) & AC) {
|
|
PC = AR & RMASK;
|
|
f_pc_inh = 1;
|
|
}
|
|
FLAGS &= 017777 ^ (AC << 9);
|
|
break;
|
|
|
|
case 0256: /* XCT */
|
|
f_load_pc = 0;
|
|
f_pc_inh = 1;
|
|
#if KI | KL
|
|
if ((FLAGS & USER) == 0)
|
|
xct_flag = AC;
|
|
#endif
|
|
break;
|
|
|
|
case 0257: /* MAP */
|
|
#if KI | KL
|
|
f = AB >> 9;
|
|
last_page = ((f ^ 0777) << 1);
|
|
pag_reload &= 037;
|
|
if ((FLAGS & USER) != 0) {
|
|
/* Check if small user and outside range */
|
|
if (small_user && (f & 0340) != 0) {
|
|
AR = 0420000LL; /* Page failure, no match */
|
|
break;
|
|
}
|
|
AR = ub_ptr;
|
|
} else {
|
|
if (!page_enable) {
|
|
AR = 0020000LL + f; /* direct map */
|
|
break;
|
|
}
|
|
|
|
/* Map executive to use space */
|
|
if ((f & 0740) == 0340) {
|
|
AR = ub_ptr;
|
|
f += 01000 - 0340;
|
|
/* Executive high segment */
|
|
} else if (f & 0400) {
|
|
AR = eb_ptr;
|
|
} else {
|
|
AR = 0020000LL + f; /* direct map */
|
|
break;
|
|
}
|
|
last_page |= 1;
|
|
}
|
|
AB = (AR + (f >> 1)) & RMASK;
|
|
pag_reload = ((pag_reload + 1) & 037) | 040;
|
|
if (Mem_read(0, 0))
|
|
goto last;
|
|
AR = MB;
|
|
if ((f & 1) == 0)
|
|
AR >>= 18;
|
|
if ((AR & LSIGN) == 0) {
|
|
AR = 0437777LL; /* Return invalid if not accessable */
|
|
} else {
|
|
AR &= 0357777LL;
|
|
if ((AR & 0100000LL) == 0)
|
|
AR |= LSIGN;
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
/* Stack, JUMP */
|
|
case 0260: /* PUSHJ */ /* AR Frm PC */
|
|
MB = ((uint64)(FLAGS) << 23) | ((PC + !pi_cycle) & RMASK);
|
|
BR = AB;
|
|
AR = AOB(AR);
|
|
AB = AR & RMASK;
|
|
if (Mem_write(uuo_cycle | pi_cycle, 0))
|
|
goto last;
|
|
FLAGS &= ~ (BYTI|ADRFLT|TRP1|TRP2);
|
|
if (AR & C1) {
|
|
#if KI | KL
|
|
if (!pi_cycle)
|
|
FLAGS |= TRP2;
|
|
#else
|
|
push_ovf = 1;
|
|
check_apr_irq();
|
|
#endif
|
|
}
|
|
AR &= FMASK;
|
|
if (uuo_cycle | pi_cycle) {
|
|
FLAGS &= ~(USER|PUBLIC); /* Clear USER */
|
|
}
|
|
PC = BR & RMASK;
|
|
f_pc_inh = 1;
|
|
break;
|
|
|
|
case 0261: /* PUSH */
|
|
AR = AOB(AR);
|
|
AB = AR & RMASK;
|
|
if (AR & C1) {
|
|
#if KI | KL
|
|
if (!pi_cycle)
|
|
FLAGS |= TRP2;
|
|
#else
|
|
push_ovf = 1;
|
|
check_apr_irq();
|
|
#endif
|
|
}
|
|
AR &= FMASK;
|
|
MB = BR;
|
|
if (Mem_write(0, 0))
|
|
goto last;
|
|
break;
|
|
|
|
case 0262: /* POP */
|
|
AB = AR & RMASK;
|
|
if (Mem_read(0, 0))
|
|
goto last;
|
|
AR = SOB(AR);
|
|
AB = BR & RMASK;
|
|
if (Mem_write(0, 0))
|
|
goto last;
|
|
if ((AR & C1) == 0) {
|
|
#if KI | KL
|
|
if (!pi_cycle)
|
|
FLAGS |= TRP2;
|
|
#else
|
|
push_ovf = 1;
|
|
check_apr_irq();
|
|
#endif
|
|
}
|
|
AR &= FMASK;
|
|
break;
|
|
|
|
case 0263: /* POPJ */
|
|
AB = AR & RMASK;
|
|
if (Mem_read(0, 0))
|
|
goto last;
|
|
PC = MB & RMASK;
|
|
AR = SOB(AR);
|
|
if ((AR & C1) == 0) {
|
|
#if KI | KL
|
|
if (!pi_cycle)
|
|
FLAGS |= TRP2;
|
|
#else
|
|
push_ovf = 1;
|
|
check_apr_irq();
|
|
#endif
|
|
}
|
|
AR &= FMASK;
|
|
f_pc_inh = 1;
|
|
break;
|
|
|
|
case 0264: /* JSR */ /* AR Frm PC */
|
|
MB = ((uint64)(FLAGS) << 23) |
|
|
((PC + !pi_cycle) & RMASK);
|
|
if (uuo_cycle | pi_cycle) {
|
|
FLAGS &= ~(USER|PUBLIC); /* Clear USER */
|
|
}
|
|
if (Mem_write(0, 0))
|
|
goto last;
|
|
FLAGS &= ~ (BYTI|ADRFLT|TRP1|TRP2);
|
|
PC = (AR + 1) & RMASK;
|
|
f_pc_inh = 1;
|
|
break;
|
|
|
|
case 0265: /* JSP */ /* AR Frm PC */
|
|
AD = ((uint64)(FLAGS) << 23) |
|
|
((PC + !pi_cycle) & RMASK);
|
|
FLAGS &= ~ (BYTI|ADRFLT|TRP1|TRP2);
|
|
if (uuo_cycle | pi_cycle) {
|
|
FLAGS &= ~(USER|PUBLIC); /* Clear USER */
|
|
}
|
|
PC = AR & RMASK;
|
|
AR = AD;
|
|
f_pc_inh = 1;
|
|
break;
|
|
|
|
case 0266: /* JSA */ /* AR Frm PC */
|
|
set_reg(AC, (AR << 18) | ((PC + 1) & RMASK));
|
|
if (uuo_cycle | pi_cycle) {
|
|
FLAGS &= ~(USER|PUBLIC); /* Clear USER */
|
|
}
|
|
PC = AR & RMASK;
|
|
AR = BR;
|
|
break;
|
|
|
|
case 0267: /* JRA */
|
|
AD = AB;
|
|
AB = (get_reg(AC) >> 18) & RMASK;
|
|
if (Mem_read(uuo_cycle | pi_cycle, 0))
|
|
goto last;
|
|
set_reg(AC, MB);
|
|
PC = AD & RMASK;
|
|
f_pc_inh = 1;
|
|
break;
|
|
|
|
case 0270: /* ADD */
|
|
case 0271: /* ADDI */
|
|
case 0272: /* ADDM */
|
|
case 0273: /* ADDB */
|
|
flag1 = flag3 = 0;
|
|
FLAGS &= 01777;
|
|
if (((AR & CMASK) + (BR & CMASK)) & SMASK) {
|
|
FLAGS |= CRY1;
|
|
flag1 = 1;
|
|
}
|
|
BR = AR + BR;
|
|
if (BR & C1) {
|
|
FLAGS |= CRY0;
|
|
flag3 = 1;
|
|
}
|
|
if (flag1 != flag3) {
|
|
if (!pi_cycle)
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
BR &= FMASK;
|
|
AR = BR;
|
|
break;
|
|
|
|
case 0274: /* SUB */
|
|
case 0275: /* SUBI */
|
|
case 0276: /* SUBM */
|
|
case 0277: /* SUBB */
|
|
flag1 = flag3 = 0;
|
|
FLAGS &= 01777;
|
|
if ((((AR & CMASK) ^ CMASK) + (BR & CMASK) + 1) & SMASK) {
|
|
FLAGS |= CRY1;
|
|
flag1 = 1;
|
|
}
|
|
BR = CM(AR) + BR + 1;
|
|
if (BR & C1) {
|
|
FLAGS |= CRY0;
|
|
flag3 = 1;
|
|
}
|
|
if (flag1 != flag3) {
|
|
if (!pi_cycle)
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
BR &= FMASK;
|
|
AR = BR;
|
|
break;
|
|
|
|
/* SKIP */
|
|
case 0300: /* CAI */
|
|
case 0301: /* CAIL */
|
|
case 0302: /* CAIE */
|
|
case 0303: /* CAILE */
|
|
case 0304: /* CAIA */
|
|
case 0305: /* CAIGE */
|
|
case 0306: /* CAIN */
|
|
case 0307: /* CAIG */
|
|
case 0310: /* CAM */
|
|
case 0311: /* CAML */
|
|
case 0312: /* CAME */
|
|
case 0313: /* CAMLE */
|
|
case 0314: /* CAMA */
|
|
case 0315: /* CAMGE */
|
|
case 0316: /* CAMN */
|
|
case 0317: /* CAMG */
|
|
f = 0;
|
|
AD = (CM(AR) + BR) + 1;
|
|
if (((BR & SMASK) != 0) && (AR & SMASK) == 0)
|
|
f = 1;
|
|
if (((BR & SMASK) == (AR & SMASK)) &&
|
|
(AD & SMASK) != 0)
|
|
f = 1;
|
|
goto skip_op;
|
|
|
|
case 0320: /* JUMP */
|
|
case 0321: /* JUMPL */
|
|
case 0322: /* JUMPE */
|
|
case 0323: /* JUMPLE */
|
|
case 0324: /* JUMPA */
|
|
case 0325: /* JUMPGE */
|
|
case 0326: /* JUMPN */
|
|
case 0327: /* JUMPG */
|
|
AD = AR;
|
|
f = ((AD & SMASK) != 0);
|
|
goto jump_op; /* JUMP, SKIP */
|
|
|
|
case 0330: /* SKIP */
|
|
case 0331: /* SKIPL */
|
|
case 0332: /* SKIPE */
|
|
case 0333: /* SKIPLE */
|
|
case 0334: /* SKIPA */
|
|
case 0335: /* SKIPGE */
|
|
case 0336: /* SKIPN */
|
|
case 0337: /* SKIPG */
|
|
AD = AR;
|
|
f = ((AD & SMASK) != 0);
|
|
goto skip_op; /* JUMP, SKIP */
|
|
|
|
case 0340: /* AOJ */
|
|
case 0341: /* AOJL */
|
|
case 0342: /* AOJE */
|
|
case 0343: /* AOJLE */
|
|
case 0344: /* AOJA */
|
|
case 0345: /* AOJGE */
|
|
case 0346: /* AOJN */
|
|
case 0347: /* AOJG */
|
|
case 0360: /* SOJ */
|
|
case 0361: /* SOJL */
|
|
case 0362: /* SOJE */
|
|
case 0363: /* SOJLE */
|
|
case 0364: /* SOJA */
|
|
case 0365: /* SOJGE */
|
|
case 0366: /* SOJN */
|
|
case 0367: /* SOJG */
|
|
flag1 = flag3 = 0;
|
|
FLAGS &= 01777;
|
|
AD = (IR & 020) ? FMASK : 1;
|
|
if (((AR & CMASK) + (AD & CMASK)) & SMASK) {
|
|
FLAGS |= CRY1;
|
|
flag1 = 1;
|
|
}
|
|
AD = AR + AD;
|
|
if (AD & C1) {
|
|
FLAGS |= CRY0;
|
|
flag3 = 1;
|
|
}
|
|
if (flag1 != flag3) {
|
|
if (!pi_cycle)
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
f = ((AD & SMASK) != 0);
|
|
jump_op:
|
|
AD &= FMASK;
|
|
AR = AD;
|
|
f |= ((AD == 0) << 1);
|
|
f = f & IR;
|
|
if (((IR & 04) != 0) == (f == 0)) {
|
|
PC = AB;
|
|
f_pc_inh = 1;
|
|
}
|
|
break;
|
|
|
|
case 0350: /* AOS */
|
|
case 0351: /* AOSL */
|
|
case 0352: /* AOSE */
|
|
case 0353: /* AOSLE */
|
|
case 0354: /* AOSA */
|
|
case 0355: /* AOSGE */
|
|
case 0356: /* AOSN */
|
|
case 0357: /* AOSG */
|
|
case 0370: /* SOS */
|
|
case 0371: /* SOSL */
|
|
case 0372: /* SOSE */
|
|
case 0373: /* SOSLE */
|
|
case 0374: /* SOSA */
|
|
case 0375: /* SOSGE */
|
|
case 0376: /* SOSN */
|
|
case 0377: /* SOSG */
|
|
flag1 = flag3 = 0;
|
|
FLAGS &= 01777;
|
|
AD = (IR & 020) ? FMASK : 1;
|
|
if (((AR & CMASK) + (AD & CMASK)) & SMASK) {
|
|
FLAGS |= CRY1;
|
|
flag1 = 1;
|
|
}
|
|
AD = AR + AD;
|
|
if (AD & C1) {
|
|
if (!pi_cycle)
|
|
FLAGS |= CRY0;
|
|
flag3 = 1;
|
|
}
|
|
if (flag1 != flag3) {
|
|
if (!pi_cycle)
|
|
FLAGS |= OVR|TRP1;
|
|
check_apr_irq();
|
|
}
|
|
f = ((AD & SMASK) != 0);
|
|
skip_op:
|
|
AD &= FMASK;
|
|
AR = AD;
|
|
f |= ((AD == 0) << 1);
|
|
f = f & IR;
|
|
if (((IR & 04) != 0) == (f == 0)) {
|
|
PC = (PC + 1) & RMASK;
|
|
#if KI | KL
|
|
} else if (pi_cycle) {
|
|
pi_ov = pi_hold = 1;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
/* Bool */
|
|
case 0400: /* SETZ */
|
|
case 0401: /* SETZI */
|
|
case 0402: /* SETZM */
|
|
case 0403: /* SETZB */
|
|
AR = 0; /* SETZ */
|
|
break;
|
|
|
|
case 0404: /* AND */
|
|
case 0405: /* ANDI */
|
|
case 0406: /* ANDM */
|
|
case 0407: /* ANDB */
|
|
AR = AR & BR; /* AND */
|
|
break;
|
|
|
|
case 0410: /* ANDCA */
|
|
case 0411: /* ANDCAI */
|
|
case 0412: /* ANDCAM */
|
|
case 0413: /* ANDCAB */
|
|
AR = AR & CM(BR); /* ANDCA */
|
|
break;
|
|
|
|
case 0414: /* SETM */
|
|
case 0415: /* SETMI */
|
|
case 0416: /* SETMM */
|
|
case 0417: /* SETMB */
|
|
/* SETM */
|
|
break;
|
|
|
|
case 0420: /* ANDCM */
|
|
case 0421: /* ANDCMI */
|
|
case 0422: /* ANDCMM */
|
|
case 0423: /* ANDCMB */
|
|
AR = CM(AR) & BR; /* ANDCM */
|
|
break;
|
|
|
|
case 0424: /* SETA */
|
|
case 0425: /* SETAI */
|
|
case 0426: /* SETAM */
|
|
case 0427: /* SETAB */
|
|
AR = BR; /* SETA */
|
|
break;
|
|
|
|
case 0430: /* XOR */
|
|
case 0431: /* XORI */
|
|
case 0432: /* XORM */
|
|
case 0433: /* XORB */
|
|
AR = AR ^ BR; /* XOR */
|
|
break;
|
|
|
|
case 0434: /* IOR */
|
|
case 0435: /* IORI */
|
|
case 0436: /* IORM */
|
|
case 0437: /* IORB */
|
|
AR = CM(CM(AR) & CM(BR)); /* IOR */
|
|
break;
|
|
|
|
case 0440: /* ANDCB */
|
|
case 0441: /* ANDCBI */
|
|
case 0442: /* ANDCBM */
|
|
case 0443: /* ANDCBB */
|
|
AR = CM(AR) & CM(BR); /* ANDCB */
|
|
break;
|
|
|
|
case 0444: /* EQV */
|
|
case 0445: /* EQVI */
|
|
case 0446: /* EQVM */
|
|
case 0447: /* EQVB */
|
|
AR = CM(AR ^ BR); /* EQV */
|
|
break;
|
|
|
|
case 0450: /* SETCA */
|
|
case 0451: /* SETCAI */
|
|
case 0452: /* SETCAM */
|
|
case 0453: /* SETCAB */
|
|
AR = CM(BR); /* SETCA */
|
|
break;
|
|
|
|
case 0454: /* ORCA */
|
|
case 0455: /* ORCAI */
|
|
case 0456: /* ORCAM */
|
|
case 0457: /* ORCAB */
|
|
AR = CM(CM(AR) & BR); /* ORCA */
|
|
break;
|
|
|
|
case 0460: /* SETCM */
|
|
case 0461: /* SETCMI */
|
|
case 0462: /* SETCMM */
|
|
case 0463: /* SETCMB */
|
|
AR = CM(AR); /* SETCM */
|
|
break;
|
|
|
|
case 0464: /* ORCM */
|
|
case 0465: /* ORCMI */
|
|
case 0466: /* ORCMM */
|
|
case 0467: /* ORCMB */
|
|
AR = CM(AR & CM(BR)); /* ORCM */
|
|
break;
|
|
|
|
case 0470: /* ORCB */
|
|
case 0471: /* ORCBI */
|
|
case 0472: /* ORCBM */
|
|
case 0473: /* ORCBB */
|
|
AR = CM(AR & BR); /* ORCB */
|
|
break;
|
|
|
|
case 0474: /* SETO */
|
|
case 0475: /* SETOI */
|
|
case 0476: /* SETOM */
|
|
case 0477: /* SETOB */
|
|
AR = FMASK; /* SETO */
|
|
break;
|
|
|
|
case 0500: /* HLL */
|
|
case 0501: /* HLLI */
|
|
case 0502: /* HLLM */
|
|
case 0503: /* HLLS */
|
|
case 0504: /* HRL */
|
|
case 0505: /* HRLI */
|
|
case 0506: /* HRLM */
|
|
case 0507: /* HRLS */
|
|
AR = (AR & LMASK) | (BR & RMASK);
|
|
break;
|
|
|
|
case 0510: /* HLLZ */
|
|
case 0511: /* HLLZI */
|
|
case 0512: /* HLLZM */
|
|
case 0513: /* HLLZS */
|
|
case 0514: /* HRLZ */
|
|
case 0515: /* HRLZI */
|
|
case 0516: /* HRLZM */
|
|
case 0517: /* HRLZS */
|
|
AR = (AR & LMASK);
|
|
break;
|
|
|
|
case 0520: /* HLLO */
|
|
case 0521: /* HLLOI */
|
|
case 0522: /* HLLOM */
|
|
case 0523: /* HLLOS */
|
|
case 0524: /* HRLO */
|
|
case 0525: /* HRLOI */
|
|
case 0526: /* HRLOM */
|
|
case 0527: /* HRLOS */
|
|
AR = (AR & LMASK) | RMASK;
|
|
break;
|
|
|
|
case 0530: /* HLLE */
|
|
case 0531: /* HLLEI */
|
|
case 0532: /* HLLEM */
|
|
case 0533: /* HLLES */
|
|
case 0534: /* HRLE */
|
|
case 0535: /* HRLEI */
|
|
case 0536: /* HRLEM */
|
|
case 0537: /* HRLES */
|
|
AD = ((AR & SMASK) != 0) ? RMASK : 0;
|
|
AR = (AR & LMASK) | AD;
|
|
break;
|
|
|
|
case 0540: /* HRR */
|
|
case 0541: /* HRRI */
|
|
case 0542: /* HRRM */
|
|
case 0543: /* HRRS */
|
|
case 0544: /* HLR */
|
|
case 0545: /* HLRI */
|
|
case 0546: /* HLRM */
|
|
case 0547: /* HLRS */
|
|
AR = (BR & LMASK) | (AR & RMASK);
|
|
break;
|
|
|
|
case 0550: /* HRRZ */
|
|
case 0551: /* HRRZI */
|
|
case 0552: /* HRRZM */
|
|
case 0553: /* HRRZS */
|
|
case 0554: /* HLRZ */
|
|
case 0555: /* HLRZI */
|
|
case 0556: /* HLRZM */
|
|
case 0557: /* HLRZS */
|
|
AR = (AR & RMASK);
|
|
break;
|
|
|
|
case 0560: /* HRRO */
|
|
case 0561: /* HRROI */
|
|
case 0562: /* HRROM */
|
|
case 0563: /* HRROS */
|
|
case 0564: /* HLRO */
|
|
case 0565: /* HLROI */
|
|
case 0566: /* HLROM */
|
|
case 0567: /* HLROS */
|
|
AR = LMASK | (AR & RMASK);
|
|
break;
|
|
|
|
case 0570: /* HRRE */
|
|
case 0571: /* HRREI */
|
|
case 0572: /* HRREM */
|
|
case 0573: /* HRRES */
|
|
case 0574: /* HLRE */
|
|
case 0575: /* HLREI */
|
|
case 0576: /* HLREM */
|
|
case 0577: /* HLRES */
|
|
AD = ((AR & LSIGN) != 0) ? LMASK: 0;
|
|
AR = AD | (AR & RMASK);
|
|
break;
|
|
|
|
case 0600: /* TxN */
|
|
case 0601: /* TxN */
|
|
case 0602: /* TxN */
|
|
case 0603: /* TxN */
|
|
case 0604: /* TxN */
|
|
case 0605: /* TxN */
|
|
case 0606: /* TxN */
|
|
case 0607: /* TxN */
|
|
case 0610:
|
|
case 0611:
|
|
case 0612:
|
|
case 0613:
|
|
case 0614:
|
|
case 0615:
|
|
case 0616:
|
|
case 0617:
|
|
MQ = AR; /* N */
|
|
goto test_op;
|
|
|
|
case 0620: /* TxZ */
|
|
case 0621: /* TxZ */
|
|
case 0622: /* TxZ */
|
|
case 0623: /* TxZ */
|
|
case 0624: /* TxZ */
|
|
case 0625: /* TxZ */
|
|
case 0626: /* TxZ */
|
|
case 0627: /* TxZ */
|
|
case 0630:
|
|
case 0631:
|
|
case 0632:
|
|
case 0633:
|
|
case 0634:
|
|
case 0635:
|
|
case 0636:
|
|
case 0637:
|
|
MQ = CM(AR) & BR; /* Z */
|
|
goto test_op;
|
|
|
|
case 0640: /* TxC */
|
|
case 0641: /* TxC */
|
|
case 0642: /* TxC */
|
|
case 0643: /* TxC */
|
|
case 0644: /* TxC */
|
|
case 0645: /* TxC */
|
|
case 0646: /* TxC */
|
|
case 0647: /* TxC */
|
|
case 0650:
|
|
case 0651:
|
|
case 0652:
|
|
case 0653:
|
|
case 0654:
|
|
case 0655:
|
|
case 0656:
|
|
case 0657:
|
|
MQ = AR ^ BR; /* C */
|
|
goto test_op;
|
|
|
|
case 0660: /* TxO */
|
|
case 0661: /* TxO */
|
|
case 0662: /* TxO */
|
|
case 0663: /* TxO */
|
|
case 0664: /* TxO */
|
|
case 0665: /* TxO */
|
|
case 0666: /* TxO */
|
|
case 0667: /* TxO */
|
|
case 0670:
|
|
case 0671:
|
|
case 0672:
|
|
case 0673:
|
|
case 0674:
|
|
case 0675:
|
|
case 0676:
|
|
case 0677:
|
|
MQ = AR | BR; /* O */
|
|
test_op:
|
|
AR &= BR;
|
|
f = ((AR == 0) & ((IR >> 1) & 1)) ^ ((IR >> 2) & 1);
|
|
if (f)
|
|
PC = (PC + 1) & RMASK;
|
|
AR = MQ;
|
|
break;
|
|
|
|
/* IOT */
|
|
case 0700: case 0701: case 0702: case 0703:
|
|
case 0704: case 0705: case 0706: case 0707:
|
|
case 0710: case 0711: case 0712: case 0713:
|
|
case 0714: case 0715: case 0716: case 0717:
|
|
case 0720: case 0721: case 0722: case 0723:
|
|
case 0724: case 0725: case 0726: case 0727:
|
|
case 0730: case 0731: case 0732: case 0733:
|
|
case 0734: case 0735: case 0736: case 0737:
|
|
case 0740: case 0741: case 0742: case 0743:
|
|
case 0744: case 0745: case 0746: case 0747:
|
|
case 0750: case 0751: case 0752: case 0753:
|
|
case 0754: case 0755: case 0756: case 0757:
|
|
case 0760: case 0761: case 0762: case 0763:
|
|
case 0764: case 0765: case 0766: case 0767:
|
|
case 0770: case 0771: case 0772: case 0773:
|
|
case 0774: case 0775: case 0776: case 0777:
|
|
#if KI
|
|
if (!pi_cycle && ((FLAGS & (USER|USERIO)) == USER &&
|
|
(IR & 040) == 0 || (FLAGS & (USER|PUBLIC)) == PUBLIC)) {
|
|
|
|
#else
|
|
if ((FLAGS & (USER|USERIO)) == USER && !pi_cycle) {
|
|
#endif
|
|
/* User and not User I/O */
|
|
goto muuo;
|
|
} else {
|
|
int d = ((IR & 077) << 1) | ((AC & 010) != 0);
|
|
switch(AC & 07) {
|
|
case 0: /* 00 BLKI */
|
|
case 2: /* 10 BLKO */
|
|
if (Mem_read(pi_cycle, 0))
|
|
break;
|
|
AR = MB;
|
|
if (hst_lnt) {
|
|
hst[hst_p].mb = AR;
|
|
}
|
|
AC |= 1; /* Make into DATAI/DATAO */
|
|
f_load_pc = 0;
|
|
f_inst_fetch = 0;
|
|
AR = AOB(AR);
|
|
if (AR & C1) {
|
|
pi_ov = f_pc_inh = 1;
|
|
} else if (!pi_cycle) {
|
|
PC = (PC + 1) & RMASK;
|
|
}
|
|
AR &= FMASK;
|
|
MB = AR;
|
|
if (Mem_write(pi_cycle, 0))
|
|
break;
|
|
AB = AR & RMASK;
|
|
goto fetch_opr;
|
|
break;
|
|
case 1: /* 04 DATAI */
|
|
dev_tab[d](DATAI|(d<<2), &AR);
|
|
MB = AR;
|
|
Mem_write(pi_cycle, 0);
|
|
break;
|
|
case 3: /* 14 DATAO */
|
|
if (Mem_read(pi_cycle, 0))
|
|
break;
|
|
AR = MB;
|
|
dev_tab[d](DATAO|(d<<2), &AR);
|
|
break;
|
|
case 4: /* 20 CONO */
|
|
dev_tab[d](CONO|(d<<2), &AR);
|
|
break;
|
|
case 5: /* 24 CONI */
|
|
dev_tab[d](CONI|(d<<2), &AR);
|
|
MB = AR;
|
|
Mem_write(pi_cycle, 0);
|
|
break;
|
|
case 6: /* 30 CONSZ */
|
|
dev_tab[d](CONI|(d<<2), &AR);
|
|
AR &= AB;
|
|
if (AR == 0)
|
|
PC = (PC + 1) & RMASK;
|
|
break;
|
|
case 7: /* 34 CONSO */
|
|
dev_tab[d](CONI|(d<<2), &AR);
|
|
AR &= AB;
|
|
if (AR != 0)
|
|
PC = (PC + 1) & RMASK;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!sac_inh && (i_flags & (SCE|FCEPSE))) {
|
|
MB = AR;
|
|
if (Mem_write(0, 0))
|
|
goto last;
|
|
}
|
|
if (!sac_inh && ((i_flags & SAC) || ((i_flags & SACZ) && AC != 0)))
|
|
set_reg(AC, AR); /* blank, I, B */
|
|
|
|
if (!sac_inh && (i_flags & SAC2))
|
|
set_reg(AC+1, MQ);
|
|
|
|
if (hst_lnt) {
|
|
hst[hst_p].fmb = AR;
|
|
}
|
|
|
|
last:
|
|
#if KI | KL
|
|
/* Handle page fault and traps */
|
|
if (page_enable && (page_fault || private_page)) {
|
|
page_fault = private_page = 0;
|
|
AB = ub_ptr + ((FLAGS & USER) ? 0427 : 0426);
|
|
MB = fault_data;
|
|
Mem_write_nopage();
|
|
FLAGS |= trap_flag & (TRP1|TRP2);
|
|
trap_flag = 1;
|
|
AB = 0420;
|
|
f_pc_inh = 1;
|
|
pi_cycle = 1;
|
|
AB += (FLAGS & USER) ? ub_ptr : eb_ptr;
|
|
Mem_read_nopage();
|
|
goto no_fetch;
|
|
}
|
|
#endif
|
|
|
|
if (!f_pc_inh && !pi_cycle) {
|
|
PC = (PC + 1) & RMASK;
|
|
}
|
|
|
|
/* Dismiss an interrupt */
|
|
if (pi_cycle) {
|
|
#if KI | KL
|
|
if (page_enable && (page_fault || private_page)) {
|
|
page_fault = private_page = 0;
|
|
inout_fail = 1;
|
|
}
|
|
#endif
|
|
|
|
if ((IR & 0700) == 0700 && ((AC & 04) == 0)) {
|
|
pi_hold = pi_ov;
|
|
if (!pi_hold & f_inst_fetch) {
|
|
pi_restore = 1;
|
|
pi_cycle = 0;
|
|
} else {
|
|
AB = 040 | (pi_enc << 1) | pi_ov;
|
|
pi_ov = 0;
|
|
pi_hold = 0;
|
|
#if KI | KL
|
|
AB |= eb_ptr;
|
|
Mem_read_nopage();
|
|
goto no_fetch;
|
|
#else
|
|
goto fetch;
|
|
#endif
|
|
}
|
|
} else if (pi_hold) {
|
|
AB = 040 | (pi_enc << 1) | pi_ov;
|
|
pi_ov = 0;
|
|
pi_hold = 0;
|
|
#if KI | KL
|
|
AB |= eb_ptr;
|
|
Mem_read_nopage();
|
|
goto no_fetch;
|
|
#else
|
|
goto fetch;
|
|
#endif
|
|
} else {
|
|
f_inst_fetch = 1;
|
|
f_load_pc = 1;
|
|
pi_cycle = 0;
|
|
}
|
|
}
|
|
|
|
if (pi_restore) {
|
|
restore_pi_hold();
|
|
pi_restore = 0;
|
|
}
|
|
sim_interval--;
|
|
}
|
|
/* Should never get here */
|
|
|
|
return reason;
|
|
}
|
|
|
|
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/2;
|
|
clk_flg = 1;
|
|
if (clk_en) {
|
|
set_interrupt(4, clk_irq);
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Reset routine */
|
|
|
|
t_stat cpu_reset (DEVICE *dptr)
|
|
{
|
|
int i;
|
|
BYF5 = uuo_cycle = 0;
|
|
#if KA | PDP6
|
|
Pl = Ph = Rl = Rh = Pflag = 0;
|
|
push_ovf = mem_prot = 0;
|
|
#endif
|
|
nxm_flag = clk_flg = 0;
|
|
PIR = PIH = PIE = pi_enable = parity_irq = 0;
|
|
pi_pending = pi_req = pi_enc = apr_irq = 0;
|
|
ov_irq =fov_irq =clk_en =clk_irq = 0;
|
|
pi_restore = pi_hold = 0;
|
|
#if KI | KL
|
|
ub_ptr = eb_ptr = 0;
|
|
pag_reload = ac_stack = 0;
|
|
fm_sel = small_user = user_addr_cmp = page_enable = 0;
|
|
#endif
|
|
for(i=0; i < 128; dev_irq[i++] = 0);
|
|
sim_brk_types = sim_brk_dflt = SWMASK ('E');
|
|
sim_rtcn_init (cpu_unit.wait, TMR_RTC);
|
|
sim_activate(&cpu_unit, cpu_unit.wait);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Memory examine */
|
|
|
|
t_stat cpu_ex (t_value *vptr, t_addr ea, UNIT *uptr, int32 sw)
|
|
{
|
|
if (vptr == NULL)
|
|
return SCPE_ARG;
|
|
if (ea < 020)
|
|
*vptr = FM[ea] & FMASK;
|
|
else {
|
|
if (sw & SWMASK ('V')) {
|
|
if (ea >= MAXMEMSIZE)
|
|
return SCPE_REL;
|
|
}
|
|
if (ea >= MEMSIZE)
|
|
return SCPE_NXM;
|
|
*vptr = M[ea] & FMASK;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Memory deposit */
|
|
|
|
t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw)
|
|
{
|
|
if (ea < 020)
|
|
FM[ea] = val & FMASK;
|
|
else {
|
|
if (sw & SWMASK ('V')) {
|
|
if (ea >= MAXMEMSIZE)
|
|
return SCPE_REL;
|
|
}
|
|
if (ea >= MEMSIZE)
|
|
return SCPE_NXM;
|
|
M[ea] = val & FMASK;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Memory size change */
|
|
|
|
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
uint32 i;
|
|
|
|
if ((val <= 0) || ((val * 16 * 1024) > MAXMEMSIZE))
|
|
return SCPE_ARG;
|
|
val = val * 16 * 1024;
|
|
if (val < MEMSIZE) {
|
|
uint64 mc = 0;
|
|
for (i = val; i < MEMSIZE; i++)
|
|
mc = mc | M[i];
|
|
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
|
|
return SCPE_OK;
|
|
}
|
|
for (i = MEMSIZE; i < val; i++)
|
|
M[i] = 0;
|
|
MEMSIZE = val;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Build device dispatch table */
|
|
t_bool build_dev_tab (void)
|
|
{
|
|
DEVICE *dptr;
|
|
DIB *dibp;
|
|
uint32 i, j;
|
|
|
|
for (i = 0; i < 128; i++)
|
|
dev_tab[i] = &null_dev;
|
|
dev_tab[0] = &dev_apr;
|
|
dev_tab[1] = &dev_pi;
|
|
#if KI | KL
|
|
dev_tab[2] = &dev_pag;
|
|
#endif
|
|
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
|
|
dibp = (DIB *) dptr->ctxt;
|
|
if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */
|
|
for (j = 0; j < dibp->num_devs; j++) { /* loop thru disp */
|
|
if (dibp->io) { /* any dispatch? */
|
|
if (dev_tab[(dibp->dev_num >> 2) + j] != &null_dev) {
|
|
/* already filled? */
|
|
sim_printf ("%s device number conflict at %02o\n",
|
|
sim_dname (dptr), dibp->dev_num + (j << 2));
|
|
return TRUE;
|
|
}
|
|
dev_tab[(dibp->dev_num >> 2) + j] = dibp->io; /* fill */
|
|
} /* end if dsp */
|
|
} /* end for j */
|
|
} /* end if enb */
|
|
} /* end for i */
|
|
return FALSE;
|
|
}
|
|
|
|
#if KI | KL
|
|
|
|
/* Set serial */
|
|
t_stat cpu_set_serial (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
int32 lnt;
|
|
t_stat r;
|
|
|
|
if (cptr == NULL) {
|
|
apr_serial = -1;
|
|
return SCPE_OK;
|
|
}
|
|
lnt = (int32) get_uint (cptr, 10, 001777, &r);
|
|
if ((r != SCPE_OK) || (lnt <= 0))
|
|
return SCPE_ARG;
|
|
apr_serial = lnt & 01777;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Show serial */
|
|
t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
fprintf (st, "Serial: " );
|
|
if (apr_serial == -1) {
|
|
fprintf (st, "%d (default)", DEF_SERIAL);
|
|
return SCPE_OK;
|
|
}
|
|
fprintf (st, "%d", apr_serial);
|
|
return SCPE_OK;
|
|
}
|
|
#endif
|
|
|
|
/* Set history */
|
|
t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
int32 i, lnt;
|
|
t_stat r;
|
|
|
|
if (cptr == NULL) {
|
|
for (i = 0; i < hst_lnt; i++)
|
|
hst[i].pc = 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 = (InstHistory *) calloc (lnt, sizeof (InstHistory));
|
|
if (hst == NULL)
|
|
return SCPE_MEM;
|
|
hst_lnt = lnt;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Show history */
|
|
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
int32 k, di, lnt;
|
|
char *cptr = (char *) desc;
|
|
t_stat r;
|
|
t_value sim_eval;
|
|
InstHistory *h;
|
|
|
|
if (hst_lnt == 0) /* enabled? */
|
|
return SCPE_NOFNC;
|
|
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, "PC AC EA AR RES FLAGS IR\n\n");
|
|
for (k = 0; k < lnt; k++) { /* print specified */
|
|
h = &hst[(++di) % hst_lnt]; /* entry pointer */
|
|
if (h->pc & HIST_PC) { /* instruction? */
|
|
fprintf (st, "%06o ", (uint32)(h->pc & RMASK));
|
|
fprint_val (st, h->ac, 8, 36, PV_RZRO);
|
|
fputs (" ", st);
|
|
fprintf (st, "%06o ", h->ea);
|
|
fputs (" ", st);
|
|
fprint_val (st, h->mb, 8, 36, PV_RZRO);
|
|
fputs (" ", st);
|
|
fprint_val (st, h->fmb, 8, 36, PV_RZRO);
|
|
fputs (" ", st);
|
|
fprintf (st, "%06o ", h->flags);
|
|
if ((h->pc & HIST_PC2) == 0) {
|
|
sim_eval = h->ir;
|
|
fprint_val (st, sim_eval, 8, 36, PV_RZRO);
|
|
fputs (" ", st);
|
|
if ((fprint_sym (st, h->pc & RMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0) {
|
|
fputs ("(undefined) ", st);
|
|
fprint_val (st, h->ir, 8, 36, 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, "%s\n\n", cpu_description(dptr));
|
|
fprintf(st, "To stop the cpu use the command:\n\n");
|
|
fprintf(st, " sim> SET CTY STOP\n\n");
|
|
fprintf(st, "This will write a 1 to location %03o, causing TOPS10 to stop\n", CTY_SWITCH);
|
|
fprint_set_help(st, dptr);
|
|
fprint_show_help(st, dptr);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
const char *
|
|
cpu_description (DEVICE *dptr)
|
|
{
|
|
#if KL
|
|
return "KL10A CPU";
|
|
#endif
|
|
#if KI
|
|
return "KI10 CPU";
|
|
#endif
|
|
#if KA
|
|
return "KA10 CPU";
|
|
#endif
|
|
#if PDP6
|
|
return "PDP6 CPU";
|
|
#endif
|
|
}
|