mirror of
https://github.com/simh/simh.git
synced 2026-01-11 23:52:58 +00:00
simh Alpha CPU
This commit is contained in:
parent
15919a2dd7
commit
5c173cdd67
49
Alpha/alpha_500au_syslist.c
Normal file
49
Alpha/alpha_500au_syslist.c
Normal file
@ -0,0 +1,49 @@
|
||||
/* alpha_500au_syslist.c: Alpha device list for 500au
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern DEVICE tlb_dev;
|
||||
extern DEVICE ev5pal_dev;
|
||||
extern DEVICE rom_dev;
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name
|
||||
sim_devices array of pointers to simulated devices
|
||||
*/
|
||||
|
||||
char sim_name[] = "Alpha";
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&tlb_dev,
|
||||
&ev5pal_dev,
|
||||
&rom_dev,
|
||||
NULL
|
||||
};
|
||||
|
||||
1867
Alpha/alpha_cpu.c
Normal file
1867
Alpha/alpha_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
457
Alpha/alpha_defs.h
Normal file
457
Alpha/alpha_defs.h
Normal file
@ -0,0 +1,457 @@
|
||||
/* alpha_defs.h: Alpha architecture definitions file
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
Respectfully dedicated to the great people of the Alpha chip, systems, and
|
||||
software development projects; and to the memory of Peter Conklin, of the
|
||||
Alpha Program Office.
|
||||
*/
|
||||
|
||||
#ifndef _ALPHA_DEFS_H_
|
||||
#define _ALPHA_DEFS_H_ 0
|
||||
|
||||
#include "sim_defs.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
#if defined (__GNUC__)
|
||||
#define INLINE inline
|
||||
#else
|
||||
#define INLINE
|
||||
#endif
|
||||
|
||||
/* Configuration */
|
||||
|
||||
#define INITMEMSIZE (1 << 24) /* !!debug!! */
|
||||
#define MEMSIZE (cpu_unit.capac)
|
||||
#define ADDR_IS_MEM(x) ((x) < MEMSIZE)
|
||||
#define DEV_DIB (1u << (DEV_V_UF + 0)) /* takes a DIB */
|
||||
|
||||
/* Simulator stops */
|
||||
|
||||
#define STOP_HALT 1 /* halt */
|
||||
#define STOP_IBKPT 2 /* breakpoint */
|
||||
#define STOP_NSPAL 3 /* non-supported PAL */
|
||||
#define STOP_KSNV 4 /* kernel stk inval */
|
||||
#define STOP_INVABO 5 /* invalid abort code */
|
||||
#define STOP_MME 6 /* console mem mgt error */
|
||||
|
||||
/* Bit patterns */
|
||||
|
||||
#define M8 0xFF
|
||||
#define M16 0xFFFF
|
||||
#define M32 0xFFFFFFFF
|
||||
#define M64 0xFFFFFFFFFFFFFFFF
|
||||
#define B_SIGN 0x80
|
||||
#define W_SIGN 0x8000
|
||||
#define L_SIGN 0x80000000
|
||||
#define Q_SIGN 0x8000000000000000
|
||||
#define Q_GETSIGN(x) (((uint32) ((x) >> 63)) & 1)
|
||||
|
||||
/* Architectural variants */
|
||||
|
||||
#define AMASK_BWX 0x0001 /* byte/word */
|
||||
#define AMASK_FIX 0x0002 /* sqrt/flt-int moves */
|
||||
#define AMASK_CIX 0x0004 /* counts */
|
||||
#define AMASK_MVI 0x0100 /* multimedia */
|
||||
#define AMASK_PRC 0x0200 /* precise exceptions */
|
||||
#define AMASK_PFM 0x1000 /* prefetch w modify */
|
||||
|
||||
#define IMPLV_EV4 0x0 /* EV4 (21064) */
|
||||
#define IMPLV_EV5 0x1 /* EV5 (21164) */
|
||||
#define IMPLV_EV6 0x2 /* EV6 (21264) */
|
||||
#define IMPLV_EV7 0x3 /* EV7 (21364) */
|
||||
|
||||
/* Instruction formats */
|
||||
|
||||
#define I_V_OP 26 /* opcode */
|
||||
#define I_M_OP 0x3F
|
||||
#define I_OP (I_M_OP << I_V_OP)
|
||||
#define I_V_RA 21 /* Ra */
|
||||
#define I_M_RA 0x1F
|
||||
#define I_V_RB 16 /* Rb */
|
||||
#define I_M_RB 0x1F
|
||||
#define I_V_FTRP 13 /* floating trap mode */
|
||||
#define I_M_FTRP 0x7
|
||||
#define I_FTRP (I_M_FTRP << I_V_FTRP)
|
||||
#define I_F_VAXRSV 0x4800 /* VAX reserved */
|
||||
#define I_FTRP_V 0x2000 /* /V trap */
|
||||
#define I_FTRP_U 0x2000 /* /U trap */
|
||||
#define I_FTRP_S 0x8000 /* /S trap */
|
||||
#define I_FTRP_SUI 0xE000 /* /SUI trap */
|
||||
#define I_FTRP_SVI 0xE000 /* /SVI trap */
|
||||
#define I_V_FRND 11 /* floating round mode */
|
||||
#define I_M_FRND 0x3
|
||||
#define I_FRND (I_M_FRND << I_V_FRND)
|
||||
#define I_FRND_C 0 /* chopped */
|
||||
#define I_FRND_M 1 /* to minus inf */
|
||||
#define I_FRND_N 2 /* normal */
|
||||
#define I_FRND_D 3 /* dynamic */
|
||||
#define I_FRND_P 3 /* in FPCR: plus inf */
|
||||
#define I_V_FSRC 9 /* floating source */
|
||||
#define I_M_FSRC 0x3
|
||||
#define I_FSRC (I_M_FSRC << I_V_FSRC)
|
||||
#define I_FSRC_X 0x0200 /* data type X */
|
||||
#define I_V_FFNC 5 /* floating function */
|
||||
#define I_M_FFNC 0x3F
|
||||
#define I_V_LIT8 13 /* integer 8b literal */
|
||||
#define I_M_LIT8 0xFF
|
||||
#define I_V_ILIT 12 /* literal flag */
|
||||
#define I_ILIT (1u << I_V_ILIT)
|
||||
#define I_V_IFNC 5 /* integer function */
|
||||
#define I_M_IFNC 0x3F
|
||||
#define I_V_RC 0 /* Rc */
|
||||
#define I_M_RC 0x1F
|
||||
#define I_V_MDSP 0 /* memory displacement */
|
||||
#define I_M_MDSP 0xFFFF
|
||||
#define I_V_BDSP 0
|
||||
#define I_M_BDSP 0x1FFFFF /* branch displacement */
|
||||
#define I_V_PALOP 0
|
||||
#define I_M_PALOP 0x3FFFFFF /* PAL subopcode */
|
||||
#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP)
|
||||
#define I_GETRA(x) (((x) >> I_V_RA) & I_M_RA)
|
||||
#define I_GETRB(x) (((x) >> I_V_RB) & I_M_RB)
|
||||
#define I_GETLIT8(x) (((x) >> I_V_LIT8) & I_M_LIT8)
|
||||
#define I_GETIFNC(x) (((x) >> I_V_IFNC) & I_M_IFNC)
|
||||
#define I_GETFRND(x) (((x) >> I_V_FRND) & I_M_FRND)
|
||||
#define I_GETFFNC(x) (((x) >> I_V_FFNC) & I_M_FFNC)
|
||||
#define I_GETRC(x) (((x) >> I_V_RC) & I_M_RC)
|
||||
#define I_GETMDSP(x) (((x) >> I_V_MDSP) & I_M_MDSP)
|
||||
#define I_GETBDSP(x) (((x) >> I_V_BDSP) & I_M_BDSP)
|
||||
#define I_GETPAL(x) (((x) >> I_V_PALOP) & I_M_PALOP)
|
||||
|
||||
/* Floating point types */
|
||||
|
||||
#define DT_F 0 /* type F */
|
||||
#define DT_G 1 /* type G */
|
||||
#define DT_S 0 /* type S */
|
||||
#define DT_T 1 /* type T */
|
||||
|
||||
/* Floating point memory format (VAX F) */
|
||||
|
||||
#define F_V_SIGN 15
|
||||
#define F_SIGN (1u << F_V_SIGN)
|
||||
#define F_V_EXP 7
|
||||
#define F_M_EXP 0xFF
|
||||
#define F_BIAS 0x80
|
||||
#define F_EXP (F_M_EXP << F_V_EXP)
|
||||
#define F_V_FRAC 29
|
||||
#define F_GETEXP(x) ((uint32) (((x) >> F_V_EXP) & F_M_EXP))
|
||||
#define SWAP_VAXF(x) ((((x) >> 16) & 0xFFFF) | (((x) & 0xFFFF) << 16))
|
||||
|
||||
/* Floating point memory format (VAX G) */
|
||||
|
||||
#define G_V_SIGN 15
|
||||
#define G_SIGN (1u << F_V_SIGN)
|
||||
#define G_V_EXP 4
|
||||
#define G_M_EXP 0x7FF
|
||||
#define G_BIAS 0x400
|
||||
#define G_EXP (G_M_EXP << G_V_EXP)
|
||||
#define G_GETEXP(x) ((uint32) (((x) >> G_V_EXP) & G_M_EXP))
|
||||
#define SWAP_VAXG(x) ((((x) & 0x000000000000FFFF) << 48) | \
|
||||
(((x) & 0x00000000FFFF0000) << 16) | \
|
||||
(((x) >> 16) & 0x00000000FFFF0000) | \
|
||||
(((x) >> 48) & 0x000000000000FFFF))
|
||||
|
||||
/* Floating memory format (IEEE S) */
|
||||
|
||||
#define S_V_SIGN 31
|
||||
#define S_SIGN (1u << S_V_SIGN)
|
||||
#define S_V_EXP 23
|
||||
#define S_M_EXP 0xFF
|
||||
#define S_BIAS 0x7F
|
||||
#define S_NAN 0xFF
|
||||
#define S_EXP (S_M_EXP << S_V_EXP)
|
||||
#define S_V_FRAC 29
|
||||
#define S_GETEXP(x) ((uint32) (((x) >> S_V_EXP) & S_M_EXP))
|
||||
|
||||
/* Floating point memory format (IEEE T) */
|
||||
|
||||
#define T_V_SIGN 63
|
||||
#define T_SIGN 0x8000000000000000
|
||||
#define T_V_EXP 52
|
||||
#define T_M_EXP 0x7FF
|
||||
#define T_BIAS 0x3FF
|
||||
#define T_NAN 0x7FF
|
||||
#define T_EXP 0x7FF0000000000000
|
||||
#define T_FRAC 0x000FFFFFFFFFFFFF
|
||||
#define T_GETEXP(x) ((uint32) (((uint32) ((x) >> T_V_EXP)) & T_M_EXP))
|
||||
|
||||
/* Floating point register format (all except VAX D) */
|
||||
|
||||
#define FPR_V_SIGN 63
|
||||
#define FPR_SIGN 0x8000000000000000
|
||||
#define FPR_V_EXP 52
|
||||
#define FPR_M_EXP 0x7FF
|
||||
#define FPR_NAN 0x7FF
|
||||
#define FPR_EXP 0x7FF0000000000000
|
||||
#define FPR_HB 0x0010000000000000
|
||||
#define FPR_FRAC 0x000FFFFFFFFFFFFF
|
||||
#define FPR_GUARD (UF_V_NM - FPR_V_EXP)
|
||||
#define FPR_GETSIGN(x) (((uint32) ((x) >> FPR_V_SIGN)) & 1)
|
||||
#define FPR_GETEXP(x) (((uint32) ((x) >> FPR_V_EXP)) & FPR_M_EXP)
|
||||
#define FPR_GETFRAC(x) ((x) & FPR_FRAC)
|
||||
|
||||
#define FP_TRUE 0x4000000000000000 /* 0.5/2.0 in reg */
|
||||
|
||||
/* Floating point register format (VAX D) */
|
||||
|
||||
#define FDR_V_SIGN 63
|
||||
#define FDR_SIGN 0x8000000000000000
|
||||
#define FDR_V_EXP 55
|
||||
#define FDR_M_EXP 0xFF
|
||||
#define FDR_EXP 0x7F80000000000000
|
||||
#define FDR_HB 0x0080000000000000
|
||||
#define FDR_FRAC 0x007FFFFFFFFFFFFF
|
||||
#define FDR_GUARD (UF_V_NM - FDR_V_EXP)
|
||||
#define FDR_GETSIGN(x) (((uint32) ((x) >> FDR_V_SIGN)) & 1)
|
||||
#define FDR_GETEXP(x) (((uint32) ((x) >> FDR_V_EXP)) & FDR_M_EXP)
|
||||
#define FDR_GETFRAC(x) ((x) & FDR_FRAC)
|
||||
|
||||
#define D_BIAS 0x80
|
||||
|
||||
/* Unpacked floating point number */
|
||||
|
||||
typedef struct {
|
||||
uint32 sign;
|
||||
int32 exp;
|
||||
t_uint64 frac;
|
||||
} UFP;
|
||||
|
||||
#define UF_V_NM 63
|
||||
#define UF_NM 0x8000000000000000 /* normalized */
|
||||
|
||||
/* IEEE control register (left 32b only) */
|
||||
|
||||
#define FPCR_SUM 0x80000000 /* summary */
|
||||
#define FPCR_INED 0x40000000 /* inexact disable */
|
||||
#define FPCR_UNFD 0x20000000 /* underflow disable */
|
||||
#define FPCR_UNDZ 0x10000000 /* underflow to 0 */
|
||||
#define FPCR_V_RMOD 26 /* rounding mode */
|
||||
#define FPCR_M_RMOD 0x3
|
||||
#define FPCR_IOV 0x02000000 /* integer overflow */
|
||||
#define FPCR_INE 0x01000000 /* inexact */
|
||||
#define FPCR_UNF 0x00800000 /* underflow */
|
||||
#define FPCR_OVF 0x00400000 /* overflow */
|
||||
#define FPCR_DZE 0x00200000 /* div by zero */
|
||||
#define FPCR_INV 0x00100000 /* invalid operation */
|
||||
#define FPCR_OVFD 0x00080000 /* overflow disable */
|
||||
#define FPCR_DZED 0x00040000 /* div by zero disable */
|
||||
#define FPCR_INVD 0x00020000 /* invalid op disable */
|
||||
#define FPCR_DNZ 0x00010000 /* denormal to zero */
|
||||
#define FPCR_DNOD 0x00008000 /* denormal disable */
|
||||
#define FPCR_RAZ 0x00007FFF /* zero */
|
||||
#define FPCR_ERR (FPCR_IOV|FPCR_INE|FPCR_UNF|FPCR_OVF|FPCR_DZE|FPCR_INV)
|
||||
#define FPCR_GETFRND(x) (((x) >> FPCR_V_RMOD) & FPCR_M_RMOD)
|
||||
|
||||
/* PTE - hardware format */
|
||||
|
||||
#define PTE_V_PFN 32 /* PFN */
|
||||
#define PFN_MASK 0xFFFFFFFF
|
||||
#define PTE_V_UWE 15 /* write enables */
|
||||
#define PTE_V_SWE 14
|
||||
#define PTE_V_EWE 13
|
||||
#define PTE_V_KWE 12
|
||||
#define PTE_V_URE 11 /* read enables */
|
||||
#define PTE_V_SRE 10
|
||||
#define PTE_V_ERE 9
|
||||
#define PTE_V_KRE 8
|
||||
#define PTE_V_GH 5 /* granularity hint */
|
||||
#define PTE_M_GH 0x3
|
||||
#define PTE_GH (PTE_M_GH << PTE_V_GH)
|
||||
#define PTE_V_ASM 4 /* address space match */
|
||||
#define PTE_V_FOE 3 /* fault on execute */
|
||||
#define PTE_V_FOW 2 /* fault on write */
|
||||
#define PTE_V_FOR 1 /* fault on read */
|
||||
#define PTE_V_V 0 /* valid */
|
||||
#define PTE_UWE (1u << PTE_V_UWE)
|
||||
#define PTE_SWE (1u << PTE_V_SWE)
|
||||
#define PTE_EWE (1u << PTE_V_EWE)
|
||||
#define PTE_KWE (1u << PTE_V_KWE)
|
||||
#define PTE_URE (1u << PTE_V_URE)
|
||||
#define PTE_SRE (1u << PTE_V_SRE)
|
||||
#define PTE_ERE (1u << PTE_V_ERE)
|
||||
#define PTE_KRE (1u << PTE_V_KRE)
|
||||
#define PTE_ASM (1u << PTE_V_ASM)
|
||||
#define PTE_FOE (1u << PTE_V_FOE)
|
||||
#define PTE_FOW (1u << PTE_V_FOW)
|
||||
#define PTE_FOR (1u << PTE_V_FOR)
|
||||
#define PTE_V (1u << PTE_V_V)
|
||||
#define PTE_MASK 0xFF7F
|
||||
#define PTE_GETGH(x) ((((uint32) (x)) >> PTE_V_GH) & PTE_M_GH)
|
||||
#define VPN_GETLVL1(x) (((x) >> ((2 * VA_N_LVL) - 3)) & (VA_M_LVL << 3))
|
||||
#define VPN_GETLVL2(x) (((x) >> (VA_N_LVL - 3)) & (VA_M_LVL << 3))
|
||||
#define VPN_GETLVL3(x) (((x) << 3) & (VA_M_LVL << 3))
|
||||
|
||||
#define ACC_E(m) ((PTE_KRE << (m)) | PTE_FOE | PTE_V)
|
||||
#define ACC_R(m) ((PTE_KRE << (m)) | PTE_FOR | PTE_V)
|
||||
#define ACC_W(m) ((PTE_KWE << (m)) | PTE_FOW | PTE_V)
|
||||
#define ACC_M(m) (((PTE_KRE|PTE_KWE) << (m)) | PTE_FOR | PTE_FOW | PTE_V)
|
||||
|
||||
/* Exceptions */
|
||||
|
||||
#define ABORT(x) longjmp (save_env, (x))
|
||||
#define ABORT1(x,y) { p1 = (x); longjmp (save_env, (y)); }
|
||||
|
||||
#define EXC_RSVI 0x01 /* reserved instruction */
|
||||
#define EXC_RSVO 0x02 /* reserved operand */
|
||||
#define EXC_ALIGN 0x03 /* operand alignment */
|
||||
#define EXC_FPDIS 0x04 /* flt point disabled */
|
||||
#define EXC_TBM 0x08 /* TLB miss */
|
||||
#define EXC_FOX 0x10 /* fault on r/w/e */
|
||||
#define EXC_ACV 0x14 /* access control viol */
|
||||
#define EXC_TNV 0x18 /* translation not valid */
|
||||
#define EXC_BVA 0x1C /* bad address format */
|
||||
#define EXC_E 0x00 /* offset for execute */
|
||||
#define EXC_R 0x01 /* offset for read */
|
||||
#define EXC_W 0x02 /* offset for write */
|
||||
|
||||
/* Traps - corresponds to arithmetic trap summary register */
|
||||
|
||||
#define TRAP_SWC 0x001 /* software completion */
|
||||
#define TRAP_INV 0x002 /* invalid operand */
|
||||
#define TRAP_DZE 0x004 /* divide by zero */
|
||||
#define TRAP_OVF 0x008 /* overflow */
|
||||
#define TRAP_UNF 0x010 /* underflow */
|
||||
#define TRAP_INE 0x020 /* inexact */
|
||||
#define TRAP_IOV 0x040 /* integer overflow */
|
||||
#define TRAP_SUMM_RW 0x07F
|
||||
|
||||
/* PALcode */
|
||||
|
||||
#define SP R[30] /* stack pointer */
|
||||
#define MODE_K 0 /* kernel */
|
||||
#define MODE_E 1 /* executive (UNIX user) */
|
||||
#define MODE_S 2 /* supervisor */
|
||||
#define MODE_U 3 /* user */
|
||||
|
||||
#define PAL_UNDF 0 /* undefined */
|
||||
#define PAL_VMS 1 /* VMS */
|
||||
#define PAL_UNIX 2 /* UNIX */
|
||||
#define PAL_NT 3 /* Windows NT */
|
||||
|
||||
/* Machine check error summary register */
|
||||
|
||||
#define MCES_INP 0x01 /* in progress */
|
||||
#define MCES_SCRD 0x02 /* sys corr in prog */
|
||||
#define MCES_PCRD 0x04 /* proc corr in prog */
|
||||
#define MCES_DSCRD 0x08 /* disable system corr */
|
||||
#define MCES_DPCRD 0x10 /* disable proc corr */
|
||||
#define MCES_W1C (MCES_INP|MCES_SCRD|MCES_PCRD)
|
||||
#define MCES_DIS (MCES_DSCRD|MCES_DPCRD)
|
||||
|
||||
/* I/O devices */
|
||||
|
||||
#define L_BYTE 0 /* IO request lengths */
|
||||
#define L_WORD 1
|
||||
#define L_LONG 2
|
||||
#define L_QUAD 3
|
||||
|
||||
/* Device information block */
|
||||
|
||||
typedef struct { /* device info block */
|
||||
t_uint64 low; /* low addr */
|
||||
t_uint64 high; /* high addr */
|
||||
t_bool (*read)(t_uint64 pa, t_uint64 *val, uint32 lnt);
|
||||
t_bool (*write)(t_uint64 pa, t_uint64 val, uint32 lnt);
|
||||
uint32 ipl;
|
||||
} DIB;
|
||||
|
||||
/* Interrupt system - 6 levels in EV4 and EV6, 4 in EV5 - software expects 4 */
|
||||
|
||||
#define IPL_HMAX 0x17 /* highest hwre level */
|
||||
#define IPL_HMIN 0x14 /* lowest hwre level */
|
||||
#define IPL_HLVL (IPL_HMAX - IPL_HMIN + 1) /* # hardware levels */
|
||||
#define IPL_SMAX 0x0F /* highest swre level */
|
||||
|
||||
/* Macros */
|
||||
|
||||
#define PCQ_SIZE 64 /* must be 2**n */
|
||||
#define PCQ_MASK (PCQ_SIZE - 1)
|
||||
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = (PC - 4) & M64
|
||||
|
||||
#define SEXT_B_Q(x) (((x) & B_SIGN)? ((x) | ~((t_uint64) M8)): ((x) & M8))
|
||||
#define SEXT_W_Q(x) (((x) & W_SIGN)? ((x) | ~((t_uint64) M16)): ((x) & M16))
|
||||
#define SEXT_L_Q(x) (((x) & L_SIGN)? ((x) | ~((t_uint64) M32)): ((x) & M32))
|
||||
#define NEG_Q(x) ((~(x) + 1) & M64)
|
||||
#define ABS_Q(x) (((x) & Q_SIGN)? NEG_Q (x): (x))
|
||||
|
||||
#define SIGN_BDSP 0x008000
|
||||
#define SIGN_MDSP 0x100000
|
||||
#define SEXT_MDSP(x) (((x) & SIGN_MDSP)? \
|
||||
((x) | ~((t_uint64) I_M_MDSP)): ((x) & I_M_MDSP))
|
||||
#define SEXT_BDSP(x) (((x) & SIGN_BDSP)? \
|
||||
((x) | ~((t_uint64) I_M_BDSP)): ((x) & I_M_BDSP))
|
||||
|
||||
/* Opcodes */
|
||||
|
||||
enum opcodes {
|
||||
OP_PAL, OP_OPC01, OP_OPC02, OP_OPC03,
|
||||
OP_OPC04, OP_OPC05, OP_OPC06, OP_OPC07,
|
||||
OP_LDA, OP_LDAH, OP_LDBU, OP_LDQ_U,
|
||||
OP_LDWU, OP_STW, OP_STB, OP_STQ_U,
|
||||
OP_IALU, OP_ILOG, OP_ISHFT, OP_IMUL,
|
||||
OP_IFLT, OP_VAX, OP_IEEE, OP_FP,
|
||||
OP_MISC, OP_PAL19, OP_JMP, OP_PAL1B,
|
||||
OP_FLTI, OP_PAL1D, OP_PAL1E, OP_PAL1F,
|
||||
OP_LDF, OP_LDG, OP_LDS, OP_LDT,
|
||||
OP_STF, OP_STG, OP_STS, OP_STT,
|
||||
OP_LDL, OP_LDQ, OP_LDL_L, OP_LDQ_L,
|
||||
OP_STL, OP_STQ, OP_STL_C, OP_STQ_C,
|
||||
OP_BR, OP_FBEQ, OP_FBLT, OP_FBLE,
|
||||
OP_BSR, OP_FBNE, OP_FBGE, OP_FBGT,
|
||||
OP_BLBC, OP_BEQ, OP_BLT, OP_BLE,
|
||||
OP_BLBS, OP_BNE, OP_BGE, OP_BGT
|
||||
};
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
uint32 ReadI (t_uint64 va);
|
||||
t_uint64 ReadB (t_uint64 va);
|
||||
t_uint64 ReadW (t_uint64 va);
|
||||
t_uint64 ReadL (t_uint64 va);
|
||||
t_uint64 ReadQ (t_uint64 va);
|
||||
t_uint64 ReadAccL (t_uint64 va, uint32 acc);
|
||||
t_uint64 ReadAccQ (t_uint64 va, uint32 acc);
|
||||
INLINE t_uint64 ReadPB (t_uint64 pa);
|
||||
INLINE t_uint64 ReadPW (t_uint64 pa);
|
||||
INLINE t_uint64 ReadPL (t_uint64 pa);
|
||||
INLINE t_uint64 ReadPQ (t_uint64 pa);
|
||||
t_bool ReadIO (t_uint64 pa, t_uint64 *val, uint32 lnt);
|
||||
void WriteB (t_uint64 va, t_uint64 dat);
|
||||
void WriteW (t_uint64 va, t_uint64 dat);
|
||||
void WriteL (t_uint64 va, t_uint64 dat);
|
||||
void WriteQ (t_uint64 va, t_uint64 dat);
|
||||
void WriteAccL (t_uint64 va, t_uint64 dat, uint32 acc);
|
||||
void WriteAccQ (t_uint64 va, t_uint64 dat, uint32 acc);
|
||||
INLINE void WritePB (t_uint64 pa, t_uint64 dat);
|
||||
INLINE void WritePW (t_uint64 pa, t_uint64 dat);
|
||||
INLINE void WritePL (t_uint64 pa, t_uint64 dat);
|
||||
INLINE void WritePQ (t_uint64 pa, t_uint64 dat);
|
||||
t_bool WriteIO (t_uint64 pa, t_uint64 val, uint32 lnt);
|
||||
uint32 mmu_set_cm (uint32 mode);
|
||||
void mmu_set_icm (uint32 mode);
|
||||
void mmu_set_dcm (uint32 mode);
|
||||
void arith_trap (uint32 trap, uint32 ir);
|
||||
|
||||
#endif
|
||||
143
Alpha/alpha_ev5_cons.c
Normal file
143
Alpha/alpha_ev5_cons.c
Normal file
@ -0,0 +1,143 @@
|
||||
/* alpha_ev5_cons.c - Alpha console support routines for EV5
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
#include "alpha_ev5_defs.h"
|
||||
|
||||
t_uint64 srm_ptbr = 1;
|
||||
|
||||
extern uint32 dtlb_spage;
|
||||
extern uint32 pal_type;
|
||||
extern uint32 ev5_mcsr;
|
||||
extern t_uint64 *M;
|
||||
extern t_uint64 ev5_mvptbr;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
/* Local quadword physical read - <no> exceptions or IO space lookups */
|
||||
|
||||
t_stat l_ReadPQ (t_uint64 pa, t_uint64 *dat)
|
||||
{
|
||||
if (ADDR_IS_MEM (pa)) {
|
||||
*dat = M[pa >> 3];
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* "SRM" 3-level pte lookup
|
||||
|
||||
Inputs:
|
||||
va = virtual address
|
||||
*pte = pointer to pte to be returned
|
||||
Output:
|
||||
status = 0 for successful fill
|
||||
EXC_ACV for ACV on intermediate level
|
||||
EXC_TNV for TNV on intermediate level
|
||||
*/
|
||||
|
||||
uint32 cons_find_pte_srm (t_uint64 va, t_uint64 *l3pte)
|
||||
{
|
||||
t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte;
|
||||
uint32 vpte_vpn;
|
||||
TLBENT *vpte_p;
|
||||
|
||||
vptea = FMT_MVA_VMS (va); /* try virt lookup */
|
||||
vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */
|
||||
vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */
|
||||
if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V)))
|
||||
l3ptea = PHYS_ADDR (vpte_p->pfn, vptea);
|
||||
else {
|
||||
uint32 vpn = VA_GETVPN (va);
|
||||
if (srm_ptbr & 1) return 1; /* uninitialized? */
|
||||
l1ptea = srm_ptbr + VPN_GETLVL1 (vpn);
|
||||
if (!l_ReadPQ (l1ptea, &l1pte)) return 1;
|
||||
if ((l1pte & PTE_V) == 0)
|
||||
return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV);
|
||||
l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF);
|
||||
l2ptea = l2ptea + VPN_GETLVL2 (vpn);
|
||||
if (!l_ReadPQ (l2ptea, &l2pte)) return 1;
|
||||
if ((l2pte & PTE_V) == 0)
|
||||
return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV);
|
||||
l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF);
|
||||
l3ptea = l3ptea + VPN_GETLVL3 (vpn);
|
||||
}
|
||||
if (!l_ReadPQ (l3ptea, l3pte)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NT 2-level pte lookup
|
||||
|
||||
Inputs:
|
||||
va = virtual address
|
||||
*pte = pointer to pte to be returned
|
||||
Output:
|
||||
status = 0 for successful fill
|
||||
EXC_ACV for ACV on intermediate level
|
||||
EXC_TNV for TNV on intermediate level
|
||||
*/
|
||||
|
||||
uint32 cons_find_pte_nt (t_uint64 va, t_uint64 *l3pte)
|
||||
{
|
||||
t_uint64 vptea, l3ptea;
|
||||
uint32 vpte_vpn;
|
||||
TLBENT *vpte_p;
|
||||
|
||||
vptea = FMT_MVA_NT (va); /* try virt lookup */
|
||||
vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */
|
||||
vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */
|
||||
if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V)))
|
||||
l3ptea = PHYS_ADDR (vpte_p->pfn, vptea);
|
||||
else {
|
||||
return 1; /* for now */
|
||||
}
|
||||
if (!l_ReadPQ (l3ptea, l3pte)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Translate address for console access */
|
||||
|
||||
t_uint64 trans_c (t_uint64 va)
|
||||
{
|
||||
uint32 va_sext = VA_GETSEXT (va);
|
||||
uint32 vpn = VA_GETVPN (va);
|
||||
TLBENT *tlbp;
|
||||
t_uint64 pte64;
|
||||
uint32 exc, pfn;
|
||||
|
||||
if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */
|
||||
return M64;
|
||||
if ((dtlb_spage & SPEN_43) && (VPN_GETSP43 (vpn) == 2))
|
||||
return (va & SP43_MASK); /* 43b superpage? */
|
||||
if ((dtlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE))
|
||||
return (va & SP32_MASK); /* 32b superpage? */
|
||||
if (tlbp = dtlb_lookup (vpn)) /* try TLB */
|
||||
return PHYS_ADDR (tlbp->pfn, va); /* found it */
|
||||
if (ev5_mcsr & MCSR_NT) exc = cons_find_pte_nt (va, &pte64);
|
||||
else exc = cons_find_pte_srm (va, &pte64);
|
||||
if (exc || ((pte64 & PTE_V) == 0)) return M64; /* check valid */
|
||||
pfn = (uint32) (pte64 >> 32) & M32;
|
||||
return PHYS_ADDR (pfn, va); /* return phys addr */
|
||||
}
|
||||
428
Alpha/alpha_ev5_defs.h
Normal file
428
Alpha/alpha_ev5_defs.h
Normal file
@ -0,0 +1,428 @@
|
||||
/* alpha_ev5_defs.h: Alpha EV5 chip definitions file
|
||||
|
||||
Copyright (c) 2003-2005, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
Respectfully dedicated to the great people of the Alpha chip, systems, and
|
||||
software development projects; and to the memory of Peter Conklin, of the
|
||||
Alpha Program Office.
|
||||
*/
|
||||
|
||||
#ifndef _ALPHA_EV5_DEFS_H_
|
||||
#define _ALPHA_EV5_DEFS_H_ 0
|
||||
|
||||
/* Address limits */
|
||||
|
||||
#define VA_SIZE 43 /* VA size */
|
||||
#define NTVA_WIDTH 32 /* VA width for NT */
|
||||
#define VA_MASK 0x000007FFFFFFFFFF
|
||||
#define EV5_PA_SIZE 40 /* PA size */
|
||||
#define EV5_PA_MASK 0x000000FFFFFFFFFF
|
||||
|
||||
/* Virtual address */
|
||||
|
||||
#define VA_N_OFF 13 /* offset size */
|
||||
#define VA_PAGSIZE (1u << VA_N_OFF) /* page size */
|
||||
#define VA_M_OFF ((1u << VA_N_OFF) - 1) /* offset mask */
|
||||
#define VA_N_LVL 10 /* width per level */
|
||||
#define VA_M_LVL ((1u << VA_N_LVL) - 1) /* level mask */
|
||||
#define VA_V_VPN VA_N_OFF /* vpn start */
|
||||
#define VA_N_VPN (VA_N_LVL * 3) /* vpn size */
|
||||
#define VA_M_VPN ((1u << VA_N_VPN) - 1) /* vpn mask */
|
||||
#define VA_WIDTH (VA_N_VPN + VA_N_OFF) /* total VA size */
|
||||
#define VA_V_SEXT (VA_WIDTH - 1) /* sext start */
|
||||
#define VA_M_SEXT ((1u << (64 - VA_V_SEXT)) - 1) /* sext mask */
|
||||
#define VA_GETOFF(x) (((uint32) (x)) & VA_M_OFF)
|
||||
#define VA_GETVPN(x) (((uint32) ((x) >> VA_V_VPN)) & VA_M_VPN)
|
||||
#define VA_GETSEXT(x) (((uint32) ((x) >> VA_V_SEXT)) & VA_M_SEXT)
|
||||
#define PHYS_ADDR(p,v) ((((t_uint64) (p)) < VA_N_OFF) | VA_GETOFF (v))
|
||||
|
||||
/* 43b and 32b superpages - present in all implementations */
|
||||
|
||||
#define SPEN_43 0x2
|
||||
#define SPEN_32 0x1
|
||||
#define SP43_MASK 0x000001FFFFFFFFFF
|
||||
#define SP32_MASK 0x000000003FFFFFFF
|
||||
#define VPN_GETSP43(x) ((uint32) (((x) >> (VA_WIDTH - VA_N_OFF - 2)) & 3))
|
||||
#define VPN_GETSP32(x) ((uint32) (((x) >> (NTVA_WIDTH - VA_N_OFF - 2)) & 0x1FFF))
|
||||
|
||||
/* TLBs */
|
||||
|
||||
#define INV_TAG M32
|
||||
#define ITLB_SIZE 48
|
||||
#define DTLB_SIZE 64
|
||||
#define ITLB_WIDTH 6
|
||||
#define DTLB_WIDTH 6
|
||||
|
||||
#define TLB_CI 0x1 /* clear I */
|
||||
#define TLB_CD 0x2 /* clear D */
|
||||
#define TLB_CA 0x4 /* clear all */
|
||||
|
||||
typedef struct {
|
||||
uint32 tag; /* tag */
|
||||
uint8 asn; /* addr space # */
|
||||
uint8 idx; /* entry # */
|
||||
uint16 gh_mask; /* gh mask */
|
||||
uint32 pfn; /* pfn */
|
||||
uint32 pte; /* swre/pte */
|
||||
} TLBENT;
|
||||
|
||||
/* Register shadow */
|
||||
|
||||
#define PALSHAD_SIZE 8
|
||||
#define PAL_USE_SHADOW \
|
||||
ev5_palsave[0] = R[8]; ev5_palsave[1] = R[9]; \
|
||||
ev5_palsave[2] = R[10]; ev5_palsave[3] = R[11]; \
|
||||
ev5_palsave[4] = R[12]; ev5_palsave[5] = R[13]; \
|
||||
ev5_palsave[6] = R[14]; ev5_palsave[7] = R[25]; \
|
||||
R[8] = ev5_palshad[0]; R[9] = ev5_palshad[1]; \
|
||||
R[10] = ev5_palshad[2]; R[11] = ev5_palshad[3]; \
|
||||
R[12] = ev5_palshad[4]; R[13] = ev5_palshad[5]; \
|
||||
R[14] = ev5_palshad[6]; R[25] = ev5_palshad[7]
|
||||
#define PAL_USE_MAIN \
|
||||
ev5_palshad[0] = R[8]; ev5_palshad[1] = R[9]; \
|
||||
ev5_palshad[2] = R[10]; ev5_palshad[3] = R[11]; \
|
||||
ev5_palshad[4] = R[12]; ev5_palshad[5] = R[13]; \
|
||||
ev5_palshad[6] = R[14]; ev5_palshad[7] = R[25]; \
|
||||
R[8] = ev5_palsave[0]; R[9] = ev5_palsave[1]; \
|
||||
R[10] = ev5_palsave[2]; R[11] = ev5_palsave[3]; \
|
||||
R[12] = ev5_palsave[4]; R[13] = ev5_palsave[5]; \
|
||||
R[14] = ev5_palsave[6]; R[25] = ev5_palsave[7]
|
||||
|
||||
/* PAL instructions */
|
||||
|
||||
#define HW_MFPR 0x19
|
||||
#define HW_LD 0x1B
|
||||
#define HW_MTPR 0x1D
|
||||
#define HW_REI 0x1E
|
||||
#define HW_ST 0x1F
|
||||
|
||||
#define HW_LD_V 0x8000
|
||||
#define HW_LD_ALT 0x4000
|
||||
#define HW_LD_WCH 0x2000
|
||||
#define HW_LD_Q 0x1000
|
||||
#define HW_LD_PTE 0x0800
|
||||
#define HW_LD_LCK 0x0400
|
||||
#define HW_LD_DSP 0x03FF
|
||||
#define SIGN_HW_LD_DSP 0x0200
|
||||
#define HW_LD_GETDSP(x) ((x) & HW_LD_DSP)
|
||||
#define SEXT_HW_LD_DSP(x) (((x) & SIGN_HW_LD_DSP)? \
|
||||
((x) | ~((t_uint64) HW_LD_DSP)): ((x) & HW_LD_DSP))
|
||||
|
||||
#define HW_REI_S 0x4000
|
||||
|
||||
/* PAL entry offsets */
|
||||
|
||||
#define PALO_RESET 0x0000
|
||||
#define PALO_IACV 0x0080
|
||||
#define PALO_INTR 0x0100
|
||||
#define PALO_ITBM 0x0180
|
||||
#define PALO_DTBM 0x0200
|
||||
#define PALO_DTBM_D 0x0280
|
||||
#define PALO_ALGN 0x0300
|
||||
#define PALO_DFLT 0x0380
|
||||
#define PALO_MCHK 0x0400
|
||||
#define PALO_RSVI 0x0480
|
||||
#define PALO_TRAP 0x0500
|
||||
#define PALO_FDIS 0x0580
|
||||
#define PALO_CALLPR 0x2000
|
||||
#define PALO_CALLUNPR 0x3000
|
||||
|
||||
/* Special (above 1F) and normal interrupt levels */
|
||||
|
||||
#define IPL_HALT 0x40
|
||||
#define IPL_SLI 0x20
|
||||
#define IPL_1F 0x1F /* highest level */
|
||||
#define IPL_CRD 0x1F /* corrected read data */
|
||||
#define IPL_PWRFL 0x1E /* power fail */
|
||||
#define IPL_AST 0x02 /* AST interrupt level */
|
||||
|
||||
/* Internal registers */
|
||||
|
||||
#define PALTEMP_SIZE 24
|
||||
|
||||
enum ev5_internal_reg {
|
||||
ISR = 0x100, ITB_TAG, ITB_PTE, ITB_ASN,
|
||||
ITB_PTE_TEMP, ITB_IA, ITB_IAP, ITB_IS,
|
||||
SIRR, ASTRR, ASTEN, EXC_ADDR,
|
||||
EXC_SUMM, EXC_MASK, PAL_BASE, ICM,
|
||||
IPLR, INTID, IFAULT_VA_FORM, IVPTBR,
|
||||
HWINT_CLR = 0x115, SL_XMIT, SL_RCV,
|
||||
ICSR, IC_FLUSH_CTL, ICPERR_STAT, PMCTR = 0x11C,
|
||||
PALTEMP = 0x140,
|
||||
DTB_ASN = 0x200, DTB_CM, DTB_TAG, DTB_PTE,
|
||||
DTB_PTE_TEMP, MM_STAT, VA, VA_FORM,
|
||||
MVPTBR, DTB_IAP, DTB_IA, DTB_IS,
|
||||
ALTMODE, CC, CC_CTL, MCSR,
|
||||
DC_FLUSH, DC_PERR_STAT = 0x212, DC_TEST_CTL,
|
||||
DC_TEST_TAG, DC_TEST_TAG_TEMP, DC_MODE, MAF_MODE
|
||||
};
|
||||
|
||||
/* Ibox registers */
|
||||
/* ISR - instruction summary register - read only */
|
||||
|
||||
#define ISR_V_AST 0
|
||||
#define ISR_V_SIRR 4
|
||||
#define ISR_V_ATR 19
|
||||
#define ISR_V_IRQ0 20
|
||||
#define ISR_V_IRQ1 21
|
||||
#define ISR_V_IRQ2 22
|
||||
#define ISR_V_IRQ3 23
|
||||
#define ISR_V_PFL 30
|
||||
#define ISR_V_MCHK 31
|
||||
#define ISR_V_CRD 32
|
||||
#define ISR_V_SLI 33
|
||||
#define ISR_V_HALT 34
|
||||
|
||||
#define ISR_ATR (((t_uint64) 1u) << ISR_V_ATR)
|
||||
#define ISR_IRQ0 (((t_uint64) 1u) << ISR_V_IRQ0)
|
||||
#define ISR_IRQ1 (((t_uint64) 1u) << ISR_V_IRQ1)
|
||||
#define ISR_IRQ2 (((t_uint64) 1u) << ISR_V_IRQ2)
|
||||
#define ISR_IRQ3 (((t_uint64) 1u) << ISR_V_IRQ3)
|
||||
#define ISR_HALT (((t_uint64) 1u) << ISR_V_HALT)
|
||||
|
||||
/* ITB_TAG - ITLB tag - write only - stores VPN (tag) of faulting address */
|
||||
|
||||
/* ITB_PTE - ITLB pte - read and write in different formats */
|
||||
|
||||
#define ITBR_PTE_V_ASM 13
|
||||
#define ITBR_PTE_ASM (1u << ITBR_PTE_V_ASM)
|
||||
#define ITBR_PTE_V_KRE 18
|
||||
#define ITBR_PTE_GH0 0x00000000
|
||||
#define ITBR_PTE_GH1 0x20000000
|
||||
#define ITBR_PTE_GH2 0x60000000
|
||||
#define ITBR_PTE_GH3 0xE0000000
|
||||
|
||||
/* ITB_ASN - ITLB ASN - read write */
|
||||
|
||||
#define ITB_ASN_V_ASN 4
|
||||
#define ITB_ASN_M_ASN 0x7F
|
||||
#define ITB_ASN_WIDTH 7
|
||||
|
||||
/* ITB_PTE_TEMP - ITLB PTE readout - read only */
|
||||
|
||||
/* ITB_IA, ITB_IAP, ITB_IS - ITLB invalidates - write only */
|
||||
|
||||
/* SIRR - software interrupt request register - read/write */
|
||||
|
||||
#define SIRR_V_SIRR 4
|
||||
#define SIRR_M_SIRR 0x7FFF
|
||||
|
||||
/* ASTRR, ASTEN - AST request, enable registers - read/write */
|
||||
|
||||
#define AST_MASK 0xF /* AST bits */
|
||||
|
||||
/* EXC_ADDR - read/write */
|
||||
|
||||
/* EXC_SUMM - read/cleared on write */
|
||||
|
||||
/* EXC_MASK - read only */
|
||||
|
||||
/* PAL_BASE - read/write */
|
||||
|
||||
#define PAL_BASE_RW 0x000000FFFFFFFFC000
|
||||
|
||||
/* ICM - ITLB current mode - read/write */
|
||||
|
||||
#define ICM_V_CM 3
|
||||
#define ICM_M_CM 0x3
|
||||
|
||||
/* IPLR - interrupt priority level - read/write */
|
||||
|
||||
#define IPLR_V_IPL 0
|
||||
#define IPLR_M_IPL 0x1F
|
||||
|
||||
/* INTID - interrupt ID - read only */
|
||||
|
||||
#define INTID_MASK 0x1F
|
||||
|
||||
/* IFAULT_VA_FORM - formated fault VA - read only */
|
||||
|
||||
/* IVPTBR - virtual page table base - read/write */
|
||||
|
||||
#define IVPTBR_VMS 0xFFFFFFF800000000
|
||||
#define IVPTBR_NT 0xFFFFFFFFC0000000
|
||||
#define FMT_IVA_VMS(x) (ev5_ivptbr | (((x) >> (VA_N_OFF - 3)) & 0x1FFFFFFF8))
|
||||
#define FMT_IVA_NT(x) (ev5_ivptbr | (((x) >> (VA_N_OFF - 3)) & 0x0003FFFF8))
|
||||
|
||||
/* HWINT_CLR - hardware interrupt clear - write only */
|
||||
|
||||
#define HWINT_CLR_W1C 0x00000003C8000000
|
||||
|
||||
/* SL_XMIT - serial line transmit - write only */
|
||||
|
||||
/* SL_RCV - real line receive - read only */
|
||||
|
||||
/* ICSR - Ibox control/status - read/write */
|
||||
|
||||
#define ICSR_V_PME 8
|
||||
#define ICSR_M_PME 0x3
|
||||
#define ICSR_V_BSE 17
|
||||
#define ICSR_V_MSK0 20
|
||||
#define ICSR_V_MSK1 21
|
||||
#define ICSR_V_MSK2 22
|
||||
#define ICSR_V_MSK3 23
|
||||
#define ICSR_V_TMM 24
|
||||
#define ICSR_V_TMD 25
|
||||
#define ICSR_V_FPE 26
|
||||
#define ICSR_V_HWE 27
|
||||
#define ICSR_V_SPE 28
|
||||
#define ICSR_M_SPE 0x3
|
||||
#define ICSR_V_SDE 30
|
||||
#define ICSR_V_CRDE 32
|
||||
#define ICSR_V_SLE 33
|
||||
#define ICSR_V_FMS 34
|
||||
#define ICSR_V_FBT 35
|
||||
#define ICSR_V_FBD 36
|
||||
#define ICSR_V_BIST 38
|
||||
#define ICSR_V_TEST 39
|
||||
|
||||
#define ICSR_NT (((t_uint64) 1u) << ICSR_V_SPE)
|
||||
#define ICSR_BSE (((t_uint64) 1u) << ICSR_V_BSE)
|
||||
#define ICSR_MSK0 (((t_uint64) 1u) << ICSR_V_MSK0)
|
||||
#define ICSR_MSK1 (((t_uint64) 1u) << ICSR_V_MSK1)
|
||||
#define ICSR_MSK2 (((t_uint64) 1u) << ICSR_V_MSK2)
|
||||
#define ICSR_MSK3 (((t_uint64) 1u) << ICSR_V_MSK3)
|
||||
#define ICSR_HWE (((t_uint64) 1u) << ICSR_V_HWE)
|
||||
#define ICSR_SDE (((t_uint64) 1u) << ICSR_V_SDE)
|
||||
#define ICSR_CRDE (((t_uint64) 1u) << ICSR_V_CRDE)
|
||||
#define ICSR_SLE (((t_uint64) 1u) << ICSR_V_SLE)
|
||||
|
||||
#define ICSR_RW 0x0000009F4BF00300
|
||||
#define ICSR_MBO 0x0000006000000000
|
||||
|
||||
/* IC_FLUSH_CTL - Icache flush control - write only */
|
||||
|
||||
/* ICPERR_STAT - Icache parity status - read/write 1 to clear */
|
||||
|
||||
#define ICPERR_V_DPE 11
|
||||
#define ICPERR_V_TPE 12
|
||||
#define ICPERR_V_TMO 13
|
||||
|
||||
#define ICPERR_DPE (1u << ICPERR_V_DPE)
|
||||
#define ICPERR_TPE (1u << ICPERR_V_TPE)
|
||||
#define ICPERR_TMO (1u << ICPERR_V_TMO)
|
||||
|
||||
#define ICPERR_W1C (ICPERR_DPE|ICPERR_TPE|ICPERR_TMO)
|
||||
|
||||
/* Mbox registers */
|
||||
/* DTB_ASN - DTLB ASN - write only */
|
||||
|
||||
#define DTB_ASN_V_ASN 57
|
||||
#define DTB_ASN_M_ASN 0x7F
|
||||
#define DTB_ASN_WIDTH 7
|
||||
|
||||
/* DTB_CM - DTLB current mode - write only */
|
||||
|
||||
#define DCM_V_CM 3
|
||||
#define DCM_M_CM 0x3
|
||||
|
||||
/* DTB_TAG - DTLB tag and update - write only */
|
||||
|
||||
/* DTB_PTE - DTLB PTE - read/write */
|
||||
|
||||
/* DTB_PTE_TEMP - DTLB PTE read out register - read only */
|
||||
|
||||
/* MM_STAT - data fault status register - read only */
|
||||
|
||||
#define MM_STAT_WR 0x00001
|
||||
#define MM_STAT_ACV 0x00002
|
||||
#define MM_STAT_FOR 0x00004
|
||||
#define MM_STAT_FOW 0x00008
|
||||
#define MM_STAT_TBM 0x00010
|
||||
#define MM_STAT_BVA 0x00020
|
||||
#define MM_STAT_V_RA 6
|
||||
#define MM_STAT_IMASK 0x1FFC0
|
||||
|
||||
/* VA - data fault virtual address - read only */
|
||||
|
||||
/* VA_FORM - data fault formated virtual address - read only */
|
||||
|
||||
#define FMT_MVA_VMS(x) (ev5_mvptbr | (((x) >> (VA_N_OFF - 3)) & 0x1FFFFFFF8))
|
||||
#define FMT_MVA_NT(x) (ev5_mvptbr | (((x) >> (VA_N_OFF - 3)) & 0x0003FFFF8))
|
||||
|
||||
/* MVPTBR - DTB virtual page table base - write only */
|
||||
|
||||
#define MVPTBR_MBZ ((t_uint64) 0x3FFFFFFF)
|
||||
|
||||
/* DTB_IAP, DTB_IA, DTB_IS - DTB invalidates - write only */
|
||||
|
||||
/* ALT_MODE - DTLB current mode - write only */
|
||||
|
||||
#define ALT_V_CM 3
|
||||
#define ALT_M_CM 0x3
|
||||
|
||||
/* CC - cycle counter - upper half is RW, lower half is RO */
|
||||
|
||||
/* CC_CTL - cycle counter control - write only */
|
||||
|
||||
#define CC_CTL_ENB 0x100000000
|
||||
#define CC_CTL_MBZ 0xF
|
||||
|
||||
/* MCSR - Mbox control/status register - read/write */
|
||||
|
||||
#define MCSR_RW 0x11
|
||||
#define MCSR_V_SPE 1
|
||||
#define MCSR_M_SPE 0x3
|
||||
#define MCSR_NT 0x02
|
||||
|
||||
/* DC_PERR_STAT - data cache parity error status - read/write */
|
||||
|
||||
#define DC_PERR_W1C 0x3
|
||||
#define DC_PERR_ERR 0x1C
|
||||
|
||||
/* DC_MODE - data cache mode - read/write */
|
||||
|
||||
#define DC_MODE_RW 0xF
|
||||
|
||||
/* MAF_MODE - miss address file mode - read/write */
|
||||
|
||||
#define MAF_MODE_RW 0xFF
|
||||
|
||||
/* DC_TEST_CTL - data cache test control - read/write */
|
||||
|
||||
#define DC_TEST_CTL_RW 0x1FFFB
|
||||
|
||||
/* DC_TEST_TAG - data cache test tag - read/write */
|
||||
|
||||
#define DC_TEST_TAG_RW 0x0000007FFFFFFF04
|
||||
|
||||
/* Function prototypes (TLB interface) */
|
||||
|
||||
void tlb_ia (uint32 flags);
|
||||
void tlb_is (t_uint64 va, uint32 flags);
|
||||
void itlb_set_asn (uint32 asn);
|
||||
void itlb_set_cm (uint32 mode);
|
||||
void itlb_set_spage (uint32 spage);
|
||||
TLBENT *itlb_lookup (uint32 vpn);
|
||||
TLBENT *itlb_load (uint32 vpn, t_uint64 pte);
|
||||
t_uint64 itlb_read (void);
|
||||
void dtlb_set_asn (uint32 asn);
|
||||
void dtlb_set_cm (uint32 mode);
|
||||
void dtlb_set_spage (uint32 spage);
|
||||
TLBENT *dtlb_lookup (uint32 vpn);
|
||||
TLBENT *dtlb_load (uint32 vpn, t_uint64 pte);
|
||||
t_uint64 dtlb_read (void);
|
||||
|
||||
#endif
|
||||
|
||||
961
Alpha/alpha_ev5_pal.c
Normal file
961
Alpha/alpha_ev5_pal.c
Normal file
@ -0,0 +1,961 @@
|
||||
/* alpha_ev5_pal.c - Alpha EV5 PAL mode simulator
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
EV5 was the second generation Alpha CPU. It was a four-way, in order issue
|
||||
CPU with onchip primary instruction and data caches, an onchip second level
|
||||
cache, and support for an offchip third level cache. EV56 was a shrink, with
|
||||
added support for byte and word operations. PCA56 was a version of EV56
|
||||
without the onchip second level cache. PCA57 was a shrink of PCA56.
|
||||
|
||||
EV5 includes the usual five PALcode instructions:
|
||||
|
||||
HW_LD PALcode load
|
||||
HW_ST PALcode store
|
||||
HW_MTPR PALcode move to internal processor register
|
||||
HW_MFPR PALcode move from internal processor register
|
||||
HW_REI PALcode return
|
||||
|
||||
PALcode instructions can only be issued in PALmode, or in kernel mode
|
||||
if the appropriate bit is set in ICSR.
|
||||
|
||||
EV5 implements 8 "PAL shadow" registers, which replace R8-R14, R25 in
|
||||
PALmode without save/restore; and 24 "PAL temporary" registers.
|
||||
|
||||
Internal registers fall into three groups: IBox IPRs, MBox IPRs, and
|
||||
PAL temporaries.
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
#include "alpha_ev5_defs.h"
|
||||
|
||||
t_uint64 ev5_palshad[PALSHAD_SIZE] = { 0 }; /* PAL shadow reg */
|
||||
t_uint64 ev5_palsave[PALSHAD_SIZE] = { 0 }; /* PAL save main */
|
||||
t_uint64 ev5_paltemp[PALTEMP_SIZE] = { 0 }; /* PAL temps */
|
||||
t_uint64 ev5_palbase = 0; /* PALcode base */
|
||||
t_uint64 ev5_excaddr = 0; /* exception address */
|
||||
t_uint64 ev5_isr = 0; /* intr summary */
|
||||
t_uint64 ev5_icsr = 0; /* IBox control */
|
||||
t_uint64 ev5_itb_pte = 0; /* ITLB pte */
|
||||
t_uint64 ev5_itb_pte_temp = 0; /* ITLB readout */
|
||||
t_uint64 ev5_ivptbr = 0; /* IBox virt ptbl */
|
||||
t_uint64 ev5_iva_form = 0; /* Ibox fmt'd VA */
|
||||
t_uint64 ev5_va = 0; /* Mbox VA */
|
||||
t_uint64 ev5_mvptbr = 0; /* Mbox virt ptbl */
|
||||
t_uint64 ev5_va_form = 0; /* Mbox fmt'd VA */
|
||||
t_uint64 ev5_dtb_pte = 0; /* DTLB pte */
|
||||
t_uint64 ev5_dtb_pte_temp = 0; /* DTLB readout */
|
||||
t_uint64 ev5_dc_test_tag = 0; /* Dcache test tag */
|
||||
t_uint64 ev5_dc_test_tag_temp = 0; /* Dcache tag readout */
|
||||
uint32 ev5_itb_tag = 0; /* ITLB tag (vpn) */
|
||||
uint32 ev5_dtb_tag = 0; /* DTLB tag (vpn) */
|
||||
uint32 ev5_icperr = 0; /* Icache par err */
|
||||
uint32 ev5_mm_stat = 0; /* MBox fault code */
|
||||
uint32 ev5_mcsr = 0; /* MBox control */
|
||||
uint32 ev5_alt_mode = 0; /* MBox alt mode */
|
||||
uint32 ev5_dc_mode = 0; /* Dcache mode */
|
||||
uint32 ev5_dcperr = 0; /* Dcache par err */
|
||||
uint32 ev5_dc_test_ctl = 0; /* Dcache test ctrl */
|
||||
uint32 ev5_maf_mode = 0; /* MAF mode */
|
||||
uint32 ev5_va_lock = 0; /* VA lock flag */
|
||||
uint32 ev5_mchk = 0; /* machine check pin */
|
||||
uint32 ev5_sli = 0; /* serial line intr */
|
||||
uint32 ev5_crd = 0; /* corr read data pin */
|
||||
uint32 ev5_pwrfl = 0; /* power fail pin */
|
||||
uint32 ev5_ipl = 0; /* ipl */
|
||||
uint32 ev5_sirr = 0; /* software int req */
|
||||
uint32 ev5_astrr = 0; /* AST requests */
|
||||
uint32 ev5_asten = 0; /* AST enables */
|
||||
const uint32 ast_map[4] = { 0x1, 0x3, 0x7, 0xF };
|
||||
|
||||
t_stat ev5_palent (t_uint64 fpc, uint32 off);
|
||||
t_stat ev5_palent_d (t_uint64 fpc, uint32 off, uint32 sta);
|
||||
t_stat pal_proc_reset_hwre (DEVICE *dptr);
|
||||
t_stat pal_proc_intr_ev5 (uint32 lvl);
|
||||
uint32 pal_eval_intr_ev5 (uint32 flag);
|
||||
|
||||
extern t_uint64 R[32];
|
||||
extern t_uint64 PC;
|
||||
extern t_uint64 trap_mask;
|
||||
extern t_uint64 p1;
|
||||
extern uint32 ir;
|
||||
extern uint32 vax_flag, lock_flag;
|
||||
extern uint32 fpen;
|
||||
extern uint32 pcc_h, pcc_l, pcc_enb;
|
||||
extern uint32 trap_summ;
|
||||
extern uint32 arch_mask;
|
||||
extern uint32 pal_mode, pal_type;
|
||||
extern uint32 int_req[IPL_HLVL];
|
||||
extern uint32 itlb_cm, dtlb_cm;
|
||||
extern uint32 itlb_asn, dtlb_asn;
|
||||
extern uint32 itlb_spage, dtlb_spage;
|
||||
extern jmp_buf save_env;
|
||||
extern uint32 pal_type;
|
||||
extern t_uint64 pcq[PCQ_SIZE]; /* PC queue */
|
||||
extern int32 pcq_p; /* PC queue ptr */
|
||||
|
||||
extern int32 parse_reg (char *cptr);
|
||||
|
||||
/* EV5PAL data structures
|
||||
|
||||
ev5pal_dev device descriptor
|
||||
ev5pal_unit unit
|
||||
ev5pal_reg register list
|
||||
*/
|
||||
|
||||
UNIT ev5pal_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
REG ev5pal_reg[] = {
|
||||
{ BRDATA (PALSHAD, ev5_palshad, 16, 64, PALSHAD_SIZE) },
|
||||
{ BRDATA (PALSAVE, ev5_palsave, 16, 64, PALSHAD_SIZE) },
|
||||
{ BRDATA (PALTEMP, ev5_paltemp, 16, 64, PALTEMP_SIZE) },
|
||||
{ HRDATA (PALBASE, ev5_palbase, 64) },
|
||||
{ HRDATA (EXCADDR, ev5_excaddr, 64) },
|
||||
{ HRDATA (IPL, ev5_ipl, 5) },
|
||||
{ HRDATA (SIRR, ev5_sirr, 15) },
|
||||
{ HRDATA (ASTRR, ev5_astrr, 4) },
|
||||
{ HRDATA (ASTEN, ev5_asten, 4) },
|
||||
{ HRDATA (ISR, ev5_isr, 35) },
|
||||
{ HRDATA (ICSR, ev5_icsr, 40) },
|
||||
{ HRDATA (ITB_TAG, ev5_itb_tag, 32) },
|
||||
{ HRDATA (ITB_PTE, ev5_itb_pte, 64) },
|
||||
{ HRDATA (ITB_PTE_TEMP, ev5_itb_pte_temp, 64) },
|
||||
{ HRDATA (IVA_FORM, ev5_iva_form, 64) },
|
||||
{ HRDATA (IVPTBR, ev5_ivptbr, 64) },
|
||||
{ HRDATA (ICPERR_STAT, ev5_icperr, 14) },
|
||||
{ HRDATA (VA, ev5_va, 64) },
|
||||
{ HRDATA (VA_FORM, ev5_va_form, 64) },
|
||||
{ HRDATA (MVPTBR, ev5_mvptbr, 64) },
|
||||
{ HRDATA (MM_STAT, ev5_mm_stat, 17) },
|
||||
{ HRDATA (MCSR, ev5_mcsr, 6) },
|
||||
{ HRDATA (DTB_TAG, ev5_dtb_tag, 32) },
|
||||
{ HRDATA (DTB_PTE, ev5_dtb_pte, 64) },
|
||||
{ HRDATA (DTB_PTE_TEMP, ev5_dtb_pte_temp, 64) },
|
||||
{ HRDATA (DC_MODE, ev5_dc_mode, 4) },
|
||||
{ HRDATA (DC_PERR_STAT, ev5_dcperr, 6) },
|
||||
{ HRDATA (DC_TEST_CTL, ev5_dc_test_ctl, 13) },
|
||||
{ HRDATA (DC_TEST_TAG, ev5_dc_test_tag, 39) },
|
||||
{ HRDATA (DC_TEST_TAG_TEMP, ev5_dc_test_tag_temp, 39) },
|
||||
{ HRDATA (MAF_MODE, ev5_maf_mode, 8) },
|
||||
{ FLDATA (VA_LOCK, ev5_va_lock, 0) },
|
||||
{ FLDATA (MCHK, ev5_mchk, 0) },
|
||||
{ FLDATA (CRD, ev5_crd, 0) },
|
||||
{ FLDATA (PWRFL, ev5_pwrfl, 0) },
|
||||
{ FLDATA (SLI, ev5_sli, 0) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
DEVICE ev5pal_dev = {
|
||||
"EV5PAL", &ev5pal_unit, ev5pal_reg, NULL,
|
||||
1, 16, 1, 1, 16, 8,
|
||||
NULL, NULL, &pal_proc_reset_hwre,
|
||||
NULL, NULL, NULL,
|
||||
NULL, DEV_DIS
|
||||
};
|
||||
|
||||
/* EV5 interrupt dispatch - reached from top of instruction loop -
|
||||
dispatch to PALcode */
|
||||
|
||||
t_stat pal_proc_intr (uint32 lvl)
|
||||
{
|
||||
return ev5_palent (PC, PALO_INTR);
|
||||
}
|
||||
|
||||
/* EV5 trap dispatch - reached from bottom of instruction loop -
|
||||
trap_mask and trap_summ are set up correctly - dispatch to PALcode */
|
||||
|
||||
t_stat pal_proc_trap (uint32 summ)
|
||||
{
|
||||
return ev5_palent (PC, PALO_TRAP);
|
||||
}
|
||||
|
||||
/* EV5 exception dispatch - reached from ABORT handler -
|
||||
set up any exception-specific registers - dispatch to PALcode */
|
||||
|
||||
t_stat pal_proc_excp (uint32 abval)
|
||||
{
|
||||
switch (abval) {
|
||||
|
||||
case EXC_RSVI: /* reserved instruction */
|
||||
return ev5_palent (PC, PALO_RSVI);
|
||||
|
||||
case EXC_ALIGN: /* unaligned */
|
||||
return ev5_palent (PC, PALO_ALGN);
|
||||
|
||||
case EXC_FPDIS: /* fp disabled */
|
||||
return ev5_palent (PC, PALO_FDIS);
|
||||
|
||||
case EXC_FOX+EXC_R: /* FOR */
|
||||
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_FOR);
|
||||
|
||||
case EXC_FOX+EXC_W: /* FOW */
|
||||
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_FOR|MM_STAT_WR);
|
||||
|
||||
case EXC_BVA+EXC_E: /* instr bad VA */
|
||||
case EXC_ACV+EXC_E: /* instr ACV */
|
||||
ev5_itb_tag = VA_GETVPN (PC); /* fault VPN */
|
||||
if (ev5_icsr & ICSR_NT) /* formatted addr */
|
||||
ev5_iva_form = ev5_ivptbr | FMT_IVA_NT (PC);
|
||||
else ev5_iva_form = ev5_ivptbr | FMT_IVA_VMS (PC);
|
||||
return ev5_palent (PC, PALO_IACV);
|
||||
|
||||
case EXC_ACV+EXC_R: /* data read ACV */
|
||||
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_ACV);
|
||||
|
||||
case EXC_ACV+EXC_W: /* data write ACV */
|
||||
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_ACV|MM_STAT_WR);
|
||||
|
||||
case EXC_BVA+EXC_R: /* data read bad addr */
|
||||
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_BVA);
|
||||
|
||||
case EXC_BVA+EXC_W: /* data write bad addr */
|
||||
return ev5_palent_d (PC, PALO_DFLT, MM_STAT_BVA|MM_STAT_WR);
|
||||
|
||||
case EXC_TBM + EXC_E: /* TLB miss */
|
||||
ev5_itb_tag = VA_GETVPN (PC); /* fault VPN */
|
||||
if (ev5_icsr & ICSR_NT) /* formatted addr */
|
||||
ev5_iva_form = ev5_ivptbr | FMT_IVA_NT (PC);
|
||||
else ev5_iva_form = ev5_ivptbr | FMT_IVA_VMS (PC);
|
||||
return ev5_palent (PC, PALO_ITBM);
|
||||
|
||||
case EXC_TBM + EXC_R: /* data TB miss read */
|
||||
if ((I_GETOP (ir) == HW_LD) && (ir & HW_LD_PTE))
|
||||
return ev5_palent_d (PC, PALO_DTBM_D, MM_STAT_TBM);
|
||||
return ev5_palent_d (PC, PALO_DTBM, MM_STAT_TBM);
|
||||
|
||||
case EXC_TBM + EXC_W: /* data TB miss write */
|
||||
if ((I_GETOP (ir) == HW_LD) && (ir & HW_LD_PTE))
|
||||
return ev5_palent_d (PC, PALO_DTBM_D, MM_STAT_TBM|MM_STAT_WR);
|
||||
return ev5_palent_d (PC, PALO_DTBM, MM_STAT_TBM|MM_STAT_WR);
|
||||
|
||||
case EXC_RSVO: /* reserved operand */
|
||||
case EXC_TNV+EXC_E: /* instr TNV */
|
||||
case EXC_TNV+EXC_R: /* data read TNV */
|
||||
case EXC_TNV+EXC_W: /* data write TNV */
|
||||
case EXC_FOX+EXC_E: /* FOE */
|
||||
return SCPE_IERR; /* should never get here */
|
||||
|
||||
default:
|
||||
return STOP_INVABO;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* EV5 call PAL - reached from instruction decoder -
|
||||
compute offset from function code - dispatch to PALcode */
|
||||
|
||||
t_stat pal_proc_inst (uint32 fnc)
|
||||
{
|
||||
uint32 off = (fnc & 0x3F) << 6;
|
||||
|
||||
if (fnc & 0x80) return ev5_palent (PC, PALO_CALLUNPR + off);
|
||||
if (itlb_cm != MODE_K) ABORT (EXC_RSVI);
|
||||
return ev5_palent (PC, PALO_CALLPR + off);
|
||||
}
|
||||
|
||||
/* EV5 evaluate interrupts - returns highest outstanding
|
||||
interrupt level about target ipl - plus nonmaskable flags
|
||||
|
||||
flag = 1: evaluate for real interrupt capability
|
||||
flag = 0: evaluate as though IPL = 0, normal mode */
|
||||
|
||||
uint32 pal_eval_intr (uint32 flag)
|
||||
{
|
||||
uint32 i, req = 0;
|
||||
uint32 lvl = flag? ev5_ipl: 0;
|
||||
|
||||
if (flag && pal_mode) return 0;
|
||||
if (ev5_mchk) req = IPL_1F;
|
||||
else if (ev5_crd && (ICSR & ICSR_CRDE)) req = IPL_CRD;
|
||||
else if (ev5_pwrfl) req = IPL_PWRFL;
|
||||
else if (int_req[3] && !(ICSR & ICSR_MSK3)) req = IPL_HMIN + 3;
|
||||
else if (int_req[2] && !(ICSR & ICSR_MSK2)) req = IPL_HMIN + 2;
|
||||
else if (int_req[1] && !(ICSR & ICSR_MSK1)) req = IPL_HMIN + 1;
|
||||
else if (int_req[0] && !(ICSR & ICSR_MSK0)) req = IPL_HMIN + 0;
|
||||
else if (ev5_sirr) {
|
||||
for (i = IPL_SMAX; i > 0; i--) { /* check swre int */
|
||||
if ((ev5_sirr >> (i - 1)) & 1) { /* req != 0? int */
|
||||
req = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((req < IPL_AST) && (ev5_astrr & ev5_asten & ast_map[itlb_cm]))
|
||||
req = IPL_AST;
|
||||
if (req <= lvl) req = 0;
|
||||
if (ev5_sli && (ICSR & ICSR_SLE)) req = req | IPL_SLI;
|
||||
if (ev5_isr & ISR_HALT) req = req | IPL_HALT;
|
||||
return req;
|
||||
}
|
||||
|
||||
/* EV5 enter PAL, data TLB miss/memory management flows -
|
||||
set Mbox registers - dispatch to PALcode */
|
||||
|
||||
t_stat ev5_palent_d (t_uint64 fpc, uint32 off, uint32 sta)
|
||||
{
|
||||
if (!ev5_va_lock) { /* not locked? */
|
||||
ev5_mm_stat = sta | /* merge IR<31:21> */
|
||||
((ir >> (I_V_RA - MM_STAT_V_RA)) & MM_STAT_IMASK);
|
||||
ev5_va = p1; /* fault address */
|
||||
if (ev5_mcsr & MCSR_NT) /* formatted VA */
|
||||
ev5_va_form = ev5_mvptbr | FMT_MVA_NT (p1);
|
||||
else ev5_va_form = ev5_mvptbr | FMT_MVA_VMS (p1);
|
||||
ev5_va_lock = 1; /* lock registers */
|
||||
}
|
||||
return ev5_palent (fpc, off);
|
||||
}
|
||||
|
||||
/* EV5 enter PAL */
|
||||
|
||||
t_stat ev5_palent (t_uint64 fpc, uint32 off)
|
||||
{
|
||||
ev5_excaddr = fpc | pal_mode; /* save exc addr */
|
||||
PCQ_ENTRY; /* save PC */
|
||||
PC = ev5_palbase + off; /* new PC */
|
||||
if (!pal_mode && (ev5_icsr & ICSR_SDE)) { /* entering PALmode? */
|
||||
PAL_USE_SHADOW; /* swap in shadows */
|
||||
}
|
||||
pal_mode = 1; /* in PAL mode */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* PAL instructions */
|
||||
|
||||
/* 1B: HW_LD */
|
||||
|
||||
t_stat pal_1b (uint32 ir)
|
||||
{
|
||||
t_uint64 dsp, ea, res;
|
||||
uint32 ra, rb, acc, mode;
|
||||
|
||||
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
|
||||
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
|
||||
ra = I_GETRA (ir); /* get ra */
|
||||
rb = I_GETRB (ir); /* get rb */
|
||||
dsp = HW_LD_GETDSP (ir); /* get displacement */
|
||||
ea = (R[rb] + (SEXT_HW_LD_DSP (dsp))) & M64; /* eff address */
|
||||
if (ir & HW_LD_V) { /* virtual? */
|
||||
mode = (ir & HW_LD_ALT)? ev5_alt_mode: dtlb_cm; /* access mode */
|
||||
acc = (ir & HW_LD_WCH)? ACC_W (mode): ACC_R (mode);
|
||||
if (ir & HW_LD_Q) res = ReadAccQ (ea, acc); /* quad? */
|
||||
else { /* long, sext */
|
||||
res = ReadAccL (ea, acc);
|
||||
res = SEXT_L_Q (res);
|
||||
}
|
||||
}
|
||||
else if (ir & HW_LD_Q) R[ra] = ReadPQ (ea); /* physical, quad? */
|
||||
else {
|
||||
res = ReadPL (ea); /* long, sext */
|
||||
res = SEXT_L_Q (res);
|
||||
}
|
||||
if (ir & HW_LD_LCK) lock_flag = 1; /* lock? set flag */
|
||||
if (ra != 31) R[ra] = res; /* if not R31, store */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* 1F: HW_ST */
|
||||
|
||||
t_stat pal_1f (uint32 ir)
|
||||
{
|
||||
t_uint64 dsp, ea;
|
||||
uint32 ra, rb, acc, mode;
|
||||
|
||||
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
|
||||
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
|
||||
ra = I_GETRA (ir); /* get ra */
|
||||
rb = I_GETRB (ir); /* get rb */
|
||||
dsp = HW_LD_GETDSP (ir); /* get displacement */
|
||||
ea = (R[rb] + (SEXT_HW_LD_DSP (dsp))) & M64; /* eff address */
|
||||
if ((ir & HW_LD_LCK) && !lock_flag) R[ra] = 0; /* lock fail? */
|
||||
else {
|
||||
if (ir & HW_LD_V) { /* virtual? */
|
||||
mode = (ir & HW_LD_ALT)? ev5_alt_mode: dtlb_cm; /* access mode */
|
||||
acc = ACC_W (mode);
|
||||
if (ir & HW_LD_Q) WriteAccQ (ea, R[ra], acc); /* quad? */
|
||||
else WriteAccL (ea, R[ra], acc); /* long */
|
||||
}
|
||||
else if (ir & HW_LD_Q) WritePQ (ea, R[ra]); /* physical, quad? */
|
||||
else WritePL (ea, R[ra]); /* long */
|
||||
if (ir & HW_LD_LCK) lock_flag = 0; /* unlock? clr flag */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* 1E: HW_REI */
|
||||
|
||||
t_stat pal_1e (uint32 ir)
|
||||
{
|
||||
uint32 new_pal = ((uint32) ev5_excaddr) & 1;
|
||||
|
||||
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
|
||||
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
|
||||
PCQ_ENTRY;
|
||||
PC = ev5_excaddr;
|
||||
if (pal_mode && !new_pal && (ev5_icsr & ICSR_SDE)) { /* leaving PAL mode? */
|
||||
PAL_USE_MAIN; /* swap out shadows */
|
||||
}
|
||||
pal_mode = new_pal;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* PAL move from processor registers */
|
||||
|
||||
t_stat pal_19 (uint32 ir)
|
||||
{
|
||||
t_uint64 res;
|
||||
uint32 fnc, ra;
|
||||
static const uint32 itbr_map_gh[4] = {
|
||||
ITBR_PTE_GH0, ITBR_PTE_GH1, ITBR_PTE_GH2, ITBR_PTE_GH3 };
|
||||
|
||||
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
|
||||
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
|
||||
fnc = I_GETMDSP (ir);
|
||||
ra = I_GETRA (ir);
|
||||
switch (fnc) {
|
||||
|
||||
case ISR: /* intr summary */
|
||||
res = ev5_isr | ((ev5_astrr & ev5_asten) << ISR_V_AST) |
|
||||
((ev5_sirr & SIRR_M_SIRR) << ISR_V_SIRR) |
|
||||
(int_req[0] && !(ev5_icsr & ICSR_MSK0)? ISR_IRQ0: 0) |
|
||||
(int_req[1] && !(ev5_icsr & ICSR_MSK1)? ISR_IRQ1: 0) |
|
||||
(int_req[2] && !(ev5_icsr & ICSR_MSK2)? ISR_IRQ2: 0) |
|
||||
(int_req[3] && !(ev5_icsr & ICSR_MSK3)? ISR_IRQ3: 0);
|
||||
if (ev5_astrr & ev5_asten & ast_map[itlb_cm]) res = res | ISR_ATR;
|
||||
break;
|
||||
|
||||
case ITB_PTE:
|
||||
res = itlb_read ();
|
||||
ev5_itb_pte_temp = (res & PFN_MASK) |
|
||||
((res & PTE_ASM)? ITBR_PTE_ASM: 0) |
|
||||
((res & (PTE_KRE|PTE_ERE|PTE_SRE|PTE_URE)) <<
|
||||
(ITBR_PTE_V_KRE - PTE_V_KRE)) |
|
||||
itbr_map_gh[PTE_GETGH (res)];
|
||||
res = 0;
|
||||
break;
|
||||
|
||||
case ITB_ASN:
|
||||
res = (itlb_asn & ITB_ASN_M_ASN) << ITB_ASN_V_ASN;
|
||||
break;
|
||||
|
||||
case ITB_PTE_TEMP:
|
||||
res = ev5_itb_pte_temp;
|
||||
break;
|
||||
|
||||
case SIRR:
|
||||
res = (ev5_sirr & SIRR_M_SIRR) << SIRR_V_SIRR;
|
||||
break;
|
||||
|
||||
case ASTRR:
|
||||
res = ev5_astrr & AST_MASK;
|
||||
break;
|
||||
|
||||
case ASTEN:
|
||||
res = ev5_asten & AST_MASK;
|
||||
break;
|
||||
|
||||
case EXC_ADDR:
|
||||
res = ev5_excaddr;
|
||||
break;
|
||||
|
||||
case EXC_SUMM:
|
||||
res = trap_summ & TRAP_SUMM_RW;
|
||||
break;
|
||||
|
||||
case EXC_MASK:
|
||||
res = trap_mask;
|
||||
break;
|
||||
|
||||
case PAL_BASE:
|
||||
res = ev5_palbase & PAL_BASE_RW;
|
||||
break;
|
||||
|
||||
case ICM:
|
||||
res = (itlb_cm & ICM_M_CM) << ICM_V_CM;
|
||||
break;
|
||||
|
||||
case IPLR:
|
||||
res = (ev5_ipl & IPLR_M_IPL) << IPLR_V_IPL;
|
||||
break;
|
||||
|
||||
case INTID:
|
||||
res = pal_eval_intr (0) & INTID_MASK;
|
||||
break;
|
||||
|
||||
case IFAULT_VA_FORM:
|
||||
res = ev5_iva_form;
|
||||
break;
|
||||
|
||||
case IVPTBR:
|
||||
res = ev5_ivptbr;
|
||||
break;
|
||||
|
||||
case ICSR:
|
||||
res = (ev5_icsr & ICSR_RW) | ICSR_MBO |
|
||||
((itlb_spage & ICSR_M_SPE) << ICSR_V_SPE) |
|
||||
((fpen & 1) << ICSR_V_FPE) |
|
||||
((arch_mask & AMASK_BWX)? ICSR_BSE: 0);
|
||||
break;
|
||||
|
||||
case PALTEMP+0x00: case PALTEMP+0x01: case PALTEMP+0x02: case PALTEMP+0x03:
|
||||
case PALTEMP+0x04: case PALTEMP+0x05: case PALTEMP+0x06: case PALTEMP+0x07:
|
||||
case PALTEMP+0x08: case PALTEMP+0x09: case PALTEMP+0x0A: case PALTEMP+0x0B:
|
||||
case PALTEMP+0x0C: case PALTEMP+0x0D: case PALTEMP+0x0E: case PALTEMP+0x0F:
|
||||
case PALTEMP+0x10: case PALTEMP+0x11: case PALTEMP+0x12: case PALTEMP+0x13:
|
||||
case PALTEMP+0x14: case PALTEMP+0x15: case PALTEMP+0x16: case PALTEMP+0x17:
|
||||
res = ev5_paltemp[fnc - PALTEMP];
|
||||
break;
|
||||
|
||||
case DTB_PTE:
|
||||
ev5_dtb_pte_temp = dtlb_read ();
|
||||
res = 0;
|
||||
break;
|
||||
|
||||
case DTB_PTE_TEMP:
|
||||
res = ev5_dtb_pte_temp;
|
||||
break;
|
||||
|
||||
case MM_STAT:
|
||||
res = ev5_mm_stat;
|
||||
break;
|
||||
|
||||
case VA:
|
||||
res = ev5_va;
|
||||
ev5_va_lock = 0;
|
||||
break;
|
||||
|
||||
case VA_FORM:
|
||||
res = ev5_va_form;
|
||||
break;
|
||||
|
||||
case DC_PERR_STAT:
|
||||
res = ev5_dcperr;
|
||||
break;
|
||||
|
||||
case MCSR:
|
||||
res = (ev5_mcsr & MCSR_RW) | ((dtlb_spage & MCSR_M_SPE) << MCSR_V_SPE);
|
||||
break;
|
||||
|
||||
case DC_MODE:
|
||||
res = ev5_dc_mode & DC_MODE_RW;
|
||||
break;
|
||||
|
||||
case MAF_MODE:
|
||||
res = ev5_maf_mode & MAF_MODE_RW;
|
||||
break;
|
||||
|
||||
case CC:
|
||||
res = (((t_uint64) pcc_h) << 32) | ((t_uint64) pcc_l);
|
||||
break;
|
||||
|
||||
case DC_TEST_CTL:
|
||||
res = ev5_dc_test_ctl & DC_TEST_CTL_RW;
|
||||
break;
|
||||
|
||||
case DC_TEST_TAG:
|
||||
// to be determined
|
||||
res = 0;
|
||||
break;
|
||||
|
||||
case DC_TEST_TAG_TEMP:
|
||||
res = ev5_dc_test_tag_temp & DC_TEST_TAG_RW;
|
||||
break;
|
||||
|
||||
default:
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ra != 31) R[ra] = res & M64;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* PAL move to processor registers */
|
||||
|
||||
t_stat pal_1d (uint32 ir)
|
||||
{
|
||||
uint32 fnc = I_GETMDSP (ir);
|
||||
uint32 ra = I_GETRA (ir);
|
||||
t_uint64 val = R[ra];
|
||||
|
||||
if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */
|
||||
!(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */
|
||||
switch (fnc) {
|
||||
|
||||
case ITB_TAG:
|
||||
ev5_itb_tag = VA_GETVPN (val);
|
||||
break;
|
||||
|
||||
case ITB_PTE:
|
||||
ev5_itb_pte = (val | PTE_V) & (PFN_MASK | ((t_uint64) (PTE_ASM | PTE_GH |
|
||||
PTE_KRE | PTE_ERE | PTE_SRE | PTE_URE)));
|
||||
itlb_load (ev5_itb_tag, ev5_itb_pte);
|
||||
break;
|
||||
|
||||
case ITB_ASN:
|
||||
itlb_set_asn ((((uint32) val) >> ITB_ASN_V_ASN) & ITB_ASN_M_ASN);
|
||||
break;
|
||||
|
||||
case ITB_IA:
|
||||
tlb_ia (TLB_CI | TLB_CA);
|
||||
break;
|
||||
|
||||
case ITB_IAP:
|
||||
tlb_ia (TLB_CI);
|
||||
break;
|
||||
|
||||
case ITB_IS:
|
||||
tlb_is (val, TLB_CI);
|
||||
break;
|
||||
|
||||
case SIRR:
|
||||
ev5_sirr = (((uint32) val) >> SIRR_V_SIRR) & SIRR_M_SIRR;
|
||||
break;
|
||||
|
||||
case ASTRR:
|
||||
ev5_astrr = ((uint32) val) & AST_MASK;
|
||||
break;
|
||||
|
||||
case ASTEN:
|
||||
ev5_asten = ((uint32) val) & AST_MASK;
|
||||
break;
|
||||
|
||||
case EXC_ADDR:
|
||||
ev5_excaddr = val;
|
||||
break;
|
||||
|
||||
case EXC_SUMM:
|
||||
trap_summ = 0;
|
||||
trap_mask = 0;
|
||||
break;
|
||||
|
||||
case PAL_BASE:
|
||||
ev5_palbase = val & PAL_BASE_RW;
|
||||
break;
|
||||
|
||||
case ICM:
|
||||
itlb_set_cm ((((uint32) val) >> ICM_V_CM) & ICM_M_CM);
|
||||
break;
|
||||
|
||||
case IPLR:
|
||||
ev5_ipl = (((uint32) val) >> IPLR_V_IPL) & IPLR_M_IPL;
|
||||
break;
|
||||
|
||||
case IVPTBR:
|
||||
if (ev5_icsr & ICSR_NT) ev5_ivptbr = val & IVPTBR_NT;
|
||||
else ev5_ivptbr = val & IVPTBR_VMS;
|
||||
break;
|
||||
|
||||
case HWINT_CLR:
|
||||
ev5_isr = ev5_isr & ~(val & HWINT_CLR_W1C);
|
||||
break;
|
||||
|
||||
case ICSR:
|
||||
if (pal_mode && ((val ^ ev5_icsr) & ICSR_SDE)) {
|
||||
if (val & ICSR_SDE) { PAL_USE_SHADOW; }
|
||||
else { PAL_USE_MAIN; }
|
||||
}
|
||||
ev5_icsr = val & ICSR_RW;
|
||||
itlb_set_spage ((((uint32) val) >> ICSR_V_SPE) & ICSR_M_SPE);
|
||||
fpen = (((uint32) val) >> ICSR_V_FPE) & 1;
|
||||
if (val & ICSR_BSE) arch_mask = arch_mask | AMASK_BWX;
|
||||
else arch_mask = arch_mask & ~AMASK_BWX;
|
||||
break;
|
||||
|
||||
case ICPERR_STAT:
|
||||
ev5_icperr = ev5_icperr & ~(((uint32) val) & ICPERR_W1C);
|
||||
break;
|
||||
|
||||
case PALTEMP+0x00: case PALTEMP+0x01: case PALTEMP+0x02: case PALTEMP+0x03:
|
||||
case PALTEMP+0x04: case PALTEMP+0x05: case PALTEMP+0x06: case PALTEMP+0x07:
|
||||
case PALTEMP+0x08: case PALTEMP+0x09: case PALTEMP+0x0A: case PALTEMP+0x0B:
|
||||
case PALTEMP+0x0C: case PALTEMP+0x0D: case PALTEMP+0x0E: case PALTEMP+0x0F:
|
||||
case PALTEMP+0x10: case PALTEMP+0x11: case PALTEMP+0x12: case PALTEMP+0x13:
|
||||
case PALTEMP+0x14: case PALTEMP+0x15: case PALTEMP+0x16: case PALTEMP+0x17:
|
||||
ev5_paltemp[fnc - PALTEMP] = val;
|
||||
break;
|
||||
|
||||
case DTB_ASN:
|
||||
dtlb_set_asn ((((uint32) val) >> DTB_ASN_V_ASN) & DTB_ASN_M_ASN);
|
||||
break;
|
||||
|
||||
case DTB_CM:
|
||||
dtlb_set_cm ((((uint32) val) >> ICM_V_CM) & ICM_M_CM);
|
||||
break;
|
||||
|
||||
case DTB_TAG:
|
||||
ev5_dtb_tag = VA_GETVPN (val);
|
||||
val = (val | PTE_V) & (PFN_MASK | ((t_uint64) (PTE_MASK & ~PTE_FOE)));
|
||||
dtlb_load (ev5_dtb_tag, val);
|
||||
break;
|
||||
|
||||
case DTB_PTE:
|
||||
ev5_dtb_pte = val;
|
||||
break;
|
||||
|
||||
case MVPTBR:
|
||||
ev5_mvptbr = val & ~MVPTBR_MBZ;
|
||||
break;
|
||||
|
||||
case DC_PERR_STAT:
|
||||
ev5_dcperr = ev5_dcperr & ~(((uint32) val) & DC_PERR_W1C);
|
||||
if ((ev5_dcperr & DC_PERR_W1C) == 0) ev5_dcperr = 0;
|
||||
break;
|
||||
|
||||
case DTB_IA:
|
||||
tlb_ia (TLB_CD | TLB_CA);
|
||||
break;
|
||||
|
||||
case DTB_IAP:
|
||||
tlb_ia (TLB_CD);
|
||||
break;
|
||||
|
||||
case DTB_IS:
|
||||
tlb_is (val, TLB_CD);
|
||||
break;
|
||||
|
||||
case MCSR:
|
||||
ev5_mcsr = ((uint32) val) & MCSR_RW;
|
||||
dtlb_set_spage ((((uint32) val) >> MCSR_V_SPE) & MCSR_M_SPE);
|
||||
if (ev5_mcsr & MCSR_NT) pal_type = PAL_NT;
|
||||
break;
|
||||
|
||||
case DC_MODE:
|
||||
ev5_dc_mode = ((uint32) val) & DC_MODE_RW;
|
||||
break;
|
||||
|
||||
case MAF_MODE:
|
||||
ev5_maf_mode = ((uint32) val) & MAF_MODE_RW;
|
||||
break;
|
||||
|
||||
case CC:
|
||||
pcc_h = (uint32) ((val >> 32) & M32);
|
||||
break;
|
||||
|
||||
case CC_CTL:
|
||||
pcc_l = ((uint32) val) & (M32 & ~CC_CTL_MBZ);
|
||||
if (val & CC_CTL_ENB) pcc_enb = 1;
|
||||
else pcc_enb = 0;
|
||||
break;
|
||||
|
||||
case DC_TEST_CTL:
|
||||
ev5_dc_test_ctl = ((uint32) val) & DC_TEST_CTL_RW;
|
||||
break;
|
||||
|
||||
case DC_TEST_TAG:
|
||||
ev5_dc_test_tag = val & DC_TEST_TAG_RW;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* EV5 PALcode reset */
|
||||
|
||||
t_stat pal_proc_reset_hwre (DEVICE *dptr)
|
||||
{
|
||||
ev5_palbase = 0;
|
||||
ev5_mchk = 0;
|
||||
ev5_pwrfl = 0;
|
||||
ev5_crd = 0;
|
||||
ev5_sli = 0;
|
||||
itlb_set_cm (MODE_K);
|
||||
itlb_set_asn (0);
|
||||
itlb_set_spage (0);
|
||||
dtlb_set_cm (MODE_K);
|
||||
dtlb_set_asn (0);
|
||||
dtlb_set_spage (0);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* EV5 PAL instruction print and parse routines */
|
||||
|
||||
static const char *pal_inam[] = {
|
||||
"HW_MFPR", "HW_LD", "HW_MTPR", "HW_REI", "HW_ST", NULL
|
||||
};
|
||||
|
||||
static const uint32 pal_ival[] = {
|
||||
0x64000000, 0x6C000000, 0x74000000, 0x7BFF8000, 0x7C000000
|
||||
};
|
||||
|
||||
struct pal_opt {
|
||||
uint32 mask; /* bit mask */
|
||||
char let; /* matching letter */
|
||||
};
|
||||
|
||||
static struct pal_opt ld_st_opt[] = {
|
||||
{ HW_LD_V, 'V' },
|
||||
{ HW_LD_ALT, 'A' },
|
||||
{ HW_LD_WCH, 'W' },
|
||||
{ HW_LD_Q, 'Q' },
|
||||
{ HW_LD_PTE, 'P' },
|
||||
{ HW_LD_LCK, 'L' },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static struct pal_opt rei_opt[] = {
|
||||
{ HW_REI_S, 'S' },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* Print options for hardware PAL instruction */
|
||||
|
||||
void fprint_opt_ev5 (FILE *of, uint32 inst, struct pal_opt opt[])
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; opt[i].mask != 0; i++) {
|
||||
if (inst & opt[i].mask) {
|
||||
fprintf (of, "/%c", opt[i].let);
|
||||
inst = inst & ~opt[i].mask;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse options for hardware PAL instruction */
|
||||
|
||||
char *parse_opt_ev5 (char *cptr, uint32 *val, struct pal_opt opt[])
|
||||
{
|
||||
uint32 i;
|
||||
char *tptr, gbuf[CBUFSIZE];
|
||||
|
||||
if (*(cptr - 1) != '/') return cptr;
|
||||
cptr = get_glyph (cptr - 1, tptr = gbuf, 0);
|
||||
while (*tptr == '/') {
|
||||
tptr++;
|
||||
for (i = 0; opt[i].mask != 0; i++) {
|
||||
if (*tptr == opt[i].let) {
|
||||
*val = *val | opt[i].mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (opt[i].mask == 0) return NULL;
|
||||
tptr++;
|
||||
}
|
||||
if (*tptr != 0) return NULL;
|
||||
return cptr;
|
||||
}
|
||||
|
||||
/* Print PAL hardware opcode symbolically */
|
||||
|
||||
t_stat fprint_pal_hwre (FILE *of, uint32 inst)
|
||||
{
|
||||
uint32 op, ra, rb;
|
||||
|
||||
op = I_GETOP (inst);
|
||||
ra = I_GETRA (inst);
|
||||
rb = I_GETRB (inst);
|
||||
switch (op) {
|
||||
|
||||
case OP_PAL19: /* HW_MFPR */
|
||||
case OP_PAL1D: /* HW_MTPR */
|
||||
fputs ((op == OP_PAL19)? "HW_MFPR": "HW_MTPR", of);
|
||||
fprintf (of, " R%d,%X", ra, inst & M16);
|
||||
break;
|
||||
|
||||
case OP_PAL1B: /* HW_LD */
|
||||
case OP_PAL1F: /* HW_ST */
|
||||
fputs ((op == OP_PAL1B)? "HW_LD": "HW_ST", of);
|
||||
fprint_opt_ev5 (of, inst, ld_st_opt);
|
||||
fprintf (of, " R%d,%X", ra, inst & HW_LD_DSP);
|
||||
if (rb != 31) fprintf (of, "(R%d)", rb);
|
||||
break;
|
||||
|
||||
case OP_PAL1E: /* HW_REI */
|
||||
fputs ("HW_REI", of);
|
||||
fprint_opt_ev5 (of, inst, rei_opt);
|
||||
break;
|
||||
|
||||
default:
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Parse PAL hardware opcode symbolically */
|
||||
|
||||
t_stat parse_pal_hwre (char *cptr, t_value *inst)
|
||||
{
|
||||
uint32 i, d, val = 0;
|
||||
int32 reg;
|
||||
char *tptr, gbuf[CBUFSIZE];
|
||||
t_stat r;
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, '/');
|
||||
for (i = 0; pal_inam[i] != NULL; i++) {
|
||||
if (strcmp (gbuf, pal_inam[i]) == 0) val = pal_ival[i];
|
||||
}
|
||||
if (val == 0) return SCPE_ARG;
|
||||
switch (I_GETOP (val)) {
|
||||
|
||||
case OP_PAL19: /* HW_MFPR */
|
||||
case OP_PAL1D: /* HW_MTPR */
|
||||
if (*(cptr - 1) == '/') return SCPE_ARG;
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get reg */
|
||||
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
|
||||
val = val | (reg << I_V_RA) | (reg << I_V_RB);
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get ipr */
|
||||
d = (uint32) get_uint (gbuf, 16, M16, &r);
|
||||
if (r != SCPE_OK) return r;
|
||||
val = val | d;
|
||||
break;
|
||||
|
||||
case OP_PAL1B: /* HW_LD */
|
||||
case OP_PAL1F: /* HW_ST */
|
||||
cptr = parse_opt_ev5 (cptr, &val, ld_st_opt);
|
||||
if (cptr == NULL) return SCPE_ARG;
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get reg */
|
||||
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
|
||||
val = val | (reg << I_V_RA);
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
d = (uint32) strtotv (gbuf, &tptr, 16);
|
||||
if ((gbuf == tptr) || (d > HW_LD_DSP)) return SCPE_ARG;
|
||||
val = val | d;
|
||||
if (*tptr == '(') {
|
||||
tptr = get_glyph (tptr + 1, gbuf, ')');
|
||||
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
|
||||
val = val | (reg << I_V_RB);
|
||||
}
|
||||
else val = val | (31 << I_V_RB);
|
||||
break;
|
||||
|
||||
case OP_PAL1E: /* HW_REI */
|
||||
cptr = parse_opt_ev5 (cptr, &val, rei_opt);
|
||||
if (cptr == NULL) return SCPE_ARG;
|
||||
break;
|
||||
|
||||
default:
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
*inst = val;
|
||||
if (*cptr != 0) return SCPE_ARG;
|
||||
return -3;
|
||||
}
|
||||
|
||||
566
Alpha/alpha_ev5_tlb.c
Normal file
566
Alpha/alpha_ev5_tlb.c
Normal file
@ -0,0 +1,566 @@
|
||||
/* alpha_ev5_tlb.c - Alpha EV5 TLB simulator
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
EV5 was the second generation Alpha CPU. It was a four-way, in order issue
|
||||
CPU with onchip primary instruction and data caches, an onchip second level
|
||||
cache, and support for an offchip third level cache. EV56 was a shrink, with
|
||||
added support for byte and word operations. EV56PC was a version of EV56
|
||||
without the onchip second level cache.
|
||||
|
||||
This module contains the routines for
|
||||
|
||||
itlb_lookup lookup vpn in instruction TLB
|
||||
itlb_load load pte into instruction TLB
|
||||
itlb_read read pte from instruction TLB using NLU pointer
|
||||
itlb_set_asn set iasn
|
||||
itlb_set_cm set icm
|
||||
itlb_set_spage set ispage
|
||||
dtlb_lookup lookup vpn in data TLB
|
||||
dtlb_load load pte into data TLB
|
||||
dtlb_read read pte from data TLB using NLU pointer
|
||||
dtlb_set_asn set dasn
|
||||
dtlb_set_cm set dcm
|
||||
dtlb_set_spage set dspage
|
||||
tlb_ia TLB invalidate all
|
||||
tlb_is TLB invalidate single
|
||||
tlb_set_cm TLB set current mode
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
#include "alpha_ev5_defs.h"
|
||||
|
||||
#define ITLB_SORT qsort (itlb, ITLB_SIZE, sizeof (TLBENT), &tlb_comp);
|
||||
#define DTLB_SORT qsort (dtlb, DTLB_SIZE, sizeof (TLBENT), &tlb_comp);
|
||||
#define TLB_ESIZE (sizeof (TLBENT)/sizeof (uint32))
|
||||
#define MM_RW(x) (((x) & PTE_FOW)? EXC_W: EXC_R)
|
||||
|
||||
uint32 itlb_cm = 0; /* current modes */
|
||||
uint32 itlb_spage = 0; /* superpage enables */
|
||||
uint32 itlb_asn = 0;
|
||||
uint32 itlb_nlu = 0;
|
||||
TLBENT i_mini_tlb;
|
||||
TLBENT itlb[ITLB_SIZE];
|
||||
uint32 dtlb_cm = 0;
|
||||
uint32 dtlb_spage = 0;
|
||||
uint32 dtlb_asn = 0;
|
||||
uint32 dtlb_nlu = 0;
|
||||
TLBENT d_mini_tlb;
|
||||
TLBENT dtlb[DTLB_SIZE];
|
||||
|
||||
uint32 cm_eacc = ACC_E (MODE_K); /* precomputed */
|
||||
uint32 cm_racc = ACC_R (MODE_K); /* access checks */
|
||||
uint32 cm_wacc = ACC_W (MODE_K);
|
||||
uint32 cm_macc = ACC_M (MODE_K);
|
||||
|
||||
extern t_uint64 p1;
|
||||
extern jmp_buf save_env;
|
||||
|
||||
uint32 mm_exc (uint32 macc);
|
||||
void tlb_inval (TLBENT *tlbp);
|
||||
t_stat itlb_reset (void);
|
||||
t_stat dtlb_reset (void);
|
||||
int tlb_comp (const void *e1, const void *e2);
|
||||
t_stat tlb_reset (DEVICE *dptr);
|
||||
|
||||
/* TLB data structures
|
||||
|
||||
tlb_dev pager device descriptor
|
||||
tlb_unit pager units
|
||||
tlb_reg pager register list
|
||||
*/
|
||||
|
||||
UNIT tlb_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
REG tlb_reg[] = {
|
||||
{ HRDATA (ICM, itlb_cm, 2) },
|
||||
{ HRDATA (ISPAGE, itlb_spage, 2), REG_HRO },
|
||||
{ HRDATA (IASN, itlb_asn, ITB_ASN_WIDTH) },
|
||||
{ HRDATA (INLU, itlb_nlu, ITLB_WIDTH) },
|
||||
{ BRDATA (IMINI, &i_mini_tlb, 16, 32, TLB_ESIZE) },
|
||||
{ BRDATA (ITLB, itlb, 16, 32, ITLB_SIZE*TLB_ESIZE) },
|
||||
{ HRDATA (DCM, dtlb_cm, 2) },
|
||||
{ HRDATA (DSPAGE, dtlb_spage, 2), REG_HRO },
|
||||
{ HRDATA (DASN, dtlb_asn, DTB_ASN_WIDTH) },
|
||||
{ HRDATA (DNLU, dtlb_nlu, DTLB_WIDTH) },
|
||||
{ BRDATA (DMINI, &d_mini_tlb, 16, 32, TLB_ESIZE) },
|
||||
{ BRDATA (DTLB, dtlb, 16, 32, DTLB_SIZE*TLB_ESIZE) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
DEVICE tlb_dev = {
|
||||
"TLB", &tlb_unit, tlb_reg, NULL,
|
||||
1, 0, 0, 1, 0, 0,
|
||||
NULL, NULL, &tlb_reset,
|
||||
NULL, NULL, NULL
|
||||
};
|
||||
|
||||
/* Translate address, instruction, data, and console
|
||||
|
||||
Inputs:
|
||||
va = virtual address
|
||||
acc = (VAX only) access mode
|
||||
Outputs:
|
||||
pa = translation buffer index
|
||||
*/
|
||||
|
||||
t_uint64 trans_i (t_uint64 va)
|
||||
{
|
||||
uint32 va_sext = VA_GETSEXT (va);
|
||||
uint32 vpn = VA_GETVPN (va);
|
||||
TLBENT *tlbp;
|
||||
|
||||
if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */
|
||||
ABORT1 (va, EXC_BVA + EXC_E);
|
||||
if ((itlb_spage & SPEN_43) && VPN_GETSP43 (vpn) == 2) { /* 43b superpage? */
|
||||
if (itlb_cm != MODE_K) ABORT1 (va, EXC_ACV + EXC_E);
|
||||
return (va & SP43_MASK);
|
||||
}
|
||||
if ((itlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) {
|
||||
if (itlb_cm != MODE_K) ABORT1 (va, EXC_ACV + EXC_E);
|
||||
return (va & SP32_MASK); /* 32b superpage? */
|
||||
}
|
||||
if (!(tlbp = itlb_lookup (vpn))) /* lookup vpn; miss? */
|
||||
ABORT1 (va, EXC_TBM + EXC_E); /* abort reference */
|
||||
if (cm_eacc & ~tlbp->pte) /* check access */
|
||||
ABORT1 (va, mm_exc (cm_eacc & ~tlbp->pte) | EXC_E);
|
||||
return PHYS_ADDR (tlbp->pfn, va); /* return phys addr */
|
||||
}
|
||||
|
||||
t_uint64 trans_d (t_uint64 va, uint32 acc)
|
||||
{
|
||||
uint32 va_sext = VA_GETSEXT (va);
|
||||
uint32 vpn = VA_GETVPN (va);
|
||||
TLBENT *tlbp;
|
||||
|
||||
if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */
|
||||
ABORT1 (va, EXC_BVA + MM_RW (acc));
|
||||
if ((dtlb_spage & SPEN_43) && (VPN_GETSP43 (vpn) == 2)) {
|
||||
if (dtlb_cm != MODE_K) ABORT1 (va, EXC_ACV + MM_RW (acc));
|
||||
return (va & SP43_MASK); /* 43b superpage? */
|
||||
}
|
||||
if ((dtlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) {
|
||||
if (dtlb_cm != MODE_K) ABORT1 (va, EXC_ACV + MM_RW (acc));
|
||||
return (va & SP32_MASK); /* 32b superpage? */
|
||||
}
|
||||
if (!(tlbp = dtlb_lookup (vpn))) /* lookup vpn; miss? */
|
||||
ABORT1 (va, EXC_TBM + MM_RW (acc)); /* abort reference */
|
||||
if (acc & ~tlbp->pte) /* check access */
|
||||
ABORT1 (va, mm_exc (acc & ~tlbp->pte) | MM_RW (acc));
|
||||
return PHYS_ADDR (tlbp->pfn, va); /* return phys addr */
|
||||
}
|
||||
|
||||
/* Generate a memory management error code, based on the access check bits not
|
||||
set in PTE
|
||||
|
||||
- If the access check bits, without FOx and V, fail, then ACV
|
||||
- If FOx set, then FOx
|
||||
- Otherwise, TNV */
|
||||
|
||||
uint32 mm_exc (uint32 not_set)
|
||||
{
|
||||
uint32 tacc;
|
||||
|
||||
tacc = not_set & ~(PTE_FOR | PTE_FOW | PTE_FOE | PTE_V);
|
||||
if (tacc) return EXC_ACV;
|
||||
tacc = not_set & (PTE_FOR | PTE_FOW | PTE_FOE);
|
||||
if (tacc) return EXC_FOX;
|
||||
return EXC_TNV;
|
||||
}
|
||||
|
||||
/* TLB invalidate single */
|
||||
|
||||
void tlb_is (t_uint64 va, uint32 flags)
|
||||
{
|
||||
uint32 va_sext = VA_GETSEXT (va);
|
||||
uint32 vpn = VA_GETVPN (va);
|
||||
TLBENT *itlbp, *dtlbp;
|
||||
|
||||
if ((va_sext != 0) && (va_sext != VA_M_SEXT)) return;
|
||||
if ((flags & TLB_CI) && (itlbp = itlb_lookup (vpn))) {
|
||||
tlb_inval (itlbp);
|
||||
tlb_inval (&i_mini_tlb);
|
||||
ITLB_SORT;
|
||||
}
|
||||
if ((flags & TLB_CD) && (dtlbp = dtlb_lookup (vpn))) {
|
||||
tlb_inval (dtlbp);
|
||||
tlb_inval (&d_mini_tlb);
|
||||
DTLB_SORT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* TLB invalidate all */
|
||||
|
||||
void tlb_ia (uint32 flags)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
if (flags & TLB_CA) {
|
||||
if (flags & TLB_CI) itlb_reset ();
|
||||
if (flags & TLB_CD) dtlb_reset ();
|
||||
return;
|
||||
}
|
||||
if (flags & TLB_CI) {
|
||||
for (i = 0; i < ITLB_SIZE; i++) {
|
||||
if (!(itlb[i].pte & PTE_ASM)) tlb_inval (&itlb[i]);
|
||||
}
|
||||
tlb_inval (&i_mini_tlb);
|
||||
ITLB_SORT;
|
||||
}
|
||||
if (flags & TLB_CD) {
|
||||
for (i = 0; i < DTLB_SIZE; i++) {
|
||||
if (!(dtlb[i].pte & PTE_ASM)) tlb_inval (&dtlb[i]);
|
||||
}
|
||||
tlb_inval (&d_mini_tlb);
|
||||
DTLB_SORT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* TLB lookup */
|
||||
|
||||
TLBENT *itlb_lookup (uint32 vpn)
|
||||
{
|
||||
int32 p, hi, lo;
|
||||
|
||||
if (vpn == i_mini_tlb.tag) return &i_mini_tlb;
|
||||
lo = 0; /* initial bounds */
|
||||
hi = ITLB_SIZE - 1;
|
||||
do {
|
||||
p = (lo + hi) >> 1; /* probe */
|
||||
if ((itlb_asn == itlb[p].asn) &&
|
||||
(((vpn ^ itlb[p].tag) &
|
||||
~((uint32) itlb[p].gh_mask)) == 0)) { /* match to TLB? */
|
||||
i_mini_tlb.tag = vpn;
|
||||
i_mini_tlb.pte = itlb[p].pte;
|
||||
i_mini_tlb.pfn = itlb[p].pfn;
|
||||
itlb_nlu = itlb[p].idx + 1;
|
||||
if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0;
|
||||
return &i_mini_tlb;
|
||||
}
|
||||
if ((itlb_asn < itlb[p].asn) ||
|
||||
((itlb_asn == itlb[p].asn) && (vpn < itlb[p].tag)))
|
||||
hi = p - 1; /* go down? p is upper */
|
||||
else lo = p + 1; /* go up? p is lower */
|
||||
}
|
||||
while (lo <= hi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TLBENT *dtlb_lookup (uint32 vpn)
|
||||
{
|
||||
int32 p, hi, lo;
|
||||
|
||||
if (vpn == d_mini_tlb.tag) return &d_mini_tlb;
|
||||
lo = 0; /* initial bounds */
|
||||
hi = DTLB_SIZE - 1;
|
||||
do {
|
||||
p = (lo + hi) >> 1; /* probe */
|
||||
if ((dtlb_asn == dtlb[p].asn) &&
|
||||
(((vpn ^ dtlb[p].tag) &
|
||||
~((uint32) dtlb[p].gh_mask)) == 0)) { /* match to TLB? */
|
||||
d_mini_tlb.tag = vpn;
|
||||
d_mini_tlb.pte = dtlb[p].pte;
|
||||
d_mini_tlb.pfn = dtlb[p].pfn;
|
||||
dtlb_nlu = dtlb[p].idx + 1;
|
||||
if (dtlb_nlu >= DTLB_SIZE) dtlb_nlu = 0;
|
||||
return &d_mini_tlb;
|
||||
}
|
||||
if ((dtlb_asn < dtlb[p].asn) ||
|
||||
((dtlb_asn == dtlb[p].asn) && (vpn < dtlb[p].tag)))
|
||||
hi = p - 1; /* go down? p is upper */
|
||||
else lo = p + 1; /* go up? p is lower */
|
||||
}
|
||||
while (lo <= hi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Load TLB entry at NLU pointer, advance NLU pointer */
|
||||
|
||||
TLBENT *itlb_load (uint32 vpn, t_uint64 l3pte)
|
||||
{
|
||||
uint32 i, gh;
|
||||
|
||||
for (i = 0; i < ITLB_SIZE; i++) {
|
||||
if (itlb[i].idx == itlb_nlu) {
|
||||
TLBENT *tlbp = itlb + i;
|
||||
itlb_nlu = itlb_nlu + 1;
|
||||
if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0;
|
||||
tlbp->tag = vpn;
|
||||
tlbp->pte = (uint32) (l3pte & PTE_MASK) ^ (PTE_FOR|PTE_FOR|PTE_FOE);
|
||||
tlbp->pfn = ((uint32) (l3pte >> PTE_V_PFN)) & PFN_MASK;
|
||||
tlbp->asn = itlb_asn;
|
||||
gh = PTE_GETGH (tlbp->pte);
|
||||
tlbp->gh_mask = (1u << (3 * gh)) - 1;
|
||||
tlb_inval (&i_mini_tlb);
|
||||
ITLB_SORT;
|
||||
return tlbp;
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "%%ITLB entry not found, itlb_nlu = %d\n", itlb_nlu);
|
||||
ABORT (-SCPE_IERR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TLBENT *dtlb_load (uint32 vpn, t_uint64 l3pte)
|
||||
{
|
||||
uint32 i, gh;
|
||||
|
||||
for (i = 0; i < DTLB_SIZE; i++) {
|
||||
if (dtlb[i].idx == dtlb_nlu) {
|
||||
TLBENT *tlbp = dtlb + i;
|
||||
dtlb_nlu = dtlb_nlu + 1;
|
||||
if (dtlb_nlu >= ITLB_SIZE) dtlb_nlu = 0;
|
||||
tlbp->tag = vpn;
|
||||
tlbp->pte = (uint32) (l3pte & PTE_MASK) ^ (PTE_FOR|PTE_FOR|PTE_FOE);
|
||||
tlbp->pfn = ((uint32) (l3pte >> PTE_V_PFN)) & PFN_MASK;
|
||||
tlbp->asn = dtlb_asn;
|
||||
gh = PTE_GETGH (tlbp->pte);
|
||||
tlbp->gh_mask = (1u << (3 * gh)) - 1;
|
||||
tlb_inval (&d_mini_tlb);
|
||||
DTLB_SORT;
|
||||
return tlbp;
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "%%DTLB entry not found, dtlb_nlu = %d\n", dtlb_nlu);
|
||||
ABORT (-SCPE_IERR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read TLB entry at NLU pointer, advance NLU pointer */
|
||||
|
||||
t_uint64 itlb_read (void)
|
||||
{
|
||||
uint8 i;
|
||||
|
||||
for (i = 0; i < ITLB_SIZE; i++) {
|
||||
if (itlb[i].idx == itlb_nlu) {
|
||||
TLBENT *tlbp = itlb + i;
|
||||
itlb_nlu = itlb_nlu + 1;
|
||||
if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0;
|
||||
return (((t_uint64) tlbp->pfn) << PTE_V_PFN) |
|
||||
((tlbp->pte ^ (PTE_FOR|PTE_FOR|PTE_FOE)) & PTE_MASK);
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "%%ITLB entry not found, itlb_nlu = %d\n", itlb_nlu);
|
||||
ABORT (-SCPE_IERR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_uint64 dtlb_read (void)
|
||||
{
|
||||
uint8 i;
|
||||
|
||||
for (i = 0; i < DTLB_SIZE; i++) {
|
||||
if (dtlb[i].idx == dtlb_nlu) {
|
||||
TLBENT *tlbp = dtlb + i;
|
||||
dtlb_nlu = dtlb_nlu + 1;
|
||||
if (dtlb_nlu >= DTLB_SIZE) dtlb_nlu = 0;
|
||||
return (((t_uint64) tlbp->pfn) << PTE_V_PFN) |
|
||||
((tlbp->pte ^ (PTE_FOR|PTE_FOR|PTE_FOE)) & PTE_MASK);
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "%%DTLB entry not found, dtlb_nlu = %d\n", dtlb_nlu);
|
||||
ABORT (-SCPE_IERR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set ASN - rewrite TLB globals with correct ASN */
|
||||
|
||||
void itlb_set_asn (uint32 asn)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
itlb_asn = asn;
|
||||
for (i = 0; i < ITLB_SIZE; i++) {
|
||||
if (itlb[i].pte & PTE_ASM) itlb[i].asn = asn;
|
||||
}
|
||||
tlb_inval (&i_mini_tlb);
|
||||
ITLB_SORT;
|
||||
return;
|
||||
}
|
||||
|
||||
void dtlb_set_asn (uint32 asn)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
dtlb_asn = asn;
|
||||
for (i = 0; i < DTLB_SIZE; i++) {
|
||||
if (dtlb[i].pte & PTE_ASM) dtlb[i].asn = asn;
|
||||
}
|
||||
tlb_inval (&d_mini_tlb);
|
||||
DTLB_SORT;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set superpage */
|
||||
|
||||
void itlb_set_spage (uint32 spage)
|
||||
{
|
||||
itlb_spage = spage;
|
||||
return;
|
||||
}
|
||||
|
||||
void dtlb_set_spage (uint32 spage)
|
||||
{
|
||||
dtlb_spage = spage;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set current mode */
|
||||
|
||||
void itlb_set_cm (uint32 mode)
|
||||
{
|
||||
itlb_cm = mode;
|
||||
cm_eacc = ACC_E (mode);
|
||||
return;
|
||||
}
|
||||
|
||||
void dtlb_set_cm (uint32 mode)
|
||||
{
|
||||
dtlb_cm = mode;
|
||||
cm_racc = ACC_R (mode);
|
||||
cm_wacc = ACC_W (mode);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 tlb_set_cm (int32 cm)
|
||||
{
|
||||
if (cm >= 0) {
|
||||
itlb_set_cm (cm);
|
||||
dtlb_set_cm (cm);
|
||||
return cm;
|
||||
}
|
||||
itlb_set_cm (itlb_cm);
|
||||
dtlb_set_cm (dtlb_cm);
|
||||
return dtlb_cm;
|
||||
}
|
||||
|
||||
/* Invalidate TLB entry */
|
||||
|
||||
void tlb_inval (TLBENT *tlbp)
|
||||
{
|
||||
tlbp->tag = INV_TAG;
|
||||
tlbp->pte = 0;
|
||||
tlbp->pfn = 0;
|
||||
tlbp->asn = tlbp->idx;
|
||||
tlbp->gh_mask = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Compare routine for qsort */
|
||||
|
||||
int tlb_comp (const void *e1, const void *e2)
|
||||
{
|
||||
TLBENT *t1 = (TLBENT *) e1;
|
||||
TLBENT *t2 = (TLBENT *) e2;
|
||||
|
||||
if (t1->asn > t2->asn) return +1;
|
||||
if (t1->asn < t2->asn) return -1;
|
||||
if (t1->tag > t2->tag) return +1;
|
||||
if (t1->tag < t2->tag) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ITLB reset */
|
||||
|
||||
t_stat itlb_reset (void)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
itlb_nlu = 0;
|
||||
for (i = 0; i < ITLB_SIZE; i++) {
|
||||
itlb[i].tag = INV_TAG;
|
||||
itlb[i].pte = 0;
|
||||
itlb[i].pfn = 0;
|
||||
itlb[i].asn = i;
|
||||
itlb[i].gh_mask = 0;
|
||||
itlb[i].idx = i;
|
||||
}
|
||||
tlb_inval (&i_mini_tlb);
|
||||
return SCPE_OK;
|
||||
}
|
||||
/* DTLB reset */
|
||||
|
||||
t_stat dtlb_reset (void)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
dtlb_nlu = 0;
|
||||
for (i = 0; i < DTLB_SIZE; i++) {
|
||||
dtlb[i].tag = INV_TAG;
|
||||
dtlb[i].pte = 0;
|
||||
dtlb[i].pfn = 0;
|
||||
dtlb[i].asn = i;
|
||||
dtlb[i].gh_mask = 0;
|
||||
dtlb[i].idx = i;
|
||||
}
|
||||
tlb_inval (&d_mini_tlb);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* SimH reset */
|
||||
|
||||
t_stat tlb_reset (DEVICE *dptr)
|
||||
{
|
||||
itlb_reset ();
|
||||
dtlb_reset ();
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show TLB entry or entries */
|
||||
|
||||
t_stat cpu_show_tlb (FILE *of, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
t_addr lo, hi;
|
||||
uint32 lnt;
|
||||
TLBENT *tlbp;
|
||||
DEVICE *dptr;
|
||||
char *cptr = (char *) desc;
|
||||
|
||||
lnt = (val)? DTLB_SIZE: ITLB_SIZE;
|
||||
dptr = find_dev_from_unit (uptr);
|
||||
if (dptr == NULL) return SCPE_IERR;
|
||||
if (cptr) {
|
||||
cptr = get_range (dptr, cptr, &lo, &hi, 10, lnt, 0);
|
||||
if ((cptr == NULL) || (*cptr != 0)) return SCPE_ARG;
|
||||
}
|
||||
else {
|
||||
lo = 0;
|
||||
hi = lnt - 1;
|
||||
}
|
||||
tlbp = (val)? dtlb + lo: itlb + lo;
|
||||
|
||||
do {
|
||||
fprintf (of, "TLB %02d\tTAG=%02X/%08X, ", (uint32) lo, tlbp->asn, tlbp->tag);
|
||||
fprintf (of, "MASK=%X, INDX=%d, ", tlbp->gh_mask, tlbp->idx);
|
||||
fprintf (of, "PTE=%04X, PFN=%08X\n", tlbp->pte, tlbp->pfn);
|
||||
tlbp++;
|
||||
lo++;
|
||||
} while (lo <= hi);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
772
Alpha/alpha_fpi.c
Normal file
772
Alpha/alpha_fpi.c
Normal file
@ -0,0 +1,772 @@
|
||||
/* alpha_fpi.c - Alpha IEEE floating point simulator
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This module contains the instruction simulators for
|
||||
|
||||
- single precision floating point, S
|
||||
- double precision floating point, T
|
||||
|
||||
Portions of this module (specifically, the convert floating to integer
|
||||
routine and the square root routine) are a derivative work from SoftFloat,
|
||||
written by John Hauser. SoftFloat includes the following license terms:
|
||||
|
||||
Written by John R. Hauser. This work was made possible in part by the
|
||||
International Computer Science Institute, located at Suite 600, 1947 Center
|
||||
Street, Berkeley, California 94704. Funding was partially provided by the
|
||||
National Science Foundation under grant MIP-9311980. The original version
|
||||
of this code was written as part of a project to build a fixed-point vector
|
||||
processor in collaboration with the University of California at Berkeley,
|
||||
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
|
||||
is available through the Web page 'http://www.cs.berkeley.edu/~jhauser/
|
||||
arithmetic/SoftFloat.html'.
|
||||
|
||||
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
|
||||
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
|
||||
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
|
||||
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
|
||||
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
|
||||
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
|
||||
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
|
||||
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
|
||||
|
||||
Derivative works are acceptable, even for commercial purposes, so long as
|
||||
(1) the source code for the derivative work includes prominent notice that
|
||||
the work is derivative, and (2) the source code includes prominent notice with
|
||||
these four paragraphs for those parts of this code that are retained.
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
|
||||
#define UFT_ZERO 0 /* unpacked: zero */
|
||||
#define UFT_FIN 1 /* finite */
|
||||
#define UFT_DENORM 2 /* denormal */
|
||||
#define UFT_INF 3 /* infinity */
|
||||
#define UFT_NAN 4 /* not a number */
|
||||
|
||||
#define Q_FINITE(x) ((x) <= UFT_FIN) /* finite */
|
||||
#define Q_SUI(x) (((x) & I_FTRP) == I_FTRP_SVI)
|
||||
|
||||
/* Register format constants */
|
||||
|
||||
#define QNAN 0x0008000000000000 /* quiet NaN flag */
|
||||
#define CQNAN 0xFFF8000000000000 /* canonical quiet NaN */
|
||||
#define FPZERO 0x0000000000000000 /* plus zero (fp) */
|
||||
#define FMZERO 0x8000000000000000 /* minus zero (fp) */
|
||||
#define FPINF 0x7FF0000000000000 /* plus infinity (fp) */
|
||||
#define FMINF 0xFFF0000000000000 /* minus infinity (fp) */
|
||||
#define FPMAX 0x7FEFFFFFFFFFFFFF /* plus MAX (fp) */
|
||||
#define FMMAX 0xFFEFFFFFFFFFFFFF /* minus MAX (fp) */
|
||||
#define IPMAX 0x7FFFFFFFFFFFFFFF /* plus MAX (int) */
|
||||
#define IMMAX 0x8000000000000000 /* minus MAX (int) */
|
||||
|
||||
/* Unpacked rounding constants */
|
||||
|
||||
#define UF_SRND 0x0000008000000000 /* S normal round */
|
||||
#define UF_SINF 0x000000FFFFFFFFFF /* S infinity round */
|
||||
#define UF_TRND 0x0000000000000400 /* T normal round */
|
||||
#define UF_TINF 0x00000000000007FF /* T infinity round */
|
||||
|
||||
extern t_uint64 FR[32];
|
||||
extern uint32 fpcr;
|
||||
extern jmp_buf save_env;
|
||||
|
||||
t_bool ieee_unpack (t_uint64 op, UFP *r, uint32 ir);
|
||||
void ieee_norm (UFP *r);
|
||||
t_uint64 ieee_rpack (UFP *r, uint32 ir, uint32 dp);
|
||||
void ieee_trap (uint32 trap, uint32 instenb, uint32 fpcrdsb, uint32 ir);
|
||||
int32 ieee_fcmp (t_uint64 a, t_uint64 b, uint32 ir, uint32 signal_nan);
|
||||
t_uint64 ieee_cvtst (t_uint64 op, uint32 ir);
|
||||
t_uint64 ieee_cvtts (t_uint64 op, uint32 ir);
|
||||
t_uint64 ieee_cvtif (t_uint64 val, uint32 ir, uint32 dp);
|
||||
t_uint64 ieee_cvtfi (t_uint64 op, uint32 ir);
|
||||
t_uint64 ieee_fadd (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp, t_bool sub);
|
||||
t_uint64 ieee_fmul (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp);
|
||||
t_uint64 ieee_fdiv (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp);
|
||||
uint32 estimateSqrt32 (uint32 exp, uint32 a);
|
||||
t_uint64 estimateDiv128 (t_uint64 hi, t_uint64 lo, t_uint64 dvr);
|
||||
|
||||
extern t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi);
|
||||
extern t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky);
|
||||
t_uint64 fsqrt64 (t_uint64 frac, int32 exp);
|
||||
|
||||
/* IEEE S load */
|
||||
|
||||
t_uint64 op_lds (t_uint64 op)
|
||||
{
|
||||
uint32 exp = S_GETEXP (op); /* get exponent */
|
||||
|
||||
if (exp == S_NAN) exp = FPR_NAN; /* inf or NaN? */
|
||||
else if (exp != 0) exp = exp + T_BIAS - S_BIAS; /* zero or denorm? */
|
||||
return (((t_uint64) (op & S_SIGN))? FPR_SIGN: 0) | /* reg format */
|
||||
(((t_uint64) exp) << FPR_V_EXP) |
|
||||
(((t_uint64) (op & ~(S_SIGN|S_EXP))) << S_V_FRAC);
|
||||
}
|
||||
|
||||
/* IEEE S store */
|
||||
|
||||
t_uint64 op_sts (t_uint64 op)
|
||||
{
|
||||
uint32 sign = FPR_GETSIGN (op)? S_SIGN: 0;
|
||||
uint32 exp = ((uint32) (op >> (FPR_V_EXP - S_V_EXP))) & S_EXP;
|
||||
uint32 frac = ((uint32) (op >> S_V_FRAC)) & M32;
|
||||
|
||||
return (t_uint64) (sign | exp | (frac & ~(S_SIGN|S_EXP)));
|
||||
}
|
||||
|
||||
/* IEEE floating operate */
|
||||
|
||||
void ieee_fop (uint32 ir)
|
||||
{
|
||||
UFP a, b;
|
||||
uint32 ftpa, ftpb, fnc, ra, rb, rc;
|
||||
t_uint64 res;
|
||||
|
||||
fnc = I_GETFFNC (ir); /* get function */
|
||||
ra = I_GETRA (ir); /* get registers */
|
||||
rb = I_GETRB (ir);
|
||||
rc = I_GETRC (ir);
|
||||
switch (fnc) { /* case on func */
|
||||
|
||||
case 0x00: /* ADDS */
|
||||
res = ieee_fadd (FR[ra], FR[rb], ir, DT_S, 0);
|
||||
break;
|
||||
|
||||
case 0x01: /* SUBS */
|
||||
res = ieee_fadd (FR[ra], FR[rb], ir, DT_S, 1);
|
||||
break;
|
||||
|
||||
case 0x02: /* MULS */
|
||||
res = ieee_fmul (FR[ra], FR[rb], ir, DT_S);
|
||||
break;
|
||||
|
||||
case 0x03: /* DIVS */
|
||||
res = ieee_fdiv (FR[ra], FR[rb], ir, DT_S);
|
||||
break;
|
||||
|
||||
case 0x20: /* ADDT */
|
||||
res = ieee_fadd (FR[ra], FR[rb], ir, DT_T, 0);
|
||||
break;
|
||||
|
||||
case 0x21: /* SUBT */
|
||||
res = ieee_fadd (FR[ra], FR[rb], ir, DT_T, 1);
|
||||
break;
|
||||
|
||||
case 0x22: /* MULT */
|
||||
res = ieee_fmul (FR[ra], FR[rb], ir, DT_T);
|
||||
break;
|
||||
|
||||
case 0x23: /* DIVT */
|
||||
res = ieee_fdiv (FR[ra], FR[rb], ir, DT_T);
|
||||
break;
|
||||
|
||||
case 0x24: /* CMPTUN */
|
||||
ftpa = ieee_unpack (FR[ra], &a, ir); /* unpack */
|
||||
ftpb = ieee_unpack (FR[rb], &b, ir);
|
||||
if ((ftpa == UFT_NAN) || (ftpb == UFT_NAN)) /* if NaN, T */
|
||||
res = FP_TRUE;
|
||||
else res = 0;
|
||||
break;
|
||||
|
||||
case 0x25: /* CMPTEQ */
|
||||
if (ieee_fcmp (FR[ra], FR[rb], ir, 0) == 0) res = FP_TRUE;
|
||||
else res = 0;
|
||||
break;
|
||||
|
||||
case 0x26: /* CMPTLT */
|
||||
if (ieee_fcmp (FR[ra], FR[rb], ir, 1) < 0) res = FP_TRUE;
|
||||
else res = 0;
|
||||
break;
|
||||
|
||||
case 0x27: /* CMPTLE */
|
||||
if (ieee_fcmp (FR[ra], FR[rb], ir, 1) <= 0) res = FP_TRUE;
|
||||
else res = 0;
|
||||
break;
|
||||
|
||||
case 0x2C: /* CVTST, CVTTS */
|
||||
if (ir & 0x2000) res = ieee_cvtst (FR[rb], ir); /* CVTST */
|
||||
else res = ieee_cvtts (FR[rb], ir); /* CVTTS */
|
||||
break;
|
||||
|
||||
case 0x2F: /* CVTTQ */
|
||||
res = ieee_cvtfi (FR[rb], ir);
|
||||
break;
|
||||
|
||||
case 0x3C: /* CVTQS */
|
||||
res = ieee_cvtif (FR[rb], ir, DT_S);
|
||||
break;
|
||||
|
||||
case 0x3E: /* CVTQT */
|
||||
res = ieee_cvtif (FR[rb], ir, DT_T);
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((ir & I_FSRC) == I_FSRC_X) ABORT (EXC_RSVI);
|
||||
res = FR[rc];
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != 31) FR[rc] = res & M64;
|
||||
return;
|
||||
}
|
||||
|
||||
/* IEEE S to T convert - LDS doesn't handle denorms correctly */
|
||||
|
||||
t_uint64 ieee_cvtst (t_uint64 op, uint32 ir)
|
||||
{
|
||||
UFP b;
|
||||
uint32 ftpb;
|
||||
|
||||
ftpb = ieee_unpack (op, &b, ir); /* unpack; norm dnorm */
|
||||
if (ftpb == UFT_DENORM) { /* denormal? */
|
||||
b.exp = b.exp + T_BIAS - S_BIAS; /* change 0 exp to T */
|
||||
return ieee_rpack (&b, ir, DT_T); /* round, pack */
|
||||
}
|
||||
else return op; /* identity */
|
||||
}
|
||||
|
||||
/* IEEE T to S convert */
|
||||
|
||||
t_uint64 ieee_cvtts (t_uint64 op, uint32 ir)
|
||||
{
|
||||
UFP b;
|
||||
uint32 ftpb;
|
||||
|
||||
ftpb = ieee_unpack (op, &b, ir); /* unpack */
|
||||
if (Q_FINITE (ftpb)) return ieee_rpack (&b, ir, DT_S); /* finite? round, pack */
|
||||
if (ftpb == UFT_NAN) return (op | QNAN); /* nan? cvt to quiet */
|
||||
if (ftpb == UFT_INF) return op; /* inf? unchanged */
|
||||
return 0; /* denorm? 0 */
|
||||
}
|
||||
|
||||
/* IEEE floating compare
|
||||
|
||||
- Take care of NaNs
|
||||
- Force -0 to +0
|
||||
- Then normal compare will work (even on inf and denorms) */
|
||||
|
||||
int32 ieee_fcmp (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 trap_nan)
|
||||
{
|
||||
UFP a, b;
|
||||
uint32 ftpa, ftpb;
|
||||
|
||||
ftpa = ieee_unpack (s1, &a, ir);
|
||||
ftpb = ieee_unpack (s2, &b, ir);
|
||||
if ((ftpa == UFT_NAN) || (ftpb == UFT_NAN)) { /* NaN involved? */
|
||||
if (trap_nan) ieee_trap (TRAP_INV, 1, FPCR_INVD, ir);
|
||||
return +1; /* force failure */
|
||||
}
|
||||
if (ftpa == UFT_ZERO) a.sign = 0; /* only +0 allowed */
|
||||
if (ftpb == UFT_ZERO) b.sign = 0;
|
||||
if (a.sign != b.sign) return (a.sign? -1: +1); /* unequal signs? */
|
||||
if (a.exp != b.exp) return ((a.sign ^ (a.exp < b.exp))? -1: +1);
|
||||
if (a.frac != b.frac) return ((a.sign ^ (a.frac < b.frac))? -1: +1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* IEEE integer to floating convert */
|
||||
|
||||
t_uint64 ieee_cvtif (t_uint64 val, uint32 ir, uint32 dp)
|
||||
{
|
||||
UFP a;
|
||||
|
||||
if (val == 0) return 0; /* 0? return +0 */
|
||||
if (val < 0) { /* < 0? */
|
||||
a.sign = 1; /* set sign */
|
||||
val = NEG_Q (val); /* |val| */
|
||||
}
|
||||
else a.sign = 0;
|
||||
a.exp = 63 + T_BIAS; /* set exp */
|
||||
a.frac = val; /* set frac */
|
||||
ieee_norm (&a); /* normalize */
|
||||
return ieee_rpack (&a, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* IEEE floating to integer convert - rounding code from SoftFloat
|
||||
The Alpha architecture specifies return of the low order bits of
|
||||
the true result, whereas the IEEE standard specifies the return
|
||||
of the maximum plus or minus value */
|
||||
|
||||
t_uint64 ieee_cvtfi (t_uint64 op, uint32 ir)
|
||||
{
|
||||
UFP a;
|
||||
t_uint64 sticky;
|
||||
uint32 rndm, ftpa, ovf;
|
||||
int32 ubexp;
|
||||
|
||||
ftpa = ieee_unpack (op, &a, ir); /* unpack */
|
||||
if (!Q_FINITE (ftpa)) { /* inf, NaN, dnorm? */
|
||||
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv operation */
|
||||
return 0;
|
||||
}
|
||||
if (ftpa == UFT_ZERO) return 0; /* zero? */
|
||||
ovf = 0; /* assume no ovflo */
|
||||
ubexp = a.exp - T_BIAS; /* unbiased exp */
|
||||
if (ubexp < 0) { /* < 1? */
|
||||
if (ubexp == -1) sticky = a.frac; /* [.5,1)? */
|
||||
else sticky = 1; /* (0,.5) */
|
||||
a.frac = 0;
|
||||
}
|
||||
else if (ubexp < UF_V_NM) { /* in range? */
|
||||
sticky = (a.frac << (64 - (UF_V_NM - ubexp))) & M64;
|
||||
a.frac = a.frac >> (UF_V_NM - ubexp); /* result */
|
||||
}
|
||||
else if (ubexp == UF_V_NM) sticky = 0; /* at limit of range? */
|
||||
else {
|
||||
if ((ubexp - UF_V_NM) > 63) a.frac = 0; /* out of range */
|
||||
else a.frac = (a.frac << (ubexp - UF_V_NM)) & M64;
|
||||
ovf = 1; /* overflow */
|
||||
sticky = 0; /* no rounding */
|
||||
}
|
||||
rndm = I_GETFRND (ir); /* get round mode */
|
||||
if (((rndm == I_FRND_N) && (sticky & Q_SIGN)) || /* nearest? */
|
||||
((rndm == I_FRND_P) && !a.sign && sticky) || /* +inf and +? */
|
||||
((rndm == I_FRND_M) && a.sign && sticky)) { /* -inf and -? */
|
||||
a.frac = (a.frac + 1) & M64;
|
||||
if (a.frac == 0) ovf = 1; /* overflow? */
|
||||
if ((rndm == I_FRND_N) && (sticky == Q_SIGN)) /* round nearest hack */
|
||||
a.frac = a.frac & ~1;
|
||||
}
|
||||
if (a.frac > (a.sign? IMMAX: IPMAX)) ovf = 1; /* overflow? */
|
||||
if (ovf) ieee_trap (TRAP_IOV, ir & I_FTRP_V, 0, 0); /* overflow trap */
|
||||
if (ovf || sticky) /* ovflo or round? */
|
||||
ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir);
|
||||
return (a.sign? NEG_Q (a.frac): a.frac);
|
||||
}
|
||||
|
||||
/* IEEE floating add
|
||||
|
||||
- Take care of NaNs and infinites
|
||||
- Test for zero (fast exit)
|
||||
- Sticky logic for floating add
|
||||
> If result normalized, sticky in right place
|
||||
> If result carries out, renormalize, retain sticky
|
||||
- Sticky logic for floating subtract
|
||||
> If shift < guard, no sticky bits; 64b result is exact
|
||||
If shift <= 1, result may require extensive normalization,
|
||||
but there are no sticky bits to worry about
|
||||
> If shift >= guard, there is a sticky bit,
|
||||
but normalization is at most 1 place, sticky bit is retained
|
||||
for rounding purposes (but not in low order bit) */
|
||||
|
||||
t_uint64 ieee_fadd (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp, t_bool sub)
|
||||
{
|
||||
UFP a, b, t;
|
||||
uint32 ftpa, ftpb;
|
||||
uint32 sticky, rndm;
|
||||
int32 ediff;
|
||||
|
||||
ftpa = ieee_unpack (s1, &a, ir); /* unpack operands */
|
||||
ftpb = ieee_unpack (s2, &b, ir);
|
||||
if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */
|
||||
if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */
|
||||
if (sub) b.sign = b.sign ^ 1; /* sign of B */
|
||||
if (ftpb == UFT_INF) { /* B = inf? */
|
||||
if ((ftpa == UFT_INF) && (a.sign ^ b.sign)) { /* eff sub of inf? */
|
||||
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */
|
||||
return CQNAN; /* canonical NaN */
|
||||
}
|
||||
return (sub? (s2 ^ FPR_SIGN): s2); /* return B */
|
||||
}
|
||||
if (ftpa == UFT_INF) return s1; /* A = inf? ret A */
|
||||
rndm = I_GETFRND (ir); /* inst round mode */
|
||||
if (rndm == I_FRND_D) rndm = FPCR_GETFRND (fpcr); /* dynamic? use FPCR */
|
||||
if (ftpa == UFT_ZERO) { /* A = 0? */
|
||||
if (ftpb != UFT_ZERO) a = b; /* B != 0? result is B */
|
||||
else if (a.sign != b.sign) /* both 0, subtract? */
|
||||
a.sign = (rndm == I_FRND_M); /* +0 unless RM */
|
||||
}
|
||||
else if (ftpb != UFT_ZERO) { /* s2 != 0? */
|
||||
if ((a.exp < b.exp) || /* s1 < s2? swap */
|
||||
((a.exp == b.exp) && (a.frac < b.frac))) {
|
||||
t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
ediff = a.exp - b.exp; /* exp diff */
|
||||
if (ediff > 63) b.frac = 1; /* >63? retain sticky */
|
||||
else if (ediff) { /* [1,63]? shift */
|
||||
sticky = ((b.frac << (64 - ediff)) & M64)? 1: 0; /* lost bits */
|
||||
b.frac = ((b.frac >> ediff) & M64) | sticky;
|
||||
}
|
||||
if (a.sign ^ b.sign) { /* eff sub? */
|
||||
a.frac = (a.frac - b.frac) & M64; /* subtract fractions */
|
||||
if (a.frac == 0) { /* result 0? */
|
||||
a.exp = 0;
|
||||
a.sign = (rndm == I_FRND_M); /* +0 unless RM */
|
||||
}
|
||||
else ieee_norm (&a); /* normalize */
|
||||
}
|
||||
else { /* eff add */
|
||||
a.frac = (a.frac + b.frac) & M64; /* add frac */
|
||||
if (a.frac < b.frac) { /* chk for carry */
|
||||
a.frac = UF_NM | (a.frac >> 1) | /* shift in carry */
|
||||
(a.frac & 1); /* retain sticky */
|
||||
a.exp = a.exp + 1; /* skip norm */
|
||||
}
|
||||
}
|
||||
} /* end else if */
|
||||
return ieee_rpack (&a, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* IEEE floating multiply
|
||||
|
||||
- Take care of NaNs and infinites
|
||||
- Test for zero operands (fast exit)
|
||||
- 64b x 64b fraction multiply, yielding 128b result
|
||||
- Normalize (at most 1 bit)
|
||||
- Insert "sticky" bit in low order fraction, for rounding
|
||||
|
||||
Because IEEE fractions have a range of [1,2), the result can have a range
|
||||
of [1,4). Results in the range of [1,2) appear to be denormalized by one
|
||||
place, when in fact they are correct. Results in the range of [2,4) appear
|
||||
to be in correct, when in fact they are 2X larger. This problem is taken
|
||||
care of in the result exponent calculation. */
|
||||
|
||||
t_uint64 ieee_fmul (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp)
|
||||
{
|
||||
UFP a, b;
|
||||
uint32 ftpa, ftpb;
|
||||
t_uint64 resl;
|
||||
|
||||
ftpa = ieee_unpack (s1, &a, ir); /* unpack operands */
|
||||
ftpb = ieee_unpack (s2, &b, ir);
|
||||
if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */
|
||||
if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */
|
||||
a.sign = a.sign ^ b.sign; /* sign of result */
|
||||
if ((ftpa == UFT_ZERO) || (ftpb == UFT_ZERO)) { /* zero operand? */
|
||||
if ((ftpa == UFT_INF) || (ftpb == UFT_INF)) { /* 0 * inf? */
|
||||
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */
|
||||
return CQNAN; /* canonical NaN */
|
||||
}
|
||||
return (a.sign? FMZERO: FPZERO); /* return signed 0 */
|
||||
}
|
||||
if (ftpb == UFT_INF) return (a.sign? FMINF: FPINF); /* B = inf? */
|
||||
if (ftpa == UFT_INF) return (a.sign? FMINF: FPINF); /* A = inf? */
|
||||
a.exp = a.exp + b.exp + 1 - T_BIAS; /* add exponents */
|
||||
resl = uemul64 (a.frac, b.frac, &a.frac); /* multiply fracs */
|
||||
ieee_norm (&a); /* normalize */
|
||||
a.frac = a.frac | (resl? 1: 0); /* sticky bit */
|
||||
return ieee_rpack (&a, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* Floating divide
|
||||
|
||||
- Take care of NaNs and infinites
|
||||
- Check for zero cases
|
||||
- Divide fractions (55b to develop a rounding bit)
|
||||
- Set sticky bit if remainder non-zero
|
||||
|
||||
Because IEEE fractions have a range of [1,2), the result can have a range
|
||||
of (.5,2). Results in the range of [1,2) are correct. Results in the
|
||||
range of (.5,1) need to be normalized by one place. */
|
||||
|
||||
t_uint64 ieee_fdiv (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp)
|
||||
{
|
||||
UFP a, b;
|
||||
uint32 ftpa, ftpb, sticky;
|
||||
|
||||
ftpa = ieee_unpack (s1, &a, ir);
|
||||
ftpb = ieee_unpack (s2, &b, ir);
|
||||
if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */
|
||||
if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */
|
||||
a.sign = a.sign ^ b.sign; /* sign of result */
|
||||
if (ftpb == UFT_INF) { /* B = inf? */
|
||||
if (ftpa == UFT_INF) { /* inf/inf? */
|
||||
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */
|
||||
return CQNAN; /* canonical NaN */
|
||||
}
|
||||
return (a.sign? FMZERO: FPZERO); /* !inf/inf, ret 0 */
|
||||
}
|
||||
if (ftpa == UFT_INF) /* A = inf? */
|
||||
return (a.sign? FMINF: FPINF); /* return inf */
|
||||
if (ftpb == UFT_ZERO) { /* B = 0? */
|
||||
if (ftpa == UFT_ZERO) { /* 0/0? */
|
||||
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */
|
||||
return CQNAN; /* canonical NaN */
|
||||
}
|
||||
ieee_trap (TRAP_DZE, 1, FPCR_DZED, ir); /* div by 0 trap */
|
||||
return (a.sign? FMINF: FPINF); /* return inf */
|
||||
}
|
||||
if (ftpa == UFT_ZERO) return (a.sign? FMZERO: FPZERO); /* A = 0? */
|
||||
a.exp = a.exp - b.exp + T_BIAS; /* unbiased exp */
|
||||
a.frac = a.frac >> 1; /* allow 1 bit left */
|
||||
b.frac = b.frac >> 1;
|
||||
a.frac = ufdiv64 (a.frac, b.frac, 55, &sticky); /* divide */
|
||||
ieee_norm (&a); /* normalize */
|
||||
a.frac = a.frac | sticky; /* insert sticky */
|
||||
return ieee_rpack (&a, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* IEEE floating square root
|
||||
|
||||
- Take care of NaNs, +infinite, zero
|
||||
- Check for negative operand
|
||||
- Compute result exponent
|
||||
- Compute sqrt of fraction */
|
||||
|
||||
t_uint64 ieee_sqrt (uint32 ir, uint32 dp)
|
||||
{
|
||||
t_uint64 op;
|
||||
uint32 ftpb;
|
||||
UFP b;
|
||||
|
||||
op = FR[I_GETRB (ir)]; /* get F[rb] */
|
||||
ftpb = ieee_unpack (op, &b, ir); /* unpack */
|
||||
if (ftpb == UFT_NAN) return op | QNAN; /* NaN? */
|
||||
if ((ftpb == UFT_ZERO) || /* zero? */
|
||||
((ftpb == UFT_INF) && !b.sign)) return op; /* +infinity? */
|
||||
if (b.sign) { /* minus? */
|
||||
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */
|
||||
return CQNAN;
|
||||
}
|
||||
b.exp = ((b.exp - T_BIAS) >> 1) + T_BIAS - 1; /* result exponent */
|
||||
b.frac = fsqrt64 (b.frac, b.exp); /* result fraction */
|
||||
return ieee_rpack (&b, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* Support routines */
|
||||
|
||||
t_bool ieee_unpack (t_uint64 op, UFP *r, uint32 ir)
|
||||
{
|
||||
r->sign = FPR_GETSIGN (op); /* get sign */
|
||||
r->exp = FPR_GETEXP (op); /* get exponent */
|
||||
r->frac = FPR_GETFRAC (op); /* get fraction */
|
||||
if (r->exp == 0) { /* exponent = 0? */
|
||||
if (r->frac == 0) return UFT_ZERO; /* frac = 0? then true 0 */
|
||||
if (fpcr & FPCR_DNZ) { /* denorms to 0? */
|
||||
r->frac = 0; /* clear fraction */
|
||||
return UFT_ZERO;
|
||||
}
|
||||
r->frac = r->frac << FPR_GUARD; /* guard fraction */
|
||||
ieee_norm (r); /* normalize dnorm */
|
||||
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */
|
||||
return UFT_DENORM;
|
||||
}
|
||||
if (r->exp == FPR_NAN) { /* exponent = max? */
|
||||
if (r->frac == 0) return UFT_INF; /* frac = 0? then inf */
|
||||
if (!(r->frac & QNAN)) /* signaling NaN? */
|
||||
ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */
|
||||
return UFT_NAN;
|
||||
}
|
||||
r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */
|
||||
return UFT_FIN; /* finite */
|
||||
}
|
||||
|
||||
/* Normalize - input must be zero, finite, or denorm */
|
||||
|
||||
void ieee_norm (UFP *r)
|
||||
{
|
||||
int32 i;
|
||||
static t_uint64 normmask[5] = {
|
||||
0xc000000000000000, 0xf000000000000000, 0xff00000000000000,
|
||||
0xffff000000000000, 0xffffffff00000000
|
||||
};
|
||||
static int32 normtab[6] = { 1, 2, 4, 8, 16, 32 };
|
||||
|
||||
r->frac = r->frac & M64;
|
||||
if (r->frac == 0) { /* if fraction = 0 */
|
||||
r->sign = 0;
|
||||
r->exp = 0; /* result is 0 */
|
||||
return;
|
||||
}
|
||||
while ((r->frac & UF_NM) == 0) { /* normalized? */
|
||||
for (i = 0; i < 5; i++) { /* find first 1 */
|
||||
if (r->frac & normmask[i]) break;
|
||||
}
|
||||
r->frac = r->frac << normtab[i]; /* shift frac */
|
||||
r->exp = r->exp - normtab[i]; /* decr exp */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Round and pack
|
||||
|
||||
Much of the treachery of the IEEE standard is buried here
|
||||
- Rounding modes (chopped, +infinity, nearest, -infinity)
|
||||
- Inexact (set if there are any rounding bits, regardless of rounding)
|
||||
- Overflow (result is infinite if rounded, max if not)
|
||||
- Underflow (no denorms!)
|
||||
|
||||
Underflow handling is particularly complicated
|
||||
- Result is always 0
|
||||
- UNF and INE are always set in FPCR
|
||||
- If /U is set,
|
||||
o If /S is clear, trap
|
||||
o If /S is set, UNFD is set, but UNFZ is clear, ignore UNFD and
|
||||
trap, because the hardware cannot produce denormals
|
||||
o If /S is set, UNFD is set, and UNFZ is set, do not trap
|
||||
- If /SUI is set, and INED is clear, trap */
|
||||
|
||||
t_uint64 ieee_rpack (UFP *r, uint32 ir, uint32 dp)
|
||||
{
|
||||
static const t_uint64 stdrnd[2] = { UF_SRND, UF_TRND };
|
||||
static const t_uint64 infrnd[2] = { UF_SINF, UF_TINF };
|
||||
static const int32 expmax[2] = { T_BIAS - S_BIAS + S_M_EXP - 1, T_M_EXP - 1 };
|
||||
static const int32 expmin[2] = { T_BIAS - S_BIAS, 0 };
|
||||
t_uint64 rndadd, rndbits, res;
|
||||
uint32 rndm;
|
||||
|
||||
if (r->frac == 0) return (r->sign << FPR_V_SIGN); /* result 0? */
|
||||
rndm = I_GETFRND (ir); /* inst round mode */
|
||||
if (rndm == I_FRND_D) rndm = FPCR_GETFRND (fpcr); /* dynamic? use FPCR */
|
||||
rndbits = r->frac & infrnd[dp]; /* isolate round bits */
|
||||
if (rndm == I_FRND_N) rndadd = stdrnd[dp]; /* round to nearest? */
|
||||
else if (((rndm == I_FRND_P) && !r->sign) || /* round to inf and */
|
||||
((rndm == I_FRND_M) && r->sign)) /* right sign? */
|
||||
rndadd = infrnd[dp];
|
||||
else rndadd = 0;
|
||||
r->frac = (r->frac + rndadd) & M64; /* round */
|
||||
if ((r->frac & UF_NM) == 0) { /* carry out? */
|
||||
r->frac = (r->frac >> 1) | UF_NM; /* renormalize */
|
||||
r->exp = r->exp + 1;
|
||||
}
|
||||
if (rndbits) /* inexact? */
|
||||
ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */
|
||||
if (r->exp > expmax[dp]) { /* ovflo? */
|
||||
ieee_trap (TRAP_OVF, 1, FPCR_OVFD, ir); /* set overflow trap */
|
||||
ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */
|
||||
if (rndadd) /* did we round? */
|
||||
return (r->sign? FMINF: FPINF); /* return infinity */
|
||||
return (r->sign? FMMAX: FPMAX); /* no, return max */
|
||||
}
|
||||
if (r->exp <= expmin[dp]) { /* underflow? */
|
||||
ieee_trap (TRAP_UNF, ir & I_FTRP_U, /* set underflow trap */
|
||||
(fpcr & FPCR_UNDZ)? FPCR_UNFD: 0, ir); /* (dsbl only if UNFZ set) */
|
||||
ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */
|
||||
return 0; /* underflow to +0 */
|
||||
}
|
||||
res = (((t_uint64) r->sign) << FPR_V_SIGN) | /* form result */
|
||||
(((t_uint64) r->exp) << FPR_V_EXP) |
|
||||
((r->frac >> FPR_GUARD) & FPR_FRAC);
|
||||
if ((rndm == I_FRND_N) && (rndbits == stdrnd[dp])) /* nearest and halfway? */
|
||||
res = res & ~1; /* clear lo bit */
|
||||
return res;
|
||||
}
|
||||
|
||||
/* IEEE arithmetic trap - only one can be set at a time! */
|
||||
|
||||
void ieee_trap (uint32 trap, uint32 instenb, uint32 fpcrdsb, uint32 ir)
|
||||
{
|
||||
fpcr = fpcr | (trap << 19); /* FPCR to trap summ offset */
|
||||
if ((instenb == 0) || /* not enabled in inst? ignore */
|
||||
((ir & I_FTRP_S) && (fpcr & fpcrdsb))) return; /* /S and disabled? ignore */
|
||||
arith_trap (trap, ir); /* set Alpha trap */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fraction square root routine - code from SoftFloat */
|
||||
|
||||
t_uint64 fsqrt64 (t_uint64 asig, int32 exp)
|
||||
{
|
||||
t_uint64 zsig, remh, reml, t;
|
||||
uint32 sticky = 0;
|
||||
|
||||
zsig = estimateSqrt32 (exp, (uint32) (asig >> 32));
|
||||
|
||||
/* Calculate the final answer in two steps. First, do one iteration of
|
||||
Newton's approximation. The divide-by-2 is accomplished by clever
|
||||
positioning of the operands. Then, check the bits just below the
|
||||
(double precision) rounding bit to see if they are close to zero
|
||||
(that is, the rounding bits are close to midpoint). If so, make
|
||||
sure that the result^2 is <below> the input operand */
|
||||
|
||||
asig = asig >> ((exp & 1)? 3: 2); /* leave 2b guard */
|
||||
zsig = estimateDiv128 (asig, 0, zsig << 32) + (zsig << 30 );
|
||||
if ((zsig & 0x1FF) <= 5) { /* close to even? */
|
||||
reml = uemul64 (zsig, zsig, &remh); /* result^2 */
|
||||
remh = asig - remh - (reml? 1:0); /* arg - result^2 */
|
||||
reml = NEG_Q (reml);
|
||||
while (Q_GETSIGN (remh) != 0) { /* if arg < result^2 */
|
||||
zsig = zsig - 1; /* decr result */
|
||||
t = (zsig << 1) | 1; /* incr result^2 */
|
||||
reml = reml + t; /* and retest */
|
||||
remh = remh + (zsig >> 63) + ((reml < t)? 1: 0);
|
||||
}
|
||||
if ((remh | reml) != 0 ) sticky = 1; /* not exact? */
|
||||
}
|
||||
return zsig;
|
||||
}
|
||||
|
||||
/* Estimate 32b SQRT
|
||||
|
||||
Calculate an approximation to the square root of the 32-bit significand given
|
||||
by 'a'. Considered as an integer, 'a' must be at least 2^31. If bit 0 of
|
||||
'exp' (the least significant bit) is 1, the integer returned approximates
|
||||
2^31*sqrt('a'/2^31), where 'a' is considered an integer. If bit 0 of 'exp'
|
||||
is 0, the integer returned approximates 2^31*sqrt('a'/2^30). In either
|
||||
case, the approximation returned lies strictly within +/-2 of the exact
|
||||
value. */
|
||||
|
||||
uint32 estimateSqrt32 (uint32 exp, uint32 a)
|
||||
{
|
||||
uint32 index, z;
|
||||
static const uint32 sqrtOdd[] = {
|
||||
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
|
||||
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
|
||||
};
|
||||
static const uint32 sqrtEven[] = {
|
||||
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
|
||||
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
|
||||
};
|
||||
|
||||
index = (a >> 27) & 0xF; /* bits<30:27> */
|
||||
if (exp & 1) { /* odd exp? */
|
||||
z = 0x4000 + (a >> 17) - sqrtOdd[index]; /* initial guess */
|
||||
z = ((a / z) << 14) + (z << 15); /* Newton iteration */
|
||||
a = a >> 1;
|
||||
}
|
||||
else {
|
||||
z = 0x8000 + (a >> 17) - sqrtEven[index]; /* initial guess */
|
||||
z = (a / z) + z; /* Newton iteration */
|
||||
z = (z >= 0x20000) ? 0xFFFF8000: (z << 15);
|
||||
if (z <= a) z = (a >> 1) | 0x80000000;
|
||||
}
|
||||
return (uint32) ((((((t_uint64) a) << 31) / ((t_uint64) z)) + (z >> 1)) & M32);
|
||||
}
|
||||
|
||||
/* Estimate 128b unsigned divide */
|
||||
|
||||
t_uint64 estimateDiv128 (t_uint64 a0, t_uint64 a1, t_uint64 b)
|
||||
{
|
||||
t_uint64 b0, b1;
|
||||
t_uint64 rem0, rem1, term0, term1;
|
||||
t_uint64 z;
|
||||
|
||||
if (b <= a0) return 0xFFFFFFFFFFFFFFFF;
|
||||
b0 = b >> 32;
|
||||
z = ((b0 << 32) <= a0)? 0xFFFFFFFF00000000: ((a0 / b0) << 32);
|
||||
term1 = uemul64 (b, z, &term0);
|
||||
rem0 = a0 - term0 - (a1 < term1);
|
||||
rem1 = a1 - term1;
|
||||
while (Q_GETSIGN (rem0)) {
|
||||
z = z - ((t_uint64) 0x100000000);
|
||||
b1 = b << 32;
|
||||
rem1 = b1 + rem1;
|
||||
rem0 = b0 + rem0 + (rem1 < b1);
|
||||
}
|
||||
rem0 = (rem0 << 32) | (rem1 >> 32);
|
||||
z |= (((b0 << 32) <= rem0)? 0xFFFFFFFF : (rem0 / b0));
|
||||
return z;
|
||||
}
|
||||
455
Alpha/alpha_fpv.c
Normal file
455
Alpha/alpha_fpv.c
Normal file
@ -0,0 +1,455 @@
|
||||
/* alpha_fpv.c - Alpha VAX floating point simulator
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This module contains the instruction simulators for
|
||||
|
||||
- single precision floating point, F
|
||||
- double precision floating point, G
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
|
||||
#define IPMAX 0x7FFFFFFFFFFFFFFF /* plus MAX (int) */
|
||||
#define IMMAX 0x8000000000000000 /* minus MAX (int) */
|
||||
|
||||
/* Unpacked rounding constants */
|
||||
|
||||
#define UF_FRND 0x0000008000000000 /* F round */
|
||||
#define UF_DRND 0x0000000000000080 /* D round */
|
||||
#define UF_GRND 0x0000000000000400 /* G round */
|
||||
|
||||
extern t_uint64 FR[32];
|
||||
extern jmp_buf save_env;
|
||||
|
||||
t_bool vax_unpack (t_uint64 op, UFP *a, uint32 ir);
|
||||
t_bool vax_unpack_d (t_uint64 op, UFP *a, uint32 ir);
|
||||
void vax_norm (UFP *a);
|
||||
t_uint64 vax_rpack (UFP *a, uint32 ir, uint32 dp);
|
||||
t_uint64 vax_rpack_d (UFP *a, uint32 ir);
|
||||
int32 vax_fcmp (t_uint64 a, t_uint64 b, uint32 ir);
|
||||
t_uint64 vax_cvtif (t_uint64 val, uint32 ir, uint32 dp);
|
||||
t_uint64 vax_cvtfi (t_uint64 op, uint32 ir);
|
||||
t_uint64 vax_fadd (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp, t_bool sub);
|
||||
t_uint64 vax_fmul (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp);
|
||||
t_uint64 vax_fdiv (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp);
|
||||
|
||||
extern t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi);
|
||||
extern t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky);
|
||||
extern t_uint64 fsqrt64 (t_uint64 frac, int32 exp);
|
||||
|
||||
/* VAX floating point loads and stores */
|
||||
|
||||
t_uint64 op_ldf (t_uint64 op)
|
||||
{
|
||||
uint32 exp = F_GETEXP (op);
|
||||
|
||||
if (exp != 0) exp = exp + G_BIAS - F_BIAS; /* zero? */
|
||||
return (((t_uint64) (op & F_SIGN))? FPR_SIGN: 0) | /* finite non-zero */
|
||||
(((t_uint64) exp) << FPR_V_EXP) |
|
||||
(((t_uint64) SWAP_VAXF (op & ~(F_SIGN|F_EXP))) << F_V_FRAC);
|
||||
}
|
||||
|
||||
t_uint64 op_ldg (t_uint64 op)
|
||||
{
|
||||
return SWAP_VAXG (op); /* swizzle bits */
|
||||
}
|
||||
|
||||
t_uint64 op_stf (t_uint64 op)
|
||||
{
|
||||
uint32 sign = FPR_GETSIGN (op)? F_SIGN: 0;
|
||||
uint32 exp = ((uint32) (op >> (FPR_V_EXP - F_V_EXP))) & F_EXP;
|
||||
uint32 frac = (uint32) (op >> F_V_FRAC);
|
||||
|
||||
return (t_uint64) (sign | exp | (SWAP_VAXF (frac) & ~(F_SIGN|F_EXP)));
|
||||
}
|
||||
|
||||
t_uint64 op_stg (t_uint64 op)
|
||||
{
|
||||
return SWAP_VAXG (op); /* swizzle bits */
|
||||
}
|
||||
|
||||
/* VAX floating point operate */
|
||||
|
||||
void vax_fop (uint32 ir)
|
||||
{
|
||||
UFP b;
|
||||
t_uint64 res;
|
||||
uint32 fnc, ra, rb, rc;
|
||||
|
||||
fnc = I_GETFFNC (ir); /* get function */
|
||||
ra = I_GETRA (ir); /* get registers */
|
||||
rb = I_GETRB (ir);
|
||||
rc = I_GETRC (ir);
|
||||
switch (fnc) { /* case on func */
|
||||
|
||||
case 0x00: /* ADDF */
|
||||
res = vax_fadd (FR[ra], FR[rb], ir, DT_F, 0);
|
||||
break;
|
||||
|
||||
case 0x01: /* SUBF */
|
||||
res = vax_fadd (FR[ra], FR[rb], ir, DT_F, 1);
|
||||
break;
|
||||
|
||||
case 0x02: /* MULF */
|
||||
res = vax_fmul (FR[ra], FR[rb], ir, DT_F);
|
||||
break;
|
||||
|
||||
case 0x03: /* DIVF */
|
||||
res = vax_fdiv (FR[ra], FR[rb], ir, DT_F);
|
||||
break;
|
||||
|
||||
case 0x20: /* ADDG */
|
||||
res = vax_fadd (FR[ra], FR[rb], ir, DT_G, 0);
|
||||
break;
|
||||
|
||||
case 0x21: /* SUBG */
|
||||
res = vax_fadd (FR[ra], FR[rb], ir, DT_G, 1);
|
||||
break;
|
||||
|
||||
case 0x22: /* MULG */
|
||||
res = vax_fmul (FR[ra], FR[rb], ir, DT_G);
|
||||
break;
|
||||
|
||||
case 0x23: /* DIVG */
|
||||
res = vax_fdiv (FR[ra], FR[rb], ir, DT_G);
|
||||
break;
|
||||
|
||||
case 0x25: /* CMPGEQ */
|
||||
if (vax_fcmp (FR[ra], FR[rb], ir) == 0) res = FP_TRUE;
|
||||
else res = 0;
|
||||
break;
|
||||
|
||||
case 0x26: /* CMPGLT */
|
||||
if (vax_fcmp (FR[ra], FR[rb], ir) < 0) res = FP_TRUE;
|
||||
else res = 0;
|
||||
break;
|
||||
|
||||
case 0x27: /* CMPGLE */
|
||||
if (vax_fcmp (FR[ra], FR[rb], ir) <= 0) res = FP_TRUE;
|
||||
else res = 0;
|
||||
break;
|
||||
|
||||
case 0x1E: /* CVTDG */
|
||||
if (vax_unpack_d (FR[rb], &b, ir)) res = 0;
|
||||
else res = vax_rpack (&b, ir, DT_G);
|
||||
break;
|
||||
|
||||
case 0x2C: /* CVTGF */
|
||||
if (vax_unpack (FR[rb], &b, ir)) res = 0;
|
||||
else res = vax_rpack (&b, ir, DT_F);
|
||||
break;
|
||||
|
||||
case 0x2D: /* CVTGD */
|
||||
if (vax_unpack (FR[rb], &b, ir)) res = 0;
|
||||
else res = vax_rpack_d (&b, ir);
|
||||
break;
|
||||
|
||||
case 0x2F: /* CVTGQ */
|
||||
res = vax_cvtfi (FR[rb], ir);
|
||||
break;
|
||||
|
||||
case 0x3C: /* CVTQF */
|
||||
res = vax_cvtif (FR[rb], ir, DT_F);
|
||||
break;
|
||||
|
||||
case 0x3E: /* CVTQG */
|
||||
res = vax_cvtif (FR[rb], ir, DT_G);
|
||||
break;
|
||||
|
||||
default:
|
||||
res = FR[rc];
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != 31) FR[rc] = res & M64;
|
||||
return;
|
||||
}
|
||||
|
||||
/* VAX floating compare */
|
||||
|
||||
int32 vax_fcmp (t_uint64 s1, t_uint64 s2, uint32 ir)
|
||||
{
|
||||
UFP a, b;
|
||||
|
||||
if (vax_unpack (s1, &a, ir)) return +1; /* unpack, rsv? */
|
||||
if (vax_unpack (s2, &b, ir)) return +1; /* unpack, rsv? */
|
||||
if (s1 == s2) return 0; /* equal? */
|
||||
if (a.sign != b.sign) return (a.sign? -1: +1); /* opp signs? */
|
||||
return (((s1 < s2) ^ a.sign)? -1: +1); /* like signs */
|
||||
}
|
||||
|
||||
/* VAX integer to floating convert */
|
||||
|
||||
t_uint64 vax_cvtif (t_uint64 val, uint32 ir, uint32 dp)
|
||||
{
|
||||
UFP a;
|
||||
|
||||
if (val == 0) return 0; /* 0? return +0 */
|
||||
if (val < 0) { /* < 0? */
|
||||
a.sign = 1; /* set sign */
|
||||
val = NEG_Q (val); /* |val| */
|
||||
}
|
||||
else a.sign = 0;
|
||||
a.exp = 64 + G_BIAS; /* set exp */
|
||||
a.frac = val; /* set frac */
|
||||
vax_norm (&a); /* normalize */
|
||||
return vax_rpack (&a, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* VAX floating to integer convert - note that rounding cannot cause a
|
||||
carry unless the fraction has been shifted right at least FP_GUARD
|
||||
places; in which case a carry out is impossible */
|
||||
|
||||
t_uint64 vax_cvtfi (t_uint64 op, uint32 ir)
|
||||
{
|
||||
UFP a;
|
||||
uint32 rndm = I_GETFRND (ir);
|
||||
int32 ubexp;
|
||||
|
||||
if (vax_unpack (op, &a, ir)) return 0; /* unpack, rsv? */
|
||||
ubexp = a.exp - G_BIAS; /* unbiased exp */
|
||||
if (ubexp < 0) return 0; /* zero or too small? */
|
||||
if (ubexp <= UF_V_NM) { /* in range? */
|
||||
a.frac = a.frac >> (UF_V_NM - ubexp); /* leave rnd bit */
|
||||
if (rndm) a.frac = a.frac + 1; /* not chopped, round */
|
||||
a.frac = a.frac >> 1; /* now justified */
|
||||
if ((a.frac > (a.sign? IMMAX: IPMAX)) && /* out of range? */
|
||||
(ir & I_FTRP_V)) /* trap enabled? */
|
||||
arith_trap (TRAP_IOV, ir); /* set overflow */
|
||||
}
|
||||
else {
|
||||
if (ubexp > (UF_V_NM + 64)) a.frac = 0; /* out of range */
|
||||
else a.frac = (a.frac << (ubexp - UF_V_NM - 1)) & M64; /* no rnd bit */
|
||||
if (ir & I_FTRP_V) /* trap enabled? */
|
||||
arith_trap (TRAP_IOV, ir); /* set overflow */
|
||||
}
|
||||
return (a.sign? NEG_Q (a.frac): a.frac);
|
||||
}
|
||||
|
||||
/* VAX floating add */
|
||||
|
||||
t_uint64 vax_fadd (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp, t_bool sub)
|
||||
{
|
||||
UFP a, b, t;
|
||||
uint32 sticky;
|
||||
int32 ediff;
|
||||
|
||||
if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */
|
||||
if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */
|
||||
if (sub) b.sign = b.sign ^ 1; /* sub? invert b sign */
|
||||
if (a.exp == 0) a = b; /* s1 = 0? */
|
||||
else if (b.exp) { /* s2 != 0? */
|
||||
if ((a.exp < b.exp) || /* |s1| < |s2|? swap */
|
||||
((a.exp == b.exp) && (a.frac < b.frac))) {
|
||||
t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
ediff = a.exp - b.exp; /* exp diff */
|
||||
if (a.sign ^ b.sign) { /* eff sub? */
|
||||
if (ediff > 63) b.frac = 1; /* >63? retain sticky */
|
||||
else if (ediff) { /* [1,63]? shift */
|
||||
sticky = ((b.frac << (64 - ediff)) & M64)? 1: 0; /* lost bits */
|
||||
b.frac = (b.frac >> ediff) | sticky;
|
||||
}
|
||||
a.frac = (a.frac - b.frac) & M64; /* subtract fractions */
|
||||
vax_norm (&a); /* normalize */
|
||||
}
|
||||
else { /* eff add */
|
||||
if (ediff > 63) b.frac = 0; /* >63? b disappears */
|
||||
else if (ediff) b.frac = b.frac >> ediff; /* denormalize */
|
||||
a.frac = (a.frac + b.frac) & M64; /* add frac */
|
||||
if (a.frac < b.frac) { /* chk for carry */
|
||||
a.frac = UF_NM | (a.frac >> 1); /* shift in carry */
|
||||
a.exp = a.exp + 1; /* skip norm */
|
||||
}
|
||||
}
|
||||
} /* end else if */
|
||||
return vax_rpack (&a, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* VAX floating multiply */
|
||||
|
||||
t_uint64 vax_fmul (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp)
|
||||
{
|
||||
UFP a, b;
|
||||
|
||||
if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */
|
||||
if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */
|
||||
if ((a.exp == 0) || (b.exp == 0)) return 0; /* zero argument? */
|
||||
a.sign = a.sign ^ b.sign; /* sign of result */
|
||||
a.exp = a.exp + b.exp - G_BIAS; /* add exponents */
|
||||
uemul64 (a.frac, b.frac, &a.frac); /* mpy fractions */
|
||||
vax_norm (&a); /* normalize */
|
||||
return vax_rpack (&a, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* VAX floating divide
|
||||
Needs to develop at least one rounding bit. Since the first
|
||||
divide step can fail, develop 2 more bits than the precision of
|
||||
the fraction. */
|
||||
|
||||
t_uint64 vax_fdiv (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp)
|
||||
{
|
||||
UFP a, b;
|
||||
|
||||
if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */
|
||||
if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */
|
||||
if (b.exp == 0) { /* divr = 0? */
|
||||
arith_trap (TRAP_DZE, ir); /* dze trap */
|
||||
return 0;
|
||||
}
|
||||
if (a.exp == 0) return 0; /* divd = 0? */
|
||||
a.sign = a.sign ^ b.sign; /* result sign */
|
||||
a.exp = a.exp - b.exp + G_BIAS + 1; /* unbiased exp */
|
||||
a.frac = a.frac >> 1; /* allow 1 bit left */
|
||||
b.frac = b.frac >> 1;
|
||||
a.frac = ufdiv64 (a.frac, b.frac, 55, NULL); /* divide */
|
||||
vax_norm (&a); /* normalize */
|
||||
return vax_rpack (&a, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* VAX floating square root */
|
||||
|
||||
t_uint64 vax_sqrt (uint32 ir, uint32 dp)
|
||||
{
|
||||
t_uint64 op;
|
||||
UFP b;
|
||||
|
||||
op = FR[I_GETRB (ir)]; /* get F[rb] */
|
||||
if (vax_unpack (op, &b, ir)) return 0; /* unpack, rsv? */
|
||||
if (b.exp == 0) return 0; /* zero? */
|
||||
if (b.sign) { /* minus? */
|
||||
arith_trap (TRAP_INV, ir); /* invalid operand */
|
||||
return 0;
|
||||
}
|
||||
b.exp = ((b.exp + 1 - G_BIAS) >> 1) + G_BIAS; /* result exponent */
|
||||
b.frac = fsqrt64 (b.frac, b.exp); /* result fraction */
|
||||
return vax_rpack (&b, ir, dp); /* round and pack */
|
||||
}
|
||||
|
||||
/* Support routines */
|
||||
|
||||
t_bool vax_unpack (t_uint64 op, UFP *r, uint32 ir)
|
||||
{
|
||||
r->sign = FPR_GETSIGN (op); /* get sign */
|
||||
r->exp = FPR_GETEXP (op); /* get exponent */
|
||||
r->frac = FPR_GETFRAC (op); /* get fraction */
|
||||
if (r->exp == 0) { /* exp = 0? */
|
||||
if (op != 0) arith_trap (TRAP_INV, ir); /* rsvd op? */
|
||||
r->frac = r->sign = 0;
|
||||
return TRUE;
|
||||
}
|
||||
r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool vax_unpack_d (t_uint64 op, UFP *r, uint32 ir)
|
||||
{
|
||||
r->sign = FDR_GETSIGN (op); /* get sign */
|
||||
r->exp = FDR_GETEXP (op); /* get exponent */
|
||||
r->frac = FDR_GETFRAC (op); /* get fraction */
|
||||
if (r->exp == 0) { /* exp = 0? */
|
||||
if (op != 0) arith_trap (TRAP_INV, ir); /* rsvd op? */
|
||||
r->frac = r->sign = 0;
|
||||
return TRUE;
|
||||
}
|
||||
r->exp = r->exp + G_BIAS - D_BIAS; /* change to G bias */
|
||||
r->frac = (r->frac | FDR_HB) << FDR_GUARD; /* ins hidden bit, guard */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* VAX normalize */
|
||||
|
||||
void vax_norm (UFP *r)
|
||||
{
|
||||
int32 i;
|
||||
static t_uint64 normmask[5] = {
|
||||
0xc000000000000000, 0xf000000000000000, 0xff00000000000000,
|
||||
0xffff000000000000, 0xffffffff00000000
|
||||
};
|
||||
static int32 normtab[6] = { 1, 2, 4, 8, 16, 32 };
|
||||
|
||||
r->frac = r->frac & M64;
|
||||
if (r->frac == 0) { /* if fraction = 0 */
|
||||
r->sign = r->exp = 0; /* result is 0 */
|
||||
return;
|
||||
}
|
||||
while ((r->frac & UF_NM) == 0) { /* normalized? */
|
||||
for (i = 0; i < 5; i++) { /* find first 1 */
|
||||
if (r->frac & normmask[i]) break;
|
||||
}
|
||||
r->frac = r->frac << normtab[i]; /* shift frac */
|
||||
r->exp = r->exp - normtab[i]; /* decr exp */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* VAX round and pack */
|
||||
|
||||
t_uint64 vax_rpack (UFP *r, uint32 ir, uint32 dp)
|
||||
{
|
||||
uint32 rndm = I_GETFRND (ir);
|
||||
static const t_uint64 roundbit[2] = { UF_FRND, UF_GRND };
|
||||
static const int32 expmax[2] = { G_BIAS - F_BIAS + F_M_EXP, G_M_EXP };
|
||||
static const int32 expmin[2] = { G_BIAS - F_BIAS, 0 };
|
||||
|
||||
if (r->frac == 0) return 0; /* result 0? */
|
||||
if (rndm) { /* round? */
|
||||
r->frac = (r->frac + roundbit[dp]) & M64; /* add round bit */
|
||||
if ((r->frac & UF_NM) == 0) { /* carry out? */
|
||||
r->frac = (r->frac >> 1) | UF_NM; /* renormalize */
|
||||
r->exp = r->exp + 1;
|
||||
}
|
||||
}
|
||||
if (r->exp > expmax[dp]) { /* ovflo? */
|
||||
arith_trap (TRAP_OVF, ir); /* set trap */
|
||||
r->exp = expmax[dp]; /* return max */
|
||||
}
|
||||
if (r->exp <= expmin[dp]) { /* underflow? */
|
||||
if (ir & I_FTRP_V) arith_trap (TRAP_UNF, ir); /* enabled? set trap */
|
||||
return 0; /* underflow to 0 */
|
||||
}
|
||||
return (((t_uint64) r->sign) << FPR_V_SIGN) |
|
||||
(((t_uint64) r->exp) << FPR_V_EXP) |
|
||||
((r->frac >> FPR_GUARD) & FPR_FRAC);
|
||||
}
|
||||
|
||||
t_uint64 vax_rpack_d (UFP *r, uint32 ir)
|
||||
{
|
||||
if (r->frac == 0) return 0; /* result 0? */
|
||||
r->exp = r->exp + D_BIAS - G_BIAS; /* rebias */
|
||||
if (r->exp > FDR_M_EXP) { /* ovflo? */
|
||||
arith_trap (TRAP_OVF, ir); /* set trap */
|
||||
r->exp = FDR_M_EXP; /* return max */
|
||||
}
|
||||
if (r->exp <= 0) { /* underflow? */
|
||||
if (ir & I_FTRP_V) arith_trap (TRAP_UNF, ir); /* enabled? set trap */
|
||||
return 0; /* underflow to 0 */
|
||||
}
|
||||
return (((t_uint64) r->sign) << FDR_V_SIGN) |
|
||||
(((t_uint64) r->exp) << FDR_V_EXP) |
|
||||
((r->frac >> FDR_GUARD) & FDR_FRAC);
|
||||
}
|
||||
214
Alpha/alpha_io.c
Normal file
214
Alpha/alpha_io.c
Normal file
@ -0,0 +1,214 @@
|
||||
/* alpha_io.c: Alpha I/O and miscellaneous devices
|
||||
|
||||
Copyright (c) 2006, Robert M. Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
rom boot ROM
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
#include "alpha_sys_defs.h"
|
||||
|
||||
t_uint64 *rom = NULL; /* boot ROM */
|
||||
|
||||
extern DEVICE *sim_devices[];
|
||||
|
||||
t_bool rom_rd (t_uint64 pa, t_uint64 *val, uint32 lnt);
|
||||
t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt);
|
||||
t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
|
||||
t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw);
|
||||
t_stat rom_reset (DEVICE *dptr);
|
||||
|
||||
/* ROM data structures
|
||||
|
||||
rom_dev ROM device descriptor
|
||||
rom_unit ROM units
|
||||
rom_reg ROM register list
|
||||
*/
|
||||
|
||||
DIB rom_dib = {
|
||||
ROMBASE, ROMBASE + ROMSIZE, &rom_rd, &rom_wr, 0
|
||||
};
|
||||
|
||||
UNIT rom_unit = {
|
||||
UDATA (NULL, UNIT_FIX+UNIT_BINK, ROMSIZE)
|
||||
};
|
||||
|
||||
REG rom_reg[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
DEVICE rom_dev = {
|
||||
"ROM", &rom_unit, rom_reg, NULL,
|
||||
1, 16, 24, 8, 16, 64,
|
||||
&rom_ex, &rom_dep, &rom_reset,
|
||||
NULL, NULL, NULL,
|
||||
&rom_dib, DEV_DIB
|
||||
};
|
||||
|
||||
/* ReadIO - read IO space
|
||||
|
||||
Inputs:
|
||||
pa = physical address
|
||||
*dat = pointer to data
|
||||
lnt = length (BWLQ)
|
||||
Output:
|
||||
TRUE if read succeeds, else FALSE
|
||||
*/
|
||||
|
||||
t_bool ReadIO (t_uint64 pa, t_uint64 *dat, uint32 lnt)
|
||||
{
|
||||
DEVICE *dptr;
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; sim_devices[i] != NULL; i++) {
|
||||
dptr = sim_devices[i];
|
||||
if (dptr->flags & DEV_DIB) {
|
||||
DIB *dibp = (DIB *) dptr->ctxt;
|
||||
if ((pa >= dibp->low) && (pa < dibp->high))
|
||||
return dibp->read (pa, dat, lnt);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* WriteIO - write register space
|
||||
|
||||
Inputs:
|
||||
ctx = CPU context
|
||||
pa = physical address
|
||||
val = data to write, right justified in 64b quadword
|
||||
lnt = length (BWLQ)
|
||||
Output:
|
||||
TRUE if write succeeds, else FALSE
|
||||
*/
|
||||
|
||||
t_bool WriteIO (t_uint64 pa, t_uint64 dat, uint32 lnt)
|
||||
{
|
||||
DEVICE *dptr;
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; sim_devices[i] != NULL; i++) {
|
||||
dptr = sim_devices[i];
|
||||
if (dptr->flags & DEV_DIB) {
|
||||
DIB *dibp = (DIB *) dptr->ctxt;
|
||||
if ((pa >= dibp->low) && (pa < dibp->high))
|
||||
return dibp->write (pa, dat, lnt);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Boot ROM read */
|
||||
|
||||
t_bool rom_rd (t_uint64 pa, t_uint64 *val, uint32 lnt)
|
||||
{
|
||||
uint32 sc, rg = ((uint32) ((pa - ROMBASE) & (ROMSIZE - 1))) >> 3;
|
||||
|
||||
switch (lnt) {
|
||||
|
||||
case L_BYTE:
|
||||
sc = (((uint32) pa) & 7) * 8;
|
||||
*val = (rom[rg] >> sc) & M8;
|
||||
break;
|
||||
|
||||
case L_WORD:
|
||||
sc = (((uint32) pa) & 6) * 8;
|
||||
*val = (rom[rg] >> sc) & M16;
|
||||
break;
|
||||
|
||||
case L_LONG:
|
||||
if (pa & 4) *val = (rom[rg] >> 32) & M32;
|
||||
else *val = rom[rg] & M32;
|
||||
break;
|
||||
|
||||
case L_QUAD:
|
||||
*val = rom[rg];
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Boot ROM write */
|
||||
|
||||
t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt)
|
||||
{
|
||||
uint32 sc, rg = ((uint32) ((pa - ROMBASE) & (ROMSIZE - 1))) >> 3;
|
||||
|
||||
switch (lnt) {
|
||||
|
||||
case L_BYTE:
|
||||
sc = (((uint32) pa) & 7) * 8;
|
||||
rom[rg] = (rom[rg] & ~(((t_uint64) M8) << sc)) | (((t_uint64) (val & M8)) << sc);
|
||||
break;
|
||||
|
||||
case L_WORD:
|
||||
sc = (((uint32) pa) & 6) * 8;
|
||||
rom[rg] = (rom[rg] & ~(((t_uint64) M16) << sc)) | (((t_uint64) (val & M16)) << sc);
|
||||
break;
|
||||
|
||||
case L_LONG:
|
||||
if (pa & 4) rom[rg] = ((t_uint64) (rom[rg] & M32)) | (((t_uint64) (val & M32)) << 32);
|
||||
else rom[rg] = (rom[rg] & ~((t_uint64) M32)) | ((t_uint64) val & M32);
|
||||
break;
|
||||
|
||||
case L_QUAD:
|
||||
rom[rg] = val;
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ROM examine */
|
||||
|
||||
t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
|
||||
{
|
||||
uint32 addr = (uint32) exta;
|
||||
|
||||
if (vptr == NULL) return SCPE_ARG;
|
||||
if (addr >= ROMSIZE) return SCPE_NXM;
|
||||
*vptr = rom[addr >> 3];
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* ROM deposit */
|
||||
|
||||
t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
|
||||
{
|
||||
uint32 addr = (uint32) exta;
|
||||
|
||||
if (addr >= ROMSIZE) return SCPE_NXM;
|
||||
rom[addr >> 3] = val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* ROM reset */
|
||||
|
||||
t_stat rom_reset (DEVICE *dptr)
|
||||
{
|
||||
if (rom == NULL) rom = (t_uint64 *) calloc (ROMSIZE >> 3, sizeof (t_uint64));
|
||||
if (rom == NULL) return SCPE_MEM;
|
||||
return SCPE_OK;
|
||||
}
|
||||
308
Alpha/alpha_mmu.c
Normal file
308
Alpha/alpha_mmu.c
Normal file
@ -0,0 +1,308 @@
|
||||
/* alpha_mmu.c - Alpha memory management simulator
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This module contains the routines for
|
||||
|
||||
ReadB,W,L,Q - read aligned virtual
|
||||
ReadAccL,Q - read aligned virtual, special access check
|
||||
ReadPB,W,L,Q - read aligned physical
|
||||
WriteB,W,L,Q - write aligned virtual
|
||||
WriteAccL,Q - write aligned virtual, special access check
|
||||
WritePB,W,L,Q - write aligned physical
|
||||
|
||||
The TLB is organized for optimum lookups and is broken up into three fields:
|
||||
|
||||
tag VA<42:13> for an 8KB page system
|
||||
pte PTE<31:0>, <31:16> are zero; FOE, FOR, FOW stored inverted
|
||||
pfn PFN<31:0> left shifted by page size
|
||||
|
||||
The inversion of FOE, FOR, FOW means that all checked bits must be one
|
||||
for a reference to proceed.
|
||||
|
||||
All Alpha implementations provide support for a 43b superpage for Unix,
|
||||
and a 32b superpage for NT:
|
||||
|
||||
43b superpage 0xFFFFFC0000000000:0xFFFFFDFFFFFFFFFF
|
||||
32b superpage 0xFFFFFFFF80000000:0xFFFFFFFFBFFFFFFF
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
|
||||
extern t_uint64 trans_i (t_uint64 va);
|
||||
extern t_uint64 trans_d (t_uint64 va, uint32 acc);
|
||||
|
||||
extern t_uint64 *M;
|
||||
extern t_uint64 p1;
|
||||
extern uint32 pal_mode, dmapen;
|
||||
extern uint32 cm_eacc, cm_racc, cm_wacc;
|
||||
extern jmp_buf save_env;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
/* Read virtual aligned
|
||||
|
||||
Inputs:
|
||||
va = virtual address
|
||||
Output:
|
||||
returned data, right justified
|
||||
*/
|
||||
|
||||
t_uint64 ReadB (t_uint64 va)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */
|
||||
else pa = va;
|
||||
return ReadPB (pa);
|
||||
}
|
||||
|
||||
t_uint64 ReadW (t_uint64 va)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 1) ABORT1 (va, EXC_ALIGN); /* must be W aligned */
|
||||
if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */
|
||||
else pa = va;
|
||||
return ReadPW (pa);
|
||||
}
|
||||
|
||||
t_uint64 ReadL (t_uint64 va)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */
|
||||
if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */
|
||||
else pa = va;
|
||||
return ReadPL (pa);
|
||||
}
|
||||
|
||||
t_uint64 ReadQ (t_uint64 va)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */
|
||||
if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */
|
||||
else pa = va;
|
||||
return ReadPQ (pa);
|
||||
}
|
||||
|
||||
/* Read with generalized access controls - used by PALcode */
|
||||
|
||||
t_uint64 ReadAccL (t_uint64 va, uint32 acc)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */
|
||||
if (dmapen) pa = trans_d (va, acc); /* mapping on? */
|
||||
else pa = va;
|
||||
return ReadPL (pa);
|
||||
}
|
||||
|
||||
t_uint64 ReadAccQ (t_uint64 va, uint32 acc)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */
|
||||
if (dmapen) pa = trans_d (va, acc); /* mapping on? */
|
||||
else pa = va;
|
||||
return ReadPQ (pa);
|
||||
}
|
||||
|
||||
/* Read instruction */
|
||||
|
||||
uint32 ReadI (t_uint64 va)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (!pal_mode) pa = trans_i (va); /* mapping on? */
|
||||
else pa = va;
|
||||
return (uint32) ReadPL (pa);
|
||||
}
|
||||
|
||||
/* Write virtual aligned
|
||||
|
||||
Inputs:
|
||||
va = virtual address
|
||||
val = data to be written, right justified in 32b or 64b
|
||||
Output:
|
||||
none
|
||||
*/
|
||||
|
||||
void WriteB (t_uint64 va, t_uint64 dat)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */
|
||||
else pa = va;
|
||||
WritePB (pa, dat);
|
||||
return;
|
||||
}
|
||||
|
||||
void WriteW (t_uint64 va, t_uint64 dat)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 1) ABORT1 (va, EXC_ALIGN); /* must be W aligned */
|
||||
if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */
|
||||
else pa = va;
|
||||
WritePW (pa, dat);
|
||||
return;
|
||||
}
|
||||
|
||||
void WriteL (t_uint64 va, t_uint64 dat)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */
|
||||
if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */
|
||||
else pa = va;
|
||||
WritePL (pa, dat);
|
||||
return;
|
||||
}
|
||||
|
||||
void WriteQ (t_uint64 va, t_uint64 dat)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */
|
||||
if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */
|
||||
else pa = va;
|
||||
WritePQ (pa, dat);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Write with generalized access controls - used by PALcode */
|
||||
|
||||
void WriteAccL (t_uint64 va, t_uint64 dat, uint32 acc)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */
|
||||
if (dmapen) pa = trans_d (va, acc); /* mapping on? */
|
||||
else pa = va;
|
||||
WritePL (pa, dat);
|
||||
return;
|
||||
}
|
||||
|
||||
void WriteAccQ (t_uint64 va, t_uint64 dat, uint32 acc)
|
||||
{
|
||||
t_uint64 pa;
|
||||
|
||||
if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */
|
||||
if (dmapen) pa = trans_d (va, acc); /* mapping on? */
|
||||
else pa = va;
|
||||
WritePQ (pa, dat);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read and write physical aligned - access point to I/O */
|
||||
|
||||
INLINE t_uint64 ReadPB (t_uint64 pa)
|
||||
{
|
||||
t_uint64 val;
|
||||
|
||||
if (ADDR_IS_MEM (pa)) {
|
||||
uint32 bo = ((uint32) pa) & 07;
|
||||
return (((M[pa >> 3] >> (bo << 3))) & M8);
|
||||
}
|
||||
if (ReadIO (pa, &val, L_BYTE)) return val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
INLINE t_uint64 ReadPW (t_uint64 pa)
|
||||
{
|
||||
t_uint64 val;
|
||||
|
||||
if (ADDR_IS_MEM (pa)) {
|
||||
uint32 bo = ((uint32) pa) & 06;
|
||||
return (((M[pa >> 3] >> (bo << 3))) & M16);
|
||||
}
|
||||
if (ReadIO (pa, &val, L_WORD)) return val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
INLINE t_uint64 ReadPL (t_uint64 pa)
|
||||
{
|
||||
t_uint64 val;
|
||||
|
||||
if (ADDR_IS_MEM (pa)) {
|
||||
if (pa & 4) return (((M[pa >> 3] >> 32)) & M32);
|
||||
return ((M[pa >> 3]) & M32);
|
||||
}
|
||||
if (ReadIO (pa, &val, L_LONG)) return val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
INLINE t_uint64 ReadPQ (t_uint64 pa)
|
||||
{
|
||||
t_uint64 val;
|
||||
|
||||
if (ADDR_IS_MEM (pa)) return M[pa >> 3];
|
||||
if (ReadIO (pa, &val, L_QUAD)) return val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
INLINE void WritePB (t_uint64 pa, t_uint64 dat)
|
||||
{
|
||||
dat = dat & M8;
|
||||
if (ADDR_IS_MEM (pa)) {
|
||||
uint32 bo = ((uint32) pa) & 07;
|
||||
M[pa >> 3] = (M[pa >> 3] & ~(((t_uint64) M8) << (bo << 3))) |
|
||||
(dat << (bo << 3));
|
||||
}
|
||||
else WriteIO (pa, dat, L_BYTE);
|
||||
return;
|
||||
}
|
||||
|
||||
INLINE void WritePW (t_uint64 pa, t_uint64 dat)
|
||||
{
|
||||
dat = dat & M16;
|
||||
if (ADDR_IS_MEM (pa)) {
|
||||
uint32 bo = ((uint32) pa) & 07;
|
||||
M[pa >> 3] = (M[pa >> 3] & ~(((t_uint64) M16) << (bo << 3))) |
|
||||
(dat << (bo << 3));
|
||||
}
|
||||
else WriteIO (pa, dat, L_WORD);
|
||||
return;
|
||||
}
|
||||
|
||||
INLINE void WritePL (t_uint64 pa, t_uint64 dat)
|
||||
{
|
||||
dat = dat & M32;
|
||||
if (ADDR_IS_MEM (pa)) {
|
||||
if (pa & 4) M[pa >> 3] = (M[pa >> 3] & M32) |
|
||||
(dat << 32);
|
||||
else M[pa >> 3] = (M[pa >> 3] & ~((t_uint64) M32)) | dat;
|
||||
}
|
||||
else WriteIO (pa, dat, L_LONG);
|
||||
return;
|
||||
}
|
||||
|
||||
INLINE void WritePQ (t_uint64 pa, t_uint64 dat)
|
||||
{
|
||||
if (ADDR_IS_MEM (pa)) M[pa >> 3] = dat;
|
||||
else WriteIO (pa, dat, L_QUAD);
|
||||
return;
|
||||
}
|
||||
|
||||
814
Alpha/alpha_sys.c
Normal file
814
Alpha/alpha_sys.c
Normal file
@ -0,0 +1,814 @@
|
||||
/* alpha_sys.c: Alpha simulator interface
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern int32 sim_switches;
|
||||
extern uint32 pal_type;
|
||||
|
||||
t_stat fprint_sym_m (FILE *of, t_addr addr, uint32 inst);
|
||||
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *inst);
|
||||
int32 parse_reg (char *cptr);
|
||||
|
||||
extern t_stat fprint_pal_hwre (FILE *of, uint32 inst);
|
||||
extern t_stat parse_pal_hwre (char *cptr, t_value *inst);
|
||||
extern t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt);
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax number of words for examine
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 1;
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Unsupported PAL variation",
|
||||
"Kernel stack not valid",
|
||||
"Unknown abort code",
|
||||
"Memory management error"
|
||||
};
|
||||
|
||||
/* Binary loader
|
||||
|
||||
The binary loader handles absolute system images, that is, system
|
||||
images linked /SYSTEM. These are simply a byte stream, with no
|
||||
origin or relocation information.
|
||||
|
||||
-r load ROM
|
||||
-o specify origin
|
||||
*/
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
t_stat r;
|
||||
int32 i;
|
||||
t_uint64 origin;
|
||||
|
||||
if (flag) return SCPE_ARG; /* dump? */
|
||||
origin = 0; /* memory */
|
||||
if (sim_switches & SWMASK ('O')) { /* origin? */
|
||||
origin = get_uint (cptr, 16, 0xFFFFFFFF, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
}
|
||||
|
||||
while ((i = getc (fileref)) != EOF) { /* read byte stream */
|
||||
if (sim_switches & SWMASK ('R')) { /* ROM? */
|
||||
if (!rom_wr (origin, i, L_BYTE))
|
||||
return SCPE_NXM;
|
||||
}
|
||||
else if (ADDR_IS_MEM (origin)) /* valid memory? */
|
||||
WritePB (origin, i);
|
||||
else return SCPE_NXM;
|
||||
origin = origin + 1;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Opcode mnemonics table */
|
||||
|
||||
#define CL_NO 0 /* no operand */
|
||||
#define CL_BR 1 /* branch */
|
||||
#define CL_MR 2 /* memory reference */
|
||||
#define CL_IO 3 /* integer opr */
|
||||
#define CL_FO 4 /* floating opr */
|
||||
#define CL_MO 5 /* memory opr */
|
||||
#define CL_JP 6 /* jump */
|
||||
#define CL_HW 7 /* hardware */
|
||||
#define CL_M_PAL 0x00F0
|
||||
#define CL_V_PAL 4
|
||||
#define CL_VMS (1u << (PAL_VMS + CL_V_PAL))
|
||||
#define CL_UNIX (1u << (PAL_UNIX + CL_V_PAL))
|
||||
#define CL_NT (1u << (PAL_NT + CL_V_PAL))
|
||||
#define FL_RA 0x0100
|
||||
#define FL_RB 0x0200
|
||||
#define FL_RC 0x0400
|
||||
#define FL_RBI 0x0800
|
||||
#define FL_MDP 0x1000
|
||||
#define FL_BDP 0x2000
|
||||
#define FL_JDP 0x4000
|
||||
#define FL_LIT 0x8000
|
||||
#define CL_CLASS 0x000F
|
||||
#define PAL_MASK(x) (1u << (pal_type + CL_V_PAL))
|
||||
|
||||
#define C_NO CL_NO
|
||||
#define C_PCM CL_NO | CL_VMS | CL_UNIX | CL_NT
|
||||
#define C_PVM CL_NO | CL_VMS
|
||||
#define C_PUN CL_NO | CL_UNIX
|
||||
#define C_PNT CL_NO | CL_NT
|
||||
#define C_BR CL_BR | FL_RA | FL_BDP
|
||||
#define C_MR CL_MR | FL_RA | FL_RB | FL_RBI | FL_MDP
|
||||
#define C_FE CL_MO | FL_RB | FL_RBI
|
||||
#define C_RV CL_MO | FL_RA
|
||||
#define C_MO CL_MO | FL_RA | FL_RB
|
||||
#define C_IO CL_IO | FL_RA | FL_RB | FL_RC | FL_LIT
|
||||
#define C_IAC CL_IO | FL_RA | FL_RC
|
||||
#define C_IBC CL_IO | FL_RB | FL_RC | FL_LIT
|
||||
#define C_FO CL_FO | FL_RA | FL_RB | FL_RC
|
||||
#define C_FAC CL_FO | FL_RA | FL_RC
|
||||
#define C_FBC CL_FO | FL_RB | FL_RC
|
||||
#define C_JP CL_JP | FL_RA | FL_RB | FL_RBI | FL_JDP
|
||||
#define C_HW CL_HW
|
||||
|
||||
uint32 masks[8] = {
|
||||
0xFFFFFFFF, 0xFC000000,
|
||||
0xFC000000, 0xFC000FE0,
|
||||
0xFC00FFE0, 0xFC00FFFF,
|
||||
0xFC00C000, 0xFC000000
|
||||
};
|
||||
|
||||
const char *opcode[] = {
|
||||
"HALT", "DRAINA", "CFLUSH", "LDQP", /* VMS PALcode */
|
||||
"STQP", "SWPCTX", "MFPR_ASN", "MTPR_ASTEN",
|
||||
"MTPR_ASTSR", "CSERVE", "SWPPAL", "MFPR_FEN",
|
||||
"MTPR_FEN", "MTPR_IPIR", "MFPR_IPL", "MTPR_IPL",
|
||||
"MFPR_MCES", "MTPR_MCES", "MFPR_PCBB", "MFPR_PRBR",
|
||||
"MTPR_PRBR", "MFPR_PTBR", "MFPR_SCBB", "MTPR_SCBB",
|
||||
"MTPR_SIRR", "MFPR_SISR", "MFPR_TBCHK", "MTPR_TBIA",
|
||||
"MTPR_TBIAP", "MTPR_TBIS", "MFPR_ESP", "MTPR_ESP",
|
||||
"MFPR_SSP", "MTPR_SSP", "MFPR_USP", "MTPR_USP",
|
||||
"MTPR_TBISD", "MTPR_TBISI", "MFPR_ASTEN", "MFPR_ASTSR",
|
||||
"MFPR_VTBR", "MTPR_VTBR", "MTPR_PERFMON", "MTPR_DATFX",
|
||||
"MFPR_VIRBND", "MTPR_VIRBND", "MFPR_SYSPTBR", "MTPR_SYSPTBR",
|
||||
"WTINT", "MFPR_WHAMI",
|
||||
"BPT", "BUGCHK", "CHME", "CHMK",
|
||||
"CHMS", "CHMU", "IMB", "INSQHIL",
|
||||
"INSQTIL", "INSQHIQ", "INSQTIQ", "INSQUEL",
|
||||
"INSQUEQ", "INSQUEL/D", "INSQUEQ/D", "PROBER",
|
||||
"PROBEW", "RD_PS", "REI", "REMQHIL",
|
||||
"REMQTIL", "REMQHIQ", "REMQTIQ", "REMQUEL",
|
||||
"REMQUEQ", "REMQUEL/D", "REMQUEQ/D", "SWASTEN",
|
||||
"WR_PS_SW", "RSCC", "RD_UNQ", "WR_UNQ",
|
||||
"AMOVRR", "AMOVRM", "INSQHILR", "INSQTILR",
|
||||
"INSQHIQR", "INSQTIQR", "REMQHILR", "REMQTILR",
|
||||
"REMQHIQR", "REMQTIQR", "GENTRAP", "CLRFEN",
|
||||
"RDMCES", "WRMCES", "WRVIRBND", "WRSYSPTBR", /* UNIX PALcode */
|
||||
"WRFEN", "WRVPTPTR", "WRASN",
|
||||
"SWPCTX", "WRVAL", "RDVAL", "TBI",
|
||||
"WRENT", "SWPIPL", "RDPS", "WRKGP",
|
||||
"WRUSP", "WRPERFMON", "RDUSP",
|
||||
"WHAMI", "RETSYS", "RTI",
|
||||
"URTI", "RDUNIQUE", "WRUNIQUE",
|
||||
"LDA", "LDAH", "LDBU", "LDQ_U",
|
||||
"LDWU", "STW", "STB", "STQ_U",
|
||||
"ADDL", "S4ADDL", "SUBL", "S4SUBL",
|
||||
"CMPBGE", "S8ADDL", "S8SUBL", "CMPULT",
|
||||
"ADDQ", "S4ADDQ", "SUBQ", "S4SUBQ",
|
||||
"CMPEQ", "S8ADDQ", "S8SUBQ", "CMPULE",
|
||||
"ADDL/V", "SUBL/V", "CMPLT",
|
||||
"ADDQ/V", "SUBQ/V", "CMPLE",
|
||||
"AND", "BIC", "CMOVLBS", "CMOVLBC",
|
||||
"BIS", "CMOVEQ", "CMOVNE", "ORNOT",
|
||||
"XOR", "CMOVLT", "CMOVGE", "EQV",
|
||||
"CMOVLE", "CMOVGT",
|
||||
"MSKBL", "EXTBL", "INSBL",
|
||||
"MSKWL", "EXTWL", "INSWL",
|
||||
"MSKLL", "EXTLL", "INSLL",
|
||||
"ZAP", "ZAPNOT", "MSKQL", "SRL",
|
||||
"EXTQL", "SLL", "INSQL", "SRA",
|
||||
"MSKWQ", "EXTWQ", "INSWQ",
|
||||
"MSKLQ", "EXTLQ", "INSLQ",
|
||||
"MSKQH", "EXTQH", "INSQH",
|
||||
"MULL", "MULQ", "UMULH",
|
||||
"MULL/V", "MULLQ/V",
|
||||
"ITOFS", "ITOFF", "ITOFT",
|
||||
"SQRTF/C", "SQRTF", "SQRTF/UC", "SQRTF/U",
|
||||
"SQRTF/SC", "SQRTF/S", "SQRTF/SUC", "SQRTF/SU",
|
||||
"SQRTG/C", "SQRTG", "SQRTG/UC", "SQRTG/U",
|
||||
"SQRTG/SC", "SQRTG/S", "SQRTG/SUC", "SQRTG/SU",
|
||||
"SQRTS/C", "SQRTS/M", "SQRTS", "SQRTS/D",
|
||||
"SQRTS/UC", "SQRTS/UM", "SQRTS/U", "SQRTS/UD",
|
||||
"SQRTS/SUC", "SQRTS/SUM", "SQRTS/SU", "SQRTS/SUD",
|
||||
"SQRTS/SUIC", "SQRTS/SUIM", "SQRTS/SUI", "SQRTS/SUID",
|
||||
"SQRTT/C", "SQRTT/M", "SQRTT", "SQRTT/D",
|
||||
"SQRTT/UC", "SQRTT/UM", "SQRTT/U", "SQRTT/UD",
|
||||
"SQRTT/SUC", "SQRTT/SUM", "SQRTT/SU", "SQRTT/SUD",
|
||||
"SQRTT/SUIC", "SQRTT/SUIM", "SQRTT/SUI", "SQRTT/SUID",
|
||||
"ADDF/C", "ADDF", "ADDF/UC", "ADDF/U",
|
||||
"ADDF/SC", "ADDF/S", "ADDF/SUC", "ADDF/SU",
|
||||
"SUBF/C", "SUBF", "SUBF/UC", "SUBF/U",
|
||||
"SUBF/SC", "SUBF/S", "SUBF/SUC", "SUBF/SU",
|
||||
"MULF/C", "MULF", "MULF/UC", "MULF/U",
|
||||
"MULF/SC", "MULF/S", "MULF/SUC", "MULF/SU",
|
||||
"DIVF/C", "DIVF", "DIVF/UC", "DIVF/U",
|
||||
"DIVF/SC", "DIVF/S", "DIVF/SUC", "DIVF/SU",
|
||||
"ADDG/C", "ADDG", "ADDG/UC", "ADDG/U",
|
||||
"ADDG/SC", "ADDG/S", "ADDG/SUC", "ADDG/SU",
|
||||
"SUBG/C", "SUBG", "SUBG/UC", "SUBG/U",
|
||||
"SUBG/SC", "SUBG/S", "SUBG/SUC", "SUBG/SU",
|
||||
"MULG/C", "MULG", "MULG/UC", "MULG/U",
|
||||
"MULG/SC", "MULG/S", "MULG/SUC", "MULG/SU",
|
||||
"DIVG/C", "DIVG", "DIVG/UC", "DIVG/U",
|
||||
"DIVG/SC", "DIVG/S", "DIVG/SUC", "DIVG/SU",
|
||||
"CVTDG/C", "CVTDG", "CVTDG/UC", "CVTDG/U",
|
||||
"CVTDG/SC", "CVTDG/S", "CVTDG/SUC", "CVTDG/SU",
|
||||
"CVTGF/C", "CVTGF", "CVTGF/UC", "CVTGF/U",
|
||||
"CVTGF/SC", "CVTGF/S", "CVTGF/SUC", "CVTGF/SU",
|
||||
"CVTGD/C", "CVTGD", "CVTGD/UC", "CVTGD/U",
|
||||
"CVTGD/SC", "CVTGD/S", "CVTGD/SUC", "CVTGD/SU",
|
||||
"CVTGQ/C", "CVTGQ", "CVTGQ/VC", "CVTGQ/V",
|
||||
"CVTGQ/SC", "CVTGQ/S", "CVTGQ/SVC", "CVTGQ/SV",
|
||||
"CVTQF/C", "CVTQF", "CVTQG/C", "CVTQG",
|
||||
"CMPGEQ/C", "CMPGEQ/SC", "CMPGLT/C", "CMPGLT/SC",
|
||||
"CMPGLE/C", "CMPGLE/SC",
|
||||
"ADDS/C", "ADDS/M", "ADDS", "ADDS/D",
|
||||
"ADDS/UC", "ADDS/UM", "ADDS/U", "ADDS/UD",
|
||||
"ADDS/SUC", "ADDS/SUM", "ADDS/SU", "ADDS/SUD",
|
||||
"ADDS/SUIC", "ADDS/SUIM", "ADDS/SUI", "ADDS/SUID",
|
||||
"SUBS/C", "SUBS/M", "SUBS", "SUBS/D",
|
||||
"SUBS/UC", "SUBS/UM", "SUBS/U", "SUBS/UD",
|
||||
"SUBS/SUC", "SUBS/SUM", "SUBS/SU", "SUBS/SUD",
|
||||
"SUBS/SUIC", "SUBS/SUIM", "SUBS/SUI", "SUBS/SUID",
|
||||
"MULS/C", "MULS/M", "MULS", "MULS/D",
|
||||
"MULS/UC", "MULS/UM", "MULS/U", "MULS/UD",
|
||||
"MULS/SUC", "MULS/SUM", "MULS/SU", "MULS/SUD",
|
||||
"MULS/SUIC", "MULS/SUIM", "MULS/SUI", "MULS/SUID",
|
||||
"DIVS/C", "DIVS/M", "DIVS", "DIVS/D",
|
||||
"DIVS/UC", "DIVS/UM", "DIVS/U", "DIVS/UD",
|
||||
"DIVS/SUC", "DIVS/SUM", "DIVS/SU", "DIVS/SUD",
|
||||
"DIVS/SUIC", "DIVS/SUIM", "DIVS/SUI", "DIVS/SUID",
|
||||
"ADDT/C", "ADDT/M", "ADDT", "ADDT/D",
|
||||
"ADDT/UC", "ADDT/UM", "ADDT/U", "ADDT/UD",
|
||||
"ADDT/SUC", "ADDT/SUM", "ADDT/SU", "ADDT/SUD",
|
||||
"ADDT/SUIC", "ADDT/SUIM", "ADDT/SUI", "ADDT/SUID",
|
||||
"SUBT/C", "SUBT/M", "SUBT", "SUBT/D",
|
||||
"SUBT/UC", "SUBT/UM", "SUBT/U", "SUBT/UD",
|
||||
"SUBT/SUC", "SUBT/SUM", "SUBT/SU", "SUBT/SUD",
|
||||
"SUBT/SUIC", "SUBT/SUIM", "SUBT/SUI", "SUBT/SUID",
|
||||
"MULT/C", "MULT/M", "MULT", "MULT/D",
|
||||
"MULT/UC", "MULT/UM", "MULT/U", "MULT/UD",
|
||||
"MULT/SUC", "MULT/SUM", "MULT/SU", "MULT/SUD",
|
||||
"MULT/SUIC", "MULT/SUIM", "MULT/SUI", "MULT/SUID",
|
||||
"DIVT/C", "DIVT/M", "DIVT", "DIVT/D",
|
||||
"DIVT/UC", "DIVT/UM", "DIVT/U", "DIVT/UD",
|
||||
"DIVT/SUC", "DIVT/SUM", "DIVT/SU", "DIVT/SUD",
|
||||
"DIVT/SUIC", "DIVT/SUIM", "DIVT/SUI", "DIVT/SUID",
|
||||
"CVTTS/C", "CVTTS/M", "CVTTS", "CVTTS/D",
|
||||
"CVTTS/UC", "CVTTS/UM", "CVTTS/U", "CVTTS/UD",
|
||||
"CVTTS/SUC", "CVTTS/SUM", "CVTTS/SU", "CVTTS/SUD",
|
||||
"CVTTS/SUIC", "CVTTS/SUIM", "CVTTS/SUI", "CVTTS/SUID",
|
||||
"CVTTQ/C", "CVTTQ/M", "CVTTQ", "CVTTQ/D",
|
||||
"CVTTQ/VC", "CVTTQ/VM", "CVTTQ/V", "CVTTQ/VD",
|
||||
"CVTTQ/SVC", "CVTTQ/SVM", "CVTTQ/SV", "CVTTQ/SVD",
|
||||
"CVTTQ/SVIC", "CVTTQ/SVIM", "CVTTQ/SVI", "CVTTQ/SVID",
|
||||
"CVTQS/C", "CVTQS/M", "CVTQS", "CVTQS/D",
|
||||
"CVTQS/SUIC", "CVTQS/SUIM", "CVTQS/SUI", "CVTQS/SUID",
|
||||
"CVTQT/C", "CVTQT/M", "CVTQT", "CVTQT/D",
|
||||
"CVTQT/SUIC", "CVTQT/SUIM", "CVTQT/SUI", "CVTQT/SUID",
|
||||
"CMPTUN/C", "CMPTUN/S", "CMPTEQ/C", "CMPTEQ/S",
|
||||
"CMPTLT/C", "CMPTLT/S", "CMPTLE/C", "CMPTLE/S",
|
||||
"CVTLQ", "CPYS", "CPYSN", "CPYSE",
|
||||
"MT_FPCR", "MF_FPCR",
|
||||
"FCMOVEQ", "FCMOVNE", "FCMOVLT",
|
||||
"FCMOVGE", "FCMOVLE", "FCMOVGT",
|
||||
"CVTQL", "CVTQL/V", "CVTQL/SV",
|
||||
"TRAPB", "EXCB", "MB", "WMB",
|
||||
"FETCH", "FETCH_M", "RPCC",
|
||||
"RC", "RS",
|
||||
"JMP", "JSR", "RET", "JSR_COROUTINE",
|
||||
"SEXTB", "SEXTW",
|
||||
"CTPOP", "PERR", "CTLZ", "CTTZ",
|
||||
"UNPKBW", "UNPKBL", "PKWB", "PKLB",
|
||||
"MINSB8", "MINSW4", "MINUB8", "MINUW4",
|
||||
"MAXSB8", "MAXSW4", "MAXUB8", "MAXUW4",
|
||||
"FTOIT", "FTOIS",
|
||||
"LDF", "LDG", "LDS", "LDT",
|
||||
"STS", "STG", "STS", "STT",
|
||||
"LDL", "LDQ", "LDL_L", "LDQ_L",
|
||||
"STL", "STQ", "STL_L", "STQ_L",
|
||||
"BR", "FBEQ", "FBLT", "FBLE",
|
||||
"BSR", "FBNE", "BFGE", "FBGT",
|
||||
"BLBC", "BEQ", "BLT", "BLE",
|
||||
"BLBS", "BNE", "BGE", "BGT",
|
||||
NULL
|
||||
};
|
||||
|
||||
const uint32 opval[] = {
|
||||
0x00000000, C_PCM, 0x00000001, C_PCM, 0x00000002, C_PCM, 0x00000003, C_PVM,
|
||||
0x00000004, C_PVM, 0x00000005, C_PVM, 0x00000006, C_PVM, 0x00000007, C_PVM,
|
||||
0x00000008, C_PVM, 0x00000009, C_PCM, 0x0000000A, C_PCM, 0x0000000B, C_PVM,
|
||||
0x0000000C, C_PVM, 0x0000000D, C_PVM, 0x0000000E, C_PVM, 0x0000000F, C_PVM,
|
||||
0x00000010, C_PVM, 0x00000011, C_PVM, 0x00000012, C_PVM, 0x00000013, C_PVM,
|
||||
0x00000014, C_PVM, 0x00000015, C_PVM, 0x00000016, C_PVM, 0x00000017, C_PVM,
|
||||
0x00000018, C_PVM, 0x00000019, C_PVM, 0x0000001A, C_PVM, 0x0000001B, C_PVM,
|
||||
0x0000001C, C_PVM, 0x0000001D, C_PVM, 0x0000001E, C_PVM, 0x0000001F, C_PVM,
|
||||
0x00000020, C_PVM, 0x00000021, C_PVM, 0x00000022, C_PVM, 0x00000023, C_PVM,
|
||||
0x00000024, C_PVM, 0x00000025, C_PVM, 0x00000026, C_PVM, 0x00000027, C_PVM,
|
||||
0x00000029, C_PVM, 0x0000002A, C_PVM, 0x0000002B, C_PVM, 0x0000002E, C_PVM,
|
||||
0x00000030, C_PVM, 0x00000031, C_PVM, 0x00000032, C_PVM, 0x00000033, C_PVM,
|
||||
0x0000003E, C_PCM, 0x0000003F, C_PVM,
|
||||
0x00000080, C_PCM, 0x00000081, C_PCM, 0x00000082, C_PVM, 0x00000083, C_PVM,
|
||||
0x00000084, C_PVM, 0x00000085, C_PVM, 0x00000086, C_PCM, 0x00000087, C_PVM,
|
||||
0x00000088, C_PVM, 0x00000089, C_PVM, 0x0000008A, C_PVM, 0x0000008B, C_PVM,
|
||||
0x0000008C, C_PVM, 0x0000008D, C_PVM, 0x0000008E, C_PVM, 0x0000008F, C_PVM,
|
||||
0x00000090, C_PVM, 0x00000091, C_PVM, 0x00000092, C_PVM, 0x00000093, C_PVM,
|
||||
0x00000094, C_PVM, 0x00000095, C_PVM, 0x00000096, C_PVM, 0x00000097, C_PVM,
|
||||
0x00000098, C_PVM, 0x00000099, C_PVM, 0x0000009A, C_PVM, 0x0000009B, C_PVM,
|
||||
0x0000009C, C_PVM, 0x0000009D, C_PVM, 0x0000009E, C_PVM, 0x0000009F, C_PVM,
|
||||
0x000000A0, C_PVM, 0x000000A1, C_PVM, 0x000000A2, C_PVM, 0x000000A3, C_PVM,
|
||||
0x000000A4, C_PVM, 0x000000A5, C_PVM, 0x000000A6, C_PVM, 0x000000A7, C_PVM,
|
||||
0x000000A8, C_PVM, 0x000000A9, C_PVM, 0x000000AA, C_PCM, 0x000000AE, C_PCM,
|
||||
0x00000010, C_PUN, 0x00000011, C_PUN, 0x00000013, C_PUN, 0x00000014, C_PUN,
|
||||
0x0000002B, C_PUN, 0x0000002D, C_PUN, 0x0000002E, C_PUN,
|
||||
0x00000030, C_PUN, 0x00000031, C_PUN, 0x00000032, C_PUN, 0x00000033, C_PUN,
|
||||
0x00000034, C_PUN, 0x00000035, C_PUN, 0x00000036, C_PUN, 0x00000037, C_PUN,
|
||||
0x00000038, C_PUN, 0x00000039, C_PUN, 0x0000003A, C_PUN,
|
||||
0x0000003C, C_PUN, 0x0000003D, C_PUN, 0x0000003F, C_PUN,
|
||||
0x00000092, C_PUN, 0x0000009E, C_PUN, 0x0000009F, C_PUN,
|
||||
0x20000000, C_MR, 0x24000000, C_MR, 0x28000000, C_MR, 0x2C000000, C_MR,
|
||||
0x30000000, C_MR, 0x34000000, C_MR, 0x38000000, C_MR, 0x3C000000, C_MR,
|
||||
0x40000000, C_IO, 0x40000040, C_IO, 0x40000120, C_IO, 0x40000160, C_IO,
|
||||
0x400001C0, C_IO, 0x40000240, C_IO, 0x40000360, C_IO, 0x400003A0, C_IO,
|
||||
0x40000400, C_IO, 0x40000440, C_IO, 0x40000520, C_IO, 0x40000560, C_IO,
|
||||
0x400005A0, C_IO, 0x40000640, C_IO, 0x40000760, C_IO, 0x400007A0, C_IO,
|
||||
0x40000800, C_IO, 0x40000920, C_IO, 0x400009A0, C_IO,
|
||||
0x40000C00, C_IO, 0x40000D20, C_IO, 0x40000DA0, C_IO,
|
||||
0x44000000, C_IO, 0x44000100, C_IO, 0x44000280, C_IO, 0x440002C0, C_IO,
|
||||
0x44000400, C_IO, 0x44000480, C_IO, 0x440004C0, C_IO, 0x44000500, C_IO,
|
||||
0x44000800, C_IO, 0x44000880, C_IO, 0x440008C0, C_IO, 0x44000900, C_IO,
|
||||
0x44000C80, C_IO, 0x44000CC0, C_IO,
|
||||
0x48000040, C_IO, 0x480000C0, C_IO, 0x48000160, C_IO,
|
||||
0x48000240, C_IO, 0x480002C0, C_IO, 0x48000360, C_IO,
|
||||
0x48000440, C_IO, 0x480004C0, C_IO, 0x48000560, C_IO,
|
||||
0x48000600, C_IO, 0x48000620, C_IO, 0x48000640, C_IO, 0x48000680, C_IO,
|
||||
0x480006C0, C_IO, 0x48000720, C_IO, 0x48000760, C_IO, 0x48000780, C_IO,
|
||||
0x48000A40, C_IO, 0x48000AE0, C_IO, 0x48000B40, C_IO,
|
||||
0x48000C40, C_IO, 0x48000CE0, C_IO, 0x48000D40, C_IO,
|
||||
0x48000E40, C_IO, 0x48000EE0, C_IO, 0x48000F40, C_IO,
|
||||
0x4C000000, C_IO, 0x4C000400, C_IO, 0x4C000600, C_IO,
|
||||
0x4C000800, C_IO, 0x4C000C00, C_IO,
|
||||
0x501F0080, C_FAC, 0x501F0280, C_FAC, 0x501F0480, C_FAC,
|
||||
0x53E00140, C_FBC, 0x53E01140, C_FBC, 0x53E02140, C_FBC, 0x53E03140, C_FBC,
|
||||
0x53E08140, C_FBC, 0x53E09140, C_FBC, 0x53E0A140, C_FBC, 0x53E0B140, C_FBC,
|
||||
0x53E00540, C_FBC, 0x53E01540, C_FBC, 0x53E02540, C_FBC, 0x53E03540, C_FBC,
|
||||
0x53E08540, C_FBC, 0x53E09540, C_FBC, 0x53E0A540, C_FBC, 0x53E0B540, C_FBC,
|
||||
0x53E00160, C_FBC, 0x53E00960, C_FBC, 0x53E01160, C_FBC, 0x53E01960, C_FBC,
|
||||
0x53E02160, C_FBC, 0x53E02960, C_FBC, 0x53E03160, C_FBC, 0x53E03960, C_FBC,
|
||||
0x53E0A160, C_FBC, 0x53E0A960, C_FBC, 0x53E0B160, C_FBC, 0x53E0B960, C_FBC,
|
||||
0x53E0E160, C_FBC, 0x53E0E960, C_FBC, 0x53E0F160, C_FBC, 0x53E0F960, C_FBC,
|
||||
0x53E00560, C_FBC, 0x53E00D60, C_FBC, 0x53E01560, C_FBC, 0x53E01D60, C_FBC,
|
||||
0x53E02560, C_FBC, 0x53E02D60, C_FBC, 0x53E03560, C_FBC, 0x53E03D60, C_FBC,
|
||||
0x53E0A560, C_FBC, 0x53E0AD60, C_FBC, 0x53E0B560, C_FBC, 0x53E0BD60, C_FBC,
|
||||
0x53E0E560, C_FBC, 0x53E0ED60, C_FBC, 0x53E0F560, C_FBC, 0x53E0FD60, C_FBC,
|
||||
0x54000000, C_FO, 0x54001000, C_FO, 0x54002000, C_FO, 0x54003000, C_FO,
|
||||
0x54008000, C_FO, 0x54009000, C_FO, 0x5400A000, C_FO, 0x5400B000, C_FO,
|
||||
0x54000020, C_FO, 0x54001020, C_FO, 0x54002020, C_FO, 0x54003020, C_FO,
|
||||
0x54008020, C_FO, 0x54009020, C_FO, 0x5400A020, C_FO, 0x5400B020, C_FO,
|
||||
0x54000040, C_FO, 0x54001040, C_FO, 0x54002040, C_FO, 0x54003040, C_FO,
|
||||
0x54008040, C_FO, 0x54009040, C_FO, 0x5400A040, C_FO, 0x5400B040, C_FO,
|
||||
0x54000060, C_FO, 0x54001060, C_FO, 0x54002060, C_FO, 0x54003060, C_FO,
|
||||
0x54008060, C_FO, 0x54009060, C_FO, 0x5400A060, C_FO, 0x5400B060, C_FO,
|
||||
0x54000400, C_FO, 0x54001400, C_FO, 0x54002400, C_FO, 0x54003400, C_FO,
|
||||
0x54008400, C_FO, 0x54009400, C_FO, 0x5400A400, C_FO, 0x5400B400, C_FO,
|
||||
0x54000420, C_FO, 0x54001420, C_FO, 0x54002420, C_FO, 0x54003420, C_FO,
|
||||
0x54008420, C_FO, 0x54009420, C_FO, 0x5400A420, C_FO, 0x5400B420, C_FO,
|
||||
0x54000440, C_FO, 0x54001440, C_FO, 0x54002440, C_FO, 0x54003440, C_FO,
|
||||
0x54008440, C_FO, 0x54009440, C_FO, 0x5400A440, C_FO, 0x5400B440, C_FO,
|
||||
0x54000460, C_FO, 0x54001460, C_FO, 0x54002460, C_FO, 0x54003460, C_FO,
|
||||
0x54008460, C_FO, 0x54009460, C_FO, 0x5400A460, C_FO, 0x5400B460, C_FO,
|
||||
0x57E003C0, C_FBC, 0x57E013C0, C_FBC, 0x57E023C0, C_FBC, 0x57E033C0, C_FBC,
|
||||
0x57E083C0, C_FBC, 0x57E093C0, C_FBC, 0x57E0A3C0, C_FBC, 0x57E0B3C0, C_FBC,
|
||||
0x57E00580, C_FBC, 0x57E01580, C_FBC, 0x57E02580, C_FBC, 0x57E03580, C_FBC,
|
||||
0x57E08580, C_FBC, 0x57E09580, C_FBC, 0x57E0A580, C_FBC, 0x57E0B580, C_FBC,
|
||||
0x57E005A0, C_FBC, 0x57E015A0, C_FBC, 0x57E025A0, C_FBC, 0x57E035A0, C_FBC,
|
||||
0x57E085A0, C_FBC, 0x57E095A0, C_FBC, 0x57E0A5A0, C_FBC, 0x57E0B5A0, C_FBC,
|
||||
0x57E005E0, C_FBC, 0x57E015E0, C_FBC, 0x57E025E0, C_FBC, 0x57E035E0, C_FBC,
|
||||
0x57E085E0, C_FBC, 0x57E095E0, C_FBC, 0x57E0A5E0, C_FBC, 0x57E0B5E0, C_FBC,
|
||||
0x57E00780, C_FBC, 0x57E01780, C_FBC, 0x57E007C0, C_FBC, 0x57E017C0, C_FBC,
|
||||
0x540014A0, C_FO, 0x540094A0, C_FO, 0x540014C0, C_FO, 0x540094C0, C_FO,
|
||||
0x540014E0, C_FO, 0x540094E0, C_FO,
|
||||
0x58000000, C_FO, 0x58000800, C_FO, 0x58001000, C_FO, 0x58001800, C_FO,
|
||||
0x58002000, C_FO, 0x58002800, C_FO, 0x58003000, C_FO, 0x58003800, C_FO,
|
||||
0x5800A000, C_FO, 0x5800A800, C_FO, 0x5800B000, C_FO, 0x5800B800, C_FO,
|
||||
0x5800E000, C_FO, 0x5800E800, C_FO, 0x5800F000, C_FO, 0x5800F800, C_FO,
|
||||
0x58000020, C_FO, 0x58000820, C_FO, 0x58001020, C_FO, 0x58001820, C_FO,
|
||||
0x58002020, C_FO, 0x58002820, C_FO, 0x58003020, C_FO, 0x58003820, C_FO,
|
||||
0x5800A020, C_FO, 0x5800A820, C_FO, 0x5800B020, C_FO, 0x5800B820, C_FO,
|
||||
0x5800E020, C_FO, 0x5800E820, C_FO, 0x5800F020, C_FO, 0x5800F820, C_FO,
|
||||
0x58000040, C_FO, 0x58000840, C_FO, 0x58001040, C_FO, 0x58001840, C_FO,
|
||||
0x58002040, C_FO, 0x58002840, C_FO, 0x58003040, C_FO, 0x58003840, C_FO,
|
||||
0x5800A040, C_FO, 0x5800A840, C_FO, 0x5800B040, C_FO, 0x5800B840, C_FO,
|
||||
0x5800E040, C_FO, 0x5800E840, C_FO, 0x5800F040, C_FO, 0x5800F840, C_FO,
|
||||
0x58000060, C_FO, 0x58000860, C_FO, 0x58001060, C_FO, 0x58001860, C_FO,
|
||||
0x58002060, C_FO, 0x58002860, C_FO, 0x58003060, C_FO, 0x58003860, C_FO,
|
||||
0x5800A060, C_FO, 0x5800A860, C_FO, 0x5800B060, C_FO, 0x5800B860, C_FO,
|
||||
0x5800E060, C_FO, 0x5800E860, C_FO, 0x5800F060, C_FO, 0x5800F860, C_FO,
|
||||
0x58000400, C_FO, 0x58000C00, C_FO, 0x58001400, C_FO, 0x58001C00, C_FO,
|
||||
0x58002400, C_FO, 0x58002C00, C_FO, 0x58003400, C_FO, 0x58003C00, C_FO,
|
||||
0x5800A400, C_FO, 0x5800AC00, C_FO, 0x5800B400, C_FO, 0x5800BC00, C_FO,
|
||||
0x5800E400, C_FO, 0x5800EC00, C_FO, 0x5800F400, C_FO, 0x5800FC00, C_FO,
|
||||
0x58000420, C_FO, 0x58000C20, C_FO, 0x58001420, C_FO, 0x58001C20, C_FO,
|
||||
0x58002420, C_FO, 0x58002C20, C_FO, 0x58003420, C_FO, 0x58003C20, C_FO,
|
||||
0x5800A420, C_FO, 0x5800AC20, C_FO, 0x5800B420, C_FO, 0x5800BC20, C_FO,
|
||||
0x5800E420, C_FO, 0x5800EC20, C_FO, 0x5800F420, C_FO, 0x5800FC20, C_FO,
|
||||
0x58000440, C_FO, 0x58000C40, C_FO, 0x58001440, C_FO, 0x58001C40, C_FO,
|
||||
0x58002440, C_FO, 0x58002C40, C_FO, 0x58003440, C_FO, 0x58003C40, C_FO,
|
||||
0x5800A440, C_FO, 0x5800AC40, C_FO, 0x5800B440, C_FO, 0x5800BC40, C_FO,
|
||||
0x5800E440, C_FO, 0x5800EC40, C_FO, 0x5800F440, C_FO, 0x5800FC40, C_FO,
|
||||
0x58000460, C_FO, 0x58000C60, C_FO, 0x58001460, C_FO, 0x58001C60, C_FO,
|
||||
0x58002460, C_FO, 0x58002C60, C_FO, 0x58003460, C_FO, 0x58003C60, C_FO,
|
||||
0x5800A460, C_FO, 0x5800AC60, C_FO, 0x5800B460, C_FO, 0x5800BC60, C_FO,
|
||||
0x5800E460, C_FO, 0x5800EC60, C_FO, 0x5800F460, C_FO, 0x5800FC60, C_FO,
|
||||
0x5BE00580, C_FBC, 0x5BE00D80, C_FBC, 0x5BE01580, C_FBC, 0x5BE01D80, C_FBC,
|
||||
0x5BE02580, C_FBC, 0x5BE02D80, C_FBC, 0x5BE03580, C_FBC, 0x5BE03D80, C_FBC,
|
||||
0x5BE0A580, C_FBC, 0x5BE0AD80, C_FBC, 0x5BE0B580, C_FBC, 0x5BE0BD80, C_FBC,
|
||||
0x5BE0E580, C_FBC, 0x5BE0ED80, C_FBC, 0x5BE0F580, C_FBC, 0x5BE0FD80, C_FBC,
|
||||
0x5BE005E0, C_FBC, 0x5BE00DE0, C_FBC, 0x5BE015E0, C_FBC, 0x5BE01DE0, C_FBC,
|
||||
0x5BE025E0, C_FBC, 0x5BE02DE0, C_FBC, 0x5BE035E0, C_FBC, 0x5BE03DE0, C_FBC,
|
||||
0x5BE0A5E0, C_FBC, 0x5BE0ADE0, C_FBC, 0x5BE0B5E0, C_FBC, 0x5BE0BDE0, C_FBC,
|
||||
0x5BE0E5E0, C_FBC, 0x5BE0EDE0, C_FBC, 0x5BE0F5E0, C_FBC, 0x5BE0FDE0, C_FBC,
|
||||
0x5BE00780, C_FBC, 0x5BE00F80, C_FBC, 0x5BE01780, C_FBC, 0x5BE01F80, C_FBC,
|
||||
0x5BE0E780, C_FBC, 0x5BE0EF80, C_FBC, 0x5BE0F780, C_FBC, 0x5BE0FF80, C_FBC,
|
||||
0x5BE007C0, C_FBC, 0x5BE00FC0, C_FBC, 0x5BE017C0, C_FBC, 0x5BE01FC0, C_FBC,
|
||||
0x5BE0E7C0, C_FBC, 0x5BE0EFC0, C_FBC, 0x5BE0F7C0, C_FBC, 0x5BE0FFC0, C_FBC,
|
||||
0x58001480, C_FO, 0x58009480, C_FO, 0x580014A0, C_FO, 0x580094A0, C_FO,
|
||||
0x580014C0, C_FO, 0x580094C0, C_FO, 0x580014E0, C_FO, 0x580094E0, C_FO,
|
||||
0x5FE00200, C_IBC, 0x5C000400, C_IO, 0x5C000420, C_IO, 0x5C000440, C_IO,
|
||||
0x5C000480, C_IO, 0x5C0004A0, C_IO,
|
||||
0x5C000540, C_IO, 0x5C000560, C_IO, 0x5C000580, C_IO,
|
||||
0x5C0005A0, C_IO, 0x5C0005C0, C_IO, 0x5C0005E0, C_IO,
|
||||
0x5FE00060, C_IBC, 0x5FE00260, C_IBC, 0x5FE00A60, C_IBC,
|
||||
0x60000000, C_NO, 0x60000400, C_NO, 0x60004000, C_NO, 0x60004400, C_NO,
|
||||
0x60008000, C_FE, 0x6000A000, C_FE, 0x6000C000, C_NO,
|
||||
0x6000E000, C_RV, 0x6000F000, C_RV,
|
||||
0x68000000, C_JP, 0x68004000, C_JP, 0x68008000, C_JP, 0x6800C000, C_JP,
|
||||
0x73E00000, C_IBC, 0x73E00020, C_IBC,
|
||||
0x73E00600, C_IBC, 0x70000620, C_IO, 0x73E00640, C_IBC, 0x73E00660, C_IBC,
|
||||
0x73E00680, C_IBC, 0x73E006A0, C_IBC, 0x73E006C0, C_IBC, 0x73E006E0, C_IBC,
|
||||
0x70000700, C_IO, 0x70000720, C_IO, 0x70000740, C_IO, 0x70000780, C_IO,
|
||||
0x70000780, C_IO, 0x700007A0, C_IO, 0x700007C0, C_IO, 0x700007E0, C_IO,
|
||||
0x701F0E00, C_IAC, 0x701F0F00, C_IAC,
|
||||
0x80000000, C_MR, 0x84000000, C_MR, 0x88000000, C_MR, 0x8C000000, C_MR,
|
||||
0x90000000, C_MR, 0x94000000, C_MR, 0x98000000, C_MR, 0x9C000000, C_MR,
|
||||
0xA0000000, C_MR, 0xA4000000, C_MR, 0xA8000000, C_MR, 0xAC000000, C_MR,
|
||||
0xB0000000, C_MR, 0xB4000000, C_MR, 0xB8000000, C_MR, 0xBC000000, C_MR,
|
||||
0xC0000000, C_BR, 0xC4000000, C_BR, 0xC8000000, C_BR, 0xCC000000, C_BR,
|
||||
0xD0000000, C_BR, 0xD4000000, C_BR, 0xD8000000, C_BR, 0xDC000000, C_BR,
|
||||
0xE0000000, C_BR, 0xE4000000, C_BR, 0xE8000000, C_BR, 0xEC000000, C_BR,
|
||||
0xF0000000, C_BR, 0xF4000000, C_BR, 0xF8000000, C_BR, 0xFC000000, C_BR,
|
||||
M32, 0
|
||||
};
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = values to decode
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = if >= 0, error code
|
||||
if < 0, number of extra bytes retired
|
||||
*/
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
uint32 c, sc, rdx;
|
||||
t_stat r;
|
||||
DEVICE *dptr;
|
||||
|
||||
if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */
|
||||
else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */
|
||||
dptr = find_dev_from_unit (uptr); /* find dev */
|
||||
if (dptr == NULL) return SCPE_IERR;
|
||||
if (sw & SWMASK ('D')) rdx = 10; /* get radix */
|
||||
else if (sw & SWMASK ('O')) rdx = 8;
|
||||
else if (sw & SWMASK ('H')) rdx = 16;
|
||||
else rdx = dptr->dradix;
|
||||
|
||||
if (sw & SWMASK ('A')) { /* ASCII? */
|
||||
sc = (uint32) (addr & 0x7) * 8; /* shift count */
|
||||
c = (uint32) (val[0] >> sc) & 0x7F;
|
||||
fprintf (of, (c < 0x20)? "<%02X>": "%c", c);
|
||||
return 0;
|
||||
}
|
||||
if (sw & SWMASK ('B')) { /* byte? */
|
||||
sc = (uint32) (addr & 0x7) * 8; /* shift count */
|
||||
c = (uint32) (val[0] >> sc) & M8;
|
||||
fprintf (of, "%02X", c);
|
||||
return 0;
|
||||
}
|
||||
if (sw & SWMASK ('W')) { /* word? */
|
||||
sc = (uint32) (addr & 0x6) * 8; /* shift count */
|
||||
c = (uint32) (val[0] >> sc) & M16;
|
||||
fprintf (of, "%04X", c);
|
||||
return -1;
|
||||
}
|
||||
if (sw & SWMASK ('L')) { /* long? */
|
||||
if (addr & 4) c = (uint32) (val[0] >> 32) & M32;
|
||||
else c = (uint32) val[0] & M32;
|
||||
fprintf (of, "%08X", c);
|
||||
return -3;
|
||||
}
|
||||
if (sw & SWMASK ('C')) { /* char format? */
|
||||
for (sc = 0; sc < 64; sc = sc + 8) { /* print string */
|
||||
c = (uint32) (val[0] >> sc) & 0x7F;
|
||||
fprintf (of, (c < 0x20)? "<%02X>": "%c", c);
|
||||
}
|
||||
return -7; /* return # chars */
|
||||
}
|
||||
if (sw & SWMASK ('M')) { /* inst format? */
|
||||
if (addr & 4) c = (uint32) (val[0] >> 32) & M32;
|
||||
else c = (uint32) val[0] & M32;
|
||||
r = fprint_sym_m (of, addr, c); /* decode inst */
|
||||
if (r <= 0) return r;
|
||||
}
|
||||
|
||||
fprint_val (of, val[0], rdx, 64, PV_RZRO);
|
||||
return -7;
|
||||
}
|
||||
|
||||
/* Symbolic decode for -m
|
||||
|
||||
Inputs:
|
||||
of = output stream
|
||||
addr = current PC
|
||||
inst = instruction to decode
|
||||
Outputs:
|
||||
return = if >= 0, error code
|
||||
if < 0, number of extra bytes retired (-3)
|
||||
*/
|
||||
|
||||
t_stat fprint_sym_m (FILE *of, t_addr addr, uint32 inst)
|
||||
{
|
||||
uint32 i, j, k, fl, ra, rb, rc, md, bd, jd, lit8, any;
|
||||
t_stat r;
|
||||
|
||||
if ((r = fprint_pal_hwre (of, inst)) < 0) return r; /* PAL instruction? */
|
||||
for (i = 0; opval[i] != M32; i = i + 2) { /* loop thru ops */
|
||||
fl = opval[i + 1]; /* flags */
|
||||
j = fl & CL_CLASS; /* get class */
|
||||
k = i >> 1;
|
||||
if (((opval[i] & masks[j]) == (inst & masks[j])) && /* match? */
|
||||
((j != CL_NO) || (fl & PAL_MASK (pal_type)))) {
|
||||
ra = I_GETRA (inst); /* all fields */
|
||||
rb = I_GETRB (inst);
|
||||
rc = I_GETRC (inst);
|
||||
lit8 = I_GETLIT8 (inst);
|
||||
md = I_GETMDSP (inst);
|
||||
bd = I_GETBDSP (inst);
|
||||
jd = inst & 0x3FFF;
|
||||
any = 0;
|
||||
fprintf (of, "%s", opcode[k]); /* opcode */
|
||||
if (fl & FL_RA) /* ra? */
|
||||
any = fprintf (of, " R%d", ra);
|
||||
if (fl & FL_BDP) { /* branch? */
|
||||
addr = (addr + (SEXT_BDSP (bd) << 2) + 4) & M64;
|
||||
any = fprintf (of, (any? ",": " "));
|
||||
fprint_val (of, addr, 16, 64, PV_LEFT);
|
||||
}
|
||||
else if (fl & FL_MDP) { /* mem ref? */
|
||||
if ((fl & FL_RBI) && (rb != 31))
|
||||
any = fprintf (of, (any? ",%X(R%d)": " %X(R%d)"), md, rb);
|
||||
else any = fprintf (of, (any? ",%X": " %X"), md);
|
||||
}
|
||||
else if (fl & FL_RB) { /* rb? */
|
||||
if (fl & FL_RBI)
|
||||
any = fprintf (of, (any? ",(R%d)": " (R%d)"), rb);
|
||||
else if ((fl & FL_LIT) && (inst & I_ILIT))
|
||||
any = fprintf (of, (any? ",#%X": " #%X"), lit8);
|
||||
else any = fprintf (of, (any? ",R%d": " R%d"), rb);
|
||||
}
|
||||
if ((fl & FL_JDP) && jd) /* jmp? */
|
||||
any = fprintf (of, (any? ",%X": " %X"), jd);
|
||||
else if (fl & FL_RC) /* rc? */
|
||||
any = fprintf (of, (any? ",R%d": " R%d"), rc);
|
||||
return -3;
|
||||
} /* end if */
|
||||
} /* end for */
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = > 0 error code
|
||||
<= 0 -number of extra words
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
t_value num;
|
||||
uint32 i, sc, rdx;
|
||||
t_stat r;
|
||||
DEVICE *dptr;
|
||||
|
||||
if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */
|
||||
else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */
|
||||
dptr = find_dev_from_unit (uptr); /* find dev */
|
||||
if (dptr == NULL) return SCPE_IERR;
|
||||
if (sw & SWMASK ('D')) rdx = 10; /* get radix */
|
||||
else if (sw & SWMASK ('O')) rdx = 8;
|
||||
else if (sw & SWMASK ('H')) rdx = 16;
|
||||
else rdx = dptr->dradix;
|
||||
|
||||
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
sc = (uint32) (addr & 0x7) * 8; /* shift count */
|
||||
val[0] = (val[0] & ~(((t_uint64) M8) << sc)) |
|
||||
(((t_uint64) cptr[0]) << sc);
|
||||
return 0;
|
||||
}
|
||||
if (sw & SWMASK ('B')) { /* byte? */
|
||||
num = get_uint (cptr, rdx, M8, &r); /* get byte */
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
sc = (uint32) (addr & 0x7) * 8; /* shift count */
|
||||
val[0] = (val[0] & ~(((t_uint64) M8) << sc)) |
|
||||
(num << sc);
|
||||
return 0;
|
||||
}
|
||||
if (sw & SWMASK ('W')) { /* word? */
|
||||
num = get_uint (cptr, rdx, M16, &r); /* get word */
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
sc = (uint32) (addr & 0x6) * 8; /* shift count */
|
||||
val[0] = (val[0] & ~(((t_uint64) M16) << sc)) |
|
||||
(num << sc);
|
||||
return -1;
|
||||
}
|
||||
if (sw & SWMASK ('L')) { /* longword? */
|
||||
num = get_uint (cptr, rdx, M32, &r); /* get longword */
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
sc = (uint32) (addr & 0x4) * 8; /* shift count */
|
||||
val[0] = (val[0] & ~(((t_uint64) M32) << sc)) |
|
||||
(num << sc);
|
||||
return -3;
|
||||
}
|
||||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (cptr[i] == 0) break;
|
||||
sc = i * 8;
|
||||
val[0] = (val[0] & ~(((t_uint64) M8) << sc)) |
|
||||
(((t_uint64) cptr[i]) << sc);
|
||||
}
|
||||
return -7;
|
||||
}
|
||||
|
||||
if ((addr & 3) == 0) { /* aligned only */
|
||||
r = parse_sym_m (cptr, addr, &num); /* try to parse inst */
|
||||
if (r <= 0) { /* ok? */
|
||||
sc = (uint32) (addr & 0x4) * 8; /* shift count */
|
||||
val[0] = (val[0] & ~(((t_uint64) M32) << sc)) |
|
||||
(num << sc);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
val[0] = get_uint (cptr, rdx, M64, &r); /* get number */
|
||||
if (r != SCPE_OK) return r;
|
||||
return -7;
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*val = pointer to output values
|
||||
Outputs:
|
||||
status = > 0 error code
|
||||
<= 0 -number of extra words
|
||||
*/
|
||||
|
||||
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *inst)
|
||||
{
|
||||
t_uint64 bra, df, db;
|
||||
uint32 i, k, lit8, fl;
|
||||
int32 reg;
|
||||
t_stat r;
|
||||
char *tptr, gbuf[CBUFSIZE];
|
||||
|
||||
if ((r = parse_pal_hwre (cptr, inst)) < 0) return r; /* PAL hardware? */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
|
||||
for (i = 0; opcode[i] != NULL; i++) { /* loop thru opcodes */
|
||||
if (strcmp (opcode[i], gbuf) == 0) { /* string match? */
|
||||
k = i << 1; /* index to opval */
|
||||
fl = opval[k + 1]; /* get flags */
|
||||
if (((fl & CL_CLASS) != CL_NO) || /* not PAL or */
|
||||
(fl & PAL_MASK (pal_type))) break; /* PAL type match? */
|
||||
}
|
||||
}
|
||||
if (opcode[i] == NULL) return SCPE_ARG;
|
||||
*inst = opval[k]; /* save base op */
|
||||
|
||||
if (fl & FL_RA) { /* need Ra? */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get reg */
|
||||
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
|
||||
*inst = *inst | (reg << I_V_RA);
|
||||
}
|
||||
if (fl & FL_BDP) { /* need branch disp? */
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
bra = get_uint (gbuf, 16, M64, &r);
|
||||
if ((r != SCPE_OK) || (bra & 3)) return SCPE_ARG;
|
||||
df = ((bra - (addr + 4)) >> 2) & I_M_BDSP;
|
||||
db = ((addr + 4 - bra) >> 2) & I_M_BDSP;
|
||||
if (bra == ((addr + 4 + (SEXT_BDSP (df) << 2)) & M64))
|
||||
*inst = *inst | (uint32) df;
|
||||
else if (bra == ((addr + 4 + (SEXT_BDSP (db) << 2)) & M64))
|
||||
*inst = *inst | (uint32) db;
|
||||
else return SCPE_ARG;
|
||||
}
|
||||
else if (fl & FL_MDP) { /* need mem disp? */
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
df = strtotv (gbuf, &tptr, 16);
|
||||
if ((gbuf == tptr) || (df > I_M_MDSP)) return SCPE_ARG;
|
||||
*inst = *inst | (uint32) df;
|
||||
if (*tptr == '(') {
|
||||
tptr = get_glyph (tptr + 1, gbuf, ')');
|
||||
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
|
||||
*inst = *inst | (reg << I_V_RB);
|
||||
}
|
||||
else *inst = *inst | (31 << I_V_RB);
|
||||
if (*tptr != 0) return SCPE_ARG;
|
||||
}
|
||||
else if (fl & FL_RBI) { /* indexed? */
|
||||
cptr = get_glyph (cptr, gbuf, ',');
|
||||
if (gbuf[0] != '(') return SCPE_ARG;
|
||||
tptr = get_glyph (gbuf + 1, gbuf, ')');
|
||||
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
|
||||
*inst = *inst | (reg << I_V_RB);
|
||||
if (*tptr != 0) return SCPE_ARG;
|
||||
}
|
||||
else if (fl & FL_RB) {
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get reg/lit */
|
||||
if ((gbuf[0] == '#') && (fl & FL_LIT)) { /* literal? */
|
||||
lit8 = (uint32) get_uint (gbuf + 1, 16, I_M_LIT8, &r);
|
||||
if (r != SCPE_OK) return r;
|
||||
*inst = *inst | I_ILIT | (lit8 << I_V_LIT8);
|
||||
}
|
||||
else { /* rb */
|
||||
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
|
||||
*inst = *inst | (reg << I_V_RB);
|
||||
}
|
||||
}
|
||||
if (fl & FL_JDP) { /* jmp? */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get disp */
|
||||
df = get_uint (gbuf, 16, 0x3FFF, &r);
|
||||
if (r != SCPE_OK) return r;
|
||||
*inst = *inst | df;
|
||||
}
|
||||
else if (fl & FL_RC) { /* rc? */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get reg */
|
||||
if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG;
|
||||
*inst = *inst | (reg << I_V_RC);
|
||||
}
|
||||
|
||||
if (*cptr != 0) return SCPE_ARG; /* any leftovers? */
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Parse a register */
|
||||
|
||||
int32 parse_reg (char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
int32 reg;
|
||||
|
||||
if ((*cptr == 'R') || (*cptr == 'r') ||
|
||||
(*cptr == 'F') || (*cptr == 'f')) cptr++;
|
||||
reg = (int32) get_uint (cptr, 10, 31, &r);
|
||||
if (r != SCPE_OK) return -1;
|
||||
return reg;
|
||||
}
|
||||
|
||||
43
Alpha/alpha_sys_defs.h
Normal file
43
Alpha/alpha_sys_defs.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* alpha_system_defs.h: Alpha system definitions file
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
Respectfully dedicated to the great people of the Alpha chip, systems, and
|
||||
software development projects; and to the memory of Peter Conklin, of the
|
||||
Alpha Program Office.
|
||||
|
||||
This is a STUB!
|
||||
*/
|
||||
|
||||
#ifndef _ALPHA_SYS_DEFS_H_
|
||||
#define _ALPHA_SYS_DEFS_H_ 0
|
||||
|
||||
#define PA_SIZE 36 /* PA size */
|
||||
#define PA_MASK 0x0000000FFFFFFFFF
|
||||
|
||||
#define ROMBASE 0x000000FFFC000000
|
||||
#define ROMSIZE 0x0000000004000000
|
||||
|
||||
#endif
|
||||
|
||||
208
Alpha/old_pal/alpha_pal_defs.h
Normal file
208
Alpha/old_pal/alpha_pal_defs.h
Normal file
@ -0,0 +1,208 @@
|
||||
/* alpha_pal_defs.h: Alpha architecture PAL definitions file
|
||||
|
||||
Copyright (c) 2003-2006, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
Respectfully dedicated to the great people of the Alpha chip, systems, and
|
||||
software development projects; and to the memory of Peter Conklin, of the
|
||||
Alpha Program Office.
|
||||
*/
|
||||
|
||||
#ifndef _ALPHA_PAL_DEFS_H_
|
||||
#define _ALPHA_PAL_DEFS_H_ 0
|
||||
|
||||
/* VA - NT software format */
|
||||
|
||||
#define NTVA_N_PDE (VA_N_OFF - 2) /* PDE width */
|
||||
#define NTVA_M_PDE ((1u << NTVA_N_PDE) - 1) /* PDE mask */
|
||||
#define NTVA_N_PTD (32 - VA_N_OFF - NTVA_N_PDE) /* PTD width */
|
||||
#define NTVA_M_PTD ((1u << NTVA_N_PTD) - 1) /* PTD mask */
|
||||
#define NTVA_M_VPN (M32 >> VA_N_OFF) /* 32b VPN mask */
|
||||
#define NTVPN_N_SEXT (VA_WIDTH - 32 + 1) /* VPN sext size */
|
||||
#define NTVPN_V_SEXT (VA_N_VPN - NTVPN_N_SEXT) /* VPN sext start */
|
||||
#define NTVPN_M_SEXT ((1u << NTVPN_N_SEXT) - 1) /* VPN sext mask */
|
||||
#define NTVPN_GETSEXT(x) (((x) >> NTVPN_V_SEXT) & NTVPN_M_SEXT)
|
||||
|
||||
/* PTE - NT software format */
|
||||
|
||||
#define NT_VPTB 0xFFFFFFFFC0000000 /* virt page tbl base */
|
||||
#define NTP_V_PFN 9 /* PFN */
|
||||
#define NTP_M_PFN 0x7FFFFF
|
||||
#define NTP_PFN (NTP_M_PFN << NTP_V_PFN)
|
||||
#define NTP_V_GH 5
|
||||
#define NTP_M_GH 0x3
|
||||
#define NTP_V_GBL 4 /* global = ASM */
|
||||
#define NTP_V_DIRTY 2 /* dirty = !FOW */
|
||||
#define NTP_V_OWNER 1 /* owner */
|
||||
#define NTP_V_V 0 /* valid */
|
||||
#define NTP_GBL (1u << NTP_V_GBL)
|
||||
#define NTP_DIRTY (1u << NTP_V_DIRTY)
|
||||
#define NTP_OWNER (1u << NTP_V_OWNER)
|
||||
#define NTP_V (1u << NTP_V_V)
|
||||
#define NT_VPNPTD(x) (((x) >> (NTVA_N_PDE - 2)) & (NTVA_M_PTD << 2))
|
||||
#define NT_VPNPDE(x) (((x) << 2) & (NTVA_M_PDE << 2))
|
||||
|
||||
/* VMS PALcode */
|
||||
|
||||
#define PSV_V_SPA 56 /* VMS PS: stack align */
|
||||
#define PSV_M_SPA 0x3F
|
||||
#define PSV_V_IPL 8 /* interrupt priority */
|
||||
#define PSV_M_IPL 0x1F
|
||||
#define PSV_V_VMM 7 /* virt machine monitor */
|
||||
#define PSV_V_CM 3 /* current mode */
|
||||
#define PSV_M_CM 0x3
|
||||
#define PSV_V_IP 2 /* intr in progress */
|
||||
#define PSV_V_SW 0 /* software */
|
||||
#define PSV_M_SW 0x3
|
||||
#define PSV_VMM (1u << PSV_V_VMM)
|
||||
#define PSV_IP (1u << PSV_V_IP)
|
||||
#define PSV_MASK (PSV_VMM | PSV_IP | PSV_M_SW)
|
||||
#define PSV_MBZ 0xC0FFFFFFFFFFE0E4 /* must be zero */
|
||||
|
||||
#define PCBV_FLAGS 56 /* PCB flags word */
|
||||
|
||||
#define SISR_MASK 0xFFFE /* SISR bits */
|
||||
|
||||
#define IPL_SMAX 0x0F /* highest swre level */
|
||||
|
||||
#define SCB_FDIS 0x010 /* SCB offsets */
|
||||
#define SCB_ACV 0x080
|
||||
#define SCB_TNV 0x090
|
||||
#define SCB_FOR 0x0A0
|
||||
#define SCB_FOW 0x0B0
|
||||
#define SCB_FOE 0x0C0
|
||||
#define SCB_ARITH 0x200
|
||||
#define SCB_KAST 0x240
|
||||
#define SCB_EAST 0x250
|
||||
#define SCB_SAST 0x260
|
||||
#define SCB_UAST 0x270
|
||||
#define SCB_ALIGN 0x280
|
||||
#define SCB_BPT 0x400
|
||||
#define SCB_BUG 0x410
|
||||
#define SCB_RSVI 0x420
|
||||
#define SCB_RSVO 0x430
|
||||
#define SCB_GENTRAP 0x440
|
||||
#define SCB_CHMK 0x480
|
||||
#define SCB_CHME 0x490
|
||||
#define SCB_CHMS 0x4A0
|
||||
#define SCB_CHMU 0x4B0
|
||||
#define SCB_SISR0 0x500
|
||||
#define SCB_CLOCK 0x600
|
||||
#define SCB_IPIR 0x610
|
||||
#define SCB_SCRD 0x620
|
||||
#define SCB_PCRD 0x630
|
||||
#define SCB_POWER 0x640
|
||||
#define SCB_PERFM 0x650
|
||||
#define SCB_SMCHK 0x660
|
||||
#define SCB_PMCHK 0x670
|
||||
#define SCB_PASVR 0x6F0
|
||||
#define SCB_IO 0x800
|
||||
|
||||
#define VMS_L_STKF (8 * 8) /* stack frame length */
|
||||
#define VMS_MME_E 0x0000000000000001 /* mem mgt error flags */
|
||||
#define VMS_MME_R 0x0000000000000000
|
||||
#define VMS_MME_W 0x8000000000000000
|
||||
|
||||
/* VAX compatible data length definitions (for ReadUna, WriteUna) */
|
||||
|
||||
#define L_BYTE 1
|
||||
#define L_WORD 2
|
||||
#define L_LONG 4
|
||||
#define L_QUAD 8
|
||||
|
||||
/* Unix PALcode */
|
||||
|
||||
#define PSU_V_CM 3 /* Unix PS: curr mode */
|
||||
#define PSU_M_CM 0x1
|
||||
#define PSU_CM (PSU_M_CM << PSU_V_CM)
|
||||
#define PSU_V_IPL 0 /* IPL */
|
||||
#define PSU_M_IPL 0x7
|
||||
#define PSU_IPL (PSU_M_IPL << PSU_V_IPL)
|
||||
|
||||
#define PCBU_FLAGS 40 /* PCB flags word */
|
||||
|
||||
#define UNIX_L_STKF (6 * 8) /* kernel stack frame */
|
||||
#define UNIX_IF_BPT 0 /* entIF a0 values */
|
||||
#define UNIX_IF_BUG 1
|
||||
#define UNIX_IF_GEN 2
|
||||
#define UNIX_IF_FDIS 3
|
||||
#define UNIX_IF_RSVI 4
|
||||
#define UNIX_INT_IPIR 0 /* entInt a0 values */
|
||||
#define UNIX_INT_CLK 1
|
||||
#define UNIX_INT_MCRD 2
|
||||
#define UNIX_INT_IO 3
|
||||
#define UNIX_INT_PERF 4
|
||||
#define UNIX_MMCSR_TNV 0 /* entMM a1 values */
|
||||
#define UNIX_MMCSR_ACV 1
|
||||
#define UNIX_MMCSR_FOR 2
|
||||
#define UNIX_MMCSR_FOW 3
|
||||
#define UNIX_MMCSR_FOE 4
|
||||
#define UNIX_MME_E M64 /* entMM a2 values */
|
||||
#define UNIX_MME_R 0
|
||||
#define UNIX_MME_W 1
|
||||
|
||||
enum vms_pal_opcodes {
|
||||
OP_HALT, OP_DRAINA, OP_CFLUSH, OP_LDQP,
|
||||
OP_STQP, OP_SWPCTX, MF_ASN, MT_ASTEN,
|
||||
MT_ASTSR, OP_CSERVE, OP_SWPPAL, MF_FEN,
|
||||
MT_FEN, MT_IPIR, MF_IPL, MT_IPL,
|
||||
MF_MCES, MT_MCES, MF_PCBB, MF_PRBR,
|
||||
MT_PRBR, MF_PTBR, MF_SCBB, MT_SCBB,
|
||||
MT_SIRR, MF_SISR, MF_TBCHK, MT_TBIA,
|
||||
MT_TBIAP, MT_TBIS, MF_ESP, MT_ESP,
|
||||
MF_SSP, MT_SSP, MF_USP, MT_USP,
|
||||
MT_TBISD, MT_TBISI, MF_ASTEN, MF_ASTSR,
|
||||
MF_VTBR = 0x29, MT_VTBR,MT_PERFMON, MT_DATFX = 0x2E,
|
||||
MF_VIRBND = 0x30, MT_VIRBND, MF_SYSPTBR, MT_SYSPTBR,
|
||||
OP_WTINT = 0x3E, MF_WHAMI = 0x3F,
|
||||
OP_BPT = 0x80, OP_BUGCHK, OP_CHME, OP_CHMK,
|
||||
OP_CHMS, OP_CHMU, OP_IMB, OP_INSQHIL,
|
||||
OP_INSQTIL, OP_INSQHIQ, OP_INSQTIQ, OP_INSQUEL,
|
||||
OP_INSQUEQ, OP_INSQUELD,OP_INSQUEQD,OP_PROBER,
|
||||
OP_PROBEW, OP_RD_PS, OP_REI, OP_REMQHIL,
|
||||
OP_REMQTIL, OP_REMQHIQ, OP_REMQTIQ, OP_REMQUEL,
|
||||
OP_REMQUEQ, OP_REMQUELD,OP_REMQUEQD,OP_SWASTEN,
|
||||
OP_WR_PS_SW,OP_RSCC, OP_RD_UNQ, OP_WR_UNQ,
|
||||
OP_AMOVRR, OP_AMOVRM, OP_INSQHILR,OP_INSQTILR,
|
||||
OP_INSQHIQR,OP_INSQTIQR,OP_REMQHILR,OP_REMQTILR,
|
||||
OP_REMQHIQR,OP_REMQTIQR,OP_GENTRAP,
|
||||
OP_CLRFEN = 0xAE
|
||||
};
|
||||
|
||||
enum unix_pal_opcodes {
|
||||
OP_halt, OP_draina, OP_cflush,
|
||||
OP_cserve = 0x9, OP_swppal,
|
||||
OP_rdmces = 0x10, OP_wrmces,
|
||||
OP_wrvirbnd = 0x13, OP_wrsysptbr = 0x14,
|
||||
OP_wrfen = 0x2B, OP_wrvptptr = 0x2D, OP_wrasn,
|
||||
OP_swpctx = 0x30, OP_wrval, OP_rdval, OP_tbi,
|
||||
OP_wrent, OP_swpipl, OP_rdps, OP_wrkgp,
|
||||
OP_wrusp, OP_wrperfmon, OP_rdusp,
|
||||
OP_whami = 0x3C, OP_retsys, OP_wtint, OP_rti,
|
||||
OP_bpt = 0x80, OP_bugchk, OP_syscall = 0x83,
|
||||
OP_imb = 0x86,
|
||||
OP_urti = 0x92, OP_rdunique = 0x9E, OP_wrunique,
|
||||
OP_gentrap = 0xAA, OP_clrfen = 0xAE
|
||||
};
|
||||
|
||||
#endif
|
||||
702
Alpha/old_pal/alpha_pal_unix.c
Normal file
702
Alpha/old_pal/alpha_pal_unix.c
Normal file
@ -0,0 +1,702 @@
|
||||
/* alpha_pal_unix.c - Alpha Unix PAL code simulator
|
||||
|
||||
Copyright (c) 2003-2005, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This module contains the PALcode implementation for Alpha Unix, except for
|
||||
the console, which is always done in hardware mode.
|
||||
|
||||
Alpha Unix/Linux requires the following privileged state:
|
||||
|
||||
ps<3:0> processor status
|
||||
cm<0> current mode - in base
|
||||
ipl<2:0> interrupt level - in base
|
||||
ksp<63:0> kernel stack pointer
|
||||
kgp<63:0> kernel global pointer
|
||||
usp<63:0> user stack pointer
|
||||
pcbb<63:0> process control block base
|
||||
ptptr<63:0> page table base
|
||||
vptptr<63:0> virtual page table base
|
||||
virbnd<63:0> virtual address boundary
|
||||
sysptbr<63:0> system page table base register
|
||||
sysval<63:0> processor base (sysvalue)
|
||||
unique<63:0> thread-unique value
|
||||
entArith<63:0> entry vector, arithmetic trap
|
||||
entIF<63:0> entry vector, instruction
|
||||
entInt<63:0> entry vector, interrupt
|
||||
entSys<63:0> entry vector, system call
|
||||
entMM<63:0> entry vector, memory management fault
|
||||
entUna<63:0> entry vector, unaligned
|
||||
|
||||
Unix maps kernel/user to the hardware's kernel/executive. It maps the
|
||||
8 IPL's to the hardware IPL's as follows:
|
||||
|
||||
0 0
|
||||
1 1
|
||||
2 2
|
||||
3 IPL_HMIN
|
||||
4 IPL_HMIN+1
|
||||
5 IPL_HMIN+2
|
||||
6 IPL_HMIN+3
|
||||
7 IPL_1F
|
||||
*/
|
||||
|
||||
#include "alpha_defs.h"
|
||||
|
||||
#define GET_PSU (((unix_cm & PSU_M_CM) << PSU_V_CM) | \
|
||||
((unix_ipl & PSU_M_IPL) << PSU_V_IPL))
|
||||
|
||||
// kludge for debugging...
|
||||
#define io_get_vec(x) 0
|
||||
|
||||
#define ksp unix_stkp[MODE_K]
|
||||
#define usp unix_stkp[MODE_E]
|
||||
#define entInt unix_entVec[0]
|
||||
#define entArith unix_entVec[1]
|
||||
#define entMM unix_entVec[2]
|
||||
#define entIF unix_entVec[3]
|
||||
#define entUna unix_entVec[4]
|
||||
#define entSys unix_entVec[5]
|
||||
#define v0 R[0]
|
||||
#define a0 R[16]
|
||||
#define a1 R[17]
|
||||
#define a2 R[18]
|
||||
#define a3 R[19]
|
||||
#define at R[28]
|
||||
#define gp R[29]
|
||||
|
||||
t_uint64 unix_ptptr = 0; /* page table base */
|
||||
t_uint64 unix_vptptr = 0; /* virt page table base */
|
||||
t_uint64 unix_virbnd = M64; /* virtual boundary */
|
||||
t_uint64 unix_sysptbr = 0; /* system page table base */
|
||||
t_uint64 unix_hwpcb = 0; /* hardware PCB */
|
||||
t_uint64 unix_unique = 0; /* thread unique */
|
||||
t_uint64 unix_sysval = 0; /* processor unique */
|
||||
t_uint64 unix_mces = 0; /* machine check err summ */
|
||||
t_uint64 unix_stkp[2] = { 0 };
|
||||
t_uint64 unix_entVec[6] = { 0 };
|
||||
t_uint64 unix_kgp = 0;
|
||||
uint32 unix_ipl = 0;
|
||||
uint32 unix_cm = 0;
|
||||
|
||||
static const uint32 map_ipl[8] = {
|
||||
0, 1, 2, IPL_HMIN, IPL_HMIN + 1, IPL_HMIN + 2, IPL_HMIN + 3, IPL_1F
|
||||
};
|
||||
|
||||
extern t_uint64 R[32];
|
||||
extern t_uint64 PC, trap_mask;
|
||||
extern t_uint64 p1;
|
||||
extern uint32 vax_flag, lock_flag;
|
||||
extern uint32 fpen;
|
||||
extern uint32 ir, pcc_h, pcc_l, pcc_enb;
|
||||
extern uint32 cm_racc, cm_wacc;
|
||||
extern uint32 mmu_ispage, mmu_dspage;
|
||||
extern jmp_buf save_env;
|
||||
extern uint32 int_req[IPL_HLVL];
|
||||
|
||||
t_stat unix_syscall (void);
|
||||
t_stat unix_retsys (void);
|
||||
t_stat unix_rti (void);
|
||||
void unix_urti (void);
|
||||
void unix_swpctx (void);
|
||||
t_stat unix_intexc (t_uint64 vec, t_uint64 arg);
|
||||
t_stat unix_mm_intexc (t_uint64 par1, t_uint64 par2);
|
||||
t_stat pal_proc_reset_unix (DEVICE *dptr);
|
||||
uint32 pal_find_pte_unix (uint32 vpn, t_uint64 *l3pte);
|
||||
|
||||
extern t_stat (*pal_eval_intr) (uint32 ipl);
|
||||
extern t_stat (*pal_proc_excp) (uint32 type);
|
||||
extern t_stat (*pal_proc_trap) (uint32 type);
|
||||
extern t_stat (*pal_proc_intr) (uint32 type);
|
||||
extern t_stat (*pal_proc_inst) (uint32 fnc);
|
||||
extern uint32 (*pal_find_pte) (uint32 vpn, t_uint64 *pte);
|
||||
extern uint32 Test (t_uint64 va, uint32 acc, t_uint64 *pa);
|
||||
|
||||
/* UNIXPAL data structures
|
||||
|
||||
unixpal_dev device descriptor
|
||||
unixpal_unit unit
|
||||
unixpal_reg register list
|
||||
*/
|
||||
|
||||
UNIT unixpal_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
REG unixpal_reg[] = {
|
||||
{ HRDATA (KSP, ksp, 64) },
|
||||
{ HRDATA (USP, usp, 64) },
|
||||
{ HRDATA (ENTARITH, entArith, 64) },
|
||||
{ HRDATA (ENTIF, entIF, 64) },
|
||||
{ HRDATA (ENTINT, entInt, 64) },
|
||||
{ HRDATA (ENTMM, entMM, 64) },
|
||||
{ HRDATA (ENTSYS, entSys, 64) },
|
||||
{ HRDATA (ENTUNA, entUna, 64) },
|
||||
{ HRDATA (KGP, unix_kgp, 64) },
|
||||
{ HRDATA (PTPTR, unix_ptptr, 64) },
|
||||
{ HRDATA (VPTPTR, unix_vptptr, 64) },
|
||||
{ HRDATA (VIRBND, unix_virbnd, 64) },
|
||||
{ HRDATA (SYSPTBR, unix_sysptbr, 64) },
|
||||
{ HRDATA (UNIQUE, unix_unique, 64) },
|
||||
{ HRDATA (SYSVAL, unix_sysval, 64) },
|
||||
{ HRDATA (HWPCB, unix_hwpcb, 64) },
|
||||
{ HRDATA (MCES, unix_mces, 64) },
|
||||
{ HRDATA (IPL, unix_ipl, 3) },
|
||||
{ HRDATA (CM, unix_cm, 0) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
DEVICE unixpal_dev = {
|
||||
"UNIXPAL", &unixpal_unit, unixpal_reg, NULL,
|
||||
1, 16, 1, 1, 16, 8,
|
||||
NULL, NULL, &pal_proc_reset_unix,
|
||||
NULL, NULL, NULL,
|
||||
NULL, DEV_DIS
|
||||
};
|
||||
|
||||
/* Unix interrupt evaluator - returns IPL of highest priority interrupt */
|
||||
|
||||
uint32 pal_eval_intr_unix (uint32 lvl)
|
||||
{
|
||||
uint32 i;
|
||||
uint32 mipl = map_ipl[lvl & PSU_M_IPL];
|
||||
|
||||
for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */
|
||||
if (i <= mipl) return 0; /* at ipl? no int */
|
||||
if (int_req[i - IPL_HMIN]) return i; /* req != 0? int */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unix interrupt dispatch - reached from top of execute loop */
|
||||
|
||||
t_stat pal_proc_intr_unix (uint32 lvl)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
if (lvl > IPL_HMAX) return SCPE_IERR; /* above max? */
|
||||
else if (lvl >= IPL_HMIN) a1 = io_get_vec (lvl); /* hwre? get vector */
|
||||
else return SCPE_IERR; /* bug */
|
||||
r = unix_intexc (entInt, UNIX_INT_IO); /* do interrupt */
|
||||
if (a1 == SCB_CLOCK) a0 = UNIX_INT_CLK;
|
||||
if (a1 == SCB_IPIR) a0 = UNIX_INT_IPIR;
|
||||
unix_ipl = lvl;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Unix trap dispatch - reached synchronously from bottom of execute loop */
|
||||
|
||||
t_stat pal_proc_trap_unix (uint32 tsum)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
r = unix_intexc (entArith, tsum); /* arithmetic trap */
|
||||
a1 = trap_mask; /* set parameter */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Unix exception dispatch - reached from the ABORT handler */
|
||||
|
||||
t_stat pal_proc_excp_unix (uint32 abval)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
switch (abval) {
|
||||
|
||||
case EXC_RSVI: /* reserved instruction */
|
||||
return unix_intexc (entIF, UNIX_IF_RSVI); /* trap */
|
||||
|
||||
case EXC_RSVO: /* reserved operand */
|
||||
return unix_intexc (entIF, UNIX_IF_RSVI); /* trap */
|
||||
|
||||
case EXC_ALIGN: /* unaligned */
|
||||
PC = (PC - 4) & M64; /* back up PC */
|
||||
r = unix_intexc (entUna, PC); /* fault */
|
||||
a1 = I_GETOP (ir); /* get opcode */
|
||||
a2 = I_GETRA (ir); /* get ra */
|
||||
return r;
|
||||
|
||||
case EXC_FPDIS: /* fp disabled */
|
||||
PC = (PC - 4) & M64; /* backup PC */
|
||||
return unix_intexc (entIF, UNIX_IF_FDIS); /* fault */
|
||||
|
||||
case EXC_FOX+EXC_E: /* FOE */
|
||||
tlb_is (p1, TLB_CI);
|
||||
return unix_mm_intexc (UNIX_MMCSR_FOE, UNIX_MME_E);
|
||||
|
||||
case EXC_FOX+EXC_R: /* FOR */
|
||||
PC = (PC - 4) & M64; /* back up PC */
|
||||
return unix_mm_intexc (UNIX_MMCSR_FOR, UNIX_MME_R);
|
||||
|
||||
case EXC_FOX+EXC_W: /* FOW */
|
||||
PC = (PC - 4) & M64; /* back up PC */
|
||||
return unix_mm_intexc (UNIX_MMCSR_FOW, UNIX_MME_W);
|
||||
|
||||
case EXC_BVA+EXC_E:
|
||||
case EXC_ACV+EXC_E: /* instr ACV */
|
||||
return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_E);
|
||||
|
||||
case EXC_BVA+EXC_R:
|
||||
case EXC_ACV+EXC_R: /* data read ACV */
|
||||
PC = (PC - 4) & M64; /* back up PC */
|
||||
return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_R);
|
||||
|
||||
case EXC_BVA+EXC_W:
|
||||
case EXC_ACV+EXC_W: /* data write ACV */
|
||||
PC = (PC - 4) & M64; /* back up PC */
|
||||
return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_W);
|
||||
|
||||
case EXC_TNV+EXC_E: /* instr TNV */
|
||||
tlb_is (p1, TLB_CI);
|
||||
return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_E);
|
||||
|
||||
case EXC_TNV+EXC_R: /* data read TNV */
|
||||
tlb_is (p1, TLB_CD);
|
||||
PC = (PC - 4) & M64; /* back up PC */
|
||||
return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_R);
|
||||
|
||||
case EXC_TNV+EXC_W: /* data write TNV */
|
||||
tlb_is (p1, TLB_CD);
|
||||
PC = (PC - 4) & M64; /* back up PC */
|
||||
return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_W);
|
||||
|
||||
case EXC_TBM + EXC_E: /* TLB miss */
|
||||
case EXC_TBM + EXC_R:
|
||||
case EXC_TBM + EXC_W:
|
||||
return SCPE_IERR; /* should not occur */
|
||||
|
||||
default:
|
||||
return STOP_INVABO;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* PALcode instruction dispatcher - function code verified in CPU */
|
||||
|
||||
t_stat pal_proc_inst_unix (uint32 fnc)
|
||||
{
|
||||
uint32 arg32 = (uint32) a0;
|
||||
|
||||
if ((fnc < 0x40) && (unix_cm != MODE_K)) ABORT (EXC_RSVI);
|
||||
switch (fnc) {
|
||||
|
||||
case OP_halt:
|
||||
return STOP_HALT;
|
||||
|
||||
case OP_cflush:
|
||||
case OP_draina:
|
||||
break;
|
||||
|
||||
case OP_cserve:
|
||||
//tbd
|
||||
break;
|
||||
|
||||
case OP_swppal:
|
||||
v0 = 0;
|
||||
break;
|
||||
|
||||
case OP_rdmces:
|
||||
v0 = unix_mces;
|
||||
break;
|
||||
|
||||
case OP_wrmces:
|
||||
unix_mces = (unix_mces | (arg32 & MCES_DIS)) & ~(arg32 & MCES_W1C);
|
||||
break;
|
||||
|
||||
case OP_wrvirbnd:
|
||||
unix_virbnd = a0;
|
||||
break;
|
||||
|
||||
case OP_wrsysptbr:
|
||||
unix_sysptbr = a0;
|
||||
break;
|
||||
|
||||
case OP_wrfen:
|
||||
fpen = arg32 & 1;
|
||||
arg32 = ReadPL (unix_hwpcb + PCBU_FLAGS);
|
||||
arg32 = (arg32 & ~1) | fpen;
|
||||
WritePL (unix_hwpcb + PCBU_FLAGS, arg32);
|
||||
break;
|
||||
|
||||
case OP_wrvptptr:
|
||||
unix_vptptr = a0;
|
||||
break;
|
||||
|
||||
case OP_wrasn:
|
||||
itlb_set_asn (arg32 & M16);
|
||||
dtlb_set_asn (arg32 & M16);
|
||||
WritePL (unix_hwpcb + 28, arg32 & M16);
|
||||
break;
|
||||
|
||||
case OP_swpctx:
|
||||
unix_swpctx ();
|
||||
break;
|
||||
|
||||
case OP_wrval:
|
||||
unix_sysval = a0;
|
||||
break;
|
||||
|
||||
case OP_rdval:
|
||||
v0 = unix_sysval;
|
||||
break;
|
||||
|
||||
case OP_tbi:
|
||||
switch (a0 + 2) {
|
||||
case 0: /* -2 = tbia */
|
||||
tlb_ia (TLB_CI | TLB_CD | TLB_CA);
|
||||
break;
|
||||
case 1: /* -1 = tbiap */
|
||||
tlb_ia (TLB_CI | TLB_CD);
|
||||
break;
|
||||
case 3: /* +1 = tbis */
|
||||
tlb_is (a1, TLB_CI | TLB_CD);
|
||||
break;
|
||||
case 4: /* +2 = tbisd */
|
||||
tlb_is (a1, TLB_CD);
|
||||
break;
|
||||
case 5: /* +3 = tbisi */
|
||||
tlb_is (a1, TLB_CI);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_wrent:
|
||||
if (a0 <= 5) unix_entVec[arg32] = a0;
|
||||
break;
|
||||
|
||||
case OP_swpipl:
|
||||
v0 = unix_ipl;
|
||||
unix_ipl = arg32 & PSU_M_IPL;
|
||||
break;
|
||||
|
||||
case OP_rdps:
|
||||
v0 = GET_PSU;
|
||||
break;
|
||||
|
||||
case OP_wrkgp:
|
||||
unix_kgp = a0;
|
||||
break;
|
||||
|
||||
case OP_wrusp:
|
||||
usp = a0;
|
||||
break;
|
||||
|
||||
case OP_wrperfmon:
|
||||
// tbd
|
||||
break;
|
||||
|
||||
case OP_rdusp:
|
||||
v0 = usp;
|
||||
break;
|
||||
|
||||
case OP_whami:
|
||||
v0 = 0;
|
||||
break;
|
||||
|
||||
case OP_retsys:
|
||||
unix_retsys ();
|
||||
break;
|
||||
|
||||
case OP_wtint:
|
||||
v0 = 0;
|
||||
break;
|
||||
|
||||
case OP_rti:
|
||||
unix_rti ();
|
||||
break;
|
||||
|
||||
/* Non-privileged */
|
||||
|
||||
case OP_bpt:
|
||||
return unix_intexc (entIF, UNIX_IF_BPT);
|
||||
|
||||
case OP_bugchk:
|
||||
return unix_intexc (entIF, UNIX_IF_BUG);
|
||||
|
||||
case OP_syscall:
|
||||
if (unix_cm == MODE_K) {
|
||||
//tbd
|
||||
}
|
||||
return unix_syscall ();
|
||||
|
||||
case OP_imb:
|
||||
break;
|
||||
|
||||
case OP_urti:
|
||||
if (unix_cm == MODE_K) {
|
||||
//tbd
|
||||
}
|
||||
unix_urti ();
|
||||
break;
|
||||
|
||||
case OP_rdunique:
|
||||
v0 = unix_unique;
|
||||
break;
|
||||
|
||||
case OP_wrunique:
|
||||
unix_unique = a0;
|
||||
break;
|
||||
|
||||
case OP_gentrap:
|
||||
return unix_intexc (entIF, UNIX_IF_GEN);
|
||||
|
||||
case OP_clrfen:
|
||||
fpen = 0;
|
||||
arg32 = ReadPL (unix_hwpcb + PCBU_FLAGS);
|
||||
arg32 = arg32 & ~1;
|
||||
WritePL (unix_hwpcb + PCBU_FLAGS, arg32);
|
||||
break;
|
||||
|
||||
default:
|
||||
ABORT (EXC_RSVI);
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Swap privileged context */
|
||||
|
||||
void unix_swpctx (void)
|
||||
{
|
||||
t_uint64 val;
|
||||
uint32 tmp1;
|
||||
|
||||
WritePQ (unix_hwpcb + 0, SP); /* save stack ptrs */
|
||||
WritePQ (unix_hwpcb + 8, usp);
|
||||
tmp1 = (pcc_h + pcc_l) & M32; /* elapsed time */
|
||||
WritePL (unix_hwpcb + 24, tmp1); /* save PCC */
|
||||
WritePQ (unix_hwpcb + 32, unix_unique); /* save unique */
|
||||
v0 = unix_hwpcb; /* return curr PCBB */
|
||||
unix_hwpcb = a0; /* new PCBB */
|
||||
SP = ksp = ReadPQ (unix_hwpcb + 0); /* read stack ptrs */
|
||||
usp = ReadPQ (unix_hwpcb + 8);
|
||||
val = ReadPQ (unix_hwpcb + 16) << VA_N_OFF; /* read new PTBR */
|
||||
if (val != unix_ptptr) tlb_ia (TLB_CI | TLB_CD); /* ptbr change? zap TLB */
|
||||
unix_ptptr = val;
|
||||
tmp1 = ReadPL (unix_hwpcb + 24); /* restore PCC */
|
||||
pcc_h = (tmp1 - pcc_l) & M32;
|
||||
tmp1 = ReadPL (unix_hwpcb + 28) & M16; /* read ASN */
|
||||
itlb_set_asn (tmp1);
|
||||
dtlb_set_asn (tmp1);
|
||||
unix_unique = ReadPQ (unix_hwpcb + 32); /* read unique */
|
||||
fpen = ReadPL (unix_hwpcb + PCBU_FLAGS) & 1; /* read FEN */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unix interrupt or exception - always to kernel mode
|
||||
|
||||
Inputs:
|
||||
vec = entry vector
|
||||
arg = argument for a0
|
||||
Outputs:
|
||||
reason = possible processor halt
|
||||
*/
|
||||
|
||||
t_stat unix_intexc (t_uint64 vec, t_uint64 arg)
|
||||
{
|
||||
t_uint64 sav_ps = GET_PSU; /* old PS */
|
||||
|
||||
if ((unix_cm & PSU_M_CM) != MODE_K) { /* not kernel? */
|
||||
usp = SP; /* save SP */
|
||||
SP = ksp; /* load new SP */
|
||||
unix_cm = mmu_set_cm (MODE_K); /* PS = 0 */
|
||||
unix_ipl = 0;
|
||||
}
|
||||
SP = (SP - UNIX_L_STKF) & M64; /* decr stack */
|
||||
if (Test (SP, cm_wacc, NULL)) return STOP_KSNV; /* validate writes */
|
||||
if (Test (SP + UNIX_L_STKF - 8, cm_wacc, NULL) < 0) return STOP_KSNV;
|
||||
WriteQ (SP, sav_ps); /* save PS, PC, gp */
|
||||
WriteQ (SP + 8, PC);
|
||||
WriteQ (SP + 16, gp);
|
||||
WriteQ (SP + 24, a0); /* save a0-a2 */
|
||||
WriteQ (SP + 32, a1);
|
||||
WriteQ (SP + 40, a2);
|
||||
PC = vec; /* new PC */
|
||||
gp = unix_kgp; /* kernel GP */
|
||||
a0 = arg; /* argument */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Memory management fault */
|
||||
|
||||
t_stat unix_mm_intexc (t_uint64 par1, t_uint64 par2)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
r = unix_intexc (entMM, p1); /* do exception */
|
||||
a1 = par1; /* set arguments */
|
||||
a2 = par2;
|
||||
tlb_is (p1, TLB_CI | TLB_CD); /* zap TLB entry */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* System call - always user to kernel, abbreviated stack frame, no arguments */
|
||||
|
||||
t_stat unix_syscall (void)
|
||||
{
|
||||
t_uint64 sav_ps = GET_PSU; /* save PS */
|
||||
|
||||
usp = SP; /* save user SP */
|
||||
SP = ksp; /* load kernel SP */
|
||||
unix_cm = mmu_set_cm (MODE_K); /* PS = 0 */
|
||||
unix_ipl = 0;
|
||||
SP = (SP - UNIX_L_STKF) & M64; /* decr stack */
|
||||
if (Test (SP, cm_wacc, NULL)) return STOP_KSNV; /* validate writes */
|
||||
if (Test (SP + UNIX_L_STKF - 8, cm_wacc, NULL)) return STOP_KSNV;
|
||||
WriteQ (SP, sav_ps); /* save PS, PC, gp */
|
||||
WriteQ (SP + 8, PC);
|
||||
WriteQ (SP + 16, gp);
|
||||
PC = entSys; /* new PC */
|
||||
gp = unix_kgp; /* kernel GP */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Return from trap or interrupt - always from kernel */
|
||||
|
||||
t_stat unix_rti (void)
|
||||
{
|
||||
t_uint64 tpc;
|
||||
uint32 tps, newm;
|
||||
|
||||
if (Test (SP, cm_racc, NULL)) return STOP_KSNV; /* validate reads */
|
||||
if (Test (SP + UNIX_L_STKF - 8, cm_racc, NULL)) return STOP_KSNV;
|
||||
tps = (uint32) ReadQ (SP); /* read PS, PC */
|
||||
tpc = ReadQ (SP + 8);
|
||||
gp = ReadQ (SP + 16); /* restore gp, a0-a2 */
|
||||
a0 = ReadQ (SP + 24);
|
||||
a1 = ReadQ (SP + 32);
|
||||
a2 = ReadQ (SP + 40);
|
||||
SP = (SP + UNIX_L_STKF); /* incr stack */
|
||||
newm = (tps >> PSU_V_CM) & PSU_M_CM;
|
||||
unix_cm = mmu_set_cm (newm); /* new current mode */
|
||||
if (newm) { /* to user? */
|
||||
ksp = SP; /* save kernel stack */
|
||||
SP = usp; /* load user stack */
|
||||
unix_ipl = 0; /* ipl = 0 */
|
||||
}
|
||||
else unix_ipl = (tps >> PSU_V_IPL) & PSU_V_IPL; /* restore ipl */
|
||||
PC = tpc; /* restore PC */
|
||||
vax_flag = 0; /* clear VAX, lock flags */
|
||||
lock_flag = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Return from system call - always from kernel to user */
|
||||
|
||||
t_stat unix_retsys (void)
|
||||
{
|
||||
t_uint64 tpc;
|
||||
|
||||
if (Test (SP + 8, cm_racc, NULL)) return STOP_KSNV; /* validate reads */
|
||||
if (Test (SP + 16, cm_racc, NULL)) return STOP_KSNV;
|
||||
tpc = ReadQ (SP + 8); /* read PC */
|
||||
gp = ReadQ (SP + 16); /* restore GP */
|
||||
ksp = (SP + UNIX_L_STKF); /* update kernel stack */
|
||||
SP = usp; /* restore user stack */
|
||||
unix_cm = mmu_set_cm (MODE_E); /* PS = 8 */
|
||||
unix_ipl = 0;
|
||||
PC = tpc; /* restore PC */
|
||||
vax_flag = 0; /* clear VAX, lock flags */
|
||||
lock_flag = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Return from user mode trap - always from user to user */
|
||||
|
||||
void unix_urti (void)
|
||||
{
|
||||
t_uint64 tsp, tpc;
|
||||
uint32 tps;
|
||||
|
||||
if (SP & 0x3F) ABORT (EXC_RSVO); /* not aligned? */
|
||||
tps = ReadL (SP + 16); /* read PS */
|
||||
if (!(tps & PSU_CM) || (tps & PSU_IPL)) ABORT (EXC_RSVO);
|
||||
at = ReadQ (SP + 0); /* restore at */
|
||||
tsp = ReadQ (SP + 8); /* read SP, PC */
|
||||
tpc = ReadQ (SP + 24);
|
||||
gp = ReadQ (SP + 32); /* restore gp, a0-a2 */
|
||||
a0 = ReadQ (SP + 40);
|
||||
a1 = ReadQ (SP + 48);
|
||||
a2 = ReadQ (SP + 56);
|
||||
SP = tsp; /* restore SP */
|
||||
PC = tpc; /* restore PC */
|
||||
vax_flag = 0; /* clear VAX, lock flags */
|
||||
lock_flag = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unix 3-level PTE lookup
|
||||
|
||||
Inputs:
|
||||
vpn = virtual page number (30b, sext)
|
||||
*pte = pointer to pte to be returned
|
||||
Output:
|
||||
status = 0 for successful fill
|
||||
EXC_ACV for ACV on intermediate level
|
||||
EXC_TNV for TNV on intermediate level
|
||||
*/
|
||||
|
||||
uint32 pal_find_pte_unix (uint32 vpn, t_uint64 *l3pte)
|
||||
{
|
||||
t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte;
|
||||
uint32 vpte_vpn;
|
||||
TLBENT *vpte_p;
|
||||
|
||||
vptea = unix_vptptr | (((t_uint64) (vpn & VA_M_VPN)) << 3); /* try virtual lookup */
|
||||
vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */
|
||||
vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */
|
||||
if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V)))
|
||||
l3ptea = vpte_p->pfn | VA_GETOFF (vptea);
|
||||
else {
|
||||
l1ptea = unix_ptptr + VPN_GETLVL1 (vpn);
|
||||
l1pte = ReadPQ (l1ptea);
|
||||
if ((l1pte & PTE_V) == 0)
|
||||
return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV);
|
||||
l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF);
|
||||
l2ptea = l2ptea + VPN_GETLVL2 (vpn);
|
||||
l2pte = ReadPQ (l2ptea);
|
||||
if ((l2pte & PTE_V) == 0)
|
||||
return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV);
|
||||
l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF);
|
||||
l3ptea = l3ptea + VPN_GETLVL3 (vpn);
|
||||
}
|
||||
*l3pte = ReadPQ (l3ptea);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unix PALcode reset */
|
||||
|
||||
t_stat pal_proc_reset_unix (DEVICE *dptr)
|
||||
{
|
||||
mmu_ispage = mmu_dspage = SPEN_43;
|
||||
unix_ipl = PSU_M_IPL;
|
||||
unix_cm = mmu_set_cm (MODE_K);
|
||||
pcc_enb = 1;
|
||||
pal_eval_intr = &pal_eval_intr_unix;
|
||||
pal_proc_intr = &pal_proc_intr_unix;
|
||||
pal_proc_trap = &pal_proc_trap_unix;
|
||||
pal_proc_excp = &pal_proc_excp_unix;
|
||||
pal_proc_inst = &pal_proc_inst_unix;
|
||||
pal_find_pte = &pal_find_pte_unix;
|
||||
return SCPE_OK;
|
||||
}
|
||||
1780
Alpha/old_pal/alpha_pal_vms.c
Normal file
1780
Alpha/old_pal/alpha_pal_vms.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user