tcg generic translate loop v15

-----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJZsBwXAAoJEGTfOOivfiFfst4IAIkgld9yabywTZc5KUvJmMc/
 Zh8BoI+1L27NqcQiRAB2m82yFho8jKdk618dFp2KadXzhmKr6CDztsD6y0BPg7YW
 pBWakZ4Q/HpAIwkAKiKoXZ5+go13z3OSjYZxYCDZzokl0cgxfKshoN2RYVD0L1my
 SGPp2DuF2YgrNy0VHU7Ki+lW77f1wYPykDv6geb7NGI4ePUvSpoCLKdcoPmCQOut
 sFiRijkW6W2HB70Tfq+OJFBb2UqJEZzu1uDwP156FKWGDrzGyP0tclRnnmrHuder
 wxdUoiscz5Ow4J4oa9/CERRAR11S1aHF45ofwjf2VpuqyeZy98d4mX9GG4oVqEc=
 =ItTI
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/rth/tags/pull-tgt-20170906' into staging

tcg generic translate loop v15

# gpg: Signature made Wed 06 Sep 2017 17:02:31 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-tgt-20170906: (32 commits)
  target/arm: Perform per-insn cross-page check only for Thumb
  target/arm: Split out thumb_tr_translate_insn
  target/arm: Move ss check to init_disas_context
  target/arm: [a64] Move page and ss checks to init_disas_context
  target/arm: [tcg] Port to generic translation framework
  target/arm: [tcg,a64] Port to disas_log
  target/arm: [tcg] Port to disas_log
  target/arm: [tcg,a64] Port to tb_stop
  target/arm: [tcg] Port to tb_stop
  target/arm: [tcg,a64] Port to translate_insn
  target/arm: [tcg] Port to translate_insn
  target/arm: [tcg,a64] Port to breakpoint_check
  target/arm: [tcg,a64] Port to insn_start
  target/arm: [tcg] Port to insn_start
  target/arm: [tcg] Port to tb_start
  target/arm: [tcg,a64] Port to init_disas_context
  target/arm: [tcg] Port to init_disas_context
  target/arm: [tcg] Port to DisasContextBase
  target/i386: [tcg] Port to generic translation framework
  target/i386: [tcg] Port to disas_log
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-09-07 14:34:25 +01:00
commit 7e375e0442
17 changed files with 920 additions and 581 deletions

View File

@ -1,3 +1,4 @@
obj-$(CONFIG_SOFTMMU) += tcg-all.o
obj-$(CONFIG_SOFTMMU) += cputlb.o
obj-y += cpu-exec.o cpu-exec-common.o translate-all.o
obj-y += translator.o

138
accel/tcg/translator.c Normal file
View File

@ -0,0 +1,138 @@
/*
* Generic intermediate code generation.
*
* Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "cpu.h"
#include "tcg/tcg.h"
#include "tcg/tcg-op.h"
#include "exec/exec-all.h"
#include "exec/gen-icount.h"
#include "exec/log.h"
#include "exec/translator.h"
/* Pairs with tcg_clear_temp_count.
To be called by #TranslatorOps.{translate_insn,tb_stop} if
(1) the target is sufficiently clean to support reporting,
(2) as and when all temporaries are known to be consumed.
For most targets, (2) is at the end of translate_insn. */
void translator_loop_temp_check(DisasContextBase *db)
{
if (tcg_check_temp_count()) {
qemu_log("warning: TCG temporary leaks before "
TARGET_FMT_lx "\n", db->pc_next);
}
}
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
CPUState *cpu, TranslationBlock *tb)
{
int max_insns;
/* Initialize DisasContext */
db->tb = tb;
db->pc_first = tb->pc;
db->pc_next = db->pc_first;
db->is_jmp = DISAS_NEXT;
db->num_insns = 0;
db->singlestep_enabled = cpu->singlestep_enabled;
/* Instruction counting */
max_insns = db->tb->cflags & CF_COUNT_MASK;
if (max_insns == 0) {
max_insns = CF_COUNT_MASK;
}
if (max_insns > TCG_MAX_INSNS) {
max_insns = TCG_MAX_INSNS;
}
if (db->singlestep_enabled || singlestep) {
max_insns = 1;
}
max_insns = ops->init_disas_context(db, cpu, max_insns);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
/* Reset the temp count so that we can identify leaks */
tcg_clear_temp_count();
/* Start translating. */
gen_tb_start(db->tb);
ops->tb_start(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
while (true) {
db->num_insns++;
ops->insn_start(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
/* Pass breakpoint hits to target for further processing */
if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
CPUBreakpoint *bp;
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
if (bp->pc == db->pc_next) {
if (ops->breakpoint_check(db, cpu, bp)) {
break;
}
}
}
/* The breakpoint_check hook may use DISAS_TOO_MANY to indicate
that only one more instruction is to be executed. Otherwise
it should use DISAS_NORETURN when generating an exception,
but may use a DISAS_TARGET_* value for Something Else. */
if (db->is_jmp > DISAS_TOO_MANY) {
break;
}
}
/* Disassemble one instruction. The translate_insn hook should
update db->pc_next and db->is_jmp to indicate what should be
done next -- either exiting this loop or locate the start of
the next instruction. */
if (db->num_insns == max_insns && (db->tb->cflags & CF_LAST_IO)) {
/* Accept I/O on the last instruction. */
gen_io_start();
ops->translate_insn(db, cpu);
gen_io_end();
} else {
ops->translate_insn(db, cpu);
}
/* Stop translation if translate_insn so indicated. */
if (db->is_jmp != DISAS_NEXT) {
break;
}
/* Stop translation if the output buffer is full,
or we have executed all of the allowed instructions. */
if (tcg_op_buf_full() || db->num_insns >= max_insns) {
db->is_jmp = DISAS_TOO_MANY;
break;
}
}
/* Emit code to exit the TB, as indicated by db->is_jmp. */
ops->tb_stop(db, cpu);
gen_tb_end(db->tb, db->num_insns);
/* The disas_log hook may use these values rather than recompute. */
db->tb->size = db->pc_next - db->pc_first;
db->tb->icount = db->num_insns;
#ifdef DEBUG_DISAS
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
&& qemu_log_in_addr_range(db->pc_first)) {
qemu_log_lock();
qemu_log("----------------\n");
ops->disas_log(db, cpu);
qemu_log("\n");
qemu_log_unlock();
}
#endif
}

View File

@ -35,35 +35,6 @@ typedef abi_ulong tb_page_addr_t;
typedef ram_addr_t tb_page_addr_t;
#endif
/* DisasContext is_jmp field values
*
* is_jmp starts as DISAS_NEXT. The translator will keep processing
* instructions until an exit condition is reached. If we reach the
* exit condition and is_jmp is still DISAS_NEXT (because of some
* other condition) we simply "jump" to the next address.
* The remaining exit cases are:
*
* DISAS_JUMP - Only the PC was modified dynamically (e.g computed)
* DISAS_TB_JUMP - Only the PC was modified statically (e.g. branch)
*
* In these cases as long as the PC is updated we can chain to the
* next TB either by exiting the loop or looking up the next TB via
* the loookup helper.
*
* DISAS_UPDATE - CPU State was modified dynamically
*
* This covers any other CPU state which necessities us exiting the
* TCG code to the main run-loop. Typically this includes anything
* that might change the interrupt state.
*
* Individual translators may define additional exit cases to deal
* with per-target special conditions.
*/
#define DISAS_NEXT 0 /* next instruction can be analyzed */
#define DISAS_JUMP 1 /* only pc was modified dynamically */
#define DISAS_TB_JUMP 2 /* only pc was modified statically */
#define DISAS_UPDATE 3 /* cpu state was modified dynamically */
#include "qemu/log.h"
void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb);

144
include/exec/translator.h Normal file
View File

