mirror of
https://github.com/rcornwell/sims.git
synced 2026-01-30 05:24:52 +00:00
Add sel32_fltpt.c subroutine set that handles 32/64 bit floating point arithmetic. Also float/fix conversions.
4361 lines
251 KiB
C
4361 lines
251 KiB
C
/* sel32_cpu.c: Sel 32 CPU simulator
|
|
|
|
Copyright (c) 2018, 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 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 */
|
|
/* */
|
|
/* 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 */
|
|
//#define TRME /* set defined to enable instruction trace */
|
|
#undef TRME
|
|
int traceme = 0; /* dynamic trace function */
|
|
int trstart = 8000000; /* count of when to start tracing */
|
|
//int trstart = 37; /* count of when to start tracing */
|
|
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 */
|
|
/* CPU mapping cache entries */
|
|
/* 32/55 has none */
|
|
/* 32/7x has 32 8KW maps per task */
|
|
/* Concept/32 has 2048 2KW maps per task */
|
|
uint32 MAPC[1024]; /* maps are 16bit entries on word bountries */
|
|
uint32 HIWM = 0; /* max maps loaded so far */
|
|
|
|
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 psd1; /* the PC for the instruction */
|
|
uint32 psd2; /* the PC for the instruction */
|
|
uint32 inst; /* the instruction itself */
|
|
uint32 ea; /* computed effective address of data */
|
|
uint32 reg; /* reg for operation */
|
|
uint32 dest; /* destination value */
|
|
uint32 src; /* source value */
|
|
uint8 cc; /* cc's */
|
|
};
|
|
|
|
/* 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);
|
|
t_stat load_maps(uint32 thepsd[2]);
|
|
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 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(void); /* 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(int ss, uint32 level); /* tell rtc to start/stop */
|
|
extern void itm_setup(int ss, uint32 level); /* tell itm to start/stop */
|
|
extern int32 itm_rdwr(uint32 cmd, int32 cnt, uint32 level); /* read/write the interval timer */
|
|
extern int32 itm_srv(UNIT *uptr); /* read/write the interval timer */
|
|
extern UNIT itm_unit; /* fake 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
|
|
*/
|
|
|
|
#ifdef DEFINED_IN_SIM_DEFS_H
|
|
/* Unit data structure from sim_defs.h
|
|
|
|
Parts of the unit structure are device specific, that is, they are
|
|
not referenced by the simulator control package and can be freely
|
|
used by device simulators. Fields starting with 'buf', and flags
|
|
starting with 'UF', are device specific. The definitions given here
|
|
are for a typical sequential device.
|
|
*/
|
|
|
|
struct UNIT {
|
|
UNIT *next; /* next active */
|
|
t_stat (*action)(UNIT *up); /* action routine */
|
|
char *filename; /* open file name */
|
|
FILE *fileref; /* file reference */
|
|
void *filebuf; /* memory buffer */
|
|
uint32 hwmark; /* high water mark */
|
|
int32 time; /* time out */
|
|
uint32 flags; /* flags */
|
|
uint32 dynflags; /* dynamic flags */
|
|
t_addr capac; /* capacity */
|
|
t_addr pos; /* file position */
|
|
void (*io_flush)(UNIT *up); /* io flush routine */
|
|
uint32 iostarttime; /* I/O start time */
|
|
int32 buf; /* buffer */
|
|
int32 wait; /* wait */
|
|
int32 u3; /* device specific */
|
|
int32 u4; /* device specific */
|
|
int32 u5; /* device specific */
|
|
int32 u6; /* device specific */
|
|
void *up7; /* device specific */
|
|
void *up8; /* device specific */
|
|
uint16 us9; /* device specific */
|
|
uint16 us10; /* device specific */
|
|
void *tmxr; /* TMXR linkage */
|
|
t_bool (*cancel)(UNIT *);
|
|
double usecs_remaining; /* time balance for long delays */
|
|
char *uname; /* Unit name */
|
|
#ifdef SIM_ASYNCH_IO
|
|
void (*a_check_completion)(UNIT *);
|
|
t_bool (*a_is_active)(UNIT *);
|
|
UNIT *a_next; /* next asynch active */
|
|
int32 a_event_time;
|
|
ACTIVATE_API a_activate_call;
|
|
/* Asynchronous Polling control */
|
|
/* These fields should only be referenced when holding the sim_tmxr_poll_lock */
|
|
t_bool a_polling_now; /* polling active flag */
|
|
int32 a_poll_waiter_count; /* count of polling threads */
|
|
/* waiting for this unit */
|
|
/* Asynchronous Timer control */
|
|
double a_due_time; /* due time for timer event */
|
|
double a_due_gtime; /* due time (in instructions) for timer event */
|
|
double a_usec_delay; /* time delay for timer event */
|
|
#endif /* SIM_ASYNCH_IO */
|
|
};
|
|
|
|
/* Unit flags */
|
|
|
|
#define UNIT_V_UF_31 12 /* dev spec, V3.1 */
|
|
#define UNIT_V_UF 16 /* device specific */
|
|
#define UNIT_V_RSV 31 /* reserved!! */
|
|
#define FEAT_TIMER (1<<(UNIT_V_UF+12)) /* interval timer */
|
|
#define TMR_RTC 0
|
|
|
|
#define UNIT_ATTABLE 0000001 /* attachable */
|
|
#define UNIT_RO 0000002 /* read only */
|
|
#define UNIT_FIX 0000004 /* fixed capacity */
|
|
#define UNIT_SEQ 0000010 /* sequential */
|
|
#define UNIT_ATT 0000020 /* attached */
|
|
#define UNIT_BINK 0000040 /* K = power of 2 */
|
|
#define UNIT_BUFABLE 0000100 /* bufferable */
|
|
#define UNIT_MUSTBUF 0000200 /* must buffer */
|
|
#define UNIT_BUF 0000400 /* buffered */
|
|
#define UNIT_ROABLE 0001000 /* read only ok */
|
|
#define UNIT_DISABLE 0002000 /* disable-able */
|
|
#define UNIT_DIS 0004000 /* disabled */
|
|
#define UNIT_IDLE 0040000 /* idle eligible */
|
|
#endif /* DEFINED_IN_SIM_DEFS_H */
|
|
|
|
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 */
|
|
UNIT_BINK|MODEL(MODEL_27)|MEMAMOUNT(1), /* 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 */
|
|
};
|
|
|
|
/* Register data structure definition from sim_defs.h */
|
|
#ifdef DEFINED_IN_SIM_DEFS_H
|
|
struct REG {
|
|
CONST char *name; /* name */
|
|
void *loc; /* location */
|
|
uint32 radix; /* radix */
|
|
uint32 width; /* width */
|
|
uint32 offset; /* starting bit */
|
|
uint32 depth; /* save depth */
|
|
const char *desc; /* description */
|
|
BITFIELD *fields; /* bit fields */
|
|
uint32 qptr; /* circ q ptr */
|
|
size_t str_size; /* structure size */
|
|
/* NOTE: Flags MUST always be last since it is initialized outside of macro definitions */
|
|
uint32 flags; /* flags */
|
|
};
|
|
|
|
/* Register flags from sim_defs.h */
|
|
#define REG_FMT 00003 /* see PV_x */
|
|
#define REG_RO 00004 /* read only */
|
|
#define REG_HIDDEN 00010 /* hidden */
|
|
#define REG_NZ 00020 /* must be non-zero */
|
|
#define REG_UNIT 00040 /* in unit struct */
|
|
#define REG_STRUCT 00100 /* in structure array */
|
|
#define REG_CIRC 00200 /* circular array */
|
|
#define REG_VMIO 00400 /* use VM data print/parse */
|
|
#define REG_VMAD 01000 /* use VM addr print/parse */
|
|
#define REG_FIT 02000 /* fit access to size */
|
|
#define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */
|
|
|
|
#define REG_V_UF 16 /* device specific */
|
|
#define REG_UFMASK (~((1u << REG_V_UF) - 1)) /* user flags mask */
|
|
#define REG_VMFLAGS (REG_VMIO | REG_UFMASK) /* call VM routine if any of these are set */
|
|
#endif /* DEFINED_IN_SIM_DEFS_H */
|
|
|
|
//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, "Progtam 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(SPAD, SPAD, 16, 32, 256, "CPU Scratchpad memory"), REG_FIT},
|
|
{BRDATAD(MAPC, MAPC, 16, 32, 1024, "CPU map cache"), 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},
|
|
// {ORDATAD(BASE, baseaddr, 16, "Relocation base"), 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), "8M", "8M", &cpu_set_size},
|
|
{UNIT_MSIZE, MEMAMOUNT(8), "16M", "16M", &cpu_set_size},
|
|
{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 */
|
|
24, /* uint32 awidth */ /* address width */
|
|
2, /* uint32 aincr */ /* address increment */
|
|
16, /* uint32 dradix */ /* data radix */
|
|
32, /* 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 SDD 0x0200 /* Stores double into destination */
|
|
#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, INV, INV,
|
|
/* 50 54 58 5C */
|
|
/* */
|
|
INV, INV, INV, INV,
|
|
|
|
/* 60 64 68 6C */
|
|
/* NOR NORD SCZ SRA */
|
|
HLF, HLF, HLF, HLF,
|
|
|
|
/* 70 74 78 7C */
|
|
/* SRL SRC SRAD SRLD */
|
|
SD|HLF, SD|HLF, HLF, HLF,
|
|
|
|
/* 80 84 88 8C */
|
|
/* LEAR ANM ORM EOM */
|
|
SD|ADR, SCC|SD|RR|RM|ADR, SCC|SD|RR|RM|ADR, SCC|SD|RR|RM|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,
|
|
|
|
/* 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 */
|
|
RM|ADR, RM|ADR, SCC|SM|RR|RM|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|RR|SD|HLF, SCC|RR|SD|HLF, SCC|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, SD|HLF, SD|HLF,
|
|
/* 40 44 48 4C */
|
|
/* */
|
|
INV, INV, INV, INV,
|
|
|
|
/* 50 54 58 5C */
|
|
/* LA BASE BASE CALLM */
|
|
SD|ADR, SM,ADR, SB|RM|ADR, 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|RM|ADR, SD|RM|ADR, SD|RM|ADR,
|
|
|
|
/* CAM CMM SBM ZBM */
|
|
/* 90 94 98 9C */
|
|
RM|ADR, RM|ADR, ADR, ADR,
|
|
|
|
/* A0 A4 A8 AC */
|
|
/* ABM TBM EXM L */
|
|
ADR, ADR, ADR, SD|RM|ADR,
|
|
|
|
/* B0 B4 B8 BC */
|
|
/* LM LN ADM SUM */
|
|
SD|RM|ADR,SD|RM|ADR, SD|RM|ADR, SD|RM|ADR,
|
|
|
|
/* C0 C4 C8 CC */
|
|
/* MPM DVM IMM LF */
|
|
SD|RM|ADR, RM|ADR, IMM, ADR,
|
|
|
|
/* D0 D4 D8 DC */
|
|
/* LEA ST STM STFBR */
|
|
SD|ADR, SM|ADR, SM|ADR, ADR,
|
|
|
|
/* E0 E4 E8 EC */
|
|
/* ADF MPF ARM BCT */
|
|
RM|ADR, RM|ADR, SM|RM|ADR, ADR,
|
|
|
|
/* F0 F4 F8 FC */
|
|
/* BCF BI MISC IO */
|
|
ADR, RR|SB|WRD, ADR, IMM,
|
|
};
|
|
|
|
/* 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 */
|
|
t_stat load_maps(uint32 thepsd[2])
|
|
{
|
|
uint32 num, sdc, spc;
|
|
uint32 mpl, cpixmsdl, bpixmsdl, msdl, midl;
|
|
uint32 cpix, bpix, i, j, map, osmidl;
|
|
|
|
if (CPU_MODEL < MODEL_27)
|
|
{
|
|
/* 32/7x machine, 8KW maps */
|
|
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 */
|
|
bpix = (thepsd[1] >> 18) & 0xfff; /* 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 */
|
|
cpixmsdl = M[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 bpix msdl word address */
|
|
sdc = (bpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */
|
|
msdl = (bpixmsdl >> 2) & 0x3fffff; /* get 24 bit real address of msdl */
|
|
for (i = 0; i < sdc; i++) /* loop through the msd's */
|
|
{
|
|
spc = (M[msdl + i] >> 24) & 0xff; /* get segment page count from msdl */
|
|
midl = (M[msdl + i] >> 2) && 0x3fffff; /* get 24 bit real word address of midl */
|
|
for (j = 0; j < spc; j++)
|
|
{
|
|
/* load 16 bit map descriptors */
|
|
map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */
|
|
if (j & 1)
|
|
map = (map & RMASK); /* use right half word map entry */
|
|
else
|
|
map = ((map >> 16) & RMASK); /* use left half word map entry */
|
|
/* the map register contents is now in right 16 bits */
|
|
/* now load a 32 bit word with both maps from memory */
|
|
/* and or in the new map entry data */
|
|
if (num & 1) {
|
|
/* entry going to rt hw, clean it first */
|
|
map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */
|
|
}
|
|
else {
|
|
/* entry going to left hw, clean it first */
|
|
map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */
|
|
}
|
|
MAPC[num++/2] = map; /* store the map reg contents into cache */
|
|
if (num >= 32)
|
|
return MAPFLT; /* map loading overflow, map fault error */
|
|
}
|
|
}
|
|
}
|
|
/* now load cpix maps */
|
|
cpixmsdl = M[mpl + cpix]; /* get cpix msdl word address */
|
|
sdc = (cpixmsdl >> 24) & 0x3f; /* get 6 bit segment description count */
|
|
msdl = (cpixmsdl >> 2) & 0x3fffff; /* get 24 bit real address of msdl */
|
|
for (i = 0; i < sdc; i++)
|
|
{
|
|
spc = (M[msdl + i] >> 24) & 0xff; /* get segment page count from msdl */
|
|
midl = (M[msdl + i] >> 2) && 0x3fffff; /* get 24 bit real word address of midl */
|
|
for (j = 0; j < spc; j++)
|
|
{
|
|
/* load 16 bit map descriptors */
|
|
map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */
|
|
if (j & 1)
|
|
map = (map & RMASK); /* use right half word map entry */
|
|
else
|
|
map = ((map >> 16) & RMASK); /* use left half word map entry */
|
|
/* the map register contents is now in right 16 bits */
|
|
/* now load a 32 bit word with both maps from memory */
|
|
/* and or in the new map entry data */
|
|
if (num & 1) {
|
|
/* entry going to rt hw, clean it first */
|
|
map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */
|
|
}
|
|
else {
|
|
/* entry going to left hw, clean it first */
|
|
map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */
|
|
}
|
|
MAPC[num++/2] = map; /* store the map reg contents into cache */
|
|
if (num >= 32)
|
|
return MAPFLT; /* map loading overflow, map fault error */
|
|
}
|
|
}
|
|
/* if none loaded, map fault */
|
|
if (num == 0)
|
|
return MAPFLT; /* map fault error */
|
|
if (num & 1) { /* clear rest of maps */
|
|
/* left hw of map is good, zero right */
|
|
map = (MAPC[num/2] & LMASK); /* clean rt hw */
|
|
MAPC[num++/2] = map; /* store the map reg contents into cache */
|
|
}
|
|
/* num should be even at this point, so zero 32 bit word for remaining maps */
|
|
if ((num/2) > HIWM) /* largerst number of maps loaded so far* */
|
|
HIWM = num/2; /* yes, set new high water mark */
|
|
// for (i = num/2; i < 32/2; i++) /* zero any remaining entries */
|
|
for (i = num/2; i < HIWM; i++) /* zero any remaining entries */
|
|
MAPC[i] = 0; /* clear the map entry to make not valid */
|
|
HIWM = num/2; /* set new high water mark */
|
|
return ALLOK; /* all cache is loaded, return OK */
|
|
}
|
|
else
|
|
{
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
char n[9];
|
|
uint32 dqe;
|
|
#endif
|
|
/* 32/27, 32/67, 32/87, 32/97 2KW maps */
|
|
/* Concept/32 machine, 2KW maps */
|
|
if ((modes & MAPMODE) == 0) { /* mapped mode? */
|
|
return ALLOK; /* no, all OK, no mapping required */
|
|
}
|
|
/* we are mapped, so calculate real address from map information */
|
|
cpix = (thepsd[1] >> 2) & 0xfff; /* get word cpix 11 bit offset from psd wd 2 */
|
|
num = 0; /* no maps loaded yet */
|
|
/* master process list is in 0xf3 of spad for concept */
|
|
mpl = SPAD[0xf3] >> 2; /* get mpl from spad address */
|
|
midl = M[mpl+cpix]; /* get mpl entry wd 0 for given cpix */
|
|
msdl = M[mpl+cpix+1]; /* get mpl entry wd 1 for given cpix */
|
|
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
//traceme = trstart;
|
|
if (traceme >= trstart) {
|
|
dqe = M[0x8e8>>2];
|
|
for (j=0; j<8; j++) {
|
|
n[j] = (M[((dqe+0x18)>>2)+(j/4)] >> ((3-(j&7))*8)) & 0xff;
|
|
if (n[j] == 0)
|
|
n[j] = 0x20;
|
|
}
|
|
n[8] = 0;
|
|
fprintf(stderr, "\r\nmapping SPAD[0xf3] %x mpl %x mpl0 %x mpl1 %x midl %x msdl %x cpix %x\r\n",
|
|
SPAD[0xf3], mpl<<2, M[mpl], M[mpl+1], midl, msdl, cpix<<2);
|
|
fprintf(stderr, "mapping SPAD PSD2 %.8x PSD2 %x mpl %x osmidl %x osmidl2 %x umidl %x C.CURR %x LMN %s\r\n",
|
|
SPAD[0xf5], PSD2, mpl<<2, M[mpl], M[mpl+1], midl, dqe, n);
|
|
}
|
|
#endif
|
|
/* load msd 0 maps first (O/S) */
|
|
osmidl = M[mpl]; /* get midl 0 word address */
|
|
/* if bit zero of cpix mpl entry is set, use msd entry 0 first to load maps */
|
|
/* This test must be made (cpix == bpix) to allow sysgen to run without using a valid cpix */
|
|
/* the cpix is zero indicating only load MSD 0 for the target system */
|
|
/* bit 0 of msd 0 will be zero saying load the maps */
|
|
if ((osmidl == midl) || (midl & BIT0)) {
|
|
/* Do not load O/S if already loaded. Bit zero of O/S midl will be set by swapper on startup */
|
|
/* load msd 0 maps first (O/S) */
|
|
spc = osmidl & MASK16; /* get 16 bit segment description count */
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
fprintf(stderr, "mapping osmidl %x spc %x osmsdl %x usermidl %x\r\n", osmidl, spc, M[mpl+1], midl);
|
|
#endif
|
|
if (osmidl & BIT0) { /* see if O/S already loaded */
|
|
num = spc; /* set the number of o/s maps loaded */
|
|
goto skipos; /* skip load */
|
|
}
|
|
midl = M[mpl+1] & MASK24; /* get 24 bit real address from mpl wd2 */
|
|
midl = midl>>2; /* make word address */
|
|
for (j = 0; j < spc; j++)
|
|
{
|
|
/* load 16 bit map descriptors */
|
|
map = (M[midl + (j / 2)]); /* get 2 16 bit map entries */
|
|
if (j & 1)
|
|
map = (map & RMASK); /* use right half word map entry */
|
|
else
|
|
map = ((map >> 16) & RMASK); /* use left half word map entry */
|
|
/* the map register contents is now in right 16 bits */
|
|
/* now load a 32 bit word with both maps from memory */
|
|
/* and or in the new map entry data */
|
|
if (num & 1) {
|
|
/* entry going to rt hw, clean it first */
|
|
map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
if (traceme >= trstart) {
|
|
fprintf(stderr, "mapping 0x%x O/S num 0x%x midl %x MAPC[%d] %x\r\n",
|
|
spc, num-1, (midl+(j/2))<<2, num/2, map);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
/* entry going to left hw, clean it first */
|
|
map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */
|
|
}
|
|
MAPC[num/2] = map; /* store the map reg contents into cache */
|
|
if (++num >= 2048)
|
|
return MAPFLT; /* map loading overflow, map fault error */
|
|
}
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
if (traceme >= trstart) {
|
|
if (num & 1)
|
|
fprintf(stderr, "mapping 0x%x O/S num 0x%x midl %x MAPC[%d] %x\r\n",
|
|
spc, num-1, (midl+((spc-1)/2))<<2, num/2, map);
|
|
}
|
|
#endif
|
|
}
|
|
skipos:
|
|
/* sysgen in mpx does not have a valid cpix MPL entry, only a bpix entry */
|
|
/* that entry uses 64 map entries to map between target/host systems */
|
|
/* When cpix in instruction is zero, just load the O/S specified by MSD 0 */
|
|
if (cpix == 0)
|
|
goto skipcpix; /* only load maps specified by msd 0 */
|
|
|
|
/* now load cpix maps */
|
|
midl = M[mpl+cpix]; /* get cpix midl word address */
|
|
msdl = M[mpl+cpix+1]; /* get 24 bit real word address of midl */
|
|
spc = midl & RMASK; /* get segment page count from msdl */
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
fprintf(stderr, "mapping usmidl %x spc %x msdl %x\r\n", midl, spc, msdl);
|
|
#endif
|
|
midl = M[mpl+cpix+1] & MASK24; /* get 24 bit real word address of midl */
|
|
midl = midl>>2; /* get word address of midl */
|
|
for (j = 0; j < spc; j++)
|
|
{
|
|
/* load 16 bit map descriptors */
|
|
map = M[midl + (j / 2)]; /* get 2 16 bit map entries */
|
|
if (j & 1)
|
|
map = (map & RMASK); /* use right half word map entry */
|
|
else
|
|
map = ((map >> 16) & RMASK); /* use left half word map entry */
|
|
/* the map register contents is now in right 16 bits */
|
|
/* now load a 32 bit word with both maps from memory */
|
|
/* and or in the new map entry data */
|
|
if (num & 1) {
|
|
/* entry going to rt hw, clean it first */
|
|
map = (MAPC[num/2] & LMASK) | map; /* map is in rt hw */
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
if (traceme >= trstart) {
|
|
fprintf(stderr, "mapping 0x%x USER num 0x%x midl %x MAPC[%d] %x\r\n",
|
|
spc, num-1, (midl+(j/2))<<2, num/2, map);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
/* entry going to left hw, clean it first */
|
|
map = (MAPC[num/2] & RMASK) | (map << 16); /* map is in left hw */
|
|
}
|
|
MAPC[num/2] = map; /* store the map reg contents into cache */
|
|
if (++num >= 2048)
|
|
return MAPFLT; /* map loading overflow, map fault error */
|
|
}
|
|
/* if none loaded, map fault */
|
|
/* we got here without map block found, return map fault error */
|
|
if (num == 0)
|
|
return MAPFLT; /* map fault error */
|
|
skipcpix:
|
|
if (num & 1) {
|
|
/* left hw of map is good, zero right */
|
|
map = (MAPC[num/2] & LMASK); /* clean rt hw */
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
if (traceme >= trstart) {
|
|
if (spc != 0)
|
|
fprintf(stderr, "mapping 0x%x USER num 0x%x midl %x MAPC[%d] %x\r\n",
|
|
spc, num-1, (midl+((spc-1)/2))<<2, num/2, map);
|
|
}
|
|
#endif
|
|
MAPC[num++/2] = map; /* store the map reg contents into cache */
|
|
}
|
|
/* num should be even at this point, so zero 32 bit words for remaining maps */
|
|
if ((num/2) > HIWM) /* largest number of maps loaded so far* */
|
|
HIWM = num/2; /* yes, set new high water mark */
|
|
// for (i = num/2; i < 2048/2; i++) /* zero any remaining entries */
|
|
for (i = num/2; i < HIWM; i++) /* zero any remaining entries */
|
|
MAPC[i] = 0; /* clear the map entry to make not valid */
|
|
HIWM = num/2; /* set new high water mark */
|
|
return ALLOK; /* all cache is loaded, retun OK */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return the real memory address from the logical address
|
|
* Also return the protection status, 1 if write protected address
|
|
*/
|
|
t_stat RealAddr(uint32 addr, uint32 *realaddr, uint32 *prot)
|
|
{
|
|
uint32 word, index, map, mask;
|
|
|
|
*prot = 0; /* show unprotected memory as default */
|
|
/* unmapped mode is unprotected */
|
|
|
|
/* 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) /* 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 = MAPC[index/2]; /* get two hw map entries */
|
|
if (index & 1)
|
|
/* entry is in rt hw, clear left hw */
|
|
map &= RMASK; /* map is in rt hw */
|
|
else
|
|
/* entry is in left hw, move to rt hw */
|
|
map >>= 16; /* map is in left hw */
|
|
/* see if map is valid */
|
|
if (map & 0x4000) {
|
|
/* 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) /* 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 */
|
|
}
|
|
/* map is invalid, so return map fault error */
|
|
return MAPFLT; /* map fault error */
|
|
}
|
|
else {
|
|
/* 32/27, 32/67, 32/87, 32/97 2KW maps */
|
|
/* Concept 32 machine, 2KW maps */
|
|
if (modes & (BASEBIT | EXTDBIT))
|
|
word = addr & 0xffffff; /* get 24 bit address */
|
|
else
|
|
word = addr & 0x7ffff; /* get 19 bit address */
|
|
if ((modes & MAPMODE) == 0) {
|
|
/* check if valid real address */
|
|
if (word >= MEMSIZE) /* 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 */
|
|
}
|
|
/* replace bits 8-18 with 11 bits from memory map register */
|
|
/* we are mapped, so calculate real address from map information */
|
|
index = (word >> 13) & 0x7ff; /* get 11 bit value */
|
|
map = MAPC[index/2]; /* get two hw map entries */
|
|
if (index & 1)
|
|
/* entry is in rt hw, clear left hw */
|
|
map &= RMASK; /* map is in rt hw */
|
|
else
|
|
/* entry is in left hw, move to rt hw */
|
|
map >>= 16; /* map is in left hw */
|
|
if (map & 0x8000) { /* see if map is valid */
|
|
/* required map is valid, get 11 bit address and merge with 13 bit page offset */
|
|
word = ((map & 0x7ff) << 13) | (word & 0x1fff);
|
|
/* check if valid real address */
|
|
if (word >= MEMSIZE) /* 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 */
|
|
mask = (word & 0x1800) >> 11; /* get offset of 2kb block for map being addressed */
|
|
if (map & (0x4000 >> mask)) /* 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 */
|
|
}
|
|
/* map is invalid, so return map fault error */
|
|
sim_debug(DEBUG_CMD, &cpu_dev, "RealAddr MAP FAIL %x MAPC %x word %x addr %x index %x\n",
|
|
map, MAPC[index/2], word, addr, index);
|
|
return MAPFLT; /* map fault error */
|
|
}
|
|
}
|
|
|
|
/* fetch the current instruction from the PC address */
|
|
t_stat read_instruction(uint32 thepsd[2], uint32 *instr)
|
|
{
|
|
uint32 addr, status;
|
|
|
|
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 */
|
|
}
|
|
status = Mem_read(addr, instr); /* get the instruction at the specified address */
|
|
sim_debug(DEBUG_DETAIL, &cpu_dev, "read_instr status = %x\n", status);
|
|
return status; /* return ALLOK or ERROR */
|
|
}
|
|
|
|
/*
|
|
* Read a full word from memory
|
|
* Return error type if failure, ALLOK if
|
|
* success. Addr is logical address.
|
|
*/
|
|
t_stat Mem_read(uint32 addr, uint32 *data)
|
|
{
|
|
uint32 status, realaddr, prot;
|
|
|
|
status = RealAddr(addr, &realaddr, &prot); /* convert address to real physical address */
|
|
sim_debug(DEBUG_DETAIL, &cpu_dev, "Mem_read status = %x\n", status);
|
|
if (status == ALLOK) {
|
|
*data = M[realaddr >> 2]; /* valid address, get physical address contents */
|
|
status = ALLOK; /* good status return */
|
|
sim_debug(DEBUG_DETAIL, &cpu_dev, "Mem_read addr %.8x realaddr %.8x data %.8x prot %d\n",
|
|
addr, realaddr, *data, prot);
|
|
}
|
|
return status; /* return ALLOK or ERROR */
|
|
}
|
|
|
|
/*
|
|
* Write a full word to memory, checking protection
|
|
* and alignment restrictions. Return 1 if failure, 0 if
|
|
* success. Addr is logical address, data is 32bit word
|
|
*/
|
|
t_stat Mem_write(uint32 addr, uint32 *data)
|
|
{
|
|
uint32 status, realaddr, prot;
|
|
|
|
status = RealAddr(addr, &realaddr, &prot); /* convert address to real physical address */
|
|
sim_debug(DEBUG_DETAIL, &cpu_dev, "Mem_write addr %.8x realaddr %.8x data %.8x prot %d\n",
|
|
addr, realaddr, *data, prot);
|
|
if (status == ALLOK) {
|
|
if (prot) /* check for write protected memory */
|
|
return MPVIOL; /* return memory protection violation */
|
|
M[realaddr >> 2] = *data; /* valid address, put physical address contents */
|
|
status = ALLOK; /* good status return */
|
|
}
|
|
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 */
|
|
uint32 addr; /* Holds address of last access */
|
|
uint32 temp; /* General holding place for stuff */
|
|
uint32 IR; /* Instruction register */
|
|
uint32 i_flags; /* Instruction description flags from table */
|
|
uint32 t; /* Temporary */
|
|
uint32 temp2; /* Temporary */
|
|
uint32 bc; /* 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 */
|
|
int reg; /* GPR or Base register bits 6-8 */
|
|
int sreg; /* Source reg in from bits 9-11 reg-reg instructions */
|
|
int ix; /* index register */
|
|
int dbl; /* Double word */
|
|
int ovr; /* Overflow flag */
|
|
int stopnext = 0; /* Stop on next instruction */
|
|
int skipinstr = 0; /* Skip test for interrupt on this instruction */
|
|
uint32 int_icb; /* interrupt context block address */
|
|
uint32 OIR; /* Original Instruction register */
|
|
uint32 OPSD1; /* Original PSD1 */
|
|
uint32 OPC; /* Original PC */
|
|
|
|
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)
|
|
stopnext = 1;
|
|
else
|
|
break; /* process */
|
|
}
|
|
}
|
|
|
|
if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) {
|
|
reason = STOP_IBKPT;
|
|
break;
|
|
}
|
|
|
|
/* call our fake interval timer to count down 64 instructions per count */
|
|
itm_srv(&itm_unit); /* service interval timer */
|
|
sim_interval--; /* count down */
|
|
|
|
if (skipinstr) { /* need to skip interrupt test? */
|
|
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_icb = scan_chan(); /* no, go scan for I/O int pending */
|
|
if (int_icb != 0) { /* was ICB returned for an I/O or interrupt */
|
|
int il;
|
|
/* find interrupt level for icb address */
|
|
for (il=0; il<112; il++) {
|
|
/* get the address of the interrupt IVL table in main memory */
|
|
uint32 civl = SPAD[0xf1] + (il<<2); /* contents of spad f1 points to chan ivl in mem */
|
|
civl = M[civl >> 2]; /* get the interrupt context block addr in memory */
|
|
if (civl == int_icb)
|
|
break;
|
|
}
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "Normal int scan return icb %x irq_pend %x wait4int %x\n",
|
|
int_icb, 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 */
|
|
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 */
|
|
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 */
|
|
sim_debug(DEBUG_INST, &cpu_dev,
|
|
"Interrupt %x OPSD1 %.8x OPSD2 %.8x NPSD1 %.8x NPSD2 %.8x ICBA %x\n",
|
|
il, M[int_icb>>2], M[(int_icb>>2)+1], PSD1, PSD2, int_icb);
|
|
wait4int = 0; /* wait is over for int */
|
|
skipinstr = 1; /* skip next interrupt test only once */
|
|
}
|
|
/* see if waiting at a wait instruction */
|
|
if (wait4int || loading) {
|
|
// ???? sim_interval++; /* restore count */
|
|
goto wait_loop; /* continue waiting */
|
|
}
|
|
} else {
|
|
if (loading) {
|
|
uint32 chsa = scan_chan(); /* 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 = 0x80000000; /* get new PSD 1, priv and addr is 0 */
|
|
PSD2 = 0x00004000; /* get new PSD 2, blocked */
|
|
modes = PSD1 & 0x87000000; /* extract bits 0, 5, 6, 7 from PSD 1 */
|
|
sim_debug(DEBUG_INST, &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 */
|
|
loading = 0; /* we are done loading */
|
|
skipinstr = 1; /* skip next interrupt test only once */
|
|
}
|
|
goto wait_loop; /* continue waiting */
|
|
}
|
|
/* see if in wait instruction */
|
|
if (wait4int) /* TRY this */
|
|
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; /* do only once */
|
|
sim_debug(DEBUG_DETAIL, &cpu_dev, "Attention TRAP %x\n", TRAPME);
|
|
skipinstr = 1; /* skip next interrupt test only once */
|
|
goto newpsd; /* got process trap */
|
|
}
|
|
|
|
skipi:
|
|
if (sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) {
|
|
reason = STOP_IBKPT;
|
|
break;
|
|
}
|
|
|
|
/* fill IR from logical memory address */
|
|
if ((TRAPME = read_instruction(PSD, &IR))) {
|
|
sim_debug(DEBUG_INST, &cpu_dev, "read_instr TRAPME = %x\n", TRAPME);
|
|
goto newpsd; /* got process trap */
|
|
}
|
|
|
|
/* If executing right half */
|
|
if (PSD1 & 2)
|
|
IR <<= 16;
|
|
exec:
|
|
/*FIXME temp saves for debugging */
|
|
OIR = IR;
|
|
OPSD1 = PSD1;
|
|
OPC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */
|
|
|
|
/* TODO 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].psd1 = PSD1; /* set execution address */
|
|
hst[hst_p].psd2 = PSD2; /* set mapping/blocking status */
|
|
}
|
|
|
|
/* Split instruction into pieces */
|
|
PC = PSD1 & 0xfffffe; /* get 24 bit addr from PSD1 */
|
|
sim_debug(DEBUG_DATA, &cpu_dev, "-----Instr @ PC %x PSD1 %.8x PSD2 %.8x IR %.8x\n", PC, PSD1, PSD2, IR);
|
|
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 */
|
|
|
|
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_INST, &cpu_dev, "Base i_flags %x addr %.8x\n", 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:
|
|
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 >> 20) & 7; /* get index reg from instruction */
|
|
if (ix != 0)
|
|
addr += GPR[ix]; /* if not zero, add in reg contents */
|
|
ix = (IR >> 16) & 7; /* get base reg from instruction */
|
|
if (ix != 0)
|
|
addr += BR[ix]; /* 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 */
|
|
break;
|
|
case INV:
|
|
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
|
|
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 */
|
|
|
|
sim_debug(DEBUG_INST, &cpu_dev, "Non Based i_flags %x addr %.8x\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)) {
|
|
TRAPME = ADDRSPEC_TRAP; /* bad address, error */
|
|
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. */
|
|
/* Bit 0,1 are set to 1 of 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 */
|
|
while (t & IND) { /* process indirection */
|
|
if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */
|
|
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 */
|
|
if (modes & EXTDBIT) { /* check if in extended mode */
|
|
/* extended mode, so location has 24 bit addr, not X,I ADDR */
|
|
addr = temp & MASK24; /* get 24 bit addr */
|
|
/* if no C bits set, use original, else new */
|
|
if ((IR & F_BIT) || (addr & 3))
|
|
FC = ((IR & F_BIT) ? 0x4 : 0) | (addr & 3);
|
|
t &= ~IND; /* turn off IND bit to stop while loop */
|
|
} else {
|
|
/* non-extended mode, 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);
|
|
t = temp; /* go process next indirect location */
|
|
}
|
|
}
|
|
if (OP == 0xD0) /* test for LEA op */
|
|
addr |= bc; /* insert bits 0,1 values into address */
|
|
dest = (t_uint64)addr; /* make into 64 bit variable */
|
|
break;
|
|
case INV: /* Invalid instruction */
|
|
if ((TRAPME = Mem_read(addr, &temp))) /* get the word from memory */
|
|
goto newpsd; /* memory read error or map fault */
|
|
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
|
|
goto newpsd; /* handle trap */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Read memory operand */
|
|
if (i_flags & RM) {
|
|
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 */
|
|
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 & 2) != 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 */
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* TODO Update other history information for this instruction */
|
|
if(hst_lnt) {
|
|
hst[hst_p].inst = IR; /* save the instruction */
|
|
hst[hst_p].dest = dest; /* save the destination */
|
|
hst[hst_p].src = source; /* save the source */
|
|
hst[hst_p].reg = reg; /* save the src/dst reg */
|
|
}
|
|
|
|
sim_debug(DEBUG_INST, &cpu_dev, "SW OP %x Non Based i_flags %x addr %.8x\n", OP, i_flags, 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 */
|
|
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 */
|
|
}
|
|
/*FIXME*/
|
|
reason = STOP_HALT; /* do halt for now */
|
|
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 */
|
|
goto newpsd; /* Privlege violation trap */
|
|
}
|
|
if (wait4int == 0) {
|
|
time_t result = time(NULL);
|
|
// fprintf(stderr, "Starting WAIT mode @%ju\r\n", (intmax_t)result);
|
|
sim_debug(DEBUG_CMD, &cpu_dev, "Starting WAIT mode %ju\n", (intmax_t)result);
|
|
}
|
|
wait4int = 1; /* show we are waiting for interrupt */
|
|
i_flags |= BT; /* keep PC from being incremented while waiting */
|
|
break;
|
|
case 0x2: /* NOP */
|
|
break;
|
|
case 0x3: /* LCS */
|
|
GPR[reg] = M[0x780 >> 2]; /* get console switches from memory loc 0x780 */
|
|
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 */
|
|
if (GPR[reg+1] & FSIGN) { /* if sign of R+1 is set, incr R by 1 */
|
|
temp++; /* incr temp R value */
|
|
if (temp < GPR[reg]) /* if temp R less than R, we have overflow */
|
|
ovr = 1; /* show we have overflow */
|
|
GPR[reg] = temp; /* update the R 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 */
|
|
}
|
|
break;
|
|
case 0x6: /* BEI */
|
|
if ((modes & PRIVBIT) == 0) { /* must be privileged to BEI */
|
|
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
|
|
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 */
|
|
break;
|
|
case 0x7: /* UEI */
|
|
if ((modes & PRIVBIT) == 0) { /* must be privileged to UEI */
|
|
TRAPME = PRIVVIOL_TRAP; /* set the trap to take */
|
|
goto newpsd; /* Privlege violation trap */
|
|
}
|
|
CPUSTATUS &= ~0x80; /* into status word bit 24 too */
|
|
PSD2 &= ~0x0000c000; /* clear bit 48 & 49 to be unblocked */
|
|
SPAD[0xf5] = PSD2; /* save the current PSD2 */
|
|
irq_pend = 1; /* start scanning interrupts again */
|
|
break;
|
|
case 0x8: /* EAE */
|
|
PSD1 |= AEXPBIT; /* set the enable AEXP flag in PSD */
|
|
CPUSTATUS |= AEXPBIT; /* into status word too */
|
|
break;
|
|
case 0x9: /* RDSTS */
|
|
GPR[reg] = CPUSTATUS; /* get CPU status word */
|
|
break;
|
|
case 0xA: /* SIPU */ /* ignore for now */
|
|
break;
|
|
case 0xB: /* INV */ /* RWCS ignore for now */
|
|
case 0xC: /* INV */ /* WWCS ignore for now */
|
|
break;
|
|
case 0xD: /* SEA */
|
|
modes |= EXTDBIT; /* set new Extended flag in modes & PSD */
|
|
PSD1 |= EXTDBIT; /* set the enable AEXP flag in PSD */
|
|
CPUSTATUS |= EXTDBIT; /* into status word too */
|
|
break;
|
|
case 0xE: /* DAE */
|
|
modes &= AEXPBIT; /* set new extended flag in modes & PSD */
|
|
PSD1 &= ~AEXPBIT; /* disable AEXP flag in PSD */
|
|
CPUSTATUS &= ~AEXPBIT; /* into status word too */
|
|
break;
|
|
|
|
case 0xF: /* CEA */
|
|
modes &= ~EXTDBIT; /* disable extended mode in modes and PSD */
|
|
PSD1 &= ~EXTDBIT; /* disable extended mode flag in PSD */
|
|
CPUSTATUS &= ~EXTDBIT; /* into status word too */
|
|
break;
|
|
}
|
|
break;
|
|
case 0x04>>2: /* 0x04 SCC|RR|R1|SD|HLF - SD|HLF */ /* ANR, SMC, CMC, RPSWT */
|
|
switch(opr & 0xF) {
|
|
case 0x0: /* ANR */
|
|
dest &= source; /* just an and reg to reg */
|
|
i_flags |= SCC; /* make sure we set CC's for dest value */
|
|
break;
|
|
case 0xA: /* CMC */ /* Cache Memory Control - Diag use only */
|
|
/* write reg to cache memory controller */
|
|
break;
|
|
case 0x7: /* SMC */ /* Shared Memory Control Not Used */
|
|
/* write reg to shared memory controller */
|
|
break;
|
|
case 0xB: /* RPSWT */ /* Read Processor Status Word 2 (PSD2) */
|
|
dest = PSD2; /* get PSD2 for user */
|
|
break;
|
|
default: /* INV */ /* everything else is invalid instruction */
|
|
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
|
|
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 */
|
|
if (opr & 0x8) /* is this ORRM op? */
|
|
dest &= GPR[4]; /* mask with reg 4 contents */
|
|
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 */
|
|
if (opr & 0x8) /* is this EORM op? */
|
|
dest &= GPR[4]; /* mask with reg 4 contents */
|
|
break;
|
|
|
|
case 0x10>>2: /* 0x10 HLF - HLF */ /* CAR or (basemode SACZ ) */
|
|
if (modes & BASEBIT) { /* 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 */
|
|
}
|
|
else
|
|
if (temp & BIT0) {
|
|
CC = 0; /* clear CC4 & set count to zero */
|
|
}
|
|
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 */
|
|
} else {
|
|
/* handle non basemode CAR instr */
|
|
temp = GPR[reg] - GPR[sreg]; /* subtract src from destination value */
|
|
set_CCs(temp, ovr); /* set the CC's, CC1 = ovr */
|
|
}
|
|
break;
|
|
|
|
case 0x14>>2: /* 0x14 HLF - HLF */ /* CMR compare masked with reg */
|
|
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 SD|HLF - SD|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 */
|
|
goto newpsd; /* handle trap */
|
|
|
|
} else { /* handle non basemode SBR */
|
|
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 */
|
|
if ((opr & 0x60) == 0x00) /* SRA instruction */
|
|
goto sra; /* use nonbase SRA code */
|
|
if ((opr & 0x60) == 0x20) /* SRL instruction */
|
|
goto srl; /* use nonbase SRL code */
|
|
if ((opr & 0x60) == 0x40) /* SLA instruction */
|
|
goto sla; /* use nonbase SLA code */
|
|
if ((opr & 0x60) == 0x60) /* SLL instruction */
|
|
goto sll; /* use nonbase SLL code */
|
|
} else { /* handle nonbase ZBR */
|
|
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 SRA, SRL, SLA, SLL */
|
|
if ((opr & 0x60) == 0x00) /* SRAD instruction */
|
|
goto sra; /* use nonbase SRAD code */
|
|
if ((opr & 0x60) == 0x20) /* SRLD instruction */
|
|
goto srl; /* use nonbase SRLD code */
|
|
if ((opr & 0x60) == 0x40) /* SLAD instruction */
|
|
goto sla; /* use nonbase SLAD code */
|
|
if ((opr & 0x60) == 0x60) /* SLLD instruction */
|
|
goto sll; /* use nonbase SLLD code */
|
|
} else { /* handle nonbase mode ABR */
|
|
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 */
|
|
ovr = ((temp & FSIGN) != 0); /* set ovr to status of sign bit 0 */
|
|
temp += bc; /* add the bit value to the reg */
|
|
ovr ^= ((temp & FSIGN) != 0); /* set ovr if sign bit changed */
|
|
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 */
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x24>>2: /* 0x24 HLF - HLF */ /* TBR (basemode SRC) */
|
|
if (modes & BASEBIT) { /* handle SRC basemode */
|
|
if ((opr & 0x60) == 0x00) /* SRC instruction */
|
|
goto src; /* use nonbase code */
|
|
if ((opr & 0x60) == 0x40) /* SLC instruction */
|
|
goto slc; /* use nonbase code */
|
|
goto inv; /* else invalid */
|
|
} else { /* handle TBR non basemode */
|
|
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 */
|
|
temp = GPR[reg]; /* get reg value */
|
|
switch(opr & 0xF) {
|
|
|
|
case 0x0: /* TRSW */
|
|
if (modes & BASEBIT)
|
|
addr = temp & MASK24; /* 24 bits for based mode */
|
|
else
|
|
addr = temp & 0x7FFFE; /* 19 bits for non based mode */
|
|
/* we are returning to the addr in reg, set CC's from reg */
|
|
/* update the PSD with new address */
|
|
PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */
|
|
PSD1 = ((PSD1 & 0x87ffffff) | (temp & 0x78000000)); /* insert CCs from reg */
|
|
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 */
|
|
if ((modes & BASEBIT) == 0) /* see if nonbased */
|
|
goto inv; /* invalid instruction in nonbased mode */
|
|
temp = CC >> 27; /* right justify CC's in reg */
|
|
break;
|
|
|
|
case 0x5: /* TRCC */ /* Transfer GPR to condition codes */
|
|
if ((modes & BASEBIT) == 0) /* see if nonbased */
|
|
goto inv; /* invalid instruction in nonbased mode */
|
|
PSD1 = ((PSD1 & 0x87fffffe) | (GPR[reg] << 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-8), this is a BSUB instruction */
|
|
/* otherwise it is a CALL instruction (Rd != 0) */
|
|
if (reg == 0) {
|
|
/* BSUB instruction */
|
|
uint32 fp = 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 */
|
|
}
|
|
M[fp>>2] = (PSD1 + 2) & 0x01fffffe; /* save AEXP bit and PC into frame */
|
|
M[(fp>>2)+1] = 0x80000000; /* show frame created by BSUB instr */
|
|
BR[3] = GPR[0]; /* GPR 0 to BR 3 (AP) */
|
|
BR[0] = BR[2]; /* set frame pointer from BR 2 into BR 0 */
|
|
BR[1] = BR[sreg]; /* Rs reg to BR 1 */
|
|
PSD1 = (PSD1 & 0xff000000) | (BR[sreg] & 0xffffff); /* New PSD address */
|
|
} else {
|
|
/* CALL instruction */
|
|
/* get frame pointer from BR2 - 16 words & make it a dword addr */
|
|
uint32 cfp = ((BR[2]-0x40) & 0xfffffff8);
|
|
M[cfp>>2] = (PSD1 + 2) & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */
|
|
M[(cfp>>2)+1] = 0x00000000; /* show frame created by CALL instr */
|
|
for (ix=0; ix<8; ix++)
|
|
M[(cfp>>2)+ix+2] = BR[ix]; /* save BRs 0-7 to call frame */
|
|
for (ix=2; ix<8; ix++)
|
|
M[(cfp>>2)+ix+10] = GPR[ix]; /* save GPRs 2-7 to call frame */
|
|
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] */
|
|
BR[1] = BR[sreg]; /* Rs reg to BR 1 */
|
|
PSD1 = (PSD1 & 0xff000000) | (BR[sreg] & 0xffffff); /* New PSD address */
|
|
}
|
|
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 0x1: /* INV */
|
|
case 0x3: /* INV */
|
|
case 0x6: /* INV */
|
|
case 0x7: /* INV */
|
|
case 0x9: /* INV */
|
|
case 0xA: /* INV */
|
|
case 0xB: /* INV */
|
|
case 0xD: /* INV */
|
|
case 0xE: /* INV */
|
|
case 0xF: /* INV */
|
|
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 = -addr; /* negate Rs value */
|
|
if (temp == addr) /* overflow if nothing changed */
|
|
ovr = 1; /* set overflow flag */
|
|
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 */
|
|
goto inv;
|
|
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 */
|
|
CPUSTATUS &= 0xfffff0bf; /* zero bits that can change */
|
|
CPUSTATUS |= (temp & 0x0f40); /* or in the new status bits */
|
|
break;
|
|
|
|
case 0xA: /* TMAPR */ /* Transfer map to Reg - Diags only */
|
|
goto inv; /* not used */
|
|
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 = -addr; /* complement GPR[reg] */
|
|
if (temp == addr) /* check for overflow */
|
|
ovr = 1; /* overflow */
|
|
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 */
|
|
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 */
|
|
break;
|
|
|
|
case 0xF: /* TSCR */ /* Transfer scratchpad to register */
|
|
t = (GPR[sreg] >> 16) & 0xff; /* get SPAD address from Rs (9-11) */
|
|
temp = SPAD[t]; /* get SPAD data into Rd (6-8) */
|
|
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 */
|
|
}
|
|
break;
|
|
|
|
/*TODO*/ case 0x30>>2: /* 0x30 */ /* CALM */
|
|
fprintf(stderr, "ERROR - CALM called\r\n");
|
|
goto inv; /* TODO */
|
|
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 */
|
|
dest = (t_uint64)addr; /* just pure 24 bit address */
|
|
} else { /* use bits 13-31 */
|
|
dest = (t_uint64)(addr | ((FC & 4) << 17)); /* F bit to bit 12 */
|
|
}
|
|
break;
|
|
|
|
case 0x38>>2: /* 0x38 HLF - SD|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 = -addr; /* subtract, so negate source */
|
|
temp2 = s_adfw(temp, addr, &CC); /* all add float numbers */
|
|
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 = s_dvfw(temp, addr, &CC); /* divide reg by sreg */
|
|
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 */
|
|
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 */
|
|
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 */
|
|
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 */
|
|
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 */
|
|
dbl = (td < 0); /* double reg is neg remainder */
|
|
if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
|
|
td = -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 */
|
|
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(addr, &CC);
|
|
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 */
|
|
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 */
|
|
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 */
|
|
addr = -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 */
|
|
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 */
|
|
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 */ /* MPR */
|
|
if (reg & 1) {
|
|
/* Spec fault */
|
|
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 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 */
|
|
i_flags |= SD|SCC; /* save regs and set CC's */
|
|
dbl = 1; /* double reg save */
|
|
break;
|
|
|
|
case 0x44>>2: /* 0x44 ADR - ADR */ /* DVR */
|
|
/* sreg has Rs */
|
|
if (reg & 1) {
|
|
/* Spec fault */
|
|
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 doovr3;
|
|
break;
|
|
}
|
|
td = (t_int64)dest % (t_int64)source; /* remainder */
|
|
dbl = (td < 0); /* double reg is neg remainder */
|
|
if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
|
|
td = -td; /* dividend and remainder must be same sign */
|
|
dest = (t_int64)dest / (t_int64)source; /* now do the divide */
|
|
if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) { /* test for overflow */
|
|
doovr3:
|
|
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 0x48>>2: /* 0x48 INV - INV */ /* unused opcodes */
|
|
case 0x4C>>2: /* 0x4C INV - INV */ /* unused opcodes */
|
|
default:
|
|
//fprintf(stderr, "place @ UI op = %.8x\r\n", IR);
|
|
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
|
|
goto newpsd; /* handle trap */
|
|
break;
|
|
|
|
case 0x50>>2: /* 0x50 INV - SD|ADR */ /* LA basemode */
|
|
if ((modes & BASEBIT) == 0) /* see if nonbased */
|
|
goto inv; /* invalid instruction in nonbased mode */
|
|
if (modes & (BASEBIT|EXTDBIT)) {
|
|
dest = (t_uint64)addr; /* just pure 24 bit address */
|
|
} else {
|
|
dest = (t_uint64)(addr | ((FC & 4) << 17)); /* F bit to bit 12 */
|
|
}
|
|
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 */
|
|
dest = BR[reg] - addr; /* subtract addr from the BR and store back to BR */
|
|
} else { /* LABR if F=1 */
|
|
dest = addr; /* addr goes to specified BR */
|
|
}
|
|
break;
|
|
case 0x5C>>2: /* 0x5C RM|SB|ADR - INV */ /* (basemode LWBR and BSUBM) */
|
|
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 */
|
|
}
|
|
if ((FC & 0x4) != 0x4) { /* this is a LWBR instruction */
|
|
BR[reg] = source; /* load memory location in 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 fp = 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 */
|
|
}
|
|
M[fp>>2] = (PSD1+4) & 0x01fffffe; /* save AEXP bit and PC into frame */
|
|
M[(fp>>2)+1] = 0x80000000; /* show frame created by BSUB instr */
|
|
BR[3] = GPR[0]; /* GPR 0 to BR 3 (AP) */
|
|
BR[0] = BR[2]; /* set frame pointer from BR 2 into BR 0 */
|
|
BR[1] = (addr+0x80) & 0xfffffe; /* effective address to BR 1 */
|
|
PSD1 = (PSD1 & 0xff000000) | BR[1]; /* New PSD address */
|
|
} else {
|
|
/* CALM instruction */
|
|
/* get frame pointer from BR2 - 16 words & make it a dword addr */
|
|
uint32 cfp = ((BR[2]-0x40) & 0xfffffff8);
|
|
M[cfp>>2] = (PSD1+4) & 0x01fffffe; /* save AEXP bit and PC from PSD1 in to frame */
|
|
M[(cfp>>2)+1] = 0x00000000; /* show frame created by CALL instr */
|
|
for (ix=0; ix<8; ix++)
|
|
M[(cfp>>2)+ix+2] = BR[ix]; /* save BRs 0-7 to call frame */
|
|
for (ix=2; ix<8; ix++)
|
|
M[(cfp>>2)+ix+10] = GPR[ix];/* save GPRs 2-7 to call frame */
|
|
BR[3] = GPR[reg]; /* Rd to BR 3 (AP) */
|
|
BR[0] = (uint32)cfp; /* set current frame pointer into BR[0] */
|
|
BR[2] = (uint32)cfp; /* set current frame pointer into BR[2] */
|
|
BR[1] = (addr + 0x80) & 0xfffffe; /* effective address to BR 1 */
|
|
PSD1 = (PSD1 & 0xff000000) | BR[1]; /* New PSD address */
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x60>>2: /* 0x60 HLF - INV */ /* NOR Rd,Rs */
|
|
if ((modes & BASEBIT)) { /* only for nonbased mode */
|
|
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
|
|
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] */
|
|
GPR[reg] = s_nor(GPR[reg], &GPR[sreg]);
|
|
break;
|
|
|
|
case 0x64>>2: /* 0x64 SD|HLF - INV */ /* NORD */
|
|
if ((modes & BASEBIT)) { /* only for nonbased mode */
|
|
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
|
|
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 */
|
|
}
|
|
/* shift until upper 5 bits are neither 0 or all 1's */
|
|
/* merge the GPR[reg] & GPR[reg+1] into a 64bit value */
|
|
dest = (((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(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 */
|
|
goto sacz; /* use basemode sacz instruction */
|
|
|
|
case 0x6C>>2: /* 0x6C HLF - INV */ /* non basemode SRA & SLA */
|
|
if (modes & BASEBIT)
|
|
goto inv; /* invalid instruction */
|
|
sra:
|
|
sla:
|
|
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 */
|
|
}
|
|
} 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 */
|
|
sll:
|
|
srl:
|
|
bc = opr & 0x1f; /* get bit shift count */
|
|
temp = GPR[reg]; /* get reg value to shift */
|
|
if (opr & 0x0040) /* is this SLL, bit 9 set */
|
|
temp <<= bc; /* shift left #bits */
|
|
else
|
|
temp >>= bc; /* shift right #bits */
|
|
dest = temp; /* value to be output */
|
|
break;
|
|
|
|
case 0x74>>2: /* 0x74 SD|HLF - INV */ /* non-basemode SRC & SLC */
|
|
if (modes & BASEBIT)
|
|
goto inv; /* invalid instruction in basemode */
|
|
slc:
|
|
src:
|
|
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 */
|
|
}
|
|
}
|
|
dest = 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 */
|
|
}
|
|
} 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);
|
|
if (TRAPME != ALLOK)
|
|
goto newpsd; /* memory read error or map fault */
|
|
/* OS code says F bit is not transferred, so just ignore it */
|
|
// if (FC & 4) /* see if F bit was set */
|
|
// temp |= 0x01000000; /* set bit 7 of address */
|
|
dest = temp; /* put in dest to go out */
|
|
break;
|
|
|
|
case 0x84>>2: /* 0x84 SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* ANMx */
|
|
dest &= source;
|
|
break;
|
|
|
|
case 0x88>>2: /* 0x88 SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* ORMx */
|
|
dest |= source;
|
|
break;
|
|
|
|
case 0x8C>>2: /* 0x8C SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* EOMx */
|
|
dest ^= source;
|
|
break;
|
|
|
|
case 0x90>>2: /* 0x90 SCC|RR|RM|ADR - RM|ADR */ /* CAMx */
|
|
dest -= source;
|
|
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 = (CC & 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 = (CC & 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 */
|
|
ovr = (temp & FSIGN) != 0; /* set ovr to status of sign bit 0 */
|
|
temp += bc; /* add the bit value to the reg */
|
|
ovr ^= (temp & FSIGN) != 0; /* set ovr if sign bit changed */
|
|
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 */
|
|
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 = (CC & 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 */
|
|
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 */
|
|
goto exec; /* go execute the instruction */
|
|
|
|
case 0xAC>>2: /* 0xAC SCC|SD|RM|ADR - SD|RM|ADR */ /* Lx */
|
|
dest = source; /* set value to load into reg */
|
|
break;
|
|
|
|
case 0xB0>>2: /* 0xB0 SCC|SD|RM|ADR - 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 */
|
|
}
|
|
break;
|
|
|
|
case 0xB4>>2: /* 0xB4 SCC|SD|RM|ADR - SD|RM|ADR */ /* LNx */
|
|
dest = -source; /* set the value to load into reg */
|
|
if (dest == source)
|
|
ovr = 1; /* set arithmetic exception status */
|
|
/* 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 0xBC>>2: /* 0xBC SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* SUMx */
|
|
source = -source;
|
|
/* Fall through */
|
|
|
|
case 0xE8>>2: /* 0xE8 SCC|SM|RR|RM|ADR - SM|RM|ADR */ /* ARMx */
|
|
case 0xB8>>2: /* 0xB8 SCC|SD|RR|RM|ADR - SD|RM|ADR */ /* ADMx */
|
|
t = (source & DMSIGN) != 0;
|
|
t |= ((dest & DMSIGN) != 0) ? 2 : 0;
|
|
dest = dest + source;
|
|
if ((t == 3) && ((dest & DMSIGN) == 0)) {
|
|
ovr = 1;
|
|
}
|
|
if ((t == 0) && ((dest & DMSIGN) != 0)) {
|
|
ovr = 1;
|
|
}
|
|
if ((dbl == 0) && ((dest & D32LMASK) != 0) && ((dest & D32LMASK) != D32LMASK)) {
|
|
ovr = 1;
|
|
}
|
|
|
|
/* 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 - 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 */
|
|
}
|
|
dest = (t_uint64)GPR[reg+1]; /* get low order reg value */
|
|
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 */
|
|
}
|
|
dest = (((t_uint64)GPR[reg]) << 32); /* insert upper reg value */
|
|
dest |= (t_uint64)GPR[reg+1]; /* get low order reg value */
|
|
if (source == 0) {
|
|
goto doovr; /* we have div by zero */
|
|
}
|
|
td = ((t_int64)dest % (t_int64)source); /* remainder */
|
|
dbl = (td < 0); /* double reg if neg remainder */
|
|
if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
|
|
td = -td; /* dividend and remainder must be same sign */
|
|
dest = (t_int64)dest / (t_int64)source; /* now do the divide */
|
|
if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) { /* test for overflow */
|
|
doovr:
|
|
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 */
|
|
set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */
|
|
} 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 = -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 */
|
|
}
|
|
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 */
|
|
dbl = (td < 0); /* double reg if neg remainder */
|
|
if (((td & DMSIGN) ^ (dest & DMSIGN)) != 0) /* Fix sign if needed */
|
|
td = -td; /* dividend and remainder must be same sign */
|
|
dest = (t_int64)dest / (t_int64)source; /* now do the divide */
|
|
if ((dest & D32LMASK) != 0 && (dest & D32LMASK) != D32LMASK) { /* test for overflow */
|
|
doovr2:
|
|
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 */
|
|
set_CCs(GPR[reg+1], ovr); /* set the CC's, CC1 = ovr */
|
|
} 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 */
|
|
/* |-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------| */
|
|
/* |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 | N/U | N/U | Aug | SVC Index | 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 */
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
int j;
|
|
char n[9];
|
|
uint32 dqe = M[0x8e8>>2]; /* get DQE of current task */
|
|
for (j=0; j<8; j++) { /* get the task name */
|
|
n[j] = (M[((dqe+0x18)>>2)+(j/4)] >> ((3-(j&7))*8)) & 0xff;
|
|
if (n[j] == 0)
|
|
n[j] = 0x20;
|
|
}
|
|
n[8] = 0;
|
|
#endif
|
|
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 */
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
fprintf(stderr, "SVC @ %.8x SVC %x,%x PSD1 %.8x PSD2 %.8x SPAD PSD@ %x C.CURR %x LMN %s\r\n",
|
|
OPSD1, temp2>>2, IR&0xFFF, PSD1, PSD2, SPAD[0xf5], dqe, n);
|
|
fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]);
|
|
fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]);
|
|
fprintf(stderr, "\r\n");
|
|
if (((temp2>>2) == 1) && ((IR&0xfff) == 0x75))
|
|
fprintf(stderr, "SVC %x,%x GPR[6] %x GPR[6] %x\r\n", temp2>>2, IR&0xfff, GPR[6], GPR[7]);
|
|
#endif
|
|
/* 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 */
|
|
/* 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 */
|
|
goto newpsd; /* new psd loaded */
|
|
}
|
|
break;
|
|
|
|
case 0x7: /* EXR */
|
|
IR = temp; /* get instruction to execute */
|
|
if (addr & 2) /* if bit 30 set, instruction is in right hw, do EXRR */
|
|
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 */
|
|
goto exec;
|
|
break;
|
|
|
|
/* these instruction were never used by MPX, only diags */
|
|
case 0x8: /* SEM */
|
|
case 0x9: /* LEM */
|
|
case 0xA: /* CEMA */
|
|
case 0xB: /* INV */
|
|
case 0xC: /* INV */
|
|
case 0xD: /* INV */
|
|
case 0xE: /* INV */
|
|
case 0xF: /* INV */
|
|
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 */
|
|
}
|
|
bc = addr & 0x20; /* bit 26 initial value */
|
|
while (reg < 8) {
|
|
if (bc != (addr & 0x20)) { /* test for crossing file boundry */
|
|
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
|
|
goto newpsd; /* go execute the trap now */
|
|
}
|
|
if (FC & 0x4) /* LFBR? */
|
|
TRAPME = Mem_read(addr, &BR[reg]); /* read the base reg */
|
|
else /* LF */
|
|
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 */
|
|
dest = (t_uint64)(addr);
|
|
break;
|
|
|
|
case 0xD4>>2: /* 0xD4 SM|ADR - SM|ADR */ /* STx */
|
|
break;
|
|
|
|
case 0xD8>>2: /* 0xD8 SM|ADR - 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 - */ /* INV nonbasemode (STFx basemode) */
|
|
/* DC00 STF */ /* DC08 STFBR */
|
|
if ((FC & 0x4) && (CPU_MODEL <= MODEL_27)) {
|
|
/* basemode undefined for 32/7x & 32/27 */ /* TODO check this */
|
|
TRAPME = UNDEFINSTR_TRAP; /* Undefined Instruction Trap */
|
|
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 */
|
|
while (reg < 8) {
|
|
if (bc != (addr & 0x20)) { /* test for crossing file boundry */
|
|
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 RM|ADR - RM|ADR */ /* ADFx, SUFx */
|
|
if ((FC & 3) != 0) { /* must be word address */
|
|
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
|
|
goto newpsd; /* go execute the trap now */
|
|
}
|
|
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 & 0x0008) { /* 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 */
|
|
}
|
|
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 & 0x0008) { /* Was it ADFD? */
|
|
dest = s_adfd(td, source, &CC); /* do ADFW */
|
|
} else {
|
|
/* s_sufd will negate the memory value before calling add */
|
|
dest = s_sufd(td, source, &CC); /* do SUFD */
|
|
}
|
|
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 RM|ADR - RM|ADR */ /* MPFx, DVFx */
|
|
if ((FC & 3) != 0) { /* must be word address */
|
|
TRAPME = ADDRSPEC_TRAP; /* bad reg address, error */
|
|
goto newpsd; /* go execute the trap now */
|
|
}
|
|
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 & 0xf) == 0x8) { /* Was it MPFW? */
|
|
temp = s_mpfw(temp2, addr, &CC); /* do MPFW */
|
|
} else {
|
|
temp = s_dvfw(temp2, addr, &CC); /* do DVFW */
|
|
}
|
|
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 & 0xf) == 0x8) { /* Was it MPFD? */
|
|
dest = s_mpfd(td, source, &CC); /* do MPFD */
|
|
} else {
|
|
dest = s_sufd(td, source, &CC); /* do DVFD */
|
|
}
|
|
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 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 */
|
|
if (IR & IND) /* see if CCs from last indirect are wanted */
|
|
PSD1 = (PSD1 & 0x87fffffe) | temp2; /* insert last indirect CCs */
|
|
/* update the PSD with new address */
|
|
PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */
|
|
i_flags |= BT; /* we branched, so no PC update */
|
|
}
|
|
/* branch not taken, go do next instruction */
|
|
break;
|
|
|
|
case 0xF0>>2: /* 0xF0 ADR - ADR */ /* Branch False or Branch Function 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 = (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 (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 0xF4>>2: /* 0xF4 RR|SD|ADR - RR|SB|WRD */ /* Branch increment */
|
|
dest += 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 1 /* set to 1 to stop branch to self, for now */
|
|
/* FIXME */ if (PC == (addr & 0x7FFFC)) { /* BIB to current PC, bump branch addr */
|
|
addr += 4;
|
|
// fprintf(stderr, "BI? stopping BIB $ addr %x PC %x\r\n", addr, PC);
|
|
}
|
|
#endif
|
|
PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe); /* set new PC */
|
|
if (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 & 0x78000000) | (PSD1 & 0x7fffe)) + 4;
|
|
if (IR & IND) /* see if CC from last indirect are wanted */
|
|
GPR[0] = (GPR[0] & 0x87fffffe) | CC; /* insert last CCs */
|
|
/* update the PSD with new address */
|
|
PSD1 = (PSD1 & 0xff000000) | (addr & 0xfffffe);
|
|
i_flags |= BT; /* we branched, so no PC update */
|
|
break;
|
|
|
|
case 0x3: /* LPSD F980 */
|
|
/* fall through */;
|
|
case 0x5: /* LPSDCM FA80 */
|
|
{
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
int j;
|
|
char n[9];
|
|
uint32 dqe = M[0x8e8>>2];
|
|
/* get task name blank filled */
|
|
for (j=0; j<8; j++) {
|
|
n[j] = (M[((dqe+0x18)>>2)+(j/4)] >> ((3-(j&7))*8)) & 0xff;
|
|
if (n[j] == 0)
|
|
n[j] = 0x20;
|
|
}
|
|
n[8] = 0;
|
|
#endif
|
|
CPUSTATUS |= 0x40; /* enable software traps */
|
|
/* this will allow attn and */
|
|
/* power fail traps */
|
|
if ((TRAPME = Mem_read(addr, &PSD1))) { /* get PSD1 from memory */
|
|
goto newpsd; /* memory read error or map fault */
|
|
}
|
|
if ((TRAPME = Mem_read(addr+4, &PSD2))) { /* get PSD2 from memory */
|
|
goto newpsd; /* memory read error or map fault */
|
|
}
|
|
/* 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 */
|
|
/* 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) {
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
// FIXME DEBUG EDIT
|
|
// if (n[0] == 'E' && n[1] == 'D' && n[2] == 'I' && n[3] == 'T')
|
|
// FIXME DEBUG SYSGEN
|
|
//if (n[0] == 'S' && n[1] == 'Y' && n[2] == 'S' && n[3] == 'G')
|
|
// traceme = trstart; /* start tracing */
|
|
traceme++; /* start trace */
|
|
//if (traceme >= trstart) {
|
|
fprintf(stderr, "LPSDCM #%d LOAD MAPS PSD1 %x PSD2 %x SPAD PSD2 %x CPUSTATUS %x C.CURR %x LMN %s\r\n", traceme, PSD1, PSD2, SPAD[0xf5], CPUSTATUS, dqe, n);
|
|
fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]);
|
|
fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]);
|
|
fprintf(stderr, "\r\n");
|
|
//reason = STOP_HALT; /* do halt for now */
|
|
//}
|
|
#endif
|
|
/* set mapped mode in cpu status */
|
|
CPUSTATUS |= 0x00800000; /* set bit 8 of cpu status */
|
|
/* we need to load the new maps */
|
|
TRAPME = load_maps(&PSD1); /* load maps for new PSD */
|
|
PSD2 &= ~RETMBIT; /* turn off retain bit in PSD2 */
|
|
SPAD[0xf5] = PSD2; /* save the current PSD2 */
|
|
sim_debug(DEBUG_EXP, &cpu_dev,
|
|
"LPSDCM MAPS LOADED TRAPME = %x PSD1 %x PSD2 %x CPUSTATUS %x\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 */
|
|
}
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "LPSD PSD1 %x PSD2 %x CPUSTATUS %x\n", PSD1, PSD2, CPUSTATUS);
|
|
//if (traceme >= trstart) {
|
|
fprintf(stderr, "LPSD PSD1 %x PSD2 %x SPAD PSD2 %x CPUSTATUS %x C.CURR %x LMN %s\r\n",
|
|
PSD1, PSD2, SPAD[0xf5], CPUSTATUS, dqe, n);
|
|
fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]);
|
|
fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]);
|
|
fprintf(stderr, "\r\n");
|
|
//}
|
|
#endif
|
|
}
|
|
}
|
|
/* TRAPME can be error from LPSDCM or OK here */
|
|
skipinstr = 1; /* skip next interrupt test only once */
|
|
goto newpsd; /* load the new psd */
|
|
break;
|
|
|
|
case 0x4: /* JWCS */ /* not used in simulator */
|
|
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 */
|
|
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 */
|
|
TRAPSTATUS |= 0x1000; /* set Bit 19 of Trap Status word */
|
|
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 */
|
|
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 */
|
|
|
|
switch(opr & 0x7) { /* use bits 13-15 to determine instruction */
|
|
case 0x0: /* EI FC00 Enable Interrupt */
|
|
prior = (opr >> 3) & 0x7f; /* get priority level */
|
|
/* 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, die */
|
|
goto syscheck; /* system check */
|
|
INTS[prior] |= INTS_ENAB; /* enable specified int level */
|
|
SPAD[prior+0x80] |= SINT_ENAB; /* enable in SPAD too */
|
|
irq_pend = 1; /* start scanning interrupts again */
|
|
if (prior == 0x18) /* is this the clock starting */
|
|
rtc_setup(1, prior); /* tell clock to start */
|
|
if (prior == 0x5f) /* is this the initerval timer starting */
|
|
itm_setup(1, prior); /* tell timer to start */
|
|
break;
|
|
|
|
case 0x1: /* DI FC01 */
|
|
prior = (opr >> 3) & 0x7f; /* get priority level */
|
|
/* 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, die */
|
|
goto syscheck; /* system check */
|
|
INTS[prior] &= ~INTS_ENAB; /* disable specified int level */
|
|
INTS[prior] &= ~INTS_REQ; /* clears any requests also */
|
|
SPAD[prior+0x80] &= ~SINT_ENAB; /* disable in SPAD too */
|
|
if (prior == 0x18) /* is this the clock stopping */
|
|
rtc_setup(0, prior); /* tell clock to stop */
|
|
if (prior == 0x5f) /* is this the initerval timer stopping */
|
|
itm_setup(0, prior); /* tell timer to stop */
|
|
break;
|
|
|
|
case 0x2: /* RI FC02 */
|
|
prior = (opr >> 3) & 0x7f; /* get priority level */
|
|
/* 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, die */
|
|
goto syscheck; /* system check */
|
|
INTS[prior] |= INTS_REQ; /* set the request flag for this level */
|
|
irq_pend = 1; /* start scanning interrupts again */
|
|
break;
|
|
|
|
case 0x3: /* AI FC03 */
|
|
prior = (opr >> 3) & 0x7f; /* get priority level */
|
|
/* 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, die */
|
|
goto syscheck; /* system check */
|
|
INTS[prior] |= INTS_ACT; /* activate specified int level */
|
|
break;
|
|
|
|
case 0x4: /* DAI FC04 */
|
|
prior = (opr >> 3) & 0x7f; /* get priority level */
|
|
/* 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, die */
|
|
goto syscheck; /* system check */
|
|
INTS[prior] &= ~INTS_ACT; /* deactivate specified int level */
|
|
SPAD[prior+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */
|
|
irq_pend = 1; /* start scanning interrupts again */
|
|
skipinstr = 1; /* skip interrupt test */
|
|
/* instruction following a DAI can not be interrupted */
|
|
/* skip tests for interrupts if this is the case */
|
|
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 */
|
|
/* 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 {
|
|
/* 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 */
|
|
//fprintf(stderr, "XIO1 chan %8x intr %8x spad %.8x\r\n", chan, ix, bc);
|
|
ix = 127 - ix; /* get positive number for interrupt */
|
|
//fprintf(stderr, "XIO2 chan %x intr %x spad %.8x\r\n", chan, ix, bc);
|
|
temp = (IR & 0x7f); /* get cmd from instruction */
|
|
if (device == 0x7f) {
|
|
//fprintf(stderr, "Interval Timer CD call cmd %x GPR[0] %x intr %x\r\n", temp, GPR[0], ix);
|
|
status = itm_rdwr(temp, GPR[0], ix); /* read/write the interval timer */
|
|
//fprintf(stderr, "Interval Timer CD return status %x cmd %x GPR[0] %x intr %x\r\n", status, temp, GPR[0], ix);
|
|
if (temp != 0x39) /* this cmd does not return value */
|
|
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, die */
|
|
goto syscheck; /* machine check */
|
|
/* sim_debug(DEBUG_EXP, &cpu_dev, "$$ XIO lchan %x sa %x spad %.8x\n", lchan, suba, t); */
|
|
if ((t & 0x0f000000) != 0x0f000000) { /* class in bits 4-7 */
|
|
mcheck:
|
|
TRAPME = MACHINECHK_TRAP; /* trap condition */
|
|
TRAPSTATUS |= BIT0; /* class F error bit */
|
|
TRAPSTATUS &= ~BIT1; /* I/O processing error */
|
|
goto newpsd; /* machine check trap */
|
|
}
|
|
/* 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 */
|
|
addr = SPAD[0xf1] + (ix<<2); /* vector address in SPAD */
|
|
addr = M[addr>>2]; /* get the interrupt context block addr */
|
|
/* the context block contains the old PSD, */
|
|
/* new PSD, IOCL address, and I/O status address */
|
|
if (addr == 0) /* 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 */
|
|
|
|
//fprintf(stderr, "XIO ready chan %x intr %x icb %x iocla %x iocd1 %.8x iocd2 %0.x8\r\n",
|
|
// chan, ix, addr, addr+16, M[temp>>2], M[(temp+4)>>2]);
|
|
//sim_debug(DEBUG_EXP, &cpu_dev, "XIO ready chan %x intr %x icb %x iocla %x iocd1 %.8x iocd2 %.8x\n",
|
|
// 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 */
|
|
//fprintf(stderr, "XIO switch %x lchan %x chan %x intr %x chsa %x IOCDa %x\r\n", ((opr>>3)&0xf), lchan, chan, ix, (chan<<8)|suba, temp);
|
|
//sim_debug(DEBUG_EXP, &cpu_dev, "XIO switch chan %x intr %x chsa %x IOCDa %.8x\n", 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 */
|
|
goto newpsd; /* undefined instruction trap */
|
|
break;
|
|
|
|
case 0x09: /* Enable write channel ECWCS */
|
|
case 0x0B: /* Write channel WCS WCWCS */
|
|
/* for now or maybe forever, return unsupported transaction */
|
|
PSD1 = ((PSD1 & 0x87fffffe) | (CC2BIT|CC4BIT)); /* insert status 5 */
|
|
TRAPME = UNDEFINSTR_TRAP; /* trap condition */
|
|
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_EXP, &cpu_dev, "XIO SIO ret chan %x chsa %x status %x\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)))
|
|
goto newpsd; /* error returned, trap cpu */
|
|
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "XIO TIO ret chan %x chsa %x status %x\n",
|
|
chan, (chan<<8)|suba, status);
|
|
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 */
|
|
/* SPAD entries for interrupts begin at 0x80 */
|
|
/* 07-16-18 chg */ INTS[ix] &= ~INTS_REQ; /* clears any requests also */
|
|
INTS[ix] &= ~INTS_ACT; /* deactivate specified int level */
|
|
SPAD[ix+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */
|
|
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "XIO STPIO ret chan %x chsa %x status %x\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 */
|
|
if ((TRAPME = rschnlxio(chsa, &status)))
|
|
goto newpsd; /* error returned, trap cpu */
|
|
PSD1 = ((PSD1 & 0x87fffffe) | (status & 0x78000000)); /* insert status */
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "XIO RSCHNL ret chan %x chsa %x status %x\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_EXP, &cpu_dev, "HIO HALTXIO ret chan %x chsa %x status %x\n",
|
|
chan, (chan<<8)|suba, status);
|
|
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_EXP, &cpu_dev, "XIO GRIO ret chan %x chsa %x status %x\n",
|
|
chan, (chan<<8)|suba, status);
|
|
break;
|
|
|
|
case 0x08: /* Reset controller RSCTL */
|
|
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_EXP, &cpu_dev, "XIO RSCTL ret chan %x chsa %x status %x\n",
|
|
chan, (chan<<8)|suba, status);
|
|
break;
|
|
|
|
/* TODO Finish XIO interrupts */
|
|
case 0x0C: /* Enable channel interrupt ECI */
|
|
chsa = temp2 & 0x7FFF; /* get logical device address */
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "XIO ECI chan %x sa %x spad %.8x\n", chan, suba, t);
|
|
/* SPAD entries for interrupts begin at 0x80 */
|
|
INTS[ix] |= INTS_ENAB; /* enable specified int level */
|
|
SPAD[ix+0x80] |= SINT_ENAB; /* enable in SPAD too */
|
|
INTS[ix] &= ~INTS_REQ; /* clears any requests also TRY 06-09-18 */
|
|
//TRY 06-09-18 irq_pend = 1; /* start scanning interrupts again */
|
|
break;
|
|
|
|
case 0x0D: /* Disable channel interrupt DCI */
|
|
chsa = temp2 & 0x7FFF; /* get logical device address */
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "XIO DCI chan %x sa %x spad %.8x\n", chan, suba, t);
|
|
/* SPAD entries for interrupts begin at 0x80 */
|
|
INTS[ix] &= ~INTS_ENAB; /* disable specified int level */
|
|
INTS[ix] &= ~INTS_REQ; /* clears any requests also */
|
|
SPAD[ix+0x80] &= ~SINT_ENAB; /* disable in SPAD too */
|
|
break;
|
|
|
|
case 0x0E: /* Activate channel interrupt ACI */
|
|
chsa = temp2 & 0x7FFF; /* get logical device address */
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "XIO ACI chan %x sa %x spad %.8x\n", chan, suba, t);
|
|
/* SPAD entries for interrupts begin at 0x80 */
|
|
INTS[ix] |= INTS_ACT; /* activate specified int level */
|
|
break;
|
|
|
|
case 0x0F: /* Deactivate channel interrupt DACI */
|
|
/* Note, instruction following DACI is not interruptable */
|
|
chsa = temp2 & 0x7FFF; /* get logical device address */
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "XIO DACI chan %x sa %x spad %.8x\n", chan, suba, t);
|
|
/* SPAD entries for interrupts begin at 0x80 */
|
|
/* 07-16-18 chg */ INTS[ix] &= ~INTS_REQ; /* clears any requests also */
|
|
INTS[ix] &= ~INTS_ACT; /* deactivate specified int level */
|
|
SPAD[ix+0x80] &= ~SINT_ACT; /* deactivate in SPAD too */
|
|
irq_pend = 1; /* start scanning interrupts again */
|
|
skipinstr = 1; /* skip interrupt test */
|
|
/* NOTE CC must be returned */
|
|
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 */
|
|
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 & 2) != 2) {
|
|
TRAPME = ADDRSPEC_TRAP; /* address not on dbl wd boundry, error */
|
|
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 */
|
|
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 */
|
|
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 */
|
|
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 ((t_int64)dest < 0) /* is it neg */
|
|
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 */
|
|
}
|
|
|
|
/* Update instruction pointer to next instruction */
|
|
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 & BT) == 0) { /* see if PSD was replaced on a branch instruction */
|
|
/* branch not taken, so update the PC */
|
|
if (i_flags & HLF) {
|
|
PSD1 = (PSD1 + 2) | (((PSD1 & 2) >> 1) & 1);
|
|
} else {
|
|
PSD1 = (PSD1 + 4) | (((PSD1 & 2) >> 1) & 1);
|
|
}
|
|
}
|
|
|
|
/* 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 */
|
|
}
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
/* no trap, so continue with next instruction */
|
|
if (traceme >= trstart) {
|
|
OPSD1 &= 0x87FFFFFE; /* clear the old CC's */
|
|
OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */
|
|
if (modes & MAPMODE)
|
|
fprintf(stderr, "M%.8x %.8x ", OPSD1, OIR);
|
|
else
|
|
fprintf(stderr, "U%.8x %.8x ", OPSD1, OIR);
|
|
fprint_inst(stderr, OIR, 0); /* display instruction */
|
|
fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]);
|
|
fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]);
|
|
fprintf(stderr, "\r\n");
|
|
}
|
|
#endif
|
|
sim_debug(DEBUG_DATA, &cpu_dev, "R0=%08x R1=%08x R2=%08x R3=%08x\n", GPR[0], GPR[1], GPR[2], GPR[3]);
|
|
sim_debug(DEBUG_DATA, &cpu_dev, "R4=%08x R5=%08x R6=%08x R7=%08x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
|
|
continue; /* keep running */
|
|
// break; /* quit for now after each instruction */
|
|
|
|
newpsd:
|
|
/* we get here from a LPSD, LPSDCM, INTR, or TRAP */
|
|
if (TRAPME) {
|
|
/* 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 power fail trap */
|
|
case POWERON_TRAP: /* 0x84 Power-On trap */
|
|
case MEMPARITY_TRAP: /* 0x88 Memory Parity Error trap */
|
|
case NONPRESMEM_TRAP: /* 0x8C Non Present Memory trap */
|
|
case UNDEFINSTR_TRAP: /* 0x90 Undefined Instruction Trap */
|
|
case PRIVVIOL_TRAP: /* 0x94 Privlege Violation Trap */
|
|
//TODO case SVCCALL_TRAP: /* 0x98 Supervisor Call Trap */
|
|
case MACHINECHK_TRAP: /* 0x9C Machine Check Trap */
|
|
case SYSTEMCHK_TRAP: /* 0xA0 System Check Trap */
|
|
case MAPFAULT_TRAP: /* 0xA4 Map Fault Trap */
|
|
case IPUUNDEFI_TRAP: /* 0xA8 IPU Undefined Instruction Trap */
|
|
case SIGNALIPU_TRAP: /* 0xAC Signal IPU/CPU Trap */
|
|
case ADDRSPEC_TRAP: /* 0xB0 Address Specification Trap */
|
|
case CONSOLEATN_TRAP: /* 0xB4 Console Attention Trap */
|
|
case PRIVHALT_TRAP: /* 0xB8 Privlege Mode Halt Trap */
|
|
case AEXPCEPT_TRAP: /* 0xBC Arithmetic Exception Trap */
|
|
default:
|
|
tta = tta + (TRAPME - 0x80); /* tta has mem addr of trap vector */
|
|
tvl = M[tta>>2] & 0x7FFFC; /* get trap vector address from trap vector loc */
|
|
//fprintf(stderr, "tvl %.8x, tta %.8x status %.8x\r\n", tvl, tta, CPUSTATUS);
|
|
if (tvl == 0 || tvl == 0x7FFFC || (CPUSTATUS & 0x40) == 0) {
|
|
/* vector is zero or software has not enabled traps yet */
|
|
/* execute a trap halt */
|
|
/* set the PSD to trap vector location */
|
|
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 */
|
|
fprintf(stderr, "[][][][][][][][][][][] HALT TRAP [][][][][][][][][][][][]\r\n");
|
|
fprintf(stderr, "PSD1 %.8x PSD2 %.8x TRAPME %.4x\r\n", PSD1, PSD2, TRAPME);
|
|
for (ix=0; ix<8; ix+=2) {
|
|
fprintf(stderr, "GPR[%d] %.8x GPR[%d] %.8x\r\n", ix, GPR[ix], ix+1, GPR[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 */
|
|
M[tvl>>2] = PSD1 & 0xfffffffe; /* 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 */
|
|
|
|
/* 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 */
|
|
/* 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 */
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
//if (TRAPME == UNDEFINSTR_TRAP || TRAPME == MAPFAULT_TRAP) {
|
|
if (TRAPME == MAPFAULT_TRAP) {
|
|
sim_debug(DEBUG_EXP, &cpu_dev, "TRAP PSD1 %x PSD2 %x CPUSTATUS %x\n", PSD1, PSD2, CPUSTATUS);
|
|
fprintf(stderr, "TRAPS %x LOAD MAPS PSD1 %x PSD2 %x CPUSTATUS %x\r\n", TRAPME, PSD1, PSD2, CPUSTATUS);
|
|
goto dumpi;
|
|
}
|
|
#endif
|
|
break; /* Go execute the trap */
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
skipinstr = 1; /* skip next instruction */
|
|
/* we have a new PSD loaded via a LPSD or LPSDCM */
|
|
/* TODO finish instruction history, then continue */
|
|
/* update cpu status word too */
|
|
#ifdef TRME /* set to 1 for traceme to work */
|
|
if (traceme >= trstart) {
|
|
dumpi:
|
|
OPSD1 &= 0x87FFFFFE; /* clear the old CC's */
|
|
OPSD1 |= PSD1 & 0x78000000; /* update the CC's in the PSD */
|
|
if (modes & MAPMODE)
|
|
fprintf(stderr, "M%.8x %.8x ", OPSD1, OIR);
|
|
else
|
|
fprintf(stderr, "U%.8x %.8x ", OPSD1, OIR);
|
|
fprint_inst(stderr, OIR, 0); /* display instruction */
|
|
fprintf(stderr, " R0=%x R1=%x R2=%x R3=%x", GPR[0], GPR[1], GPR[2], GPR[3]);
|
|
fprintf(stderr, " R4=%x R5=%x R6=%x R7=%x", GPR[4], GPR[5], GPR[6], GPR[7]);
|
|
fprintf(stderr, "\r\n");
|
|
fprintf(stderr, "Current MAPC\r\n");
|
|
for (ix=0; ix<16; ix++) {
|
|
fprintf(stderr, "MAP %x MPC %x\r\n", ix/2, MAPC[ix]);
|
|
}
|
|
fflush(stderr);
|
|
//if (TRAPME == UNDEFINSTR_TRAP || TRAPME == MAPFAULT_TRAP)
|
|
if (TRAPME == MAPFAULT_TRAP)
|
|
return STOP_HALT; /* exit to simh for halt */
|
|
}
|
|
#endif
|
|
sim_debug(DEBUG_DATA, &cpu_dev, "R0=%08x R1=%08x R2=%08x R3=%08x\n", GPR[0], GPR[1], GPR[2], GPR[3]);
|
|
sim_debug(DEBUG_DATA, &cpu_dev, "R4=%08x R5=%08x R6=%08x R7=%08x\n", GPR[4], GPR[5], GPR[6], GPR[7]);
|
|
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 */
|
|
|
|
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] = 0; /* clear the registers */
|
|
BR[i] = 0; /* clear the registers */
|
|
}
|
|
/* 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 ??) */
|
|
SPAD[0xf7] = 0; /* make sure key is zero */
|
|
SPAD[0xf8] = 0x0000f000; /* set DRT to class f (anything else is E) */
|
|
SPAD[0xf9] = CPU_MODEL; /* 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 */
|
|
/* address is byte address with bits 30,31 = 0 */
|
|
t_stat cpu_ex(t_value *vptr, t_addr baddr, UNIT *uptr, int32 sw)
|
|
{
|
|
uint32 temp, t;
|
|
uint32 addr = (baddr & 0xfffffc) >> 2; /* make 24 bit byte address into word address */
|
|
|
|
/* 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]; /* return memory contents */
|
|
return SCPE_OK; /* we are all ok */
|
|
}
|
|
|
|
/* Memory deposit */
|
|
/* modify 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 */
|
|
|
|
/* MSIZE is in 32 bit words */
|
|
if (addr >= MEMSIZE) /* see if address is within our memory */
|
|
return SCPE_NXM; /* no, none existant memory error */
|
|
M[addr] = val; /* set the new data value */
|
|
return SCPE_OK; /* all OK */
|
|
}
|
|
|
|
/* set the CPU memory size */
|
|
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;
|
|
cpu_unit.flags |= val; /* set new memory size */
|
|
val >>= UNIT_V_MSIZE; /* set size in 32bit words */
|
|
val = (val + 1) * 128 * 1024; /* KW's */
|
|
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 */
|
|
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].psd1 = 0; /* just psd1 for now */
|
|
hst_p = 0; /* start at teh 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 */
|
|
fprintf(st, "PSD1 PSD2 INST DEST SRC CC\n");
|
|
for (k = 0; k < lnt; k++) { /* print specified entries */
|
|
h = &hst[(++di) % hst_lnt]; /* entry pointer */
|
|
/* display the instruction and results */
|
|
fprintf(st, "%08x %08x %08x %08x %08x %1x",
|
|
h->psd1, h->psd2, h->inst, h->dest, h->src, h->cc);
|
|
fputc('\n', st); /* end line */
|
|
} /* 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 be set to \n");
|
|
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;
|
|
}
|