1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-01-13 15:27:04 +00:00
rcornwell.sims/SEL32/sel32_cpu.c
AZBevier d198882980 SEL32: Correct real time clock interrupt processing.
SEL32: start code cleanup.
SEL32: add mfp and mfp scsi disk intitial support code.
SEL32: add new files sel32_mfp.c and sel32_scsi.c to makefile.
SEL32: modify sel32_mt.c code to define tape as BTP for UTX.
2020-03-06 21:41:59 -07:00

7264 lines
431 KiB
C

/* sel32_cpu.c: Sel 32 CPU simulator
Copyright (c) 2018-2020, James C. Bevier
Portions provided by Richard Cornwell and other SIMH contributers
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
JAMES C. BEVIER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "sel32_defs.h"
/* 32/7x PSW/PSD Mode Trap/Interrupt Priorities */
/* Relative Logical Int Vect TCW IOCD Description */
/* Priority Priority Location Addr Addr */
/* 0 0F4 Power Fail Safe Trap */
/* 1 0FC System Override Trap (Not Used) */
/* 2 0E8* Memory Parity Trap */
/* 3 190 Nonpresent Memory Trap */
/* 4 194 Undefined Instruction Trap */
/* 5 198 Privilege Violation Trap */
/* 6 180 Supervisor Call Trap (SVC) */
/* 7 184 Machine Check Trap */
/* 8 188 System Check Trap */
/* 9 18C Map Fault Trap */
/* A Not Used */
/* B Not Used */
/* C Not Used */
/* D Not Used */
/* E 0E4 Block Mode Timeout Trap */
/* F 1A4* Arithmetic Exception Trap */
/* 10 00 0F0 Power Fail Safe Interrupt */
/* 11 01 0F8 System Override Interrupt */
/* 12 12 0E8* Memory Parity Trap */
/* 13 13 0EC Attention Interrupt */
/* 14 14 140 100 700 I/O Channel 0 interrupt */
/* 15 15 144 104 708 I/O Channel 1 interrupt */
/* 16 16 148 108 710 I/O Channel 2 interrupt */
/* 17 17 14C 10C 718 I/O Channel 3 interrupt */
/* 18 18 150 110 720 I/O Channel 4 interrupt */
/* 19 19 154 114 728 I/O Channel 5 interrupt */
/* 1A 1A 158 118 730 I/O Channel 6 interrupt */
/* 1B 1B 15C 11C 738 I/O Channel 7 interrupt */
/* 1C 1C 160 120 740 I/O Channel 8 interrupt */
/* 1D 1D 164 124 748 I/O Channel 9 interrupt */
/* 1E 1E 168 128 750 I/O Channel A interrupt */
/* 1F 1F 16C 12C 758 I/O Channel B interrupt */
/* 20 20 170 130 760 I/O Channel C interrupt */
/* 21 21 174 134 768 I/O Channel D interrupt */
/* 22 22 178 138 770 I/O Channel E interrupt */
/* 23 23 17C 13C 778 I/O Channel F interrupt */
/* 24 24 190* Nonpresent Memory Trap */
/* 25 25 194* Undefined Instruction Trap */
/* 26 26 198* Privlege Violation Trap */
/* 27 27 19C Call Monitor Interrupt */
/* 28 28 1A0 Real-Time Clock Interrupt */
/* 29 29 1A4* Arithmetic Exception Interrupt */
/* 2A 2A 1A8 External/Software Interrupt */
/* 2B 2B 1AC External/Software Interrupt */
/* 2C 2C 1B0 External/Software Interrupt */
/* 2D 2D 1B4 External/Software Interrupt */
/* 2E 2E 1B8 External/Software Interrupt */
/* 2F 2F 1BC External/Software Interrupt */
/* 30 30 1C0 External/Software Interrupt */
/* 31 31 1C4 External/Software Interrupt */
/* THRU THRU THRU THRU */
/* 77 77 2DC External/Software Interrupt */
/* 78 2E0 End of IPU Processing Trap (CPU) */
/* 79 2E4 Start IPU Processing Trap (IPU) */
/* 7A 2E8 Supervisor Call Trap (IPU) */
/* 7B 2EC Error Trap (IPU) */
/* 7C 2F0 Call Monitor Trap (IPU) */
/* 7D 7D 2F4 Stop IPU Processing Trap (IPU) */
/* 7E 7E 2F8 External/Software Interrupt */
/* 7F 7F 2FC External/Software Interrupt */
/* Concept 32 PSD Mode Trap/Interrupt Priorities */
/* Relative|Logical |Int Vect|TCW |IOCD|Description */
/* Priority|Priority|Location|Addr|Addr */
/* - 080 Power Fail Safe Trap */
/* - 084 Power On Trap */
/* - 088 Memory Parity Trap */
/* - 08C Nonpresent Memory Trap */
/* - 090 Undefined Instruction Trap */
/* - 094 Privilege Violation Trap */
/* - 098 Supervisor Call Trap (SVC) */
/* - 09C Machine Check Trap */
/* - 0A0 System Check Trap */
/* - 0A4 Map Fault Trap */
/* - 0A8 CALM or Undefined IPU Instruction Trap */
/* - 0AC Signal CPU or Signal IPU Trap */
/* - 0B0 Address Specification Trap */
/* - 0B4 Console Attention Trap */
/* - 0B8 Privlege Mode Halt Trap */
/* - 0BC Arithmetic Exception Trap */
/* - 0C0 Cache Error Trap (V9 Only) */
/* - 0C4 Demand Page Fault Trap (V6&V9 Only) */
/* */
/* 0 00 100 External/software Interrupt 0 */
/* 1 01 104 External/software Interrupt 1 */
/* 2 02 108 External/software Interrupt 2 */
/* 3 03 10C External/software Interrupt 3 */
/* 4 04 110 704 700 I/O Channel 0 interrupt */
/* 5 05 114 70C 708 I/O Channel 1 interrupt */
/* 6 06 118 714 710 I/O Channel 2 interrupt */
/* 7 07 11C 71C 718 I/O Channel 3 interrupt */
/* 8 08 120 724 720 I/O Channel 4 interrupt */
/* 9 09 124 72C 728 I/O Channel 5 interrupt */
/* A 0A 128 734 730 I/O Channel 6 interrupt */
/* B 0B 12C 73C 738 I/O Channel 7 interrupt */
/* C 0C 130 744 740 I/O Channel 8 interrupt */
/* D 0D 134 74C 748 I/O Channel 9 interrupt */
/* E 0E 138 754 750 I/O Channel A interrupt */
/* F 0F 13C 75C 758 I/O Channel B interrupt */
/* 10 10 140 764 760 I/O Channel C interrupt */
/* 11 11 144 76C 768 I/O Channel D interrupt */
/* 12 12 148 774 770 I/O Channel E interrupt */
/* 13 13 14c 77C 778 I/O Channel F interrupt */
/* 14 14 150 External/Software Interrupt */
/* 15 15 154 External/Software Interrupt */
/* 16 16 158 External/Software Interrupt */
/* 17 17 15C External/Software Interrupt */
/* 18 18 160 Real-Time Clock Interrupt */
/* 19 19 164 External/Software Interrupt */
/* 1A 1A 1A8 External/Software Interrupt */
/* 1B 1B 1AC External/Software Interrupt */
/* 1C 1C 1B0 External/Software Interrupt */
/* THRU THRU THRU THRU */
/* 6C 6C 2B0 External/Software Interrupt */
/* 6D 6D 2B4 External/Software Interrupt */
/* 6E 6E 2B8 External/Software Interrupt */
/* 6F 6F 2BC Interval Timer Interrupt */
/* IVL ------------> ICB Trap/Interrupt Vector Location points to Interrupt Context Block */
/* Wd 0 - Old PSD Word 1 points to return location */
/* Wd 1 - Old PSD Word 2 */
/* Wd 2 - New PSD Word 1 points to first instruction of service routine */
/* Wd 3 - New PSD Word 2 */
/* Wd 4 - CPU Status word at time of interrupt/trap */
/* Wd 5 - N/U For Traps/Interrupts */
/* IVL ------------> ICB XIO Interrupt Vector Location */
/* Wd 0 - Old PSD Word 1 points to return location */
/* Wd 1 - Old PSD Word 2 */
/* Wd 2 - New PSD Word 1 points to first instruction of service routine */
/* Wd 3 - New PSD Word 2 */
/* Wd 4 - Input/Output Command List Address (IOCL) for the Class F I/O CHannel */
/* Wd 5 - 24 bit real address of the channel status word */
/* CPU registers, map cache, spad, and other variables */
int cpu_index; /* Current CPU running */
uint32 PSD[2]; /* the PC for the instruction */
#define PSD1 PSD[0] /* word 1 of PSD */
#define PSD2 PSD[1] /* word 2 of PSD */
uint32 M[MAXMEMSIZE] = { 0 }; /* Memory */
uint32 GPR[8]; /* General Purpose Registers */
uint32 BR[8]; /* Base registers */
uint32 PC; /* Program counter */
uint32 CC; /* Condition codes, bits 1-4 of PSD1 */
uint32 SPAD[256]; /* Scratch pad memory */
uint32 INTS[112]; /* Interrupt status flags */
uint32 CPUSTATUS; /* cpu status word */
uint32 TRAPSTATUS; /* trap status word */
uint32 CMCR; /* Cache Memory Control Register */
uint32 SMCR; /* Shared Memory Control Register */
uint32 CMSMC; /* V9 Cache/Shadow Memory Configuration */
uint32 CSMCW; /* CPU Shadow Memory Configuration Word */
uint32 ISMCW; /* IPU Shadow Memory Configuration Word */
uint32 CCW; /* Computer Configuration Word */
uint32 CSW = 0; /* Console switches going to 0x780 */
uint32 BOOTR[8] = {0}; /* Boot registers settings */
/* CPU mapping cache entries */
/* 32/55 has none */
/* 32/7x has 32 8KW maps per task */
/* Concept 32/27 has 256 2KW maps per task */
/* Concept 32/X7 has 2048 2KW maps per task */
uint32 MAPC[1024]; /* maps are 16bit entries on word bountries */
uint32 dummy=0;
uint32 pfault; /* page # of fault from read/write */
uint32 BPIX=0; /* # pages loaded for O/S */
uint32 CPIXPL=0; /* highest page loaded for User */
uint32 CPIX=0; /* CPIX user MPL offset */
uint32 HIWM=0; /* max maps loaded so far */
uint32 TLB[2048]; /* Translated addresses for each map entry */
/* bits 0-4 are bits 0-4 from map entry */
/* bit 0 valid */
/* bit 1 p1 write access if set */
/* bit 2 p2 write access if set */
/* bit 3 p3 write access if set MM - memory modify */
/* bit 4 p4 write access if set MA - memory accessed */
/* bit 5 hit bit means entry is setup, even if not valid map */
/* if hit bit is set and entry not valid, we will do a page fault */
/* bit 6 dirty bit, set when written to, page update required */
/* bits 8-18 has map reg contents for this page (Map << 13) */
/* bit 19-31 is zero for page offset of zero */
uint32 dummy2=0;
uint32 modes; /* Operating modes, bits 0, 5, 6, 7 of PSD1 */
uint8 wait4int = 0; /* waiting for interrupt if set */
/* define traps */
uint32 TRAPME = 0; /* trap to be executed */
uint32 attention_trap = 0; /* set when trap is requested */
struct InstHistory
{
uint32 opsd1; /* original PSD1 */
uint32 opsd2; /* original PSD2 */
uint32 npsd1; /* new PSD1 after instruction */
uint32 npsd2; /* new PSD2 after instruction */
uint32 oir; /* the instruction itself */
uint32 modes; /* current cpu mode bits */
uint32 reg[16]; /* regs/bregs for operation */
};
/* forward definitions */
t_stat cpu_ex(t_value * vptr, t_addr addr, UNIT * uptr, int32 sw);
t_stat cpu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw);
t_stat cpu_reset(DEVICE * dptr);
t_stat cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc);
t_stat cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
uint32 cpu_cmd(UNIT * uptr, uint16 cmd, uint16 dev);
t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
const char *cpu_description (DEVICE *dptr);
t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access);
t_stat load_maps(uint32 thepsd[2], uint32 lmap);
t_stat read_instruction(uint32 thepsd[2], uint32 *instr);
t_stat Mem_read(uint32 addr, uint32 *data);
t_stat Mem_write(uint32 addr, uint32 *data);
/* external definitions */
extern t_stat checkxio(uint16 addr, uint32 *status); /* XIO check in chan.c */
extern t_stat startxio(uint16 addr, uint32 *status); /* XIO start in chan.c */
extern t_stat testxio(uint16 addr, uint32 *status); /* XIO test in chan.c */
extern t_stat stopxio(uint16 addr, uint32 *status); /* XIO stop in chan.c */
extern t_stat rschnlxio(uint16 addr, uint32 *status); /* reset channel XIO */
extern t_stat haltxio(uint16 addr, uint32 *status); /* halt XIO */
extern t_stat grabxio(uint16 addr, uint32 *status); /* grab XIO n/u */
extern t_stat rsctlxio(uint16 addr, uint32 *status); /* reset controller XIO */
extern t_stat chan_set_devs(); /* set up the defined devices on the simulator */
extern uint32 scan_chan(int *ilev); /* go scan for I/O int pending */
extern uint16 loading; /* set when doing IPL */
extern int fprint_inst(FILE *of, uint32 val, int32 sw); /* instruction print function */
extern int irq_pend; /* go scan for pending interrupt */
extern void rtc_setup(uint32 ss, uint32 level); /* tell rtc to start/stop */
extern void itm_setup(uint32 ss, uint32 level); /* tell itm to start/stop */
extern int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level); /* read/write the interval timer */
/* floating point subroutines definitions */
extern uint32 s_fixw(uint32 val, uint32 *cc);
extern uint32 s_fltw(uint32 val, uint32 *cc);
extern t_uint64 s_fixd(t_uint64 val, uint32 *cc);
extern t_uint64 s_fltd(t_uint64 val, uint32 *cc);
extern uint32 s_nor(uint32 reg, uint32 *exp);
extern t_uint64 s_nord(t_uint64 reg, uint32 *exp);
extern uint32 s_adfw(uint32 reg, uint32 mem, uint32 *cc);
extern uint32 s_sufw(uint32 reg, uint32 mem, uint32 *cc);
extern t_uint64 s_adfd(t_uint64 reg, t_uint64 mem, uint32 *cc);
extern t_uint64 s_sufd(t_uint64 reg, t_uint64 mem, uint32 *cc);
extern uint32 s_mpfw(uint32 reg, uint32 mem, uint32 *cc);
extern t_uint64 s_dvfw(uint32 reg, uint32 mem, uint32 *cc);
extern uint32 s_mpfd(t_uint64 reg, t_uint64 mem, uint32 *cc);
extern t_uint64 s_dvfd(t_uint64 reg, t_uint64 mem, uint32 *cc);
/* History information */
int32 hst_p = 0; /* History pointer */
int32 hst_lnt = 0; /* History length */
struct InstHistory *hst = NULL; /* History stack */
/* CPU data structures
cpu_dev CPU device descriptor
cpu_unit CPU unit descriptor
cpu_reg CPU register list
cpu_mod CPU modifiers list
*/
UNIT cpu_unit =
/* Unit data layout for CPU */
/* { UDATA(rtc_srv, UNIT_BINK | MODEL(MODEL_27) | MEMAMOUNT(0), MAXMEMSIZE ), 120 }; */
{
NULL, /* UNIT *next */ /* next active */
NULL, /* t_stat (*action) */ /* action routine */
NULL, /* char *filename */ /* open file name */
NULL, /* FILE *fileref */ /* file reference */
NULL, /* void *filebuf */ /* memory buffer */
0, /* uint32 hwmark */ /* high water mark */
0, /* int32 time */ /* time out */
//was UNIT_BINK|MODEL(MODEL_27)|MEMAMOUNT(1), /* uint32 flags */ /* flags */
UNIT_IDLE|UNIT_BINK|MODEL(MODEL_27)|MEMAMOUNT(4), /* uint32 flags */ /* flags */
0, /* uint32 dynflags */ /* dynamic flags */
MAXMEMSIZE, /* t_addr capac */ /* capacity */
0, /* t_addr pos */ /* file position */
NULL, /* void (*io_flush) */ /* io flush routine */
0, /* uint32 iostarttime */ /* I/O start time */
0, /* int32 buf */ /* buffer */
80, /* int32 wait */ /* wait */
};
//UNIT cpu_unit = { UDATA (&rtc_srv, UNIT_BINK, MAXMEMSIZE) };
REG cpu_reg[] = {
{HRDATAD(PC, PC, 24, "Program Counter"), REG_FIT},
{BRDATAD(PSD, PSD, 16, 32, 2, "Program Status Doubleword"), REG_FIT},
{BRDATAD(GPR, GPR, 16, 32, 8, "Index registers"), REG_FIT},
{BRDATAD(BR, BR, 16, 32, 8, "Base registers"), REG_FIT},
{BRDATAD(BOOTR, BOOTR, 16, 32, 8, "Boot registers"), REG_FIT},
{BRDATAD(SPAD, SPAD, 16, 32, 256, "CPU Scratchpad memory"), REG_FIT},
{BRDATAD(MAPC, MAPC, 16, 32, 1024, "CPU map cache"), REG_FIT},
{BRDATAD(TLB, TLB, 16, 32, 2048, "CPU Translation Lookaside Buffer"), REG_FIT},
{HRDATAD(HIWM, HIWM, 32, "Max Maps Loaded"), REG_FIT},
{HRDATAD(BPIX, BPIX, 32, "# Maps Loaded for O/S"), REG_FIT},
{HRDATAD(CPIXPL, CPIXPL, 32, "Maximum Map # Loaded for User"), REG_FIT},
{HRDATAD(CPIX, CPIX, 32, "Current CPIX user MPL offset"), REG_FIT},
{HRDATAD(CPUSTATUS, CPUSTATUS, 32, "CPU Status Word"), REG_FIT},
{HRDATAD(TRAPSTATUS, TRAPSTATUS, 32, "TRAP Status Word"), REG_FIT},
{HRDATAD(CC, CC, 32, "Condition Codes"), REG_FIT},
{BRDATAD(INTS, INTS, 16, 32, 112, "Interrupt Status"), REG_FIT},
{HRDATAD(CMCR, CMCR, 32, "Cache Memory Control Register"), REG_FIT},
{HRDATAD(SMCR, SMCR, 32, "Shared Memory Control Register"), REG_FIT},
{HRDATAD(CMSMC, CMSMC, 32, "V9 Cache/Shadow Memory Configuration Word"), REG_FIT},
{HRDATAD(CSMCW, CSMCW, 32, "V9 CPU Shadow Memory Configuration Word"), REG_FIT},
{HRDATAD(ISMCW, ISMCW, 32, "V9 IPU Shadow Memory Configuration Word"), REG_FIT},
{HRDATAD(CCW, CCW, 32, "Computer Configuration Word"), REG_FIT},
{HRDATAD(CSW, CSW, 32, "Console Switches"), REG_FIT},
{NULL}
};
/* Modifier table layout (MTAB) - only extended entries have disp, reg, or flags */
MTAB cpu_mod[] = {
{
/* MTAB table layout for cpu type */
/* {UNIT_MODEL, MODEL(MODEL_55), "32/55", "32/55", NULL, NULL, NULL, "Concept 32/55"}, */
UNIT_MODEL, /* uint32 mask */ /* mask */
MODEL(MODEL_55), /* uint32 match */ /* match */
"32/55", /* cchar *pstring */ /* print string */
"32/55", /* cchar *mstring */ /* match string */
NULL, /* t_stat (*valid) */ /* validation routine */
NULL, /* t_stat (*disp) */ /* display routine */
NULL, /* void *desc */ /* value descriptor, REG* if MTAB_VAL, int* if not */
"Concept 32/55", /* cchar *help */ /* help string */
},
{UNIT_MODEL, MODEL(MODEL_75), "32/75", "32/75", NULL, NULL, NULL, "Concept 32/75"},
{UNIT_MODEL, MODEL(MODEL_27), "32/27", "32/27", NULL, NULL, NULL, "Concept 32/27"},
{UNIT_MODEL, MODEL(MODEL_67), "32/67", "32/67", NULL, NULL, NULL, "Concept 32/67"},
{UNIT_MODEL, MODEL(MODEL_87), "32/87", "32/87", NULL, NULL, NULL, "Concept 32/87"},
{UNIT_MODEL, MODEL(MODEL_97), "32/97", "32/97", NULL, NULL, NULL, "Concept 32/97"},
{UNIT_MODEL, MODEL(MODEL_V6), "V6", "V6", NULL, NULL, NULL, "Concept V6"},
{UNIT_MODEL, MODEL(MODEL_V9), "V9", "V9", NULL, NULL, NULL, "Concept V9"},
{
/* MTAB table layout for cpu memory size */
/* {UNIT_MSIZE, MEMAMOUNT(0), "128K", "128K", &cpu_set_size}, */
UNIT_MSIZE, /* uint32 mask */ /* mask */
MEMAMOUNT(0), /* uint32 match */ /* match */
"128K", /* cchar *pstring */ /* print string */
"128K", /* cchar *mstring */ /* match string */
&cpu_set_size, /* t_stat (*valid) */ /* validation routine */
NULL, /* t_stat (*disp) */ /* display routine */
NULL, /* void *desc */ /* value descriptor, REG* if MTAB_VAL, int* if not */
NULL, /* cchar *help */ /* help string */
},
{UNIT_MSIZE, MEMAMOUNT(1), "256K", "256K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(2), "512K", "512K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(3), "1M", "1M", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(4), "2M", "2M", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(5), "3M", "3M", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(6), "4M", "4M", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(7), "6M", "6M", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(8), "8M", "8M", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(9), "12M", "12M", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(10), "16M", "16M", &cpu_set_size},
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
{MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist},
{0}
};
/* CPU device descriptor */
DEVICE cpu_dev = {
/* "CPU", &cpu_unit, cpu_reg, cpu_mod,
1, 8, 24, 1, 8, 32,
&cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
NULL, DEV_DEBUG, 0, dev_debug,
NULL, NULL, &cpu_help, NULL, NULL, &cpu_description */
"CPU", /* cchar *name */ /* device name */
&cpu_unit, /* UNIT *units */ /* unit array */
cpu_reg, /* REG *registers */ /* register array */
cpu_mod, /* MTAB *modifiers */ /* modifier array */
1, /* uint32 numunits */ /* number of units */
16, /* uint32 aradix */ /* address radix */
32, /* uint32 awidth */ /* address width */
1, /* uint32 aincr */ /* address increment */
16, /* uint32 dradix */ /* data radix */
8, /* uint32 dwidth */ /* data width */
&cpu_ex, /* t_stat (*examine) */ /* examine routine */
&cpu_dep, /* t_stat (*deposit) */ /* deposit routine */
&cpu_reset, /* t_stat (*reset) */ /* reset routine */
NULL, /* t_stat (*boot) */ /* boot routine */
NULL, /* t_stat (*attach) */ /* attach routine */
NULL, /* t_stat (*detach) */ /* detach routine */
NULL, /* void *ctxt */ /* (context) device information block pointer */
DEV_DEBUG, /* uint32 flags */ /* device flags */
0, /* uint32 dctrl */ /* debug control flags */
dev_debug, /* DEBTAB *debflags */ /* debug flag name array */
NULL, /* t_stat (*msize) */ /* memory size change routine */
NULL, /* char *lname */ /* logical device name */
&cpu_help, /* t_stat (*help) */ /* help function */
NULL, /* t_stat (*attach_help) */ /* attach help function */
NULL, /* void *help_ctx */ /* Context available to help routines */
&cpu_description, /* cchar *(*description) */ /* Device description */
NULL, /* BRKTYPTB *brk_types */ /* Breakpoint types */
};
/* CPU Instruction decode flags */
#define INV 0x0000 /* Instruction is invalid */
#define HLF 0x0001 /* Half word instruction */
#define ADR 0x0002 /* Normal addressing mode */
#define IMM 0x0004 /* Immediate mode */
#define WRD 0x0008 /* Word addressing, no index */
#define SCC 0x0010 /* Sets CC */
#define RR 0x0020 /* Read source register */
#define R1 0x0040 /* Read destination register */
#define RB 0x0080 /* Read base register into dest */
#define SD 0x0100 /* Stores into destination register */
#define RNX 0x0200 /* Reads memory without sign extend */
#define RM 0x0400 /* Reads memory */
#define SM 0x0800 /* Stores memory */
#define DBL 0x1000 /* Double word operation */
#define SB 0x2000 /* Store Base register */
#define BT 0x4000 /* Branch taken, no PC incr */
#define SF 0x8000 /* Special flag */
int nobase_mode[] = {
/* 00 04 08 0C */
/* 00 ANR, ORR, EOR */
HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF,
/* 10 14 18 1C */
/* CAR, CMR, SBR ZBR */
HLF, HLF, HLF, HLF,
/* 20 24 28 2C */
/* ABR TBR REG TRR */
HLF, HLF, HLF, HLF,
/* 30 34 38 3C */
/* CALM LA ADR SUR */
HLF, SD|ADR, HLF, HLF,
/* 40 44 48 4C */
/* MPR DVR */
SCC|SD|HLF, HLF, HLF|INV, HLF|INV,
/* 50 54 58 5C */
/* */
HLF|INV, HLF|INV, HLF|INV, HLF|INV,
/* 60 64 68 6C */
/* NOR NORD SCZ SRA */
HLF, HLF, HLF, HLF,
/* 70 74 78 7C */
/* SRL SRC SRAD SRLD */
HLF, HLF, HLF, HLF,
/* 80 84 88 8C */
/* LEAR ANM ORM EOM */
SD|ADR, SD|RR|RNX|ADR, SD|RR|RNX|ADR, SD|RR|RNX|ADR,
/* 90 94 98 9C */
/* CAM CMM SBM ZBM */
SCC|RR|RM|ADR, RR|RM|ADR, ADR, ADR,
/* A0 A4 A8 AC */
/* ABM TBM EXM L */
ADR, ADR, ADR, SCC|SD|RM|ADR,
/* B0 B4 B8 BC */
/* LM LN ADM SUM */
// SCC|SD|RM|ADR, SCC|SD|RM|ADR, SCC|SD|RR|RM|ADR, SCC|SD|RR|RM|ADR,
SCC|SD|RM|ADR, SCC|SD|RM|ADR, SD|RR|RM|ADR, SD|RR|RM|ADR,
/* C0 C4 C8 CC */
/* MPM DVM IMM LF */
SCC|SD|RM|ADR, RM|ADR, IMM, ADR,
/* D0 D4 D8 DC */
/* LEA ST STM STF */
SD|ADR, RR|SM|ADR, RR|SM|ADR, ADR,
/* E0 E4 E8 EC */
/* ADF MPF ARM BCT */
ADR, ADR, SM|RR|RNX|ADR, ADR,
/* F0 F4 F8 FC */
/* BCF BI MISC IO */
ADR, RR|SD|WRD, ADR, IMM,
};
int base_mode[] = {
/* 00 04 08 0C */
/* 00 AND, OR, EOR */
// HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF,
HLF, R1|RR|SD|HLF, SCC|R1|RR|SD|HLF, SCC|R1|RR|SD|HLF,
/* 10 14 18 1C */
/* SACZ CMR xBR SRx */
HLF, HLF, HLF, HLF,
/* 20 24 28 2C */
/* SRxD SRC REG TRR */
HLF, HLF, HLF, HLF,
/* 30 34 38 3C */
/* LA FLRop SUR */
INV, INV, HLF, HLF,
/* 40 44 48 4C */
/* */
INV, INV, INV, INV,
/* 50 54 58 5C */
/* LA BASE BASE CALLM */
SD|ADR, SM|ADR, SB|ADR, RM|ADR,
/* 60 64 68 6C */
/* */
INV, INV, INV, INV,
/* 70 74 78 7C */
/* */
INV, INV, INV, INV,
/* LEAR ANM ORM EOM */
/* 80 84 88 8C */
SD|ADR, SD|RR|RNX|ADR, SD|RR|RNX|ADR, SD|RR|RNX|ADR,
/* CAM CMM SBM ZBM */
/* 90 94 98 9C */
SCC|RR|RM|ADR, RR|RM|ADR, ADR, ADR,
/* A0 A4 A8 AC */
/* ABM TBM EXM L */
ADR, ADR, ADR, SCC|SD|RM|ADR,
/* B0 B4 B8 BC */
/* LM LN ADM SUM */
// SCC|SD|RM|ADR, SCC|SD|RM|ADR, SCC|SD|RR|RM|ADR, SCC|SD|RR|RM|ADR,
SCC|SD|RM|ADR, SCC|SD|RM|ADR, SD|RR|RM|ADR, SD|RR|RM|ADR,
/* C0 C4 C8 CC */
/* MPM DVM IMM LF */
SCC|SD|RM|ADR, RM|ADR, IMM, ADR,
/* D0 D4 D8 DC */
/* LEA ST STM STFBR */
INV, RR|SM|ADR, RR|SM|ADR, ADR,
/* E0 E4 E8 EC */
/* ADF MPF ARM BCT */
ADR, ADR, SM|RR|RNX|ADR, ADR,
/* F0 F4 F8 FC */
/* BCF BI MISC IO */
ADR, RR|SD|WRD, ADR, IMM,
};
/* Map image descriptor 32/77 */
/* |--------------------------------------| */
/* |0|1|2|3 4 5 6|7 8 9 10 11 12 13 14 15| */
/* |N|V|P| n/u | 9 bit map block entry | */
/* |U| | | | 32kb/block | */
/* | | 32 8kb maps per task | */
/* | | 1 mb address space | */
/* |--------------------------------------| */
/* Map image descriptor 32/27 */
/* |--------------------------------------| */
/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */
/* |V|P|P|P|P| 11 bit map block entry | */
/* | |1|2|3|4| 8kb/block | */
/* | | 256 8kb maps per task | */
/* | | 2 mb address space | */
/* |--------------------------------------| */
/* Map image descriptor 32/67, 32/87, 32/97 */
/* |--------------------------------------| */
/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */
/* |V|P|P|P|P| 11 bit map block entry | */
/* | |1|2|3|4| 2kb/block | */
/* | | 2048 8kb maps per task | */
/* | | 16 mb address space | */
/* |--------------------------------------| */
/* BIT 0 = 0 Invalid map block (page) entry */
/* = 1 Valid map block (page) entry */
/* 1 = 0 000-7ff of 8kb page is not write protected */
/* = 1 000-7ff of 8kb page is write protected */
/* 2 = 0 800-fff of 8kb page is not write protected */
/* = 1 800-fff of 8kb page is write protected */
/* 3 = 0 1000-17ff of 8kb page is not write protected */
/* = 1 1000-17ff of 8kb page is write protected */
/* 4 = 0 1800-1fff of 8kb page is not write protected */
/* = 1 1800-1fff of 8kb page is write protected */
/* 5-15 = 11 most significant bits of the 24 bit real address for page */
/* Map image descriptor V6 & V9 */
/* |--------------------------------------| */
/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */
/* |V|P|P|M|M| 11 bit map block entry | */
/* | |1|2|M|A| 2kb/map | */
/* | | 2048 8kb maps per task | */
/* | | 16 mb address space | */
/* |--------------------------------------| */
/* BIT 0 = 0 Invalid map block (page) entry */
/* = 1 Valid map block (page) entry */
/* */
/* PSD 1 BIT 0 - Map Bit 1 - Map Bit 2 - Access state */
/* Priv Bits with ECO for Access Protection change */
/* 0 0 0 No access allowed to page */
/* 0 0 1 No access allowed to page */
/* 0 1 0 Read/Write/Execute access */
/* 0 1 1 Read/Execute access only */
/*O/S*/
/* 1 0 0 Read/Write/Execute access */
/* 1 0 1 Read/Execute access only */
/* 1 1 0 Read/Write/Execute access */
/* 1 1 1 Read/Execute access only */
/* Priv Bits without ECO for Access Protection change */
/* 0 0 0 No access allowed to page */
/* 0 0 1 Read/Execute access only */
/* 0 1 0 Read//Execute access only */
/* 0 1 1 Read/Write/Execute access */
/*O/S*/
/* 1 0 0 Read/Write/Execute only */
/* 1 0 1 Read/Execute access only */
/* 1 1 0 Read/Write/Execute access */
/* 1 1 1 Read/Write/Execute access */
/* */
/* BIT 3 = 0 (MM) A first write (modify) to the map block (page) has not occurred */
/* = 1 (MM) A first write (modify) to the map block (page) has occurred */
/* BIT 4 = 0 (MA) A first read or write (access) to the map block (page) has not occurred */
/* = 1 (MA) A first read or write (access) to the map block (page) has occurred */
/* 5-15 = 11 most significant bits of the 24 bit real address for page */
/* Note */
/* If a map is valid, a MAP (page) hit occurs and logical to physical translation occures */
/* If the map is not valid, a demand MAP (page) fault occures and the faulting page is provided */
/* P1 and P2 are used with Bit 0 of PSD to define the access rights */
/* A privilege violation trap occurres if access it denied */
/* Bits 5-15 contain the 11 most-significant bits of the physical address */
/* MSD 0 page limit is used to verify access to O/S pages */
/* CPIXPL page limit is used to verify access to user pages and page faults */
/* CPIX CPIX of user MPL offset */
/* Access to pages outside the limit registers results in a map fault */
#define MAX32 32 /* 32/77 map limit */
#define MAX256 256 /* 32/27 and 32/87 map limit */
#define MAX2048 2048 /* 32/67, V6, and V9 map limit */
/* set up the map registers for the current task in the cpu */
/* the PSD bpix and cpix are used to setup the maps */
/* return non-zero if mapping error */
/* if lmap set, always load maps on 67, 97, V6, and V7 */
/* The RMW and WMW macros are used to read/write memory words */
/* RMW(addr) or WMW(addr, data) where addr is a byte alligned word address */
/* The RMR and WMR macros are used to read/write the MAPC cache registers */
/* RMR(addr) or WMR(addr, data) where addr is a half word alligned address */
/* We will only get here if the retain maps bit is not set in PSD word 2 */
t_stat load_maps(uint32 thepsd[2], uint32 lmap)
{
uint32 num, sdc, spc, onlyos=0;
uint32 mpl, cpixmsdl, bpixmsdl, msdl, midl;
uint32 cpix, bpix, i, j, map, osmsdl, osmidl;
uint32 MAXMAP = MAX2048; /* default to 2048 maps */
sim_debug(DEBUG_CMD, &cpu_dev,
"Load Maps Entry PSD %08x %08x STATUS %08x lmap %01x CPU Mode %2x\n",
thepsd[0], thepsd[1], CPUSTATUS, lmap, CPU_MODEL);
/* process 32/7X computers */
if (CPU_MODEL < MODEL_27) {
MAXMAP = MAX32; /* 32 maps for 32/77 */
/* 32/7x machine, 8KW maps 32 maps total */
modes &= ~BASEBIT; /* no basemode on 7x */
if ((thepsd[1] & 0xc0000000) == 0) /* mapped mode? */
return ALLOK; /* no, all OK, no mapping required */
/* we are mapped, so load the maps for this task into the cpu map cache */
// cpix = (thepsd[1] >> 2) & 0xfff; /* get cpix 12 bit offset from psd wd 2 */
cpix = (thepsd[1]) & 0x3ffc; /* get cpix 12 bit offset from psd wd 2 */
// bpix = (thepsd[1] >> 18) & 0xfff; /* get bpix 12 bit offset from psd wd 2 */
bpix = (thepsd[1] >> 16) & 0x3ffc; /* get bpix 12 bit offset from psd wd 2 */
num = 0; /* working map number */
/* master process list is in 0x83 of spad for 7x */
// mpl = SPAD[0x83] >> 2; /* get mpl from spad address */
mpl = SPAD[0x83]; /* get mpl from spad address */
/* diags want the mpl entries checked to make sure valid dbl wowrd address */
if (mpl & 0x7) { /* test for double word address */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MPL not on double word boundry %06x\n", mpl);
TRAPSTATUS |= BIT20; /* set bit 20 of trap status */
return MAPFLT; /* not dbl bound, map fault error */
}
/* check if valid real address */
if ((mpl == 0) || ((mpl & MASK24) >= (MEMSIZE*4))) { /* see if in memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZE7 %06x mpl %06x invalid\n",
MEMSIZE*4, mpl);
TRAPSTATUS |= BIT18; /* set bit 18 of trap status */
return MAPFLT; /* no, map fault error */
// return NPMEM; /* no, none present memory error */
}
/* mpl is ok, get the msdl for given cpix */
// cpixmsdl = M[mpl + cpix]; /* get msdl from mpl for given cpix */
cpixmsdl = RMW(mpl+cpix); /* get msdl from mpl for given cpix */
/* if bit zero of mpl entry is set, use bpix first to load maps */
if (cpixmsdl & BIT0) {
/* load bpix maps first */
// bpixmsdl = M[mpl + bpix]; /* get msdl from mpl for given cpix */
bpixmsdl = RMW(mpl+bpix); /* get bpix msdl word address */
/* check for valid bpix msdl addr */
if ((bpixmsdl & MASK24) >= (MEMSIZE*4)) { /* see if in memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZE8 %06x bpix msdl %08x invalid\n",
MEMSIZE*4, bpixmsdl);
return NPMEM; /* no, none present memory error */
}
sdc = (bpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */
// msdl = (bpixmsdl >> 2) & MASK24; /* get 24 bit real address of msdl */
msdl = bpixmsdl & MASK24; /* get 24 bit real address of msdl */
/* check for valid msdl addr */
if ((msdl & MASK24) >= (MEMSIZE*4)) { /* see if in memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZE9 %06x msdl %08x invalid\n", MEMSIZE*4, msdl);
return NPMEM; /* no, none present memory error */
}
/* process all of the msdl's */
for (i = 0; i < sdc; i++) { /* loop through the msd's */
// spc = (M[msdl + i] >> 24) & 0xff; /* get segment page count from msdl */
spc = (RMW(msdl+i) >> 24) & 0xff; /* get segment page count from msdl */
// midl = (M[msdl + i] >> 2) & MASK24; /* get 24 bit real word address of midl */
midl = RMW(msdl+i) & MASK24; /* get 24 bit real word address of midl */
/* check for valid midl addr */
if ((midl & MASK24) >= (MEMSIZE*4)) { /* see if in memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZEa %06x midl %08x invalid\n", MEMSIZE*4, midl);
return NPMEM; /* no, none present memory error */
}
for (j = 0; j < spc; j++, num++) { /* loop throught the midl's */
uint32 pad = RMW(midl+(j<<1)); /* get page descriptor address */
if (num >= MAXMAP) {
TRAPSTATUS |= BIT5; /* set bit 5 of trap status */
return MAPFLT; /* map loading overflow, map fault error */
}
/* load 16 bit map descriptors */
map = RMH(pad); /* get 16 bit map entries */
WMR((num<<1), map); /* store the map reg contents into cache */
}
}
}
/* now load cpix maps */
/* check for valid cpix msdl addr */
if ((cpixmsdl & MASK24) >= (MEMSIZE*4)) { /* see if in memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZEb %06x cpix msdl %08x invalid\n", MEMSIZE*4, cpixmsdl);
return NPMEM; /* no, none present memory error */
}
sdc = (cpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */
// msdl = (cpixmsdl >> 2) & 0x3fffff; /* get 24 bit real address of msdl */
msdl = cpixmsdl & 0xffffff; /* get 24 bit real address of msdl */
/* check for valid msdl addr */
if ((msdl & MASK24) >= (MEMSIZE*4)) { /* see if in memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZEc %06x msdl %08x invalid\n", MEMSIZE*4, msdl);
return NPMEM; /* no, none present memory error */
}
/* process all of the msdl's */
for (i = 0; i < sdc; i++) {
// spc = (M[msdl + i] >> 24) & 0xff; /* get segment page count from msdl */
spc = (RMW(msdl+i) >> 24) & 0xff; /* get segment page count from msdl */
// midl = (M[msdl + i] >> 2) & 0x3fffff; /* get 24 bit real word address of midl */
midl = RMW(msdl+i) & MASK24; /* get 24 bit real word address of midl */
/* check for valid midl addr */
if ((midl & MASK24) >= (MEMSIZE*4)) { /* see if in memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZEd %06x midl %08x invalid\n", MEMSIZE*4, midl);
return NPMEM; /* no, none present memory error */
}
for (j = 0; j < spc; j++, num++) { /* loop through the midl's */
uint32 pad = RMW(midl+(j<<1)); /* get page descriptor address */
if (num >= MAXMAP) {
TRAPSTATUS |= BIT16; /* set bit 16 of trap status */
return MAPFLT; /* map loading overflow, map fault error */
}
/* load 16 bit map descriptors */
map = RMH(pad); /* get 16 bit map entries */
WMR((num<<1), map); /* store the map reg unmodified into cache */
}
}
/* if none loaded, map fault */
if (num == 0) {
TRAPSTATUS |= BIT16; /* set bit 16 of trap status */
return MAPFLT; /* attempt to load 0 maps, map fault error */
}
/* clear the rest of the previously used maps */
for (i = num; i < HIWM; i++) /* zero any remaining entries */
WMR((i<<1), 0); /* clear the map entry to make not valid */
HIWM = num; /* set new high water mark */
return ALLOK; /* all cache is loaded, return OK */
}
/****************** END-OF-32/7X-MAPPING ********************/
/* process a 32/27, 32/67, 32/87, 32/97, V6, or V9 here with 2KW (8kb) maps */
/* 32/27 & 32/87 have 256 maps. Others have 2048 maps */
/* 32/27 & 32/87 must have all maps preallocated and loaded */
/* 32/67 & 32/97 must load O/S maps and have user preallocated maps loaded on access */
/* V6 and V9 must load O/S maps and have user maps allocated and loaded on access */
/* See if any mapping to take place */
if ((modes & MAPMODE) == 0) /* mapped mode? */
return ALLOK; /* no, all OK, no mapping required */
/* set maximum maps for 32/27 and 32/87 processors */
if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87))
MAXMAP = MAX256; /* only 256 2KW (8kb) maps */
/* we are mapped, so load the map definitions */
cpix = thepsd[1] & 0x3ff8; /* get cpix 11 bit offset from psd wd 2 */
num = 0; /* no maps loaded yet */
/* master process list is in 0xf3 of spad for concept machines */
mpl = SPAD[0xf3]; /* get mpl from spad address */
/* diags want the mpl entries checked to make sure valid dbl wowrd address */
if (mpl & 0x7) { /* test for double word address */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MPL not on double word boundry %06x\n", mpl);
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT6; /* set bit 6 of trap status */
else
TRAPSTATUS |= BIT20; /* set bit 20 of trap status */
return MAPFLT; /* no, map fault error */
}
#ifdef DO_DYNAMIC_DEBUG
/* start debugging at test 46 of cn.mmm diag */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
/* check if valid real address */
mpl &= MASK24; /* clean mpl address */
if (mpl >= (MEMSIZE*4)) { /* see if in our real memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZE1 %06x mpl %06x invalid\n", MEMSIZE*4, mpl);
npmem:
BPIX = 0; /* no os maps loaded */
CPIXPL = 0; /* no user pages */
CPIX = cpix; /* save user CPIX */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
} else
TRAPSTATUS |= BIT10; /* set bit 8 of trap status */
return NPMEM; /* non present memory error */
}
/* output O/S and User MPX entries */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"#MEMORY %06x MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n",
MEMSIZE*4, mpl, RMW(mpl), RMW(mpl+4), cpix,
RMW(cpix+mpl), RMW(cpix+mpl+4));
sim_debug(DEBUG_DETAIL, &cpu_dev,
"MEMORY2 %06x BPIX %04x cpix %04x CPIX %04x CPIXPL %04x HIWM %04x\n",
MEMSIZE*4, BPIX, cpix, CPIX, CPIXPL, HIWM);
/* load the users regs first or the O/S. Verify the User MPL entry too. */
/* If bit zero of cpix mpl entry is set, use msd entry 0 first to load maps */
/* The load the user maps after the O/S */
/* If the cpix is zero, then only load the O/S. */
/* This test must be made to allow sysgen to run with a zero cpix */
/* If bit 0 of MPL[0] is 0, load the O/S maps. */
/* Do not load O/S if bit 0 of O/S MPL[0] s set. It is set by the */
/* swapper on MPX startup */
/* mpl is valid, get msdls for O/S and User */
osmidl = RMW(mpl); /* get O/S map count & retain flag from MPL[0] */
osmsdl = RMW(mpl+4); /* get msdl pointer for OS from MPL[1] */
midl = RMW(mpl+cpix); /* get midl entry for given user cpix */
msdl = RMW(mpl+cpix+4); /* get mpl entry wd 1 for given cpix */
spc = osmidl & MASK16; /* get 16 bit O/S segment description count */
/* see if we are to only load the O/S */
if (cpix == 0) {
CPIX = cpix; /* save CPIX */
onlyos = 1; /* flag to only load O/S, nothing else */
if (osmidl & BIT0) { /* see if the O/S retain bit 0 is on */
return ALLOK; /* O/S retain bit is set, no mapping required */
}
loados: /* merge point for loading O/S first */
/* to be followed by user maps */
/* the retain bit is not set so load the O/S */
if (spc > MAXMAP) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps bad O/S page count %04x, map fault\n", spc);
nomaps:
/* Bad map load count specified. */
BPIX = 0; /* no os maps loaded */
CPIXPL = 0; /* no user pages */
CPIX = cpix; /* save CPIX */
HIWM = 0; /* reset high water mark */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT5; /* set bit 5 of trap status */
else
TRAPSTATUS |= BIT16; /* set bit 16 of trap status */
return MAPFLT; /* map loading overflow, map fault error */
}
/* we have a valid count, load the O/S map list address */
osmsdl &= MASK24; /* get 24 bit real address from mpl 0 wd2 */
if (osmsdl >= (MEMSIZE*4)) { /* see if address is within our memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZE2 %06x os page list address %06x invalid\n",
MEMSIZE*4, osmsdl);
goto npmem; /* non present memory trap */
}
/* load the O/S maps */
for (j = 0; j < spc; j++, num++) { /* copy maps from msdl to map cache */
uint32 pad = osmsdl+(j<<1); /* get page descriptor address */
/* see if map overflow */
if (num >= MAXMAP) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps O/S page count overflow %04x, map fault\n", num);
goto nomaps; /* map overflow, map fault trap */
}
if (pad >= (MEMSIZE*4)) { /* see if address is within our memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZE3 %06x os page address %06x invalid\n",
MEMSIZE*4, pad);
goto npmem; /* non present memeory trap */
}
/* load 16 bit map descriptors */
map = RMH(pad); /* get page descriptor from memory */
/* for valid maps translate the map number to a real address */
/* put this address in the TLB for later translation */
/* copy the map status bits too and set hit bit in the TLB */
if (map & 0x8000) { /* see if map is valid */
TLB[num] = (((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000));
TLB[num] |= 0x04000000; /* set HIT bit for non lmap */
WMR((num<<1), map); /* store the map unmodified into cache */
} else {
TLB[num] = 0; /* clear the TLB for non valid maps */
}
if ((num < 0x20) || (num > (spc - 0x10)))
sim_debug(DEBUG_CMD, &cpu_dev,
"OS pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x MAPC %08x\n",
pad, map, num, map, (((map << 16) & 0xf8000000) | ((map & 0x7ff) << 13)),
TLB[num], MAPC[num/2]);
}
BPIX = num; /* save the # maps loaded in O/S */
CPIXPL = 0; /* no user pages */
if (!onlyos) /* see if only O/S to be loaded */
goto loaduser; /* no, go load the user maps */
for (i = BPIX; i < MAXMAP; i++) /* zero any remaining entries */
TLB[i] = 0; /* clear look aside buffer */
/* Only the O/S is to be loaded, finish up & return */
HIWM = num; /* set new high water mark */
return ALLOK; /* all cache is loaded, return OK */
}
/* The csect is not zero here, so see what we have to do */
/* See if O/S is to be loaded first because user MPL entry has BIT 0 set */
if (midl & BIT0) {
/* the user wants the O/S to load first, if the O/S retain bit set? */
if (osmidl & BIT0) { /* see if the O/S retain bit 0 is on */
num = spc; /* yes, set the number of O/S maps loaded */
BPIX = spc; /* save the # maps in O/S */
goto loaduser; /* load user map only or after O/S */
}
/* no retain bit, load user maps only, or after O/S */
/* validate O/S map count */
if (spc > MAXMAP) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps bad O/S page count %04x, map fault\n", spc);
goto nomaps; /* we have error, make way out */
}
/* see if any O/S maps to load */
if (spc == 0) {
BPIX = 0; /* no os maps loaded */
/* O/S page count is zero, so just load the user */
goto loaduser; /* load user map only or after O/S */
}
/* user wants to have O/S loaded first */
onlyos = 0; /* return to loaduser after loading O/S */
goto loados; /* go load the O/S */
}
/* the user wants to only load the user maps, no O/S maps are to be retained */
BPIX = 0; /* clear O/S loaded page count */
num = 0; /* nothing loaded yet */
/****************** END-OF-O/S-MAPPING ********************/
loaduser:
spc = midl & MASK16; /* get 16 bit User page count */
/* see if O/S has already loaded the MAXMAPS */
/* if borrow bit is on and cpix count is zero, return ok */
/* if borrow bit is on and cpix count not zero, map overflow error */
if (BPIX == MAXMAP) {
HIWM = num; /* set new high water mark */
CPIXPL = 0; /* no user pages */
if ((midl & BIT0) && (spc == 0)) { /* see if the user had borrow bit on */
sim_debug(DEBUG_CMD, &cpu_dev,
"load_maps @loaduser num %04x BPIX loaded %04x load done\n", num, BPIX);
return ALLOK; /* all cache is loaded, return OK */
}
else {
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps map overflow BPIX %04x count %04x, map fault\n", BPIX, spc);
goto nomaps; /* we have error, make way out */
}
}
/* the O/S has been loaded if requested or retained, so now load the user */
msdl &= MASK24; /* get 24 bit real word address of msdl */
/* This test fails cn.mmm diag at test 46, subtest 2 with unexpected error */
/* Do this test if we are a LMAP instruction and not a 32/27 or 32/87 */
if (lmap && (msdl >= (MEMSIZE*4))) { /* see if address is within our memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZE4 %06x user page list address %06x invalid\n",
MEMSIZE*4, msdl);
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
} else
TRAPSTATUS |= BIT28; /* set bit 28 of trap status */
return NPMEM; /* non present memory error */
}
/* We have a valid user MPL[cpix] address, msdl */
spc = midl & MASK16; /* get 16 bit User page count */
/* it is OK here to have no O/S maps loaded, num can be 0 */
if ((spc > MAXMAP) || ((spc+BPIX) > MAXMAP)) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps bad User page count %04x num %04x bpix %04x, map fault\n", spc, num, BPIX);
/* Bad map load count specified. */
BPIX = 0; /* no os maps loaded */
CPIXPL = 0; /* no user pages */
CPIX = cpix; /* save CPIX */
HIWM = 0; /* reset high water mark */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT5; /* set bit 5 of trap status */
else
TRAPSTATUS |= BIT16; /* set bit 16 of trap status */
return MAPFLT; /* map overflow fault error */
// goto nomaps; /* non presemt memory */
}
CPIX = cpix; /* save user MPL offset (cpix) */
CPIXPL = spc; /* save user map load count */
/* Load maps for 32/27 aand 32/87 */
if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) {
sim_debug(DEBUG_CMD, &cpu_dev,
"load_maps Processing 32/27 & 32/87 Model# %02x\n", CPU_MODEL);
/* handle non virtual page loading or diag LMAP instruction */
/* do 32/27 and 32/87 that force load all maps */
/* now load user maps specified by the cpix value */
for (j = 0; j < spc; j++, num++) { /* copy maps from midl to map cache */
uint32 pad = msdl+(j<<1); /* get page descriptor address */
/* see if map overflow */
if (num >= MAXMAP) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps User page count overflow %04x, map fault\n", num);
TRAPSTATUS |= BIT16; /* set bit 16 of trap status */
goto nomaps; /* map overflow, map fault trap */
}
if (pad >= (MEMSIZE*4)) { /* see if address is within our memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZE5 %06x User page address %06x invalid\n",
MEMSIZE*4, pad);
goto npmem; /* non present memeory trap */
}
/* load 16 bit map descriptors */
map = RMH(pad); /* get page descriptor from memory */
/* for valid maps translate the map number to a real address */
/* put this address in the TLB for later translation */
/* copy the map status bits too and set hit bit in the TLB */
/* leaving out diags in next statment fails test3/1 of vm.mmm */
if ((map & 0x8000)) { /* see if map is valid */
TLB[num] = (((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000));
TLB[num] |= 0x04000000; /* set HIT bit on */
} else
TLB[num] = 0; /* clear the TLB for non valid maps */
WMR((num<<1), map); /* store map unmodified into cache */
/* do partial map dump */
if ((num < 0x20) || (num > (spc+BPIX) - 0x10))
sim_debug(DEBUG_DETAIL, &cpu_dev,
"UserN pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x, MAPC %08x\n",
pad, map, num, map, (((map << 16) & 0xf8000000) | ((map & 0x7ff) << 13)),
TLB[num], MAPC[num/2]);
}
if (num == 0) { /* see if any maps loaded */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps1 No maps loaded %04x, map fault\n", num);
goto nomaps; /* return map fault error */
}
/* All maps are now loaded, finish up & return */
for (i = num; i < MAXMAP; i++) /* zero any remaining TLB entries */
TLB[i] = 0; /* clear look aside buffer */
HIWM = num; /* set new high water mark */
return ALLOK; /* all cache is loaded, return OK */
}
/**************END-OF-NON-VIRTUAL-USER-MAPPING-FOR-27-87************/
/* handle load on memory access case for 67, 97, V6 & V9 */
/* now clear TLB & maps specified by the cpix value */
for (j = 0; j < spc; j++, num++) { /* clear maps in map cache */
uint32 pad = msdl+(j<<1); /* get page descriptor address */
/* if this is a LPSDCM instruction, just clear the TLB entry */
if (!lmap) {
/* load 16 bit map descriptors */
map = RMH(pad); /* get page descriptor from memory */
if ((num < 0x20) || (num > (spc+BPIX) - 0x10))
sim_debug(DEBUG_DETAIL, &cpu_dev,
"UserV pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x, MAPC %08x\n",
pad, map, num, map, (((map << 16) & 0xf8000000)|(map & 0x7ff)<<13)|0x04000000,
TLB[num], MAPC[num/2]);
TLB[num] = 0; /* clear the TLB for non valid maps */
continue; /* just clear the TLBs */
}
/* only do the following tests for LMAP instruction, not LPSDCM */
/* see if map overflow */
if (num >= MAXMAP) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps User page count overflow %04x, map fault\n", num);
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT5; /* set bit 5 of trap status */
else
TRAPSTATUS |= BIT16; /* set bit 16 of trap status */
goto nomaps; /* map overflow, map fault trap */
}
if (pad >= (MEMSIZE*4)) { /* see if address is within our memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps MEM SIZE6 %06x User page address %06x non present\n",
MEMSIZE*4, pad);
goto npmem; /* non present memeory trap */
}
/* load 16 bit map descriptors */
map = RMH(pad); /* get page descriptor from memory */
if (lmap) {
TLB[num] = (((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000));
TLB[num] |= 0x04000000; /* set HIT bit for lmap */
/* removing this store of map fails test 2 on 97 */
WMR((num<<1), map); /* store the map unmodified into cache */
}
if ((num < 0x20) || (num > (spc+BPIX) - 0x10))
sim_debug(DEBUG_DETAIL, &cpu_dev,
"UserV2 pad %06x=%04x map #%4x, %04x, map2 %08x, TLB %08x, MAPC %08x\n",
pad, map, num, map, (((map << 16) & 0xf8000000)|(map & 0x7ff)<<13)|0x04000000,
TLB[num], MAPC[num/2]);
}
if (num == 0) { /* see if any maps loaded */
sim_debug(DEBUG_TRAP, &cpu_dev,
"load_maps2 No maps loaded %04x, map fault\n", num);
goto nomaps;
}
/* All maps are now loaded, finish up & return */
/* removing this code causes diag to stop at 17/0 for 97 in cn.mmm */
for (i = num; i < MAXMAP; i++) /* zero any remaining entries */
TLB[i] = 0; /* clear look aside buffer */
HIWM = num; /* set new high water mark */
return ALLOK; /* all cache is loaded, return OK */
/****************** END-OF-VIRTUAL-USER-MAP-LOADING ********************/
}
/*
* Return the real memory address from the logical address
* Also return the protection status, 1 if write protected address.
* For 67, 97, V6, & V9 return all protection bits.
* Addr is a byte address.
*/
t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot, uint32 access)
{
uint32 word, index, map, raddr, mpl, offset;
uint32 nix, msdl, mix;
*prot = 0; /* show unprotected memory as default */
/* unmapped mode is unprotected */
/*****************START-7X-ADDRESS-PROCESSING****************/
/* see what machine we have */
if (CPU_MODEL < MODEL_27) {
/* 32/7x machine with 8KW maps */
if (modes & EXTDBIT)
word = addr & 0xfffff; /* get 20 bit logical word address */
else
word = addr & 0x7ffff; /* get 19 bit logical word address */
if ((modes & MAPMODE) == 0) {
/* check if valid real address */
if (word >= (MEMSIZE*4)) { /* see if address is within our memory */
return NPMEM; /* no, none present memory error */
}
*realaddr = word; /* return the real address */
return ALLOK; /* all OK, return instruction */
}
/* we are mapped, so calculate real address from map information */
/* 32/7x machine, 8KW maps */
index = word >> 15; /* get 4 or 5 bit value */
map = RMR((index<<1)); /* read the map reg cache contents */
/* see if map is valid */
if ((map & 0x4000) == 0)
/* map is invalid, so return map fault error */
return MAPFLT; /* map fault error */
/* required map is valid, get 9 bit address and merge with 15 bit page offset */
word = ((map & 0x1ff) << 15) | (word & 0x7fff);
/* check if valid real address */
if (word >= (MEMSIZE*4)) /* see if address is within our memory */
return NPMEM; /* no, none present memory error */
if ((modes & PRIVBIT) == 0) { /* see if we are in unprivileged mode */
if (map & 0x2000) /* check if protect bit is set in map entry */
*prot = 1; /* return memory write protection status */
}
*realaddr = word; /* return the real address */
return ALLOK; /* all OK, return instruction */
}
/*****************END-OF-7X-ADDRESS-PROCESSING****************/
/* Everyone else has 2KW maps */
/* do common processing */
/* diag wants the address to be 19 or 24 bit, use masked address */
if (modes & (BASEBIT | EXTDBIT))
word = addr & 0xffffff; /* get 24 bit address */
else
word = addr & 0x7ffff; /* get 19 bit address */
if ((modes & MAPMODE) == 0) {
/* we are in unmapped mode, check if valid real address */
if (word >= (MEMSIZE*4)) { /* see if address is within our memory */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
if (access == MEM_RD)
TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
if (access == MEM_WR)
TRAPSTATUS |= BIT2; /* set bit 2 of trap status */
} else {
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
}
return NPMEM; /* no, none present memory error */
}
*realaddr = word; /* return the real address */
return ALLOK; /* all OK, return instruction */
}
mpl = SPAD[0xf3] & MASK24; /* get 24 bit dbl wd mpl from spad address */
/* did not get expected machine check trap for */
/* 27, 87, 67 in test 37/0 if code removed */
/* unexpected machine check trap for 67 in test 37/0 cn.mmm */
/* now check the O/S midl pointer for being valid */
/* we may want to delay checking until we actually use it */
if ((RMW(mpl+4) & MASK24) >= (MEMSIZE*4)) { /* check OS midl */
sim_debug(DEBUG_TRAP, &cpu_dev,
"RealAddr Non Present Memory O/S msdl MPL %06x MPL[1] %06x\n",
mpl, RMW(mpl+4));
if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) {
// 32/27, 32/87 want MACHINECHK for test 37/1 in CN.MMM
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
return MACHINECHK_TRAP; /* diags want machine check error */
} else
if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6)) {
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
return MAPFLT; /* map fault error */
}
else
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
// V9 & 32/97 wants MACHINECHK for test 37/1 in CN.MMM & VM.MMM */
TRAPSTATUS |= BIT7; /* set bit 7 of trap status */
TRAPSTATUS |= BIT28; /* set bit 28 of trap status */
return MACHINECHK_TRAP; /* diags want machine check error */
}
}
/* we are mapped, so calculate real address from map information */
/* get 11 bit page number from address bits 8-18 */
index = (word >> 13) & 0x7ff; /* get 11 bit page value */
offset = word & 0x1fff; /* get 13 bit page offset */
/* make sure map index is valid */
if (index >= (BPIX + CPIXPL)) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"RealAddr %06x word %06x loadmap gets mapfault index %04x B(%x)+C(%x) %04x\n",
word, addr, index, BPIX, CPIXPL, BPIX+CPIXPL);
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT5; /* set bit 5 of trap status */
else
TRAPSTATUS |= BIT16; /* set bit 16 of trap status */
return MAPFLT; /* map fault error */
}
/* continue processing non virtual machines here 32/27 & 32/87 */
/* at this point all maps have been force loaded in load_maps */
/* just do the conversion from logical to real address */
if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) {
map = RMR((index<<1)); /* read the map reg cache contents */
raddr = TLB[index]; /* get the base address & bits */
#ifndef MAYBE_NOT_NEEDED
if ((RMW(mpl+CPIX+4) & MASK24) >= (MEMSIZE*4)) { /* check user midl */
sim_debug(DEBUG_TRAP, &cpu_dev,
"RealAddr 27 & 87 map fault index %04x B+C %04x map %04x TLB %08x\n",
index, BPIX+CPIXPL, map, TLB[index]);
// 32/27 & 32/87 want MACHINECHK for test 37/1 in CN.MMM
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
return MACHINECHK_TRAP; /* diags want machine check error */
}
#endif
if (((map & 0x8000) == 0) || ((raddr & BIT0) == 0)) { /* see if valid map */
sim_debug(DEBUG_TRAP, &cpu_dev,
"RealAddr loadmap 0a map fault index %04x B+C %04x map %04x TLB %08x\n",
index, BPIX+CPIXPL, map, TLB[index]);
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
return MAPFLT; /* no, map fault error */
}
// diag test 34/1 fails in cn.mmm
// needed for 32/27 & 32/87
/* check if valid real address */
if ((raddr & MASK24) >= (MEMSIZE*4)) { /* see if address is within our memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"RealAddr loadmap 0c non present memory fault addr %06x raddr %08x index %04x\n",
word, raddr, index);
TRAPSTATUS |= BIT28; /* set bit 28 of trap status */
return NPMEM; /* no, none present memory error */
}
word = (raddr & 0xffe000) | offset; /* combine real addr and offset */
*realaddr = word; /* return the real address */
if (modes & BIT0) /* all OK if privledged */
return ALLOK; /* all OK, return instruction */
/* get user protection status of map */
offset = (word >> 11) & 0x3; /* see which 1/4 page we are in */
if ((BIT1 >> offset) & raddr) { /* is 1/4 page write protected */
*prot = 1; /* return memory write protection status */
}
sim_debug(DEBUG_DETAIL, &cpu_dev,
"RealAddrRa address %08x, TLB %08x MAPC[%03x] %08x wprot %02x prot %02x\n",
word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot);
return ALLOK; /* all OK, return instruction */
}
/*****************END-OF-27-87-ADDRESS-PROCESSING****************/
/* handle 32/67, 32/97 and V6 & V9 here */
/* Concept 32 machine, 2KW maps */
/* the index is less than B+C, so setup to get a map */
if (TLB[index] & 0x04000000) { /* is HIT bit on in TLB */
/* handle HIT bit already on in TLB here */
/* diags wants a NPMEM error if physical addr is exceeded */
index &= 0x7ff; /* map # */
raddr = TLB[index]; /* get the base address & bits */
/* check if valid real address */
if ((raddr & MASK24) >= (MEMSIZE*4)) { /* see if address is within our memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"RealAddr loadmap 2a non present memory fault addr %08x raddr %08x index %04x\n",
addr, raddr, index);
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
#ifndef TRY_AGAIN
if (access == MEM_RD)
TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
else
if (access == MEM_WR)
TRAPSTATUS |= BIT2; /* set bit 2 of trap status */
/* returning this error fixes 34/2, but still fails 46/2 */
return NPMEM; /* none present memory error */
#else
TRAPSTATUS |= BIT7; /* set bit 7 of trap status */
TRAPSTATUS |= BIT12; /* set bit 12 of trap status */
/* returning this error fails test 34/2 of mmm diag */
return MAPFLT; /* map fault error on memory access */
#endif
/*NEW*/// return MAPFLT; /* map fault error on memory access */
/* returning this error fails test 34/2 of mmm diag */
/*NEW*/// return MACHINECHK_TRAP; /* diags want machine check error */
} else
TRAPSTATUS |= BIT28; /* set bit 28 of trap status */
return NPMEM; /* none present memory error */
}
map = RMR((index<<1)); /* read the map reg contents */
word = (raddr & 0xffe000) | offset; /* combine map and offset */
*realaddr = word; /* return the real address */
/* handle 32/67 & 32/97 protection here */
if (CPU_MODEL < MODEL_V6) {
/* process 32/67 & 32/97 load map on access */
/* handle 32/67 & 32/97 */
if (modes & BIT0) /* all OK if privledged */
return ALLOK; /* all OK, return instruction */
/* get protection status of map */
offset = (word >> 11) & 0x3; /* see which 1/4 page we are in */
if ((BIT1 >> offset) & raddr) { /* is 1/4 page write protected */
*prot = 1; /* return memory write protection status */
}
sim_debug(DEBUG_DETAIL, &cpu_dev,
"RealAddrR address %08x, TLB %08x MAPC[%03x] %08x wprot %02x prot %02x\n",
word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot);
return ALLOK; /* all OK, return instruction */
}
/* handle valid V6 & V9 HIT bit on */
/* get protection status of map */
offset = ((map >> 12) & 0x6); /* get bits p1 & p2 from map into bits 13 & 14 */
if (modes & BIT0) /* all access if privledged */
*prot = offset | 0x8; /* set priv bit */
else
*prot = offset; /* return memory write protection status */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"RealAddrX address %06x, TLB %06x MAPC[%03x] %08x wprot %02x prot %02x\n",
word, TLB[index], index/2, MAPC[index/2], (word>>11)&3, *prot);
return ALLOK; /* all OK, return instruction */
}
/* Hit bit is off in TLB, so lets go get some maps */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"$MEMORY %06x HIT MPL %06x MPL[0] %08x %06x MPL[%04x] %08x %06x\n",
MEMSIZE*4, mpl, RMW(mpl), RMW(mpl+4), CPIX, RMW(CPIX+mpl), RMW(CPIX+mpl+4));
/* check user msdl address now that we are going to access it */
msdl = RMW(mpl+CPIX+4); /* get msdl entry for given CPIX */
if ((msdl & MASK24) >= (MEMSIZE*4)) { /* check user midl */
sim_debug(DEBUG_TRAP, &cpu_dev,
"RealAddr User CPIX Non Present Memory User msdl %06x CPIX %04x\n",
msdl, CPIX);
if (CPU_MODEL == MODEL_67) {
/* test 37/0 wants MAPFLT trap for 67 */
TRAPSTATUS |= BIT28; /* set bit 28 of trap status */
return MAPFLT; /* map fault error on memory access */
} else
if (CPU_MODEL == MODEL_97) {
// 32/97 wants MAPFLT for test 37/1 in CN.MMM
TRAPSTATUS |= BIT12; /* set bit 12 of trap status */
return MAPFLT; /* no, map fault error */
/*TRY*/// return NPMEM; /* no, none present memory error */
/*TRY*/// return MACHINECHK_TRAP; /* diags want machine check error */
/*TRY*/// return SYSTEMCHK_TRAP; /* diags want machine check error */
/*TRY*/// return PRIVVIOL_TRAP; /* set the trap to take */
// if (access == MEM_RD)
// TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
// else
// if (access == MEM_WR)
// TRAPSTATUS |= BIT2; /* set bit 2 of trap status */
// return MAPFLT; /* no, map fault error */
// return MACHINECHK_TRAP; /* diags want machine check error */
// return NPMEM; /* no, none present memory error */
} else
if (CPU_MODEL == MODEL_V6) {
// V6 wants MAPFLT for test 37/1 in CN.MMM & VM.MMM */
TRAPSTATUS |= BIT28; /* set bit 28 of trap status */
/* OK for V6 */
return MAPFLT; /* map fault error */
}
else
if (CPU_MODEL == MODEL_V9) {
/* V9 wants MAPFLT for test 37/1 in CN.MMM & VM.MMM */
/* V9 fails test 46/subtest 2 with "did not get expected map trap */
TRAPSTATUS |= BIT12; /* set bit 12 of trap status */
return MAPFLT; /* map fault error */
// if (access == MEM_RD)
// TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
// else
// if (access == MEM_WR)
// TRAPSTATUS |= BIT2; /* set bit 2 of trap status */
// return MAPFLT; /* map fault error */
// if (access == MEM_RD)
// TRAPSTATUS |= 0x40000000; /* set bit 0 of trap status */
// else
// if (access == MEM_WR)
// TRAPSTATUS |= 0x20000000; /* set bit 1 of trap status */
// return NPMEM; /* no, none present memory error */
// return MACHINECHK_TRAP; /* diags want machine check error */
}
}
/* get os or user msdl, index < BPIX; os, else user */
if (index < BPIX)
msdl = RMW(mpl+4); /* get mpl entry wd 1 for os */
else
/* check user msdl address now that we are going to access it */
msdl = RMW(mpl+CPIX+4); /* get mpl entry wd 1 for given cpix */
/* HIT bit is off, we must load the map entries from memory */
/* turn on the map hit flag if valid and set maps real base addr */
nix = index & 0x7ff; /* map # or mapc index */
word = (TLB[nix] & 0xffe000) | offset; /* combine map and offset */
if (index < BPIX)
mix = nix; /* get map index in memory */
else
mix = nix-BPIX; /* get map index in memory */
map = RMH(msdl+(mix<<1)); /* map content from memory */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Addr %06x RealAddr %06x Map0[%04x] HIT %04x TLB[%3x] %08x MAPC[%03x] %08x\n",
addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]);
/* process HIT bit off V6 & V9 here */
if ((map & 0x8000) == 0) {
/* for V6 & V9 handle demand paging */
if (CPU_MODEL >= MODEL_V6) {
/* map is not valid, so we have map fault */
sim_debug(DEBUG_TRAP, &cpu_dev,
"AddrMa %06x RealAddr %06x Map0 HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n",
addr, word, map, nix, TLB[nix], nix/2, MAPC[nix/2]);
/* do a demand page request for the required page */
pfault = nix; /* save page number */
sim_debug(DEBUG_TRAP, &cpu_dev,
"Mem_write Daddr2 %06x page %04x demand page bits set TLB %08x map %04x\n",
addr, nix, TLB[nix], map);
return DMDPG; /* demand page request */
}
/* handle 67 & 97 map invalid here */
if (CPU_MODEL == MODEL_97) {
if (access == MEM_RD)
TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
else
if (access == MEM_WR)
TRAPSTATUS |= BIT2; /* set bit 2 of trap status */
} else
TRAPSTATUS |= BIT28; /* set bit 28 of trap status */
return MAPFLT; /* map fault error */
}
/* map is valid, process it */
TLB[nix] = ((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000) | 0x04000000;
word = (TLB[nix] & 0xffe000) | offset; /* combine map and offset */
WMR((nix<<1), map); /* store the map reg contents into MAPC cache */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"RealAddrm RMH %04x mix %04x TLB[%04x] %08x B+C %04x RMR[nix] %04x\n",
map, mix, nix, TLB[nix], BPIX+CPIXPL, RMR(nix<<1));
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Addr1c %06x RealAddr %06x Map1[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x RMR %04x\n",
addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2], RMR(nix<<1));
*realaddr = word; /* return the real address */
raddr = TLB[nix]; /* get the base address & bits */
if ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_97)) {
/* get protection status of map */
if ((modes & BIT0) == 0) { /* OK if privledged */
/* otherwise check protection bit */
offset = (word >> 11) & 0x3; /* see which 1/4 page we are in */
if ((BIT1 >> offset) & raddr) /* is 1/4 page write protected */
*prot = 1; /* return memory write protection status */
}
} else {
/* get protection status of map */
offset = ((map >> 12) & 0x6); /* get bits p1 & p2 from map into bits 13 & 14 */
if (modes & BIT0) /* all access if privledged */
*prot = offset | 0x8; /* set priv bit */
else
*prot = offset; /* return memory write protection status */
}
/* now do the other halfword of the memory map pair */
/* calc index of previous or next halfword */
if ((mix & 1) == 0) {
mix += 1; /* we are at lf hw, so do next hw */
nix += 1; /* point to next map in MAPC */
/* This is really a firmware error where the CPU loads the */
/* right halfword map information even though it exceeds */
/* the allowed map count. It does not hurt anything, so OK */
/* 32/67 & V6 allow loading the extra rt hw map entry */
if ((nix == BPIX) || (nix > (BPIX+CPIXPL)))
return ALLOK; /* no other map is valid, we are done */
} else
if ((mix & 1) == 1) {
if (nix == BPIX)
return ALLOK; /* no other map is valid, we are done */
mix -= 1; /* we are at rt hw, so backup hw */
nix -= 1; /* point to last map in MAPC */
}
sim_debug(DEBUG_DETAIL, &cpu_dev,
"RealAddrp mix %04x nix %04x TLB[%04x] %08x B+C %04x RMR[nix] %04x\n",
mix, nix, nix, TLB[nix], BPIX+CPIXPL, RMR(nix<<1));
/* allow the excess map entry to be loaded, even though bad */
if (nix <= (BPIX+CPIXPL)) { /* needs to be a mapped reg */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Addr1d BPIX %03x CPIXPL %03x RealAddr %06x TLB[%3x] %08x MAPC[%03x] %08x RMR %04x\n",
BPIX, CPIXPL, word, nix, TLB[nix], nix/2, MAPC[nix/2], RMR(nix<<1));
/* mix & nix has other map correct index */
if ((TLB[nix] & 0x04000000) == 0) { /* is HIT bit already on */
/* hit not on, so load the map */
/* allow the excess map entry to be loaded, even though bad */
if (nix <= (BPIX+CPIXPL)) { /* needs to be a mapped reg */
map = RMH(msdl+(mix<<1)); /* map content from memory */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Addr2a %06x MapX[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n",
addr, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]);
if (map & 0x8000) { /* must be valid to load */
/* setting access bit fails test 15/0 in vm.mmm diag */
TLB[nix] = ((map & 0x7ff) << 13) | ((map << 16) & 0xf8000000) | 0x04000000;
word = (TLB[nix] & 0xffe000); /* combine map and offset */
WMR((nix<<1), map); /* store the map reg contents into MAPC cache */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Addr2b %06x RealAddr %06x Map2[%04x] HIT %04x, TLB[%3x] %08x MAPC[%03x] %08x\n",
addr, word, mix, map, nix, TLB[nix], nix/2, MAPC[nix/2]);
}
}
}
}
/*****************END-OF-V6-V9-ADDRESS-HIT-PROCESSING****************/
/*****************END-OF-67-97-ADDRESS-HIT-PROCESSING****************/
return ALLOK; /* all OK, return instruction */
}
/* fetch the current instruction from the PC address */
t_stat read_instruction(uint32 thepsd[2], uint32 *instr)
{
uint32 status, addr;
if (CPU_MODEL < MODEL_27) {
/* 32/7x machine with 8KW maps */
/* instruction must be in first 512KB of address space */
addr = thepsd[0] & 0x7fffc; /* get 19 bit logical word address */
} else {
/* 32/27, 32/67, 32/87, 32/97 2KW maps */
/* Concept 32 machine, 2KW maps */
if (thepsd[0] & BASEBIT) { /* bit 6 is base mode? */
addr = thepsd[0] & 0xfffffc; /* get 24 bit address */
}
else
addr = thepsd[0] & 0x7fffc; /* get 19 bit address */
}
/* go read the memory location */
status = Mem_read(addr, instr);
if ((status == MAPFLT) && (TRAPSTATUS == BIT1)) {
/* if map fault on read, change code to read instruction */
TRAPSTATUS &= ~BIT1; /* clear error on read memory */
TRAPSTATUS |= BIT0; /* set error on instruction read */
} else
if (status == DMDPG)
pfault |= 0x80000000; /* set instruction fetch paging error */
sim_debug(DEBUG_DETAIL, &cpu_dev, "read_instr status %02x @ %06x\n", status, addr);
return status; /* return ALLOK or ERROR status */
}
/*
* Read a full word from memory
* Return error type if failure, ALLOK if
* success. Addr is logical byte address.
*/
t_stat Mem_read(uint32 addr, uint32 *data)
{
uint32 status, realaddr, prot, page, map, mix, nix, msdl, mpl, nmap;
status = RealAddr(addr, &realaddr, &prot, MEM_RD); /* convert address to real physical address */
// if (addr != realaddr)
//sim_debug(DEBUG_EXP, &cpu_dev,
//"At Mem_read convert %06x to addr %08x\n", addr, realaddr);
if (status == ALLOK) {
// *data = M[realaddr >> 2]; /* valid address, get physical address contents */
*data = RMW(realaddr); /* valid address, get physical address contents */
if (((CPU_MODEL >= MODEL_V6) || (CPU_MODEL == MODEL_97) ||
(CPU_MODEL == MODEL_67)) && (modes & MAPMODE)) {
page = (addr >> 13) & 0x7ff; /* get 11 bit value */
if (CPU_MODEL >= MODEL_V6) {
/* check for v6 & v9 if we have read access */
switch (prot & 0x0e) {
case 0x0: case 0x2:
/* O/S or user has no read/execute access, do protection violation */
sim_debug(DEBUG_EXP, &cpu_dev,
"Mem_readA protect error @ %06x prot %02x modes %08x page %04x\n",
addr, prot, modes, page);
if (CPU_MODEL == MODEL_V9)
TRAPSTATUS |= BIT2; /* set bit 2 of trap status */
else
TRAPSTATUS &= ~BIT12; /* clear bit 12 of trap status */
return MPVIOL; /* return memory protection violation */
case 0x4: case 0x6: case 0x8: case 0xa: case 0xc: case 0xe:
/* O/S or user has read/execute access, no protection violation */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Mem_readB protect is ok @ %06x prot %02x modes %08x page %04x\n",
addr, prot, modes, page);
}
mpl = SPAD[0xf3]; /* get mpl from spad address */
nix = page & 0x7ff; /* map # or mapc index */
if (page < BPIX) {
mix = nix; /* get map index in memory */
msdl = RMW(mpl+4); /* get mpl entry for o/s */
} else {
mix = nix-BPIX; /* get map index in memory */
msdl = RMW(mpl+CPIX+4); /* get mpl entry for given cpix */
}
nmap = RMH(msdl+(mix<<1)); /* map content from memory */
map = RMR((page<<1)); /* read the map reg contents */
/* if I remove this test, we fail at test 14/0 */
if (((map & 0x800) == 0)) {
map |= 0x800; /* set the accessed bit in the map cache entry */
WMR((page<<1), map); /* store the map reg contents into cache */
TLB[page] |= 0x0c000000; /* set the accessed bit in TLB too */
WMH(msdl+(mix<<1), map); /* save modified map with access bit set */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Mem_read Yaddr %06x page %04x set access bit TLB %08x map %04x nmap %04x\n",
addr, page, TLB[page], map, nmap);
}
}
/* everybody else has read access */
}
sim_debug(DEBUG_DETAIL, &cpu_dev, "Mem_read addr %06x realaddr %08x data %08x prot %02x\n",
addr, realaddr, *data, prot);
} else {
/* RealAddr returned an error */
sim_debug(DEBUG_EXP, &cpu_dev, "Mem_read error addr %.8x realaddr %.8x data %.8x prot %02x status %04x\n",
addr, realaddr, *data, prot, status);
if (status == NPMEM) { /* operand nonpresent memory error */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
} else
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
}
if (status == MAPFLT) {
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT12; /* set bit 12 of trap status */
else
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
}
sim_debug(DEBUG_EXP, &cpu_dev, "Mem_read error %02x @ %06x TRAPSTATUS %08x\n",
status, addr, TRAPSTATUS);
}
return status; /* return ALLOK or ERROR status */
}
/*
* Write a full word to memory, checking protection
* and alignment restrictions. Return 1 if failure, 0 if
* success. Addr is logical byte address, data is 32bit word
*/
t_stat Mem_write(uint32 addr, uint32 *data)
{
uint32 status, realaddr=0, prot=0, raddr, page, nmap, msdl, mpl, map, nix, mix;
status = RealAddr(addr, &realaddr, &prot, MEM_WR); /* convert address to real physical address */
if (prot) {
sim_debug(DEBUG_DETAIL, &cpu_dev, "Mem_write addr %.8x realaddr %.8x data %.8x prot %02x\n",
addr, realaddr, *data, prot);
}
if (status == ALLOK) {
if (((CPU_MODEL >= MODEL_V6) || (CPU_MODEL == MODEL_97) ||
(CPU_MODEL == MODEL_67)) && (modes & MAPMODE)) {
page = (addr >> 13) & 0x7ff; /* get 11 bit value */
if (CPU_MODEL >= MODEL_V6) {
/* check for v6 & v9 if we have write access */
switch (prot &0x0e) {
case 0x0: case 0x2: case 0x6: case 0xa: case 0xe:
/* O/S or user has read/execute access, do protection violation */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Mem_writeA protect error @ %06x prot %02x modes %08x\n", addr, prot, modes);
if (CPU_MODEL == MODEL_V9)
TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
else
TRAPSTATUS |= BIT12; /* set bit 12 of trap status */
return MPVIOL; /* return memory protection violation */
case 0x4: case 0x8: case 0xc:
/* O/S or user has write access, no protection violation */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Mem_writeB protect is ok @ %06x prot %02x modes %08x\n", addr, prot, modes);
}
map = RMR((page<<1)); /* read the map reg contents */
raddr = TLB[page]; /* get the base address & bits */
nix = page & 0x7ff; /* map # or mapc index */
mpl = SPAD[0xf3]; /* get mpl from spad address */
if (page < BPIX) {
mix = nix; /* get map index in memory */
msdl = RMW(mpl+4); /* get mpl entry for o/s */
} else {
mix = nix-BPIX; /* get map index in memory */
msdl = RMW(mpl+CPIX+4); /* get mpl entry for given cpix */
}
nmap = RMH(msdl+(mix<<1)); /* map content from memory */
// if ((nmap & 0x1800) == 0) {
if ((nmap & 0x1000) == 0) {
nmap |= 0x1800; /* set the modify/accessed bit in the map cache entry */
WMR((page<<1), nmap); /* store the map reg contents into cache */
TLB[page] |= 0x18000000; /* set the modify/accessed bits in TLB too */
WMH((msdl+(mix << 1)), nmap); /* save modified map with access bit set */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Mem_write Waddr %06x page %04x set access bit TLB %08x map %04x nmap %04x raddr %08x\n",
addr, page, TLB[page], map, nmap, raddr);
}
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Mem_write Xaddr %06x page %04x MA bits set TLB %08x map %04x prot %04x mode %04x\n",
addr, page, TLB[page], map, prot, modes);
} else {
if (prot) { /* check for write protected memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"Mem_writeB 32/67 protect error @ %06x prot %02x page %04x\n",
addr, prot, page);
if (CPU_MODEL == MODEL_97)
TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
else
TRAPSTATUS |= BIT12; /* set bit 12 of trap status */
return MPVIOL; /* return memory protection violation */
}
}
/* everything else has write access */
} else {
if (prot) { /* check for write protected memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"Mem_writeC protect error @ %06x prot %02x\n", addr, prot);
TRAPSTATUS |= BIT12; /* set bit 12 of trap status */
return MPVIOL; /* return memory protection violation */
}
}
// M[realaddr >> 2] = *data; /* valid address, put physical address contents */
WMW(realaddr, *data); /* valid address, put physical address contents */
} else {
/* RealAddr returned an error */
sim_debug(DEBUG_TRAP, &cpu_dev,
"Mem_write error addr %.8x realaddr %.8x data %.8x prot %02x status %04x\n",
addr, realaddr, *data, prot, status);
if (status == NPMEM) { /* operand nonpresent memory error */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
TRAPSTATUS |= BIT2; /* set bit 2 of trap status */
} else
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
}
if (status == MAPFLT) {
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT12; /* set bit 12 of trap status */
else
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
}
sim_debug(DEBUG_TRAP, &cpu_dev,
"Mem_write error %02x @ %06x TRAPSTATUS %08x pfaualt %04x\n",
status, addr, TRAPSTATUS, pfault);
}
return status; /* return ALLOK or ERROR */
}
/* function to set the CCs in PSD1 */
/* ovr is setting for CC1 */
void set_CCs(uint32 value, int ovr)
{
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
if (ovr)
CC = CC1BIT; /* CC1 value */
else
CC = 0; /* CC1 off */
if (value & FSIGN)
CC |= CC3BIT; /* CC3 for neg */
else if (value == 0)
CC |= CC4BIT; /* CC4 for zero */
else
CC |= CC2BIT; /* CC2 for greater than zero */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
}
/* Opcode definitions */
/* called from simulator */
t_stat sim_instr(void) {
t_stat reason = 0; /* reason for stopping */
t_uint64 dest; /* Holds destination/source register */
t_uint64 source; /* Holds source or memory data */
t_uint64 td; /* Temporary */
t_int64 int64a; /* temp int */
t_int64 int64b; /* temp int */
t_int64 int64c; /* temp int */
uint32 addr; /* Holds address of last access */
uint32 temp; /* General holding place for stuff */
uint32 IR; /* Instruction register */
uint32 i_flags=0; /* Instruction description flags from table */
uint32 t; /* Temporary */
uint32 temp2; /* Temporary */
uint32 bc=0; /* Temporary bit count */
uint16 opr; /* Top half of Instruction register */
uint16 OP; /* Six bit instruction opcode */
uint16 chan; /* I/O channel address */
uint16 lchan; /* Logical I/O channel address */
uint16 suba; /* I/O subaddress */
uint8 FC; /* Current F&C bits */
uint8 EXM_EXR=0; /* PC Increment for EXM/EXR instructions */
uint32 reg; /* GPR or Base register bits 6-8 */
uint32 sreg; /* Source reg in from bits 9-11 reg-reg instructions */
uint32 ix; /* index register */
uint32 dbl; /* Double word */
uint32 ovr=0; /* Overflow flag */
//FORSTEP uint32 stopnext = 0; /* Stop on next instruction */
uint32 skipinstr = 0; /* Skip test for interrupt on this instruction */
uint32 drop_nop = 0; /* Set if right hw instruction is a nop */
uint32 int_icb; /* interrupt context block address */
uint32 OIR=0; /* Original Instruction register */
uint32 OPSD1=0; /* Original PSD1 */
uint32 OPSD2=0; /* Original PSD2 */
uint32 TPSD[2]; /* Temp PSD */
int32 int32a; /* temp int */
int32 int32b; /* temp int */
int32 int32c; /* temp int */
#ifdef DO_DYNAMIC_DEBUG
int32 event = 0;
#endif
wait_loop:
while (reason == 0) { /* loop until halted */
// wait_loop:
if (sim_interval <= 0) { /* event queue? */
reason = sim_process_event(); /* process */
if (reason != SCPE_OK) {
if (reason == SCPE_STEP) {
//FORSTEP stopnext = 1;
break;
} else
break; /* process */
}
}
/* stop simulator if user break requested */
if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) {
reason = STOP_IBKPT;
break;
}
sim_interval--; /* count down */
if (drop_nop) { /* need to drop a nop? */
PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); /* skip this instruction */
PSD1 &= ~1; /* clear bit 31, no lr */
drop_nop = 0; /* we dropped the nop */
}
if (skipinstr) { /* need to skip interrupt test? */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"Skipinstr set to zero PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
PSD1, PSD2, CPUSTATUS);
#endif
skipinstr = 0; /* skip only once */
goto skipi; /* skip int test */
}
/* process pending I/O interrupts */
if (!loading && (wait4int || irq_pend)) { /* see if ints are pending */
int ilev;
int_icb = scan_chan(&ilev); /* no, go scan for I/O int pending */
if (int_icb != 0) { /* was ICB returned for an I/O or interrupt */
int il = ilev; /* get the interrupt level */
sim_debug(DEBUG_IRQ, &cpu_dev,
"<>Normal int return icb %06x level %02x irq_pend %01x wait4int %01x\n",
int_icb, il, irq_pend, wait4int);
/* take interrupt, store the PSD, fetch new PSD */
bc = PSD2 & 0x3ffc; /* get copy of cpix */
M[int_icb>>2] = PSD1&0xfffffffe; /* store PSD 1 */
M[(int_icb>>2)+1] = PSD2; /* store PSD 2 */
PSD1 = M[(int_icb>>2)+2]; /* get new PSD 1 */
PSD2 = (M[(int_icb>>2)+3] & ~0x3ffc) | bc; /* get new PSD 2 w/old cpix */
/* I/O status DW address will be in WD 6 */
/* set new map mode and interrupt blocking state in CPUSTATUS */
modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */
CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */
CPUSTATUS |= modes; /* now insert into CPUSTATUS */
if (PSD2 & MAPBIT) {
CPUSTATUS |= BIT8; /* set bit 8 of cpu status */
modes |= MAPMODE; /* set mapped mode */
} else
CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */
if ((PSD2 & 0x8000) == 0) { /* is it retain blocking state */
if (PSD2 & 0x4000) { /* no, is it set blocking state */
CPUSTATUS |= 0x80; /* yes, set blk state in cpu status bit 24 */
/* This test fixed the hangs on terminal input for diags & UTX! */
/*TRY*/ t = SPAD[il+0x80]; /* get spad entry for interrupt */
/* Class F I/O spec says to reset interrupt active if user's */
/* interrupt service routine runs with interrupts blocked */
/*TRY*/ if ((t & 0x0f000000) == 0x0f000000) { /* if class F clear interrupt */
/* if this is F class I/O interrupt, clear the active level */
/* SPAD entries for interrupts begin at 0x80 */
INTS[il] &= ~INTS_ACT; /* deactivate specified int level */
SPAD[il+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */
irq_pend = 1; /* scan for interrupts again */
sim_debug(DEBUG_IRQ, &cpu_dev,
"<>Auto-reset interrupt INTS[%02x] %08x SPAD[%03x] %08x\n",
il, INTS[il], il+0x80, SPAD[il+0x80]);
/*TRY*/ }
}
else
CPUSTATUS &= ~0x80; /* no, reset blk state in cpu status bit 24 */
}
PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */
if (CPUSTATUS & 0x80) /* see if old mode is blocked */
PSD2 |= 0x00004000; /* set to blocked state */
PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */
SPAD[0xf5] = PSD2; /* save the current PSD2 */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
sim_debug(DEBUG_IRQ, &cpu_dev,
"<>Int %03x OPSD1 %08x OPSD2 %08x NPSD1 %08x NPSD2 %08x\n",
il, RMW(int_icb), RMW(int_icb+4), PSD1, PSD2);
bc = RMW(int_icb+20) & 0xffffff;
if (RMW(int_icb+16) == 0)
sim_debug(DEBUG_IRQ, &cpu_dev,
"<>Int2 %03x ICBA %06x IOCLA %06x\n",
il, int_icb, RMW(int_icb+16));
else
sim_debug(DEBUG_IRQ, &cpu_dev,
"<>Int2 %03x ICBA %06x IOCLA %06x STAT %08x SW1 %08x SW2 %08x\n",
il, int_icb, RMW(int_icb+16), RMW(int_icb+20), RMW(bc), RMW(bc+4));
wait4int = 0; /* wait is over for int */
irq_pend = 1; /* scan for interrupts again */
skipinstr = 1; /* skip next inter test after this instr */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"Skipinstr set to one PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
PSD1, PSD2, CPUSTATUS);
#endif
goto skipi; /* skip int test */
}
/* see if waiting at a wait instruction */
if (wait4int || loading) {
/* tell simh we will be waiting */
sim_idle(TMR_RTC, 1); /* wait for clock tick */
goto wait_loop; /* continue waiting */
}
} else {
if (loading) {
int il;
uint32 chsa = scan_chan(&il); /* go scan for load complete pending */
if (chsa != 0) { /* see if a boot channel/subaddress were returned */
/* take interrupt, store the PSD, fetch new PSD */
PSD1 = M[0>>2]; /* PSD1 from location 0 */
PSD2 = M[4>>2]; /* PSD2 from location 4 */
modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */
CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */
CPUSTATUS |= modes; /* now insert into CPUSTATUS */
sim_debug(DEBUG_IRQ, &cpu_dev, "Boot Loading PSD1 %.8x PSD2 %.8x\n", PSD1, PSD2);
/* set interrupt blocking state in CPUSTATUS */
CPUSTATUS |= 0x80; /* set blocked state in cpu status, bit 24 too */
PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */
SPAD[0xf5] = PSD2; /* save the current PSD2 */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
loading = 0; /* we are done loading */
skipinstr = 1; /* skip next interrupt test only once */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"Skipinstr set to one PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
PSD1, PSD2, CPUSTATUS);
#endif
}
goto wait_loop; /* continue waiting */
}
/* see if in wait instruction */
if (wait4int) { /* keep waiting */
/* tell simh we will be waiting */
sim_idle(TMR_RTC, 1); /* wait for clock tick */
goto wait_loop; /* continue waiting */
}
}
/* Check for external interrupt here */
/* see if we have an attention request from console */
if (!skipinstr && attention_trap) {
TRAPME = attention_trap; /* get trap number */
attention_trap = 0; /* clear flag */
sim_debug(DEBUG_XIO, &cpu_dev, "Attention TRAP %04x\n", TRAPME);
skipinstr = 1; /* skip next interrupt test only once */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"Skipinstr set to one PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
PSD1, PSD2, CPUSTATUS);
#endif
goto newpsd; /* got process trap */
}
skipi:
i_flags = 0; /* do not update pc if MF or NPM */
//XXX skipinstr = 0; /* skip only once */
TRAPSTATUS = CPUSTATUS & 0x57; /* clear all trap status except cpu type */
/* fill IR from logical memory address */
if ((TRAPME = read_instruction(PSD, &IR))) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"read_instr TRAPME %04x PSD %08x %08x i_flags %04x drop_nop %01x\n",
TRAPME, PSD1, PSD2, i_flags, drop_nop);
if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67) ||
(CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97)) {
if ((TRAPME == MAPFLT) || (TRAPME == NPMEM)) {
i_flags |= HLF; /* assume half word instr */
/*DIAG*/ PSD1 &= ~1; /* force off last right */
// fix for 32/67 test 32/3 in MMM diag
if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_67))
i_flags |= BT; /* do not update pc if MF or NPM */
else
i_flags &= ~BT; /* do not update pc if MF or NPM */
}
} else {
if ((TRAPME == PRIVVIOL_TRAP) && (CPU_MODEL == MODEL_V9)) {
i_flags |= HLF; /* assume half word instr */
drop_nop = 0;
i_flags &= ~BT; /* no branch taken */
/*DIAG*/ PSD1 &= ~1; /* force off last right */
}
}
sim_debug(DEBUG_TRAP, &cpu_dev,
"read_instr2 TRAPME %04x PSD %08x %08x i_flags %04x drop_nop %01x\n",
TRAPME, PSD1, PSD2, i_flags, drop_nop);
goto newpsd; /* got process trap */
}
if (PSD1 & 2) { /* see if executing right half */
/* we have a rt hw instruction */
IR <<= 16; /* put instruction in left hw */
if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_87) ||
(CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
skipinstr = 0; /* only test this once */
drop_nop = 0; /* not dropping nop for these machines */
goto exec; /* machine does not drop nop instructions */
}
/* We have 67 or V6 and have a rt hw instruction */
if (IR == 0x00020000) { /* is this a NOP from rt hw? */
PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1); /* skip this instruction */
// fprintf(stderr, "RIGHT HW skip NOP instr %x skip nop at %x\n", IR, PSD1);
skipinstr = 0; /* only test this once */
goto skipi; /* go read next instruction */
}
skipinstr = 0; /* only test this once */
} else {
/* we have a left hw or fullword instruction */
/* see if we can drop a rt hw nop instruction */
OP = (IR >> 24) & 0xFC; /* this is a 32/67 or above, get OP */
if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_87) ||
(CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
goto exec; /* old machines did not drop nop instructions */
if (PSD1 & BASEBIT)
i_flags = base_mode[OP>>2]; /* set the BM instruction processing flags */
else
i_flags = nobase_mode[OP>>2]; /* set the NBM instruction processing flags */
if ((i_flags & 0xf) == HLF) { /* this is left HW instruction */
if ((IR & 0xffff) == 0x0002) { /* see if rt hw is a nop */
/* treat this as a fw instruction */
drop_nop = 1; /* we need to skip nop next time */
// fprintf(stderr, "LEFT HW skip NOP instr %x skip nop at %x\r\n", IR, PSD1);
}
}
}
exec:
/* temp saves for debugging */
OIR = IR; /* save the instruction */
OPSD1 = PSD1; /* save the old PSD1 */
OPSD2 = PSD2; /* save the old PSD2 */
TRAPSTATUS = CPUSTATUS & 0x57; /* clear all trap status except cpu type */
/* Split instruction into pieces */
PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */
sim_debug(DEBUG_DETAIL, &cpu_dev, "-----Instr @ PC %08x PSD1 %08x PSD2 %08x IR %08x\n",
PC, PSD1, PSD2, IR);
/* check for breakpoint request */
if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) {
reason = STOP_IBKPT;
break;
}
/* Update history for this instruction */
if (hst_lnt) {
hst_p += 1; /* next history location */
if (hst_p >= hst_lnt) /* check for wrap */
hst_p = 0; /* start over at beginning */
hst[hst_p].opsd1 = OPSD1; /* set original psd1 */
hst[hst_p].opsd2 = OPSD2; /* set original psd2 */
hst[hst_p].oir = OIR; /* set original instruction */
}
opr = (IR >> 16) & MASK16; /* use upper half of instruction */
OP = (opr >> 8) & 0xFC; /* Get opcode (bits 0-5) left justified */
FC = ((IR & F_BIT) ? 0x4 : 0) | (IR & 3); /* get F & C bits for addressing */
reg = (opr >> 7) & 0x7; /* dest reg or xr on base mode */
sreg = (opr >> 4) & 0x7; /* src reg for reg-reg instructions or BR instr */
dbl = 0; /* no doubleword instruction */
ovr = 0; /* no overflow or arithmetic exception either */
dest = (t_uint64)IR; /* assume memory address specified */
CC = PSD1 & 0x78000000; /* save CC's if any */
/* changed for diags 052719*/
modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */
CPUSTATUS &= ~0x87000000; /* reset those bits in CPUSTATUS */
CPUSTATUS |= modes; /* not insert them into CPUSTATUS */
if (PSD2 & MAPBIT)
modes |= MAPMODE; /* set mapped mode */
if (modes & BASEBIT) {
i_flags = base_mode[OP>>2]; /* set the instruction processing flags */
addr = IR & RMASK; /* get address offset from instruction */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Base OP %04x i_flags %04x addr %08x\n", OP, i_flags, addr);
switch(i_flags & 0xf) {
case HLF:
source = GPR[sreg]; /* get the src reg from instruction */
break;
case IMM:
if (PC & 02) { /* if pc is on HW boundry, bad address */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
break;
case ADR:
ix = (IR >> 20) & 7; /* get index reg from instruction */
if (ix != 0)
addr += (GPR[ix] & MASK24); /* if not zero, add in reg contents */
case WRD:
if (PC & 02) { /* if pc is on HW boundry, bad address */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
ix = (IR >> 16) & 7; /* get base reg from instruction */
if (ix != 0)
addr += (BR[ix] & MASK24); /* if not zero, add to base reg contents */
FC = ((IR & F_BIT) ? 4 : 0); /* get F bit from original instruction */
FC |= addr & 3; /* set new C bits to address from orig or regs */
/*TRY*/ addr &= MASK24; /* make pure 24 bit addr */
break;
case INV:
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
break;
}
} else {
i_flags = nobase_mode[OP>>2]; /* set the instruction processing flags */
addr = IR & 0x7ffff; /* get 19 bit address from instruction */
if (PC >= 0x80000) {
TRAPME = MAPFAULT_TRAP; /* Map Fault Trap */
// DIAG add 97 for correct PSD address CN.MMM test 32, subtest 1 fails
if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67) ||
(CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97)) {
// DIAG fix for 32/87 test 33/2, clear psd bit 31
if ((CPU_MODEL == MODEL_87))
/*DIAG*/ PSD1 &= ~1; /* force off last right */
// DIAG fix 32/27 32/67 for diag MMM test 33/2
if ((CPU_MODEL <= MODEL_27) || (CPU_MODEL == MODEL_67))
i_flags |= BT; /* do not update pc if MAPFAULT on 27 */
else
i_flags &= ~BT; /* do not update pc if MF or NPM */
i_flags |= HLF; /* assume half word instr */
}
if ((CPU_MODEL <= MODEL_27))
/* 77, 27 rolls to zero, not 80000 */
PSD1 &= 0xff07ffff; /* remove overflow bits */
else
PSD1 &= 0xff0fffff; /* leave overflow bit for trap addr */
sim_debug(DEBUG_TRAP, &cpu_dev,
"PC over 80000 Base OP %04x i_flags %04x addr %08x PSD %08x %08x\n",
OP, i_flags, addr, PSD1, PSD2);
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* handle trap */
}
sim_debug(DEBUG_DETAIL, &cpu_dev, "Non Based i_flags %04x addr %08x\n", i_flags, addr);
/* non base mode instructions have bit 0 of the instruction set */
/* for word length instructions and zero for halfword instructions */
/* the LA (op=0x34) is the only exception. So test for PC on a halfword */
/* address and trap if word opcode is in right hw */
if (PC & 02) { /* if pc is on HW boundry, addr trap if bit zero set */
if ((OP == 0x34) || (OP & 0x80)) {
i_flags |= HLF; /* diags treats these as hw instructions */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
goto newpsd; /* go execute the trap now */
}
}
switch(i_flags & 0xf) {
case HLF: /* halfword instruction */
source = GPR[sreg]; /* get the src reg contents */
break;
case IMM: /* Immediate mode */
if (PC & 02) { /* if pc is on HW boundry, bad address */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
break;
case ADR: /* Normal addressing mode */
ix = (IR >> 21) & 3; /* get the index reg if specified */
if (ix != 0) {
addr += GPR[ix]; /* if not zero, add in reg contents */
FC = ((IR & F_BIT) ? 4 : 0); /* get F bit from original instruction */
FC |= addr & 3; /* set new C bits to address from orig or regs */
}
/* wart alert! */
/* the lea instruction requires special handling for indirection. */
/* Bits 0,1 are set to 1 in result addr if indirect bit is zero in */
/* instruction. Bits 0 & 1 are set to the last word */
/* or instruction in the chain bits 0 & 1 if indirect bit set */
/* if IX == 00 => dest = IR */
/* if IX == 0x => dest = IR + reg */
/* if IX == Ix => dest = ind + reg */
/* fall through */
case WRD: /* Word addressing, no index */
bc = 0xC0000000; /* set bits 0, 1 for instruction if not indirect */
t = IR; /* get current IR */
/*TRY*/ addr &= MASK24; /* make pure 24 bit addr */
while ((t & IND) != 0) { /* process indirection */
if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"case WRD Mem_read status %02x @ %08x OP %04x\n", TRAPME, addr, OP);
if (CPU_MODEL == MODEL_V9) /* V9 wants bit0 set in pfault */
if (TRAPME == DMDPG) /* demand page request */
pfault |= 0x80000000; /* set instruction fetch paging error */
goto newpsd; /* memory read error or map fault */
}
bc = temp & 0xC0000000; /* save new bits 0, 1 from indirect location */
CC = (temp & 0x78000000); /* save CC's from the last indirect word */
/* process new X, I, ADDR fields */
addr = temp & MASK19; /* get just the addr */
ix = (temp >> 21) & 3; /* get the index reg from indirect word */
if (ix != 0)
addr += (GPR[ix] & MASK19); /* add the register to the address */
/* if no F or C bits set, use original, else new */
if ((temp & F_BIT) || (addr & 3))
FC = ((temp & F_BIT) ? 0x4 : 0) | (addr & 3);
else {
addr |= (IR & F_BIT); /* copy F bit from instruction */
addr |= (FC & 3); /* copy in last C bits */
}
t = temp; /* go process next indirect location */
temp &= MASK19; /* go process next indirect location */
addr &= ~F_BIT; /* turn off F bit */
}
dest = (t_uint64)addr; /* make into 64 bit variable */
break;
case INV: /* Invalid instruction */
#ifdef WHAT_IS_THIS
if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"case INV Mem_read status %02x @ %08x\n", TRAPME, addr);
goto newpsd; /* memory read error or map fault */
}
#endif
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
break;
}
}
/* Read memory operand */
if (i_flags & RM) {
if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"case RM Mem_read status %02x @ %08x\n", TRAPME, addr);
// DIAG add 97 for correct PSD address CN.MMM test 32, subtest 1 fails
if ((TRAPME == MAPFLT) || (TRAPME == NPMEM) || (TRAPME == MPVIOL))
/*DIAG*/ PSD1 &= ~1; /* force off last right */
goto newpsd; /* memory read error or map fault */
}
source = (t_uint64)temp; /* make into 64 bit value */
switch(FC) {
case 0: /* word address, extend sign */
source |= (source & MSIGN) ? D32LMASK : 0;
break;
case 1: /* left hw */
source >>= 16; /* move left hw to right hw*/
/* Fall through */
case 3: /* right hw or right shifted left hw */
source &= 0xffff; /* use just the right hw */
if (source & 0x8000) { /* check sign of 16 bit value */
/* sign extend the value to leftmost 48 bits */
source = 0xFFFF0000 | (source & 0xFFFF); /* extend low 32 bits */
source |= (D32LMASK); /* extend hi bits */
}
break;
case 2: /* double word address */
if ((addr & 7) != 2) { /* must be double word adddress */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"case RM wd 2 Mem_read status %02x @ %08x\n", TRAPME, addr+4);
goto newpsd; /* memory read error or map fault */
}
source = (source << 32) | (t_uint64)temp; /* merge in the low order 32 bits */
dbl = 1; /* double word instruction */
break;
case 4: /* byte mode, byte 0 */
case 5: /* byte mode, byte 1 */
case 6: /* byte mode, byte 2 */
case 7: /* byte mode, byte 3 */
source = (source >> (8*(7-FC))) & 0xff; /* right justify addressed byte */
break;
}
}
/* Read memory operand without doing sign extend for EOMX/ANMX/ORMX/ARMX */
if (i_flags & RNX) {
if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"case RNX 2 Mem_read status %02x @ %08x\n", TRAPME, addr);
goto newpsd; /* memory read error or map fault */
}
source = (t_uint64)temp; /* make into 64 bit value */
switch(FC) {
case 0: /* word address and no sign extend */
source &= D32RMASK; /* just l/o 32 bits */
break;
case 1: /* left hw */
source >>= 16; /* move left hw to right hw*/
/* Fall through */
case 3: /* right hw or right shifted left hw */
source &= 0xffff; /* use just the right hw */
break;
case 2: /* double word address */
if ((addr & 7) != 2) { /* must be double word adddress */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */
sim_debug(DEBUG_TRAP, &cpu_dev,
"case RNX wd 2 Mem_read status %02x @ %08x\n", TRAPME, addr+4);
goto newpsd; /* memory read error or map fault */
}
source = (source << 32) | (t_uint64)temp; /* merge in the low order 32 bits */
dbl = 1; /* double word instruction */
break;
case 4: /* byte mode, byte 0 */
case 5: /* byte mode, byte 1 */
case 6: /* byte mode, byte 2 */
case 7: /* byte mode, byte 3 */
source = (source >> (8*(7-FC))) & 0xff; /* right justify addressed byte */
break;
}
}
/* Read in if from register */
if (i_flags & RR) {
if (FC == 2 && (i_flags & HLF) == 0) /* double dest? */
dbl = 1; /* src must be dbl for dbl dest */
dest = (t_uint64)GPR[reg]; /* get the register content */
if (dbl) { /* is it double regs */
if (reg & 1) { /* check for odd reg load */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
/* merge the regs into the 64bit value */
dest = (((t_uint64)dest) << 32) | ((t_uint64)GPR[reg+1]);
} else {
/* sign extend the data value */
dest |= (dest & MSIGN) ? D32LMASK : 0;
}
}
/* For Base mode */
if (i_flags & RB) {
dest = (t_uint64)BR[reg]; /* get base reg contents */
}
/* For register instructions */
if (i_flags & R1) {
source = (t_uint64)GPR[sreg];
if (dbl) {
if (sreg & 1) {
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
/* merge the regs into the 64bit value */
source = (source << 32) | ((t_uint64)GPR[reg+1]);
} else {
/* sign extend the data value */
source |= (source & MSIGN) ? ((t_uint64)MASK32) << 32: 0;
}
}
/* process instruction op code */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"PSD %08x %08x SW OP %04x IR %08x addr %08x\n",
PSD1, PSD2, OP, IR, addr);
switch (OP>>2) {
/*
* For op-codes=00,04,08,0c,10,14,28,2c,38,3c,40,44,60,64,68
*/
/* Reg - Reg instruction Format (16 bit) */
/* |--------------------------------------| */
/* |0 1 2 3 4 5|6 7 8 |9 10 11|12 13 14 15| */
/* | Op Code | DReg | SReg | Aug Code | */
/* |--------------------------------------| */
case 0x00>>2: /* HLF - HLF */ /* CPU General operations */
switch(opr & 0xF) { /* switch on aug code */
case 0x0: /* HALT */
if ((modes & PRIVBIT) == 0) { /* must be privileged to halt */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* Privlege violation trap */
}
if (CPUSTATUS & 0x00000100) { /* Priv mode halt must be enabled */
TRAPME = PRIVHALT_TRAP; /* set the trap to take */
goto newpsd; /* Privlege mode halt trap */
}
sim_debug(DEBUG_EXP, &cpu_dev, "Starting HALT instruction\n");
// if (cpu_dev.dctrl & DEBUG_EXP) {
sim_debug(DEBUG_EXP, &cpu_dev, "\n[][][][][][][][][][] HALT [][][][][][][][][][]\n");
sim_debug(DEBUG_EXP, &cpu_dev, "PSD1 %.8x PSD2 %.8x TRAPME %.4x CPUSTATUS %08x\n",
PSD1, PSD2, TRAPME, CPUSTATUS);
for (ix=0; ix<8; ix+=2) {
sim_debug(DEBUG_EXP, &cpu_dev, "GPR[%d] %.8x GPR[%d] %.8x\n", ix, GPR[ix], ix+1, GPR[ix+1]);
}
sim_debug(DEBUG_EXP, &cpu_dev, "[][][][][][][][][][] HALT [][][][][][][][][][]\n");
// }
fprintf(stdout, "\r\n[][][][][][][][][][] HALT [][][][][][][][][][]\r\n");
fprintf(stdout, "PSD1 %.8x PSD2 %.8x TRAPME %.4x\r\n", PSD1, PSD2, TRAPME);
for (ix=0; ix<8; ix+=2) {
fprintf(stdout, "GPR[%d] %.8x GPR[%d] %.8x\r\n", ix, GPR[ix], ix+1, GPR[ix+1]);
}
if (modes & BASEBIT) { /* see if based */
for (ix=0; ix<8; ix+=2) {
fprintf(stdout, "BR[%d] %.8x BR[%d] %.8x\r\n", ix, BR[ix], ix+1, BR[ix+1]);
}
}
fprintf(stdout, "[][][][][][][][][][] HALT [][][][][][][][][][]\r\n");
/*TEST DIAG*/ reason = STOP_HALT; /* do halt for now */
///*TEST DIAG*/ return STOP_HALT; /* exit to simh for halt */
break;
case 0x1: /* WAIT */
if ((modes & PRIVBIT) == 0) { /* must be privileged to wait */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* Privlege violation trap */
}
/* if interrupts are blocked, system check trap */
if (CPUSTATUS & 0x80) { /* status word bit 24 says blocked */
TRAPME = SYSTEMCHK_TRAP; /* trap condition if F class */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT12; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT20; /* set bit 20 of trap status */
goto newpsd; /* system check trap */
}
if (wait4int == 0) {
time_t result = time(NULL);
sim_debug(DEBUG_DETAIL, &cpu_dev,
"Starting WAIT mode %08x\n", (uint32)result);
}
wait4int = 1; /* show we are waiting for interrupt */
/* tell simh we will be waiting */
sim_idle(TMR_RTC, 0); /* wait for next pending device event */
i_flags |= BT; /* keep PC from being incremented while waiting */
break;
case 0x2: /* NOP */
break;
case 0x3: /* LCS */
/* get console switches from memory loc 0x780 */
if ((TRAPME = Mem_read(0x780, &GPR[reg]))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
set_CCs(GPR[reg], 0); /* set the CC's, CC1 = 0 */
break;
case 0x4: /* ES */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
/* reg is reg to extend sign into from reg+1 */
GPR[reg] = (GPR[reg+1] & FSIGN) ? FMASK : 0;
set_CCs(GPR[reg], 0); /* set CCs, CC2 & CC3 */
break;
case 0x5: /* RND */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
temp = GPR[reg]; /* save the current contents of specified reg */
t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */
bc = 1;
t |= ((bc & FSIGN) != 0) ? 2 : 0; /* ditto for the bit value */
if (GPR[reg+1] & FSIGN) { /* if sign of R+1 is set, incr R by 1 */
temp += bc; /* add the bit value to the reg */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if ((t == 3 && (temp & FSIGN) == 0) ||
(t == 0 && (temp & FSIGN) != 0)) {
ovr = 1; /* we have an overflow */
}
GPR[reg] = temp; /* update the R value */
} else
ovr = 0;
set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* handle trap */
}
break;
case 0x6: /* BEI */
if ((modes & PRIVBIT) == 0) { /* must be privileged to BEI */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* Privlege violation trap */
}
CPUSTATUS |= 0x80; /* into status word bit 24 too */
PSD2 &= ~0x0000c000; /* clear bit 48 & 49 */
PSD2 |= 0x00004000; /* set bit 49 only */
SPAD[0xf5] = PSD2; /* save the current PSD2 */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"BEI skipinstr %x irq_pend %x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
skipinstr, irq_pend, PSD1, PSD2, CPUSTATUS);
#endif
break;
case 0x7: /* UEI */
if ((modes & PRIVBIT) == 0) { /* must be privileged to UEI */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* Privlege violation trap */
}
if (CPUSTATUS & 0x80) /* see if old mode is blocked */
irq_pend = 1; /* start scanning interrupts again */
CPUSTATUS &= ~0x80; /* into status word bit 24 too */
PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */
SPAD[0xf5] = PSD2; /* save the current PSD2 */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"UEI skipinstr %x irq_pend %x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
skipinstr, irq_pend, PSD1, PSD2, CPUSTATUS);
#endif
break;
case 0x8: /* EAE */
PSD1 |= AEXPBIT; /* set the enable AEXP flag in PSD */
CPUSTATUS |= AEXPBIT; /* into status word too */
modes |= AEXPBIT; /* ensable arithmetic exception in modes & PSD */
break;
case 0x9: /* RDSTS */
GPR[reg] = CPUSTATUS; /* get CPU status word */
//sim_debug(DEBUG_CMD, &cpu_dev,
//"RDSTS CPUSTATUS %08x SPAD[0xf9] %08x\n", CPUSTATUS, SPAD[0xf9]);
#ifdef DO_DYNAMIC_DEBUG
/* start debugging */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_TRAP | DEBUG_EXP | DEBUG_IRQ);
#endif
break;
case 0xA: /* SIPU */ /* ignore for now */
sim_debug(DEBUG_CMD, &cpu_dev,
"SIPU CPUSTATUS %08x SPAD[0xf9] %08x\n", CPUSTATUS, SPAD[0xf9]);
break;
case 0xB: /* RWCS */ /* RWCS ignore for now */
/* reg = specifies reg containing the ACS/WCS address */
/* sreg = specifies the ACS/WCS address */
/* if the WCS option is not present, address spec error */
/* if the mem addr is not a DW, address spec error */
/* If 0<-Rs<=fff and Rs bit 0=0, then PROM address */
/* If 0<-Rs<=fff and Rs bit 0=1, then ACS address */
/* if bit 20 set, WCS enables, else addr spec error */
if ((CPUSTATUS & 0x00000800) == 0) {
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
/* Maybe TODO copy something from WCS */
break;
case 0xC: /* WWCS */ /* WWCS ignore for now */
/* reg = specifies the logical address in memory that */
/* is to receive the ACS/WCS contents */
/* sreg = specifies the ACS/WCS address */
/* bit 20 of cpu stat must be set=1 to to write to ACS or WCS */
/* bit 21 of CPU stat must be 0 to write to ACS */
/* if bit 20 set, WCS enables, else addr spec error */
if ((CPUSTATUS & 0x00000800) == 0) {
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
/* Maybe TODO copy something to WCS */
break;
case 0xD: /* SEA */
if (modes & BASEBIT) /* see if based */
goto inv; /* invalid instruction in based mode */
modes |= EXTDBIT; /* set new extended flag (bit 5) in modes & PSD */
PSD1 |= EXTDBIT; /* set the enable AEXP flag in PSD */
CPUSTATUS |= EXTDBIT; /* into status word too */
break;
case 0xE: /* DAE */
modes &= ~AEXPBIT; /* disable arithmetic exception in modes & PSD */
PSD1 &= ~AEXPBIT; /* disable AEXP flag in PSD */
CPUSTATUS &= ~AEXPBIT; /* into status word too */
break;
case 0xF: /* CEA */
if (modes & BASEBIT) /* see if based */
goto inv; /* invalid instruction in based mode */
modes &= ~EXTDBIT; /* disable extended mode in modes and PSD */
PSD1 &= ~EXTDBIT; /* disable extended mode (bit 5) flag in PSD */
CPUSTATUS &= ~EXTDBIT; /* into status word too */
break;
}
break;
case 0x04>>2: /* 0x04 RR|R1|SD|HLF - SD|HLF */ /* ANR, SMC, CMC, RPSWT */
switch(opr & 0xF) {
case 0x0: /* ANR */
dest &= source; /* just an and reg to reg */
if (dest & MSIGN)
dest |= D32LMASK; /* force upper word to all ones */
i_flags |= SCC; /* make sure we set CC's for dest value */
break;
case 0xA: /* CMC */ /* Cache Memory Control - Diag use only */
if (CPU_MODEL == MODEL_87)
break; /* just ignore */
if (CPU_MODEL < MODEL_67) {
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
if (CPU_MODEL <= MODEL_V6) {
/* Cache memory control bit assignments for reg */
/* 0-22 reserved, must be zero */
/* 23 - Initialize Instruction Cache Bank 0 On = 1 Off = 0 */
/* 24 - Initialize Instruction Cache Bank 1 On = 1 Off = 0 */
/* 25 - Initialize Operand Cache Bank 0 On = 1 Off = 0 */
/* 26 - Initialize Operand Cache Bank 1 On = 1 Off = 0 */
/* 27 - Enable Instruction Cache Bank 0 On = 1 Off = 0 */
/* 28 - Enable Instruction Cache Bank 1 On = 1 Off = 0 */
/* 29 - Enable Operand Cache Bank 0 On = 1 Off = 0 */
/* 30 - Enable Operand Cache Bank 1 On = 1 Off = 0 */
/* 31 - Bypass Instruction Cache Bank 1 On = 1 Off = 0 */
sim_debug(DEBUG_EXP, &cpu_dev,
"CMC V6/67 GPR[%02x] = %04x CMCR = %08x CPU STATUS SPAD[f9] = %08x\r\n",
reg, GPR[reg], CMCR, SPAD[0xf9]);
CMCR = GPR[reg]; /* write reg bits 23-31 to cache memory controller */
i_flags &= ~SD; /* turn off store dest for this instruction */
} else
if (CPU_MODEL == MODEL_V9) {
sim_debug(DEBUG_EXP, &cpu_dev,
"CMC V9 GPR[%02x] = %08x CMCR = %08x CPU STATUS SPAD[f9] = %08x\r\n",
reg, GPR[reg], CMCR, SPAD[0xf9]);
CMCR = GPR[reg]; /* write reg bits 23-31 to cache memory controller */
i_flags &= ~SD; /* turn off store dest for this instruction */
}
break;
case 0x7: /* SMC */ /* Shared Memory Control - Diag use only */
if (CPU_MODEL < MODEL_67) {
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
/* Shared memory control bit assignments for reg */
/* 0 - Reserved */
/* 1 - Shared Memory Enabled (=1)/Disabled (=0) */
/* 2-6 - Upper Bound of Shared Memory */
/* 7 - Read & Lock Enabled (=1)/Disabled (=0) */
/* 8-12 - Lower Bound of Shared Memory */
/* 3-31 - Reserved and must be zero */
sim_debug(DEBUG_EXP, &cpu_dev,
"SMC V6/67 GPR[%02x] = %08x SMCR = %08x CPU STATUS SPAD[f9] = %08x\n",
reg, GPR[reg], SMCR, SPAD[0xf9]);
SMCR = GPR[reg]; /* write reg bits 0-12 to shared memory controller */
i_flags &= ~SD; /* turn off store dest for this instruction */
break;
/* 67, 97, V6 Computer Configuration Word is copied when bit zero of Rd set to one (0x80000000) */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00|01|02 03 04 05 06|07|08 09 10 11 12|13 14 15|16|17|18|19|20 21|22|23 24 25 26|27|28|29|30|31| */
/* | | S| Upper Bound |RL| Lower Bound |Reserved|4k|8k|SM|P2| Res |AP| Reserved |I0|I1|D0|D1|BY| */
/* | 0| x| x x x x x| x| x x x x x| 0 0 0| x| x| x| x| 0 0| 0| 0 0 0 0| x| x| x| x| x| */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* Bits: 0 Reserved */
/* 1 Shared Memory Enabled (=1)/Disabled (=0) */
/* 2-6 Upper Bound of Shared Memory */
/* 7 Read & Lock Enabled (=1)/Disabled (=0) */
/* 8-12 Lower Bound of Shared Memory */
/* 13-15 Reserved */
/* 16 4K WCS Option Present (=1)/Not Present (=0) */
/* 17 8K WCS Option Present (=1)/Not Present (=0) */
/* 18 Firmware Control Store Mode ROMSIM (=1)/PROM (=0) */
/* 19 IPU Present (=1)/Not Present (=0) */
/* 20-21 Reserved */
/* 22 Access Protection ECO Present (=0)/No Access Protection (=0) V6 & V9 */
/* 23-26 Reserved */
/* 27 Instruction Cache Bank 0 on (=1)/Off (=0) */
/* 28 Instruction Cache Bank 1 on (=1)/Off (=0) */
/* 29 Data Cache Bank 0 on (=1)/Off (=0) */
/* 30 Data Cache Bank 1 on (=1)/Off (=0) */
/* 31 Instruction Cache Enabled (=1)/Disabled (=0) */
/* */
/* V9 Computer Configuration Word when bit zero of Rd set to one (0x80000000) */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02 03|04 05 06 07|08 09 10 11|12 13 14 15|16|17|18|19|20|21|22|23|24 25 26 27|28 29 30 31| */
/* | CPU Bank1 | CPU Bank2 | IPU Bank0 | IPU Bank1 |M1|M2|C1|C2|P2|SM|AP| | CPU FW Ver| CPU FW Rev| */
/* | x x x x| x x x x| x x x x| x x x x| x| x| x| x| x| x| x| x| x x x x| x x x x| */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* Bits: 0-15 Cache/Shadow Unit Present (=1)/Not Present (=0) */
/* 16 MACC Present in CP1 (=1)/Not Present (=0) */
/* 17 MACC Present in CP2 (=1)/Not Present (=0) */
/* 18 CP1 Present (=1)/CP1 Not Present (=0) */
/* 19 CP2 Present (=1)/CP2 Not Present (=0) */
/* 20 IPU Present (=1)/Not Present (=0) */
/* 21 Shared Memory Present (=1)/Not Present (=0) */
/* 22 Access Protection ECO Present (=0)/No Access Protection (=0) V6 & V9 */
/* 23 Reserved */
/* 24-27 CPU Firmware Version */
/* 28-31 CPU Formware Revision Level */
/* */
/* V9 CPU Shadow Memory Configuration Word when bit one of Rd set to one (0x40000000) */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02|03 04 05 06 07|08 09 10 11 12 13 14 15|16 17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */
/* | SMU # | Not Used | CPU Unit 1 Base Addr | CPU Unit 2 Base Addr | CPU Unit 3 Base Addr | */
/* | x x x| 0 0 0 0 0| x x x x x x x 0| x x x x x x x 0| x x x x x x x 0| */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* Bits: 0 Shadow Memory Unit 1 Present (=1)/Not Present (=0) */
/* 1 Shadow Memory Unit 2 Present (=1)/Not Present (=0) */
/* 2 Shadow Memory Unit 3 Present (=1)/Not Present (=0) */
/* 3-7 Not Used */
/* 8-14 Shadow Memory Unit 1 Base Address (bits 08-14 of address) */
/* 15 Always zero */
/* 16-22 Shadow Memory Unit 2 Base Address (bits 08-14 of address) */
/* 23 Always zero */
/* 24-30 Shadow Memory Unit 2 Base Address (bits 08-14 of address) */
/* 31 Always zero */
/* */
/* V9 IPU Shadow Memory Configuration Word when bit two of Rd set to one (0x20000000) */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02|03 04 05 06 07|08 09 10 11 12 13 14 15|16 17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */
/* | SMU # | Not Used | IPU Unit 1 Base Addr | IPU Unit 2 Base Addr | IPU Unit 3 Base Addr | */
/* | x x x| 0 0 0 0 0| x x x x x x x 0| x x x x x x x 0| x x x x x x x 0| */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* Bits: 0 Shadow Memory Unit 1 Present (=1)/Not Present (=0) */
/* 1 Shadow Memory Unit 2 Present (=1)/Not Present (=0) */
/* 2 Shadow Memory Unit 3 Present (=1)/Not Present (=0) */
/* 3-7 Not Used */
/* 8-14 Shadow Memory Unit 1 Base Address (bits 08-14 of address) */
/* 15 Always zero */
/* 16-22 Shadow Memory Unit 2 Base Address (bits 08-14 of address) */
/* 23 Always zero */
/* 24-30 Shadow Memory Unit 2 Base Address (bits 08-14 of address) */
/* 31 Always zero */
/* */
/* When bit zero of Rd is zero, PSW word 2 is copies to Rd (0x00000000) */
/* */
case 0xB: /* RPSWT */ /* Read Processor Status Word 2 (PSD2) */
if ((GPR[reg] & 0x80000000) && (CPU_MODEL < MODEL_V9)) {
/* if bit 0 of reg set, return (default 0) CPU Configuration Word */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"RPSWT READ CCW GPR[%x] %08x CCW %04x SPAD[0xf5] %08x PSD2 %08x CPUSTATUS %08x\n",
reg, GPR[reg], CCW, SPAD[0xf5], PSD2, CPUSTATUS);
#endif
dest = CCW; /* no cache or shared memory */
//NO WCS dest |= 0x0000c000; /* set SIM bit for DIAGS */
/* make sure bit 19 is zero saying IPU not present */
dest &= ~0x00001000; /* reset IPU bit for DIAGS */
/* bit 22 for access ECO present */
dest |= 0x00000200; /* set ECO bit for DIAGS */
} else
if ((GPR[reg] & 0x80000000) && (CPU_MODEL == MODEL_V9)) {
/* if bit 0 of reg set, return Cache/Shadow Configuration Word */
CMSMC = 0xffff0000; /* no CPU/IPU Cache/Shadow unit present */
CMSMC |= 0x0000c000; /* MACC no present in CP1/CP2 */
CMSMC |= 0x00003000; /* CP1/CP2 not present */
CMSMC |= 0x00000800; /* bit 20, IPU not present */
CMSMC |= 0x00000400; /* Shared Memory not configured */
CMSMC |= 0x00000200; /* bit 22, Access Protection ECO present */
CMSMC |= 0x00000010; /* CPU Firmware Version 1/Rev level 0 */
dest = CMSMC; /* return starus */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"RPSWT READ Cache/Shadow CW GPR[%x] = %08x CMSMC %04x SPAD[0xf5] %x PSD2 %x\n",
reg, GPR[reg], CMSMC, SPAD[0xf5], PSD2);
#endif
} else
if ((GPR[reg] & 0x40000000) && (CPU_MODEL == MODEL_V9)) {
/* if bit 1 of reg set, return CPU Shadow Memory Configuration Word */
CSMCW = 0x00000000; /* no Shadow unit present */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"RPSWT READ V9 CPU Shadow Memory CW GPR[%x] = %08x CSMCW %04x SPAD[0xf5] %x PSD2 %x\n",
reg, GPR[reg], CSMCW, SPAD[0xf5], PSD2);
#endif
dest = CSMCW; /* return starus */
} else
if ((GPR[reg] & 0x20000000) && (CPU_MODEL == MODEL_V9)) {
/* if bit 2 of reg set, return Cache Memory Configuration Word */
ISMCW = 0x00000000; /* no Shadow unit present */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"RPSWT READ V9 IPU Shadow Memory CW GPR[%x] = %08x ISMCW %04x SPAD[0xf5] %x PSD2 %x\n",
reg, GPR[reg], ISMCW, SPAD[0xf5], PSD2);
#endif
dest = ISMCW; /* return starus */
} else
if ((GPR[reg] & BIT0) == 0x00000000) {
/* if bit 0 of reg not set, return PSD2 */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"RPSWT READ PSW2 GPR[%x] %08x SPAD[0xf5] %08x PSD2 %08x CPUSTATUS %08x\n",
reg, GPR[reg], SPAD[0xf5], PSD2, CPUSTATUS);
#endif
/* make sure bit 49 (block state is current stat */
dest = SPAD[0xf5]; /* get PSD2 for user from SPAD 0xf5 */
dest &= ~0x0000c000; /* clear bits 48 & 49 */
if (modes & BLKMODE) /* set to current mode */
dest |= 0x00004000; /* set bit 49 for blocked */
}
break;
case 0x08: /* 0x0408 INV (Diag Illegal instruction) */
#ifndef NO_HACK
/* HACK HACK HACK for DIAGS */
if (CPU_MODEL <= MODEL_27) { /* DIAG error for 32/27 only */
if ((PSD1 & 2) == 0) /* if lf hw instruction */
i_flags |= HLF; /* if nop in rt hw, bump pc a word */
}
#endif
/* drop through */
default: /* INV */ /* everything else is invalid instruction */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
break;
}
break;
case 0x08>>2: /* 0x08 SCC|RR|R1|SD|HLF - */ /* ORR or ORRM */
dest |= source; /* or the regs into dest reg */
switch(opr & 0x0f) {
case 0x8: /* this is ORRM op */
dest &= GPR[4]; /* mask with reg 4 contents */
/* drop thru */
case 0x0: /* this is ORR op */
if (dest & MSIGN) /* see if we need to sign extend */
dest |= D32LMASK; /* force upper word to all ones */
break;
default: /* INV */ /* everything else is invalid instruction */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
break;
case 0x0C>>2: /* 0x0c SCC|RR|R1|SD|HLF - SCC|SD|HLF */ /* EOR or EORM */
dest ^= source; /* exclusive or the regs into dest reg */
switch(opr & 0x0f) {
case 0x8: /* this is EORM op */
dest &= GPR[4]; /* mask with reg 4 contents */
/* drop thru */
case 0x0: /* this is EOR op */
if (dest & MSIGN) /* see if we need to sign extend */
dest |= D32LMASK; /* force upper word to all ones */
break;
default: /* INV */ /* everything else is invalid instruction */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
break;
case 0x10>>2: /* 0x10 HLF - HLF */ /* CAR or (basemode SACZ ) */
if ((opr & 0xF) == 0) { /* see if CAR instruction */
/* handle non basemode/basemode CAR instr */
if ((int32)GPR[reg] < (int32)GPR[sreg])
CC = CC3BIT; /* Rd < Rs; negative */
else
if (GPR[reg] == GPR[sreg])
CC = CC4BIT; /* Rd == Rs; zero */
else
CC = CC2BIT; /* Rd > Rs; positive */
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
} else {
if ((modes & BASEBIT) == 0) { /* if not basemode, error */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
goto newpsd; /* handle trap */
}
/* handle basemode SACZ instruction */
sacz: /* non basemode SCZ enters here */
temp = GPR[reg]; /* get destination reg contents to shift */
CC = 0; /* zero the CC's */
t = 0; /* start with zero shift count */
if (temp == 0) {
CC = CC4BIT; /* set CC4 showing dest is zero & cnt is zero too */
}
#ifdef NOT_FOR_DIAG
/* The doc says the reg is not shifted if bit 0 is set on entry. */
/* diags says it does, so that is what we will do */
/* set count to zero, but shift reg 1 left */
else
if (temp & BIT0) {
CC = 0; /* clear CC4 & set count to zero */
}
#endif
else
if (temp != 0) { /* shift non zero values */
while ((temp & FSIGN) == 0) { /* shift the reg until bit 0 is set */
temp <<= 1; /* shift left 1 bit */
t++; /* increment shift count */
}
temp <<= 1; /* shift the sign bit out */
}
GPR[reg] = temp; /* save the shifted values */
GPR[sreg] = t; /* set the shift cnt into the src reg */
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
}
break;
case 0x14>>2: /* 0x14 HLF - HLF */ /* CMR compare masked with reg */
if (opr & 0xf) { /* any subop not zero is error */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
temp = GPR[reg] ^ GPR[sreg]; /* exclusive or src and destination values */
temp &= GPR[4]; /* and with mask reg (GPR 4) */
CC = 0; /* set all CCs zero */
if (temp == 0) /* if result is zero, set CC4 */
CC = CC4BIT; /* set CC4 to show result 0 */
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
break;
case 0x18>>2: /* 0x18 HLF - HLF */ /* SBR, (basemode ZBR, ABR, TBR */
if (modes & BASEBIT) { /* handle basemode ZBR, ABR, TBR */
if ((opr & 0xC) == 0x0) /* SBR instruction */
goto sbr; /* use nonbase SBR code */
if ((opr & 0xC) == 0x4) /* ZBR instruction */
goto zbr; /* use nonbase ZBR code */
if ((opr & 0xC) == 0x8) /* ABR instruction */
goto abr; /* use nonbase ABR code */
if ((opr & 0xC) == 0xC) /* TBR instruction */
goto tbr; /* use nonbase TBR code */
inv:
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
} else { /* handle non basemode SBR */
if (opr & 0xc) { /* any subop not zero is error */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
sbr: /* handle basemode too */
/* move the byte field bits 14-15 to bits 27-28 */
/* or in the bit# from dest reg field bits 6-8 into bit 29-31 */
bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */
bc = BIT0 >> bc; /* make a bit mask of bit number */
t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
if (GPR[sreg] & bc) /* test the bit in src reg */
t |= CC1BIT; /* set CC1 to the bit value */
GPR[sreg] |= bc; /* set the bit in src reg */
PSD1 |= t; /* update the CC's in the PSD */
}
break;
case 0x1C>>2: /* 0x1C HLF - HLF */ /* ZBR (basemode SRA, SRL, SLA, SLL) */
if (modes & BASEBIT) { /* handle basemode SRA, SRL, SLA, SLL */
bc = opr & 0x1f; /* get bit shift count */
if ((opr & 0x60) == 0x00) { /* SRA instruction */
temp = GPR[reg]; /* get reg value to shift */
t = temp & FSIGN; /* sign value */
for (ix=0; ix<bc; ix++) {
temp >>= 1; /* shift bit 0 right one bit */
temp |= t; /* restore original sign bit */
}
GPR[reg] = temp; /* save the new value */
break;
}
if ((opr & 0x60) == 0x20) { /* SRL instruction */
GPR[reg] >>= bc; /* value to be output */
break;
}
if ((opr & 0x60) == 0x40) { /* SLA instruction */
temp = GPR[reg]; /* get reg value to shift */
t = temp & FSIGN; /* sign value */
ovr = 0; /* set ovr off */
for (ix=0; ix<bc; ix++) {
temp <<= 1; /* shift bit into sign position */
if ((temp & FSIGN) ^ t) /* see if sign bit changed */
ovr = 1; /* set arithmetic exception flag */
}
temp &= ~BIT0; /* clear sign bit */
temp |= t; /* restore original sign bit */
GPR[reg] = temp; /* save the new value */
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
if (ovr)
PSD1 |= BIT1; /* CC1 in PSD */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* go execute the trap now */
}
break;
}
if ((opr & 0x60) == 0x60) { /* SLL instruction */
GPR[reg] <<= bc; /* value to be output */
break;
}
break;
} else { /* handle nonbase ZBR */
if (opr & 0xc) { /* any subop not zero is error */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
zbr: /* handle basemode too */
/* move the byte field bits 14-15 to bits 27-28 */
/* or in the bit# from dest reg field bits 6-8 into bit 29-31 */
bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */
bc = BIT0 >> bc; /* make a bit mask of bit number */
t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
if (GPR[sreg] & bc) /* test the bit in src reg */
t |= CC1BIT; /* set CC1 to the bit value */
GPR[sreg] &= ~bc; /* reset the bit in src reg */
PSD1 |= t; /* update the CC's in the PSD */
}
break;
case 0x20>>2: /* 0x20 HLF - HLF */ /* ABR (basemode SRAD, SRLD, SLAD, SLLD) */
if (modes & BASEBIT) { /* handle basemode SRAD, SRLD, SLAD, SLLD */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
dest = (t_uint64)GPR[reg+1]; /* get low order reg value */
dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */
bc = opr & 0x1f; /* get bit shift count */
source = dest & DMSIGN; /* 64 bit sign value */
switch (opr & 0x60) {
case 0x00: /* SRAD instruction */
for (ix=0; ix<bc; ix++) {
dest >>= 1; /* shift bit 0 right one bit */
dest |= source; /* restore original sign bit */
}
break;
case 0x20: /* SRLD */
dest >>= bc; /* shift right #bits */
break;
case 0x40: /* SLAD instruction */
ovr = 0; /* set ovr off */
for (ix=0; ix<bc; ix++) {
dest <<= 1; /* shift bit into sign position */
if ((dest & DMSIGN) ^ source) /* see if sign bit changed */
ovr = 1; /* set arithmetic exception flag */
}
dest &= ~DMSIGN; /* clear sign bit */
dest |= source; /* restore original sign bit */
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
if (ovr)
PSD1 |= BIT1; /* CC1 in PSD */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* go execute the trap now */
}
break;
case 0x60: /* SLLD */
dest <<= bc; /* shift left #bits */
break;
}
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
break;
} else { /* handle nonbase mode ABR */
if (opr & 0xc) { /* any subop not zero is error */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
abr: /* basemode ABR too */
/* move the byte field bits 14-15 to bits 27-28 */
/* or in the bit# from dest reg field bits 6-8 into bit 29-31 */
bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */
bc = BIT0 >> bc; /* make a bit mask of bit number */
temp = GPR[sreg]; /* get reg value to add bit to */
t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */
t |= ((bc & FSIGN) != 0) ? 2 : 0; /* ditto for the bit value */
temp += bc; /* add the bit value to the reg */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if ((t == 3 && (temp & FSIGN) == 0) ||
(t == 0 && (temp & FSIGN) != 0)) {
ovr = 1; /* we have an overflow */
}
GPR[sreg] = temp; /* save the new value */
set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* handle trap */
}
}
break;
case 0x24>>2: /* 0x24 HLF - HLF */ /* TBR (basemode SRC) */
if (modes & BASEBIT) { /* handle SRC basemode */
bc = opr & 0x1f; /* get bit shift count */
temp = GPR[reg]; /* get reg value to shift */
if ((opr & 0x60) == 0x40) { /* SLC instruction */
for (ix=0; ix<bc; ix++) {
t = temp & BIT0; /* get sign bit status */
temp <<= 1; /* shift the bit out */
if (t)
temp |= 1; /* the sign bit status */
}
} else { /* this is SRC */
for (ix=0; ix<bc; ix++) {
t = temp & 1; /* get bit 31 status */
temp >>= 1; /* shift the bit out */
if (t)
temp |= BIT0; /* put in new sign bit */
}
}
GPR[reg] = temp; /* shift result */
} else { /* handle TBR non basemode */
if (opr & 0xc) { /* any subop not zero is error */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
tbr: /* handle basemode TBR too */
/* move the byte field bits 14-15 to bits 27-28 */
/* or in the bit# from dest reg field bits 6-8 into bit 29-31 */
bc = (((opr << 3) & 0x18) | reg); /* get # bits to shift right */
bc = BIT0 >> bc; /* make a bit mask of bit number */
t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
if (GPR[sreg] & bc) /* test the bit in src reg */
t |= CC1BIT; /* set CC1 to the bit value */
PSD1 |= t; /* update the CC's in the PSD */
}
break;
case 0x28>>2: /* 0x28 HLF - HLF */ /* Misc OP REG instructions */
switch(opr & 0xF) {
case 0x0: /* TRSW */
if (modes & BASEBIT)
temp = 0x78FFFFFE; /* bits 1-4 and 24 bit addr for based mode */
else
temp = 0x7807FFFE; /* bits 1-4 and 19 bit addr for non based mode */
addr = GPR[reg]; /* get reg value */
/* we are returning to the addr in reg, set CC's from reg */
/* update the PSD with new address from reg */
PSD1 &= ~temp; /* clean the bits to be changed */
PSD1 |= (addr & temp); /* insert the CC's and address */
i_flags |= BT; /* we branched, so no PC update */
break;
case 0x2: /* XCBR */ /* Exchange base registers */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
temp = BR[reg]; /* get dest reg value */
BR[reg] = BR[sreg]; /* put source reg value int dest reg */
BR[sreg] = temp; /* put dest reg value into src reg */
break;
case 0x4: /* TCCR */ /* Transfer condition codes to GPR bits 28-31 */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
temp = CC >> 27; /* right justify CC's in reg */
GPR[reg] = temp; /* put dest reg value into src reg */
break;
case 0x5: /* TRCC */ /* Transfer GPR bits 28-31 to condition codes */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
PSD1 = ((PSD1 & 0x87fffffe) | ((GPR[reg] & 0xf) << 27)); /* insert CCs from reg */
break;
case 0x8: /* BSUB */ /* Procedure call */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
/* if Rd field is 0 (reg is b6-b8), this is a BSUB instruction */
/* otherwise it is a CALL instruction (Rd != 0) */
if (reg == 0) {
/* BSUB instruction */
uint32 cfp = BR[2]; /* get dword bounded frame pointer from BR2 */
if ((BR[2] & 0x7) != 0) {
/* Fault, must be dw bounded address */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
cfp = BR[2] & 0x00fffff8; /* clean the cfp address to 24 bit dw */
M[cfp>>2] = (PSD1 + 2) & 0x01fffffe; /* save AEXP bit and PC into frame */
M[(cfp>>2)+1] = 0x80000000; /* show frame created by BSUB instr */
BR[1] = BR[sreg] & MASK24; /* Rs reg to BR 1 */
PSD1 = (PSD1 & 0xff000000) | (BR[1] & MASK24); /* New PSD address */
BR[3] = GPR[0]; /* GPR 0 to BR 3 (AP) */
BR[0] = cfp; /* set frame pointer from BR 2 into BR 0 */
i_flags |= BT; /* we changed the PC, so no PC update */
} else
{
/* CALL instruction */
/* get frame pointer from BR2-16 words & make it a dword addr */
uint32 cfp = ((BR[2]-0x40) & 0x00fffff8);
/* if cfp and cfp+15w are in different maps, then addr exception error */
if ((cfp & 0xffe000) != ((cfp+0x3f) & 0xffe000)) {
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
temp = (PSD1+2) & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */
if ((TRAPME = Mem_write(cfp, &temp))) { /* Save the PSD into memory */
goto newpsd; /* memory write error or map fault */
}
temp = 0x00000000; /* show frame created by CALL instr */
if ((TRAPME = Mem_write(cfp+4, &temp))) { /* Save zero into memory */
goto newpsd; /* memory write error or map fault */
}
/* Save BR 0-7 to stack */
for (ix=0; ix<8; ix++) {
if ((TRAPME = Mem_write(cfp+(4*ix)+8, &BR[ix]))) { /* Save into memory */
goto newpsd; /* memory write error or map fault */
}
}
/* save GPR 2-8 to stack */
for (ix=2; ix<8; ix++) {
if ((TRAPME = Mem_write(cfp+(4*ix)+32, &GPR[ix]))) { /* Save into memory */
goto newpsd; /* memory write error or map fault */
}
}
/* keep bits 0-7 from old PSD */
PSD1 = (PSD1 & 0xff000000) | ((BR[sreg]) & MASK24); /* New PSD address */
BR[1] = BR[sreg]; /* Rs reg to BR 1 */
BR[3] = GPR[reg]; /* Rd to BR 3 (AP) */
BR[0] = cfp; /* set current frame pointer into BR[0] */
BR[2] = cfp; /* set current frame pointer into BR[2] */
i_flags |= BT; /* we changed the PC, so no PC update */
}
break;
case 0xC: /* TPCBR */ /* Transfer program Counter to Base Register */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
BR[reg] = PSD1 & 0xfffffe; /* save PC from PSD1 into BR */
break;
case 0xE: /* RETURN */ /* procedure return for basemode calls */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
t = BR[0]; /* get frame pointer from BR[0] */
if ((TRAPME = Mem_read(t+4, &temp))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
/* if Bit0 set, restore all saved regs, else restore only BRs */
if ((temp & BIT0) == 0) { /* see if GPRs are to be restored */
/* Bit 0 is not set, so restore all GPRs */
for (ix=2; ix<8; ix++)
if ((TRAPME = Mem_read(t+ix*4+32, &GPR[ix]))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
}
for (ix=0; ix<8; ix++)
if ((TRAPME = Mem_read(t+ix*4+8, &BR[ix]))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
PSD1 &= ~0x1fffffe; /* leave everything except AEXP bit and PC */
if ((TRAPME = Mem_read(t, &temp))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
PSD1 |= (temp & 0x01fffffe); /* restore AEXP bit and PC from call frame */
i_flags |= BT; /* we changed the PC, so no PC update */
break;
case 0x1: /* INV */
case 0x3: /* INV */
case 0x6: /* INV */
case 0x7: /* INV */
case 0x9: /* INV */
case 0xA: /* INV */
case 0xB: /* INV */
case 0xD: /* INV */
case 0xF: /* INV */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
break;
}
break;
case 0x2C>>2: /* 0x2C HLF - HLF */ /* Reg-Reg instructions */
temp = GPR[reg]; /* reg contents specified by Rd */
addr = GPR[sreg]; /* reg contents specified by Rs */
bc = 0;
switch(opr & 0xF) {
case 0x0: /* TRR */ /* SCC|SD|R1 */
temp = addr; /* set value to go to GPR[reg] */
bc = 1; /* set CC's at end */
break;
case 0x1: /* TRBR */ /* Transfer GPR to BR */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
BR[reg] = GPR[sreg]; /* copy GPR to BR */
break;
case 0x2: /* TBRR */ /* transfer BR to GPR */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
temp = BR[sreg]; /* set base reg value */
bc = 1; /* set CC's at end */
break;
case 0x3: /* TRC */ /* Transfer register complement */
temp = addr ^ FMASK; /* complement Rs */
bc = 1; /* set CC's at end */
break;
case 0x4: /* TRN */ /* Transfer register negative */
temp = NEGATE32(addr); /* negate Rs value */
if (temp == addr) /* overflow if nothing changed */
ovr = 1; /* set overflow flag */
/* reset ovr if val == 0, not set for DIAGS */
if ((temp == 0) & ovr)
ovr = 0;
bc = 1; /* set the CC's */
break;
case 0x5: /* XCR */ /* exchange registers Rd & Rs */
GPR[sreg] = temp; /* Rd to Rs */
set_CCs(temp, ovr); /* set the CC's from original Rd */
temp = addr; /* save the Rs value to Rd reg */
break;
case 0x6: /* INV */
goto inv;
break;
case 0x7: /* LMAP */ /* Load map reg - Diags only */
if ((modes & PRIVBIT) == 0) { /* must be privileged */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* handle trap */
}
/* cpu must be unmapped */
if (modes & MAPMODE) { /* must be unmapped cpu */
TRAPME = MAPFAULT_TRAP; /* Map Fault Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT8; /* set bit 8 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* handle trap */
}
{ /* load the cpu maps using diag psd */
uint32 DPSD[2]; /* the PC for the instruction */
/* get PSD pointed to by real addr in Rd (temp) */
//WAS DPSD[0] = M[temp>>2]; /* get word one of psd */
//WAS DPSD[1] = M[(temp>>2)+1]; /* get word two of psd */
DPSD[0] = RMW(temp); /* get word one of psd */
DPSD[1] = RMW(temp+4); /* get word two of psd */
sim_debug(DEBUG_CMD, &cpu_dev,
"LMAP PSD %08x %08x DPSD %08x %08x modes %08x temp %06x\n",
PSD1, PSD2, DPSD[0], DPSD[1], modes, temp);
if ((DPSD[1] & MAPBIT) == 0) /* if PSD2 is unmapped, treat as NOP */
goto skipit;
if (PSD2 & RETMBIT) /* don't load maps if retain bit set */
goto skipit;
temp2 = modes; /* save modes bits through load_maps call */
modes = DPSD[0] & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */
modes |= MAPMODE; /* set mapped mode flag for load_maps call */
sim_debug(DEBUG_CMD, &cpu_dev,
"LMAP PSD %08x %08x DPSD %08x %08x modes %08x temp2 %08x\n",
PSD1, PSD2, DPSD[0], DPSD[1], modes, temp2);
/* we need to load the new maps */
TRAPME = load_maps(DPSD, 1); /* load maps for new PSD */
sim_debug(DEBUG_CMD, &cpu_dev,
"LMAP TRAPME %08x MAPC[8-c] %08x %08x %08x %08x %08x %08x\n",
TRAPME, MAPC[7], MAPC[8], MAPC[9], MAPC[10], MAPC[11], MAPC[12]);
modes = temp2; /* restore modes flags */
if (TRAPME) {
/* DIAGS wants the cpix for the psd to be the requested one */
PSD2 = (PSD2 & 0xffffc000) | (DPSD[1] & 0x3ffc);
goto newpsd; /* handle trap */
}
goto skipit;
break;
}
break;
case 0x8: /* TRRM */ /* SCC|SD|R1 */
temp = addr & GPR[4]; /* transfer reg-reg masked */
bc = 1; /* set CC's at end */
break;
/* CPUSTATUS bits */
/* Bits 0-19 reserved */
/* Bit 20 =0 Write to writable control store is disabled */
/* =1 Write to writable control store is enabled */
/* Bit 21 =0 Enable PROM mode */
/* =1 Enable Alterable Control Store Mode */
/* Bit 22 =0 Enable High Speed Floating Point Accelerator */
/* =1 Disable High Speed Floating Point Accelerator */
/* Bit 23 =0 Disable privileged mode halt trap */
/* =1 Enable privileged mode halt trap */
/* Bit 24 is reserved */
/* bit 25 =0 Disable software trap handling (enable automatic trap handling) */
/* =1 Enable software trap handling */
/* Bits 26-31 reserved */
case 0x9: /* SETCPU */
if ((modes & PRIVBIT) == 0) { /* must be privileged */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* handle trap */
}
temp2 = CPUSTATUS; /* save original */
sim_debug(DEBUG_EXP, &cpu_dev,
"SETCPU orig %08x user bits %08x New CPUSTATUS %08x\n",
temp2, temp, CPUSTATUS);
CPUSTATUS &= 0xfffff0bf; /* zero bits that can change */
// CPUSTATUS |= (temp & 0x0f40); /* or in the new status bits */
/* make sure WCS is off and prom mode set to 0 (off) */
CPUSTATUS |= (temp & 0x0340); /* or in the new status bits */
break;
case 0xA: /* TMAPR */ /* Transfer map to Reg - Diags only */
if ((modes & PRIVBIT) == 0) { /* must be privileged */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* handle trap */
}
if (CPU_MODEL <= MODEL_27) { /* 7X & 27 must be unmapped */
if (modes & MAPMODE) { /* must be unmapped cpu */
TRAPME = MAPFAULT_TRAP; /* Map Fault Trap */
goto newpsd; /* handle trap */
}
}
/* Rs has map number for even/odd pair loading */
if (CPU_MODEL < MODEL_27) {
/* 32/77 with 32 map regs */
addr &= 0x1e; /* make 0-15 */
temp = MAPC[addr>>1]; /* get even/odd maps */
} else
if ((CPU_MODEL == MODEL_27) || (CPU_MODEL == MODEL_87)) {
/* 32/27 & 32/87 have 256 maps */
addr &= 0xfe; /* make 0-255 */
temp = MAPC[addr>>1]; /* get even/odd maps */
} else {
/* 32/67, 32/97, V6 & V9 have 2048 maps demand paging */
addr &= 0x7ff; /* make 0-2047 */
temp = MAPC[addr>>1]; /* get even/odd maps */
if ((addr & 1) == 0) /* if even reg, use left hw */
temp >>= 16; /* move over reg value */
temp &= 0xffff; /* just 16 bits */
if (TLB[addr] & 0x04000000) /* see if HIT bit set */
temp |= 0x80000000; /* show hit BIT is set */
temp |= ((TLB[addr] & 0xf8000000) >> 16); /* add in protect bits */
if ((addr < 0x26) || (addr > 0x7f8))
sim_debug(DEBUG_CMD, &cpu_dev,
"TMAPR #%4x val %08x TLB %08x RMR %04x MAPC %08x\n",
addr, temp, TLB[addr], RMR(addr<<1), MAPC[addr/2]);
}
GPR[reg] = temp; /* save the temp value to Rd reg */
goto skipit;
break;
case 0xB: /* TRCM */ /* Transfer register complemented masked */
temp = (addr ^ FMASK) & GPR[4]; /* compliment & mask */
bc = 1; /* set the CC's */
break;
case 0xC: /* TRNM */ /* Transfer register negative masked */
temp = NEGATE32(addr); /* complement GPR[reg] */
if (temp == addr) /* check for overflow */
ovr = 1; /* overflow */
/* reset ovr if val == 0, not set for DIAGS */
if ((temp == 0) & ovr)
ovr = 0;
temp &= GPR[4]; /* and with negative reg */
bc = 1; /* set the CC's */
break;
case 0xD: /* XCRM */ /* Exchange registers masked */
addr &= GPR[4]; /* and Rs with mask reg */
temp &= GPR[4]; /* and Rd with mask reg */
GPR[sreg] = temp; /* Rs to get Rd masked value */
set_CCs(temp, ovr); /* set the CC's from original Rd */
temp = addr; /* save the Rs value to Rd reg */
break;
case 0xE: /* TRSC */ /* transfer reg to SPAD */
if ((modes & PRIVBIT) == 0) { /* must be privileged */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* handle trap */
}
t = (GPR[reg] >> 16) & 0xff; /* get SPAD address from Rd (6-8) */
temp2 = SPAD[t]; /* get old SPAD data */
SPAD[t] = GPR[sreg]; /* store Rs into SPAD */
//sim_debug(DEBUG_CMD, &cpu_dev,
//"At TRSC with spad[%02x] %08x old %08x\n", t, SPAD[t], temp2);
break;
case 0xF: /* TSCR */ /* Transfer scratchpad to register */
if ((modes & PRIVBIT) == 0) { /* must be privileged */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* handle trap */
}
t = (GPR[sreg] >> 16) & 0xff; /* get SPAD address from Rs (9-11) */
temp = SPAD[t]; /* get SPAD data into Rd (6-8) */
//sim_debug(DEBUG_CMD, &cpu_dev,
//"At TSCR with spad[%02x] %08x\n", t, SPAD[t]);
break;
}
GPR[reg] = temp; /* save the temp value to Rd reg */
if (bc) /* set cc's if bc set */
set_CCs(temp, ovr); /* set the CC's */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* handle trap */
}
skipit:
break;
case 0x30>>2: /* 0x30 */ /* CALM */
/* Process CALM for 32/27 when in left hw, else invalid */
if ((CPU_MODEL <= MODEL_87) && (CPU_MODEL != MODEL_67)) {
/* DIAG error for 32/27 or 32/87 only */
if ((PSD1 & 2) != 0) /* is it lf hw instruction */
goto inv; /* invalid instr if in rt hw */
addr = SPAD[0xf0]; /* get trap table memory address from SPAD (def 80) */
if (addr == 0 || addr == 0xffffffff) { /* see if secondary vector table set up */
TRAPME = ADDRSPEC_TRAP; /* Not setup, error */
goto newpsd; /* program error */
}
addr = addr + (0x0A << 2); /* addr has mem addr of CALM trap vector (def A8) */
t = M[addr >> 2]; /* get the ICB address from memory */
if (t == 0 || t == 0xffffffff) { /* see if ICB set up */
TRAPME = ADDRSPEC_TRAP; /* Not setup, error */
goto newpsd; /* program error */
}
//WAS bc = PSD2 & 0x3ffc; /* get copy of cpix */
bc = PSD2 & 0x3ff8; /* get copy of cpix */
#ifdef DIAG_HACK
if ((IR & 0xffff) == 2 ) /* if nop in rt hw, bump pc a word */
PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
else
PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1);
#else
/* this will skip over rt hw instruction if any */
PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1); /* bump pc by 1 wd */
#endif
M[t>>2] = PSD1 & 0xfffffffe; /* store PSD 1 + 1HW to point to next instruction */
M[(t>>2)+1] = PSD2; /* store PSD 2 */
PSD1 = M[(t>>2)+2]; /* get new PSD 1 */
PSD2 = (M[(t>>2)+3] & ~0x3ffc) | bc; /* get new PSD 2 w/old cpix */
M[(t>>2)+4] = opr & 0x03FF; /* store calm number in bits 6-15 */
/* set the mode bits and CCs from the new PSD */
CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */
modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */
CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */
CPUSTATUS |= modes; /* not insert into CPUSTATUS */
/* set new map mode and interrupt blocking state in CPUSTATUS */
if (PSD2 & MAPBIT) {
CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */
modes |= MAPMODE; /* set mapped mode */
} else
CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */
/* set interrupt blocking state */
if ((PSD2 & 0x8000) == 0) { /* is it retain blocking state */
if (PSD2 & 0x4000) /* no, is it set blocking state */
CPUSTATUS |= 0x80; /* yes, set blk state in cpu status bit 24 */
else {
CPUSTATUS &= ~0x80; /* no, reset blk state in cpu status bit 24 */
irq_pend = 1; /* start scanning interrupts again */
}
}
PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */
if (CPUSTATUS & 0x80) /* see if old mode is blocked */
PSD2 |= 0x00004000; /* set to blocked state */
PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */
SPAD[0xf5] = PSD2; /* save the current PSD2 */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
TRAPME = 0; /* not to be processed as trap */
goto newpsd; /* new psd loaded */
} else {
// fprintf(stderr, "got CALM trap\r\n");
goto inv; /* invalid instr */
}
break;
case 0x34>>2: /* 0x34 SD|ADR - inv */ /* LA non-basemode */
if (modes & BASEBIT) /* see if based */
goto inv; /* invalid instruction in based mode */
if (modes & EXTDBIT) { /* see if extended mode */
/*TRY*/ dest = (t_uint64)(addr&MASK24); /* just pure 24 bit address */
} else { /* use bits 13-31 */
/*TRY*/ dest = (t_uint64)((addr&0x7ffff) | ((FC & 4) << 17)); /* F bit to bit 12 */
}
break;
case 0x38>>2: /* 0x38 HLF - HLF */ /* REG - REG floating point */
switch(opr & 0xF) {
case 0x0: /* ADR */
temp = GPR[reg]; /* reg contents specified by Rd */
addr = GPR[sreg]; /* reg contents specified by Rs */
t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */
t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */
temp = temp + addr; /* add the values */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if ((t == 3 && (temp & FSIGN) == 0) ||
(t == 0 && (temp & FSIGN) != 0)) {
ovr = 1; /* we have an overflow */
}
i_flags |= SF; /* special processing */
break;
case 0x1: /* ADRFW */
case 0x3: /* SURFW */
/* TODO not on 32/27 */
temp = GPR[reg]; /* reg contents specified by Rd */
addr = GPR[sreg]; /* reg contents specified by Rs */
/* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */
if ((opr & 0xF) == 0x3)
addr = NEGATE32(addr); /* subtract, so negate source */
temp2 = s_adfw(temp, addr, &CC); /* all add float numbers */
sim_debug(DEBUG_CMD, &cpu_dev,
"%s GPR[%d] %08x addr %08x result %08x\n",
(opr&0xf)==3 ? "SURFW":"ADRFW", reg, GPR[reg], GPR[sreg], temp2);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
if (CC & CC1BIT) { /* check for arithmetic exception */
ovr = 1; /* exception */
/* leave Rd & Rs unchanged if AEXPBIT is set */
if (modes & AEXPBIT) {
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
}
/* AEXPBIT not set, so save the fixed return value */
/* return result to destination reg */
GPR[reg] = temp2; /* dest - reg contents specified by Rd */
break;
case 0x2: /* MPRBR */
/* TODO not on 32/27 */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
if (reg & 1) {
/* Spec fault if not even reg */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
temp = GPR[reg+1]; /* get multiplicand */
addr = GPR[sreg]; /* multiplier */
/* change value into a 64 bit value */
dest = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0);
source = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0);
dest = dest * source; /* do the multiply */
i_flags |= (SD|SCC); /* save dest reg and set CC's */
dbl = 1; /* double reg save */
break;
case 0x4: /* DVRFW */
/* TODO not on 32/27 */
temp = GPR[reg]; /* reg contents specified by Rd */
addr = GPR[sreg]; /* reg contents specified by Rs */
/* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */
temp2 = (uint32)s_dvfw(temp, addr, &CC); /* divide reg by sreg */
sim_debug(DEBUG_CMD, &cpu_dev,
"DVRFW GPR[%d] %08x src %08x result %08x\n",
reg, GPR[reg], addr, temp2);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
if (CC & CC1BIT) { /* check for arithmetic exception */
ovr = 1; /* exception */
/* leave Rd & Rs unchanged if AEXPBIT is set */
if (modes & AEXPBIT) {
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
}
/* AEXPBIT not set, so save the fixed return value */
/* return result to destination reg */
GPR[reg] = temp2; /* dest - reg contents specified by Rd */
break;
case 0x5: /* FIXW */
/* TODO not on 32/27 */
/* convert from 32 bit float to 32 bit fixed */
addr = GPR[sreg]; /* reg contents specified by Rs */
temp2 = s_fixw(addr, &CC); /* do conversion */
sim_debug(DEBUG_CMD, &cpu_dev,
"FIXW GPR[%d] %08x result %08x\n",
sreg, GPR[sreg], temp2);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
if (CC & CC1BIT) { /* check for arithmetic exception */
ovr = 1; /* exception */
/* leave Rd & Rs unchanged if AEXPBIT is set */
if (modes & AEXPBIT) {
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
}
/* AEXPBIT not set, so save the fixed return value */
/* return result to destination reg */
GPR[reg] = temp2; /* dest - reg contents specified by Rd */
break; /* go set CC's */
case 0x6: /* MPRFW */
/* TODO not on 32/27 */
temp = GPR[reg]; /* reg contents specified by Rd */
addr = GPR[sreg]; /* reg contents specified by Rs */
/* temp has Rd (GPR[reg]), addr has Rs (GPR[sreg]) */
temp2 = s_mpfw(temp, addr, &CC); /* mult reg by sreg */
sim_debug(DEBUG_CMD, &cpu_dev,
"MPRFW GPR[%d] %08x src %08x result %08x\n",
reg, GPR[reg], addr, temp2);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
if (CC & CC1BIT) { /* check for arithmetic exception */
ovr = 1; /* exception */
/* leave Rd & Rs unchanged if AEXPBIT is set */
if (modes & AEXPBIT) {
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
}
/* AEXPBIT not set, so save the fixed return value */
/* return result to destination reg */
GPR[reg] = temp2; /* dest - reg contents specified by Rd */
break;
case 0x7: /* FLTW */
/* TODO not on 32/27 */
/* convert from 32 bit integer to 32 bit float */
addr = GPR[sreg]; /* reg contents specified by Rs */
GPR[reg] = s_fltw(addr, &CC); /* do conversion & set CC's */
sim_debug(DEBUG_CMD, &cpu_dev,
"FLTW GPR[%d] %08x result %08x\n",
sreg, GPR[sreg], GPR[reg]);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
break;
case 0x8: /* ADRM */
temp = GPR[reg]; /* reg contents specified by Rd */
addr = GPR[sreg]; /* reg contents specified by Rs */
t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */
t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */
temp = temp + addr; /* add the values */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if ((t == 3 && (temp & FSIGN) == 0) ||
(t == 0 && (temp & FSIGN) != 0))
ovr = 1; /* we have an overflow */
temp &= GPR[4]; /* mask the destination reg */
i_flags |= SF; /* special processing */
break;
case 0x9: /* ADRFD */
case 0xB: /* SURFD */
/* TODO not on 32/27 */
if ((reg & 1) || (sreg & 1)) { /* see if any odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */
td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */
source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */
source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */
if ((opr & 0xF) == 0x9)
dest = s_adfd(td, source, &CC); /* add */
else
dest = s_sufd(td, source, &CC); /* subtract */
sim_debug(DEBUG_CMD, &cpu_dev,
"%s GPR[%d] %08x %08x src %016llx result %016llx\n",
(opr&0xf)==8 ? "ADRFD":"SURFD", reg, GPR[reg], GPR[reg+1], source, dest);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
if (CC & CC1BIT) { /* check for arithmetic exception */
ovr = 1; /* exception */
/* leave Rd & Rs unchanged if AEXPBIT is set */
if (modes & AEXPBIT) {
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
}
/* AEXPBIT not set, so save the fixed return value */
/* return result to destination reg */
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
break;
case 0xA: /* DVRBR */
/* TODO not on 32/27 */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
if (reg & 1) {
/* Spec fault if not even reg */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
/* get Rs divisor value */
source = (t_uint64)(GPR[sreg]) | ((GPR[sreg] & FSIGN) ? D32LMASK : 0);
/* merge the dividend regs into the 64bit value */
dest = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]);
if (source == 0) {
goto doovr4;
break;
}
td = (t_int64)dest % (t_int64)source; /* remainder */
if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
td = NEGATE32(td); /* dividend and remainder must be same sign */
dest = (t_int64)dest / (t_int64)source; /* now do the divide */
/* test for overflow */
if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) {
doovr4:
ovr = 1; /* the quotient exceeds 31 bit, overflow */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
}
/* the original regs must be returned unchanged if aexp */
set_CCs(temp, ovr); /* set the CC's */
} else {
GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */
GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */
set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */
}
break;
case 0xC: /* DVRFD */
/* TODO not on 32/27 */
if ((reg & 1) || (sreg & 1)) { /* see if any odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */
td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */
source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */
source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */
dest = s_dvfd(td, source, &CC); /* divide double values */
sim_debug(DEBUG_CMD, &cpu_dev,
"DVRFD GPR[%d] %08x %08x src %016llx result %016llx\n",
reg, GPR[reg], GPR[reg+1], source, dest);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
if (CC & CC1BIT) { /* check for arithmetic exception */
ovr = 1; /* exception */
/* leave Rd & Rs unchanged if AEXPBIT is set */
if (modes & AEXPBIT) {
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
}
/* AEXPBIT not set, so save the fixed return value */
/* return result to destination reg */
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
break;
case 0xD: /* FIXD */
/* dest - reg contents specified by Rd & Rd+1 */
/* source - reg contents specified by Rs & Rs+1 */
if (sreg & 1) {
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
/* merge the sregs into the 64bit value */
source = (((t_uint64)GPR[sreg]) << 32) | ((t_uint64)GPR[sreg+1]);
/* convert from 64 bit double to 64 bit int */
dest = s_fixd(source, &CC);
sim_debug(DEBUG_CMD, &cpu_dev,
"FIXD GPR[%d] %08x %08x result %016llx\n",
sreg, GPR[sreg], GPR[sreg+1], dest);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
if (CC & CC1BIT) { /* check for arithmetic exception */
ovr = 1; /* exception */
/* leave Rd & Rs unchanged if AEXPBIT is set */
if (modes & AEXPBIT) {
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
}
/* AEXPBIT not set, so save the fixed return value */
/* return result to destination reg */
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
break;
case 0xE: /* MPRFD */
/* TODO not on 32/27 */
if ((reg & 1) || (sreg & 1)) { /* see if any odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */
td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */
source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */
source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */
dest = s_mpfd(td, source, &CC); /* multiply double values */
sim_debug(DEBUG_CMD, &cpu_dev,
"MPRFD GPR[%d] %08x %08x src %016llx result %016llx\n",
reg, GPR[reg], GPR[reg+1], source, dest);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
if (CC & CC1BIT) { /* check for arithmetic exception */
ovr = 1; /* exception */
/* leave Rd & Rs unchanged if AEXPBIT is set */
if (modes & AEXPBIT) {
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
}
/* AEXPBIT not set, so save the fixed return value */
/* return result to destination reg */
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
break;
case 0xF: /* FLTD */
/* TODO not on 32/27 */
/* convert from 64 bit integer to 64 bit float */
if ((reg & 1) || (sreg & 1)) { /* see if any odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
source = (((t_uint64)GPR[sreg]) << 32); /* get upper reg value */
source |= (t_uint64)GPR[sreg+1]; /* insert low order reg value */
dest = s_fltd(source, &CC); /* do conversion & set CC's */
sim_debug(DEBUG_CMD, &cpu_dev,
"FLTD GPR[%d] %08x %08x result %016llx\n",
sreg, GPR[sreg], GPR[sreg+1], dest);
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
break;
}
if (i_flags & SF) { /* see if special processing */
GPR[reg] = temp; /* temp has destination reg value */
set_CCs(temp, ovr); /* set the CC's */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* go execute the trap now */
}
}
break;
case 0x3C>>2: /* 0x3C HLF - HLF */ /* SUR and SURM */
temp = GPR[reg]; /* get negative value to add */
temp2 = GPR[sreg]; /* get negative value to add */
addr = NEGATE32(GPR[sreg]); /* reg contents specified by Rs */
switch(opr & 0xF) {
case 0x0: /* SUR */
t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */
t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */
temp = temp + addr; /* add the values */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if ((t == 3 && (temp & FSIGN) == 0) ||
(t == 0 && (temp & FSIGN) != 0))
ovr = 1; /* we have an overflow */
if (addr == FSIGN)
ovr = 1; /* we have an overflow */
break;
case 0x8: /* SURM */
t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */
t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the reg value */
temp = temp + addr; /* add the values */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if ((t == 3 && (temp & FSIGN) == 0) ||
(t == 0 && (temp & FSIGN) != 0))
ovr = 1; /* we have an overflow */
temp &= GPR[4]; /* mask the destination reg */
if (addr == FSIGN)
ovr = 1; /* we have an overflow */
break;
default:
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
break;
}
GPR[reg] = temp; /* save the result */
set_CCs(temp, ovr); /* set CCs for result */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* go execute the trap now */
}
break;
case 0x40>>2: /* 0x40 SCC|SD|HLF - INV */ /* MPR */
if (modes & BASEBIT)
goto inv; /* invalid instruction in basemode */
if (reg & 1) { /* odd reg specified? */
/* Spec fault */
#ifndef NO_HACK
/* HACK HACK HACK for DIAGS */
if (CPU_MODEL <= MODEL_27) { /* DIAG error for 32/27 only */
if ((PSD1 & 2) == 0) /* if lf hw instruction */
i_flags &= ~HLF; /* if nop in rt hw, bump pc a word */
else
PSD1 &= ~3; /* fake out 32/27 diag error */
}
#endif
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if (opr & 0xf) { /* any subop not zero is error */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
temp = GPR[reg+1]; /* get multiplicand */
addr = GPR[sreg]; /* multiplier */
/* change immediate value into a 64 bit value */
dest = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0);
source = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0);
dest = dest * source; /* do the multiply */
dbl = 1; /* double reg save */
break;
case 0x44>>2: /* 0x44 ADR - ADR */ /* DVR */
/* sreg has Rs */
if (reg & 1) {
/* Spec fault */
#ifndef NO_HACK
/* HACK HACK HACK for DIAGS */
if (CPU_MODEL <= MODEL_27) { /* DIAG error for 32/27 only */
if ((PSD1 & 2) == 0) /* if lf hw instruction */
i_flags &= ~HLF; /* if nop in rt hw, bump pc a word */
else
PSD1 &= ~3; /* fake out 32/27 diag error */
}
#endif
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if (opr & 0xf) { /* any subop not zero is error */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
goto newpsd; /* handle trap */
}
/* get Rs divisor value */
source = (t_uint64)(GPR[sreg]) | ((GPR[sreg] & FSIGN) ? D32LMASK : 0);
/* merge the dividend regs into the 64bit value */
dest = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]);
if (source == 0)
goto doovr3;
td = (t_int64)dest % (t_int64)source; /* remainder */
if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
td = NEGATE32(td); /* dividend and remainder must be same sign */
dest = (t_int64)dest / (t_int64)source; /* now do the divide */
int64a = dest;
if (int64a < 0)
int64a = -int64a;
if (int64a > 0x7fffffff) /* if more than 31 bits, we have an error */
goto doovr3;
if (((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) ||
(((dest & D32LMASK) == D32LMASK) && ((dest & D32RMASK) == 0))) { /* test for overflow */
doovr3:
dest = (((t_uint64)GPR[reg]) << 32);/* insert upper reg value */
dest |= (t_uint64)GPR[reg+1]; /* get low order reg value */
ovr = 1; /* the quotient exceeds 31 bit, overflow */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
}
/* the original regs must be returned unchanged if aexp */
CC = CC1BIT; /* set ovr CC bit */
if (dest == 0)
CC |= CC4BIT; /* dw is zero, so CC4 */
else
if (dest & DMSIGN)
CC |= CC3BIT; /* it is neg dw, so CC3 */
else
CC |= CC2BIT; /* then dest > 0, so CC2 */
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
PSD1 |= CC; /* update the CC's in the PSD */
} else {
GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */
GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */
set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */
}
break;
case 0x48>>2: /* 0x48 INV - INV */ /* unused opcodes */
case 0x4C>>2: /* 0x4C INV - INV */ /* unused opcodes */
default:
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
break;
case 0x50>>2: /* 0x50 INV - SD|ADR */ /* LA basemode LABRM */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
/*TRY*/ dest = (t_uint64)(addr&MASK24); /* just pure 24 bit address */
break;
case 0x54>>2: /* 0x54 SM|ADR - INV */ /* (basemode STWBR) */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
if (FC != 0) { /* word address only */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
dest = BR[reg]; /* save the BR to memory */
break;
case 0x58>>2: /* 0x58 SB|ADR - INV */ /* (basemode SUABR and LABR) */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
if ((FC & 4) == 0) { /* see if SUABR F=0 0x5800 */
dest = BR[reg] - addr; /* subtract addr from the BR and store back to BR */
} else { /* LABR if F=1 0x5808 */
dest = addr; /* addr goes to specified BR */
}
break;
case 0x5C>>2: /* 0x5C RM|ADR - INV */ /* (basemode LWBR and BSUBM) */
if ((modes & BASEBIT) == 0) /* see if nonbased */
goto inv; /* invalid instruction in nonbased mode */
if ((FC & 3) != 0) { /* word address only */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if ((FC & 0x4) == 0) { /* this is a LWBR 0x5C00 instruction */
BR[reg] = (uint32)source; /* load memory location into BR */
} else
{ /* this is a CALLM/BSUBM instruction */
/* if Rd field is 0 (reg is b6-8), this is a BSUBM instruction */
/* otherwise it is a CALLM instruction (Rd != 0) */
if (reg == 0) {
/* BSUBM instruction */
uint32 cfp = BR[2]; /* get dword bounded frame pointer from BR2 */
if ((BR[2] & 0x7) != 0) {
/* Fault, must be dw bounded address */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
temp = (PSD1+4) & 0x01fffffe; /* save AEXP bit and PC from PSD1 into frame */
if ((TRAPME = Mem_write(cfp, &temp))) { /* Save the PSD into memory */
goto newpsd; /* memory write error or map fault */
}
temp = 0x80000000; /* show frame created by BSUBM instr */
if ((TRAPME = Mem_write(cfp+4, &temp))) { /* Save zero into memory */
goto newpsd; /* memory write error or map fault */
}
temp = addr & 0xfffffe; /* CALL memory address */
if ((temp & 0x3) != 0) { /* check for word aligned */
/* Fault, must be word bounded address */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(temp, &addr))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
BR[1] = addr; /* effective address contents to BR 1 */
/* keep bits 0-7 from old PSD */
PSD1 = ((PSD1 & 0xff000000) | (BR[1] & 0x01fffffe)); /* New PSD address */
BR[3] = GPR[0]; /* GPR[0] to BR[3] (AP) */
BR[0] = cfp; /* set current frame pointer into BR[0] */
i_flags |= BT; /* we changed the PC, so no PC update */
} else {
/* CALLM instruction */
/* get frame pointer from BR2 - 16 words & make it a dword addr */
uint32 cfp = ((BR[2]-0x40) & 0x00fffff8);
/* if cfp and cfp+15w are in different maps, then addr exception error */
if ((cfp & 0xffe000) != ((cfp+0x3f) & 0xffe000)) {
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
temp = (PSD1+4) & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */
if ((TRAPME = Mem_write(cfp, &temp))) { /* Save the PSD into memory */
goto newpsd; /* memory write error or map fault */
}
temp = 0x00000000; /* show frame created by CALL instr */
if ((TRAPME = Mem_write(cfp+4, &temp))) { /* Save zero into memory */
goto newpsd; /* memory write error or map fault */
}
/* save the BRs 0-7 on stack */
for (ix=0; ix<8; ix++) {
if ((TRAPME = Mem_write(cfp+(4*ix)+8, &BR[ix]))) { /* Save into memory */
goto newpsd; /* memory write error or map fault */
}
}
/* save GPRs 2-7 on stack */
for (ix=2; ix<8; ix++) {
if ((TRAPME = Mem_write(cfp+(4*ix)+32, &GPR[ix]))) { /* Save into memory */
goto newpsd; /* memory write error or map fault */
}
}
temp = addr & 0xfffffe; /* CALL memory address */
if ((temp & 0x3) != 0) { /* check for word aligned */
/* Fault, must be word bounded address */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(temp, &addr))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
BR[1] = addr; /* effective address contents to BR 1 */
/* keep bits 0-6 from old PSD */
PSD1 = (PSD1 & 0xff000000) | ((BR[1]) & 0x01fffffe); /* New PSD address */
BR[3] = GPR[reg]; /* Rd to BR 3 (AP) */
BR[0] = cfp; /* set current frame pointer into BR[0] */
BR[2] = cfp; /* set current frame pointer into BR[2] */
i_flags |= BT; /* we changed the PC, so no PC update */
}
}
break;
case 0x60>>2: /* 0x60 HLF - INV */ /* NOR Rd,Rs */
if ((modes & BASEBIT)) { /* only for nonbased mode */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
if (opr & 0xf) { /* any subop not zero is error */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
/* exponent must not be zero or all 1's */
/* normalize the value Rd in GPR[reg] and put exponent into Rs GPR[sreg] */
temp = s_nor(GPR[reg], &GPR[sreg]);
sim_debug(DEBUG_CMD, &cpu_dev,
"NOR GPR[%d] %08x result %08x exp %08x\n",
reg, GPR[reg], temp, GPR[sreg]);
GPR[reg] = temp;
break;
case 0x64>>2: /* 0x64 SD|HLF - INV */ /* NORD */
if ((modes & BASEBIT)) { /* only for nonbased mode */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if (opr & 0xf) { /* any subop not zero is error */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
/* shift until upper 5 bits are neither 0 or all 1's */
/* merge the GPR[reg] & GPR[reg+1] into a 64bit value */
td = (((t_uint64)GPR[reg]) << 32) | ((t_uint64)GPR[reg+1]);
/* normalize the value Rd in GPR[reg] and put exponent into Rs GPR[sreg] */
dest = s_nord(td, &GPR[sreg]);
sim_debug(DEBUG_CMD, &cpu_dev,
"NORD GPR[%d] %08x %08x result %016llx exp %08x\n",
reg, GPR[reg], GPR[reg+1], dest, GPR[sreg]);
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
break;
case 0x68>>2: /* 0x68 HLF - INV */ /* non basemode SCZ */
if (modes & BASEBIT)
goto inv; /* invalid instruction */
if (opr & 0xf) { /* any subop not zero is error */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
goto sacz; /* use basemode sacz instruction */
case 0x6C>>2: /* 0x6C HLF - INV */ /* non basemode SRA & SLA */
if (modes & BASEBIT)
goto inv; /* invalid instruction */
bc = opr & 0x1f; /* get bit shift count */
temp = GPR[reg]; /* get reg value to shift */
t = temp & FSIGN; /* sign value */
if (opr & 0x0040) { /* is this SLA */
ovr = 0; /* set ovr off */
for (ix=0; ix<bc; ix++) {
temp <<= 1; /* shift bit into sign position */
if ((temp & FSIGN) ^ t) /* see if sign bit changed */
ovr = 1; /* set arithmetic exception flag */
}
temp &= ~BIT0; /* clear sign bit */
temp |= t; /* restore original sign bit */
GPR[reg] = temp; /* save the new value */
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
if (ovr)
PSD1 |= BIT1; /* CC1 in PSD */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* go execute the trap now */
}
} else { /* this is a SRA */
for (ix=0; ix<bc; ix++) {
temp >>= 1; /* shift bit 0 right one bit */
temp |= t; /* restore original sign bit */
}
GPR[reg] = temp; /* save the new value */
}
break;
case 0x70>>2: /* 0x70 SD|HLF - INV */ /* non-basemode SRL & SLL */
if (modes & BASEBIT)
goto inv; /* invalid instruction in basemode */
bc = opr & 0x1f; /* get bit shift count */
if (opr & 0x0040) /* is this SLL, bit 9 set */
GPR[reg] <<= bc; /* shift left #bits */
else
GPR[reg] >>= bc; /* shift right #bits */
break;
case 0x74>>2: /* 0x74 SD|HLF - INV */ /* non-basemode SRC & SLC */
if (modes & BASEBIT)
goto inv; /* invalid instruction in basemode */
bc = opr & 0x1f; /* get bit shift count */
temp = GPR[reg]; /* get reg value to shift */
if (opr & 0x0040) { /* is this SLC, bit 9 set */
for (ix=0; ix<bc; ix++) {
t = temp & BIT0; /* get sign bit status */
temp <<= 1; /* shift the bit out */
if (t)
temp |= 1; /* the sign bit status */
}
} else { /* this is SRC, bit 9 not set */
for (ix=0; ix<bc; ix++) {
t = temp & 1; /* get bit 31 status */
temp >>= 1; /* shift the bit out */
if (t)
temp |= BIT0; /* put in new sign bit */
}
}
GPR[reg] = temp; /* shift result */
break;
case 0x78>>2: /* 0x78 HLF - INV */ /* non-basemode SRAD & SLAD */
if (modes & BASEBIT) /* Base mode? */
goto inv; /* invalid instruction in basemode */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
bc = opr & 0x1f; /* get bit shift count */
dest = (t_uint64)GPR[reg+1]; /* get low order reg value */
dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */
source = dest & DMSIGN; /* 64 bit sign value */
if (opr & 0x0040) { /* is this SLAD */
ovr = 0; /* set ovr off */
for (ix=0; ix<bc; ix++) {
dest <<= 1; /* shift bit into sign position */
if ((dest & DMSIGN) ^ source) /* see if sign bit changed */
ovr = 1; /* set arithmetic exception flag */
}
dest &= ~DMSIGN; /* clear sign bit */
dest |= source; /* restore original sign bit */
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
if (ovr)
PSD1 |= BIT1; /* CC1 in PSD */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* go execute the trap now */
}
} else { /* this is a SRAD */
for (ix=0; ix<bc; ix++) {
dest >>= 1; /* shift bit 0 right one bit */
dest |= source; /* restore original sign bit */
}
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
}
break;
case 0x7C>>2: /* 0x7C HLF - INV */ /* non-basemode SRLD & SLLD */
if (modes & BASEBIT)
goto inv; /* invalid instruction in basemode */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
dest = (t_uint64)GPR[reg+1]; /* get low order reg value */
dest |= (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */
bc = opr & 0x1f; /* get bit shift count */
if (opr & 0x0040) /* is this SLL, bit 9 set */
dest <<= bc; /* shift left #bits */
else
dest >>= bc; /* shift right #bits */
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
break;
case 0x80>>2: /* 0x80 SD|ADR - SD|ADR */ /* LEAR */
/* convert address to real physical address */
TRAPME = RealAddr(addr, &temp, &t, MEM_RD);
//sim_debug(DEBUG_EXP, &cpu_dev,
//"At LEAR convert %06x to addr %08x\n", addr, temp);
// diag allows any addr if mapped
if (TRAPME != ALLOK) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"At LEAR with TRAPME %04x addr %08x\n", TRAPME, addr);
goto newpsd; /* memory read error or map fault */
}
/* set access bit for mapped addresses */
if ((CPU_MODEL >= MODEL_V6) && (modes & MAPMODE)) {
uint32 map, mix, nix, msdl, mpl, mmap;
nix = (addr >> 13) & 0x7ff; /* get 11 bit map value */
/* check our access to the memory */
switch (t & 0x0e) {
case 0x0: case 0x2:
/* O/S or user has no read/execute access, do protection violation */
sim_debug(DEBUG_TRAP, &cpu_dev,
"LEAR readI protect error @ %06x prot %02x modes %08x page %04x\n",
addr, t, modes, nix);
if (CPU_MODEL == MODEL_V9)
TRAPSTATUS |= BIT1; /* set bit 1 of trap status */
else
TRAPSTATUS |= BIT12; /* set bit 12 of trap status */
return MPVIOL; /* return memory protection violation */
case 0x4: case 0x6: case 0x8: case 0xc: case 0xa: case 0xe:
/* O/S or user has read/execute access, no protection violation */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"LEAR readJ protect is ok @ %06x prot %02x modes %08x page %04x\n",
addr, t, modes, nix);
}
/* we have read access, so go set the access bit in the map entry */
mpl = SPAD[0xf3]; /* get mpl from spad address */
if (nix < BPIX) {
mix = nix; /* get map index in memory */
msdl = RMW(mpl+4); /* get mpl entry for O/S */
} else {
mix = nix-BPIX; /* get map index in memory */
msdl = RMW(mpl+CPIX+4); /* get mpl entry for given CPIX */
}
mmap = RMH(msdl+(mix<<1)); /* map content from memory */
map = RMR((nix<<1)); /* read the map cache contents */
if (((map & 0x800) == 0)) { /* see if access bit is already on */
mmap |= 0x800; /* set the accessed bit in the map cache entry */
map |= 0x800; /* set the accessed bit in the memory map entry */
WMR((nix<<1), map); /* store the map reg contents into cache */
TLB[nix] |= 0x0c000000; /* set the accessed & hit bits in TLB too */
WMH(msdl+(mix<<1), mmap); /* save modified memory map with access bit set */
sim_debug(DEBUG_EXP, &cpu_dev,
"LEAR Laddr %06x page %04x set access bit TLB %08x map %04x nmap %04x\n",
addr, nix, TLB[nix], map, mmap);
}
}
/* OS code says F bit is not transferred, so just ignore it */
/* DIAGS needs it, so put it back */
if (FC & 4) /* see if F bit was set */
temp |= 0x01000000; /* set bit 7 of address */
//sim_debug(DEBUG_EXP, &cpu_dev,
//"At LEAR convert %06x to addr %08x\n", addr, temp);
dest = temp; /* put in dest to go out */
break;
case 0x84>>2: /* 0x84 SD|RR|RNX|ADR - SD|RNX|ADR */ /* ANMx */
td = dest & source; /* DO ANMX */
CC = 0;
switch(FC) { /* adjust for hw or bytes */
case 4: case 5: case 6: case 7: /* byte address */
/* ANMB */
td &= 0xff; /* mask out right most byte */
dest &= 0xffffff00; /* make place for byte */
if (td == 0)
CC |= CC4BIT; /* byte is zero, so CC4 */
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
case 1: /* left halfword addr */
case 3: /* right halfword addr */
/* ANMH */
td &= RMASK; /* mask out right most 16 bits */
dest &= LMASK; /* make place for halfword */
if (td == 0)
CC |= CC4BIT; /* hw is zero, so CC4 */
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
case 0: /* 32 bit word */
/* ANMW */
td &= D32RMASK; /* mask out right most 32 bits */
dest = 0; /* make place for 64 bits */
if (td == 0)
CC |= CC4BIT; /* word is zero, so CC4 */
else
if (td & 0x80000000)
CC |= CC3BIT; /* it is neg wd, so CC3 */
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
case 2: /* 64 bit double */
/* ANMD */
dest = 0; /* make place for 64 bits */
if (td == 0)
CC |= CC4BIT; /* dw is zero, so CC4 */
else
if (td & DMSIGN)
CC |= CC3BIT; /* it is neg dw, so CC3 */
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
}
dest |= td; /* insert result into dest */
if (FC != 2) /* do not sign extend DW */
if (dest & 0x80000000) /* see if we need to sign extend */
dest |= D32LMASK; /* force upper word to all ones */
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
PSD1 |= CC; /* update the CC's in the PSD */
break;
case 0x88>>2: /* 0x88 SD|RR|RNX|ADR - SD|RNX|ADR */ /* ORMx */
td = dest | source; /* DO ORMX */
meoa: /* merge point for eor, and, or */
CC = 0;
switch(FC) { /* adjust for hw or bytes */
case 4: case 5: case 6: case 7: /* byte address */
/* ORMB */
td &= 0xff; /* mask out right most byte */
dest &= 0xffffff00; /* make place for byte */
dest |= td; /* insert result into dest */
if (dest == 0)
CC |= CC4BIT; /* byte is zero, so CC4 */
else
if (dest & MSIGN) {
CC |= CC3BIT; /* assume negative */
dest |= D32LMASK; /* force upper word to all ones */
}
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
case 1: /* left halfword addr */
case 3: /* right halfword addr */
/* ORMH */
td &= RMASK; /* mask out right most 16 bits */
dest &= LMASK; /* make place for halfword */
dest |= td; /* insert result into dest */
if (dest == 0)
CC |= CC4BIT; /* byte is zero, so CC4 */
else
if (dest & MSIGN) {
CC |= CC3BIT; /* assume negative */
dest |= D32LMASK; /* force upper word to all ones */
}
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
case 0: /* 32 bit word */
/* ORMW */
td &= D32RMASK; /* mask out right most 32 bits */
dest = 0; /* make place for 64 bits */
dest |= td; /* insert result into dest */
if (dest == 0)
CC |= CC4BIT; /* byte is zero, so CC4 */
else
if (dest & MSIGN) {
CC |= CC3BIT; /* assume negative */
dest |= D32LMASK; /* force upper word to all ones */
}
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
case 2: /* 64 bit double */
/* ORMD */
dest = 0; /* make place for 64 bits */
dest |= td; /* insert result into dest */
if (dest == 0)
CC |= CC4BIT; /* byte is zero, so CC4 */
else
if (dest & DMSIGN)
CC |= CC3BIT; /* assume negative */
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
}
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
PSD1 |= CC; /* update the CC's in the PSD */
break;
case 0x8C>>2: /* 0x8C SD|RR|RNX|ADR - SD|RNX|ADR */ /* EOMx */
/* must special handle because we are getting bit difference */
/* for word, halfword, & byte zero the upper 32 bits of dest */
/* Diags require CC's to be set on result value of byte, hw, wd, or dw */
td = dest ^ source; /* DO EOMX */
goto meoa;
break;
case 0x90>>2: /* 0x90 SCC|RR|RM|ADR - RM|ADR */ /* CAMx */
if (dbl == 0) {
int32a = dest & D32RMASK; /* mask out right most 32 bits */
int32b = source & D32RMASK; /* mask out right most 32 bits */
int32c = int32a - int32b; /* signed diff */
td = int32c;
if (int32a > int32b) dest = 1;
else if (int32a == int32b) dest = 0;
else dest = -1;
} else {
int64a = dest; /* mask out right most 32 bits */
int64b = source; /* mask out right most 32 bits */
int64c = int64a - int64b; /* signed diff */
td = int64c;
if (int64a > int64b) dest = 1;
else if (int64a == int64b) dest = 0;
else dest = -1;
}
break;
case 0x94>>2: /* 0x94 RR|RM|ADR - RM|ADR */ /* CMMx */
/* CMMD needs both regs to be masked with R4 */
if (dbl) {
/* we need to and both regs with R4 */
t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK);
td = dest; /* save dest */
dest ^= source;
dest &= nm; /* mask both regs with reg 4 contents */
} else {
td = dest; /* save dest */
dest ^= source; /* <= 32 bits, so just do lower 32 bits */
dest &= (((t_uint64)GPR[4]) & D32RMASK); /* mask with reg 4 contents */
}
CC = 0;
if (dest == 0ll)
CC |= CC4BIT;
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
PSD1 |= CC; /* update the CC's in the PSD */
break;
case 0x98>>2: /* 0x98 ADR - ADR */ /* SBM */
if ((FC & 04) == 0) {
/* Fault, f-bit must be set for SBM instruction */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/
/* use C bits and bits 6-8 (reg) to generate shift bit count */
bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */
bc = BIT0 >> bc; /* make a bit mask of bit number */
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
if (temp & bc) /* test the bit in memory */
t |= CC1BIT; /* set CC1 to the bit value */
PSD1 |= t; /* update the CC's in the PSD */
temp |= bc; /* set the bit in temp */
if ((TRAPME = Mem_write(addr, &temp))) { /* put word back into memory */
goto newpsd; /* memory write error or map fault */
}
break;
case 0x9C>>2: /* 0x9C ADR - ADR */ /* ZBM */
if ((FC & 04) == 0) {
/* Fault, byte address not allowed */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/
/* use C bits and bits 6-8 (reg) to generate shift bit count */
bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */
bc = BIT0 >> bc; /* make a bit mask of bit number */
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
if (temp & bc) /* test the bit in memory */
t |= CC1BIT; /* set CC1 to the bit value */
PSD1 |= t; /* update the CC's in the PSD */
temp &= ~bc; /* reset the bit in temp */
if ((TRAPME = Mem_write(addr, &temp))) { /* put word into memory */
goto newpsd; /* memory write error or map fault */
}
break;
case 0xA0>>2: /* 0xA0 ADR - ADR */ /* ABM */
if ((FC & 04) == 0) {
/* Fault, byte address not allowed */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
/* use C bits and bits 6-8 (reg) to generate shift bit count */
bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */
bc = BIT0 >> bc; /* make a bit mask of bit number */
t = (temp & FSIGN) != 0; /* set flag for sign bit not set in temp value */
t |= ((bc & FSIGN) != 0) ? 2 : 0; /* ditto for the bit value */
temp += bc; /* add the bit value to the reg */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if ((t == 3 && (temp & FSIGN) == 0) ||
(t == 0 && (temp & FSIGN) != 0)) {
ovr = 1; /* we have an overflow */
}
set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */
if ((TRAPME = Mem_write(addr, &temp))) { /* put word into memory */
goto newpsd; /* memory write error or map fault */
}
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* handle trap */
}
break;
case 0xA4>>2: /* 0xA4 ADR - ADR */ /* TBM */
if ((FC & 04) == 0) {
/* Fault, byte address not allowed */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */
goto newpsd; /* memory read error or map fault */
t = (PSD1 & 0x70000000) >> 1; /* get old CC bits 1-3 into CCs 2-4*/
/* use C bits and bits 6-8 (reg) to generate shift bit count */
bc = ((FC & 3) << 3) | reg; /* get # bits to shift right */
bc = BIT0 >> bc; /* make a bit mask of bit number */
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
if (temp & bc) /* test the bit in memory */
t |= CC1BIT; /* set CC1 to the bit value */
PSD1 |= t; /* update the CC's in the PSD */
break;
case 0xA8>>2: /* 0xA8 RM|ADR - RM|ADR */ /* EXM */
if ((FC & 04) != 0 || FC == 2) { /* can not be byte or doubleword */
/* Fault */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
if (CPU_MODEL == MODEL_V9) /* V9 wants bit0 set in pfault */
if (TRAPME == DMDPG) /* demand page request */
pfault |= 0x80000000; /* set instruction fetch paging error */
goto newpsd; /* memory read error or map fault */
}
IR = temp; /* get instruction from memory */
if (FC == 3) /* see if right halfword specified */
IR <<= 16; /* move over the HW instruction */
if ((IR & 0xFC7F0000) == 0xC8070000 ||
(IR & 0xFF800000) == 0xA8000000 ||
(IR & 0xFC000000) == 0x80000000) {
/* Fault, attempt to execute another EXR, EXRR, EXM, or LEAR */
goto inv; /* invalid instruction */
}
EXM_EXR = 4; /* set PC increment for EXM */
OPSD1 &= 0x87FFFFFE; /* clear the old PSD CC's */
OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the old PSD */
/* TODO Update other history information for this instruction */
if (hst_lnt) {
hst[hst_p].opsd1 = OPSD1; /* update the CC in opsd1 */
hst[hst_p].npsd1 = PSD1; /* save new psd1 */
hst[hst_p].npsd2 = PSD2; /* save new psd2 */
hst[hst_p].modes = modes; /* save current mode bits */
for (ix=0; ix<8; ix++) {
hst[hst_p].reg[ix] = GPR[ix]; /* save reg */
hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */
}
}
/* DEBUG_INST support code */
OPSD1 &= 0x87FFFFFE; /* clear the old CC's */
OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */
/* output mapped/unmapped */
if (modes & MAPMODE)
sim_debug(DEBUG_INST, &cpu_dev, "M%.8x %.8x %.8x ", OPSD1, PSD2, OIR);
else
sim_debug(DEBUG_INST, &cpu_dev, "U%.8x %.8x %.8x ", OPSD1, PSD2, OIR);
if (cpu_dev.dctrl & DEBUG_INST)
fprint_inst(sim_deb, OIR, 0); /* display instruction */
sim_debug(DEBUG_INST, &cpu_dev,
"\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]);
sim_debug(DEBUG_INST, &cpu_dev,
" R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"EXM skipinstr %x irq_pend %x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
skipinstr, irq_pend, PSD1, PSD2, CPUSTATUS);
#endif
/*DIAG*/ skipinstr = 0; /* only test this once */
goto exec; /* go execute the instruction */
break;
case 0xAC>>2: /* 0xAC SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* Lx */
dest = source; /* set value to load into reg */
break;
case 0xB0>>2: /* 0xB0 SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* LMx */
/* LMD needs both regs to be masked with R4 */
if (dbl) {
/* we need to and both regs with R4 */
t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK);
dest = source & nm; /* mask both regs with reg 4 contents */
} else {
dest = source; /* <= 32 bits, so just do lower 32 bits */
dest &= (((t_uint64)GPR[4]) & D32RMASK); /* mask with reg 4 contents */
if (dest & 0x80000000) /* see if we need to sign extend */
dest |= D32LMASK; /* force upper word to all ones */
}
break;
case 0xB4>>2: /* 0xB4 SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* LNx */
dest = NEGATE32(source); /* set the value to load into reg */
td = dest;
if (dest != 0 && (dest == source || dest == 0x80000000))
ovr = 1; /* set arithmetic exception status */
if (FC != 2) /* do not sign extend DW */
if (dest & 0x80000000) /* see if we need to sign extend */
dest |= D32LMASK; /* force upper word to all ones */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (dest != 0 && ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
}
break;
case 0xBC>>2: /* 0xBC SD|RR|RM|ADR - SD|RR|RM|ADR */ /* SUMx */
source = NEGATE32(source);
/* Fall through */
case 0xB8>>2: /* 0xB8 SD|RR|RM|ADR - SD|RR|RM|ADR */ /* ADMx */
ovr = 0;
CC = 0;
/* DIAG fixs */
if (dbl == 0) {
source &= D32RMASK; /* just 32 bits */
dest &= D32RMASK; /* just 32 bits */
t = (source & MSIGN) != 0;
t |= ((dest & MSIGN) != 0) ? 2 : 0;
td = dest + source; /* DO ADMx*/
td &= D32RMASK; /* mask out right most 32 bits */
dest = 0; /* make place for 64 bits */
dest |= td; /* insert 32 bit result into dest */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if (((t == 3) && ((dest & MSIGN) == 0)) ||
((t == 0) && ((dest & MSIGN) != 0)))
ovr = 1;
if ((td == 0) && ((source & MSIGN) == MSIGN) && ovr)
ovr = 0; /* Diags want 0 and no ovr on MSIGN - MSIGN */
if (dest & MSIGN)
dest = (D32LMASK | dest); /* sign extend */
else
dest = (D32RMASK & dest); /* zero fill */
if (td == 0)
CC |= CC4BIT; /* word is zero, so CC4 */
else
if (td & 0x80000000)
CC |= CC3BIT; /* it is neg wd, so CC3 */
else
CC |= CC2BIT; /* then td > 0, so CC2 */
} else {
/* ADMD */
t = (source & DMSIGN) != 0;
t |= ((dest & DMSIGN) != 0) ? 2 : 0;
td = dest + source; /* get sum */
dest = td; /* insert 64 bit result into dest */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if (((t == 3) && ((dest & DMSIGN) == 0)) ||
((t == 0) && ((dest & DMSIGN) != 0)))
ovr = 1;
if (td == 0)
CC |= CC4BIT; /* word is zero, so CC4 */
else
if (td & DMSIGN)
CC |= CC3BIT; /* it is neg wd, so CC3 */
else
CC |= CC2BIT; /* then td > 0, so CC2 */
}
if (ovr)
CC |= CC1BIT; /* set overflow CC */
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
PSD1 |= CC; /* update the CC's in the PSD */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
}
break;
case 0xC0>>2: /* 0xC0 SCC|SD|RM|ADR - SCC|SD|RM|ADR */ /* MPMx */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if (FC == 2) { /* must not be double word adddress */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
td = dest;
dest = GPR[reg+1]; /* get low order reg value */
if (dest & MSIGN)
dest = (D32LMASK | dest); /* sign extend */
dest = (t_uint64)((t_int64)dest * (t_int64)source);
dbl = 1;
break;
case 0xC4>>2: /* 0xC4 RM|ADR - RM|ADR */ /* DVMx */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if (FC == 2) { /* must not be double word adddress */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
if (source == 0)
goto doovr; /* we have div by zero */
dest = (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */
dest |= (t_uint64)GPR[reg+1]; /* get low order reg value */
td = ((t_int64)dest % (t_int64)source); /* remainder */
if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
td = NEGATE32(td); /* dividend and remainder must be same sign */
dest = (t_int64)dest / (t_int64)source; /* now do the divide */
int64a = dest;
if (int64a < 0)
int64a = -int64a;
if (int64a > 0x7fffffff) /* if more than 31 bits, we have an error */
goto doovr;
if (((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) ||
(((dest & D32LMASK) == D32LMASK) && ((dest & D32RMASK) == 0))) { /* test for overflow */
doovr:
dest = (((t_uint64)GPR[reg]) << 32);/* insert upper reg value */
dest |= (t_uint64)GPR[reg+1]; /* get low order reg value */
ovr = 1; /* the quotient exceeds 31 bit, overflow */
/* the original regs must be returned unchanged if aexp */
CC = CC1BIT; /* set ovr CC bit */
if (dest == 0)
CC |= CC4BIT; /* dw is zero, so CC4 */
else
if (dest & DMSIGN)
CC |= CC3BIT; /* it is neg dw, so CC3 */
else
CC |= CC2BIT; /* then dest > 0, so CC2 */
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
PSD1 |= CC; /* update the CC's in the PSD */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (modes & AEXPBIT)
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
} else {
GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */
GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */
set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */
}
break;
case 0xC8>>2: /* 0xC8 IMM - IMM */ /* Immedate */
temp = GPR[reg]; /* get reg contents */
addr = IR & RMASK; /* sign extend 16 bit imm value from IR */
if (addr & 0x8000) /* negative */
addr |= LMASK; /* extend sign */
switch(opr & 0xF) { /* switch on aug code */
case 0x0: /* LI */ /* SCC | SD */
GPR[reg] = addr; /* put immediate value into reg */
set_CCs(addr, ovr); /* set the CC's, CC1 = ovr */
break;
case 0x2: /* SUI */
addr = NEGATE32(addr); /* just make value a negative add */
/* drop through */
case 0x1: /* ADI */
t = (temp & FSIGN) != 0; /* set flag for sign bit not set in reg value */
t |= ((addr & FSIGN) != 0) ? 2 : 0; /* ditto for the extended immediate value */
temp = temp + addr; /* now add the numbers */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if ((t == 3 && (temp & FSIGN) == 0) ||
(t == 0 && (temp & FSIGN) != 0))
ovr = 1; /* we have an overflow */
GPR[reg] = temp; /* save the result */
set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
goto newpsd; /* go execute the trap now */
}
break;
case 0x3: /* MPI */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
/* change immediate value into a 64 bit value */
source = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0);
temp = GPR[reg+1]; /* get reg multiplier */
dest = ((t_uint64)(temp & FMASK)) | ((temp & FSIGN) ? D32LMASK : 0);
dest = dest * source; /* do the multiply */
i_flags |= (SD|SCC); /* save regs and set CC's */
dbl = 1; /* double reg save */
break;
case 0x4: /* DVI */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
/* change immediate value into a 64 bit value */
source = ((t_uint64)(addr & FMASK)) | ((addr & FSIGN) ? D32LMASK : 0);
if (source == 0) {
goto doovr2;
}
dest = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */
dest |= (t_uint64)GPR[reg+1]; /* insert low order reg value */
td = ((t_int64)dest % (t_int64)source); /* remainder */
/* fix double reg if neg remainder */
if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
td = NEGATE32(td); /* dividend and remainder must be same sign */
dest = (t_int64)dest / (t_int64)source; /* now do the divide */
int64a = dest;
if (int64a < 0)
int64a = -int64a;
if (int64a > 0x7fffffff) /* if more than 31 bits, we have an error */
goto doovr2;
if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) { /* test for overflow */
doovr2:
dest = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */
dest |= (t_uint64)GPR[reg+1]; /* insert low order reg value */
ovr = 1; /* the quotient exceeds 31 bit, overflow */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (modes & AEXPBIT)
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
/* the original regs must be returned unchanged if aexp */
/* put reg values back in dest for CC test */
CC = CC1BIT; /* set ovr CC bit */
if (dest == 0)
CC |= CC4BIT; /* dw is zero, so CC4 */
else
if (dest & DMSIGN)
CC |= CC3BIT; /* it is neg dw, so CC3 */
else
CC |= CC2BIT; /* then dest > 0, so CC2 */
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
PSD1 |= CC; /* update the CC's in the PSD */
} else {
GPR[reg] = (uint32)(td & FMASK); /* reg gets remainder, reg+1 quotient */
GPR[reg+1] = (uint32)(dest & FMASK); /* store quotient in reg+1 */
set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */
}
break;
case 0x5: /* CI */ /* SCC */
temp = ((int)temp - (int)addr); /* subtract imm value from reg value */
set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */
break;
/* SVC instruction format C806 */
/* |-------+-------+-------+-------+-------+-------+-------+-------| */
/* |0 0 0 0 0 0|0 0 0|0 1 1|1 1 1 1|1 1 1 1|2 2 2 2 2 2 2 2 2 2 3 3| */
/* |0 1 2 3 4 5|6 7 8|8 0 1|2 3 4 5|6 7 8 9|0 1 2 3 4 5 6 7 8 9 0 1| */
/* | Op Code | N/U | N/U | Aug |SVC num| SVC Call Number | */
/* |1 1 0 0 1 0|0 0 0|0 0 0|0 1 1 0|x x x x|x x x x x x x x x x x x| */
/* |-------+-------+-------+-------+-------+-------+-------+-------| */
/* */
case 0x6: /* SVC none - none */ /* Supervisor Call Trap */
addr = SPAD[0xf0]; /* get trap table memory address from SPAD (def 80) */
if (addr == 0 || addr == 0xffffffff) { /* see if secondary vector table set up */
TRAPME = ADDRSPEC_TRAP; /* Not setup, error */
goto newpsd; /* program error */
}
addr = addr + (0x06 << 2); /* addr has mem addr of SVC trap vector (def 98) */
temp = M[addr >> 2]; /* get the secondary trap table address from memory */
if (temp == 0 || temp == 0xffffffff) { /* see if ICB set up */
TRAPME = ADDRSPEC_TRAP; /* Not setup, error */
goto newpsd; /* program error */
}
temp2 = ((IR>>12) & 0x0f) << 2; /* get SVC index from IR */
t = M[(temp+temp2)>>2]; /* get secondary trap vector address ICB address */
if (t == 0 || t == 0xffffffff) { /* see if ICB set up */
TRAPME = ADDRSPEC_TRAP; /* Not setup, error */
goto newpsd; /* program error */
}
bc = PSD2 & 0x3ffc; /* get copy of cpix */
M[t>>2] = (PSD1+4) & 0xfffffffe; /* store PSD 1 + 1W to point to next instruction */
M[(t>>2)+1] = PSD2; /* store PSD 2 */
PSD1 = M[(t>>2)+2]; /* get new PSD 1 */
PSD2 = (M[(t>>2)+3] & ~0x3ffc) | bc; /* get new PSD 2 w/old cpix */
M[(t>>2)+4] = IR&0xFFF; /* store call number */
/* set the mode bits and CCs from the new PSD */
CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */
modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */
CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */
CPUSTATUS |= modes; /* not insert into CPUSTATUS */
/* set new map mode and interrupt blocking state in CPUSTATUS */
if (PSD2 & MAPBIT) {
CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */
modes |= MAPMODE; /* set mapped mode */
} else
CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */
/* set interrupt blocking state */
if ((PSD2 & 0x8000) == 0) { /* is it retain blocking state */
if (PSD2 & 0x4000) /* no, is it set blocking state */
CPUSTATUS |= 0x80; /* yes, set blk state in cpu status bit 24 */
else {
CPUSTATUS &= ~0x80; /* no, reset blk state in cpu status bit 24 */
irq_pend = 1; /* start scanning interrupts again */
}
}
PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */
if (CPUSTATUS & 0x80) /* see if old mode is blocked */
PSD2 |= 0x00004000; /* set to blocked state */
PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */
SPAD[0xf5] = PSD2; /* save the current PSD2 */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
goto newpsd; /* new psd loaded */
break;
case 0x7: /* EXR */
IR = temp; /* get instruction to execute */
/* if bit 30 set, instruction is in right hw, do EXRR */
if (addr & 2)
IR <<= 16; /* move instruction to left HW */
if ((IR & 0xFC7F0000) == 0xC8070000 ||
(IR & 0xFF800000) == 0xA8000000) {
/* Fault, attempt to execute another EXR, EXRR, or EXM */
goto inv; /* invalid instruction */
}
EXM_EXR = 4; /* set PC increment for EXR */
OPSD1 &= 0x87FFFFFE; /* clear the old CC's */
OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */
/* TODO Update other history information for this instruction */
if (hst_lnt) {
hst[hst_p].opsd1 = OPSD1; /* update the CC in opsd1 */
hst[hst_p].npsd1 = PSD1; /* save new psd1 */
hst[hst_p].npsd2 = PSD2; /* save new psd2 */
hst[hst_p].modes = modes; /* save current mode bits */
for (ix=0; ix<8; ix++) {
hst[hst_p].reg[ix] = GPR[ix]; /* save reg */
hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */
}
}
/* DEBUG_INST support code */
OPSD1 &= 0x87FFFFFE; /* clear the old CC's */
OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */
/* output mapped/unmapped */
if (modes & MAPMODE)
sim_debug(DEBUG_INST, &cpu_dev, "M%.8x %.8x %.8x ", OPSD1, PSD2, OIR);
else
sim_debug(DEBUG_INST, &cpu_dev, "U%.8x %.8x %.8x ", OPSD1, PSD2, OIR);
if (cpu_dev.dctrl & DEBUG_INST)
fprint_inst(sim_deb, OIR, 0); /* display instruction */
sim_debug(DEBUG_INST, &cpu_dev,
"\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]);
sim_debug(DEBUG_INST, &cpu_dev,
" R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"EXR skipinstr %x irq_pend %x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
skipinstr, irq_pend, PSD1, PSD2, CPUSTATUS);
#endif
/*DIAG*/ skipinstr = 0; /* only test this once */
goto exec; /* go execute the instruction */
break;
/* these instruction were never used by MPX, only diags */
/* diags treat them as invalid halfword instructions */
/* so set the HLF flag to get proper PC increment */
case 0x8: /* SEM */
case 0x9: /* LEM */
case 0xA: /* CEMA */
case 0xB: /* INV */
case 0xC: /* INV */
case 0xD: /* INV */
case 0xE: /* INV */
case 0xF: /* INV */
default:
// i_flags |= HLF; /* handle as if hw */
goto inv; /* invalid instruction */
break;
}
break;
case 0xCC>>2: /* 0xCC ADR - ADR */ /* LF */
/* For machines with Base mode 0xCC08 stores base registers */
if ((FC & 3) != 0) { /* must be word address */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
temp = addr & 0xffe000; /* get 11 bit map # */
bc = addr & 0x20; /* bit 26 initial value */
while (reg < 8) {
if (bc != (addr & 0x20)) { /* test for crossing file boundry */
if (CPU_MODEL < MODEL_27) {
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
}
if (temp != (addr & 0xffe000)) { /* test for crossing map boundry */
if (CPU_MODEL >= MODEL_V6) {
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
}
if (FC & 0x4) /* LFBR? 0xCC08 */
TRAPME = Mem_read(addr, &BR[reg]); /* read the base reg */
else /* LF? 0xCC00 */
TRAPME = Mem_read(addr, &GPR[reg]); /* read the GPR reg */
if (TRAPME) /* TRAPME has error */
goto newpsd; /* go execute the trap now */
reg++; /* next reg to write */
addr += 4; /* next addr */
}
break;
case 0xD0>>2: /* 0xD0 SD|ADR - INV */ /* LEA none basemode only */
if (modes & BASEBIT)
goto inv; /* invalid instruction in basemode */
/* bc has last bits 0,1 for indirect addr of both 1 for no indirection */
addr &= 0x3fffffff; /* clear bits 0-1 */
addr |= bc; /* insert bits 0,1 values into address */
if (FC & 0x4)
addr |= F_BIT; /* copy F bit from instruction */
dest = (t_uint64)(addr);
break;
case 0xD4>>2: /* 0xD4 RR|SM|ADR - RR|SM|ADR */ /* STx */
break;
case 0xD8>>2: /* 0xD8 RR|SM|ADR - RR|SM|ADR */ /* STMx */
/* STMD needs both regs to be masked with R4 */
if (dbl) {
/* we need to and both regs */
t_uint64 nm = (((t_uint64)GPR[4]) << 32) | (((t_uint64)GPR[4]) & D32RMASK);
dest &= nm; /* mask both regs with reg 4 contents */
} else {
dest &= (((t_uint64)GPR[4]) & D32RMASK); /* mask with reg 4 contents */
}
break;
case 0xDC>>2: /* 0xDC INV - ADR */ /* INV nonbasemode (STFx basemode) */
/* DC00 STF */ /* DC08 STFBR */
if ((FC & 0x4) && (CPU_MODEL <= MODEL_27)) {
/* basemode undefined for 32/7x & 32/27 */
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* handle trap */
}
/* For machines with Base mode 0xDC08 stores base registers */
if ((FC & 3) != 0) { /* must be word address */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
bc = addr & 0x20; /* bit 26 initial value */
temp = addr & 0xffe000; /* get 11 bit map # */
while (reg < 8) {
if (bc != (addr & 0x20)) { /* test for crossing file boundry */
if (CPU_MODEL < MODEL_27) {
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
}
if (temp != (addr & 0xffe000)) { /* test for crossing map boundry */
if (CPU_MODEL >= MODEL_V6) {
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
}
if (FC & 0x4) /* STFBR? */
TRAPME = Mem_write(addr, &BR[reg]); /* store the base reg */
else /* STF */
TRAPME = Mem_write(addr, &GPR[reg]); /* store the GPR reg */
if (TRAPME) /* TRAPME has error */
goto newpsd; /* go execute the trap now */
reg++; /* next reg to write */
addr += 4; /* next addr */
}
break;
case 0xE0>>2: /* 0xE0 ADR - ADR */ /* ADFx, SUFx */
if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
goto newpsd; /* memory read error or map fault */
}
source = (t_uint64)temp; /* make into 64 bit value */
if (FC & 2) { /* see if double word addr */
if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */
goto newpsd; /* memory read error or map fault */
}
source = (source << 32) | (t_uint64)temp; /* merge in the low order 32 bits */
dbl = 1; /* double word instruction */
} else {
source |= (source & MSIGN) ? D32LMASK : 0;
dbl = 0; /* not double wd */
}
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
CC = 0; /* clear the CC'ss */
/* handle float or double add/sub instructions */
if (dbl == 0) {
/* do ADFW or SUFW instructions */
temp2 = GPR[reg]; /* dest - reg contents specified by Rd */
addr = (uint32)(source & D32RMASK); /* get 32 bits from source memory */
if (opr & 8) { /* Was it ADFW? */
temp = s_adfw(temp2, addr, &CC); /* do ADFW */
} else {
/* s_sufw will negate the value before calling add */
temp = s_sufw(temp2, addr, &CC); /* do SUFW */
}
sim_debug(DEBUG_CMD, &cpu_dev,
"%s GPR[%d] %08x addr %08x result %08x\n",
(opr&8) ? "ADFW":"SUFW", reg, GPR[reg], addr, temp);
ovr = 0;
if (CC & CC1BIT)
ovr = 1;
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
/* check if we had an arithmetic exception on the last instruction*/
if (ovr && (modes & AEXPBIT)) {
/* leave regs unchanged */
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
/* AEXP not enabled, so apply fix here */
/* return temp to destination reg */
GPR[reg] = temp; /* dest - reg contents specified by Rd */
} else {
/* handle ADFD or SUFD */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
/* do ADFD or SUFD instructions */
td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */
td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */
/* source has 64 bit memory data */
if (opr & 8) { /* Was it ADFD? */
dest = s_adfd(td, source, &CC); /* do ADFD */
} else {
/* s_sufd will negate the memory value before calling add */
dest = s_sufd(td, source, &CC); /* do SUFD */
}
sim_debug(DEBUG_CMD, &cpu_dev,
"%s GPR[%d] %08x %08x src %016llx result %016llx\n",
(opr&8) ? "ADFD":"SUFD", reg, GPR[reg], GPR[reg+1], source, dest);
ovr = 0;
if (CC & CC1BIT) /* test for overflow detection */
ovr = 1;
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
/* check if we had an arithmetic exception on the last instruction */
if (ovr && (modes & AEXPBIT)) {
/* leave regs unchanged */
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
/* dest will be returned to destination regs */
/* if AEXP not enabled, apply fix here */
/* return dest to destination reg */
GPR[reg] = (uint32)((dest & D32LMASK) >> 32); /* get upper reg value */
GPR[reg+1] = (uint32)(dest & D32RMASK); /* get lower reg value */
}
break;
case 0xE4>>2: /* 0xE4 ADR - ADR */ /* MPFx, DVFx */
if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
goto newpsd; /* memory read error or map fault */
}
source = (t_uint64)temp; /* make into 64 bit value */
if (FC & 2) { /* see if double word addr */
if ((TRAPME = Mem_read(addr+4, &temp))) { /* get the 2nd word from memory */
goto newpsd; /* memory read error or map fault */
}
source = (source << 32) | (t_uint64)temp; /* merge in the low order 32 bits */
dbl = 1; /* double word instruction */
} else {
source |= (source & MSIGN) ? D32LMASK : 0;
dbl = 0; /* not double wd */
}
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
CC = 0; /* clear the CC'ss */
/* handle float or double mul/div instructions */
if (dbl == 0) {
/* do MPFW or DIVW instructions */
temp2 = GPR[reg]; /* dest - reg contents specified by Rd */
addr = (uint32)(source & D32RMASK); /* get 32 bits from source memory */
if (opr & 8) { /* Was it MPFW? */
temp = s_mpfw(temp2, addr, &CC); /* do MPFW */
} else {
temp = (uint32)s_dvfw(temp2, addr, &CC); /* do DVFW */
}
sim_debug(DEBUG_CMD, &cpu_dev,
"%s GPR[%d] %08x addr %08x result %08x\n",
(opr&8) ? "MPFW":"DVFW", reg, GPR[reg], addr, temp);
if (CC & CC1BIT)
ovr = 1;
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
/* check if we had an arithmetic exception on the last instruction*/
if (ovr && (modes & AEXPBIT)) {
/* leave regs unchanged */
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
/* if AEXP not enabled, apply fix here */
/* return temp to destination reg */
GPR[reg] = temp; /* dest - reg contents specified by Rd */
} else {
/* handle MPFD or DVFD */
if (reg & 1) { /* see if odd reg specified */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
/* do MPFD or DVFD instructions */
td = (((t_uint64)GPR[reg]) << 32); /* get upper reg value */
td |= (t_uint64)GPR[reg+1]; /* insert low order reg value */
/* source has 64 bit memory data */
if (opr & 8) { /* Was it MPFD? */
dest = s_mpfd(td, source, &CC); /* do MPFD */
} else {
dest = s_dvfd(td, source, &CC); /* do DVFD */
}
sim_debug(DEBUG_CMD, &cpu_dev,
"%s GPR[%d] %08x %08x src %016llx result %016llx\n",
(opr&8) ? "MPFD":"DVFD", reg, GPR[reg], GPR[reg+1], source, dest);
if (CC & CC1BIT) /* test for overflow detection */
ovr = 1;
PSD1 |= (CC & 0x78000000); /* update the CC's in the PSD */
/* check if we had an arithmetic exception on the last instruction*/
if (ovr && (modes & AEXPBIT)) {
/* leave regs unchanged */
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
/* dest will be returned to destination regs */
/* if AEXP not enabled, apply fix here */
/* return dest to destination reg */
GPR[reg] = (uint32)((dest & D32LMASK) >> 32); /* get upper reg value */
GPR[reg+1] = (uint32)(dest & D32RMASK); /* get lower reg value */
}
break;
case 0xE8>>2: /* 0xE8 SM|RR|RNX|ADR - SM|RM|ADR */ /* ARMx */
ovr = 0;
CC = 0;
switch(FC) { /* adjust for hw or bytes */
case 4: case 5: case 6: case 7: /* byte address */
/* ARMB */
td = dest + source; /* DO ARMB */
td &= 0xff; /* mask out right most byte */
dest &= 0xffffff00; /* make place for byte */
dest |= td; /* insert result into dest */
if (td == 0)
CC |= CC4BIT; /* byte is zero, so CC4 */
break;
case 1: /* left halfword addr */
case 3: /* right halfword addr */
/* ARMH */
td = dest + source; /* DO ARMH */
td &= RMASK; /* mask out right most 16 bits */
dest &= LMASK; /* make place for halfword */
dest |= td; /* insert result into dest */
if (td == 0)
CC |= CC4BIT; /* hw is zero, so CC4 */
break;
case 0: /* 32 bit word */
/* ARMW */
/* dest and source are really 32 bit values */
t = (source & MSIGN) != 0;
t |= ((dest & MSIGN) != 0) ? 2 : 0;
td = dest + source; /* DO ARMW */
td &= D32RMASK; /* mask out right most 32 bits */
dest = 0; /* make place for 64 bits */
dest |= td; /* insert result into dest */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if (((t == 3) && ((dest & MSIGN) == 0)) ||
((t == 0) && ((dest & MSIGN) != 0)))
ovr = 1;
if (dest & MSIGN)
dest = (D32LMASK | dest); /* sign extend */
else
dest = (D32RMASK & dest); /* zero fill */
if (td == 0)
CC |= CC4BIT; /* word is zero, so CC4 */
else
if (td & 0x80000000)
CC |= CC3BIT; /* it is neg wd, so CC3 */
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
case 2: /* 64 bit double */
/* ARMD */
t = (source & DMSIGN) != 0;
t |= ((dest & DMSIGN) != 0) ? 2 : 0;
td = dest + source; /* DO ARMD */
dest = td; /* insert result into dest */
/* if both signs are neg and result sign is positive, overflow */
/* if both signs are pos and result sign is negative, overflow */
if (((t == 3) && ((dest & DMSIGN) == 0)) ||
((t == 0) && ((dest & DMSIGN) != 0)))
ovr = 1;
if (td == 0)
CC |= CC4BIT; /* dw is zero, so CC4 */
else
if (td & DMSIGN)
CC |= CC3BIT; /* it is neg dw, so CC3 */
else
CC |= CC2BIT; /* then td > 0, so CC2 */
break;
}
if (ovr)
CC |= CC1BIT; /* set overflow CC */
PSD1 &= 0x87FFFFFE; /* clear the old CC's from PSD1 */
PSD1 |= CC; /* update the CC's in the PSD */
/* the arithmetic exception will be handled */
/* after instruction is completed */
/* check for arithmetic exception trap enabled */
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* set the trap type */
}
break;
case 0xEC>>2: /* 0xEC ADR - ADR */ /* Branch unconditional or Branch True */
/* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/
/* so just test for F bit and go on */
/* if ((FC & 5) != 0) { */
if ((FC & 4) != 0) {
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
temp2 = CC; /* save the old CC's */
CC = PSD1 & 0x78000000; /* get CC's if any */
switch(reg) {
case 0: t = 1; break;
case 1: t = (CC & CC1BIT) != 0; break;
case 2: t = (CC & CC2BIT) != 0; break;
case 3: t = (CC & CC3BIT) != 0; break;
case 4: t = (CC & CC4BIT) != 0; break;
case 5: t = (CC & (CC2BIT|CC4BIT)) != 0; break;
case 6: t = (CC & (CC3BIT|CC4BIT)) != 0; break;
case 7: t = (CC & (CC1BIT|CC2BIT|CC3BIT|CC4BIT)) != 0; break;
}
if (t) { /* see if we are going to branch */
/* we are taking the branch, set CC's if indirect, else leave'm */
/* update the PSD with new address */
PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */
i_flags |= BT; /* we branched, so no PC update */
if (((modes & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect are wanted */
PSD1 = (PSD1 & 0x87fffffe) | temp2; /* insert last indirect CCs */
}
/* branch not taken, go do next instruction */
break;
case 0xF0>>2: /* 0xF0 ADR - ADR */ /* Branch False or Branch Function True BFT */
/* GOOF alert, the assembler sets bit 31 to 1 so this test will fail*/
/* so just test for F bit and go on */
/* if ((FC & 5) != 0) { */
if ((FC & 4) != 0) {
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
temp2 = CC; /* save the old CC's */
CC = PSD1 & 0x78000000; /* get CC's if any */
switch(reg) {
case 0: t = (GPR[4] & (0x8000 >> ((CC >> 27) & 0xf))) != 0; break;
case 1: t = (CC & CC1BIT) == 0; break;
case 2: t = (CC & CC2BIT) == 0; break;
case 3: t = (CC & CC3BIT) == 0; break;
case 4: t = (CC & CC4BIT) == 0; break;
case 5: t = (CC & (CC2BIT|CC4BIT)) == 0; break;
case 6: t = (CC & (CC3BIT|CC4BIT)) == 0; break;
case 7: t = (CC & (CC1BIT|CC2BIT|CC3BIT|CC4BIT)) == 0; break;
}
if (t) { /* see if we are going to branch */
/* we are taking the branch, set CC's if indirect, else leave'm */
/* update the PSD with new address */
PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */
i_flags |= BT; /* we branched, so no PC update */
if (((modes & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect are wanted */
PSD1 = (PSD1 & 0x87fffffe) | temp2; /* insert last indirect CCs */
}
break;
case 0xF4>>2: /* 0xF4 RR|SD|ADR - RR|SB|WRD */ /* Branch increment */
dest += ((t_uint64)1) << ((IR >> 21) & 3);/* use bits 9 & 10 to incr reg */
if (dest != 0) { /* if reg is not 0, take the branch */
/* we are taking the branch, set CC's if indirect, else leave'm */
/* update the PSD with new address */
#if 0 /* set to 1 to stop branch to self, for now */
/* FIXME */ if (PC == (addr & 0xFFFFFC)) { /* BIB to current PC, bump branch addr */
addr += 4;
// fprintf(stderr, "BI? stopping BIB $ addr %x PC %x\r\n", addr, PC);
dest = 0; /* force reg to zero */
}
#endif
PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */
if (((modes & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect are wanted */
PSD1 = (PSD1 & 0x87fffffe) | CC; /* insert last CCs */
i_flags |= BT; /* we branched, so no PC update */
}
break;
case 0xF8>>2: /* 0xF8 SM|ADR - SM|ADR */ /* ZMx, BL, BRI, LPSD, LPSDCM, TPR, TRP */
switch((opr >> 7) & 0x7) { /* use bits 6-8 to determine instruction */
case 0x0: /* ZMx F80x */ /* SM */
dest = 0; /* destination value is zero */
i_flags |= SM; /* SM not set so set it to store value */
break;
case 0x1: /* BL F880 */
/* copy CC's from instruction and PC incremented by 4 */
GPR[0] = ((PSD1 & 0xff000000) | ((PSD1 + 4) & 0xfffffe));
if (((modes & BASEBIT) == 0) && (IR & IND)) /* see if CCs from last indirect are wanted */
PSD1 = (PSD1 & 0x87fffffe) | CC; /* insert last CCs */
/* update the PSD with new address */
if (modes & BASEBIT)
PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* bit 8-30 */
else
PSD1 = (PSD1 & 0xff000000) | (addr & 0x07fffe); /* bit 13-30 */
i_flags |= BT; /* we branched, so no PC update */
break;
case 0x3: /* LPSD F980 */
/* fall through */;
case 0x5: /* LPSDCM FA80 */
if ((modes & PRIVBIT) == 0) { /* must be privileged */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* Privlege violation trap */
}
CPUSTATUS |= 0x40; /* enable software traps */
/* this will allow attn and */
/* power fail traps */
if ((FC & 04) != 0 || FC == 2) { /* can not be byte or doubleword */
/* Fault */
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
goto newpsd; /* go execute the trap now */
}
if ((TRAPME = Mem_read(addr, &temp))) { /* get PSD1 from memory */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
TRAPSTATUS |= BIT7; /* set bit 7 of trap status */
} else
TRAPSTATUS |= BIT18; /* set bit 18 of trap status */
goto newpsd; /* memory read error or map fault */
}
bc = CPUSTATUS; /* save the CPU STATUS */
TPSD[0] = PSD1; /* save the PSD for the instruction */
TPSD[1] = PSD2;
t = modes; /* save modes too */
ix = SPAD[0xf5]; /* save the current PSD2 */
reg = irq_pend; /* save intr status */
if (opr & 0x0200) { /* Was it LPSDCM? */
if ((TRAPME = Mem_read(addr+4, &temp2))) { /* get PSD2 from memory */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
TRAPSTATUS |= BIT7; /* set bit 7 of trap status */
} else
TRAPSTATUS |= BIT18; /* set bit 18 of trap status */
goto newpsd; /* memory read error or map fault */
}
PSD2 = temp2; /* PSD2 access good, so save it */
} else {
if ((TRAPME = Mem_read(addr+4, &temp2))) { /* get PSD2 from memory */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
TRAPSTATUS |= BIT7; /* set bit 7 of trap status */
} else
TRAPSTATUS |= BIT18; /* set bit 18 of trap status */
goto newpsd; /* memory read error or map fault */
}
/* lpsd can not change cpix, so keep it */
PSD2 = ((PSD2 & 0x3fff) | (temp2 & 0xffffc000)); /* use current cpix */
}
PSD1 = temp; /* PSD1 good, so set it */
/* set the mode bits and CCs from the new PSD */
CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */
modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */
CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */
CPUSTATUS |= modes; /* not insert into CPUSTATUS */
/* set new arithmetic trap state in CPUSTATUS */
if (PSD1 & AEXPBIT) {
CPUSTATUS |= AEXPBIT; /* set bit 7 of cpu status */
modes |= AEXPBIT; /* set arithmetic exception mode */
} else
CPUSTATUS &= ~AEXPBIT; /* reset bit 7 of cpu status */
/* set new extended state in CPUSTATUS */
if (PSD1 & EXTDBIT) {
CPUSTATUS |= EXTDBIT; /* set bit 5 of cpu status */
modes |= EXTDBIT; /* set extended mode */
} else
CPUSTATUS &= ~EXTDBIT; /* reset bit 5 of cpu status */
/* set new map mode and interrupt blocking state in CPUSTATUS */
if (PSD2 & MAPBIT) {
CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */
modes |= MAPMODE; /* set mapped mode */
} else
CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */
/* set interrupt blocking state */
if ((PSD2 & 0x8000) == 0) { /* is it retain blocking state */
if (PSD2 & 0x4000) /* no, is it set blocking state */
CPUSTATUS |= 0x80; /* yes, set blk state in cpu status bit 24 */
else {
CPUSTATUS &= ~0x80; /* no, reset blk state in cpu status bit 24 */
irq_pend = 1; /* start scanning interrupts again */
}
}
PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */
if (CPUSTATUS & 0x80) /* see if old mode is blocked */
PSD2 |= 0x00004000; /* set to blocked state */
if (opr & 0x0200) { /* Was it LPSDCM? */
/* map bit must be on to load maps */
if (PSD2 & MAPBIT) {
/* set mapped mode in cpu status */
CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"B4 LPSDCM temp %06x TPSD %08x %08x PSD %08x %08x\n",
temp, TPSD[0], TPSD[1], PSD1, PSD2);
sim_debug(DEBUG_DETAIL, &cpu_dev,
"B4 LPSDCM BPIX %04x CPIX %04x CPIXPL %04x\n",
BPIX, CPIX, CPIXPL);
sim_debug(DEBUG_DETAIL, &cpu_dev,
"B4 LPSDCM OS MAPC[0-5] %08x %08x %08x %08x %08x %08x\n",
MAPC[0], MAPC[1], MAPC[2], MAPC[3], MAPC[4], MAPC[5]);
sim_debug(DEBUG_DETAIL, &cpu_dev,
"B4 LPSDCM US MAPC[%x-%x] %08x %08x %08x %08x %08x %08x\n",
BPIX, BPIX+5, MAPC[BPIX], MAPC[BPIX+1], MAPC[BPIX+2],
MAPC[BPIX+3], MAPC[BPIX+4], MAPC[BPIX+5]);
#define FIX_MPX
#ifdef FIX_MPX
/* this mod fixes MPX 1.X 1st swapr load */
/* any O/S or user maps yet? */
/* any user maps yet? */
if (((CPIX != 0) && (CPIXPL == 0)) && (PSD2 & RETMBIT)) {
PSD2 &= ~RETMBIT; /* no, turn off retain bit in PSD2 */
sim_debug(DEBUG_EXP, &cpu_dev, "Turn off retain bit\n");
}
#endif
if ((PSD2 & RETMBIT) == 0) { /* don't load maps if retain bit set */
/* we need to load the new maps */
TRAPME = load_maps(PSD, 0); /* load maps for new PSD */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"AF LPSDCM TPSD %08x %08x PSD %08x %08x TRAPME %02x\n",
TPSD[0], TPSD[1], PSD1, PSD2, TRAPME);
sim_debug(DEBUG_DETAIL, &cpu_dev,
"AF LPSDCM BPIX %04x CPIX %04x CPIXPL %04x\n",
BPIX, CPIX, CPIXPL);
sim_debug(DEBUG_DETAIL, &cpu_dev,
"AF LPSDCM OS MAPC[0-5] %08x %08x %08x %08x %08x %08x\n",
MAPC[0], MAPC[1], MAPC[2], MAPC[3], MAPC[4], MAPC[5]);
sim_debug(DEBUG_DETAIL, &cpu_dev,
"AF LPSDCM US MAPC[%x-%x] %08x %08x %08x %08x %08x %08x\n",
BPIX, BPIX+5, MAPC[BPIX], MAPC[BPIX+1], MAPC[BPIX+2],
MAPC[BPIX+3], MAPC[BPIX+4], MAPC[BPIX+5]);
}
PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */
SPAD[0xf5] = PSD2; /* save the current PSD2 */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
sim_debug(DEBUG_DETAIL, &cpu_dev,
"LPSDCM MAPS LOADED TRAPME = %02x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
TRAPME, PSD1, PSD2, CPUSTATUS);
}
PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */
} else {
/* LPSD */
/* if cpix is zero, copy cpix from PSD2 in SPAD[0xf5] */
if ((PSD2 & 0x3fff) == 0) {
PSD2 |= (SPAD[0xf5] & 0x3fff); /* use new cpix */
}
}
/* TRAPME can be error from LPSDCM or OK here */
if (TRAPME) { /* if we have an error, restore old PSD */
sim_debug(DEBUG_TRAP, &cpu_dev,
"LPSDCM MAPS2 LOADED TRAPME = %02x PSD1 %08x PSD2 %08x CPUSTATUS %08x SPAD[f9] %08x\n",
TRAPME, PSD1, PSD2, CPUSTATUS, SPAD[0xf9]);
PSD1 = TPSD[0]; /* restore PSD1 */
/* HACK HACK HACK */
/* Diags wants the new PSD2, not the original??? */
/* if old one was used, we fail test 21/0 in cn.mmm for 32/67 */
//DIAG PSD2 = TPSD[1]; /* restore PSD2 */
CPUSTATUS = bc; /* restore the CPU STATUS */
modes = t; /* restore modes too */
SPAD[0xf5] = ix; /* restore the current PSD2 to SPAD */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
irq_pend = reg; /* restore intr status */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9)) {
TRAPSTATUS |= BIT10; /* set bit 10 of trap status */
TRAPSTATUS |= BIT7; /* set bit 7 of trap status */
} else
TRAPSTATUS |= BIT18; /* set bit 18 of trap status */
goto newpsd; /* go process error */
}
skipinstr = 1; /* do not allow intr on next instruction */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"Skipinstr set to one PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
PSD1, PSD2, CPUSTATUS);
#endif
drop_nop = 0; /* nothing to drop */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"LPSD(CM) Done PSD1 %08x PSD2 %08x CPUSTATUS %08x irq %01x\n",
PSD1, PSD2, CPUSTATUS, irq_pend);
#endif
goto newpsd; /* load the new psd, or process error */
break;
case 0x4: /* JWCS */ /* not used in simulator */
sim_debug(DEBUG_DETAIL, &cpu_dev, "Got JWCS\n");
break;
case 0x2: /* BRI */ /* TODO - only for 32/55 or 32/7X in PSW mode */
case 0x6: /* TRP */
case 0x7: /* TPR */
TRAPME = UNDEFINSTR_TRAP; /* trap condition */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* undefined instruction trap */
break;
}
break;
/* F Class I/O device instruction format */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02 03 04 05|06 07 08|09 10 11 12|13 14 15|16|17 18 19 20 21 22 23|24 25 26 27 28 29 30 31| */
/* | Op Code | Reg | I/O type | Aug |0 | Channel Address | Device Sub-address | */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
/* E Class I/O device instruction format */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* |00 01 02 03 04 05|06 07 08 09 10 11 12|13 14 15|16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31| */
/* | Op Code | Device Number | Aug | Command Code | */
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
/* */
case 0xFC>>2: /* 0xFC IMM - IMM */ /* XIO, CD, TD, Interrupt Control */
if ((modes & PRIVBIT) == 0) { /* must be privileged to do I/O */
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
else
TRAPSTATUS |= BIT19; /* set bit 19 of trap status */
goto newpsd; /* Privlege violation trap */
}
if ((opr & 0x7) != 0x07) { /* aug is 111 for XIO instruction */
/* Process Non-XIO instructions */
uint32 status = 0; /* status returned from device */
uint32 device = (opr >> 3) & 0x7f; /* get device code */
uint32 prior = device; /* interrupt priority */
uint32 maxlev = 0x5f; /* max lev for all but 32/27 in diags */
//?? uint32 maxlev = 0x6f; /* max lev for all but 32/27 in diags */
t = SPAD[prior+0x80]; /* get spad entry for interrupt */
addr = SPAD[0xf1] + (prior<<2); /* vector address in SPAD */
addr = M[addr>>2]; /* get the interrupt context block addr */
prior = (opr >> 3) & 0x7f; /* get priority level */
if (CPU_MODEL <= MODEL_27) {
maxlev = 0x6f; /* 27 uses 112 */
}
// if (CPU_MODEL == MODEL_V9) {
// maxlev = 0x5f; /* 27 uses 112 */
// }
switch(opr & 0x7) { /* use bits 13-15 to determine instruction */
case 0x0: /* EI FC00 Enable Interrupt */
if (prior > maxlev) /* ignore for invalid levels */
break; /* ignore */
/* SPAD entries for interrupts begin at 0x80 */
t = SPAD[prior+0x80]; /* get spad entry for interrupt */
if (t == 0 || t == 0xffffffff) /* if not set up, not class F */
goto syscheck; /* system check */
// break; /* ignore */
if ((t & 0x0f000000) == 0x0f000000) /* if class F ignore instruction */
break; /* ignore for F class */
/* does not effect REQ status */
INTS[prior] |= INTS_ENAB; /* enable specified int level */
SPAD[prior+0x80] |= SINT_ENAB; /* enable in SPAD too */
irq_pend = 1; /* start scanning interrupts again */
/* test for clock at address 0x7f06 and interrupt level 0x18 */
/* the diags want the type to be 0, others want 3, so ignore */
//WAS bad for diag if ((SPAD[prior+0x80] & 0x0f00ffff) == 0x03007f06) {
if ((SPAD[prior+0x80] & 0x0000ffff) == 0x00007f06) {
sim_debug(DEBUG_IRQ, &cpu_dev, "Clock EI %02x Turn on\n", prior);
rtc_setup(1, prior); /* tell clock to start */
}
if ((SPAD[prior+0x80] & 0x0f00ffff) == 0x03007f04) {
sim_debug(DEBUG_IRQ, &cpu_dev, "Intv Timer EI %02x Turn on\n", prior);
itm_setup(1, prior); /* tell timer to start */
}
#ifndef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"EI lev %02x Skipinstr set to one PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
prior, PSD1, PSD2, CPUSTATUS);
#endif
break;
case 0x1: /* DI FC01 */
if (prior > maxlev) /* ignore for invalid levels */
break; /* ignore */
/* SPAD entries for interrupts begin at 0x80 */
t = SPAD[prior+0x80]; /* get spad entry for interrupt */
if (t == 0 || t == 0xffffffff) /* if not set up, not class F */
//RESTART goto syscheck; /* system check */
break; /* ignore */
if ((t & 0x0f000000) == 0x0f000000) /* if class F ignore instruction */
break; /* ignore for F class */
/* active state is left alone */
INTS[prior] &= ~INTS_ENAB; /* disable specified int level */
SPAD[prior+0x80] &= ~SINT_ENAB; /* disable in SPAD too */
INTS[prior] &= ~INTS_REQ; /* clears any requests also */
/* test for clock at address 0x7f06 and interrupt level 0x18 */
/* the diags want the type to be 0, others want 3, so ignore */
//WAS bad for diag if ((SPAD[prior+0x80] & 0x0f00ffff) == 0x03007f06) {
if ((SPAD[prior+0x80] & 0x0000ffff) == 0x00007f06) {
sim_debug(DEBUG_IRQ, &cpu_dev, "Clock DI %02x Turn off\n", prior);
rtc_setup(0, prior); /* tell clock to stop */
}
if ((SPAD[prior+0x80] & 0x0f00ffff) == 0x03007f04) {
itm_setup(0, prior); /* tell timer to stop */
sim_debug(DEBUG_IRQ, &cpu_dev, "Intv Timer DI %02x Turn off\n", prior);
}
#ifndef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"DI lev %02x Skipinstr set to %01x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
prior, skipinstr, PSD1, PSD2, CPUSTATUS);
#endif
break;
case 0x2: /* RI FC02 */
if (prior > maxlev) /* ignore for invalid levels */
break; /* ignore */
/* SPAD entries for interrupts begin at 0x80 */
t = SPAD[prior+0x80]; /* get spad entry for interrupt */
if (t == 0 || t == 0xffffffff) /* if not set up, not class F */
goto syscheck; /* system check */
// break; /* ignore */
if ((t & 0x0f000000) == 0x0f000000) /* if class F ignore instruction */
break; /* ignore for F class */
INTS[prior] |= INTS_REQ; /* set the request flag for this level */
irq_pend = 1; /* start scanning interrupts again */
#ifndef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"RI lev %02x Skipinstr set to one PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
prior, PSD1, PSD2, CPUSTATUS);
#endif
break;
case 0x3: /* AI FC03 */
if (prior > maxlev) /* ignore for invalid levels */
break; /* ignore */
/* SPAD entries for interrupts begin at 0x80 */
t = SPAD[prior+0x80]; /* get spad entry for interrupt */
if (t == 0 || t == 0xffffffff) /* if not set up, not class F */
goto syscheck; /* system check */
if ((t & 0x0f000000) == 0x0f000000) /* if class F ignore instruction */
break; /* ignore for F class */
INTS[prior] |= INTS_ACT; /* activate specified int level */
SPAD[prior+0x80] |= SINT_ACT; /* activate in SPAD too */
irq_pend = 1; /* start scanning interrupts again */
#ifndef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"AI lev %02x Skipinstr set to one PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
prior, PSD1, PSD2, CPUSTATUS);
#endif
break;
case 0x4: /* DAI FC04 */
if (prior > maxlev) /* ignore for invalid levels */
break; /* ignore */
/* SPAD entries for interrupts begin at 0x80 */
t = SPAD[prior+0x80]; /* get spad entry for interrupt */
if (t == 0 || t == 0xffffffff) /* if not set up, not class F */
goto syscheck; /* system check */
// break; /* ignore */
if ((t & 0x0f000000) == 0x0f000000) /* if class F ignore instruction */
break; /* ignore for F class */
INTS[prior] &= ~INTS_ACT; /* deactivate specified int level */
SPAD[prior+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */
irq_pend = 1; /* start scanning interrupts again */
/* instruction following a DAI can not be interrupted */
/* skip tests for interrupts if this is the case */
skipinstr = 1; /* skip interrupt test */
#ifndef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"DAI lev %02x Skipinstr set to one PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
prior, PSD1, PSD2, CPUSTATUS);
#endif
drop_nop = 0; /* nothing to drop */
break;
case 0x5: /* TD FC05 */ /* bits 13-15 is test code type */
case 0x6: /* CD FC06 */
/* If CD or TD, make sure device is not F class device */
/* the channel must be defined as a non class F I/O channel in SPAD */
/* if class F, the system will generate a system check trap */
t = SPAD[device]; /* get spad entry for channel */
if (t == 0 || t == 0xffffffff) /* if not set up, die */
goto syscheck; /* system check */
if ((t & 0x0f000000) == 0x0f000000) { /* class in bits 4-7 */
syscheck:
TRAPME = SYSTEMCHK_TRAP; /* trap condition if F class */
TRAPSTATUS &= ~BIT0; /* class E error bit */
TRAPSTATUS &= ~BIT1; /* I/O processing error */
goto newpsd; /* machine check trap */
}
if (opr & 0x1) { /* see if CD or TD */
/* TODO process a TD */
// if ((TRAPME = testEIO(device, testcode, &status)))
// goto newpsd; /* error returned, trap cpu */
/* return status has new CC's in bits 1-4 of status word */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status CCs */
//fprintf(stderr, "EIO TD chan %.4x spad %.8x\r\n", device, t);
goto inv; /* invalid instruction until I fix it */
} else {
/* TODO process a CD */
// if ((TRAPME = startEIO(device, &status)))
// goto newpsd; /* error returned, trap cpu */
// t = SPAD[device]; /* get spad entry for channel */
/* t has spad entry for device */
/* get the 1's comp of interrupt address from bits 9-15 SPAD entry */
ix = (t & 0x007f0000) >> 16;/* get the 1's comp of int level */
ix = 127 - ix; /* get positive number for interrupt */
temp = (IR & 0x7f); /* get cmd from instruction */
if (device == 0x7f) {
status = itm_rdwr(temp, GPR[0], ix); /* read/write the interval timer */
/* see if the cmd does not return value */
if ((temp != 0x39) && (temp != 0x3d) && (temp != 0x20))
GPR[0] = status; /* return count in reg 0 */
/* No CC's going out */
} else {
goto inv; /* invalid instruction until I fix it */
}
}
break;
case 0x7: /* XIO FC07*/ /* should never get here */
break;
}
break; /* skip over XIO code */
}
/* Process XIO instructions */
/* if reg is non-zero, add reg to 15 bits from instruction */
if (reg)
temp2 = (IR & 0x7fff) + (GPR[reg] & 0x7fff); /* set new chan/suba into IR */
else
temp2 = (IR & 0x7fff); /* set new chan/suba into IR */
lchan = (temp2 & 0x7F00) >> 8; /* get 7 bit logical channel address */
suba = temp2 & 0xFF; /* get 8 bit subaddress */
/* the channel must be defined as a class F I/O channel in SPAD */
/* if not class F, the system will generate a system check trap */
t = SPAD[lchan]; /* get spad entry for channel */
if ((t == 0 || t == 0xffffffff) || /* if not set up, system check */
((t & 0x0f000000) != 0x0f000000)) { /* class in bits 4-7 */
//fprintf(stderr, "SYSCHK XIO lchan %.4x spad %.8x\r\n", lchan, t);
TRAPME = SYSTEMCHK_TRAP; /* trap condition if F class */
TRAPSTATUS |= BIT0; /* class F error bit */
TRAPSTATUS &= ~BIT1; /* I/O processing error */
goto newpsd; /* undefined instruction trap */
}
sim_debug(DEBUG_XIO, &cpu_dev,
"$$ XIO lchan %04x sa %04x spad %08x\n", lchan, suba, t);
/* get real channel from spad device entry */
chan = (t & 0x7f00) >> 8; /* real channel */
/* get the 1's comp of interrupt address from bits 9-15 SPAD entry */
ix = (t & 0x007f0000) >> 16; /* get the 1's comp of int level */
ix = 127 - ix; /* get positive number for interrupt */
bc = SPAD[ix+0x80]; /* get interrupt entry for channel */
/* SPAD address F1 has interrupt table address */
temp = SPAD[0xf1] + (ix<<2); /* vector address in SPAD */
if ((TRAPME = Mem_read(temp, &addr))) { /* get interrupt context block addr */
mcheck:
/* machine check if not there */
TRAPME = MACHINECHK_TRAP; /* trap condition */
TRAPSTATUS |= BIT0; /* class F error bit */
TRAPSTATUS &= ~BIT1; /* I/O processing error */
goto newpsd; /* machine check trap */
}
/* the context block contains the old PSD, */
/* new PSD, IOCL address, and I/O status address */
if ((addr == 0) || (addr == 0xffffffff)) { /* must be initialized address */
goto mcheck; /* bad int icb address */
}
if ((TRAPME = Mem_read(addr+16, &temp))) { /* get iocl address from icb wd 4 */
goto mcheck; /* machine check if not there */
}
/* iocla must be valid addr if it is a SIO instruction */
if (((temp & MASK24) == 0) && (((opr >> 2) & 0xf) == 2)) {
goto mcheck; /* bad iocl address */
}
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO ready chan %04x intr %04x icb %08x iocla %08x iocd1 %08x iocd2 %08x\n",
chan, ix, addr, addr+16, RMW(temp), RMW(temp+4));
// chan, ix, addr, addr+16, M[temp>>2], M[(temp+4)>>2]);
/* at this point, the channel has a valid SPAD channel entry */
/* t is SPAD entry contents for chan device */
/* temp2 has IR + reg contents if reg != 0 */
/* lchan - logical channel address */
/* chan - channel address */
/* suba - channel device subaddress */
/* ix - positive interrupt level */
/* addr - ICB for specified interrupt level, points to 6 wd block */
/* temp - First IOCD address */
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO switch %02x lchan %04x, chan %04x intr %04x chsa %04x IOCDa %08x\n",
((opr>>3)&0x0f), lchan, chan, ix, (chan<<8)|suba, temp);
switch((opr >> 3) & 0xf) { /* use bits 9-12 to determine I/O instruction */
uint32 status; /* status returned by various functions */
uint16 chsa; /* logical device address */
case 0x00: /* Unassigned */
case 0x01: /* Unassigned */
case 0x0A: /* Unassigned */
TRAPME = UNDEFINSTR_TRAP; /* trap condition */
if ((CPU_MODEL == MODEL_97) || (CPU_MODEL == MODEL_V9))
TRAPSTATUS |= BIT0; /* set bit 0 of trap status */
goto newpsd; /* undefined instruction trap */
break;
case 0x09: /* Enable write channel ECWCS */
case 0x0B: /* Write channel WCS WCWCS */
/* TODO, provide support code */
/* for now or maybe forever, return unsupported transaction */
PSD1 = ((PSD1 & 0x87fffffe) | (CC2BIT|CC4BIT)); /* insert status 5 */
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO unsupported WCS chan %04x chsa %04x status %08x\n",
chan, (chan<<8)|suba, status);
/* just give unsupported transaction */
TRAPME = SYSTEMCHK_TRAP; /* trap condition if F class */
TRAPSTATUS |= BIT0; /* class F error bit */
TRAPSTATUS &= ~BIT1; /* I/O processing error */
goto newpsd; /* undefined instruction trap */
break;
case 0x02: /* Start I/O SIO */
chsa = temp2 & 0x7FFF; /* get logical device address */
if ((TRAPME = startxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO SIO ret chan %04x chsa %04x status %08x\n",
chan, (chan<<8)|suba, status);
break;
case 0x03: /* Test I/O TIO */
chsa = temp2 & 0x7FFF; /* get logical device address */
if ((TRAPME = testxio(chsa, &status))) {
sim_debug(DEBUG_TRAP, &cpu_dev,
"XIO TIO ret PSD1 %x chan %x chsa %x status %x\n",
PSD1, chan, (chan<<8)|suba, status);
goto newpsd; /* error returned, trap cpu */
}
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO TIO ret chan %04x sa %04x status %08x spad %08x INTS[%02x] %08x\n",
chan, suba, status, t, ix, INTS[ix]);
#ifdef DO_DYNAMIC_DEBUG
/* start debugging */
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
break;
case 0x04: /* Stop I/O STPIO */
chsa = temp2 & 0x7FFF; /* get logical device address */
if ((TRAPME = stopxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
sim_debug(DEBUG_XIO, &cpu_dev, "XIO STPIO ret chan %04x chsa %04x status %08x\n",
chan, (chan<<8)|suba, status);
break;
/* TODO Finish XIO */
case 0x05: /* Reset channel RSCHNL */
chsa = temp2 & 0x7FFF; /* get logical device address */
/* SPAD entries for interrupts begin at 0x80 */
INTS[ix] &= ~INTS_REQ; /* clears any requests */
INTS[ix] &= ~INTS_ACT; /* deactivate specified int level */
SPAD[ix+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */
/* TODO Maybe we need to disable int too???? */
if ((TRAPME = rschnlxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
//fprintf(stderr, "XIO RSCHNL ret chan %x chsa %x status %x\n", chan, (chan<<8)|suba, status);
sim_debug(DEBUG_XIO, &cpu_dev, "XIO RSCHNL ret chan %04x chsa %04x status %08x\n",
chan, (chan<<8)|suba, status);
break;
case 0x06: /* Halt I/O HIO */
chsa = temp2 & 0x7FFF; /* get logical device address */
if ((TRAPME = haltxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
sim_debug(DEBUG_XIO, &cpu_dev,
"HIO HALTXIO ret chan %04x chsa %04x status %08x\n",
chan, (chan<<8)|suba, status);
sim_debug(DEBUG_IRQ, &cpu_dev,
"HIO skipinstr %x irq_pend %x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
skipinstr, irq_pend, PSD1, PSD2, CPUSTATUS);
break;
case 0x07: /* Grab controller GRIO n/u */
chsa = temp2 & 0x7FFF; /* get logical device address */
if ((TRAPME = grabxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
sim_debug(DEBUG_XIO, &cpu_dev, "XIO GRIO ret chan %04x chsa %04x status %08x\n",
chan, (chan<<8)|suba, status);
break;
case 0x08: /* Reset controller RSCTL */
chsa = temp2 & 0x7FFF; /* get logical device address */
if ((TRAPME = rsctlxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
sim_debug(DEBUG_XIO, &cpu_dev, "XIO RSCTL ret chan %04x chsa %04x status %08x\n",
chan, (chan<<8)|suba, status);
break;
case 0x0C: /* Enable channel interrupt ECI */
/* disable int only */
chsa = temp2 & 0x7FFF; /* get logical device address */
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO ECI chan %04x sa %04x spad %08x INTS[%02x] %08x\n",
chan, suba, t, ix, INTS[ix]);
/* SPAD entries for interrupts begin at 0x80 */
INTS[ix] |= INTS_ENAB; /* enable specified int level */
SPAD[ix+0x80] |= SINT_ENAB; /* enable in SPAD too */
irq_pend = 1; /* start scanning interrupts again */
if ((TRAPME = checkxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
break;
case 0x0D: /* Disable channel interrupt DCI */
/* disable int, leave req */
chsa = temp2 & 0x7FFF; /* get logical device address */
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO DCI chan %04x sa %04x spad %08x INTS[%02x] %08x\n",
chan, suba, t, ix, INTS[ix]);
/* SPAD entries for interrupts begin at 0x80 */
INTS[ix] &= ~INTS_ENAB; /* disable specified int level */
SPAD[ix+0x80] &= ~SINT_ENAB; /* disable in SPAD too */
if ((TRAPME = checkxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
break;
case 0x0E: /* Activate channel interrupt ACI */
/* Set int active, clear request */
chsa = temp2 & 0x7FFF; /* get logical device address */
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO ACI chan %04x sa %04x spad %08x INTS[%02x] %08x\n",
chan, suba, t, ix, INTS[ix]);
/* SPAD entries for interrupts begin at 0x80 */
INTS[ix] |= INTS_ACT; /* activate specified int level */
SPAD[ix+0x80] |= SINT_ACT; /* enable in SPAD too */
INTS[ix] &= ~INTS_REQ; /* clears any requests also */
if ((TRAPME = checkxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
break;
case 0x0F: /* Deactivate channel interrupt DACI */
/* Clear active and leave any request */
/* Note, instruction following DACI is not interruptable */
chsa = temp2 & 0x7FFF; /* get logical device address */
sim_debug(DEBUG_XIO, &cpu_dev,
"XIO DACI chan %04x sa %04x spad %08x INTS[%02x] %08x\n",
chan, suba, t, ix, INTS[ix]);
/* SPAD entries for interrupts begin at 0x80 */
INTS[ix] &= ~INTS_ACT; /* deactivate specified int level */
SPAD[ix+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */
if ((TRAPME = checkxio(chsa, &status)))
goto newpsd; /* error returned, trap cpu */
irq_pend = 1; /* start scanning interrupts again */
skipinstr = 1; /* skip interrupt test */
#ifdef NOTNOW
sim_debug(DEBUG_IRQ, &cpu_dev,
"Skipinstr set to one PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
PSD1, PSD2, CPUSTATUS);
#endif
/*XXX*/ drop_nop = 0; /* nothing to drop */
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
break;
} /* end of XIO switch */
break;
} /* End of Instruction Switch */
/* [*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*] */
/* any instruction with an arithmetic exception will still end up here */
/* after the instruction is done and before incrementing the PC, */
/* we will trap the cpu if ovl is set nonzero by an instruction */
/* Store result to register */
if (i_flags & SD) {
if (dbl) { /* if double reg, store 2nd reg */
if (reg & 1) { /* is it double regs into odd reg */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
GPR[reg+1] = (uint32)(dest & FMASK); /* save the low order reg */
GPR[reg] = (uint32)((dest>>32) & FMASK);/* save the hi order reg */
} else {
GPR[reg] = (uint32)(dest & FMASK); /* save the reg */
}
}
/* Store result to base register */
if (i_flags & SB) {
if (dbl) { /* no dbl wd store to base regs */
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
goto newpsd; /* go execute the trap now */
}
BR[reg] = (uint32)(dest & FMASK); /* save the base reg */
}
/* Store result to memory */
if (i_flags & SM) {
/* Check if byte of half word */
if (((FC & 04) || (FC & 5) == 1)) { /* hw or byte requires read first */
if ((TRAPME = Mem_read(addr, &temp))) { /* get the word from memory */
goto newpsd; /* memory read error or map fault */
}
}
switch(FC) {
case 2: /* double word store */
if ((addr & 7) != 2) {
TRAPME = ADDRSPEC_TRAP; /* address not on dbl wd boundry, error */
//fprintf(stderr, "SM AD02 DBL WD opr %x FC %x addr = %x dest %lx\r\n", opr, FC, addr, dest);
goto newpsd; /* go execute the trap now */
}
temp = (uint32)(dest & MASK32);/* get lo 32 bit */
if ((TRAPME = Mem_write(addr + 4, &temp)))
goto newpsd; /* memory write error or map fault */
temp = (uint32)(dest >> 32); /* move upper 32 bits to lo 32 bits */
break;
case 0: /* word store */
temp = (uint32)(dest & FMASK); /* mask 32 bit of reg */
if ((addr & 3) != 0) {
/* Address fault */
TRAPME = ADDRSPEC_TRAP; /* address not on wd boundry, error */
//fprintf(stderr, "SM AD02 WD opr %x FC %x addr = %x dest %x\r\n", opr, FC, addr, temp);
goto newpsd; /* go execute the trap now */
}
break;
case 1: /* left halfword write */
temp &= RMASK; /* mask out 16 left most bits */
temp |= (uint32)(dest & RMASK) << 16; /* put into left most 16 bits */
if ((addr & 1) != 1) {
/* Address fault */
TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */
//fprintf(stderr, "SM AD02 LHWD opr %x FC %x addr = %x dest %x\r\n", opr, FC, addr, temp);
goto newpsd; /* go execute the trap now */
}
break;
case 3: /* right halfword write */
temp &= LMASK; /* mask out 16 right most bits */
temp |= (uint32)(dest & RMASK); /* put into right most 16 bits */
if ((addr & 3) != 3) {
TRAPME = ADDRSPEC_TRAP; /* address not on hw boundry, error */
//fprintf(stderr, "SM AD02 RHWD opr %x FC %x addr = %x dest %x\r\n", opr, FC, addr, temp);
goto newpsd; /* go execute the trap now */
}
break;
case 4:
case 5:
case 6:
case 7: /* byte store operation */
temp &= ~(0xFF << (8 * (7 - FC))); /* clear the byte to store */
temp |= (uint32)(dest & 0xFF) << (8 * (7 - FC)); /* insert new byte */
break;
}
/* store back the modified memory location */
if ((TRAPME = Mem_write(addr, &temp))) /* store back to memory */
goto newpsd; /* memory write error or map fault */
}
/* Update condition code registers */
if (i_flags & SCC) {
PSD1 &= 0x87FFFFFE; /* clear the old CC's */
if (ovr) /* if overflow, set CC1 */
CC = CC1BIT; /* show we had AEXP */
else
CC = 0; /* no CC's yet */
if (dest & DMSIGN) /* if neg, set CC3 */
CC |= CC3BIT; /* if neg, set CC3 */
else if (dest == 0)
CC |= CC4BIT; /* if zero, set CC4 */
else
CC |= CC2BIT; /* if gtr than zero, set CC2 */
PSD1 |= CC & 0x78000000; /* update the CC's in the PSD */
}
/* check if we had an arithmetic exception on the last instruction*/
if (ovr && (modes & AEXPBIT)) {
TRAPME = AEXPCEPT_TRAP; /* trap the system now */
goto newpsd; /* process the trap */
}
/* Update instruction pointer to next instruction */
if ((i_flags & BT) == 0) { /* see if PSD was replaced on a branch instruction */
/* branch not taken, so update the PC */
if (EXM_EXR != 0) { /* special handling for EXM, EXR, EXRR */
PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
EXM_EXR = 0; /* reset PC increment for EXR */
} else
if (i_flags & HLF) {
PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1);
} else {
PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
}
} else {
EXM_EXR = 0; /* reset PC increment for EXR */
drop_nop = 0; /* no NOP to drop */
}
OPSD1 &= 0x87FFFFFE; /* clear the old CC's */
OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */
/* TODO Update other history information for this instruction */
if (hst_lnt) {
hst[hst_p].opsd1 = OPSD1; /* update the CC in opsd1 */
hst[hst_p].npsd1 = PSD1; /* save new psd1 */
hst[hst_p].npsd2 = PSD2; /* save new psd2 */
hst[hst_p].modes = modes; /* save current mode bits */
for (ix=0; ix<8; ix++) {
hst[hst_p].reg[ix] = GPR[ix]; /* save reg */
hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */
}
}
/* DEBUG_INST support code */
/* output mapped/unmapped */
if (modes & MAPMODE)
sim_debug(DEBUG_INST, &cpu_dev, "M%.8x %.8x %.8x ", OPSD1, PSD2, OIR);
else
sim_debug(DEBUG_INST, &cpu_dev, "U%.8x %.8x %.8x ", OPSD1, PSD2, OIR);
if (cpu_dev.dctrl & DEBUG_INST)
fprint_inst(sim_deb, OIR, 0); /* display instruction */
sim_debug(DEBUG_INST, &cpu_dev, "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]);
sim_debug(DEBUG_INST, &cpu_dev, " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
if (modes & BASEBIT) {
sim_debug(DEBUG_INST, &cpu_dev, "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]);
sim_debug(DEBUG_INST, &cpu_dev, " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]);
}
continue; /* keep running */
newpsd:
/* Trap Context Block - 6 words */
/* WD1 Old PSD Wd 1 */
/* WD2 Old PSD Wd 2 */
/* WD3 New PSD WD 1 */
/* WD4 New PSD Wd 2 */
/* WD5 Multi Use */ /* N/U for Interrupts */
/* WD6 Multi Use */ /* N/U for Interrupts */
/* WD5 Multi Use */ /* IOCL address for I/O */
/* WD6 Multi Use */ /* Status address for I/O */
/* WD5 Multi Use */ /* Secondary vector table for SVC */
/* WD6 Multi Use */ /* N/U for SVC */
/* WD5 Multi Use */ /* Trap status word for traps */
/* WD6 Multi Use */ /* N/U for traps */
/* WD5 Multi Use */ /* Trap status word for page faults */
/* WD6 Multi Use */ /* Page fault status word */
/* Bit 0 = 0 The map fault was caused by an instruction fetch */
/* = 1 The mp fault was caused by an operand access */
/* Bits 1-20 Always zero */
/* Map register number (logical map block number) */
/* we get here from a LPSD, LPSDCM, INTR, or TRAP */
if (TRAPME) {
#ifdef DO_DYNAMIC_DEBUG
static int pvcnt = 0;
#endif
/* SPAD location 0xf0 has trap vector base address */
uint32 tta = SPAD[0xf0]; /* get trap table address in memory */
uint32 tvl; /* trap vector location */
if (tta == 0 || tta == 0xffffffff)
tta = 0x80; /* if not set, assume 0x80 FIXME */
/* Trap Table Address in memory is pointed to by SPAD 0xF0 */
/* TODO update cpu status and trap status words with reason too */
switch(TRAPME) {
case POWERFAIL_TRAP: /* 0x80 PL00/PL01 power fail trap */
case POWERON_TRAP: /* 0x84 PL00/PL01 Power-On trap */
case MEMPARITY_TRAP: /* 0x88 PL02 Memory Parity Error trap */
case NONPRESMEM_TRAP: /* 0x8C PL03 Non Present Memory trap */
case UNDEFINSTR_TRAP: /* 0x90 PL04 Undefined Instruction Trap */
case PRIVVIOL_TRAP: /* 0x94 PL05 Privlege Violation Trap */
//MOVED case SVCCALL_TRAP: /* 0x98 PL06 Supervisor Call Trap */
case MACHINECHK_TRAP: /* 0x9C PL07 Machine Check Trap */
case SYSTEMCHK_TRAP: /* 0xA0 PL08 System Check Trap */
case MAPFAULT_TRAP: /* 0xA4 PL09 Map Fault Trap */
case IPUUNDEFI_TRAP: /* 0xA8 PL0A IPU Undefined Instruction Trap */
//MOVED case CALM_TRAP: /* 0xA8 PL0A Call Monitor Instruction Trap */
case SIGNALIPU_TRAP: /* 0xAC PL0B Signal IPU/CPU Trap */
case ADDRSPEC_TRAP: /* 0xB0 PL0C Address Specification Trap */
case CONSOLEATN_TRAP: /* 0xB4 PL0D Console Attention Trap */
case PRIVHALT_TRAP: /* 0xB8 PL0E Privlege Mode Halt Trap */
case AEXPCEPT_TRAP: /* 0xBC PL0F Arithmetic Exception Trap */
case CACHEERR_TRAP: /* 0xC0 PL10 Cache Error Trap (V9 Only) */
/* drop through */
default:
#ifdef DO_DYNAMIC_DEBUG
/* start debugging */
// if (TRAPME == PRIVHALT_TRAP)
// if (TRAPME == UNDEFINSTR_TRAP)
if ((TRAPME == PRIVHALT_TRAP) && (pvcnt++ > 5)) {
pvcnt = 0;
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
}
#endif
sim_debug(DEBUG_TRAP, &cpu_dev,
"##TRAPME %04x LOAD MAPS PSD1 %08x PSD2 %08x CPUSTATUS %08x drop_nop %01x i_flags %04x\n",
TRAPME, PSD1, PSD2, CPUSTATUS, drop_nop, i_flags);
/* adjust PSD1 to next instruction */
/* Update instruction pointer to next instruction */
if ((i_flags & BT) == 0) { /* see if PSD was replaced on a branch instruction */
/* branch not taken, so update the PC */
if (EXM_EXR != 0) { /* special handling for EXM, EXR, EXRR */
PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
EXM_EXR = 0; /* reset PC increment for EXR */
} else
if (i_flags & HLF) { /* if nop in rt hw, bump pc a word */
//DIAG V9 if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL >= MODEL_V6)))
if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL == MODEL_V6)))
{
PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
drop_nop = 0;
} else
PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1);
} else {
PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
//DIAG fix for test 34/10 in MMM diag, reset bit 31
// if ((CPU_MODEL == MODEL_87) && (i_flags & ADR))
if ((CPU_MODEL == MODEL_87) || (CPU_MODEL == MODEL_97) ||
(CPU_MODEL == MODEL_V9))
PSD1 &= ~1; /* force off last right */
}
} else {
EXM_EXR = 0; /* reset PC increment for EXR */
if ((drop_nop) && ((CPU_MODEL == MODEL_67) || (CPU_MODEL >= MODEL_V6)))
PSD1 &= ~1; /* force off last right */
drop_nop = 0;
sim_debug(DEBUG_TRAP, &cpu_dev,
"##GOT BT TRAPME %04x LOAD MAPS PSD1 %08x PSD2 %08x\n",
TRAPME, PSD1, PSD2);
}
/* fall through */
/* do not update pc for page fault */
case DEMANDPG_TRAP: /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */
#ifdef DO_DYNAMIC_DEBUG
/* start debugging */
if (TRAPME == DEMANDPG_TRAP)
cpu_dev.dctrl |= (DEBUG_INST | DEBUG_CMD | DEBUG_EXP | DEBUG_IRQ);
#endif
if (TRAPME == DEMANDPG_TRAP) { /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */
/* Set map number */
if (CPU_MODEL >= MODEL_V9)
PSD1 &= ~1; /* force off last right */
/* pfault will have 11 bit page number and bit 0 set if op fetch */
sim_debug(DEBUG_TRAP, &cpu_dev,
"##PAGEFAULT TRAPS %04x page# %04x LOAD MAPS PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
TRAPME, pfault, PSD1, PSD2, CPUSTATUS);
}
sim_debug(DEBUG_TRAP, &cpu_dev,
"At TRAPME %04x PSD1 %08x PSD2 %08x CPUSTATUS %08x drop_nop %02x\n",
TRAPME, PSD1, PSD2, CPUSTATUS, drop_nop);
sim_debug(DEBUG_TRAP, &cpu_dev,
"At TRAP %04x IR %08x PSD1 %08x PSD2 %08x CPUSTATUS %08x ovr %02x drop_nop %02x\n",
TRAPME, IR, PSD1, PSD2, CPUSTATUS, ovr, drop_nop);
tta = tta + (TRAPME - 0x80); /* tta has mem addr of trap vector */
if (modes & (BASEBIT | EXTDBIT))
tvl = M[tta>>2] & 0xFFFFFC; /* get 24 bit trap vector address from trap vector loc */
else
tvl = M[tta>>2] & 0x7FFFC; /* get 19 bit trap vector address from trap vector loc */
sim_debug(DEBUG_TRAP, &cpu_dev,
"tvl %08x, tta %08x status %08x page# %04x\n", tvl, tta, CPUSTATUS, pfault);
if (tvl == 0 || (CPUSTATUS & 0x40) == 0) {
/* vector is zero or software has not enabled traps yet */
/* execute a trap halt */
/* set the PSD to trap vector location */
fprintf(stderr, "[][][][][][][][][][] HALT TRAP [][][][][][][][][][]\r\n");
fprintf(stderr, "PSD1 %08x PSD2 %08x TRAPME %04x\r\n", PSD1, PSD2, TRAPME);
PSD1 = 0x80000000 + TRAPME; /* just priv and PC to trap vector */
PSD2 = 0x00004000; /* unmapped, blocked interrupts mode */
M[0x680>>2] = PSD1; /* store PSD 1 */
M[0x684>>2] = PSD2; /* store PSD 2 */
M[0x688>>2] = TRAPSTATUS; /* store trap status */
M[0x68C>>2] = 0; /* This will be device table entry later TODO */
for (ix=0; ix<8; ix+=2) {
fprintf(stderr, "GPR[%d] %08x GPR[%d] %08x\r\n", ix, GPR[ix], ix+1, GPR[ix+1]);
}
if (modes & BASEBIT) {
for (ix=0; ix<8; ix+=2) {
fprintf(stderr, "BR[%d] %08x BR[%d] %08x\r\n", ix, BR[ix], ix+1, BR[ix+1]);
}
}
fprintf(stderr, "[][][][][][][][][][] HALT TRAP [][][][][][][][][][]\r\n");
return STOP_HALT; /* exit to simh for halt */
} else {
/* valid vector, so store the PSD, fetch new PSD */
bc = PSD2 & 0x3ffc; /* get copy of cpix */
if ((TRAPME) && ((CPU_MODEL <= MODEL_27) ))
/* Privlege Mode Halt Trap on 27 has bit 31 reset */
M[tvl>>2] = PSD1 & 0xfffffffe; /* store PSD 1 */
else
M[tvl>>2] = PSD1 & 0xffffffff; /* store PSD 1 */
M[(tvl>>2)+1] = PSD2; /* store PSD 2 */
PSD1 = M[(tvl>>2)+2]; /* get new PSD 1 */
PSD2 = (M[(tvl>>2)+3] & ~0x3ffc) | bc; /* get new PSD 2 w/old cpix */
M[(tvl>>2)+4] = TRAPSTATUS; /* store trap status */
if (TRAPME == DEMANDPG_TRAP) { /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */
M[(tvl>>2)+5] = pfault; /* store page fault number */
sim_debug(DEBUG_TRAP, &cpu_dev,
"DPAGE tvl %06x PSD1 %08x PSD2 %08x TRAPME %04x TRAPSTATUS %08x\n",
tvl, PSD1, PSD2, TRAPME, pfault);
}
/* set the mode bits and CCs from the new PSD */
CC = PSD1 & 0x78000000; /* extract bits 1-4 from PSD1 */
modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */
CPUSTATUS &= ~0x87000000; /* reset bits in CPUSTATUS */
CPUSTATUS |= modes; /* not insert into CPUSTATUS */
/* set new map mode and interrupt blocking state in CPUSTATUS */
if (PSD2 & MAPBIT) {
CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */
modes |= MAPMODE; /* set mapped mode */
} else
CPUSTATUS &= 0xff7fffff; /* reset bit 8 of cpu status */
/* set interrupt blocking state */
if ((PSD2 & 0x8000) == 0) { /* is it retain blocking state */
if (PSD2 & 0x4000) /* no, is it set blocking state */
CPUSTATUS |= 0x80; /* yes, set blk state in cpu status bit 24 */
else
CPUSTATUS &= ~0x80; /* no, reset blk state in cpu status bit 24 */
}
PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */
if (CPUSTATUS & 0x80) /* see if old mode is blocked */
PSD2 |= 0x00004000; /* set to blocked state */
PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */
SPAD[0xf5] = PSD2; /* save the current PSD2 */
SPAD[0xf9] = CPUSTATUS; /* save the cpu status in SPAD */
sim_debug(DEBUG_TRAP, &cpu_dev,
"Process TRAPME %04x PSD1 %08x PSD2 %08x CPUSTATUS %08x\n",
TRAPME, PSD1, PSD2, CPUSTATUS);
/* TODO provide page fault data to word 6 */
if (TRAPME == DEMANDPG_TRAP) { /* 0xC4 Demand Page Fault Trap (V6&V9 Only) */
/* Set map number */
/* pfault will have 11 bit page number and bit 0 set if op fetch */
sim_debug(DEBUG_TRAP, &cpu_dev,
"PAGE TRAP %04x TSTATUS %08x LOAD MAPS PSD1 %08x PSD2 %08x CPUSTATUS %08x pfault %08x\n",
TRAPME, TRAPSTATUS, PSD1, PSD2, CPUSTATUS, pfault);
}
//TRY*/ skipinstr = 1; /* skip intr test next instruction */
//WAS TRAPSTATUS = CPU_MODEL; /* clear all trap status except cpu type */
TRAPSTATUS = CPUSTATUS & 0x57; /* clear all trap status except cpu type */
break; /* Go execute the trap */
}
break;
}
}
//WAS skipinstr = 1; /* skip intr test next instruction */
/* we have a new PSD loaded via a LPSD or LPSDCM */
/* TODO finish instruction history, then continue */
/* update cpu status word too */
OPSD1 &= 0x87FFFFFF; /* clear the old CC's */
OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */
/* TODO Update other history information for this instruction */
if (hst_lnt) {
hst[hst_p].opsd1 = OPSD1; /* update the CC in opsd1 */
hst[hst_p].npsd1 = PSD1; /* save new psd1 */
hst[hst_p].npsd2 = PSD2; /* save new psd2 */
hst[hst_p].modes = modes; /* save current mode bits */
for (ix=0; ix<8; ix++) {
hst[hst_p].reg[ix] = GPR[ix]; /* save reg */
hst[hst_p].reg[ix+8] = BR[ix]; /* save breg */
}
}
/* DEBUG_INST support code */
/* output mapped/unmapped */
if (modes & MAPMODE)
sim_debug(DEBUG_INST, &cpu_dev, "M%.8x %.8x %.8x ", OPSD1, PSD2, OIR);
else
sim_debug(DEBUG_INST, &cpu_dev, "U%.8x %.8x %.8x ", OPSD1, PSD2, OIR);
if (cpu_dev.dctrl & DEBUG_INST)
fprint_inst(sim_deb, OIR, 0); /* display instruction */
sim_debug(DEBUG_INST, &cpu_dev, "\n\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", GPR[0], GPR[1], GPR[2], GPR[3]);
sim_debug(DEBUG_INST, &cpu_dev, " R4=%.8x R5=%.8x R6=%.8x R7=%.8x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
if (modes & BASEBIT) {
sim_debug(DEBUG_INST, &cpu_dev, "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", BR[0], BR[1], BR[2], BR[3]);
sim_debug(DEBUG_INST, &cpu_dev, " B4=%.8x B5=%.8x B6=%.8x B7=%.8x\n", BR[4], BR[5], BR[6], BR[7]);
}
/// if (TRAPME == MAPFAULT_TRAP)
/// return STOP_HALT; /* exit to simh for halt */
continue; /* single step cpu just for now */
// break; /* quit for now after each instruction */
} /* end while */
/* Simulation halted */
return reason;
}
/* these are the default ipl devices defined by the CPU jumpers */
/* they can be overridden by specifying IPL device at ipl time */
uint32 def_disk = 0x0800; /* disk channel 8, device 0 */
uint32 def_tape = 0x1000; /* tape device 10, device 0 */
uint32 def_floppy = 0x7ef0; /* IOP floppy disk channel 7e, device f0 */
/* Reset routine */
/* do any one time initialization here for cpu */
t_stat cpu_reset(DEVICE * dptr)
{
int i;
/* leave regs alone so values can be passed to boot code */
PSD1 = 0x80000000; /* privileged, non mapped, non extended, address 0 */
PSD2 = 0x00004000; /* blocked interrupts mode */
modes = (PRIVBIT | BLKMODE); /* set modes to privileged and blocked interrupts */
CC = 0; /* no CCs too */
CPUSTATUS = CPU_MODEL; /* clear all cpu status except cpu type */
CPUSTATUS |= 0x80000000; /* set privleged state bit 0 */
CPUSTATUS |= 0x00000080; /* set blocked mode state bit 24 */
TRAPSTATUS = CPU_MODEL; /* clear all trap status except cpu type */
CMCR = 0; /* No Cache Enabled */
SMCR = 0; /* No Shared Memory Enabled */
CMSMC = 0xfffffe10; /* No V9 Cache/Shadow Memory Configuration */
CSMCW = 0; /* No V9 CPU Shadow Memory Configuration */
ISMCW = 0; /* No V9 IPU Shadow Memory Configuration */
chan_set_devs(); /* set up the defined devices on the simulator */
/* set default breaks to execution tracing */
sim_brk_types = sim_brk_dflt = SWMASK('E');
/* zero regs */
for (i = 0; i < 8; i++) {
GPR[i] = BOOTR[i]; /* set boot register values */
BR[i] = 0; /* clear the registers */
}
#ifdef NOTNOW
/* TEMP for UTX boot messages */
if (GPR[7] != 0)
GPR[7] = 0x40; /* set RE_VERBOSE bit for UTX tape boot */
#endif
/* set console switch settings */
M[0x780>>2] = CSW; /* set console switch settings */
/* zero interrupt status words */
for (i = 0; i < 112; i++)
INTS[i] = 0; /* clear interrupt status flags */
/* add code here to initialize the SEL32 cpu scratchpad on initial start */
/* see if spad setup by software, if yes, leave spad alone */
/* otherwise set the default values into the spad */
/* CPU key is 0xECDAB897, IPU key is 0x13254768 */
/* Keys are loaded by the O/S software during the boot loading sequence */
if (SPAD[0xf7] != 0xecdab897)
{
int ival = 0; /* init value for concept 32 */
if (CPU_MODEL < MODEL_27)
ival = 0xfffffff; /* init value for 32/7x int and dev entries */
for (i = 0; i < 1024; i++)
MAPC[i] = 0; /* clear 2048 halfword map cache */
for (i = 0; i < 224; i++)
SPAD[i] = ival; /* init 128 devices and 96 ints in the spad */
for (i = 224; i < 256; i++) /* clear the last 32 extries */
SPAD[i] = 0; /* clear the spad */
SPAD[0xf0] = 0x80; /* default Trap Table Address (TTA) */
SPAD[0xf1] = 0x100; /* Interrupt Table Address (ITA) */
SPAD[0xf2] = 0x700; /* IOCD Base Address */
SPAD[0xf3] = 0x788; /* Master Process List (MPL) table address */
SPAD[0xf4] = def_tape; /* Default IPL address from console IPL command or jumper */
SPAD[0xf5] = 0x00004000; /* current PSD2 defaults to blocked */
SPAD[0xf6] = 0; /* reserved (PSD1 ??) */
//UTX SPAD[0xf7] = 0; /* make sure key is zero */
SPAD[0xf7] = 0xecdab897; /* load the CPU key */
SPAD[0xf8] = 0x0000f000; /* set DRT to class f (anything else is E) */
SPAD[0xf9] = CPUSTATUS; /* set default cpu type in cpu status word */
SPAD[0xff] = 0x00ffffff; /* interrupt level 7f 1's complament */
}
/* set low memory bootstrap code */
M[0] = 0x02000000; /* 0x00 IOCD 1 read into address 0 */
M[1] = 0x60000078; /* 0x04 IOCD 1 CMD Chain, Suppress incor length, 120 bytes */
M[2] = 0x53000000; /* 0x08 IOCD 2 BKSR or RZR to re-read boot code */
M[3] = 0x60000001; /* 0x0C IOCD 2 CMD chain,Supress incor length, 1 byte */
M[4] = 0x02000000; /* 0x10 IOCD 3 Read into address 0 */
M[5] = 0x000006EC; /* 0x14 IOCD 3 Read 0x6EC bytes */
loading = 0; /* not loading yet */
/* we are good to go */
return SCPE_OK;
}
/* Memory examine */
/* examine a 32bit memory location and return a byte */
t_stat cpu_ex(t_value *vptr, t_addr baddr, UNIT *uptr, int32 sw)
{
uint32 status, realaddr, prot;
uint32 addr = (baddr & 0xfffffc) >> 2; /* make 24 bit byte address into word address */
if (sw & SWMASK('V')) {
/* convert address to real physical address */
status = RealAddr(addr, &realaddr, &prot, MEM_RD);
sim_debug(DEBUG_CMD, &cpu_dev, "cpu_ex Mem_read status = %02x\n", status);
if (status == ALLOK) {
*vptr = (M[realaddr] >> (8 * (3 - (baddr & 0x3)))); /* return memory contents */
return SCPE_OK; /* we are all ok */
}
return SCPE_NXM; /* no, none existant memory error */
}
/* MSIZE is in 32 bit words */
if (addr >= MEMSIZE) /* see if address is within our memory */
return SCPE_NXM; /* no, none existant memory error */
if (vptr == NULL) /* any address specified by user */
return SCPE_OK; /* no, just ignore the request */
*vptr = (M[addr] >> (8 * (3 - (baddr & 0x3)))); /* return memory contents */
return SCPE_OK; /* we are all ok */
}
/* Memory deposit */
/* modify a byte specified by a 32bit memory location */
/* address is byte address with bits 30,31 = 0 */
t_stat cpu_dep(t_value val, t_addr baddr, UNIT *uptr, int32 sw)
{
uint32 addr = (baddr & 0xfffffc) >> 2; /* make 24 bit byte address into word address */
static const uint32 bmasks[4] = {0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00};
/* MSIZE is in 32 bit words */
if (addr >= MEMSIZE) /* see if address is within our memory */
return SCPE_NXM; /* no, none existant memory error */
val = (M[addr] & bmasks[baddr & 0x3]) | (val << (8 * (3 - (baddr & 0x3))));
M[addr] = val; /* set new value */
return SCPE_OK; /* all OK */
}
/* set the CPU memory size */
/* table values are in words, not bytes */
uint32 memwds [] = {
0x008000, /* size index 0 - 128KB = 32KW */
0x010000, /* 1 - 256KB = 64KW */
0x020000, /* 2 - 512KB = 128KW */
0x040000, /* 3 - 1MB = 256KW */
0x080000, /* 4 - 2MB = 512KW */
0x0c0000, /* 5 - 3MB = 768KW */
0x100000, /* 6 - 4MB = 1MW */
0x180000, /* 7 - 6MB = 1.5MW */
0x200000, /* 8 - 8MB = 2MW */
0x300000, /* 9 - 12MB = 3MW */
0x400000, /* 10 - 16MB = 4MW */
};
t_stat cpu_set_size(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_uint64 mc = 0;
uint32 i;
cpu_unit.flags &= ~UNIT_MSIZE; /* clear old size value 0-31 */
cpu_unit.flags |= val; /* set new memory size index value (0-31) */
val >>= UNIT_V_MSIZE; /* shift index right 19 bits */
val = memwds[val]; /* (128KB/4) << index == memory size in KW */
if ((val < 0) || (val > MAXMEMSIZE)) /* is size valid */
return SCPE_ARG; /* nope, argument error */
for (i = val; i < MEMSIZE; i++) /* see if memory contains anything */
mc |= M[i]; /* or in any bits in memory */
if ((mc != 0) && (!get_yn("Really truncate memory [N]?", FALSE)))
return SCPE_OK; /* return OK if user says no */
MEMSIZE = val; /* set new size in words */
for (i = MEMSIZE; i < MAXMEMSIZE; i++)
M[i] = 0; /* zero all of the new memory */
return SCPE_OK; /* we done */
}
/* Handle execute history */
/* Set history */
t_stat
cpu_set_hist(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) { /* check for any user options */
for (i = 0; i < hst_lnt; i++) /* none, so just zero the history */
hst[i].opsd1 = 0; /* just psd1 for now */
hst_p = 0; /* start at the beginning */
return SCPE_OK; /* all OK */
}
/* the user has specified options, process them */
lnt = (int32)get_uint(cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
return SCPE_ARG; /* arg error for bad input or too small a value */
hst_p = 0; /* start at beginning */
if (hst_lnt) { /* if a new length was input, resize history buffer */
free(hst); /* out with the old */
hst_lnt = 0; /* no length anymore */
hst = NULL; /* and no pointer either */
}
if (lnt) { /* see if new size specified, if so get new resized buffer */
hst = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt);
if (hst == NULL)
return SCPE_MEM; /* allocation error, so tell user */
hst_lnt = lnt; /* set new length */
}
return SCPE_OK; /* we are good to go */
}
/* 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;
struct InstHistory *h;
if (hst_lnt == 0) /* see if show history is enabled */
return SCPE_NOFNC; /* no, so are out of here */
if (cptr) { /* see if user provided a display count */
lnt = (int32)get_uint(cptr, 10, hst_lnt, &r); /* get the count */
if ((r != SCPE_OK) || (lnt == 0)) /* if error or 0 count */
return SCPE_ARG; /* report argument error */
} else
lnt = hst_lnt; /* dump all the entries */
di = hst_p - lnt; /* work forward */
if (di < 0)
di = di + hst_lnt; /* wrap */
for (k = 0; k < lnt; k++) { /* print specified entries */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
/* display the instruction and results */
if (h->modes & MAPMODE)
fprintf(st, "M%.8x %.8x %.8x ", h->opsd1, h->npsd2, h->oir);
else
fprintf(st, "U%.8x %.8x %.8x ", h->opsd1, h->npsd2, h->oir);
if (h->modes & BASEBIT)
fprint_inst(st, h->oir, SWMASK('M')); /* display basemode instruction */
else
fprint_inst(st, h->oir, 0); /* display non basemode instruction */
fprintf(st, "\n");
fprintf(st, "\tR0=%.8x R1=%.8x R2=%.8x R3=%.8x", h->reg[0], h->reg[1], h->reg[2], h->reg[3]);
fprintf(st, " R4=%.8x R5=%.8x R6=%.8x R7=%.8x", h->reg[4], h->reg[5], h->reg[6], h->reg[7]);
if (h->modes & BASEBIT) {
fprintf(st, "\n");
fprintf(st, "\tB0=%.8x B1=%.8x B2=%.8x B3=%.8x", h->reg[8], h->reg[9], h->reg[10], h->reg[11]);
fprintf(st, " B4=%.8x B5=%.8x B6=%.8x B7=%.8x", h->reg[12], h->reg[13], h->reg[14], h->reg[15]);
}
fprintf(st, "\n");
} /* end for */
return SCPE_OK; /* all is good */
}
/* return description for the specified device */
const char *cpu_description (DEVICE *dptr)
{
return "SEL 32 CPU"; /* return description */
}
t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf(st, "The CPU can maintain a history of the most recently executed instructions.\n");
fprintf(st, "This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:\n\n");
fprintf(st, " sim> SET CPU HISTORY clear history buffer\n");
fprintf(st, " sim> SET CPU HISTORY=0 disable history\n");
fprintf(st, " sim> SET CPU HISTORY=n{:file} enable history, length = n\n");
fprintf(st, " sim> SHOW CPU HISTORY print CPU history\n");
return SCPE_OK;
}