@ -0,0 +1,144 @@
/*
* Generic intermediate code generation.
*
* Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef EXEC__TRANSLATOR_H
#define EXEC__TRANSLATOR_H
/*
* Include this header from a target-specific file, and add a
*
* DisasContextBase base;
*
* member in your target-specific DisasContext.
*/
#include "exec/exec-all.h"
#include "tcg/tcg.h"
/**
* DisasJumpType:
* @DISAS_NEXT: Next instruction in program order.
* @DISAS_TOO_MANY: Too many instructions translated.
* @DISAS_NORETURN: Following code is dead.
* @DISAS_TARGET_*: Start of target-specific conditions.
*
* What instruction to disassemble next.
*/
typedef enum DisasJumpType {
DISAS_NEXT,
DISAS_TOO_MANY,
DISAS_NORETURN,
DISAS_TARGET_0,
DISAS_TARGET_1,
DISAS_TARGET_2,
DISAS_TARGET_3,
DISAS_TARGET_4,
DISAS_TARGET_5,
DISAS_TARGET_6,
DISAS_TARGET_7,
DISAS_TARGET_8,
DISAS_TARGET_9,
DISAS_TARGET_10,
DISAS_TARGET_11,
} DisasJumpType;
/**
* DisasContextBase:
* @tb: Translation block for this disassembly.
* @pc_first: Address of first guest instruction in this TB.
* @pc_next: Address of next guest instruction in this TB (current during
* disassembly).
* @is_jmp: What instruction to disassemble next.
* @num_insns: Number of translated instructions (including current).
* @singlestep_enabled: "Hardware" single stepping enabled.
*
* Architecture-agnostic disassembly context.
*/
typedef struct DisasContextBase {
TranslationBlock *tb;
target_ulong pc_first;
target_ulong pc_next;
DisasJumpType is_jmp;
unsigned int num_insns;
bool singlestep_enabled;
} DisasContextBase;
/**
* TranslatorOps:
* @init_disas_context:
* Initialize the target-specific portions of DisasContext struct.
* The generic DisasContextBase has already been initialized.
* Return max_insns, modified as necessary by db->tb->flags.
*
* @tb_start:
* Emit any code required before the start of the main loop,
* after the generic gen_tb_start().
*
* @insn_start:
* Emit the tcg_gen_insn_start opcode.
*
* @breakpoint_check:
* When called, the breakpoint has already been checked to match the PC,
* but the target may decide the breakpoint missed the address
* (e.g., due to conditions encoded in their flags). Return true to
* indicate that the breakpoint did hit, in which case no more breakpoints
* are checked. If the breakpoint did hit, emit any code required to
* signal the exception, and set db->is_jmp as necessary to terminate
* the main loop.
*
* @translate_insn:
* Disassemble one instruction and set db->pc_next for the start
* of the following instruction. Set db->is_jmp as necessary to
* terminate the main loop.
*
* @tb_stop:
* Emit any opcodes required to exit the TB, based on db->is_jmp.
*
* @disas_log:
* Print instruction disassembly to log.
*/
typedef struct TranslatorOps {
int (*init_disas_context)(DisasContextBase *db, CPUState *cpu,
int max_insns);
void (*tb_start)(DisasContextBase *db, CPUState *cpu);
void (*insn_start)(DisasContextBase *db, CPUState *cpu);
bool (*breakpoint_check)(DisasContextBase *db, CPUState *cpu,
const CPUBreakpoint *bp);
void (*translate_insn)(DisasContextBase *db, CPUState *cpu);
void (*tb_stop)(DisasContextBase *db, CPUState *cpu);
void (*disas_log)(const DisasContextBase *db, CPUState *cpu);
} TranslatorOps;
/**
* translator_loop:
* @ops: Target-specific operations.
* @db: Disassembly context.
* @cpu: Target vCPU.
* @tb: Translation block.
*
* Generic translator loop.
*
* Translation will stop in the following cases (in order):
* - When is_jmp set by #TranslatorOps::breakpoint_check.
* - set to DISAS_TOO_MANY exits after translating one more insn
* - set to any other value than DISAS_NEXT exits immediately.
* - When is_jmp set by #TranslatorOps::translate_insn.
* - set to any value other than DISAS_NEXT exits immediately.
* - When the TCG operation buffer is full.
* - When single-stepping is enabled (system-wide or on the current vCPU).
* - When too many instructions have been translated.
*/
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
CPUState *cpu, TranslationBlock *tb);
void translator_loop_temp_check(DisasContextBase *db);
#endif /* EXEC__TRANSLATOR_H */

View File

