[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 19/19] Add full emulation for 21264.
From: |
Tristan Gingold |
Subject: |
[Qemu-devel] [PATCH 19/19] Add full emulation for 21264. |
Date: |
Mon, 30 Mar 2009 16:36:34 +0200 |
This is still work in progress but complete enough to run the firmware.
Remove old and incomplete code for pal virtualization.
Signed-off-by: Tristan Gingold <address@hidden>
---
cpu-exec.c | 1 +
hw/alpha_palcode.c | 37 ++-
target-alpha/cpu.h | 286 +++++++++++------
target-alpha/helper.c | 798 +++++++++++++++++++++++++++++-----------------
target-alpha/helper.h | 6 +-
target-alpha/op_helper.c | 199 ++++++++-----
target-alpha/translate.c | 153 +++++----
7 files changed, 944 insertions(+), 536 deletions(-)
diff --git a/cpu-exec.c b/cpu-exec.c
index cf7c1fb..674d521 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -486,6 +486,7 @@ int cpu_exec(CPUState *env1)
}
#elif defined(TARGET_ALPHA)
if (interrupt_request & CPU_INTERRUPT_HARD) {
+ env->exception_index = EXCP_GEN_INTERRUPT;
do_interrupt(env);
next_tb = 0;
}
diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c
index 189033c..c778319 100644
--- a/hw/alpha_palcode.c
+++ b/hw/alpha_palcode.c
@@ -22,10 +22,39 @@
#include <stdlib.h>
#include <stdio.h>
-#include "qemu.h"
#include "cpu.h"
#include "exec-all.h"
+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);
+};
+
/* Shared handlers */
static void pal_reset (CPUState *env);
/* Console handlers */
@@ -88,7 +117,7 @@ static void do_swappal (CPUState *env, uint64_t palid)
case 0 ... 2:
pal_handler = &pal_handlers[palid];
env->pal_handler = pal_handler;
- env->ipr[IPR_PAL_BASE] = -1ULL;
+ env->pal_base = -1ULL;
(*pal_handler->reset)(env);
break;
case 3 ... 255:
@@ -98,8 +127,8 @@ static void do_swappal (CPUState *env, uint64_t palid)
default:
/* We were given the entry point address */
env->pal_handler = NULL;
- env->ipr[IPR_PAL_BASE] = palid;
- env->pc = env->ipr[IPR_PAL_BASE];
+ env->pal_base = palid;
+ env->pc = env->pal_base;
cpu_loop_exit();
}
}
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 7cd6395..712de88 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -140,6 +140,23 @@ enum {
FP_ROUND_DYNAMIC = 0x3,
};
+/* How palcode is interpreted. */
+enum pal_emul {
+ /* No pal emulation (user linux). */
+ PAL_NONE,
+
+ /* As a real-cpu palcode. */
+ PAL_21264
+#if 0
+ PAL_21064,
+ PAL_21164,
+ /* Palcode virtualization (TODO). */
+ PAL_CONSOLE,
+ PAL_OPENVMS,
+ PAL_UNIX
+#endif
+};
+
/* Internal processor registers */
/* XXX: TOFIX: most of those registers are implementation dependant */
enum {
@@ -170,7 +187,7 @@ enum {
IPR_IER_CM = 0x0B, /* 21264: = CM | IER */
IPR_SIRR = 0x0C, /* 21264 */
#define IPR_SIRR_SHIFT 14
-#define IPR_SIRR_MASK 0x7fff
+#define IPR_SIRR_MASK (0x7fffULL << IPR_SIRR_SHIFT)
IPR_ISUM = 0x0D, /* 21264 */
IPR_HW_INT_CLR = 0x0E, /* 21264 */
IPR_EXC_SUM = 0x0F,
@@ -178,7 +195,7 @@ enum {
IPR_I_CTL = 0x11,
#define IPR_I_CTL_CHIP_ID_SHIFT 24 /* 21264 */
#define IPR_I_CTL_BIST_FAIL (1 << 23) /* 21264 */
-#define IPR_I_CTL_IC_EN_SHIFT 2 /* 21264 */
+#define IPR_I_CTL_IC_EN_SHIFT 1 /* 21264 */
#define IPR_I_CTL_SDE1_SHIFT 7 /* 21264 */
#define IPR_I_CTL_HWE_SHIFT 12 /* 21264 */
#define IPR_I_CTL_VA_48_SHIFT 15 /* 21264 */
@@ -212,8 +229,8 @@ enum {
#define IPR_DTB_ALTMODE_MASK 3
IPR_DTB_IAP = 0xA2,
IPR_DTB_IA = 0xA3, /* 21264 */
- IPR_DTB_IS0 = 0x24,
- IPR_DTB_IS1 = 0xA4,
+ IPR_DTB_IS0 = 0x24, /* 21264 */
+ IPR_DTB_IS1 = 0xA4, /* 21264 */
IPR_DTB_ASN0 = 0x25, /* 21264 */
IPR_DTB_ASN1 = 0xA5, /* 21264 */
#define IPR_DTB_ASN_SHIFT 56
@@ -225,74 +242,44 @@ enum {
IPR_DC_STAT = 0x2A, /* 21264 */
/* 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,
+ IPR_C_SHIFT = 0x2C
};
typedef struct CPUAlphaState CPUAlphaState;
-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);
+struct alpha_pte {
+ uint32_t pa;
+ uint16_t fl;
+ uint8_t asn;
+};
+
+#define MAX_NBR_TLB_21264 128
+struct alpha_21264_tlb {
+ short int in_use;
+ short int next;
+ unsigned char spe;
+ struct alpha_21264_tlbe {
+ int64_t va;
+ struct alpha_pte pte;
+ } entries[MAX_NBR_TLB_21264];
};
+#define ALPHA_PTE_V (1 << 0)
+#define ALPHA_PTE_FOR (1 << 1)
+#define ALPHA_PTE_FOW (1 << 2)
+#define ALPHA_PTE_ASM (1 << 4)
+#define ALPHA_PTE_GH_SHIFT 5
+#define ALPHA_PTE_KRE (1 << 8)
+#define ALPHA_PTE_ERE (1 << 9)
+#define ALPHA_PTE_SRE (1 << 10)
+#define ALPHA_PTE_URE (1 << 11)
+#define ALPHA_PTE_KWE (1 << 12)
+#define ALPHA_PTE_EWE (1 << 13)
+#define ALPHA_PTE_SWE (1 << 14)
+#define ALPHA_PTE_UWE (1 << 15)
+
#if !defined(CONFIG_USER_ONLY)
-#define NB_MMU_MODES 4
+#define NB_MMU_MODES 5
#else
#define NB_MMU_MODES 2
#endif
@@ -304,29 +291,99 @@ struct CPUAlphaState {
uint64_t fpcr;
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 */
- int intr_flag; /* For RC and RS */
-
-#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;
-#endif
/* Those resources are used only in Qemu core */
CPU_COMMON
- uint32_t hflags;
+ unsigned char intr_flag; /* For RC and RS */
+ unsigned char fen; /* FPU enable */
+ unsigned char pal_mode;
+ enum pal_emul pal_emul;
+ unsigned char mmu_data_index; /* 0-3 */
+ unsigned char mmu_code_index; /* 0-4 (pal). */
+
+ /* Common. */
+ uint64_t pal_base;
+ uint64_t exc_addr;
+
#if defined(CONFIG_USER_ONLY)
struct {
uint64_t usp;
uint64_t unique;
} user;
+#else
+ union {
+ struct {
+ /* Trick to emulate an Icache during early pal decompression. */
+ uint64_t pal_reloc_mask;
+ uint64_t pal_reloc_val;
+ uint64_t pal_reloc_offset;
+
+ /* Shadow registers for pal mode. */
+ uint64_t shadow_r4;
+ uint64_t shadow_r5;
+ uint64_t shadow_r6;
+ uint64_t shadow_r7;
+ uint64_t shadow_r20;
+ uint64_t shadow_r21;
+ uint64_t shadow_r22;
+ uint64_t shadow_r23;
+
+ /* CC */
+ uint32_t cc_counter;
+ uint64_t cc_load_ticks;
+
+ /* CC_CTL */
+ uint64_t cc_offset; /* Only the 32 MSB are set. */
+ unsigned char cc_ena;
+
+ /* I_CTL */
+ uint64_t i_vptb;
+ unsigned char iva_48;
+ unsigned char hwe;
+ unsigned char sde1;
+ unsigned char chip_id;
+ unsigned char ic_en;
+ unsigned char call_pal_r23;
+
+ /* IER + CM */
+ unsigned char cm;
+ uint64_t ier;
+
+ uint64_t isum;
+ uint64_t ipend; /* fake. */
+
+ /* VA_CTL */
+ uint64_t d_vptb;
+ unsigned char dva_48;
+
+ /* PCTX. */
+ unsigned char asn;
+ unsigned char astrr;
+ unsigned char aster;
+ unsigned char fpe;
+ unsigned char ppce;
+
+ unsigned char altmode;
+
+ /* SIRR */
+ uint32_t sirr;
+
+ uint64_t mm_stat;
+ uint64_t iva_form;
+
+ uint64_t va_form;
+ uint64_t va;
+
+ uint64_t itb_tag;
+ uint64_t itb_pte;
+ uint64_t dtb_tag;
+ uint64_t dtb_pte;
+ unsigned char dtb_asn;
+
+ struct alpha_21264_tlb itlb, dtlb;
+ } a21264;
+ };
#endif
int error_code;
@@ -334,7 +391,6 @@ struct CPUAlphaState {
uint32_t features;
uint32_t amask;
int implver;
- pal_handler_t *pal_handler;
};
#define cpu_init cpu_alpha_init
@@ -389,18 +445,33 @@ 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_21064_RESET = 0x0000,
+ EXCP_21064_MCHK = 0x0020,
+ EXCP_21064_ARITH = 0x0060,
+ EXCP_21064_HW_INTERRUPT = 0x00E0,
+ EXCP_21064_DFAULT = 0x01E0,
+ EXCP_21064_DTB_MISS_PAL = 0x09E0,
+ EXCP_21064_ITB_MISS = 0x03E0,
+ EXCP_21064_ITB_ACV = 0x07E0,
+ EXCP_21064_DTB_MISS_NATIVE = 0x08E0,
+ EXCP_21064_UNALIGN = 0x11E0,
+ EXCP_21064_OPCDEC = 0x13E0,
+ EXCP_21064_FEN = 0x17E0,
+
+ EXCP_21264_DTBM_DOUBLE_3 = 0x0100,
+ EXCP_21264_DTBM_DOUBLE_4 = 0x0180,
+ EXCP_21264_FEN = 0x0200,
+ EXCP_21264_UNALIGN = 0x0280,
+ EXCP_21264_DTBM_SINGLE = 0x0300,
+ EXCP_21264_DFAULT = 0x0380,
+ EXCP_21264_OPCDEC = 0x0400,
+ EXCP_21264_IACV = 0x0480,
+ EXCP_21264_MCHK = 0x0500,
+ EXCP_21264_ITB_MISS = 0x0580,
+ EXCP_21264_ARITH = 0x0600,
+ EXCP_21264_INTERRUPT = 0x0680,
+ EXCP_21264_MT_FPCR = 0x0700,
+ EXCP_21264_RESET = 0x0780,
/* Generic exception - to be mapped to processor. */
EXCP_GEN_OPCDEC = 1,
@@ -474,11 +545,21 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t
address, int rw,
int mmu_idx, int is_softmmu);
void do_interrupt (CPUState *env);
-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);
-#if !defined (CONFIG_USER_ONLY)
-void call_pal (CPUState *env);
-#endif
+uint64_t cpu_alpha_mfpr_21264 (CPUState *env, int iprn);
+void cpu_alpha_mtpr_21264 (CPUState *env, int iprn, uint64_t val);
+void init_cpu_21264(CPUState *env);
+void swap_shadow_21264(CPUState *env);
+struct alpha_pte cpu_alpha_mmu_v2p_21264(CPUState *env, int64_t address,
+ int rwx);
+void cpu_alpha_mmu_dfault_21264(CPUState *env, int64_t address, int opc);
+int cpu_alpha_mmu_fault_21264 (CPUState *env, int64_t address, int rwx,
+ int mmu_idx, void *retaddr);
+
+void cpu_alpha_mmu_fault_pal(CPUState *env, int64_t address);
+
+void alpha_21264_srm_write(CPUState *env);
+
+void cpu_alpha_update_irq (CPUState *env, int irqs);
static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
{
@@ -490,7 +571,16 @@ static inline void cpu_get_tb_cpu_state(CPUState *env,
target_ulong *pc,
{
*pc = env->pc;
*cs_base = 0;
- *flags = env->ps;
+ *flags = (env->mmu_code_index << 2) | env->mmu_data_index;
}
+/* Flags for virt_to_phys helper. */
+#define ALPHA_HW_MMUIDX_MASK 3
+#define ALPHA_HW_V (1 << 2)
+#define ALPHA_HW_W (1 << 3)
+#define ALPHA_HW_E (1 << 4)
+#define ALPHA_HW_A (1 << 8)
+#define ALPHA_HW_L (1 << 9)
+#define ALPHA_HW_Q (1 << 10)
+
#endif /* !defined (__CPU_ALPHA_H__) */
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 4046463..8e1b317 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include "cpu.h"
+#include "sysemu.h"
#include "exec-all.h"
#if defined(CONFIG_USER_ONLY)
@@ -34,7 +35,7 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong
address, int rw,
env->exception_index = EXCP_USER_ITB_MISS;
else
env->exception_index = EXCP_USER_DFAULT;
- env->ipr[IPR_EXC_ADDR] = address;
+ env->exc_addr = address;
return 1;
}
@@ -56,354 +57,568 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState
*env, target_ulong addr)
return -1;
}
-int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int mmu_idx, int is_softmmu)
+#define GH_MASK(gh) (~((1ULL << (13 + gh)) - 1))
+#define TB_PTE_GET_GH(v) (((v) >> 5) & 3)
+#define TB_PTE_GET_RE(v) (((v) >> 8) & 0x0f)
+#define TB_PTE_GET_WE(v) (((v) >> 12) & 0x0f)
+#define TB_PTE_GET_ASM(v) (((v) >> 4) & 1)
+#define TB_PTE_GET_FO(v) (((v) >> 1) & 2)
+#define IPR_CM_GET_CM(v) (((v) >> 3) & 3)
+
+static uint64_t va_form (int64_t va, uint64_t vptb, int form)
+{
+ va = (va >> 13) << 3;
+ switch (form) {
+ case 0: /* VA_48 = 0, VA_FORM_32 = 0 */
+ return (vptb & 0xfffffffe00000000ULL)
+ | (va & 0x00000001fffffff8ULL);
+ case 1: /* VA_48 = 1, VA_FORM_32 = 0 */
+ return (vptb & 0xfffff80000000000ULL)
+ | (((va << 26) >> 26) & 0x000007fffffffff8ULL);
+ case 2: /* VA_48 = 0, VA_FORM_32 = 1 */
+ return (vptb & 0xffffffffc0000000ULL)
+ | (va & 0x00000000003ffff8ULL);
+ default:
+ abort();
+ }
+}
+
+struct alpha_pte cpu_alpha_mmu_v2p_21264(CPUState *env, int64_t address,
+ int rwx)
{
- uint32_t opc;
+ struct alpha_21264_tlb *tlb;
+ struct alpha_pte pte;
+ int i;
+ int va_sh;
- if (rw == 2) {
+ if (rwx == 2) {
/* Instruction translation buffer miss */
- env->exception_index = EXCP_ITB_MISS;
+ tlb = &env->a21264.itlb;
+ va_sh = env->a21264.iva_48 ? 64 - 48 : 64 - 43;
} else {
- if (env->ipr[IPR_EXC_ADDR] & 1)
- env->exception_index = EXCP_DTB_MISS_PAL;
+ /* Data translation buffer miss */
+ tlb = &env->a21264.dtlb;
+ va_sh = env->a21264.dva_48 ? 64 - 48 : 64 - 43;
+ }
+
+ /* Check sign extension. */
+ if (((address << va_sh) >> va_sh) != address)
+ return ((struct alpha_pte){0, 0, 1});
+
+#if 0
+ fprintf(stderr, "mmu_fault_21264: addr=%016llx, rwx=%d\n", address, rwx);
+#endif
+
+ /* Super page. */
+ if ((tlb->spe & 4) && ((address >> 46) & 3) == 2) {
+ pte.pa = (address & 0x000008ffffffe000ULL) >> 13;
+ pte.fl = ALPHA_PTE_KRE | ALPHA_PTE_KWE | ALPHA_PTE_V;
+ pte.asn = 0;
+ return pte;
+ }
+ if ((tlb->spe & 2) && ((address >> 41) & 0x7f) == 0x7e) {
+ pte.pa = (((address << 23) >> 23) & 0x000008ffffffe000ULL) >> 13;
+ pte.fl = ALPHA_PTE_KRE | ALPHA_PTE_KWE | ALPHA_PTE_V;
+ pte.asn = 0;
+ return pte;
+ }
+ if ((tlb->spe & 1) && ((address >> 30) & 0x3ffff) == 0x3fffe) {
+ pte.pa = (address & 0x000000003fffe000ULL) >> 13;
+ pte.fl = ALPHA_PTE_KRE | ALPHA_PTE_KWE | ALPHA_PTE_V;
+ pte.asn = 0;
+ return pte;
+ }
+
+ /* Search in TLB. */
+ for (i = 0; i < MAX_NBR_TLB_21264; i++) {
+ struct alpha_21264_tlbe *tlbe = &tlb->entries[i];
+ int pg_sh;
+
+ if (!(tlbe->pte.fl & ALPHA_PTE_V))
+ continue;
+
+ pg_sh = 13 + 3 * TB_PTE_GET_GH(tlbe->pte.fl);
+ if ((tlbe->va >> pg_sh) == (address >> pg_sh)
+ && ((tlbe->pte.asn == env->a21264.asn)
+ || (tlbe->pte.fl & ALPHA_PTE_ASM)))
+ return tlbe->pte;
+ }
+
+ return ((struct alpha_pte){0, 0, 0});
+}
+
+void cpu_alpha_mmu_fault_pal(CPUState *env, int64_t address)
+{
+ target_ulong phys_addr = address & TARGET_PAGE_MASK;
+
+ if ((address & env->a21264.pal_reloc_mask)
+ == env->a21264.pal_reloc_val)
+ phys_addr += env->a21264.pal_reloc_offset;
+
+ tlb_set_page_exec(env, address & TARGET_PAGE_MASK, phys_addr,
+ PAGE_EXEC, MMU_PAL_IDX, 1);
+}
+
+void cpu_alpha_mmu_dfault_21264(CPUState *env, int64_t address, int opc)
+{
+ env->a21264.mm_stat = (opc << 4) | ((opc & 0x04) != 0 ? 1 : 0);
+
+ env->a21264.va = address;
+ env->a21264.va_form =
+ va_form(address, env->a21264.d_vptb, env->a21264.dva_48);
+}
+
+int cpu_alpha_mmu_fault_21264(CPUState *env, int64_t address, int rwx,
+ int mmu_idx, void *retaddr)
+{
+ struct alpha_pte pte;
+ int rights;
+
+ pte = cpu_alpha_mmu_v2p_21264(env, address, rwx);
+
+ rights = (pte.fl >> env->a21264.cm);
+ if ((pte.fl & ALPHA_PTE_V)
+ && (rights & (rwx == 1 ? ALPHA_PTE_KWE : ALPHA_PTE_KRE))
+ && (rwx == 2 || !((pte.fl >> rwx) & ALPHA_PTE_FOR))) {
+ uint64_t mask;
+ uint64_t pa;
+
+ mask = ((1ULL << (3 * TB_PTE_GET_GH(pte.fl))) - 1) << 13;
+ pa = ((((uint64_t)pte.pa) << 13) & ~mask) | (address & mask);
+ tlb_set_page_exec
+ (env, address & TARGET_PAGE_MASK, pa,
+ (rwx == 2) ? PAGE_READ | PAGE_EXEC
+ : ((rights & ALPHA_PTE_KWE ? PAGE_WRITE : 0)
+ | (rights & ALPHA_PTE_KRE ? PAGE_READ : 0)),
+ mmu_idx, 1);
+ return 0;
+ }
+
+ /* Not found. */
+ if (rwx == 2) {
+ env->exception_index =
+ (pte.fl == 0 && pte.asn == 0) ? EXCP_21264_ITB_MISS
+ : EXCP_21264_IACV;
+
+ env->a21264.iva_form =
+ va_form(address, env->a21264.i_vptb, env->a21264.iva_48);
+ if (retaddr)
+ abort();
+ } else {
+ TranslationBlock *tb;
+ unsigned long pc;
+ uint64_t phys_pc;
+ uint32_t insn;
+
+ if (pte.fl == 0 && pte.asn == 0)
+ env->exception_index = EXCP_21264_DTBM_SINGLE;
else
- env->exception_index = EXCP_DTB_MISS_NATIVE;
- opc = (ldl_code(env->pc) >> 21) << 4;
- if (rw) {
- opc |= 0x9;
- } else {
- opc |= 0x4;
+ env->exception_index = EXCP_21264_DFAULT;
+
+ /* In order to correctly set mm_stat and find the right exception,
+ we must find which instruction created the fault. */
+
+ /* This code can only be called from a tb (but the debugger!).
+ FIXME: remove the abort() when the code is correct. */
+ if (!likely(retaddr))
+ abort();
+
+ /* now we have a real cpu fault */
+ pc = (unsigned long)retaddr;
+ tb = tb_find_pc(pc);
+ if (!likely(tb)) {
+ /* Not from translated code!! Not possible. */
+ abort();
}
- env->ipr[IPR_MM_STAT] = opc;
+
+ /* the PC is inside the translated code. It means that we
+ have a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, NULL);
+
+ /* Extract physical pc address. */
+ /* FIXME: justify why page_addr[1] is not needed. */
+ phys_pc = tb->page_addr[0] + (env->pc & ~TARGET_PAGE_MASK);
+
+ /* Extract instruction. */
+ insn = ldl_phys(phys_pc);
+
+ cpu_alpha_mmu_dfault_21264(env, address, insn >> 26);
}
return 1;
}
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
+static void insert_itlb_21264(CPUState *env, int64_t va, uint64_t pte)
+{
+ struct alpha_21264_tlb *tlb = &env->a21264.itlb;
+ struct alpha_21264_tlbe *e = &tlb->entries[tlb->next];
+
+ /* Should an already matching entry be discarded ? Not sure. */
+ e->va = ((va & TARGET_PAGE_MASK) << 16) >> 16;
+ e->pte.pa = pte >> 13;
+ e->pte.fl = (pte & 0x1fff) | ALPHA_PTE_V;
+ e->pte.asn = env->a21264.asn;
+
+ tlb->next = (tlb->next + 1) % MAX_NBR_TLB_21264;
+}
+
+static void insert_dtlb_21264(CPUState *env, int64_t va, uint64_t pte)
+{
+ struct alpha_21264_tlb *tlb = &env->a21264.dtlb;
+ struct alpha_21264_tlbe *e = &tlb->entries[tlb->next];
+
+ /* Should an already matching entry be discarded ? Not sure. */
+ e->va = ((va & TARGET_PAGE_MASK) << 16) >> 16;
+ e->pte.pa = pte >> 32;
+ e->pte.asn = env->a21264.asn;
+ e->pte.fl = pte | ALPHA_PTE_V;
+ tlb->next = (tlb->next + 1) % MAX_NBR_TLB_21264;
+}
+
+static void flush_tlb_21264(CPUState *env, struct alpha_21264_tlb *tlb)
{
- uint64_t hwpcb;
- int ret = 0;
+ int i;
+
+ for (i = 0; i < MAX_NBR_TLB_21264; i++) {
+ struct alpha_21264_tlbe *e = &tlb->entries[i];
+ if (!(e->pte.fl & ALPHA_PTE_ASM)
+ && e->pte.asn == env->a21264.asn)
+ e->pte.fl = 0;
+ }
+}
+
+static void flush_tlb_21264_page(CPUState *env, struct alpha_21264_tlb *tlb,
+ uint64_t addr)
+{
+ int i;
+
+ for (i = 0; i < MAX_NBR_TLB_21264; i++) {
+ struct alpha_21264_tlbe *e = &tlb->entries[i];
+ if (!(e->pte.fl & ALPHA_PTE_ASM)
+ && e->pte.asn == env->a21264.asn
+ && e->va == addr)
+ e->pte.fl = 0;
+ }
+}
- hwpcb = env->ipr[IPR_PCBB];
+uint64_t cpu_alpha_mfpr_21264 (CPUState *env, int iprn)
+{
switch (iprn) {
- case IPR_ASN:
- if (env->features & FEATURE_ASN)
- *valp = env->ipr[IPR_ASN];
- else
- *valp = 0;
- break;
- case IPR_ASTEN:
- *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
- break;
- case IPR_ASTSR:
- *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
- break;
- case IPR_DATFX:
- /* Write only */
- ret = -1;
+ case IPR_PAL_BASE:
+ return env->pal_base;
+ case IPR_I_CTL:
+ return env->a21264.i_vptb
+ | (env->a21264.chip_id << IPR_I_CTL_CHIP_ID_SHIFT)
+ | (env->a21264.iva_48 << IPR_I_CTL_VA_48_SHIFT)
+ | (env->a21264.hwe << IPR_I_CTL_HWE_SHIFT)
+ | (env->a21264.sde1 << IPR_I_CTL_SDE1_SHIFT)
+ | (env->a21264.ic_en << IPR_I_CTL_IC_EN_SHIFT)
+ | (env->a21264.call_pal_r23 << IPR_I_CTL_CALL_PAL_R23_SHIFT)
+ | (env->a21264.itlb.spe << IPR_I_CTL_SPE_SHIFT);
+ case IPR_IVA_FORM:
+ return env->a21264.iva_form;
+ case IPR_VA:
+ return env->a21264.va;
+ case IPR_EXC_ADDR:
+ return env->exc_addr;
+ case IPR_I_STAT: /* Not emulated */
+ case IPR_DC_STAT: /* Not emulated */
+ return 0;
+ case IPR_C_DATA:
+ case IPR_C_SHIFT:
+ return 0;
+ case IPR_PCTX ... IPR_PCTX_ALL:
+ return (((uint64_t)env->a21264.asn) << IPR_PCTX_ASN_SHIFT)
+ | (((uint64_t)env->a21264.astrr) << IPR_PCTX_ASTRR_SHIFT)
+ | (((uint64_t)env->a21264.aster) << IPR_PCTX_ASTER_SHIFT)
+ | (((uint64_t)env->a21264.fpe) << IPR_PCTX_FPE_SHIFT)
+ | (((uint64_t)env->a21264.ppce) << IPR_PCTX_PPCE_SHIFT);
+ case IPR_IER_CM:
+ case IPR_CM:
+ case IPR_IER:
+ return (((uint64_t)env->a21264.cm) << IPR_CM_SHIFT)
+ | env->a21264.ier;
+ case IPR_ISUM:
+ return env->a21264.isum;
+ case IPR_SIRR:
+ return env->a21264.sirr;
+ case IPR_MM_STAT:
+ return env->a21264.mm_stat;
+ case IPR_VA_FORM:
+ return env->a21264.va_form;
+ case IPR_EXC_SUM:
+ return 0; /* FIXME. */
+ default:
+ cpu_abort(env, "cpu_alpha_mfpr_21264: ipr 0x%x not handled\n", iprn);
+ }
+}
+
+void cpu_alpha_mtpr_21264 (CPUState *env, int iprn, uint64_t val)
+{
+#if 0
+ qemu_log("cpu_alpha_mtpr_21264: ipr=0x%02x, val="TARGET_FMT_lx"\n",
+ iprn, val);
+#endif
+ switch (iprn) {
+ case IPR_CC:
+ env->a21264.cc_offset = (val >> 32) << 32;
+ break;
+ case IPR_CC_CTL:
+ env->a21264.cc_ena = (val >> IPR_CC_CTL_ENA_SHIFT) & 1;
+ env->a21264.cc_counter = val & IPR_CC_CTL_COUNTER_MASK;
+ env->a21264.cc_load_ticks = cpu_get_ticks();
+ break;
+ case IPR_ITB_TAG:
+ env->a21264.itb_tag = val & 0x0000ffffffffe000ULL;
+ break;
+ case IPR_DTB_TAG0:
+ env->a21264.dtb_tag = val & 0x0000ffffffffe000ULL;
+ break;
+ case IPR_DTB_TAG1:
+ case IPR_DTB_ASN1:
+ case IPR_DTB_PTE1:
+ break; /* DTAG */
+ case IPR_ITB_PTE:
+ env->a21264.itb_pte = val & 0x00000fffffffef70ULL;
+ insert_itlb_21264(env, env->a21264.itb_tag, env->a21264.itb_pte);
+ break;
+ case IPR_DTB_PTE0:
+ env->a21264.dtb_pte = val &= 0x7fffffff0000ffe6ULL;
+ insert_dtlb_21264(env, env->a21264.dtb_tag, env->a21264.dtb_pte);
+ break;
+ case IPR_DTB_ASN0:
+ env->a21264.dtb_asn = (val >> IPR_DTB_ASN_SHIFT) & 0xff;
+ break;
+ case IPR_PAL_BASE:
+ env->pal_base = val & 0x00000fffffff8000ULL;
+ break;
+ case IPR_I_CTL:
+ {
+ unsigned char old_sde1 = env->a21264.sde1;
+ env->a21264.i_vptb =
+ ((((int64_t)val) << 16) >> 16) & 0xffffffffc0000000ULL;
+ env->a21264.hwe = (val >> IPR_I_CTL_HWE_SHIFT) & 1;
+ env->a21264.sde1 = (val >> IPR_I_CTL_SDE1_SHIFT) & 1;
+ env->a21264.iva_48 = (val >> IPR_I_CTL_VA_48_SHIFT) & 3;
+ env->a21264.itlb.spe = (val >> IPR_I_CTL_SPE_SHIFT) & 7;
+ env->a21264.call_pal_r23 = (val >> IPR_I_CTL_CALL_PAL_R23_SHIFT) & 1;
+ if (env->pal_mode && old_sde1 != env->a21264.sde1)
+ swap_shadow_21264(env);
break;
- case IPR_ESP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_ESP];
- else
- *valp = ldq_raw(hwpcb + 8);
- break;
- case IPR_FEN:
- *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
- break;
- case IPR_IPIR:
- /* Write-only */
- ret = -1;
- break;
- case IPR_IPL:
- *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
- break;
- case IPR_KSP:
- if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
- ret = -1;
- } else {
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_KSP];
- else
- *valp = ldq_raw(hwpcb + 0);
+ }
+ case IPR_VA_CTL:
+ env->a21264.d_vptb = val & 0xffffffffc0000000ULL;
+ env->a21264.dva_48 = (val >> IPR_VA_CTL_VA_48_SHIFT) & 3;
+ /* env->a21264.b_endian = val & 1; */
+ if (val & 1)
+ cpu_abort (env, "mtpr va_ctl: b_endian not yet handled\n");
+ break;
+ case IPR_IER_CM:
+ case IPR_CM:
+ case IPR_IER:
+ if (iprn & 2) {
+ env->a21264.ier = val & IPR_IER_MASK;
+ env->a21264.isum = env->a21264.ipend & env->a21264.ier;
+ }
+ if (iprn & 1) {
+ env->a21264.cm = (val & IPR_CM_MASK) >> IPR_CM_SHIFT;
+ env->mmu_data_index = env->a21264.cm;
}
break;
- case IPR_MCES:
- *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
+ case IPR_IC_FLUSH:
+ case IPR_IC_FLUSH_ASM:
+ // tb_flush(env);
break;
- case IPR_PERFMON:
- /* Implementation specific */
- *valp = 0;
+ case IPR_ITB_IA:
+ tlb_flush(env, 1);
+ flush_tlb_21264(env, &env->a21264.itlb);
break;
- case IPR_PCBB:
- *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
+ case IPR_ITB_IS:
+ val &= TARGET_PAGE_MASK;
+ tlb_flush_page(env, val);
+ flush_tlb_21264_page(env, &env->a21264.itlb, val);
break;
- case IPR_PRBR:
- *valp = env->ipr[IPR_PRBR];
+ case IPR_DTB_IA:
+ tlb_flush(env, 1);
+ flush_tlb_21264(env, &env->a21264.dtlb);
break;
- case IPR_PTBR:
- *valp = env->ipr[IPR_PTBR];
+ case IPR_DTB_IS0:
+ val &= TARGET_PAGE_MASK;
+ tlb_flush_page(env, val);
+ flush_tlb_21264_page(env, &env->a21264.dtlb, val);
break;
- case IPR_SCBB:
- *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
+ case IPR_DTB_IS1:
break;
- case IPR_SIRR:
- /* Write-only */
- ret = -1;
- break;
- case IPR_SISR:
- *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
- case IPR_SSP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_SSP];
- else
- *valp = ldq_raw(hwpcb + 16);
+ case IPR_I_STAT: /* Not emulated */
+ case IPR_DC_STAT: /* Not emulated */
break;
- case IPR_SYSPTBR:
- if (env->features & FEATURE_VIRBND)
- *valp = env->ipr[IPR_SYSPTBR];
- else
- ret = -1;
- break;
- case IPR_TBCHK:
- if ((env->features & FEATURE_TBCHK)) {
- /* XXX: TODO */
- *valp = 0;
- ret = -1;
- } else {
- ret = -1;
- }
+ case IPR_MM_STAT: /* RO */
break;
- case IPR_TBIA:
- /* Write-only */
- ret = -1;
+ case IPR_PCTX ... IPR_PCTX_ALL:
+ if (iprn & IPR_PCTX_ASN) {
+ env->a21264.asn = (val >> IPR_PCTX_ASN_SHIFT) & 0xff;
+ tlb_flush(env, 1);
+ tb_flush(env);
+ }
+ if (iprn & IPR_PCTX_ASTRR) {
+ env->a21264.astrr = (val >> IPR_PCTX_ASTRR_SHIFT) & 0xf;
+ if (env->a21264.astrr)
+ cpu_abort(env, "set pctx.astrr unhandled");
+ }
+ if (iprn & IPR_PCTX_ASTER) {
+ env->a21264.aster = (val >> IPR_PCTX_ASTER_SHIFT) & 0xf;
+ if (env->a21264.aster)
+ cpu_abort(env, "set pctx.aster unhandled");
+ }
+ if (iprn & IPR_PCTX_FPE) {
+ env->a21264.fpe = (val >> IPR_PCTX_FPE_SHIFT) & 1;
+ if (!env->a21264.fpe)
+ cpu_abort(env, "set pctx.fpe unhandled");
+ }
+ if (iprn & IPR_PCTX_PPCE)
+ env->a21264.ppce = (val >> IPR_PCTX_PPCE_SHIFT) & 1;
break;
- case IPR_TBIAP:
- /* Write-only */
- ret = -1;
+ case IPR_M_CTL:
+ env->a21264.dtlb.spe =
+ (val >> IPR_M_CTL_SPE_SHIFT) & IPR_M_CTL_SPE_MASK;
break;
- case IPR_TBIS:
- /* Write-only */
- ret = -1;
+ case IPR_SIRR:
+ env->a21264.sirr = val & IPR_SIRR_MASK;
+ env->a21264.ipend = ((env->a21264.ipend & ~IPR_SIRR_MASK)
+ | env->a21264.sirr);
+ env->a21264.isum = env->a21264.ipend & env->a21264.ier;
break;
- case IPR_TBISD:
- /* Write-only */
- ret = -1;
+ case IPR_HW_INT_CLR:
break;
- case IPR_TBISI:
- /* Write-only */
- ret = -1;
+ case IPR_DTB_ALTMODE0:
+ env->a21264.altmode = val & IPR_DTB_ALTMODE_MASK;
break;
- case IPR_USP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_USP];
- else
- *valp = ldq_raw(hwpcb + 24);
+ case IPR_PCTR_CTL:
+ /* Not emulated. */
break;
- case IPR_VIRBND:
- if (env->features & FEATURE_VIRBND)
- *valp = env->ipr[IPR_VIRBND];
- else
- ret = -1;
+ case IPR_C_DATA:
+ case IPR_C_SHIFT:
break;
- case IPR_VPTB:
- *valp = env->ipr[IPR_VPTB];
+ case IPR_DC_CTL:
+ /* Unhandled: f_bad_decc, f_bad_tpar, f_hit. */
+ if (val & 0x34)
+ cpu_abort(env, "cpu_alpha_mtpr_21264 dc_ctl: bad value %08x\n",
+ (unsigned)val);
break;
- case IPR_WHAMI:
- *valp = env->ipr[IPR_WHAMI];
+ case 0x2d: /* Not documented (M_FIX) */
+ /* Hack: save srm. */
+ if (env->a21264.pal_reloc_val)
+ alpha_21264_srm_write(env);
break;
default:
- /* Invalid */
- ret = -1;
- break;
+ cpu_abort(env, "cpu_alpha_mtpr_21264: ipr 0x%x not handled\n", iprn);
}
+}
- return ret;
+void init_cpu_21264(CPUState *env)
+{
+ env->pal_base = 0;
+ env->a21264.chip_id = 0x21;
+ env->a21264.ic_en = 3;
+ env->pal_emul = PAL_21264;
+ memset (&env->a21264.itlb, 0, sizeof (env->a21264.itlb));
+ memset (&env->a21264.dtlb, 0, sizeof (env->a21264.dtlb));
}
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
+void swap_shadow_21264(CPUState *env)
{
- uint64_t hwpcb, tmp64;
- uint8_t tmp8;
- int ret = 0;
+#define swap(a, b) do { uint64_t t = a; a = b; b = t; } while (0)
+ swap(env->a21264.shadow_r4, env->ir[4]);
+ swap(env->a21264.shadow_r5, env->ir[5]);
+ swap(env->a21264.shadow_r6, env->ir[6]);
+ swap(env->a21264.shadow_r7, env->ir[7]);
+ swap(env->a21264.shadow_r20, env->ir[20]);
+ swap(env->a21264.shadow_r21, env->ir[21]);
+ swap(env->a21264.shadow_r22, env->ir[22]);
+ swap(env->a21264.shadow_r23, env->ir[23]);
+#undef swap
+}
- hwpcb = env->ipr[IPR_PCBB];
- switch (iprn) {
- case IPR_ASN:
- /* Read-only */
- ret = -1;
- break;
- case IPR_ASTEN:
- tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
- *oldvalp = tmp8;
- tmp8 &= val & 0xF;
- tmp8 |= (val >> 4) & 0xF;
- env->ipr[IPR_ASTEN] &= ~0xF;
- env->ipr[IPR_ASTEN] |= tmp8;
- ret = 1;
- break;
- case IPR_ASTSR:
- tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
- *oldvalp = tmp8;
- tmp8 &= val & 0xF;
- tmp8 |= (val >> 4) & 0xF;
- env->ipr[IPR_ASTSR] &= ~0xF;
- env->ipr[IPR_ASTSR] |= tmp8;
- ret = 1;
- case IPR_DATFX:
- env->ipr[IPR_DATFX] &= ~0x1;
- env->ipr[IPR_DATFX] |= val & 1;
- tmp64 = ldq_raw(hwpcb + 56);
- tmp64 &= ~0x8000000000000000ULL;
- tmp64 |= (val & 1) << 63;
- stq_raw(hwpcb + 56, tmp64);
- break;
- case IPR_ESP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_ESP] = val;
- else
- stq_raw(hwpcb + 8, val);
- break;
- case IPR_FEN:
- env->ipr[IPR_FEN] = val & 1;
- tmp64 = ldq_raw(hwpcb + 56);
- tmp64 &= ~1;
- tmp64 |= val & 1;
- stq_raw(hwpcb + 56, tmp64);
- break;
- case IPR_IPIR:
- /* XXX: TODO: Send IRQ to CPU #ir[16] */
- break;
- case IPR_IPL:
- *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
- env->ipr[IPR_IPL] &= ~0x1F;
- env->ipr[IPR_IPL] |= val & 0x1F;
- /* XXX: may issue an interrupt or ASR _now_ */
- ret = 1;
- break;
- case IPR_KSP:
- if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
- ret = -1;
- } else {
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_KSP] = val;
- else
- stq_raw(hwpcb + 0, val);
- }
- break;
- case IPR_MCES:
- env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
- env->ipr[IPR_MCES] |= val & 0x18;
- break;
- case IPR_PERFMON:
- /* Implementation specific */
- *oldvalp = 0;
- ret = 1;
- break;
- case IPR_PCBB:
- /* Read-only */
- ret = -1;
- break;
- case IPR_PRBR:
- env->ipr[IPR_PRBR] = val;
- break;
- case IPR_PTBR:
- /* Read-only */
- ret = -1;
- break;
- case IPR_SCBB:
- env->ipr[IPR_SCBB] = (uint32_t)val;
- break;
- case IPR_SIRR:
- if (val & 0xF) {
- env->ipr[IPR_SISR] |= 1 << (val & 0xF);
- /* XXX: request a software interrupt _now_ */
- }
- break;
- case IPR_SISR:
- /* Read-only */
- ret = -1;
- break;
- case IPR_SSP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_SSP] = val;
- else
- stq_raw(hwpcb + 16, val);
- break;
- case IPR_SYSPTBR:
- if (env->features & FEATURE_VIRBND)
- env->ipr[IPR_SYSPTBR] = val;
- else
- ret = -1;
- case IPR_TBCHK:
- /* Read-only */
- ret = -1;
- break;
- case IPR_TBIA:
- tlb_flush(env, 1);
- break;
- case IPR_TBIAP:
- tlb_flush(env, 1);
- break;
- case IPR_TBIS:
- tlb_flush_page(env, val);
- break;
- case IPR_TBISD:
- tlb_flush_page(env, val);
- break;
- case IPR_TBISI:
- tlb_flush_page(env, val);
- break;
- case IPR_USP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_USP] = val;
- else
- stq_raw(hwpcb + 24, val);
- break;
- case IPR_VIRBND:
- if (env->features & FEATURE_VIRBND)
- env->ipr[IPR_VIRBND] = val;
- else
- ret = -1;
- break;
- case IPR_VPTB:
- env->ipr[IPR_VPTB] = val;
- break;
- case IPR_WHAMI:
- /* Read-only */
- ret = -1;
+void cpu_alpha_update_irq (CPUState *env, int irqs)
+{
+ switch (env->pal_emul) {
+ case PAL_21264:
+ env->a21264.ipend &= ~(0x3fULL << 33);
+ env->a21264.ipend |= ((uint64_t)irqs) << 33;
+ env->a21264.isum = env->a21264.ipend & env->a21264.ier;
+ if (env->a21264.isum && !env->pal_mode)
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
break;
default:
- /* Invalid */
- ret = -1;
+ abort();
break;
}
-
- return ret;
}
void do_interrupt (CPUState *env)
{
int excp;
- env->ipr[IPR_EXC_ADDR] = env->pc | 1;
+ if (env->pal_mode && env->exception_index == EXCP_GEN_INTERRUPT) {
+ /* Can this happen ? Maybe if the basic block finishes with a
+ palcall. */
+ cpu_abort(env, "do_interrupt: pal_mode=1\n");
+ }
+
+ env->exc_addr = env->pc | env->pal_mode;
excp = env->exception_index;
env->exception_index = 0;
env->error_code = 0;
- /* XXX: disable interrupts and memory mapping */
- if (env->ipr[IPR_PAL_BASE] != -1ULL) {
+ env->pal_mode = 1;
+ env->mmu_code_index = MMU_PAL_IDX;
+
+ /* Generic exception translation. */
+ if (excp <= EXCP_GEN_LAST) {
+ switch (env->pal_emul) {
+ case PAL_21264:
+ switch (excp) {
+ case EXCP_GEN_OPCDEC: excp = EXCP_21264_OPCDEC; break;
+ case EXCP_GEN_ARITH: excp = EXCP_21264_ARITH; break;
+ case EXCP_GEN_INTERRUPT: excp = EXCP_21264_INTERRUPT; break;
+ default:
+ abort();
+ }
+ break;
+ case PAL_NONE:
+ cpu_abort(env, "do_interrupt: pal emul not supported\n");
+ }
+ }
+
+ switch (env->pal_emul) {
+ case PAL_21264:
+ if (env->a21264.sde1 && !(env->exc_addr & 1))
+ swap_shadow_21264(env);
+ if ((excp & EXCP_CALL_PALP) && env->a21264.call_pal_r23)
+ env->ir[23] = env->pc;
+ if (excp == EXCP_21264_INTERRUPT)
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ break;
+ default:
+ break;
+ }
+
+
+ /* We use native PALcode */
+ env->pc = env->pal_base + excp;
+
+#if 0
+ if (env->pal_base != -1ULL) {
/* We use native PALcode */
- env->pc = env->ipr[IPR_PAL_BASE] + excp;
+ env->pc = env->pal_base + excp;
} else {
/* We use emulated PALcode */
call_pal(env);
/* Emulate REI */
- env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
- env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
+ env->pc = env->exc_addr & ~3ULL;
+ /* env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1; */
/* XXX: re-enable interrupts and memory mapping */
}
+#endif
}
#endif
@@ -419,8 +634,8 @@ void cpu_dump_state (CPUState *env, FILE *f,
};
int i;
- cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n",
- env->pc, env->ps);
+ cpu_fprintf(f, " PC " TARGET_FMT_lx " pal=%d\n",
+ env->pc, env->pal_mode);
for (i = 0; i < 31; i++) {
cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
linux_reg_names[i], env->ir[i]);
@@ -434,5 +649,6 @@ void cpu_dump_state (CPUState *env, FILE *f,
if ((i % 3) == 2)
cpu_fprintf(f, "\n");
}
- cpu_fprintf(f, "\nlock " TARGET_FMT_lx "\n", env->lock);
+ cpu_fprintf(f, "\n");
+ /* cpu_fprintf(f, "\nlock " TARGET_FMT_lx "\n", env->lock); */
}
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 7c7278f..eaab3d0 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -111,11 +111,9 @@ DEF_HELPER_0(hw_rei, void)
DEF_HELPER_1(hw_ret, void, i64)
DEF_HELPER_2(mfpr, i64, int, i64)
DEF_HELPER_2(mtpr, void, int, i64)
-DEF_HELPER_0(set_alt_mode, void)
-DEF_HELPER_0(restore_mode, void)
-DEF_HELPER_1(ld_virt_to_phys, i64, i64)
-DEF_HELPER_1(st_virt_to_phys, i64, i64)
+DEF_HELPER_2(21264_hw_ldq, i64, i64, i32)
+DEF_HELPER_2(21264_hw_ldl, i64, i64, i32)
DEF_HELPER_1(ldl_phys, i64, i64)
DEF_HELPER_1(ldq_phys, i64, i64)
DEF_HELPER_1(ldl_l_phys, i64, i64)
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 9e9289f..37d7be0 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -27,6 +27,8 @@
#include "softmmu_exec.h"
#endif /* !defined(CONFIG_USER_ONLY) */
+extern uint64_t cpu_get_ticks(void);
+
void helper_tb_flush (void)
{
tb_flush(env);
@@ -58,8 +60,22 @@ uint64_t helper_amask (uint64_t arg)
uint64_t helper_load_pcc (void)
{
- /* XXX: TODO */
+#ifdef CONFIG_USER_ONLY
+ /* FIXME */
return 0;
+#else
+ uint32_t res;
+
+ switch (env->pal_emul) {
+ case PAL_21264:
+ res = env->a21264.cc_counter;
+ if (env->a21264.cc_ena)
+ res += (cpu_get_ticks() - env->a21264.cc_load_ticks) >> 3;
+ return res | env->a21264.cc_offset;
+ default:
+ cpu_abort(env,"load_ppc: bad pal emul\n");
+ }
+#endif
}
uint64_t helper_load_implver (void)
@@ -145,7 +161,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 += op2;
if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
- helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ helper_excp(EXCP_GEN_ARITH, EXCP_ARITH_OVERFLOW);
}
return op1;
}
@@ -155,7 +171,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 = (uint32_t)(op1 + op2);
if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
- helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ helper_excp(EXCP_GEN_ARITH, EXCP_ARITH_OVERFLOW);
}
return op1;
}
@@ -165,7 +181,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 -= op2;
if (unlikely(((~tmp) ^ op1 ^ (-1ULL)) & ((~tmp) ^ op2) & (1ULL << 63))) {
- helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ helper_excp(EXCP_GEN_ARITH, EXCP_ARITH_OVERFLOW);
}
return op1;
}
@@ -175,7 +191,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 = (uint32_t)(op1 - op2);
if (unlikely(((~tmp) ^ op1 ^ (-1UL)) & ((~tmp) ^ op2) & (1UL << 31))) {
- helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ helper_excp(EXCP_GEN_ARITH, EXCP_ARITH_OVERFLOW);
}
return op1;
}
@@ -185,7 +201,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2)
int64_t res = (int64_t)op1 * (int64_t)op2;
if (unlikely((int32_t)res != res)) {
- helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ helper_excp(EXCP_GEN_ARITH, EXCP_ARITH_OVERFLOW);
}
return (int64_t)((int32_t)res);
}
@@ -197,7 +213,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
muls64(&tl, &th, op1, op2);
/* If th != 0 && th != -1, then we had an overflow */
if (unlikely((th + 1) > 1)) {
- helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ helper_excp(EXCP_GEN_ARITH, EXCP_ARITH_OVERFLOW);
}
return tl;
}
@@ -390,7 +406,7 @@ static always_inline float32 f_to_float32 (uint64_t a)
if (unlikely(!exp && mant_sig)) {
/* Reserved operands / Dirty zero */
- helper_excp(EXCP_OPCDEC, 0);
+ helper_excp(EXCP_GEN_OPCDEC, 0);
}
if (exp < 3) {
@@ -517,7 +533,7 @@ static always_inline float64 g_to_float64 (uint64_t a)
if (!exp && mant_sig) {
/* Reserved operands / Dirty zero */
- helper_excp(EXCP_OPCDEC, 0);
+ helper_excp(EXCP_GEN_OPCDEC, 0);
}
if (exp < 3) {
@@ -972,7 +988,7 @@ static always_inline uint64_t __helper_cvtql (uint64_t a,
int s, int v)
r |= ((uint64_t)(a & 0x7FFFFFFF)) << 29;
if (v && (int64_t)((int32_t)r) != (int64_t)r) {
- helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ helper_excp(EXCP_GEN_ARITH, EXCP_ARITH_OVERFLOW);
}
if (s) {
/* TODO */
@@ -999,96 +1015,137 @@ uint64_t helper_cvtqlsv (uint64_t a)
#if !defined (CONFIG_USER_ONLY)
void helper_hw_rei (void)
{
- env->pc = env->ipr[IPR_EXC_ADDR] & ~3;
- env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
+#if 0
+ /* FIXME: For 21064/21164 only ? */
+ env->pc = env->any.ipr[IPR_EXC_ADDR] & ~3;
+ env->any.ipr[IPR_EXC_ADDR] = env->any.ipr[IPR_EXC_ADDR] & 1;
/* XXX: re-enable interrupts and memory mapping */
+#else
+ cpu_abort(env, "hw_rei not implemented\n");
+#endif
}
void helper_hw_ret (uint64_t a)
{
- env->pc = a & ~3;
- env->ipr[IPR_EXC_ADDR] = a & 1;
- /* XXX: re-enable interrupts and memory mapping */
+ switch (env->pal_emul) {
+ case PAL_21264:
+ if (!(a & 1) && env->a21264.isum) {
+#if 0
+ qemu_log("pal mode ret interrupt ier=%016llx, isum=%016llx
ir=%x\n",
+ env->a21264.ier, env->a21264.isum,
+ env->interrupt_request);
+#endif
+ /* Very fast interrupt delivery! */
+ env->exc_addr = a;
+ env->pc = env->pal_base + EXCP_21264_INTERRUPT;
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ break;
+ }
+ env->pc = a & ~3;
+ if (env->pal_mode != (a & 1)) {
+ env->pal_mode = a & 1;
+ if (!env->pal_mode)
+ env->mmu_code_index = env->mmu_data_index;
+ else
+ env->mmu_code_index = MMU_PAL_IDX;
+ if (env->a21264.sde1 && !(a & 1))
+ swap_shadow_21264(env);
+ }
+ break;
+ case PAL_NONE:
+ cpu_abort(env, "hw_ret: not supported by pal emulation\n");
+ }
}
uint64_t helper_mfpr (int iprn, uint64_t val)
{
- uint64_t tmp;
-
- if (cpu_alpha_mfpr(env, iprn, &tmp) == 0)
- val = tmp;
-
+ switch (env->pal_emul) {
+ case PAL_21264:
+ return cpu_alpha_mfpr_21264(env, iprn);
+ break;
+ case PAL_NONE:
+ cpu_abort(env, "hw_mfpr: not supported by pal emulation\n");
+ }
return val;
}
void helper_mtpr (int iprn, uint64_t val)
{
- cpu_alpha_mtpr(env, iprn, val, NULL);
-}
-
-void helper_set_alt_mode (void)
-{
- env->saved_mode = env->ps & 0xC;
- env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC);
-}
-
-void helper_restore_mode (void)
-{
- env->ps = (env->ps & ~0xC) | env->saved_mode;
+ switch (env->pal_emul) {
+ case PAL_21264:
+ cpu_alpha_mtpr_21264(env, iprn, val);
+ return;
+ case PAL_NONE:
+ cpu_abort(env, "hw_mtpr: not supported by pal emulation\n");
+ }
}
-
#endif
/*****************************************************************************/
/* Softmmu support */
#if !defined (CONFIG_USER_ONLY)
-/* XXX: the two following helpers are pure hacks.
- * Hopefully, we emulate the PALcode, then we should never see
- * HW_LD / HW_ST instructions.
- */
-uint64_t helper_ld_virt_to_phys (uint64_t virtaddr)
+static uint64_t hw_ld_virt2phys (uint64_t virtaddr, uint32_t v2p_flags)
+{
+ int mmu_idx;
+ struct alpha_pte pte;
+
+ mmu_idx = v2p_flags & ALPHA_HW_MMUIDX_MASK;
+ pte = cpu_alpha_mmu_v2p_21264(env, virtaddr, 0);
+ if (!(pte.fl & ALPHA_PTE_V)) {
+ if (v2p_flags & ALPHA_HW_V) {
+ /* Virtual pte access. */
+ env->exception_index = env->a21264.iva_48 ?
+ EXCP_21264_DTBM_DOUBLE_4 : EXCP_21264_DTBM_DOUBLE_3;
+ } else
+ env->exception_index = EXCP_21264_DTBM_SINGLE;
+ cpu_alpha_mmu_dfault_21264(env, virtaddr, 0x03);
+ cpu_loop_exit();
+ }
+ if ((v2p_flags & ALPHA_HW_W)
+ && (!((pte.fl >> mmu_idx) & ALPHA_PTE_KRE)
+ || (pte.fl & ALPHA_PTE_FOR))) {
+ env->exception_index = EXCP_21264_DFAULT;
+ cpu_alpha_mmu_dfault_21264(env, virtaddr, 0x03);
+ cpu_loop_exit();
+ }
+ return (((uint64_t)pte.pa) << 13) | (virtaddr & ~TARGET_PAGE_MASK);
+}
+
+uint64_t helper_21264_hw_ldq (uint64_t virtaddr, uint32_t v2p_flags)
{
uint64_t tlb_addr, physaddr;
int index, mmu_idx;
- void *retaddr;
- mmu_idx = cpu_mmu_index_data(env);
+ mmu_idx = v2p_flags & ALPHA_HW_MMUIDX_MASK;
index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
tlb_addr = env->tlb_table[mmu_idx][index].addr_read;
if ((virtaddr & TARGET_PAGE_MASK) ==
(tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
+ return ldq_raw((uint8_t *)physaddr);
} else {
- /* the page is not in the TLB : fill it */
- retaddr = GETPC();
- tlb_fill(virtaddr, 0, mmu_idx, retaddr);
- goto redo;
+ physaddr = hw_ld_virt2phys(virtaddr, v2p_flags);
+ return ldq_phys(physaddr);
}
- return physaddr;
}
-uint64_t helper_st_virt_to_phys (uint64_t virtaddr)
+uint64_t helper_21264_hw_ldl (uint64_t virtaddr, uint32_t v2p_flags)
{
uint64_t tlb_addr, physaddr;
int index, mmu_idx;
- void *retaddr;
- mmu_idx = cpu_mmu_index_data(env);
+ mmu_idx = v2p_flags & ALPHA_HW_MMUIDX_MASK;
index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
- tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
+ tlb_addr = env->tlb_table[mmu_idx][index].addr_read;
if ((virtaddr & TARGET_PAGE_MASK) ==
(tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
+ return ldl_raw((uint8_t *)physaddr);
} else {
- /* the page is not in the TLB : fill it */
- retaddr = GETPC();
- tlb_fill(virtaddr, 1, mmu_idx, retaddr);
- goto redo;
+ physaddr = hw_ld_virt2phys(virtaddr, v2p_flags);
+ return ldl_phys(physaddr);
}
- return physaddr;
}
uint64_t helper_ldl_phys(uint64_t addr)
@@ -1185,31 +1242,29 @@ uint64_t helper_stq_c_phys(uint64_t val, uint64_t addr)
NULL, it means that the function was called in C code (i.e. not
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill (target_ulong addr, int rwx, int mmu_idx, void *retaddr)
{
- TranslationBlock *tb;
CPUState *saved_env;
- unsigned long pc;
int ret;
/* XXX: hack to restore env in all cases, even if not called from
generated code */
saved_env = env;
env = cpu_single_env;
- ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
- if (!likely(ret == 0)) {
- if (likely(retaddr)) {
- /* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
- if (likely(tb)) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, pc, NULL);
- }
+
+ if (rwx == 2 && mmu_idx == MMU_PAL_IDX)
+ cpu_alpha_mmu_fault_pal(env, addr);
+ else {
+ switch (env->pal_emul) {
+ case PAL_21264:
+ ret = cpu_alpha_mmu_fault_21264(env, addr, rwx, mmu_idx, retaddr);
+ if (!likely(ret == 0))
+ /* Exception index and error code are already set */
+ cpu_loop_exit();
+ break;
+ case PAL_NONE:
+ cpu_abort(env, "tlb_fill: not supported by pal emulation\n");
}
- /* Exception index and error code are already set */
- cpu_loop_exit();
}
env = saved_env;
}
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 6938b5d..99527f5 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -47,6 +47,7 @@
typedef struct DisasContext DisasContext;
struct DisasContext {
uint64_t pc;
+ CPUAlphaState *env;
int mem_idx;
#if !defined (CONFIG_USER_ONLY)
int pal_mode;
@@ -106,7 +107,7 @@ static void alpha_translate_init(void)
static inline int get_mxcr_iprn(DisasContext *ctx, uint32_t insn)
{
- switch (ctx->implver) {
+ switch (ctx->env->implver) {
case IMPLVER_2106x:
return insn & 0xff;
case IMPLVER_21164:
@@ -118,6 +119,43 @@ static inline int get_mxcr_iprn(DisasContext *ctx,
uint32_t insn)
}
}
+#if !defined (CONFIG_USER_ONLY)
+static inline void gen_hw_ld(DisasContext *ctx, int ra, TCGv addr,
+ int hw_flags)
+{
+ TCGv_i32 flags = tcg_temp_new_i32();
+
+ tcg_gen_movi_i64(cpu_pc, ctx->pc - 4);
+ tcg_gen_movi_i32(flags, ctx->mem_idx | hw_flags);
+ switch (ctx->env->pal_emul) {
+ case PAL_21264:
+ if (hw_flags & ALPHA_HW_L)
+ gen_helper_21264_hw_ldl(cpu_ir[ra], addr, flags);
+ else if (hw_flags & ALPHA_HW_Q)
+ gen_helper_21264_hw_ldq(cpu_ir[ra], addr, flags);
+ else
+ abort();
+ break;
+ default:
+ cpu_abort(ctx->env, "gen_hw_ld: pal emul %d not supported\n",
+ ctx->env->pal_emul);
+ }
+ tcg_temp_free_i32(flags);
+}
+
+static inline void gen_hw_st(DisasContext *ctx, int ra, TCGv addr,
+ int hw_flags)
+{
+ TCGv_i32 flags = tcg_temp_new_i32();
+
+ tcg_gen_movi_i64(cpu_pc, ctx->pc - 4);
+ tcg_gen_movi_i32(flags, ctx->mem_idx | hw_flags);
+ cpu_abort(ctx->env, "gen_hw_st: pal emul %d not supported\n",
+ ctx->env->pal_emul);
+ tcg_temp_free_i32(flags);
+}
+#endif /* CONFIG_USER_ONLY */
+
static always_inline void gen_excp (DisasContext *ctx,
int exception, int error_code)
{
@@ -133,7 +171,7 @@ static always_inline void gen_excp (DisasContext *ctx,
static always_inline void gen_invalid (DisasContext *ctx)
{
- gen_excp(ctx, EXCP_OPCDEC, 0);
+ gen_excp(ctx, EXCP_GEN_OPCDEC, 0);
}
static always_inline void gen_qemu_ldf (TCGv t0, TCGv t1, int flags)
@@ -1806,6 +1844,8 @@ static always_inline int translate_one (DisasContext
*ctx, uint32_t insn)
tcg_gen_addi_i64(addr, cpu_ir[rb], disp12);
else
tcg_gen_movi_i64(addr, disp12);
+ /* Data alignment check is disabled for hw_ld */
+ tcg_gen_andi_i64(addr, addr, ((insn >> 12) & 1) ? ~0x7 : ~0x3);
switch ((insn >> 12) & 0xF) {
case 0x0:
/* Longword physical access (hw_ldl/p) */
@@ -1825,11 +1865,11 @@ static always_inline int translate_one (DisasContext
*ctx, uint32_t insn)
break;
case 0x4:
/* Longword virtual PTE fetch (hw_ldl/v) */
- tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_V | ALPHA_HW_L);
break;
case 0x5:
/* Quadword virtual PTE fetch (hw_ldq/v) */
- tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_V | ALPHA_HW_Q);
break;
case 0x6:
/* Incpu_ir[ra]id */
@@ -1839,51 +1879,37 @@ static always_inline int translate_one (DisasContext
*ctx, uint32_t insn)
goto invalid_opc;
case 0x8:
/* Longword virtual access (hw_ldl) */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldl_phys(cpu_ir[ra], addr);
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_L);
break;
case 0x9:
/* Quadword virtual access (hw_ldq) */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldq_phys(cpu_ir[ra], addr);
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_Q);
break;
case 0xA:
/* Longword virtual access with protection check (hw_ldl/w) */
- tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_W | ALPHA_HW_L);
break;
case 0xB:
/* Quadword virtual access with protection check (hw_ldq/w) */
- tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_W | ALPHA_HW_Q);
break;
case 0xC:
/* Longword virtual access with alt access mode (hw_ldl/a)*/
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldl_phys(cpu_ir[ra], addr);
- gen_helper_restore_mode();
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_A | ALPHA_HW_L);
break;
case 0xD:
/* Quadword virtual access with alt access mode (hw_ldq/a) */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldq_phys(cpu_ir[ra], addr);
- gen_helper_restore_mode();
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_A | ALPHA_HW_Q);
break;
case 0xE:
/* Longword virtual access with alternate access mode and
- * protection checks (hw_ldl/wa)
- */
- gen_helper_set_alt_mode();
- gen_helper_ldl_data(cpu_ir[ra], addr);
- gen_helper_restore_mode();
+ * protection checks (hw_ldl/wa) */
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_A | ALPHA_HW_W | ALPHA_HW_L);
break;
case 0xF:
/* Quadword virtual access with alternate access mode and
- * protection checks (hw_ldq/wa)
- */
- gen_helper_set_alt_mode();
- gen_helper_ldq_data(cpu_ir[ra], addr);
- gen_helper_restore_mode();
+ * protection checks (hw_ldq/wa) */
+ gen_hw_ld(ctx, ra, addr, ALPHA_HW_A | ALPHA_HW_W | ALPHA_HW_Q);
break;
}
tcg_temp_free(addr);
@@ -2135,6 +2161,7 @@ static always_inline int translate_one (DisasContext
*ctx, uint32_t insn)
val = tcg_temp_new();
tcg_gen_movi_i64(val, 0);
}
+ LOG_DISAS("pal1f acc=%d\n", (insn >> 12) & 0xf);
switch ((insn >> 12) & 0xF) {
case 0x0:
/* Longword physical access */
@@ -2154,13 +2181,11 @@ static always_inline int translate_one (DisasContext
*ctx, uint32_t insn)
break;
case 0x4:
/* Longword virtual access */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_phys(val, addr);
+ gen_hw_st(ctx, addr, val, ALPHA_HW_L);
break;
case 0x5:
/* Quadword virtual access */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stq_phys(val, addr);
+ gen_hw_st(ctx, addr, val, ALPHA_HW_Q);
break;
case 0x6:
/* Invalid */
@@ -2182,17 +2207,11 @@ static always_inline int translate_one (DisasContext
*ctx, uint32_t insn)
goto invalid_opc;
case 0xC:
/* Longword virtual access with alternate access mode */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_phys(val, addr);
- gen_helper_restore_mode();
+ gen_hw_st(ctx, addr, val, ALPHA_HW_A | ALPHA_HW_L);
break;
case 0xD:
/* Quadword virtual access with alternate access mode */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_phys(val, addr);
- gen_helper_restore_mode();
+ gen_hw_st(ctx, addr, val, ALPHA_HW_A | ALPHA_HW_Q);
break;
case 0xE:
/* Invalid */
@@ -2367,12 +2386,20 @@ static always_inline void
gen_intermediate_code_internal (CPUState *env,
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
ctx.pc = pc_start;
ctx.amask = env->amask;
- ctx.implver = env->implver;
+ ctx.env = env;
#if defined (CONFIG_USER_ONLY)
ctx.mem_idx = 0;
#else
- ctx.mem_idx = ((env->ps >> 3) & 3);
- ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1;
+ ctx.mem_idx = env->mmu_data_index;
+ ctx.pal_mode = env->pal_mode;
+ switch (env->pal_emul) {
+ case PAL_21264:
+ if (env->a21264.hwe && env->a21264.cm == 0)
+ ctx.pal_mode = 1;
+ break;
+ default:
+ break;
+ }
#endif
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
@@ -2428,7 +2455,7 @@ static always_inline void gen_intermediate_code_internal
(CPUState *env,
if (env->singlestep_enabled) {
gen_excp(&ctx, EXCP_DEBUG, 0);
break;
- }
+ }
#if defined (DO_SINGLE_STEP)
break;
@@ -2501,7 +2528,6 @@ void alpha_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f,
const char *fmt, ...))
CPUAlphaState * cpu_alpha_init (const char *cpu_model)
{
CPUAlphaState *env;
- uint64_t hwpcb;
const struct alpha_def *cpu = alpha_defs;
if (cpu_model != NULL) {
@@ -2520,31 +2546,24 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
alpha_translate_init();
tlb_flush(env, 1);
+ env->pal_emul = PAL_NONE;
env->implver = cpu->implver;
env->amask = cpu->amask;
- env->ps = 0x1F00;
-#if defined (CONFIG_USER_ONLY)
- env->ps |= 1 << 3;
-#endif
- /* Initialize IPR */
- hwpcb = env->ipr[IPR_PCBB];
- env->ipr[IPR_ASN] = 0;
- env->ipr[IPR_ASTEN] = 0;
- env->ipr[IPR_ASTSR] = 0;
- env->ipr[IPR_DATFX] = 0;
- /* XXX: fix this */
- // env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8);
- // env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0);
- // env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16);
- // env->ipr[IPR_USP] = ldq_raw(hwpcb + 24);
- env->ipr[IPR_FEN] = 0;
- env->ipr[IPR_IPL] = 31;
- env->ipr[IPR_MCES] = 0;
- env->ipr[IPR_PERFMON] = 0; /* Implementation specific */
- // env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32);
- env->ipr[IPR_SISR] = 0;
- env->ipr[IPR_VIRBND] = -1ULL;
+#ifndef CONFIG_USER_ONLY
+ env->pal_mode = 1;
+ env->mmu_code_index = 4;
+ env->mmu_data_index = 0;
+
+ switch (env->implver) {
+ case IMPLVER_21264:
+ init_cpu_21264(env);
+ break;
+ default:
+ abort();
+ break;
+ }
+#endif
return env;
}
--
1.6.2
- [Qemu-devel] [PATCH 09/19] Add square wave output support., (continued)
- [Qemu-devel] [PATCH 09/19] Add square wave output support., Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 10/19] Add ali1543 super IO pci device., Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 11/19] Add 21272 chipset (memory and pci controller for alpha), Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 12/19] Add target-alpha/machine.c and hw/es40.c for es40 machine emulation., Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 13/19] Move softmmu_helper.h from exec.h to op_helper.c on alpha., Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 14/19] alpha ld helpers now directly return the value., Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 15/19] Add alpha_cpu_list., Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 16/19] Alpha: lower parent irq when irq is lowered., Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 17/19] Move linux-user pal emulation to linux-user/, Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 18/19] Correctly decode hw_ld/hw_st opcodes for all alpha implementations., Tristan Gingold, 2009/03/30
- [Qemu-devel] [PATCH 19/19] Add full emulation for 21264.,
Tristan Gingold <=
Re: [Qemu-devel] [PATCH 0/20]: add alpha es40 system emulation (v4), Brian Wheeler, 2009/03/30