]> git.proxmox.com Git - qemu.git/blobdiff - target-alpha/cpu.h
target-alpha: Swap shadow registers moving to/from PALmode.
[qemu.git] / target-alpha / cpu.h
index f8bbc70d7b4638a4e397877525c2d2c2dd13a73c..c1546f81864f1450f116a3e243b6f0f00c9c227b 100644 (file)
@@ -14,8 +14,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #if !defined (__CPU_ALPHA_H__)
@@ -25,6 +24,8 @@
 
 #define TARGET_LONG_BITS 64
 
+#define CPUState struct CPUAlphaState
+
 #include "cpu-defs.h"
 
 #include <setjmp.h>
 #define ICACHE_LINE_SIZE 32
 #define DCACHE_LINE_SIZE 32
 
-#define TARGET_PAGE_BITS 12
+#define TARGET_PAGE_BITS 13
 
-#define VA_BITS 43
+/* ??? EV4 has 34 phys addr bits, EV5 has 40, EV6 has 44.  */
+#define TARGET_PHYS_ADDR_SPACE_BITS    44
+#define TARGET_VIRT_ADDR_SPACE_BITS    (30 + TARGET_PAGE_BITS)
 
 /* Alpha major type */
 enum {
@@ -138,182 +141,154 @@ enum {
     FP_ROUND_DYNAMIC = 0x3,
 };
 
-/* Internal processor registers */
-/* XXX: TOFIX: most of those registers are implementation dependant */
-enum {
-    /* Ebox IPRs */
-    IPR_CC           = 0xC0,
-    IPR_CC_CTL       = 0xC1,
-    IPR_VA           = 0xC2,
-    IPR_VA_CTL       = 0xC4,
-    IPR_VA_FORM      = 0xC3,
-    /* Ibox IPRs */
-    IPR_ITB_TAG      = 0x00,
-    IPR_ITB_PTE      = 0x01,
-    IPT_ITB_IAP      = 0x02,
-    IPT_ITB_IA       = 0x03,
-    IPT_ITB_IS       = 0x04,
-    IPR_PMPC         = 0x05,
-    IPR_EXC_ADDR     = 0x06,
-    IPR_IVA_FORM     = 0x07,
-    IPR_CM           = 0x09,
-    IPR_IER          = 0x0A,
-    IPR_SIRR         = 0x0C,
-    IPR_ISUM         = 0x0D,
-    IPR_HW_INT_CLR   = 0x0E,
-    IPR_EXC_SUM      = 0x0F,
-    IPR_PAL_BASE     = 0x10,
-    IPR_I_CTL        = 0x11,
-    IPR_I_STAT       = 0x16,
-    IPR_IC_FLUSH     = 0x13,
-    IPR_IC_FLUSH_ASM = 0x12,
-    IPR_CLR_MAP      = 0x15,
-    IPR_SLEEP        = 0x17,
-    IPR_PCTX         = 0x40,
-    IPR_PCTR_CTL     = 0x14,
-    /* Mbox IPRs */
-    IPR_DTB_TAG0     = 0x20,
-    IPR_DTB_TAG1     = 0xA0,
-    IPR_DTB_PTE0     = 0x21,
-    IPR_DTB_PTE1     = 0xA1,
-    IPR_DTB_ALTMODE  = 0xA6,
-    IPR_DTB_IAP      = 0xA2,
-    IPR_DTB_IA       = 0xA3,
-    IPR_DTB_IS0      = 0x24,
-    IPR_DTB_IS1      = 0xA4,
-    IPR_DTB_ASN0     = 0x25,
-    IPR_DTB_ASN1     = 0xA5,
-    IPR_MM_STAT      = 0x27,
-    IPR_M_CTL        = 0x28,
-    IPR_DC_CTL       = 0x29,
-    IPR_DC_STAT      = 0x2A,
-    /* Cbox IPRs */
-    IPR_C_DATA       = 0x2B,
-    IPR_C_SHIFT      = 0x2C,
-
-    IPR_ASN,
-    IPR_ASTEN,
-    IPR_ASTSR,
-    IPR_DATFX,
-    IPR_ESP,
-    IPR_FEN,
-    IPR_IPIR,
-    IPR_IPL,
-    IPR_KSP,
-    IPR_MCES,
-    IPR_PERFMON,
-    IPR_PCBB,
-    IPR_PRBR,
-    IPR_PTBR,
-    IPR_SCBB,
-    IPR_SISR,
-    IPR_SSP,
-    IPR_SYSPTBR,
-    IPR_TBCHK,
-    IPR_TBIA,
-    IPR_TBIAP,
-    IPR_TBIS,
-    IPR_TBISD,
-    IPR_TBISI,
-    IPR_USP,
-    IPR_VIRBND,
-    IPR_VPTB,
-    IPR_WHAMI,
-    IPR_ALT_MODE,
-    IPR_LAST,
-};
+/* FPCR bits */
+#define FPCR_SUM               (1ULL << 63)
+#define FPCR_INED              (1ULL << 62)
+#define FPCR_UNFD              (1ULL << 61)
+#define FPCR_UNDZ              (1ULL << 60)
+#define FPCR_DYN_SHIFT         58
+#define FPCR_DYN_CHOPPED       (0ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_MINUS         (1ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_NORMAL                (2ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_PLUS          (3ULL << FPCR_DYN_SHIFT)
+#define FPCR_DYN_MASK          (3ULL << FPCR_DYN_SHIFT)
+#define FPCR_IOV               (1ULL << 57)
+#define FPCR_INE               (1ULL << 56)
+#define FPCR_UNF               (1ULL << 55)
+#define FPCR_OVF               (1ULL << 54)
+#define FPCR_DZE               (1ULL << 53)
+#define FPCR_INV               (1ULL << 52)
+#define FPCR_OVFD              (1ULL << 51)
+#define FPCR_DZED              (1ULL << 50)
+#define FPCR_INVD              (1ULL << 49)
+#define FPCR_DNZ               (1ULL << 48)
+#define FPCR_DNOD              (1ULL << 47)
+#define FPCR_STATUS_MASK       (FPCR_IOV | FPCR_INE | FPCR_UNF \
+                                | FPCR_OVF | FPCR_DZE | FPCR_INV)
+
+/* The silly software trap enables implemented by the kernel emulation.
+   These are more or less architecturally required, since the real hardware
+   has read-as-zero bits in the FPCR when the features aren't implemented.
+   For the purposes of QEMU, we pretend the FPCR can hold everything.  */
+#define SWCR_TRAP_ENABLE_INV   (1ULL << 1)
+#define SWCR_TRAP_ENABLE_DZE   (1ULL << 2)
+#define SWCR_TRAP_ENABLE_OVF   (1ULL << 3)
+#define SWCR_TRAP_ENABLE_UNF   (1ULL << 4)
+#define SWCR_TRAP_ENABLE_INE   (1ULL << 5)
+#define SWCR_TRAP_ENABLE_DNO   (1ULL << 6)
+#define SWCR_TRAP_ENABLE_MASK  ((1ULL << 7) - (1ULL << 1))
+
+#define SWCR_MAP_DMZ           (1ULL << 12)
+#define SWCR_MAP_UMZ           (1ULL << 13)
+#define SWCR_MAP_MASK          (SWCR_MAP_DMZ | SWCR_MAP_UMZ)
+
+#define SWCR_STATUS_INV                (1ULL << 17)
+#define SWCR_STATUS_DZE                (1ULL << 18)
+#define SWCR_STATUS_OVF                (1ULL << 19)
+#define SWCR_STATUS_UNF                (1ULL << 20)
+#define SWCR_STATUS_INE                (1ULL << 21)
+#define SWCR_STATUS_DNO                (1ULL << 22)
+#define SWCR_STATUS_MASK       ((1ULL << 23) - (1ULL << 17))
+
+#define SWCR_MASK  (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK)
 