@ -304,7 +304,7 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
{
gen_a64_set_pc_im(s->pc - offset);
gen_exception_internal(excp);
s->is_jmp = DISAS_EXC;
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_exception_insn(DisasContext *s, int offset, int excp,
@ -312,7 +312,7 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
{
gen_a64_set_pc_im(s->pc - offset);
gen_exception(excp, syndrome, target_el);
s->is_jmp = DISAS_EXC;
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_ss_advance(DisasContext *s)
@ -340,7 +340,7 @@ static void gen_step_complete_exception(DisasContext *s)
gen_ss_advance(s);
gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
default_exception_el(s));
s->is_jmp = DISAS_EXC;
s->base.is_jmp = DISAS_NORETURN;
}
static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
@ -348,13 +348,13 @@ static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
/* No direct tb linking with singlestep (either QEMU's or the ARM
* debug architecture kind) or deterministic io
*/
if (s->singlestep_enabled || s->ss_active || (s->tb->cflags & CF_LAST_IO)) {
if (s->base.singlestep_enabled || s->ss_active || (s->base.tb->cflags & CF_LAST_IO)) {
return false;
}
#ifndef CONFIG_USER_ONLY
/* Only link tbs from inside the same guest page */
if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
if ((s->base.tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
return false;
}
#endif
@ -366,21 +366,21 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
{
TranslationBlock *tb;
tb = s->tb;
tb = s->base.tb;
if (use_goto_tb(s, n, dest)) {
tcg_gen_goto_tb(n);
gen_a64_set_pc_im(dest);
tcg_gen_exit_tb((intptr_t)tb + n);
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
} else {
gen_a64_set_pc_im(dest);
if (s->ss_active) {
gen_step_complete_exception(s);
} else if (s->singlestep_enabled) {
} else if (s->base.singlestep_enabled) {
gen_exception_internal(EXCP_DEBUG);
} else {
tcg_gen_lookup_and_goto_ptr(cpu_pc);
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
}
}
}
@ -1331,16 +1331,16 @@ static void handle_hint(DisasContext *s, uint32_t insn,
case 0: /* NOP */
return;
case 3: /* WFI */
s->is_jmp = DISAS_WFI;
s->base.is_jmp = DISAS_WFI;
return;
case 1: /* YIELD */
if (!parallel_cpus) {
s->is_jmp = DISAS_YIELD;
s->base.is_jmp = DISAS_YIELD;
}
return;
case 2: /* WFE */
if (!parallel_cpus) {
s->is_jmp = DISAS_WFE;
s->base.is_jmp = DISAS_WFE;
}
return;
case 4: /* SEV */
@ -1424,7 +1424,7 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
tcg_temp_free_i32(tcg_op);
/* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */
gen_a64_set_pc_im(s->pc);
s->is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
s->base.is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
break;
}
default:
@ -1559,7 +1559,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
break;
}
if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
gen_io_start();
}
@ -1590,16 +1590,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
}
}
if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
/* I/O operations must end the TB here (whether read or write) */
gen_io_end();
s->is_jmp = DISAS_UPDATE;
s->base.is_jmp = DISAS_UPDATE;
} else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
/* We default to ending the TB on a coprocessor register write,
* but allow this to be suppressed by the register definition
* (usually only necessary to work around guest bugs).
*/
s->is_jmp = DISAS_UPDATE;
s->base.is_jmp = DISAS_UPDATE;
}
}
@ -1789,7 +1789,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
}
gen_helper_exception_return(cpu_env);
/* Must exit loop to check un-masked IRQs */
s->is_jmp = DISAS_EXIT;
s->base.is_jmp = DISAS_EXIT;
return;
case 5: /* DRPS */
if (rn != 0x1f) {
@ -1803,7 +1803,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
return;
}
s->is_jmp = DISAS_JUMP;
s->base.is_jmp = DISAS_JUMP;
}
/* C3.2 Branches, exception generating and system instructions */
@ -11200,23 +11200,15 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
free_tmp_a64(s);
}
void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
static int aarch64_tr_init_disas_context(DisasContextBase *dcbase,
CPUState *cpu, int max_insns)
{
CPUARMState *env = cs->env_ptr;
ARMCPU *cpu = arm_env_get_cpu(env);
DisasContext dc1, *dc = &dc1;
target_ulong pc_start;
target_ulong next_page_start;
int num_insns;
int max_insns;
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUARMState *env = cpu->env_ptr;
ARMCPU *arm_cpu = arm_env_get_cpu(env);
int bound;
pc_start = tb->pc;
dc->tb = tb;
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
dc->singlestep_enabled = cs->singlestep_enabled;
dc->pc = dc->base.pc_first;
dc->condjmp = 0;
dc->aarch64 = 1;
@ -11227,20 +11219,20 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
!arm_el_is_aa64(env, 3);
dc->thumb = 0;
dc->sctlr_b = 0;
dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
dc->condexec_mask = 0;
dc->condexec_cond = 0;
dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
dc->tbi0 = ARM_TBFLAG_TBI0(tb->flags);
dc->tbi1 = ARM_TBFLAG_TBI1(tb->flags);
dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
dc->tbi0 = ARM_TBFLAG_TBI0(dc->base.tb->flags);
dc->tbi1 = ARM_TBFLAG_TBI1(dc->base.tb->flags);
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
#if !defined(CONFIG_USER_ONLY)
dc->user = (dc->current_el == 0);
#endif
dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
dc->vec_len = 0;
dc->vec_stride = 0;
dc->cp_regs = cpu->cp_regs;
dc->cp_regs = arm_cpu->cp_regs;
dc->features = env->features;
/* Single step state. The code-generation logic here is:
@ -11258,127 +11250,131 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
* emit code to generate a software step exception
* end the TB
*/
dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
dc->is_ldex = false;
dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
/* Bound the number of insns to execute to those left on the page. */
bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
/* If architectural single step active, limit to 1. */
if (dc->ss_active) {
bound = 1;
}
max_insns = MIN(max_insns, bound);
init_tmp_a64_array(dc);
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
if (max_insns == 0) {
max_insns = CF_COUNT_MASK;
}
if (max_insns > TCG_MAX_INSNS) {
max_insns = TCG_MAX_INSNS;
}
gen_tb_start(tb);
return max_insns;
}
static void aarch64_tr_tb_start(DisasContextBase *db, CPUState *cpu)
{
tcg_clear_temp_count();
}
do {
dc->insn_start_idx = tcg_op_buf_count();
tcg_gen_insn_start(dc->pc, 0, 0);
num_insns++;
static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
CPUBreakpoint *bp;
QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
if (bp->pc == dc->pc) {
if (bp->flags & BP_CPU) {
gen_a64_set_pc_im(dc->pc);
gen_helper_check_breakpoints(cpu_env);
/* End the TB early; it likely won't be executed */
dc->is_jmp = DISAS_UPDATE;
} else {
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
/* The address covered by the breakpoint must be
included in [tb->pc, tb->pc + tb->size) in order
to for it to be properly cleared -- thus we
increment the PC here so that the logic setting
tb->size below does the right thing. */
dc->pc += 4;
goto done_generating;
}
break;
}
}
}
dc->insn_start_idx = tcg_op_buf_count();
tcg_gen_insn_start(dc->pc, 0, 0);
}
if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
gen_io_start();
}
static bool aarch64_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
const CPUBreakpoint *bp)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
if (dc->ss_active && !dc->pstate_ss) {
/* Singlestep state is Active-pending.
* If we're in this state at the start of a TB then either
* a) we just took an exception to an EL which is being debugged
* and this is the first insn in the exception handler
* b) debug exceptions were masked and we just unmasked them
* without changing EL (eg by clearing PSTATE.D)
* In either case we're going to take a swstep exception in the
* "did not step an insn" case, and so the syndrome ISV and EX
* bits should be zero.
*/
assert(num_insns == 1);
gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
default_exception_el(dc));
dc->is_jmp = DISAS_EXC;
break;
}
disas_a64_insn(env, dc);
if (tcg_check_temp_count()) {
fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
dc->pc);
}
/* Translation stops when a conditional branch is encountered.
* Otherwise the subsequent code could get translated several times.
* Also stop translation when a page boundary is reached. This
* ensures prefetch aborts occur at the right place.
*/
} while (!dc->is_jmp && !tcg_op_buf_full() &&
!cs->singlestep_enabled &&
!singlestep &&
!dc->ss_active &&
dc->pc < next_page_start &&
num_insns < max_insns);
if (tb->cflags & CF_LAST_IO) {
gen_io_end();
if (bp->flags & BP_CPU) {
gen_a64_set_pc_im(dc->pc);
gen_helper_check_breakpoints(cpu_env);
/* End the TB early; it likely won't be executed */
dc->base.is_jmp = DISAS_TOO_MANY;
} else {
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
/* The address covered by the breakpoint must be
included in [tb->pc, tb->pc + tb->size) in order
to for it to be properly cleared -- thus we
increment the PC here so that the logic setting
tb->size below does the right thing. */
dc->pc += 4;
dc->base.is_jmp = DISAS_NORETURN;
}
if (unlikely(cs->singlestep_enabled || dc->ss_active)
&& dc->is_jmp != DISAS_EXC) {
return true;
}
static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUARMState *env = cpu->env_ptr;
if (dc->ss_active && !dc->pstate_ss) {
/* Singlestep state is Active-pending.
* If we're in this state at the start of a TB then either
* a) we just took an exception to an EL which is being debugged
* and this is the first insn in the exception handler
* b) debug exceptions were masked and we just unmasked them
* without changing EL (eg by clearing PSTATE.D)
* In either case we're going to take a swstep exception in the
* "did not step an insn" case, and so the syndrome ISV and EX
* bits should be zero.
*/
assert(dc->base.num_insns == 1);
gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
default_exception_el(dc));
dc->base.is_jmp = DISAS_NORETURN;
} else {
disas_a64_insn(env, dc);
}
dc->base.pc_next = dc->pc;
translator_loop_temp_check(&dc->base);
}
static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
if (unlikely(dc->base.singlestep_enabled || dc->ss_active)) {
/* Note that this means single stepping WFI doesn't halt the CPU.
* For conditional branch insns this is harmless unreachable code as
* gen_goto_tb() has already handled emitting the debug exception
* (and thus a tb-jump is not possible when singlestepping).
*/
assert(dc->is_jmp != DISAS_TB_JUMP);
if (dc->is_jmp != DISAS_JUMP) {
switch (dc->base.is_jmp) {
default:
gen_a64_set_pc_im(dc->pc);
}
if (cs->singlestep_enabled) {
gen_exception_internal(EXCP_DEBUG);
} else {
gen_step_complete_exception(dc);
/* fall through */
case DISAS_JUMP:
if (dc->base.singlestep_enabled) {
gen_exception_internal(EXCP_DEBUG);
} else {
gen_step_complete_exception(dc);
}
break;
case DISAS_NORETURN:
break;
}
} else {
switch (dc->is_jmp) {
switch (dc->base.is_jmp) {
case DISAS_NEXT:
case DISAS_TOO_MANY:
gen_goto_tb(dc, 1, dc->pc);
break;
default:
case DISAS_UPDATE:
gen_a64_set_pc_im(dc->pc);
/* fall through */
case DISAS_JUMP:
tcg_gen_lookup_and_goto_ptr(cpu_pc);
break;
case DISAS_TB_JUMP:
case DISAS_EXC:
case DISAS_EXIT:
tcg_gen_exit_tb(0);
break;
case DISAS_NORETURN:
case DISAS_SWI:
break;
case DISAS_WFE:
@ -11400,31 +11396,29 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
*/
tcg_gen_exit_tb(0);
break;
case DISAS_UPDATE:
gen_a64_set_pc_im(dc->pc);
/* fall through */
case DISAS_EXIT:
default:
tcg_gen_exit_tb(0);
break;
}
}
done_generating:
gen_tb_end(tb, num_insns);
#ifdef DEBUG_DISAS
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
qemu_log_in_addr_range(pc_start)) {
qemu_log_lock();
qemu_log("----------------\n");
qemu_log("IN: %s\n", lookup_symbol(pc_start));
log_target_disas(cs, pc_start, dc->pc - pc_start,
4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
qemu_log("\n");
qemu_log_unlock();
}
#endif
tb->size = dc->pc - pc_start;
tb->icount = num_insns;
/* Functions above can change dc->pc, so re-align db->pc_next */
dc->base.pc_next = dc->pc;
}
static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size,
4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
}
const TranslatorOps aarch64_translator_ops = {
.init_disas_context = aarch64_tr_init_disas_context,
.tb_start = aarch64_tr_tb_start,
.insn_start = aarch64_tr_insn_start,
.breakpoint_check = aarch64_tr_breakpoint_check,
.translate_insn = aarch64_tr_translate_insn,
.tb_stop = aarch64_tr_tb_stop,
.disas_log = aarch64_tr_disas_log,
};

View File

