target/alpha: Implement CF_PCREL

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20240503072014.24751-10-philmd@linaro.org>
This commit is contained in:
Richard Henderson 2024-05-03 09:20:13 +02:00
parent b1a3eacf31
commit 23bb086350
2 changed files with 47 additions and 5 deletions

View File

@ -38,12 +38,27 @@ static vaddr alpha_cpu_get_pc(CPUState *cs)
return 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)
{
CPUAlphaState *env = cpu_env(cs);
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)
@ -78,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);
@ -190,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

@ -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;
@ -254,7 +257,12 @@ static void st_flag_byte(TCGv val, unsigned shift)
static void gen_pc_disp(DisasContext *ctx, TCGv dest, int32_t disp)
{
tcg_gen_movi_i64(dest, ctx->base.pc_next + 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)
@ -433,8 +441,14 @@ static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb,
static void gen_goto_tb(DisasContext *ctx, int idx, int32_t disp)
{
if (translator_use_goto_tb(&ctx->base, ctx->base.pc_next + disp)) {
tcg_gen_goto_tb(idx);
gen_pc_disp(ctx, cpu_pc, 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);
@ -2852,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;
@ -2887,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)