aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2014-09-16 12:16:38 -0700
committerRichard Henderson <rth@twiddle.net>2015-08-18 11:08:48 -0700
commit591243846f7d0dc59f482a89e241a6ce02d25fae (patch)
tree1590c103a70c076198d0e38b1b993f70b584c36f
parent074a9925e1cfd659d5376dcaccd1436d3840e611 (diff)
target-alpha: Use separate TCGv temporaries for the shadow registers
This avoids having to manually swap them around when swapping to and from PALmode. We simply encode the shadow registers into the translation. The VMStateDescription version changes, because the meaning of "shadow" changes in the save file when in PALmode. It would be possible to fix this, but I don't think it's worth the effort. Reviewed-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Richard Henderson <rth@twiddle.net>
-rw-r--r--target-alpha/cpu.h3
-rw-r--r--target-alpha/gdbstub.c4
-rw-r--r--target-alpha/helper.c63
-rw-r--r--target-alpha/machine.c4
-rw-r--r--target-alpha/sys_helper.c10
-rw-r--r--target-alpha/translate.c153
6 files changed, 134 insertions, 103 deletions
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 91c56d6bcf..3f1ece30ee 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -445,8 +445,9 @@ void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t);
uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env);
void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val);
+uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg);
+void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val);
#ifndef CONFIG_USER_ONLY
-void swap_shadow_regs(CPUAlphaState *env);
QEMU_NORETURN void alpha_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
bool is_write, bool is_exec,
int unused, unsigned size);
diff --git a/target-alpha/gdbstub.c b/target-alpha/gdbstub.c
index 980f140e72..99a4051b35 100644
--- a/target-alpha/gdbstub.c
+++ b/target-alpha/gdbstub.c
@@ -30,7 +30,7 @@ int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
switch (n) {
case 0 ... 30:
- val = env->ir[n];
+ val = cpu_alpha_load_gr(env, n);
break;
case 32 ... 62:
d.d = env->fir[n - 32];
@@ -66,7 +66,7 @@ int alpha_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
switch (n) {
case 0 ... 30:
- env->ir[n] = tmp;
+ cpu_alpha_store_gr(env, n, tmp);
break;
case 32 ... 62:
d.ll = tmp;
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 46b8ef9141..5a85335838 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -79,6 +79,30 @@ void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
cpu_alpha_store_fpcr(env, val);
}
+static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg)
+{
+#ifndef CONFIG_USER_ONLY
+ if (env->pal_mode) {
+ if (reg >= 8 && reg <= 14) {
+ return &env->shadow[reg - 8];
+ } else if (reg == 25) {
+ return &env->shadow[7];
+ }
+ }
+#endif
+ return &env->ir[reg];
+}
+
+uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg)
+{
+ return *cpu_alpha_addr_gr(env, reg);
+}
+
+void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
+{
+ *cpu_alpha_addr_gr(env, reg) = val;
+}
+
#if defined(CONFIG_USER_ONLY)
int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
int rw, int mmu_idx)
@@ -90,38 +114,6 @@ int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
return 1;
}
#else
-void swap_shadow_regs(CPUAlphaState *env)
-{
- uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
-
- i0 = env->ir[8];
- i1 = env->ir[9];
- i2 = env->ir[10];
- i3 = env->ir[11];
- i4 = env->ir[12];
- i5 = env->ir[13];
- i6 = env->ir[14];
- i7 = env->ir[25];
-
- env->ir[8] = env->shadow[0];
- env->ir[9] = env->shadow[1];
- env->ir[10] = env->shadow[2];
- env->ir[11] = env->shadow[3];
- env->ir[12] = env->shadow[4];
- env->ir[13] = env->shadow[5];
- env->ir[14] = env->shadow[6];
- env->ir[25] = env->shadow[7];
-
- env->shadow[0] = i0;
- env->shadow[1] = i1;
- env->shadow[2] = i2;
- env->shadow[3] = i3;
- env->shadow[4] = i4;
- env->shadow[5] = i5;
- env->shadow[6] = i6;
- env->shadow[7] = i7;
-}
-
/* Returns the OSF/1 entMM failure indication, or -1 on success. */
static int get_physical_address(CPUAlphaState *env, target_ulong addr,
int prot_need, int mmu_idx,
@@ -375,10 +367,7 @@ void alpha_cpu_do_interrupt(CPUState *cs)
env->pc = env->palbr + i;
/* Switch to PALmode. */
- if (!env->pal_mode) {
- env->pal_mode = 1;
- swap_shadow_regs(env);
- }
+ env->pal_mode = 1;
#endif /* !USER_ONLY */
}
@@ -443,7 +432,7 @@ void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
env->pc, env->ps);
for (i = 0; i < 31; i++) {
cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
- linux_reg_names[i], env->ir[i]);
+ linux_reg_names[i], cpu_alpha_load_gr(env, i));
if ((i % 3) == 2)
cpu_fprintf(f, "\n");
}
diff --git a/target-alpha/machine.c b/target-alpha/machine.c
index e796bbe27d..d9bf977fc6 100644
--- a/target-alpha/machine.c
+++ b/target-alpha/machine.c
@@ -70,8 +70,8 @@ static VMStateField vmstate_env_fields[] = {
static const VMStateDescription vmstate_env = {
.name = "env",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = vmstate_env_fields,
};
diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c
index 1c59e108b9..f01eb96e1c 100644
--- a/target-alpha/sys_helper.c
+++ b/target-alpha/sys_helper.c
@@ -45,10 +45,7 @@ void helper_hw_ret(CPUAlphaState *env, uint64_t a)
env->pc = a & ~3;
env->intr_flag = 0;
env->lock_addr = -1;
- if ((a & 1) == 0) {
- env->pal_mode = 0;
- swap_shadow_regs(env);
- }
+ env->pal_mode = a & 1;
}
void helper_call_pal(CPUAlphaState *env, uint64_t pc, uint64_t entry_ofs)
@@ -56,10 +53,7 @@ void helper_call_pal(CPUAlphaState *env, uint64_t pc, uint64_t entry_ofs)
int pal_mode = env->pal_mode;
env->exc_addr = pc | pal_mode;
env->pc = env->palbr + entry_ofs;
- if (!pal_mode) {
- env->pal_mode = 1;
- swap_shadow_regs(env);
- }
+ env->pal_mode = 1;
}
void helper_tbia(CPUAlphaState *env)
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 81d4ff827c..62002dcfc9 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -52,6 +52,9 @@ struct DisasContext {
/* implver value for this CPU. */
int implver;
+ /* The set of registers active in the current context. */
+ TCGv *ir;
+
/* Temporaries for $31 and $f31 as source and destination. */
TCGv zero;
TCGv sink;
@@ -86,13 +89,17 @@ typedef enum {
/* global register indexes */
static TCGv_ptr cpu_env;
-static TCGv cpu_ir[31];
+static TCGv cpu_std_ir[31];
static TCGv cpu_fir[31];
static TCGv cpu_pc;
static TCGv cpu_lock_addr;
static TCGv cpu_lock_st_addr;
static TCGv cpu_lock_value;
+#ifndef CONFIG_USER_ONLY
+static TCGv cpu_pal_ir[31];
+#endif
+
#include "exec/gen-icount.h"
void alpha_translate_init(void)
@@ -122,6 +129,12 @@ void alpha_translate_init(void)
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30"
};
+#ifndef CONFIG_USER_ONLY
+ static const char shadow_names[8][8] = {
+ "pal_t7", "pal_s0", "pal_s1", "pal_s2",
+ "pal_s3", "pal_s4", "pal_s5", "pal_t11"
+ };
+#endif
static bool done_init = 0;
int i;
@@ -134,9 +147,9 @@ void alpha_translate_init(void)
cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
for (i = 0; i < 31; i++) {
- cpu_ir[i] = tcg_global_mem_new_i64(TCG_AREG0,
- offsetof(CPUAlphaState, ir[i]),
- greg_names[i]);
+ cpu_std_ir[i] = tcg_global_mem_new_i64(TCG_AREG0,
+ offsetof(CPUAlphaState, ir[i]),
+ greg_names[i]);
}
for (i = 0; i < 31; i++) {
@@ -145,6 +158,17 @@ void alpha_translate_init(void)
freg_names[i]);
}
+#ifndef CONFIG_USER_ONLY
+ memcpy(cpu_pal_ir, cpu_std_ir, sizeof(cpu_pal_ir));
+ for (i = 0; i < 8; i++) {
+ int r = (i == 7 ? 25 : i + 8);
+ cpu_pal_ir[r] = tcg_global_mem_new_i64(TCG_AREG0,
+ offsetof(CPUAlphaState,
+ shadow[i]),
+ shadow_names[i]);
+ }
+#endif
+
for (i = 0; i < ARRAY_SIZE(vars); ++i) {
const GlobalVar *v = &vars[i];
*v->var = tcg_global_mem_new_i64(TCG_AREG0, v->ofs, v->name);
@@ -170,7 +194,7 @@ static TCGv dest_sink(DisasContext *ctx)
static TCGv load_gpr(DisasContext *ctx, unsigned reg)
{
if (likely(reg < 31)) {
- return cpu_ir[reg];
+ return ctx->ir[reg];
} else {
return load_zero(ctx);
}
@@ -183,7 +207,7 @@ static TCGv load_gpr_lit(DisasContext *ctx, unsigned reg,
ctx->lit = tcg_const_i64(lit);
return ctx->lit;
} else if (likely(reg < 31)) {
- return cpu_ir[reg];
+ return ctx->ir[reg];
} else {
return load_zero(ctx);
}
@@ -192,7 +216,7 @@ static TCGv load_gpr_lit(DisasContext *ctx, unsigned reg,
static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
{
if (likely(reg < 31)) {
- return cpu_ir[reg];
+ return ctx->ir[reg];
} else {
return dest_sink(ctx);
}
@@ -304,7 +328,7 @@ static inline void gen_load_mem(DisasContext *ctx,
addr = tmp;
}
- va = (fp ? cpu_fir[ra] : cpu_ir[ra]);
+ va = (fp ? cpu_fir[ra] : ctx->ir[ra]);
tcg_gen_qemu_load(va, addr, ctx->mem_idx);
tcg_temp_free(tmp);
@@ -399,13 +423,13 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
tcg_gen_qemu_ld_i64(val, addr, ctx->mem_idx, quad ? MO_LEQ : MO_LESL);
tcg_gen_brcond_i64(TCG_COND_NE, val, cpu_lock_value, lab_fail);
- tcg_gen_qemu_st_i64(cpu_ir[ra], addr, ctx->mem_idx,
+ tcg_gen_qemu_st_i64(ctx->ir[ra], addr, ctx->mem_idx,
quad ? MO_LEQ : MO_LEUL);
- tcg_gen_movi_i64(cpu_ir[ra], 1);
+ tcg_gen_movi_i64(ctx->ir[ra], 1);
tcg_gen_br(lab_done);
gen_set_label(lab_fail);
- tcg_gen_movi_i64(cpu_ir[ra], 0);
+ tcg_gen_movi_i64(ctx->ir[ra], 0);
gen_set_label(lab_done);
tcg_gen_movi_i64(cpu_lock_addr, -1);
@@ -444,7 +468,7 @@ static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
uint64_t dest = ctx->pc + (disp << 2);
if (ra != 31) {
- tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
+ tcg_gen_movi_i64(ctx->ir[ra], ctx->pc);
}
/* Notice branch-to-next; used to initialize RA with the PC. */
@@ -1059,12 +1083,13 @@ static void gen_msk_l(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit,
}
}
-static void gen_rx(int ra, int set)
+static void gen_rx(DisasContext *ctx, int ra, int set)
{
TCGv_i32 tmp;
if (ra != 31) {
- tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, offsetof(CPUAlphaState, intr_flag));
+ tcg_gen_ld8u_i64(ctx->ir[ra], cpu_env,
+ offsetof(CPUAlphaState, intr_flag));
}
tmp = tcg_const_i32(set);
@@ -1086,12 +1111,12 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
break;
case 0x9E:
/* RDUNIQUE */
- tcg_gen_ld_i64(cpu_ir[IR_V0], cpu_env,
+ tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env,
offsetof(CPUAlphaState, unique));
break;
case 0x9F:
/* WRUNIQUE */
- tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env,
+ tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env,
offsetof(CPUAlphaState, unique));
break;
default:
@@ -1115,17 +1140,17 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
break;
case 0x2D:
/* WRVPTPTR */
- tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env,
+ tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env,
offsetof(CPUAlphaState, vptptr));
break;
case 0x31:
/* WRVAL */
- tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env,
+ tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env,
offsetof(CPUAlphaState, sysval));
break;
case 0x32:
/* RDVAL */
- tcg_gen_ld_i64(cpu_ir[IR_V0], cpu_env,
+ tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env,
offsetof(CPUAlphaState, sysval));
break;
@@ -1135,12 +1160,12 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
/* Note that we already know we're in kernel mode, so we know
that PS only contains the 3 IPL bits. */
- tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env,
+ tcg_gen_ld8u_i64(ctx->ir[IR_V0], cpu_env,
offsetof(CPUAlphaState, ps));
/* But make sure and store only the 3 IPL bits from the user. */
tmp = tcg_temp_new();
- tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], PS_INT_MASK);
+ tcg_gen_andi_i64(tmp, ctx->ir[IR_A0], PS_INT_MASK);
tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, ps));
tcg_temp_free(tmp);
break;
@@ -1148,22 +1173,22 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
case 0x36:
/* RDPS */
- tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env,
+ tcg_gen_ld8u_i64(ctx->ir[IR_V0], cpu_env,
offsetof(CPUAlphaState, ps));
break;
case 0x38:
/* WRUSP */
- tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env,
+ tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env,
offsetof(CPUAlphaState, usp));
break;
case 0x3A:
/* RDUSP */
- tcg_gen_ld_i64(cpu_ir[IR_V0], cpu_env,
+ tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env,
offsetof(CPUAlphaState, usp));
break;
case 0x3C:
/* WHAMI */
- tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env,
+ tcg_gen_ld32s_i64(ctx->ir[IR_V0], cpu_env,
-offsetof(AlphaCPU, env) + offsetof(CPUState, cpu_index));
break;
@@ -1228,8 +1253,6 @@ static int cpu_pr_data(int pr)
case 11: return offsetof(CPUAlphaState, sysval);
case 12: return offsetof(CPUAlphaState, usp);
- case 32 ... 39:
- return offsetof(CPUAlphaState, shadow[pr - 32]);
case 40 ... 63:
return offsetof(CPUAlphaState, scratch[pr - 40]);
@@ -1241,36 +1264,48 @@ static int cpu_pr_data(int pr)
static ExitStatus gen_mfpr(DisasContext *ctx, TCGv va, int regno)
{
- int data = cpu_pr_data(regno);
-
- /* Special help for VMTIME and WALLTIME. */
- if (regno == 250 || regno == 249) {
- void (*helper)(TCGv) = gen_helper_get_walltime;
- if (regno == 249) {
- helper = gen_helper_get_vmtime;
- }
- if (ctx->tb->cflags & CF_USE_ICOUNT) {
+ void (*helper)(TCGv);
+ int data;
+
+ switch (regno) {
+ case 32 ... 39:
+ /* Accessing the "non-shadow" general registers. */
+ regno = regno == 39 ? 25 : regno - 32 + 8;
+ tcg_gen_mov_i64(va, cpu_std_ir[regno]);
+ break;
+
+ case 250: /* WALLTIME */
+ helper = gen_helper_get_walltime;
+ goto do_helper;
+ case 249: /* VMTIME */
+ helper = gen_helper_get_vmtime;
+ do_helper:
+ if (use_icount) {
gen_io_start();
helper(va);
gen_io_end();
return EXIT_PC_STALE;
} else {
helper(va);
- return NO_EXIT;
}
- }
+ break;
- /* The basic registers are data only, and unknown registers
- are read-zero, write-ignore. */
- if (data == 0) {
- tcg_gen_movi_i64(va, 0);
- } else if (data & PR_BYTE) {
- tcg_gen_ld8u_i64(va, cpu_env, data & ~PR_BYTE);
- } else if (data & PR_LONG) {
- tcg_gen_ld32s_i64(va, cpu_env, data & ~PR_LONG);
- } else {
- tcg_gen_ld_i64(va, cpu_env, data);
+ default:
+ /* The basic registers are data only, and unknown registers
+ are read-zero, write-ignore. */
+ data = cpu_pr_data(regno);
+ if (data == 0) {
+ tcg_gen_movi_i64(va, 0);
+ } else if (data & PR_BYTE) {
+ tcg_gen_ld8u_i64(va, cpu_env, data & ~PR_BYTE);
+ } else if (data & PR_LONG) {
+ tcg_gen_ld32s_i64(va, cpu_env, data & ~PR_LONG);
+ } else {
+ tcg_gen_ld_i64(va, cpu_env, data);
+ }
+ break;
}
+
return NO_EXIT;
}
@@ -1316,6 +1351,12 @@ static ExitStatus gen_mtpr(DisasContext *ctx, TCGv vb, int regno)
gen_helper_tb_flush(cpu_env);
return EXIT_PC_STALE;
+ case 32 ... 39:
+ /* Accessing the "non-shadow" general registers. */
+ regno = regno == 39 ? 25 : regno - 32 + 8;
+ tcg_gen_mov_i64(cpu_std_ir[regno], vb);
+ break;
+
default:
/* The basic registers are data only, and unknown registers
are read-zero, write-ignore. */
@@ -2295,14 +2336,14 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0xE000:
/* RC */
- gen_rx(ra, 0);
+ gen_rx(ctx, ra, 0);
break;
case 0xE800:
/* ECB */
break;
case 0xF000:
/* RS */
- gen_rx(ra, 1);
+ gen_rx(ctx, ra, 1);
break;
case 0xF800:
/* WH64 */
@@ -2334,7 +2375,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
vb = load_gpr(ctx, rb);
tcg_gen_andi_i64(cpu_pc, vb, ~3);
if (ra != 31) {
- tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
+ tcg_gen_movi_i64(ctx->ir[ra], ctx->pc);
}
ret = EXIT_PC_UPDATED;
break;
@@ -2374,10 +2415,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
goto invalid_opc;
break;
case 0x6:
- /* Incpu_ir[ra]id */
+ /* Invalid */
goto invalid_opc;
case 0x7:
- /* Incpu_ir[ra]id */
+ /* Invaliid */
goto invalid_opc;
case 0x8:
/* Longword virtual access (hw_ldl) */
@@ -2817,6 +2858,12 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu,
ctx.implver = env->implver;
ctx.singlestep_enabled = cs->singlestep_enabled;
+#ifdef CONFIG_USER_ONLY
+ ctx.ir = cpu_std_ir;
+#else
+ ctx.ir = (tb->flags & TB_FLAGS_PAL_MODE ? cpu_pal_ir : cpu_std_ir);
+#endif
+
/* ??? Every TB begins with unset rounding mode, to be initialized on
the first fp insn of the TB. Alternately we could define a proper
default for every TB (e.g. QUAL_RM_N or QUAL_RM_D) and make sure