@ -224,7 +224,7 @@ static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
* We choose to ignore [1:0] in ARM mode for all architecture versions.
*/
tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
s->is_jmp = DISAS_JUMP;
s->base.is_jmp = DISAS_JUMP;
}
tcg_gen_mov_i32(cpu_R[reg], var);
tcg_temp_free_i32(var);
@ -297,7 +297,7 @@ static void gen_step_complete_exception(DisasContext *s)
gen_ss_advance(s);
gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
default_exception_el(s));
s->is_jmp = DISAS_EXC;
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_singlestep_exception(DisasContext *s)
@ -321,7 +321,7 @@ static inline bool is_singlestepping(DisasContext *s)
* misnamed as it only means "one instruction per TB" and doesn't
* affect the code we generate.
*/
return s->singlestep_enabled || s->ss_active;
return s->base.singlestep_enabled || s->ss_active;
}
static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
@ -930,7 +930,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
{
TCGv_i32 tmp;
s->is_jmp = DISAS_JUMP;
s->base.is_jmp = DISAS_JUMP;
if (s->thumb != (addr & 1)) {
tmp = tcg_temp_new_i32();
tcg_gen_movi_i32(tmp, addr & 1);
@ -943,7 +943,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
/* Set PC and Thumb state from var. var is marked as dead. */
static inline void gen_bx(DisasContext *s, TCGv_i32 var)
{
s->is_jmp = DISAS_JUMP;
s->base.is_jmp = DISAS_JUMP;
tcg_gen_andi_i32(cpu_R[15], var, ~1);
tcg_gen_andi_i32(var, var, 1);
store_cpu_field(var, thumb);
@ -957,11 +957,11 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var)
static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
{
/* Generate the same code here as for a simple bx, but flag via
* s->is_jmp that we need to do the rest of the work later.
* s->base.is_jmp that we need to do the rest of the work later.
*/
gen_bx(s, var);
if (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M)) {
s->is_jmp = DISAS_BX_EXCRET;
s->base.is_jmp = DISAS_BX_EXCRET;
}
}
@ -1161,7 +1161,7 @@ static inline void gen_hvc(DisasContext *s, int imm16)
*/
s->svc_imm = imm16;
gen_set_pc_im(s, s->pc);
s->is_jmp = DISAS_HVC;
s->base.is_jmp = DISAS_HVC;
}
static inline void gen_smc(DisasContext *s)
@ -1176,7 +1176,7 @@ static inline void gen_smc(DisasContext *s)
gen_helper_pre_smc(cpu_env, tmp);
tcg_temp_free_i32(tmp);
gen_set_pc_im(s, s->pc);
s->is_jmp = DISAS_SMC;
s->base.is_jmp = DISAS_SMC;
}
static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
@ -1184,7 +1184,7 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
gen_set_condexec(s);
gen_set_pc_im(s, s->pc - offset);
gen_exception_internal(excp);
s->is_jmp = DISAS_EXC;
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_exception_insn(DisasContext *s, int offset, int excp,
@ -1193,14 +1193,14 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
gen_set_condexec(s);
gen_set_pc_im(s, s->pc - offset);
gen_exception(excp, syn, target_el);
s->is_jmp = DISAS_EXC;
s->base.is_jmp = DISAS_NORETURN;
}
/* Force a TB lookup after an instruction that changes the CPU state. */
static inline void gen_lookup_tb(DisasContext *s)
{
tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
s->is_jmp = DISAS_EXIT;
s->base.is_jmp = DISAS_EXIT;
}
static inline void gen_hlt(DisasContext *s, int imm)
@ -4145,7 +4145,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
{
#ifndef CONFIG_USER_ONLY
return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
return (s->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
((s->pc - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
#else
return true;
@ -4169,12 +4169,12 @@ static void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
if (use_goto_tb(s, dest)) {
tcg_gen_goto_tb(n);
gen_set_pc_im(s, dest);
tcg_gen_exit_tb((uintptr_t)s->tb + n);
tcg_gen_exit_tb((uintptr_t)s->base.tb + n);
} else {
gen_set_pc_im(s, dest);
gen_goto_ptr();
}
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
}
static inline void gen_jmp (DisasContext *s, uint32_t dest)
@ -4436,7 +4436,7 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
tcg_temp_free_i32(tcg_tgtmode);
tcg_temp_free_i32(tcg_regno);
tcg_temp_free_i32(tcg_reg);
s->is_jmp = DISAS_UPDATE;
s->base.is_jmp = DISAS_UPDATE;
}
static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
@ -4458,7 +4458,7 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
tcg_temp_free_i32(tcg_tgtmode);
tcg_temp_free_i32(tcg_regno);
store_reg(s, rn, tcg_reg);
s->is_jmp = DISAS_UPDATE;
s->base.is_jmp = DISAS_UPDATE;
}
/* Store value to PC as for an exception return (ie don't
@ -4482,7 +4482,7 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
gen_helper_cpsr_write_eret(cpu_env, cpsr);
tcg_temp_free_i32(cpsr);
/* Must exit loop to check un-masked IRQs */
s->is_jmp = DISAS_EXIT;
s->base.is_jmp = DISAS_EXIT;
}
/* Generate an old-style exception return. Marks pc as dead. */
@ -4505,17 +4505,17 @@ static void gen_nop_hint(DisasContext *s, int val)
case 1: /* yield */
if (!parallel_cpus) {
gen_set_pc_im(s, s->pc);
s->is_jmp = DISAS_YIELD;
s->base.is_jmp = DISAS_YIELD;
}
break;
case 3: /* wfi */
gen_set_pc_im(s, s->pc);
s->is_jmp = DISAS_WFI;
s->base.is_jmp = DISAS_WFI;
break;
case 2: /* wfe */
if (!parallel_cpus) {
gen_set_pc_im(s, s->pc);
s->is_jmp = DISAS_WFE;
s->base.is_jmp = DISAS_WFE;
}
break;
case 4: /* sev */
@ -7654,13 +7654,13 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
return 1;
}
gen_set_pc_im(s, s->pc);
s->is_jmp = DISAS_WFI;
s->base.is_jmp = DISAS_WFI;
return 0;
default:
break;
}
if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
gen_io_start();
}
@ -7751,7 +7751,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
}
}
if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
/* I/O operations must end the TB here (whether read or write) */
gen_io_end();
gen_lookup_tb(s);
@ -8065,7 +8065,7 @@ static void gen_srs(DisasContext *s,
tcg_temp_free_i32(tmp);
}
tcg_temp_free_i32(addr);
s->is_jmp = DISAS_UPDATE;
s->base.is_jmp = DISAS_UPDATE;
}
static void disas_arm_insn(DisasContext *s, unsigned int insn)
@ -8153,7 +8153,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
/* setend */
if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) {
gen_helper_setend(cpu_env);
s->is_jmp = DISAS_UPDATE;
s->base.is_jmp = DISAS_UPDATE;
}
return;
} else if ((insn & 0x0fffff00) == 0x057ff000) {
@ -9527,7 +9527,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
gen_helper_cpsr_write_eret(cpu_env, tmp);
tcg_temp_free_i32(tmp);
/* Must exit loop to check un-masked IRQs */
s->is_jmp = DISAS_EXIT;
s->base.is_jmp = DISAS_EXIT;
}
}
break;
@ -9565,7 +9565,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
/* swi */
gen_set_pc_im(s, s->pc);
s->svc_imm = extract32(insn, 0, 24);
s->is_jmp = DISAS_SWI;
s->base.is_jmp = DISAS_SWI;
break;
default:
illegal_op:
@ -11657,7 +11657,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
ARCH(6);
if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) {
gen_helper_setend(cpu_env);
s->is_jmp = DISAS_UPDATE;
s->base.is_jmp = DISAS_UPDATE;
}
break;
case 3:
@ -11751,7 +11751,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
/* swi */
gen_set_pc_im(s, s->pc);
s->svc_imm = extract32(insn, 0, 8);
s->is_jmp = DISAS_SWI;
s->base.is_jmp = DISAS_SWI;
break;
}
/* generate a conditional jump to next instruction */
@ -11824,35 +11824,14 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
return false;
}
/* generate intermediate code for basic block 'tb'. */
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
static int arm_tr_init_disas_context(DisasContextBase *dcbase,
CPUState *cs, int max_insns)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUARMState *env = cs->env_ptr;
ARMCPU *cpu = arm_env_get_cpu(env);
DisasContext dc1, *dc = &dc1;
target_ulong pc_start;
target_ulong next_page_start;
int num_insns;
int max_insns;
bool end_of_page;
/* generate intermediate code */
/* The A64 decoder has its own top level loop, because it doesn't need
* the A32/T32 complexity to do with conditional execution/IT blocks/etc.
*/
if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
gen_intermediate_code_a64(cs, tb);
return;
}
pc_start = tb->pc;
dc->tb = tb;
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
dc->singlestep_enabled = cs->singlestep_enabled;
dc->pc = dc->base.pc_first;
dc->condjmp = 0;
dc->aarch64 = 0;
@ -11861,23 +11840,23 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
*/
dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
!arm_el_is_aa64(env, 3);
dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
dc->sctlr_b = ARM_TBFLAG_SCTLR_B(tb->flags);
dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
dc->thumb = ARM_TBFLAG_THUMB(dc->base.tb->flags);
dc->sctlr_b = ARM_TBFLAG_SCTLR_B(dc->base.tb->flags);
dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) & 0xf) << 1;
dc->condexec_cond = ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) >> 4;
dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
#if !defined(CONFIG_USER_ONLY)
dc->user = (dc->current_el == 0);
#endif
dc->ns = ARM_TBFLAG_NS(tb->flags);
dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(tb->flags);
dc->ns = ARM_TBFLAG_NS(dc->base.tb->flags);
dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
dc->vfp_enabled = ARM_TBFLAG_VFPEN(dc->base.tb->flags);
dc->vec_len = ARM_TBFLAG_VECLEN(dc->base.tb->flags);
dc->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags);
dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(dc->base.tb->flags);
dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags);
dc->cp_regs = cpu->cp_regs;
dc->features = env->features;
@ -11896,11 +11875,26 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
* emit code to generate a software step exception
* end the TB
*/
dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
dc->is_ldex = false;
dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
dc->next_page_start =
(dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
/* If architectural single step active, limit to 1. */
if (is_singlestepping(dc)) {
max_insns = 1;
}
/* ARM is a fixed-length ISA. Bound the number of insns to execute
to those left on the page. */
if (!dc->thumb) {
int bound = (dc->next_page_start - dc->base.pc_first) / 4;
max_insns = MIN(max_insns, bound);
}
cpu_F0s = tcg_temp_new_i32();
cpu_F1s = tcg_temp_new_i32();
cpu_F0d = tcg_temp_new_i64();
@ -11909,19 +11903,13 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
cpu_V1 = cpu_F1d;
/* FIXME: cpu_M0 can probably be the same as cpu_V0. */
cpu_M0 = tcg_temp_new_i64();
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
if (max_insns == 0) {
max_insns = CF_COUNT_MASK;
}
if (max_insns > TCG_MAX_INSNS) {
max_insns = TCG_MAX_INSNS;
}
gen_tb_start(tb);
return max_insns;
}
tcg_clear_temp_count();
static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
/* A note on handling of the condexec (IT) bits:
*
@ -11955,141 +11943,173 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
/* Reset the conditional execution bits immediately. This avoids
complications trying to do it at the end of the block. */
if (dc->condexec_mask || dc->condexec_cond)
{
if (dc->condexec_mask || dc->condexec_cond) {
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_movi_i32(tmp, 0);
store_cpu_field(tmp, condexec_bits);
}
do {
dc->insn_start_idx = tcg_op_buf_count();
tcg_gen_insn_start(dc->pc,
(dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
0);
num_insns++;
}
tcg_clear_temp_count();
}
static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
dc->insn_start_idx = tcg_op_buf_count();
tcg_gen_insn_start(dc->pc,
(dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
0);
}
static bool arm_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
const CPUBreakpoint *bp)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
if (bp->flags & BP_CPU) {
gen_set_condexec(dc);
gen_set_pc_im(dc, dc->pc);
gen_helper_check_breakpoints(cpu_env);
/* End the TB early; it's likely not going to be executed */
dc->base.is_jmp = DISAS_TOO_MANY;
} else {
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
/* The address covered by the breakpoint must be
included in [tb->pc, tb->pc + tb->size) in order
to for it to be properly cleared -- thus we
increment the PC here so that the logic setting
tb->size below does the right thing. */
/* TODO: Advance PC by correct instruction length to
* avoid disassembler error messages */
dc->pc += 2;
dc->base.is_jmp = DISAS_NORETURN;
}
return true;
}
static bool arm_pre_translate_insn(DisasContext *dc)
{
#ifdef CONFIG_USER_ONLY
/* Intercept jump to the magic kernel page. */
if (dc->pc >= 0xffff0000) {
/* We always get here via a jump, so know we are not in a
conditional execution block. */
gen_exception_internal(EXCP_KERNEL_TRAP);
dc->is_jmp = DISAS_EXC;
break;
}
/* Intercept jump to the magic kernel page. */
if (dc->pc >= 0xffff0000) {
/* We always get here via a jump, so know we are not in a
conditional execution block. */
gen_exception_internal(EXCP_KERNEL_TRAP);
dc->base.is_jmp = DISAS_NORETURN;
return true;
}
#endif
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
CPUBreakpoint *bp;
QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
if (bp->pc == dc->pc) {
if (bp->flags & BP_CPU) {
gen_set_condexec(dc);
gen_set_pc_im(dc, dc->pc);
gen_helper_check_breakpoints(cpu_env);
/* End the TB early; it's likely not going to be executed */
dc->is_jmp = DISAS_UPDATE;
} else {
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
/* The address covered by the breakpoint must be
included in [tb->pc, tb->pc + tb->size) in order
to for it to be properly cleared -- thus we
increment the PC here so that the logic setting
tb->size below does the right thing. */
/* TODO: Advance PC by correct instruction length to
* avoid disassembler error messages */
dc->pc += 2;
goto done_generating;
}
break;
}
}
}
if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
gen_io_start();
}
if (dc->ss_active && !dc->pstate_ss) {
/* Singlestep state is Active-pending.
* If we're in this state at the start of a TB then either
* a) we just took an exception to an EL which is being debugged
* and this is the first insn in the exception handler
* b) debug exceptions were masked and we just unmasked them
* without changing EL (eg by clearing PSTATE.D)
* In either case we're going to take a swstep exception in the
* "did not step an insn" case, and so the syndrome ISV and EX
* bits should be zero.
*/
assert(num_insns == 1);
gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
default_exception_el(dc));
goto done_generating;
}
if (dc->thumb) {
disas_thumb_insn(env, dc);
if (dc->condexec_mask) {
dc->condexec_cond = (dc->condexec_cond & 0xe)
| ((dc->condexec_mask >> 4) & 1);
dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
if (dc->condexec_mask == 0) {
dc->condexec_cond = 0;
}
}
} else {
unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
dc->pc += 4;
disas_arm_insn(dc, insn);
}
if (dc->condjmp && !dc->is_jmp) {
gen_set_label(dc->condlabel);
dc->condjmp = 0;
}
if (tcg_check_temp_count()) {
fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
dc->pc);
}
/* Translation stops when a conditional branch is encountered.
* Otherwise the subsequent code could get translated several times.
* Also stop translation when a page boundary is reached. This
* ensures prefetch aborts occur at the right place. */
/* We want to stop the TB if the next insn starts in a new page,
* or if it spans between this page and the next. This means that
* if we're looking at the last halfword in the page we need to
* see if it's a 16-bit Thumb insn (which will fit in this TB)
* or a 32-bit Thumb insn (which won't).
* This is to avoid generating a silly TB with a single 16-bit insn
* in it at the end of this page (which would execute correctly
* but isn't very efficient).
if (dc->ss_active && !dc->pstate_ss) {
/* Singlestep state is Active-pending.
* If we're in this state at the start of a TB then either
* a) we just took an exception to an EL which is being debugged
* and this is the first insn in the exception handler
* b) debug exceptions were masked and we just unmasked them
* without changing EL (eg by clearing PSTATE.D)
* In either case we're going to take a swstep exception in the
* "did not step an insn" case, and so the syndrome ISV and EX
* bits should be zero.
*/
end_of_page = (dc->pc >= next_page_start) ||
((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));
assert(dc->base.num_insns == 1);
gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
default_exception_el(dc));
dc->base.is_jmp = DISAS_NORETURN;
return true;
}
} while (!dc->is_jmp && !tcg_op_buf_full() &&
!is_singlestepping(dc) &&
!singlestep &&
!end_of_page &&
num_insns < max_insns);
return false;
}
if (tb->cflags & CF_LAST_IO) {
if (dc->condjmp) {
/* FIXME: This can theoretically happen with self-modifying
code. */
cpu_abort(cs, "IO on conditional branch instruction");
static void arm_post_translate_insn(DisasContext *dc)
{
if (dc->condjmp && !dc->base.is_jmp) {
gen_set_label(dc->condlabel);
dc->condjmp = 0;
}
dc->base.pc_next = dc->pc;
translator_loop_temp_check(&dc->base);
}
static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUARMState *env = cpu->env_ptr;
unsigned int insn;
if (arm_pre_translate_insn(dc)) {
return;
}
insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
dc->pc += 4;
disas_arm_insn(dc, insn);
arm_post_translate_insn(dc);
/* ARM is a fixed-length ISA. We performed the cross-page check
in init_disas_context by adjusting max_insns. */
}
static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUARMState *env = cpu->env_ptr;
if (arm_pre_translate_insn(dc)) {
return;
}
disas_thumb_insn(env, dc);
/* Advance the Thumb condexec condition. */
if (dc->condexec_mask) {
dc->condexec_cond = ((dc->condexec_cond & 0xe) |
((dc->condexec_mask >> 4) & 1));
dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
if (dc->condexec_mask == 0) {
dc->condexec_cond = 0;
}
gen_io_end();
}
arm_post_translate_insn(dc);
/* Thumb is a variable-length ISA. Stop translation when the next insn
* will touch a new page. This ensures that prefetch aborts occur at
* the right place.
*
* We want to stop the TB if the next insn starts in a new page,
* or if it spans between this page and the next. This means that
* if we're looking at the last halfword in the page we need to
* see if it's a 16-bit Thumb insn (which will fit in this TB)
* or a 32-bit Thumb insn (which won't).
* This is to avoid generating a silly TB with a single 16-bit insn
* in it at the end of this page (which would execute correctly
* but isn't very efficient).
*/
if (dc->base.is_jmp == DISAS_NEXT
&& (dc->pc >= dc->next_page_start
|| (dc->pc >= dc->next_page_start - 3
&& insn_crosses_page(env, dc)))) {
dc->base.is_jmp = DISAS_TOO_MANY;
}
}
static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
if (dc->base.tb->cflags & CF_LAST_IO && dc->condjmp) {
/* FIXME: This can theoretically happen with self-modifying code. */
cpu_abort(cpu, "IO on conditional branch instruction");
}
/* At this stage dc->condjmp will only be set when the skipped
instruction was a conditional branch or trap, and the PC has
already been written. */
gen_set_condexec(dc);
if (dc->is_jmp == DISAS_BX_EXCRET) {
if (dc->base.is_jmp == DISAS_BX_EXCRET) {
/* Exception return branches need some special case code at the
* end of the TB, which is complex enough that it has to
* handle the single-step vs not and the condition-failed
@ -12098,7 +12118,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
gen_bx_excret_final_code(dc);
} else if (unlikely(is_singlestepping(dc))) {
/* Unconditional and "condition passed" instruction codepath. */
switch (dc->is_jmp) {
switch (dc->base.is_jmp) {
case DISAS_SWI:
gen_ss_advance(dc);
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
@ -12113,12 +12133,16 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
break;
case DISAS_NEXT:
case DISAS_TOO_MANY:
case DISAS_UPDATE:
gen_set_pc_im(dc, dc->pc);
/* fall through */
default:
/* FIXME: Single stepping a WFI insn will not halt the CPU. */
gen_singlestep_exception(dc);
break;
case DISAS_NORETURN:
break;
}
} else {
/* While branches must always occur at the end of an IT block,
@ -12129,8 +12153,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
- Hardware watchpoints.
Hardware breakpoints have already been handled and skip this code.
*/
switch(dc->is_jmp) {
switch(dc->base.is_jmp) {
case DISAS_NEXT:
case DISAS_TOO_MANY:
gen_goto_tb(dc, 1, dc->pc);
break;
case DISAS_JUMP:
@ -12143,8 +12168,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
/* indicate that the hash table must be used to find the next TB */
tcg_gen_exit_tb(0);
break;
case DISAS_TB_JUMP:
case DISAS_EXC:
case DISAS_NORETURN:
/* nothing more to generate */
break;
case DISAS_WFI:
@ -12185,23 +12209,55 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
}
}
done_generating:
gen_tb_end(tb, num_insns);
/* Functions above can change dc->pc, so re-align db->pc_next */
dc->base.pc_next = dc->pc;
}
#ifdef DEBUG_DISAS
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
qemu_log_in_addr_range(pc_start)) {
qemu_log_lock();
qemu_log("----------------\n");
qemu_log("IN: %s\n", lookup_symbol(pc_start));
log_target_disas(cs, pc_start, dc->pc - pc_start,
dc->thumb | (dc->sctlr_b << 1));
qemu_log("\n");
qemu_log_unlock();
static void arm_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size,
dc->thumb | (dc->sctlr_b << 1));
}
static const TranslatorOps arm_translator_ops = {
.init_disas_context = arm_tr_init_disas_context,
.tb_start = arm_tr_tb_start,
.insn_start = arm_tr_insn_start,
.breakpoint_check = arm_tr_breakpoint_check,
.translate_insn = arm_tr_translate_insn,
.tb_stop = arm_tr_tb_stop,
.disas_log = arm_tr_disas_log,
};
static const TranslatorOps thumb_translator_ops = {
.init_disas_context = arm_tr_init_disas_context,
.tb_start = arm_tr_tb_start,
.insn_start = arm_tr_insn_start,
.breakpoint_check = arm_tr_breakpoint_check,
.translate_insn = thumb_tr_translate_insn,
.tb_stop = arm_tr_tb_stop,
.disas_log = arm_tr_disas_log,
};
/* generate intermediate code for basic block 'tb'. */
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
{
DisasContext dc;
const TranslatorOps *ops = &arm_translator_ops;
if (ARM_TBFLAG_THUMB(tb->flags)) {
ops = &thumb_translator_ops;
}
#ifdef TARGET_AARCH64
if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
ops = &aarch64_translator_ops;
}
#endif
tb->size = dc->pc - pc_start;
tb->icount = num_insns;
translator_loop(ops, &dc.base, cpu, tb);
}
static const char *cpu_mode_names[16] = {

View File

@ -1,11 +1,16 @@
#ifndef TARGET_ARM_TRANSLATE_H
#define TARGET_ARM_TRANSLATE_H
#include "exec/translator.h"
/* internal defines */
typedef struct DisasContext {
DisasContextBase base;
target_ulong pc;
target_ulong next_page_start;
uint32_t insn;
int is_jmp;
/* Nonzero if this instruction has been conditionally skipped. */
int condjmp;
/* The label that will be jumped to when the instruction is skipped. */
@ -13,8 +18,6 @@ typedef struct DisasContext {
/* Thumb-2 conditional execution bits. */
int condexec_mask;
int condexec_cond;
struct TranslationBlock *tb;
int singlestep_enabled;
int thumb;
int sctlr_b;
TCGMemOp be_data;
@ -119,49 +122,43 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
s->insn_start_idx = 0;
}
/* target-specific extra values for is_jmp */
/* is_jmp field values */
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
/* These instructions trap after executing, so the A32/T32 decoder must
* defer them until after the conditional execution state has been updated.
* WFI also needs special handling when single-stepping.
*/
#define DISAS_WFI 4
#define DISAS_SWI 5
/* For instructions which unconditionally cause an exception we can skip
* emitting unreachable code at the end of the TB in the A64 decoder
*/
#define DISAS_EXC 6
#define DISAS_WFI DISAS_TARGET_2
#define DISAS_SWI DISAS_TARGET_3
/* WFE */
#define DISAS_WFE 7
#define DISAS_HVC 8
#define DISAS_SMC 9
#define DISAS_YIELD 10
#define DISAS_WFE DISAS_TARGET_4
#define DISAS_HVC DISAS_TARGET_5
#define DISAS_SMC DISAS_TARGET_6
#define DISAS_YIELD DISAS_TARGET_7
/* M profile branch which might be an exception return (and so needs
* custom end-of-TB code)
*/
#define DISAS_BX_EXCRET 11
#define DISAS_BX_EXCRET DISAS_TARGET_8
/* For instructions which want an immediate exit to the main loop,
* as opposed to attempting to use lookup_and_goto_ptr. Unlike
* DISAS_UPDATE this doesn't write the PC on exiting the translation
* loop so you need to ensure something (gen_a64_set_pc_im or runtime
* helper) has done so before we reach return from cpu_tb_exec.
*/
#define DISAS_EXIT 12
#define DISAS_EXIT DISAS_TARGET_9
#ifdef TARGET_AARCH64
void a64_translate_init(void);
void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb);
void gen_a64_set_pc_im(uint64_t val);
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
fprintf_function cpu_fprintf, int flags);
extern const TranslatorOps aarch64_translator_ops;
#else
static inline void a64_translate_init(void)
{
}
static inline void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb)
{
}
static inline void gen_a64_set_pc_im(uint64_t val)
{
}

