mirror of https://github.com/xqemu/xqemu.git
Queued target/alpha patches
-----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJZsY0yAAoJEGTfOOivfiFfKnoIAIWriLnTyGe+8OgUBVULxqgT IN4onubiNG+nmMp8VQPvNDS3GauIOfy3NU317qTEhCXJsCOTilHcN9RaNaIVQbe4 /A9opoR0VeN9tgzwAiLEHPwVn5LaWqgYBLdeAw/FN0qcwG+fncqzQxoGPzHPFjkZ iNKbfLgeuzn98zEg6HEvLlm3pWGNhWtuPNuC/r/Whf3BcPPs0DdYHmtvnXp4kURc YY4yhBHj9iib0MGqELzq/oFYWtd08vezxD+5rse0QqETDpQW3Get2E8zLHKqZm0I E9ozcg2E/4t8B9FeJsqzZh9uchvwALR/nrqKn6MCjZCgM2QpebK8qrSnjzHZrQ0= =6Owf -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-axp-20170907' into staging Queued target/alpha patches # gpg: Signature made Thu 07 Sep 2017 19:17:22 BST # gpg: using RSA key 0x64DF38E8AF7E215F # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-axp-20170907: target/alpha: Switch to do_transaction_failed() hook target/alpha: Convert to TranslatorOps target/alpha: Convert to DisasContextBase target/alpha: Convert to DisasJumpType Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b393d2fb02
|
@ -297,7 +297,7 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
cc->handle_mmu_fault = alpha_cpu_handle_mmu_fault;
|
cc->handle_mmu_fault = alpha_cpu_handle_mmu_fault;
|
||||||
#else
|
#else
|
||||||
cc->do_unassigned_access = alpha_cpu_unassigned_access;
|
cc->do_transaction_failed = alpha_cpu_do_transaction_failed;
|
||||||
cc->do_unaligned_access = alpha_cpu_do_unaligned_access;
|
cc->do_unaligned_access = alpha_cpu_do_unaligned_access;
|
||||||
cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
|
||||||
dc->vmsd = &vmstate_alpha_cpu;
|
dc->vmsd = &vmstate_alpha_cpu;
|
||||||
|
|
|
@ -486,9 +486,11 @@ void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val);
|
||||||
uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg);
|
uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg);
|
||||||
void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val);
|
void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val);
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
QEMU_NORETURN void alpha_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
|
void alpha_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||||
bool is_write, bool is_exec,
|
vaddr addr, unsigned size,
|
||||||
int unused, unsigned size);
|
MMUAccessType access_type,
|
||||||
|
int mmu_idx, MemTxAttrs attrs,
|
||||||
|
MemTxResult response, uintptr_t retaddr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, target_ulong *pc,
|
static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, target_ulong *pc,
|
||||||
|
|
|
@ -163,6 +163,14 @@ static int get_physical_address(CPUAlphaState *env, target_ulong addr,
|
||||||
|
|
||||||
pt = env->ptbr;
|
pt = env->ptbr;
|
||||||
|
|
||||||
|
/* TODO: rather than using ldq_phys() to read the page table we should
|
||||||
|
* use address_space_ldq() so that we can handle the case when
|
||||||
|
* the page table read gives a bus fault, rather than ignoring it.
|
||||||
|
* For the existing code the zero data that ldq_phys will return for
|
||||||
|
* an access to invalid memory will result in our treating the page
|
||||||
|
* table as invalid, which may even be the right behaviour.
|
||||||
|
*/
|
||||||
|
|
||||||
/* L1 page table read. */
|
/* L1 page table read. */
|
||||||
index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
|
index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
|
||||||
L1pte = ldq_phys(cs->as, pt + index*8);
|
L1pte = ldq_phys(cs->as, pt + index*8);
|
||||||
|
|
|
@ -49,22 +49,23 @@ void alpha_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||||
cpu_loop_exit(cs);
|
cpu_loop_exit(cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void alpha_cpu_unassigned_access(CPUState *cs, hwaddr addr,
|
void alpha_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||||
bool is_write, bool is_exec, int unused,
|
vaddr addr, unsigned size,
|
||||||
unsigned size)
|
MMUAccessType access_type,
|
||||||
|
int mmu_idx, MemTxAttrs attrs,
|
||||||
|
MemTxResult response, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
AlphaCPU *cpu = ALPHA_CPU(cs);
|
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||||
CPUAlphaState *env = &cpu->env;
|
CPUAlphaState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (retaddr) {
|
||||||
|
cpu_restore_state(cs, retaddr);
|
||||||
|
}
|
||||||
|
|
||||||
env->trap_arg0 = addr;
|
env->trap_arg0 = addr;
|
||||||
env->trap_arg1 = is_write ? 1 : 0;
|
env->trap_arg1 = access_type == MMU_DATA_STORE ? 1 : 0;
|
||||||
cs->exception_index = EXCP_MCHK;
|
cs->exception_index = EXCP_MCHK;
|
||||||
env->error_code = 0;
|
env->error_code = 0;
|
||||||
|
|
||||||
/* ??? We should cpu_restore_state to the faulting insn, but this hook
|
|
||||||
does not have access to the retaddr value from the original helper.
|
|
||||||
It's all moot until the QEMU PALcode grows an MCHK handler. */
|
|
||||||
|
|
||||||
cpu_loop_exit(cs);
|
cpu_loop_exit(cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,10 @@
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "tcg-op.h"
|
#include "tcg-op.h"
|
||||||
#include "exec/cpu_ldst.h"
|
#include "exec/cpu_ldst.h"
|
||||||
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/helper-gen.h"
|
#include "exec/helper-gen.h"
|
||||||
|
|
||||||
#include "trace-tcg.h"
|
#include "trace-tcg.h"
|
||||||
|
#include "exec/translator.h"
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,8 +43,8 @@
|
||||||
|
|
||||||
typedef struct DisasContext DisasContext;
|
typedef struct DisasContext DisasContext;
|
||||||
struct DisasContext {
|
struct DisasContext {
|
||||||
struct TranslationBlock *tb;
|
DisasContextBase base;
|
||||||
uint64_t pc;
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
uint64_t palbr;
|
uint64_t palbr;
|
||||||
#endif
|
#endif
|
||||||
|
@ -69,36 +68,14 @@ struct DisasContext {
|
||||||
TCGv sink;
|
TCGv sink;
|
||||||
/* Temporary for immediate constants. */
|
/* Temporary for immediate constants. */
|
||||||
TCGv lit;
|
TCGv lit;
|
||||||
|
|
||||||
bool singlestep_enabled;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Return values from translate_one, indicating the state of the TB.
|
/* Target-specific return values from translate_one, indicating the
|
||||||
Note that zero indicates that we are not exiting the TB. */
|
state of the TB. Note that DISAS_NEXT indicates that we are not
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
NO_EXIT,
|
|
||||||
|
|
||||||
/* We have emitted one or more goto_tb. No fixup required. */
|
|
||||||
EXIT_GOTO_TB,
|
|
||||||
|
|
||||||
/* We are not using a goto_tb (for whatever reason), but have updated
|
|
||||||
the PC (for whatever reason), so there's no need to do it again on
|
|
||||||
exiting the TB. */
|
exiting the TB. */
|
||||||
EXIT_PC_UPDATED,
|
#define DISAS_PC_UPDATED_NOCHAIN DISAS_TARGET_0
|
||||||
EXIT_PC_UPDATED_NOCHAIN,
|
#define DISAS_PC_UPDATED DISAS_TARGET_1
|
||||||
|
#define DISAS_PC_STALE DISAS_TARGET_2
|
||||||
/* We are exiting the TB, but have neither emitted a goto_tb, nor
|
|
||||||
updated the PC for the next instruction to be executed. */
|
|
||||||
EXIT_PC_STALE,
|
|
||||||
|
|
||||||
/* We are exiting the TB due to page crossing or space constraints. */
|
|
||||||
EXIT_FALLTHRU,
|
|
||||||
|
|
||||||
/* We are ending the TB with a noreturn function call, e.g. longjmp.
|
|
||||||
No following code will be executed. */
|
|
||||||
EXIT_NORETURN,
|
|
||||||
} ExitStatus;
|
|
||||||
|
|
||||||
/* global register indexes */
|
/* global register indexes */
|
||||||
static TCGv_env cpu_env;
|
static TCGv_env cpu_env;
|
||||||
|
@ -301,14 +278,14 @@ static void gen_excp_1(int exception, int error_code)
|
||||||
tcg_temp_free_i32(tmp1);
|
tcg_temp_free_i32(tmp1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code)
|
static DisasJumpType gen_excp(DisasContext *ctx, int exception, int error_code)
|
||||||
{
|
{
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc);
|
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
|
||||||
gen_excp_1(exception, error_code);
|
gen_excp_1(exception, error_code);
|
||||||
return EXIT_NORETURN;
|
return DISAS_NORETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ExitStatus gen_invalid(DisasContext *ctx)
|
static inline DisasJumpType gen_invalid(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
return gen_excp(ctx, EXCP_OPCDEC, 0);
|
return gen_excp(ctx, EXCP_OPCDEC, 0);
|
||||||
}
|
}
|
||||||
|
@ -434,7 +411,7 @@ static inline void gen_store_mem(DisasContext *ctx,
|
||||||
tcg_temp_free(tmp);
|
tcg_temp_free(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
|
static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb,
|
||||||
int32_t disp16, int mem_idx,
|
int32_t disp16, int mem_idx,
|
||||||
TCGMemOp op)
|
TCGMemOp op)
|
||||||
{
|
{
|
||||||
|
@ -468,7 +445,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
|
||||||
|
|
||||||
gen_set_label(lab_done);
|
gen_set_label(lab_done);
|
||||||
tcg_gen_movi_i64(cpu_lock_addr, -1);
|
tcg_gen_movi_i64(cpu_lock_addr, -1);
|
||||||
return NO_EXIT;
|
return DISAS_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool in_superpage(DisasContext *ctx, int64_t addr)
|
static bool in_superpage(DisasContext *ctx, int64_t addr)
|
||||||
|
@ -484,8 +461,8 @@ static bool in_superpage(DisasContext *ctx, int64_t addr)
|
||||||
|
|
||||||
static bool use_exit_tb(DisasContext *ctx)
|
static bool use_exit_tb(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
return ((ctx->tb->cflags & CF_LAST_IO)
|
return ((ctx->base.tb->cflags & CF_LAST_IO)
|
||||||
|| ctx->singlestep_enabled
|
|| ctx->base.singlestep_enabled
|
||||||
|| singlestep);
|
|| singlestep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,18 +478,18 @@ static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/* Check for the dest on the same page as the start of the TB. */
|
/* Check for the dest on the same page as the start of the TB. */
|
||||||
return ((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0;
|
return ((ctx->base.tb->pc ^ dest) & TARGET_PAGE_MASK) == 0;
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
|
static DisasJumpType gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
|
||||||
{
|
{
|
||||||
uint64_t dest = ctx->pc + (disp << 2);
|
uint64_t dest = ctx->base.pc_next + (disp << 2);
|
||||||
|
|
||||||
if (ra != 31) {
|
if (ra != 31) {
|
||||||
tcg_gen_movi_i64(ctx->ir[ra], ctx->pc);
|
tcg_gen_movi_i64(ctx->ir[ra], ctx->base.pc_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notice branch-to-next; used to initialize RA with the PC. */
|
/* Notice branch-to-next; used to initialize RA with the PC. */
|
||||||
|
@ -521,53 +498,53 @@ static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
|
||||||
} else if (use_goto_tb(ctx, dest)) {
|
} else if (use_goto_tb(ctx, dest)) {
|
||||||
tcg_gen_goto_tb(0);
|
tcg_gen_goto_tb(0);
|
||||||
tcg_gen_movi_i64(cpu_pc, dest);
|
tcg_gen_movi_i64(cpu_pc, dest);
|
||||||
tcg_gen_exit_tb((uintptr_t)ctx->tb);
|
tcg_gen_exit_tb((uintptr_t)ctx->base.tb);
|
||||||
return EXIT_GOTO_TB;
|
return DISAS_NORETURN;
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_movi_i64(cpu_pc, dest);
|
tcg_gen_movi_i64(cpu_pc, dest);
|
||||||
return EXIT_PC_UPDATED;
|
return DISAS_PC_UPDATED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitStatus gen_bcond_internal(DisasContext *ctx, TCGCond cond,
|
static DisasJumpType gen_bcond_internal(DisasContext *ctx, TCGCond cond,
|
||||||
TCGv cmp, int32_t disp)
|
TCGv cmp, int32_t disp)
|
||||||
{
|
{
|
||||||
uint64_t dest = ctx->pc + (disp << 2);
|
uint64_t dest = ctx->base.pc_next + (disp << 2);
|
||||||
TCGLabel *lab_true = gen_new_label();
|
TCGLabel *lab_true = gen_new_label();
|
||||||
|
|
||||||
if (use_goto_tb(ctx, dest)) {
|
if (use_goto_tb(ctx, dest)) {
|
||||||
tcg_gen_brcondi_i64(cond, cmp, 0, lab_true);
|
tcg_gen_brcondi_i64(cond, cmp, 0, lab_true);
|
||||||
|
|
||||||
tcg_gen_goto_tb(0);
|
tcg_gen_goto_tb(0);
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc);
|
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
|
||||||
tcg_gen_exit_tb((uintptr_t)ctx->tb);
|
tcg_gen_exit_tb((uintptr_t)ctx->base.tb);
|
||||||
|
|
||||||
gen_set_label(lab_true);
|
gen_set_label(lab_true);
|
||||||
tcg_gen_goto_tb(1);
|
tcg_gen_goto_tb(1);
|
||||||
tcg_gen_movi_i64(cpu_pc, dest);
|
tcg_gen_movi_i64(cpu_pc, dest);
|
||||||
tcg_gen_exit_tb((uintptr_t)ctx->tb + 1);
|
tcg_gen_exit_tb((uintptr_t)ctx->base.tb + 1);
|
||||||
|
|
||||||
return EXIT_GOTO_TB;
|
return DISAS_NORETURN;
|
||||||
} else {
|
} else {
|
||||||
TCGv_i64 z = tcg_const_i64(0);
|
TCGv_i64 z = tcg_const_i64(0);
|
||||||
TCGv_i64 d = tcg_const_i64(dest);
|
TCGv_i64 d = tcg_const_i64(dest);
|
||||||
TCGv_i64 p = tcg_const_i64(ctx->pc);
|
TCGv_i64 p = tcg_const_i64(ctx->base.pc_next);
|
||||||
|
|
||||||
tcg_gen_movcond_i64(cond, cpu_pc, cmp, z, d, p);
|
tcg_gen_movcond_i64(cond, cpu_pc, cmp, z, d, p);
|
||||||
|
|
||||||
tcg_temp_free_i64(z);
|
tcg_temp_free_i64(z);
|
||||||
tcg_temp_free_i64(d);
|
tcg_temp_free_i64(d);
|
||||||
tcg_temp_free_i64(p);
|
tcg_temp_free_i64(p);
|
||||||
return EXIT_PC_UPDATED;
|
return DISAS_PC_UPDATED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitStatus gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
|
static DisasJumpType gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
|
||||||
int32_t disp, int mask)
|
int32_t disp, int mask)
|
||||||
{
|
{
|
||||||
if (mask) {
|
if (mask) {
|
||||||
TCGv tmp = tcg_temp_new();
|
TCGv tmp = tcg_temp_new();
|
||||||
ExitStatus ret;
|
DisasJumpType ret;
|
||||||
|
|
||||||
tcg_gen_andi_i64(tmp, load_gpr(ctx, ra), 1);
|
tcg_gen_andi_i64(tmp, load_gpr(ctx, ra), 1);
|
||||||
ret = gen_bcond_internal(ctx, cond, tmp, disp);
|
ret = gen_bcond_internal(ctx, cond, tmp, disp);
|
||||||
|
@ -609,11 +586,11 @@ static void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitStatus gen_fbcond(DisasContext *ctx, TCGCond cond, int ra,
|
static DisasJumpType gen_fbcond(DisasContext *ctx, TCGCond cond, int ra,
|
||||||
int32_t disp)
|
int32_t disp)
|
||||||
{
|
{
|
||||||
TCGv cmp_tmp = tcg_temp_new();
|
TCGv cmp_tmp = tcg_temp_new();
|
||||||
ExitStatus ret;
|
DisasJumpType ret;
|
||||||
|
|
||||||
gen_fold_mzero(cond, cmp_tmp, load_fpr(ctx, ra));
|
gen_fold_mzero(cond, cmp_tmp, load_fpr(ctx, ra));
|
||||||
ret = gen_bcond_internal(ctx, cond, cmp_tmp, disp);
|
ret = gen_bcond_internal(ctx, cond, cmp_tmp, disp);
|
||||||
|
@ -1159,7 +1136,7 @@ static void gen_rx(DisasContext *ctx, int ra, int set)
|
||||||
tcg_temp_free(tmp);
|
tcg_temp_free(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
|
static DisasJumpType gen_call_pal(DisasContext *ctx, int palcode)
|
||||||
{
|
{
|
||||||
/* We're emulating OSF/1 PALcode. Many of these are trivial access
|
/* We're emulating OSF/1 PALcode. Many of these are trivial access
|
||||||
to internal cpu registers. */
|
to internal cpu registers. */
|
||||||
|
@ -1185,7 +1162,7 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
|
||||||
palcode &= 0xbf;
|
palcode &= 0xbf;
|
||||||
goto do_call_pal;
|
goto do_call_pal;
|
||||||
}
|
}
|
||||||
return NO_EXIT;
|
return DISAS_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
@ -1231,8 +1208,8 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow interrupts to be recognized right away. */
|
/* Allow interrupts to be recognized right away. */
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc);
|
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
|
||||||
return EXIT_PC_UPDATED_NOCHAIN;
|
return DISAS_PC_UPDATED_NOCHAIN;
|
||||||
|
|
||||||
case 0x36:
|
case 0x36:
|
||||||
/* RDPS */
|
/* RDPS */
|
||||||
|
@ -1270,7 +1247,7 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
|
||||||
palcode &= 0x3f;
|
palcode &= 0x3f;
|
||||||
goto do_call_pal;
|
goto do_call_pal;
|
||||||
}
|
}
|
||||||
return NO_EXIT;
|
return DISAS_NEXT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return gen_invalid(ctx);
|
return gen_invalid(ctx);
|
||||||
|
@ -1281,7 +1258,7 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
TCGv tmp = tcg_temp_new();
|
TCGv tmp = tcg_temp_new();
|
||||||
uint64_t exc_addr = ctx->pc;
|
uint64_t exc_addr = ctx->base.pc_next;
|
||||||
uint64_t entry = ctx->palbr;
|
uint64_t entry = ctx->palbr;
|
||||||
|
|
||||||
if (ctx->tbflags & ENV_FLAG_PAL_MODE) {
|
if (ctx->tbflags & ENV_FLAG_PAL_MODE) {
|
||||||
|
@ -1306,11 +1283,11 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
|
||||||
if (!use_exit_tb(ctx)) {
|
if (!use_exit_tb(ctx)) {
|
||||||
tcg_gen_goto_tb(0);
|
tcg_gen_goto_tb(0);
|
||||||
tcg_gen_movi_i64(cpu_pc, entry);
|
tcg_gen_movi_i64(cpu_pc, entry);
|
||||||
tcg_gen_exit_tb((uintptr_t)ctx->tb);
|
tcg_gen_exit_tb((uintptr_t)ctx->base.tb);
|
||||||
return EXIT_GOTO_TB;
|
return DISAS_NORETURN;
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_movi_i64(cpu_pc, entry);
|
tcg_gen_movi_i64(cpu_pc, entry);
|
||||||
return EXIT_PC_UPDATED;
|
return DISAS_PC_UPDATED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1344,7 +1321,7 @@ static int cpu_pr_data(int pr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitStatus gen_mfpr(DisasContext *ctx, TCGv va, int regno)
|
static DisasJumpType gen_mfpr(DisasContext *ctx, TCGv va, int regno)
|
||||||
{
|
{
|
||||||
void (*helper)(TCGv);
|
void (*helper)(TCGv);
|
||||||
int data;
|
int data;
|
||||||
|
@ -1366,7 +1343,7 @@ static ExitStatus gen_mfpr(DisasContext *ctx, TCGv va, int regno)
|
||||||
gen_io_start();
|
gen_io_start();
|
||||||
helper(va);
|
helper(va);
|
||||||
gen_io_end();
|
gen_io_end();
|
||||||
return EXIT_PC_STALE;
|
return DISAS_PC_STALE;
|
||||||
} else {
|
} else {
|
||||||
helper(va);
|
helper(va);
|
||||||
}
|
}
|
||||||
|
@ -1393,10 +1370,10 @@ static ExitStatus gen_mfpr(DisasContext *ctx, TCGv va, int regno)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NO_EXIT;
|
return DISAS_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitStatus gen_mtpr(DisasContext *ctx, TCGv vb, int regno)
|
static DisasJumpType gen_mtpr(DisasContext *ctx, TCGv vb, int regno)
|
||||||
{
|
{
|
||||||
int data;
|
int data;
|
||||||
|
|
||||||
|
@ -1424,7 +1401,7 @@ static ExitStatus gen_mtpr(DisasContext *ctx, TCGv vb, int regno)
|
||||||
case 252:
|
case 252:
|
||||||
/* HALT */
|
/* HALT */
|
||||||
gen_helper_halt(vb);
|
gen_helper_halt(vb);
|
||||||
return EXIT_PC_STALE;
|
return DISAS_PC_STALE;
|
||||||
|
|
||||||
case 251:
|
case 251:
|
||||||
/* ALARM */
|
/* ALARM */
|
||||||
|
@ -1438,7 +1415,7 @@ static ExitStatus gen_mtpr(DisasContext *ctx, TCGv vb, int regno)
|
||||||
that ended with a CALL_PAL. Since the base register usually only
|
that ended with a CALL_PAL. Since the base register usually only
|
||||||
changes during boot, flushing everything works well. */
|
changes during boot, flushing everything works well. */
|
||||||
gen_helper_tb_flush(cpu_env);
|
gen_helper_tb_flush(cpu_env);
|
||||||
return EXIT_PC_STALE;
|
return DISAS_PC_STALE;
|
||||||
|
|
||||||
case 32 ... 39:
|
case 32 ... 39:
|
||||||
/* Accessing the "non-shadow" general registers. */
|
/* Accessing the "non-shadow" general registers. */
|
||||||
|
@ -1467,7 +1444,7 @@ static ExitStatus gen_mtpr(DisasContext *ctx, TCGv vb, int regno)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NO_EXIT;
|
return DISAS_NEXT;
|
||||||
}
|
}
|
||||||
#endif /* !USER_ONLY*/
|
#endif /* !USER_ONLY*/
|
||||||
|
|
||||||
|
@ -1499,7 +1476,7 @@ static ExitStatus gen_mtpr(DisasContext *ctx, TCGv vb, int regno)
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
{
|
{
|
||||||
int32_t disp21, disp16, disp12 __attribute__((unused));
|
int32_t disp21, disp16, disp12 __attribute__((unused));
|
||||||
uint16_t fn11;
|
uint16_t fn11;
|
||||||
|
@ -1507,7 +1484,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
bool islit, real_islit;
|
bool islit, real_islit;
|
||||||
TCGv va, vb, vc, tmp, tmp2;
|
TCGv va, vb, vc, tmp, tmp2;
|
||||||
TCGv_i32 t32;
|
TCGv_i32 t32;
|
||||||
ExitStatus ret;
|
DisasJumpType ret;
|
||||||
|
|
||||||
/* Decode all instruction fields */
|
/* Decode all instruction fields */
|
||||||
opc = extract32(insn, 26, 6);
|
opc = extract32(insn, 26, 6);
|
||||||
|
@ -1530,7 +1507,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
lit = 0;
|
lit = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = NO_EXIT;
|
ret = DISAS_NEXT;
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
/* CALL_PAL */
|
/* CALL_PAL */
|
||||||
|
@ -2428,11 +2405,11 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
case 0xC000:
|
case 0xC000:
|
||||||
/* RPCC */
|
/* RPCC */
|
||||||
va = dest_gpr(ctx, ra);
|
va = dest_gpr(ctx, ra);
|
||||||
if (ctx->tb->cflags & CF_USE_ICOUNT) {
|
if (ctx->base.tb->cflags & CF_USE_ICOUNT) {
|
||||||
gen_io_start();
|
gen_io_start();
|
||||||
gen_helper_load_pcc(va, cpu_env);
|
gen_helper_load_pcc(va, cpu_env);
|
||||||
gen_io_end();
|
gen_io_end();
|
||||||
ret = EXIT_PC_STALE;
|
ret = DISAS_PC_STALE;
|
||||||
} else {
|
} else {
|
||||||
gen_helper_load_pcc(va, cpu_env);
|
gen_helper_load_pcc(va, cpu_env);
|
||||||
}
|
}
|
||||||
|
@ -2478,9 +2455,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
vb = load_gpr(ctx, rb);
|
vb = load_gpr(ctx, rb);
|
||||||
tcg_gen_andi_i64(cpu_pc, vb, ~3);
|
tcg_gen_andi_i64(cpu_pc, vb, ~3);
|
||||||
if (ra != 31) {
|
if (ra != 31) {
|
||||||
tcg_gen_movi_i64(ctx->ir[ra], ctx->pc);
|
tcg_gen_movi_i64(ctx->ir[ra], ctx->base.pc_next);
|
||||||
}
|
}
|
||||||
ret = EXIT_PC_UPDATED;
|
ret = DISAS_PC_UPDATED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1B:
|
case 0x1B:
|
||||||
|
@ -2738,7 +2715,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
tcg_temp_free(tmp);
|
tcg_temp_free(tmp);
|
||||||
tcg_gen_andi_i64(cpu_pc, vb, ~3);
|
tcg_gen_andi_i64(cpu_pc, vb, ~3);
|
||||||
/* Allow interrupts to be recognized right away. */
|
/* Allow interrupts to be recognized right away. */
|
||||||
ret = EXIT_PC_UPDATED_NOCHAIN;
|
ret = DISAS_PC_UPDATED_NOCHAIN;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
goto invalid_opc;
|
goto invalid_opc;
|
||||||
|
@ -2952,32 +2929,23 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
static int alpha_tr_init_disas_context(DisasContextBase *dcbase,
|
||||||
|
CPUState *cpu, int max_insns)
|
||||||
{
|
{
|
||||||
CPUAlphaState *env = cs->env_ptr;
|
DisasContext *ctx = container_of(dcbase, DisasContext, base);
|
||||||
DisasContext ctx, *ctxp = &ctx;
|
CPUAlphaState *env = cpu->env_ptr;
|
||||||
target_ulong pc_start;
|
int64_t bound, mask;
|
||||||
target_ulong pc_mask;
|
|
||||||
uint32_t insn;
|
|
||||||
ExitStatus ret;
|
|
||||||
int num_insns;
|
|
||||||
int max_insns;
|
|
||||||
|
|
||||||
pc_start = tb->pc;
|
ctx->tbflags = ctx->base.tb->flags;
|
||||||
|
ctx->mem_idx = cpu_mmu_index(env, false);
|
||||||
ctx.tb = tb;
|
ctx->implver = env->implver;
|
||||||
ctx.pc = pc_start;
|
ctx->amask = env->amask;
|
||||||
ctx.tbflags = tb->flags;
|
|
||||||
ctx.mem_idx = cpu_mmu_index(env, false);
|
|
||||||
ctx.implver = env->implver;
|
|
||||||
ctx.amask = env->amask;
|
|
||||||
ctx.singlestep_enabled = cs->singlestep_enabled;
|
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
ctx.ir = cpu_std_ir;
|
ctx->ir = cpu_std_ir;
|
||||||
#else
|
#else
|
||||||
ctx.palbr = env->palbr;
|
ctx->palbr = env->palbr;
|
||||||
ctx.ir = (ctx.tbflags & ENV_FLAG_PAL_MODE ? cpu_pal_ir : cpu_std_ir);
|
ctx->ir = (ctx->tbflags & ENV_FLAG_PAL_MODE ? cpu_pal_ir : cpu_std_ir);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ??? Every TB begins with unset rounding mode, to be initialized on
|
/* ??? Every TB begins with unset rounding mode, to be initialized on
|
||||||
|
@ -2986,96 +2954,87 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||||
to reset the FP_STATUS to that default at the end of any TB that
|
to reset the FP_STATUS to that default at the end of any TB that
|
||||||
changes the default. We could even (gasp) dynamiclly figure out
|
changes the default. We could even (gasp) dynamiclly figure out
|
||||||
what default would be most efficient given the running program. */
|
what default would be most efficient given the running program. */
|
||||||
ctx.tb_rm = -1;
|
ctx->tb_rm = -1;
|
||||||
/* Similarly for flush-to-zero. */
|
/* Similarly for flush-to-zero. */
|
||||||
ctx.tb_ftz = -1;
|
ctx->tb_ftz = -1;
|
||||||
|
|
||||||
TCGV_UNUSED_I64(ctx.zero);
|
TCGV_UNUSED_I64(ctx->zero);
|
||||||
TCGV_UNUSED_I64(ctx.sink);
|
TCGV_UNUSED_I64(ctx->sink);
|
||||||
TCGV_UNUSED_I64(ctx.lit);
|
TCGV_UNUSED_I64(ctx->lit);
|
||||||
|
|
||||||
num_insns = 0;
|
/* Bound the number of insns to execute to those left on the page. */
|
||||||
max_insns = tb->cflags & CF_COUNT_MASK;
|
if (in_superpage(ctx, ctx->base.pc_first)) {
|
||||||
if (max_insns == 0) {
|
mask = -1ULL << 41;
|
||||||
max_insns = CF_COUNT_MASK;
|
|
||||||
}
|
|
||||||
if (max_insns > TCG_MAX_INSNS) {
|
|
||||||
max_insns = TCG_MAX_INSNS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_superpage(&ctx, pc_start)) {
|
|
||||||
pc_mask = (1ULL << 41) - 1;
|
|
||||||
} else {
|
} else {
|
||||||
pc_mask = ~TARGET_PAGE_MASK;
|
mask = TARGET_PAGE_MASK;
|
||||||
}
|
}
|
||||||
|
bound = -(ctx->base.pc_first | mask) / 4;
|
||||||
|
|
||||||
gen_tb_start(tb);
|
return MIN(max_insns, bound);
|
||||||
tcg_clear_temp_count();
|
}
|
||||||
|
|
||||||
do {
|
static void alpha_tr_tb_start(DisasContextBase *db, CPUState *cpu)
|
||||||
tcg_gen_insn_start(ctx.pc);
|
{
|
||||||
num_insns++;
|
}
|
||||||
|
|
||||||
|
static void alpha_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||||
|
{
|
||||||
|
tcg_gen_insn_start(dcbase->pc_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool alpha_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
|
||||||
|
const CPUBreakpoint *bp)
|
||||||
|
{
|
||||||
|
DisasContext *ctx = container_of(dcbase, DisasContext, base);
|
||||||
|
|
||||||
|
ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG, 0);
|
||||||
|
|
||||||
if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
|
|
||||||
ret = gen_excp(&ctx, EXCP_DEBUG, 0);
|
|
||||||
/* The address covered by the breakpoint must be included in
|
/* The address covered by the breakpoint must be included in
|
||||||
[tb->pc, tb->pc + tb->size) in order to for it to be
|
[tb->pc, tb->pc + tb->size) in order to for it to be
|
||||||
properly cleared -- thus we increment the PC here so that
|
properly cleared -- thus we increment the PC here so that
|
||||||
the logic setting tb->size below does the right thing. */
|
the logic setting tb->size below does the right thing. */
|
||||||
ctx.pc += 4;
|
ctx->base.pc_next += 4;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alpha_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||||
|
{
|
||||||
|
DisasContext *ctx = container_of(dcbase, DisasContext, base);
|
||||||
|
CPUAlphaState *env = cpu->env_ptr;
|
||||||
|
uint32_t insn = cpu_ldl_code(env, ctx->base.pc_next);
|
||||||
|
|
||||||
|
ctx->base.pc_next += 4;
|
||||||
|
ctx->base.is_jmp = translate_one(ctx, insn);
|
||||||
|
|
||||||
|
free_context_temps(ctx);
|
||||||
|
translator_loop_temp_check(&ctx->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||||
|
{
|
||||||
|
DisasContext *ctx = container_of(dcbase, DisasContext, base);
|
||||||
|
|
||||||
|
switch (ctx->base.is_jmp) {
|
||||||
|
case DISAS_NORETURN:
|
||||||
break;
|
break;
|
||||||
}
|
case DISAS_TOO_MANY:
|
||||||
if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
|
if (use_goto_tb(ctx, ctx->base.pc_next)) {
|
||||||
gen_io_start();
|
|
||||||
}
|
|
||||||
insn = cpu_ldl_code(env, ctx.pc);
|
|
||||||
|
|
||||||
ctx.pc += 4;
|
|
||||||
ret = translate_one(ctxp, insn);
|
|
||||||
free_context_temps(ctxp);
|
|
||||||
|
|
||||||
if (tcg_check_temp_count()) {
|
|
||||||
qemu_log("TCG temporary leak before "TARGET_FMT_lx"\n", ctx.pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we reach a page boundary, are single stepping,
|
|
||||||
or exhaust instruction count, stop generation. */
|
|
||||||
if (ret == NO_EXIT
|
|
||||||
&& ((ctx.pc & pc_mask) == 0
|
|
||||||
|| tcg_op_buf_full()
|
|
||||||
|| num_insns >= max_insns
|
|
||||||
|| singlestep
|
|
||||||
|| ctx.singlestep_enabled)) {
|
|
||||||
ret = EXIT_FALLTHRU;
|
|
||||||
}
|
|
||||||
} while (ret == NO_EXIT);
|
|
||||||
|
|
||||||
if (tb->cflags & CF_LAST_IO) {
|
|
||||||
gen_io_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ret) {
|
|
||||||
case EXIT_GOTO_TB:
|
|
||||||
case EXIT_NORETURN:
|
|
||||||
break;
|
|
||||||
case EXIT_FALLTHRU:
|
|
||||||
if (use_goto_tb(&ctx, ctx.pc)) {
|
|
||||||
tcg_gen_goto_tb(0);
|
tcg_gen_goto_tb(0);
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx.pc);
|
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
|
||||||
tcg_gen_exit_tb((uintptr_t)ctx.tb);
|
tcg_gen_exit_tb((uintptr_t)ctx->base.tb);
|
||||||
}
|
}
|
||||||
/* FALLTHRU */
|
/* FALLTHRU */
|
||||||
case EXIT_PC_STALE:
|
case DISAS_PC_STALE:
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx.pc);
|
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
|
||||||
/* FALLTHRU */
|
/* FALLTHRU */
|
||||||
case EXIT_PC_UPDATED:
|
case DISAS_PC_UPDATED:
|
||||||
if (!use_exit_tb(&ctx)) {
|
if (!use_exit_tb(ctx)) {
|
||||||
tcg_gen_lookup_and_goto_ptr(cpu_pc);
|
tcg_gen_lookup_and_goto_ptr(cpu_pc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* FALLTHRU */
|
/* FALLTHRU */
|
||||||
case EXIT_PC_UPDATED_NOCHAIN:
|
case DISAS_PC_UPDATED_NOCHAIN:
|
||||||
if (ctx.singlestep_enabled) {
|
if (ctx->base.singlestep_enabled) {
|
||||||
gen_excp_1(EXCP_DEBUG, 0);
|
gen_excp_1(EXCP_DEBUG, 0);
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_exit_tb(0);
|
tcg_gen_exit_tb(0);
|
||||||
|
@ -3084,22 +3043,28 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gen_tb_end(tb, num_insns);
|
static void alpha_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
|
||||||
|
{
|
||||||
|
qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
|
||||||
|
log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
tb->size = ctx.pc - pc_start;
|
static const TranslatorOps alpha_tr_ops = {
|
||||||
tb->icount = num_insns;
|
.init_disas_context = alpha_tr_init_disas_context,
|
||||||
|
.tb_start = alpha_tr_tb_start,
|
||||||
|
.insn_start = alpha_tr_insn_start,
|
||||||
|
.breakpoint_check = alpha_tr_breakpoint_check,
|
||||||
|
.translate_insn = alpha_tr_translate_insn,
|
||||||
|
.tb_stop = alpha_tr_tb_stop,
|
||||||
|
.disas_log = alpha_tr_disas_log,
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef DEBUG_DISAS
|
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
|
||||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
{
|
||||||
&& qemu_log_in_addr_range(pc_start)) {
|
DisasContext dc;
|
||||||
qemu_log_lock();
|
translator_loop(&alpha_tr_ops, &dc.base, cpu, tb);
|
||||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
|
||||||
log_target_disas(cs, pc_start, ctx.pc - pc_start, 1);
|
|
||||||
qemu_log("\n");
|
|
||||||
qemu_log_unlock();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb,
|
void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb,
|
||||||
|
|
Loading…
Reference in New Issue