target/alpha: Implement CF_PCREL

-----BEGIN PGP SIGNATURE-----
 
 iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmY2VlYdHHJpY2hhcmQu
 aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/IxQf/UAxpxtc+glkuZ17C
 mUliqx/Vif31BuKw31GVSDENOMteD900fR8+nNGY401+2hdZxoNo2N70ZL1h9AgX
 xWVz1H33MwBXbW3lWhGSpikJ/Sd3K7dsqZpRWlr1uUEFmNXDSihKgY3JfhJ4mEsq
 8IIITyixSiiRyl1HBgfCUqLfHkWQamHz/Tbmku9wvOZ5fYkPHV1kCmlQ8X89iB9j
 yxHW9Zcm8cShD0w4pU1HZAttHhyNZrB70ebauksAWX6QIG6fdTv+qMz9XP4FofuT
 SwLuYja3ohoTijFkC7ctA0dbsF3xwCFKES6CdP8Ne5cKHSzsrejZhh8z/0uHi+D2
 jwxnMg==
 =oK6Y
 -----END PGP SIGNATURE-----

Merge tag 'pull-axp-20240504' of https://gitlab.com/rth7680/qemu into staging

target/alpha: Implement CF_PCREL

# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmY2VlYdHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/IxQf/UAxpxtc+glkuZ17C
# mUliqx/Vif31BuKw31GVSDENOMteD900fR8+nNGY401+2hdZxoNo2N70ZL1h9AgX
# xWVz1H33MwBXbW3lWhGSpikJ/Sd3K7dsqZpRWlr1uUEFmNXDSihKgY3JfhJ4mEsq
# 8IIITyixSiiRyl1HBgfCUqLfHkWQamHz/Tbmku9wvOZ5fYkPHV1kCmlQ8X89iB9j
# yxHW9Zcm8cShD0w4pU1HZAttHhyNZrB70ebauksAWX6QIG6fdTv+qMz9XP4FofuT
# SwLuYja3ohoTijFkC7ctA0dbsF3xwCFKES6CdP8Ne5cKHSzsrejZhh8z/0uHi+D2
# jwxnMg==
# =oK6Y
# -----END PGP SIGNATURE-----
# gpg: Signature made Sat 04 May 2024 08:37:58 AM PDT
# gpg:                using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg:                issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate]

* tag 'pull-axp-20240504' of https://gitlab.com/rth7680/qemu:
  target/alpha: Implement CF_PCREL
  target/alpha: Split out gen_pc_disp
  target/alpha: Split out gen_goto_tb
  target/alpha: Simplify gen_bcond_internal()
  target/alpha: Return DISAS_NORETURN once
  target/alpha: Inline DISAS_PC_UPDATED and return DISAS_NORETURN
  target/alpha: Use DISAS_NEXT definition instead of magic '0' value
  target/alpha: Hoist branch shift to initial decode
  target/alpha: Use cpu_env in preference to ALPHA_CPU

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-05-04 08:39:46 -07:00
commit 248f6f62df
3 changed files with 91 additions and 66 deletions

View File