View File

@ -31,6 +31,7 @@
#include "exec/helper-proto.h"
#include "mmu.h"
#include "exec/cpu_ldst.h"
#include "exec/translator.h"
#include "crisv32-decode.h"
#include "exec/helper-gen.h"
@ -50,7 +51,11 @@
#define BUG() (gen_BUG(dc, __FILE__, __LINE__))
#define BUG_ON(x) ({if (x) BUG();})
#define DISAS_SWI 5
/* is_jmp field values */
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
#define DISAS_SWI DISAS_TARGET_3
/* Used by the decoder. */
#define EXTRACT_FIELD(src, start, end) \

View File

@ -24,6 +24,7 @@
#include "exec/exec-all.h"
#include "tcg-op.h"
#include "exec/cpu_ldst.h"
#include "exec/translator.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@ -31,7 +32,6 @@
#include "trace-tcg.h"
#include "exec/log.h"
#define PREFIX_REPZ 0x01
#define PREFIX_REPNZ 0x02
#define PREFIX_LOCK 0x04
@ -95,6 +95,8 @@ static int x86_64_hregs;
#endif
typedef struct DisasContext {
DisasContextBase base;
/* current insn context */
int override; /* -1 if no override */
int prefix;
@ -102,8 +104,6 @@ typedef struct DisasContext {
TCGMemOp dflag;
target_ulong pc_start;
target_ulong pc; /* pc = eip + cs_base */
int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
static state change (stop translation) */
/* current block context */
target_ulong cs_base; /* base of CS segment */
int pe; /* protected mode */
@ -124,12 +124,10 @@ typedef struct DisasContext {
int cpl;
int iopl;
int tf; /* TF cpu flag */
int singlestep_enabled; /* "hardware" single step enabled */
int jmp_opt; /* use direct block chaining for direct jumps */
int repz_opt; /* optimize jumps within repz instructions */
int mem_index; /* select memory access functions */
uint64_t flags; /* all execution flags */
struct TranslationBlock *tb;
int popl_esp_hack; /* for correct popl with esp base handling */
int rip_offset; /* only used in x86_64, but left for simplicity */
int cpuid_features;
@ -1119,7 +1117,7 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
static inline void gen_ins(DisasContext *s, TCGMemOp ot)
{
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_string_movl_A0_EDI(s);
@ -1134,14 +1132,14 @@ static inline void gen_ins(DisasContext *s, TCGMemOp ot)
gen_op_movl_T0_Dshift(ot);
gen_op_add_reg_T0(s->aflag, R_EDI);
gen_bpt_io(s, cpu_tmp2_i32, ot);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
}
}
static inline void gen_outs(DisasContext *s, TCGMemOp ot)
{
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_string_movl_A0_ESI(s);
@ -1154,7 +1152,7 @@ static inline void gen_outs(DisasContext *s, TCGMemOp ot)
gen_op_movl_T0_Dshift(ot);
gen_op_add_reg_T0(s->aflag, R_ESI);
gen_bpt_io(s, cpu_tmp2_i32, ot);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
}
}
@ -2137,7 +2135,7 @@ static inline int insn_const_size(TCGMemOp ot)
static inline bool use_goto_tb(DisasContext *s, target_ulong pc)
{
#ifndef CONFIG_USER_ONLY
return (pc & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) ||
return (pc & TARGET_PAGE_MASK) == (s->base.tb->pc & TARGET_PAGE_MASK) ||
(pc & TARGET_PAGE_MASK) == (s->pc_start & TARGET_PAGE_MASK);
#else
return true;
@ -2152,7 +2150,8 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
/* jump to same page: we can use a direct jump */
tcg_gen_goto_tb(tb_num);
gen_jmp_im(eip);
tcg_gen_exit_tb((uintptr_t)s->tb + tb_num);
tcg_gen_exit_tb((uintptr_t)s->base.tb + tb_num);
s->base.is_jmp = DISAS_NORETURN;
} else {
/* jump to another page */
gen_jmp_im(eip);
@ -2173,7 +2172,6 @@ static inline void gen_jcc(DisasContext *s, int b,
gen_set_label(l1);
gen_goto_tb(s, 1, val);
s->is_jmp = DISAS_TB_JUMP;
} else {
l1 = gen_new_label();
l2 = gen_new_label();
@ -2243,12 +2241,14 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg)
because ss32 may change. For R_SS, translation must always
stop as a special handling must be done to disable hardware
interrupts for the next instruction */
if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
s->is_jmp = DISAS_TB_JUMP;
if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS)) {
s->base.is_jmp = DISAS_TOO_MANY;
}
} else {
gen_op_movl_seg_T0_vm(seg_reg);
if (seg_reg == R_SS)
s->is_jmp = DISAS_TB_JUMP;
if (seg_reg == R_SS) {
s->base.is_jmp = DISAS_TOO_MANY;
}
}
}
@ -2420,7 +2420,7 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
gen_update_cc_op(s);
gen_jmp_im(cur_eip);
gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno));
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
}
/* Generate #UD for the current instruction. The assumption here is that
@ -2458,7 +2458,7 @@ static void gen_interrupt(DisasContext *s, int intno,
gen_jmp_im(cur_eip);
gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno),
tcg_const_i32(next_eip - cur_eip));
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_debug(DisasContext *s, target_ulong cur_eip)
@ -2466,7 +2466,7 @@ static void gen_debug(DisasContext *s, target_ulong cur_eip)
gen_update_cc_op(s);
gen_jmp_im(cur_eip);
gen_helper_debug(cpu_env);
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_set_hflag(DisasContext *s, uint32_t mask)
@ -2522,10 +2522,10 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK);
}
if (s->tb->flags & HF_RF_MASK) {
if (s->base.tb->flags & HF_RF_MASK) {
gen_helper_reset_rf(cpu_env);
}
if (s->singlestep_enabled) {
if (s->base.singlestep_enabled) {
gen_helper_debug(cpu_env);
} else if (recheck_tf) {
gen_helper_rechecking_single_step(cpu_env);
@ -2541,7 +2541,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
} else {
tcg_gen_exit_tb(0);
}
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
}
static inline void
@ -2580,7 +2580,6 @@ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
set_cc_op(s, CC_OP_DYNAMIC);
if (s->jmp_opt) {
gen_goto_tb(s, tb_num, eip);
s->is_jmp = DISAS_TB_JUMP;
} else {
gen_jmp_im(eip);
gen_eob(s);
@ -4416,17 +4415,18 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
}
}
/* convert one instruction. s->is_jmp is set if the translation must
/* convert one instruction. s->base.is_jmp is set if the translation must
be stopped. Return the next pc value */
static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
target_ulong pc_start)
static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
{
CPUX86State *env = cpu->env_ptr;
int b, prefixes;
int shift;
TCGMemOp ot, aflag, dflag;
int modrm, reg, rm, mod, op, opreg, val;
target_ulong next_eip, tval;
int rex_w, rex_r;
target_ulong pc_start = s->base.pc_next;
s->pc_start = s->pc = pc_start;
prefixes = 0;
@ -5376,7 +5376,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_movl_seg_T0(s, reg);
gen_pop_update(s, ot);
/* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
if (s->is_jmp) {
if (s->base.is_jmp) {
gen_jmp_im(s->pc - s->cs_base);
if (reg == R_SS) {
s->tf = 0;
@ -5391,7 +5391,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
ot = gen_pop_T0(s);
gen_movl_seg_T0(s, (b >> 3) & 7);
gen_pop_update(s, ot);
if (s->is_jmp) {
if (s->base.is_jmp) {
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
}
@ -5442,7 +5442,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
gen_movl_seg_T0(s, reg);
/* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
if (s->is_jmp) {
if (s->base.is_jmp) {
gen_jmp_im(s->pc - s->cs_base);
if (reg == R_SS) {
s->tf = 0;
@ -5651,7 +5651,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_movl_seg_T0(s, op);
/* then put the data */
gen_op_mov_reg_v(ot, reg, cpu_T1);
if (s->is_jmp) {
if (s->base.is_jmp) {
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
}
@ -6307,7 +6307,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else {
gen_ins(s, ot);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_jmp(s, s->pc - s->cs_base);
}
}
@ -6322,7 +6322,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else {
gen_outs(s, ot);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_jmp(s, s->pc - s->cs_base);
}
}
@ -6338,14 +6338,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_movi_tl(cpu_T0, val);
gen_check_io(s, ot, pc_start - s->cs_base,
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
tcg_gen_movi_i32(cpu_tmp2_i32, val);
gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
gen_bpt_io(s, cpu_tmp2_i32, ot);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
@ -6359,14 +6359,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
svm_is_rep(prefixes));
gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
tcg_gen_movi_i32(cpu_tmp2_i32, val);
tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
gen_bpt_io(s, cpu_tmp2_i32, ot);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
@ -6377,14 +6377,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_ext16u_tl(cpu_T0, cpu_regs[R_EDX]);
gen_check_io(s, ot, pc_start - s->cs_base,
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
gen_bpt_io(s, cpu_tmp2_i32, ot);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
@ -6397,14 +6397,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
svm_is_rep(prefixes));
gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
gen_bpt_io(s, cpu_tmp2_i32, ot);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
@ -6943,7 +6943,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start));
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
}
break;
case 0x9b: /* fwait */
@ -7112,11 +7112,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 0x131: /* rdtsc */
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_rdtsc(cpu_env);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
@ -7188,7 +7188,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
}
break;
case 0x100:
@ -7371,7 +7371,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
tcg_const_i32(s->pc - pc_start));
tcg_gen_exit_tb(0);
s->is_jmp = DISAS_TB_JUMP;
s->base.is_jmp = DISAS_NORETURN;
break;
case 0xd9: /* VMMCALL */
@ -7571,11 +7571,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_rdtscp(cpu_env);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
}
@ -7940,24 +7940,24 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
if (b & 2) {
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_op_mov_v_reg(ot, cpu_T0, rm);
gen_helper_write_crN(cpu_env, tcg_const_i32(reg),
cpu_T0);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
}
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
} else {
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_read_crN(cpu_T0, cpu_env, tcg_const_i32(reg));
gen_op_mov_reg_v(ot, rm, cpu_T0);
if (s->tb->cflags & CF_USE_ICOUNT) {
if (s->base.tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
}
}
@ -8378,22 +8378,13 @@ void tcg_x86_init(void)
}
}
/* generate intermediate code for basic block 'tb'. */
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
static int i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu,
int max_insns)
{
CPUX86State *env = cs->env_ptr;
DisasContext dc1, *dc = &dc1;
target_ulong pc_ptr;
uint32_t flags;
target_ulong pc_start;
target_ulong cs_base;
int num_insns;
int max_insns;
/* generate intermediate code */
pc_start = tb->pc;
cs_base = tb->cs_base;
flags = tb->flags;
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUX86State *env = cpu->env_ptr;
uint32_t flags = dc->base.tb->flags;
target_ulong cs_base = dc->base.tb->cs_base;
dc->pe = (flags >> HF_PE_SHIFT) & 1;
dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
@ -8404,11 +8395,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
dc->iopl = (flags >> IOPL_SHIFT) & 3;
dc->tf = (flags >> TF_SHIFT) & 1;
dc->singlestep_enabled = cs->singlestep_enabled;
dc->cc_op = CC_OP_DYNAMIC;
dc->cc_op_dirty = false;
dc->cs_base = cs_base;
dc->tb = tb;
dc->popl_esp_hack = 0;
/* select memory access functions */
dc->mem_index = 0;
@ -8426,7 +8415,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
#endif
dc->flags = flags;
dc->jmp_opt = !(dc->tf || cs->singlestep_enabled ||
dc->jmp_opt = !(dc->tf || dc->base.singlestep_enabled ||
(flags & HF_INHIBIT_IRQ_MASK));
/* Do not optimize repz jumps at all in icount mode, because
rep movsS instructions are execured with different paths
@ -8438,7 +8427,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
record/replay modes and there will always be an
additional step for ecx=0 when icount is enabled.
*/
dc->repz_opt = !dc->jmp_opt && !(tb->cflags & CF_USE_ICOUNT);
dc->repz_opt = !dc->jmp_opt && !(dc->base.tb->cflags & CF_USE_ICOUNT);
#if 0
/* check addseg logic */
if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
@ -8458,107 +8447,112 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
cpu_ptr1 = tcg_temp_new_ptr();
cpu_cc_srcT = tcg_temp_local_new();
dc->is_jmp = DISAS_NEXT;
pc_ptr = pc_start;
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
if (max_insns == 0) {
max_insns = CF_COUNT_MASK;
}
if (max_insns > TCG_MAX_INSNS) {
max_insns = TCG_MAX_INSNS;
return max_insns;
}
static void i386_tr_tb_start(DisasContextBase *db, CPUState *cpu)
{
}
static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
}
static bool i386_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
const CPUBreakpoint *bp)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
/* If RF is set, suppress an internally generated breakpoint. */
int flags = dc->base.tb->flags & HF_RF_MASK ? BP_GDB : BP_ANY;
if (bp->flags & flags) {
gen_debug(dc, dc->base.pc_next - dc->cs_base);
dc->base.is_jmp = DISAS_NORETURN;
/* The address covered by the breakpoint must be included in
[tb->pc, tb->pc + tb->size) in order to for it to be
properly cleared -- thus we increment the PC here so that
the generic logic setting tb->size later does the right thing. */
dc->base.pc_next += 1;
return true;
} else {
return false;
}
}
gen_tb_start(tb);
for(;;) {
tcg_gen_insn_start(pc_ptr, dc->cc_op);
num_insns++;
static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
target_ulong pc_next = disas_insn(dc, cpu);
/* If RF is set, suppress an internally generated breakpoint. */
if (unlikely(cpu_breakpoint_test(cs, pc_ptr,
tb->flags & HF_RF_MASK
? BP_GDB : BP_ANY))) {
gen_debug(dc, pc_ptr - dc->cs_base);
/* The address covered by the breakpoint must be included in
[tb->pc, tb->pc + tb->size) in order to for it to be
properly cleared -- thus we increment the PC here so that
the logic setting tb->size below does the right thing. */
pc_ptr += 1;
goto done_generating;
}
if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
gen_io_start();
}
pc_ptr = disas_insn(env, dc, pc_ptr);
/* stop translation if indicated */
if (dc->is_jmp)
break;
if (dc->tf || (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) {
/* if single step mode, we generate only one instruction and
generate an exception */
/* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
the flag and abort the translation to give the irqs a
change to be happen */
if (dc->tf || dc->singlestep_enabled ||
(flags & HF_INHIBIT_IRQ_MASK)) {
gen_jmp_im(pc_ptr - dc->cs_base);
gen_eob(dc);
break;
}
chance to happen */
dc->base.is_jmp = DISAS_TOO_MANY;
} else if ((dc->base.tb->cflags & CF_USE_ICOUNT)
&& ((dc->base.pc_next & TARGET_PAGE_MASK)
!= ((dc->base.pc_next + TARGET_MAX_INSN_SIZE - 1)
& TARGET_PAGE_MASK)
|| (dc->base.pc_next & ~TARGET_PAGE_MASK) == 0)) {
/* Do not cross the boundary of the pages in icount mode,
it can cause an exception. Do it only when boundary is
crossed by the first instruction in the block.
If current instruction already crossed the bound - it's ok,
because an exception hasn't stopped this code.
*/
if ((tb->cflags & CF_USE_ICOUNT)
&& ((pc_ptr & TARGET_PAGE_MASK)
!= ((pc_ptr + TARGET_MAX_INSN_SIZE - 1) & TARGET_PAGE_MASK)
|| (pc_ptr & ~TARGET_PAGE_MASK) == 0)) {
gen_jmp_im(pc_ptr - dc->cs_base);
gen_eob(dc);
break;
}
/* if too long translation, stop generation too */
if (tcg_op_buf_full() ||
(pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
num_insns >= max_insns) {
gen_jmp_im(pc_ptr - dc->cs_base);
gen_eob(dc);
break;
}
if (singlestep) {
gen_jmp_im(pc_ptr - dc->cs_base);
gen_eob(dc);
break;
}
dc->base.is_jmp = DISAS_TOO_MANY;
} else if ((pc_next - dc->base.pc_first) >= (TARGET_PAGE_SIZE - 32)) {
dc->base.is_jmp = DISAS_TOO_MANY;
}
if (tb->cflags & CF_LAST_IO)
gen_io_end();
done_generating:
gen_tb_end(tb, num_insns);
#ifdef DEBUG_DISAS
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
&& qemu_log_in_addr_range(pc_start)) {
int disas_flags;
qemu_log_lock();
qemu_log("----------------\n");
qemu_log("IN: %s\n", lookup_symbol(pc_start));
dc->base.pc_next = pc_next;
}
static void i386_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
if (dc->base.is_jmp == DISAS_TOO_MANY) {
gen_jmp_im(dc->base.pc_next - dc->cs_base);
gen_eob(dc);
}
}
static void i386_tr_disas_log(const DisasContextBase *dcbase,
CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
int disas_flags = !dc->code32;
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
#ifdef TARGET_X86_64
if (dc->code64)
disas_flags = 2;
else
#endif
disas_flags = !dc->code32;
log_target_disas(cs, pc_start, pc_ptr - pc_start, disas_flags);
qemu_log("\n");
qemu_log_unlock();
if (dc->code64) {
disas_flags = 2;
}
#endif
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size, disas_flags);
}
tb->size = pc_ptr - pc_start;
tb->icount = num_insns;
static const TranslatorOps i386_tr_ops = {
.init_disas_context = i386_tr_init_disas_context,
.tb_start = i386_tr_tb_start,
.insn_start = i386_tr_insn_start,
.breakpoint_check = i386_tr_breakpoint_check,
.translate_insn = i386_tr_translate_insn,
.tb_stop = i386_tr_tb_stop,
.disas_log = i386_tr_disas_log,
};
/* generate intermediate code for basic block 'tb'. */
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
{
DisasContext dc;
translator_loop(&i386_tr_ops, &dc.base, cpu, tb);
}
void restore_state_to_opc(CPUX86State *env, TranslationBlock *tb,

View File

@ -22,6 +22,7 @@
#include "disas/disas.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/translator.h"
#include "tcg-op.h"
#include "exec/cpu_ldst.h"
@ -47,6 +48,11 @@
#define MEM_INDEX 0
/* is_jmp field values */
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
static TCGv_env cpu_env;
static TCGv cpu_R[32];
static TCGv cpu_pc;

View File

@ -25,6 +25,7 @@
#include "tcg-op.h"
#include "qemu/log.h"
#include "exec/cpu_ldst.h"
#include "exec/translator.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@ -173,7 +174,11 @@ static void do_writebacks(DisasContext *s)
}
}
#define DISAS_JUMP_NEXT 4
/* is_jmp field values */
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
#define DISAS_JUMP_NEXT DISAS_TARGET_3
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1