-typedef struct CPUAlphaState CPUAlphaState;
+/* MMU modes definitions */
 
-typedef struct pal_handler_t pal_handler_t;
-struct pal_handler_t {
-    /* Reset */
-    void (*reset)(CPUAlphaState *env);
-    /* Uncorrectable hardware error */
-    void (*machine_check)(CPUAlphaState *env);
-    /* Arithmetic exception */
-    void (*arithmetic)(CPUAlphaState *env);
-    /* Interrupt / correctable hardware error */
-    void (*interrupt)(CPUAlphaState *env);
-    /* Data fault */
-    void (*dfault)(CPUAlphaState *env);
-    /* DTB miss pal */
-    void (*dtb_miss_pal)(CPUAlphaState *env);
-    /* DTB miss native */
-    void (*dtb_miss_native)(CPUAlphaState *env);
-    /* Unaligned access */
-    void (*unalign)(CPUAlphaState *env);
-    /* ITB miss */
-    void (*itb_miss)(CPUAlphaState *env);
-    /* Instruction stream access violation */
-    void (*itb_acv)(CPUAlphaState *env);
-    /* Reserved or privileged opcode */
-    void (*opcdec)(CPUAlphaState *env);
-    /* Floating point exception */
-    void (*fen)(CPUAlphaState *env);
-    /* Call pal instruction */
-    void (*call_pal)(CPUAlphaState *env, uint32_t palcode);
-};
+/* Alpha has 5 MMU modes: PALcode, kernel, executive, supervisor, and user.
+   The Unix PALcode only exposes the kernel and user modes; presumably
+   executive and supervisor are used by VMS.
+
+   PALcode itself uses physical mode for code and kernel mode for data;
+   there are PALmode instructions that can access data via physical mode
+   or via an os-installed "alternate mode", which is one of the 4 above.
+
+   QEMU does not currently properly distinguish between code/data when
+   looking up addresses.  To avoid having to address this issue, our
+   emulated PALcode will cheat and use the KSEG mapping for its code+data
+   rather than physical addresses.
+
+   Moreover, we're only emulating Unix PALcode, and not attempting VMS.
+
+   All of which allows us to drop all but kernel and user modes.
+   Elide the unused MMU modes to save space.  */
+
+#define NB_MMU_MODES 2
 