@ -28,25 +28,37 @@
static void alpha_cpu_set_pc(CPUState *cs, vaddr value)
{
AlphaCPU *cpu = ALPHA_CPU(cs);
cpu->env.pc = value;
CPUAlphaState *env = cpu_env(cs);
env->pc = value;
}
static vaddr alpha_cpu_get_pc(CPUState *cs)
{
AlphaCPU *cpu = ALPHA_CPU(cs);
CPUAlphaState *env = cpu_env(cs);
return env->pc;
}
return cpu->env.pc;
static void alpha_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
{
/* The program counter is always up to date with CF_PCREL. */
if (!(tb_cflags(tb) & CF_PCREL)) {
CPUAlphaState *env = cpu_env(cs);
env->pc = tb->pc;
}
}
static void alpha_restore_state_to_opc(CPUState *cs,
const TranslationBlock *tb,
const uint64_t *data)
{
AlphaCPU *cpu = ALPHA_CPU(cs);
CPUAlphaState *env = cpu_env(cs);
cpu->env.pc = data[0];
if (tb_cflags(tb) & CF_PCREL) {
env->pc = (env->pc & TARGET_PAGE_MASK) | data[0];
} else {
env->pc = data[0];
}
}
static bool alpha_cpu_has_work(CPUState *cs)
@ -81,6 +93,11 @@ static void alpha_cpu_realizefn(DeviceState *dev, Error **errp)
AlphaCPUClass *acc = ALPHA_CPU_GET_CLASS(dev);
Error *local_err = NULL;
#ifndef CONFIG_USER_ONLY
/* Use pc-relative instructions in system-mode */
cs->tcg_cflags |= CF_PCREL;
#endif
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
@ -193,6 +210,7 @@ static const struct SysemuCPUOps alpha_sysemu_ops = {
static const TCGCPUOps alpha_tcg_ops = {
.initialize = alpha_translate_init,
.synchronize_from_tb = alpha_cpu_synchronize_from_tb,
.restore_state_to_opc = alpha_restore_state_to_opc,
#ifdef CONFIG_USER_ONLY

View File

@ -124,7 +124,7 @@ void alpha_cpu_record_sigsegv(CPUState *cs, vaddr address,
MMUAccessType access_type,
bool maperr, uintptr_t retaddr)
{
AlphaCPU *cpu = ALPHA_CPU(cs);
CPUAlphaState *env = cpu_env(cs);
target_ulong mmcsr, cause;
/* Assuming !maperr, infer the missing protection. */
@ -155,9 +155,9 @@ void alpha_cpu_record_sigsegv(CPUState *cs, vaddr address,
}
/* Record the arguments that PALcode would give to the kernel. */
cpu->env.trap_arg0 = address;
cpu->env.trap_arg1 = mmcsr;
cpu->env.trap_arg2 = cause;
env->trap_arg0 = address;
env->trap_arg1 = mmcsr;
env->trap_arg2 = cause;
}
#else
/* Returns the OSF/1 entMM failure indication, or -1 on success. */

View File

@ -54,6 +54,9 @@ struct DisasContext {
uint32_t tbflags;
int mem_idx;
/* True if generating pc-relative code. */
bool pcrel;
/* implver and amask values for this CPU. */
int implver;
int amask;
@ -252,6 +255,16 @@ static void st_flag_byte(TCGv val, unsigned shift)
tcg_gen_st8_i64(val, tcg_env, get_flag_ofs(shift));
}
static void gen_pc_disp(DisasContext *ctx, TCGv dest, int32_t disp)
{
uint64_t addr = ctx->base.pc_next + disp;
if (ctx->pcrel) {
tcg_gen_addi_i64(dest, cpu_pc, addr - ctx->base.pc_first);
} else {
tcg_gen_movi_i64(dest, addr);
}
}
static void gen_excp_1(int exception, int error_code)
{
TCGv_i32 tmp1, tmp2;
@ -263,7 +276,7 @@ static void gen_excp_1(int exception, int error_code)
static DisasJumpType gen_excp(DisasContext *ctx, int exception, int error_code)
{
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
gen_pc_disp(ctx, cpu_pc, 0);
gen_excp_1(exception, error_code);
return DISAS_NORETURN;
}
@ -425,60 +438,49 @@ static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb,
return DISAS_NEXT;
}
static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
static void gen_goto_tb(DisasContext *ctx, int idx, int32_t disp)
{
return translator_use_goto_tb(&ctx->base, dest);
if (translator_use_goto_tb(&ctx->base, ctx->base.pc_next + disp)) {
/* With PCREL, PC must always be up-to-date. */
if (ctx->pcrel) {
gen_pc_disp(ctx, cpu_pc, disp);
tcg_gen_goto_tb(idx);
} else {
tcg_gen_goto_tb(idx);
gen_pc_disp(ctx, cpu_pc, disp);
}
tcg_gen_exit_tb(ctx->base.tb, idx);
} else {
gen_pc_disp(ctx, cpu_pc, disp);
tcg_gen_lookup_and_goto_ptr();
}
}
static DisasJumpType gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
{
uint64_t dest = ctx->base.pc_next + (disp << 2);
if (ra != 31) {
tcg_gen_movi_i64(ctx->ir[ra], ctx->base.pc_next);
gen_pc_disp(ctx, ctx->ir[ra], 0);
}
/* Notice branch-to-next; used to initialize RA with the PC. */
if (disp == 0) {
return 0;
} else if (use_goto_tb(ctx, dest)) {
tcg_gen_goto_tb(0);
tcg_gen_movi_i64(cpu_pc, dest);
tcg_gen_exit_tb(ctx->base.tb, 0);
return DISAS_NORETURN;
} else {
tcg_gen_movi_i64(cpu_pc, dest);
return DISAS_PC_UPDATED;
return DISAS_NEXT;
}
gen_goto_tb(ctx, 0, disp);
return DISAS_NORETURN;
}
static DisasJumpType gen_bcond_internal(DisasContext *ctx, TCGCond cond,
TCGv cmp, uint64_t imm, int32_t disp)
{
uint64_t dest = ctx->base.pc_next + (disp << 2);
TCGLabel *lab_true = gen_new_label();
if (use_goto_tb(ctx, dest)) {
tcg_gen_brcondi_i64(cond, cmp, imm, lab_true);
tcg_gen_brcondi_i64(cond, cmp, imm, lab_true);
gen_goto_tb(ctx, 0, 0);
gen_set_label(lab_true);
gen_goto_tb(ctx, 1, disp);
tcg_gen_goto_tb(0);
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
tcg_gen_exit_tb(ctx->base.tb, 0);
gen_set_label(lab_true);
tcg_gen_goto_tb(1);
tcg_gen_movi_i64(cpu_pc, dest);
tcg_gen_exit_tb(ctx->base.tb, 1);
return DISAS_NORETURN;
} else {
TCGv_i64 i = tcg_constant_i64(imm);
TCGv_i64 d = tcg_constant_i64(dest);
TCGv_i64 p = tcg_constant_i64(ctx->base.pc_next);
tcg_gen_movcond_i64(cond, cpu_pc, cmp, i, d, p);
return DISAS_PC_UPDATED;
}
return DISAS_NORETURN;
}
static DisasJumpType gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
@ -1106,7 +1108,7 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode)
}
/* Allow interrupts to be recognized right away. */
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
gen_pc_disp(ctx, cpu_pc, 0);
return DISAS_PC_UPDATED_NOCHAIN;
case 0x36:
@ -1153,19 +1155,17 @@ static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode)
#else
{
TCGv tmp = tcg_temp_new();
uint64_t exc_addr = ctx->base.pc_next;
uint64_t entry = ctx->palbr;
uint64_t entry;
gen_pc_disp(ctx, tmp, 0);
if (ctx->tbflags & ENV_FLAG_PAL_MODE) {
exc_addr |= 1;
tcg_gen_ori_i64(tmp, tmp, 1);
} else {
tcg_gen_movi_i64(tmp, 1);
st_flag_byte(tmp, ENV_FLAG_PAL_SHIFT);
st_flag_byte(tcg_constant_i64(1), ENV_FLAG_PAL_SHIFT);
}
tcg_gen_movi_i64(tmp, exc_addr);
tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUAlphaState, exc_addr));
entry = ctx->palbr;
entry += (palcode & 0x80
? 0x2000 + (palcode - 0x80) * 64
: 0x1000 + palcode * 64);
@ -1382,7 +1382,7 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
real_islit = islit = extract32(insn, 12, 1);
lit = extract32(insn, 13, 8);
disp21 = sextract32(insn, 0, 21);
disp21 = sextract32(insn, 0, 21) * 4;
disp16 = sextract32(insn, 0, 16);
disp12 = sextract32(insn, 0, 12);
@ -2359,9 +2359,13 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
/* JMP, JSR, RET, JSR_COROUTINE. These only differ by the branch
prediction stack action, which of course we don't implement. */
vb = load_gpr(ctx, rb);
tcg_gen_andi_i64(cpu_pc, vb, ~3);
if (ra != 31) {
tcg_gen_movi_i64(ctx->ir[ra], ctx->base.pc_next);
tmp = tcg_temp_new();
tcg_gen_andi_i64(tmp, vb, ~3);
gen_pc_disp(ctx, ctx->ir[ra], 0);
tcg_gen_mov_i64(cpu_pc, tmp);
} else {
tcg_gen_andi_i64(cpu_pc, vb, ~3);
}
ret = DISAS_PC_UPDATED;
break;
@ -2862,6 +2866,7 @@ static void alpha_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
ctx->tbflags = ctx->base.tb->flags;
ctx->mem_idx = alpha_env_mmu_index(env);
ctx->pcrel = ctx->base.tb->cflags & CF_PCREL;
ctx->implver = env->implver;
ctx->amask = env->amask;
@ -2897,7 +2902,13 @@ static void alpha_tr_tb_start(DisasContextBase *db, CPUState *cpu)
static void alpha_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
{
tcg_gen_insn_start(dcbase->pc_next);
DisasContext *ctx = container_of(dcbase, DisasContext, base);
if (ctx->pcrel) {
tcg_gen_insn_start(dcbase->pc_next & ~TARGET_PAGE_MASK);
} else {
tcg_gen_insn_start(dcbase->pc_next);
}
}
static void alpha_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
@ -2920,14 +2931,10 @@ static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
case DISAS_NORETURN:
break;
case DISAS_TOO_MANY:
if (use_goto_tb(ctx, ctx->base.pc_next)) {
tcg_gen_goto_tb(0);
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
tcg_gen_exit_tb(ctx->base.tb, 0);
}
/* FALLTHRU */
gen_goto_tb(ctx, 0, 0);
break;
case DISAS_PC_STALE:
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
gen_pc_disp(ctx, cpu_pc, 0);
/* FALLTHRU */
case DISAS_PC_UPDATED:
tcg_gen_lookup_and_goto_ptr();