View File

@ -27,6 +27,7 @@
#include "microblaze-decode.h"
#include "exec/cpu_ldst.h"
#include "exec/helper-gen.h"
#include "exec/translator.h"
#include "trace-tcg.h"
#include "exec/log.h"
@ -46,6 +47,11 @@
#define EXTRACT_FIELD(src, start, end) \
(((src) >> start) & ((1 << (end - start + 1)) - 1))
/* is_jmp field values */
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
static TCGv env_debug;
static TCGv_env cpu_env;
static TCGv cpu_R[32];

View File

@ -29,6 +29,12 @@
#include "exec/helper-gen.h"
#include "exec/log.h"
#include "exec/cpu_ldst.h"
#include "exec/translator.h"
/* is_jmp field values */
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
#define INSTRUCTION_FLG(func, flags) { (func), (flags) }
#define INSTRUCTION(func) \

View File

@ -27,6 +27,7 @@
#include "qemu/log.h"
#include "qemu/bitops.h"
#include "exec/cpu_ldst.h"
#include "exec/translator.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@ -37,6 +38,11 @@
#define LOG_DIS(str, ...) \
qemu_log_mask(CPU_LOG_TB_IN_ASM, "%08x: " str, dc->pc, ## __VA_ARGS__)
/* is_jmp field values */
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
typedef struct DisasContext {
TranslationBlock *tb;
target_ulong pc;

View File

@ -77,7 +77,8 @@ typedef struct {
} u;
} DisasCompare;
#define DISAS_EXCP 4
/* is_jmp field values */
#define DISAS_EXCP DISAS_TARGET_0
#ifdef DEBUG_INLINE_BRANCHES
static uint64_t inline_branch_hit[CC_OP_MAX];

View File

@ -16,6 +16,7 @@
#include "tcg-op.h"
#include "qemu/log.h"
#include "exec/cpu_ldst.h"
#include "exec/translator.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@ -45,9 +46,13 @@ typedef struct DisasContext {
#define IS_USER(s) 1
#endif
/* is_jmp field values */
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
/* These instructions trap after executing, so defer them until after the
conditional executions state has been updated. */
#define DISAS_SYSCALL 5
#define DISAS_SYSCALL DISAS_TARGET_3
static TCGv_env cpu_env;
static TCGv_i32 cpu_R[32];

View File

@ -38,6 +38,7 @@
#include "sysemu/sysemu.h"
#include "exec/cpu_ldst.h"
#include "exec/semihost.h"
#include "exec/translator.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@ -46,6 +47,9 @@
#include "exec/log.h"
/* is_jmp field values */
#define DISAS_UPDATE DISAS_TARGET_0 /* cpu state was modified dynamically */
typedef struct DisasContext {
const XtensaConfig *config;
TranslationBlock *tb;