-#define NB_MMU_MODES 4
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_KERNEL_IDX   0
+#define MMU_USER_IDX     1
+
+typedef struct CPUAlphaState CPUAlphaState;
 
 struct CPUAlphaState {
     uint64_t ir[31];
-    float64  fir[31];
-    float_status fp_status;
-    uint64_t fpcr;
+    float64 fir[31];
     uint64_t pc;
-    uint64_t lock;
-    uint32_t pcc[2];
-    uint64_t ipr[IPR_LAST];
-    uint64_t ps;
     uint64_t unique;
-    int saved_mode; /* Used for HW_LD / HW_ST */
+    uint64_t lock_addr;
+    uint64_t lock_st_addr;
+    uint64_t lock_value;
+    float_status fp_status;
+    /* The following fields make up the FPCR, but in FP_STATUS format.  */
+    uint8_t fpcr_exc_status;
+    uint8_t fpcr_exc_mask;
+    uint8_t fpcr_dyn_round;
+    uint8_t fpcr_flush_to_zero;
+    uint8_t fpcr_dnz;
+    uint8_t fpcr_dnod;
+    uint8_t fpcr_undz;
+
+    /* The Internal Processor Registers.  Some of these we assume always
+       exist for use in user-mode.  */
+    uint8_t ps;
+    uint8_t intr_flag;
+    uint8_t pal_mode;
+    uint8_t fen;
+
+    uint32_t pcc_ofs;
+
+    /* These pass data from the exception logic in the translator and
+       helpers to the OS entry point.  This is used for both system
+       emulation and user-mode.  */
+    uint64_t trap_arg0;
+    uint64_t trap_arg1;
+    uint64_t trap_arg2;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* The internal data required by our emulation of the Unix PALcode.  */
+    uint64_t exc_addr;
+    uint64_t palbr;
+    uint64_t ptbr;
+    uint64_t vptptr;
+    uint64_t sysval;
+    uint64_t usp;
+    uint64_t shadow[8];
+    uint64_t scratch[24];
+#endif
 
 #if TARGET_LONG_BITS > HOST_LONG_BITS
     /* temporary fixed-point registers
      * used to emulate 64 bits target on 32 bits hosts
      */
-    target_ulong t0, t1, t2;
+    target_ulong t0, t1;
 #endif
-    /* */
-    double ft0, ft1, ft2;
 
     /* Those resources are used only in Qemu core */
     CPU_COMMON
 
-    jmp_buf jmp_env;
-    int user_mode_only; /* user mode only simulation */
-    uint32_t hflags;
-    int halted;
-
-    int exception_index;
     int error_code;
-    int interrupt_request;
 
     uint32_t features;
     uint32_t amask;
     int implver;
-    pal_handler_t *pal_handler;
 };
 
-#define CPUState CPUAlphaState
 #define cpu_init cpu_alpha_init
 #define cpu_exec cpu_alpha_exec
 #define cpu_gen_code cpu_alpha_gen_code
 #define cpu_signal_handler cpu_alpha_signal_handler
 
-/* MMU modes definitions */
-#define MMU_MODE0_SUFFIX _kernel
-#define MMU_MODE1_SUFFIX _executive
-#define MMU_MODE2_SUFFIX _supervisor
-#define MMU_MODE3_SUFFIX _user
-#define MMU_USER_IDX 3
-static inline int cpu_mmu_index (CPUState *env)
-{
-    return (env->ps >> 3) & 3;
-}
-
 #include "cpu-all.h"
 
 enum {
@@ -324,41 +299,72 @@ enum {
 };
 
 enum {
-    EXCP_RESET            = 0x0000,
-    EXCP_MCHK             = 0x0020,
-    EXCP_ARITH            = 0x0060,
-    EXCP_HW_INTERRUPT     = 0x00E0,
-    EXCP_DFAULT           = 0x01E0,
-    EXCP_DTB_MISS_PAL     = 0x09E0,
-    EXCP_ITB_MISS         = 0x03E0,
-    EXCP_ITB_ACV          = 0x07E0,
-    EXCP_DTB_MISS_NATIVE  = 0x08E0,
-    EXCP_UNALIGN          = 0x11E0,
-    EXCP_OPCDEC           = 0x13E0,
-    EXCP_FEN              = 0x17E0,
-    EXCP_CALL_PAL         = 0x2000,
-    EXCP_CALL_PALP        = 0x3000,
-    EXCP_CALL_PALE        = 0x4000,
-    /* Pseudo exception for console */
-    EXCP_CONSOLE_DISPATCH = 0x4001,
-    EXCP_CONSOLE_FIXUP    = 0x4002,
+    EXCP_RESET,
+    EXCP_MCHK,
+    EXCP_SMP_INTERRUPT,
+    EXCP_CLK_INTERRUPT,
+    EXCP_DEV_INTERRUPT,
+    EXCP_MMFAULT,
+    EXCP_UNALIGN,
+    EXCP_OPCDEC,
+    EXCP_ARITH,
+    EXCP_FEN,
+    EXCP_CALL_PAL,
+    /* For Usermode emulation.  */
+    EXCP_STL_C,
+    EXCP_STQ_C,
+};
+
+/* Hardware interrupt (entInt) constants.  */
+enum {
+    INT_K_IP,
+    INT_K_CLK,
+    INT_K_MCHK,
+    INT_K_DEV,
+    INT_K_PERF,
 };
 
-/* Arithmetic exception */
+/* Memory management (entMM) constants.  */
 enum {
-    EXCP_ARITH_OVERFLOW,
+    MM_K_TNV,
+    MM_K_ACV,
+    MM_K_FOR,
+    MM_K_FOE,
+    MM_K_FOW
 };
 
+/* Arithmetic exception (entArith) constants.  */
 enum {
-    PALCODE_CALL = 0x00000000,
-    PALCODE_LD   = 0x01000000,
-    PALCODE_ST   = 0x02000000,
-    PALCODE_MFPR = 0x03000000,
-    PALCODE_MTPR = 0x04000000,
-    PALCODE_REI  = 0x05000000,
-    PALCODE_INIT = 0xF0000000,
+    EXC_M_SWC = 1,      /* Software completion */
+    EXC_M_INV = 2,      /* Invalid operation */
+    EXC_M_DZE = 4,      /* Division by zero */
+    EXC_M_FOV = 8,      /* Overflow */
+    EXC_M_UNF = 16,     /* Underflow */
+    EXC_M_INE = 32,     /* Inexact result */
+    EXC_M_IOV = 64      /* Integer Overflow */
 };
 
+/* Processor status constants.  */
+enum {
+    /* Low 3 bits are interrupt mask level.  */
+    PS_INT_MASK = 7,
+
+    /* Bits 4 and 5 are the mmu mode.  The VMS PALcode uses all 4 modes;
+       The Unix PALcode only uses bit 4.  */
+    PS_USER_MODE = 8
+};
+
+static inline int cpu_mmu_index(CPUState *env)
+{
+    if (env->pal_mode) {
+        return MMU_KERNEL_IDX;
+    } else if (env->ps & PS_USER_MODE) {
+        return MMU_USER_IDX;
+    } else {
+        return MMU_KERNEL_IDX;
+    }
+}
+
 enum {
     IR_V0   = 0,
     IR_T0   = 1,
@@ -376,7 +382,7 @@ enum {
     IR_S4   = 13,
     IR_S5   = 14,
     IR_S6   = 15,
-#define IR_FP IR_S6
+    IR_FP   = IR_S6,
     IR_A0   = 16,
     IR_A1   = 17,
     IR_A2   = 18,
@@ -389,7 +395,7 @@ enum {
     IR_T11  = 25,
     IR_RA   = 26,
     IR_T12  = 27,
-#define IR_PV IR_T12
+    IR_PV   = IR_T12,
     IR_AT   = 28,
     IR_GP   = 29,
     IR_SP   = 30,
@@ -403,10 +409,37 @@ int cpu_alpha_exec(CPUAlphaState *s);
    is returned if the signal was handled by the virtual CPU.  */
 int cpu_alpha_signal_handler(int host_signum, void *pinfo,
                              void *puc);
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
-void cpu_loop_exit (void);
-void pal_init (CPUState *env);
-void call_pal (CPUState *env, int palcode);
+int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw,
+                                int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
+void do_interrupt (CPUState *env);
+
+uint64_t cpu_alpha_load_fpcr (CPUState *env);
+void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
+extern void swap_shadow_regs(CPUState *env);
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = env->ps;
+}
+
+#if defined(CONFIG_USER_ONLY)
+static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
+{
+    if (newsp) {
+        env->ir[IR_SP] = newsp;
+    }
+    env->ir[IR_V0] = 0;
+    env->ir[IR_A3] = 0;
+}
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+    env->unique = newtls;
+}
+#endif
 
 #endif /* !defined (__CPU_ALPHA_H__) */