mirror of
https://git.proxmox.com/git/qemu
synced 2025-08-14 12:07:25 +00:00
better arm conditionnal execution implementation (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1399 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
430116a1d8
commit
e50e6a2019
@ -251,104 +251,109 @@ void OPPROTO op_logic_T1_cc(void)
|
|||||||
void OPPROTO op_test_eq(void)
|
void OPPROTO op_test_eq(void)
|
||||||
{
|
{
|
||||||
if (env->NZF == 0)
|
if (env->NZF == 0)
|
||||||
JUMP_TB(op_test_eq, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);;
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_ne(void)
|
void OPPROTO op_test_ne(void)
|
||||||
{
|
{
|
||||||
if (env->NZF != 0)
|
if (env->NZF != 0)
|
||||||
JUMP_TB(op_test_ne, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);;
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_cs(void)
|
void OPPROTO op_test_cs(void)
|
||||||
{
|
{
|
||||||
if (env->CF != 0)
|
if (env->CF != 0)
|
||||||
JUMP_TB(op_test_cs, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_cc(void)
|
void OPPROTO op_test_cc(void)
|
||||||
{
|
{
|
||||||
if (env->CF == 0)
|
if (env->CF == 0)
|
||||||
JUMP_TB(op_test_cc, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_mi(void)
|
void OPPROTO op_test_mi(void)
|
||||||
{
|
{
|
||||||
if ((env->NZF & 0x80000000) != 0)
|
if ((env->NZF & 0x80000000) != 0)
|
||||||
JUMP_TB(op_test_mi, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_pl(void)
|
void OPPROTO op_test_pl(void)
|
||||||
{
|
{
|
||||||
if ((env->NZF & 0x80000000) == 0)
|
if ((env->NZF & 0x80000000) == 0)
|
||||||
JUMP_TB(op_test_pl, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_vs(void)
|
void OPPROTO op_test_vs(void)
|
||||||
{
|
{
|
||||||
if ((env->VF & 0x80000000) != 0)
|
if ((env->VF & 0x80000000) != 0)
|
||||||
JUMP_TB(op_test_vs, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_vc(void)
|
void OPPROTO op_test_vc(void)
|
||||||
{
|
{
|
||||||
if ((env->VF & 0x80000000) == 0)
|
if ((env->VF & 0x80000000) == 0)
|
||||||
JUMP_TB(op_test_vc, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_hi(void)
|
void OPPROTO op_test_hi(void)
|
||||||
{
|
{
|
||||||
if (env->CF != 0 && env->NZF != 0)
|
if (env->CF != 0 && env->NZF != 0)
|
||||||
JUMP_TB(op_test_hi, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_ls(void)
|
void OPPROTO op_test_ls(void)
|
||||||
{
|
{
|
||||||
if (env->CF == 0 || env->NZF == 0)
|
if (env->CF == 0 || env->NZF == 0)
|
||||||
JUMP_TB(op_test_ls, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_ge(void)
|
void OPPROTO op_test_ge(void)
|
||||||
{
|
{
|
||||||
if (((env->VF ^ env->NZF) & 0x80000000) == 0)
|
if (((env->VF ^ env->NZF) & 0x80000000) == 0)
|
||||||
JUMP_TB(op_test_ge, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_lt(void)
|
void OPPROTO op_test_lt(void)
|
||||||
{
|
{
|
||||||
if (((env->VF ^ env->NZF) & 0x80000000) != 0)
|
if (((env->VF ^ env->NZF) & 0x80000000) != 0)
|
||||||
JUMP_TB(op_test_lt, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_gt(void)
|
void OPPROTO op_test_gt(void)
|
||||||
{
|
{
|
||||||
if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0)
|
if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0)
|
||||||
JUMP_TB(op_test_gt, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_test_le(void)
|
void OPPROTO op_test_le(void)
|
||||||
{
|
{
|
||||||
if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0)
|
if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0)
|
||||||
JUMP_TB(op_test_le, PARAM1, 0, PARAM2);
|
GOTO_LABEL_PARAM(1);
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_jmp(void)
|
void OPPROTO op_jmp0(void)
|
||||||
{
|
{
|
||||||
JUMP_TB(op_jmp, PARAM1, 1, PARAM2);
|
JUMP_TB(op_jmp0, PARAM1, 0, PARAM2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_jmp1(void)
|
||||||
|
{
|
||||||
|
JUMP_TB(op_jmp1, PARAM1, 1, PARAM2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_exit_tb(void)
|
void OPPROTO op_exit_tb(void)
|
||||||
|
@ -32,6 +32,10 @@
|
|||||||
typedef struct DisasContext {
|
typedef struct DisasContext {
|
||||||
target_ulong pc;
|
target_ulong pc;
|
||||||
int is_jmp;
|
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. */
|
||||||
|
int condlabel;
|
||||||
struct TranslationBlock *tb;
|
struct TranslationBlock *tb;
|
||||||
int singlestep_enabled;
|
int singlestep_enabled;
|
||||||
} DisasContext;
|
} DisasContext;
|
||||||
@ -53,7 +57,7 @@ enum {
|
|||||||
|
|
||||||
#include "gen-op.h"
|
#include "gen-op.h"
|
||||||
|
|
||||||
static GenOpFunc2 *gen_test_cc[14] = {
|
static GenOpFunc1 *gen_test_cc[14] = {
|
||||||
gen_op_test_eq,
|
gen_op_test_eq,
|
||||||
gen_op_test_ne,
|
gen_op_test_ne,
|
||||||
gen_op_test_cs,
|
gen_op_test_cs,
|
||||||
@ -896,7 +900,7 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest)
|
|||||||
gen_op_movl_T0_im(dest);
|
gen_op_movl_T0_im(dest);
|
||||||
gen_bx(s);
|
gen_bx(s);
|
||||||
} else {
|
} else {
|
||||||
gen_op_jmp((long)s->tb, dest);
|
gen_op_jmp0((long)s->tb, dest);
|
||||||
s->is_jmp = DISAS_TB_JUMP;
|
s->is_jmp = DISAS_TB_JUMP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -939,8 +943,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
|||||||
if (cond != 0xe) {
|
if (cond != 0xe) {
|
||||||
/* if not always execute, we generate a conditional jump to
|
/* if not always execute, we generate a conditional jump to
|
||||||
next instruction */
|
next instruction */
|
||||||
gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
|
s->condlabel = gen_new_label();
|
||||||
s->is_jmp = DISAS_JUMP_NEXT;
|
gen_test_cc[cond ^ 1](s->condlabel);
|
||||||
|
s->condjmp = 1;
|
||||||
|
//gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
|
||||||
|
//s->is_jmp = DISAS_JUMP_NEXT;
|
||||||
}
|
}
|
||||||
if ((insn & 0x0f900000) == 0x03000000) {
|
if ((insn & 0x0f900000) == 0x03000000) {
|
||||||
if ((insn & 0x0ff0f000) != 0x0360f000)
|
if ((insn & 0x0ff0f000) != 0x0360f000)
|
||||||
@ -1961,8 +1968,11 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* generate a conditional jump to next instruction */
|
/* generate a conditional jump to next instruction */
|
||||||
gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
|
s->condlabel = gen_new_label();
|
||||||
s->is_jmp = DISAS_JUMP_NEXT;
|
gen_test_cc[cond ^ 1](s->condlabel);
|
||||||
|
s->condjmp = 1;
|
||||||
|
//gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
|
||||||
|
//s->is_jmp = DISAS_JUMP_NEXT;
|
||||||
gen_movl_T1_reg(s, 15);
|
gen_movl_T1_reg(s, 15);
|
||||||
|
|
||||||
/* jump to the offset */
|
/* jump to the offset */
|
||||||
@ -2034,6 +2044,8 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
|||||||
dc->is_jmp = DISAS_NEXT;
|
dc->is_jmp = DISAS_NEXT;
|
||||||
dc->pc = pc_start;
|
dc->pc = pc_start;
|
||||||
dc->singlestep_enabled = env->singlestep_enabled;
|
dc->singlestep_enabled = env->singlestep_enabled;
|
||||||
|
dc->condjmp = 0;
|
||||||
|
nb_gen_labels = 0;
|
||||||
lj = -1;
|
lj = -1;
|
||||||
do {
|
do {
|
||||||
if (env->nb_breakpoints > 0) {
|
if (env->nb_breakpoints > 0) {
|
||||||
@ -2057,25 +2069,41 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
|||||||
gen_opc_pc[lj] = dc->pc;
|
gen_opc_pc[lj] = dc->pc;
|
||||||
gen_opc_instr_start[lj] = 1;
|
gen_opc_instr_start[lj] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env->thumb)
|
if (env->thumb)
|
||||||
disas_thumb_insn(dc);
|
disas_thumb_insn(dc);
|
||||||
else
|
else
|
||||||
disas_arm_insn(env, dc);
|
disas_arm_insn(env, dc);
|
||||||
|
|
||||||
|
if (dc->condjmp && !dc->is_jmp) {
|
||||||
|
gen_set_label(dc->condlabel);
|
||||||
|
dc->condjmp = 0;
|
||||||
|
}
|
||||||
|
/* Translation stops when a conditional branch is enoutered.
|
||||||
|
* Otherwise the subsequent code could get translated several times.
|
||||||
|
*/
|
||||||
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
|
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
|
||||||
!env->singlestep_enabled &&
|
!env->singlestep_enabled &&
|
||||||
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||||
|
/* It this stage dc->condjmp will only be set when the skipped
|
||||||
|
* instruction was a conditional branch, and teh PC has already been
|
||||||
|
* written. */
|
||||||
if (__builtin_expect(env->singlestep_enabled, 0)) {
|
if (__builtin_expect(env->singlestep_enabled, 0)) {
|
||||||
/* Make sure the pc is updated, and raise a debug exception. */
|
/* Make sure the pc is updated, and raise a debug exception. */
|
||||||
if (dc->is_jmp == DISAS_NEXT || dc->is_jmp == DISAS_JUMP_NEXT) {
|
if (dc->condjmp) {
|
||||||
|
gen_op_debug();
|
||||||
|
gen_set_label(dc->condlabel);
|
||||||
|
}
|
||||||
|
if (dc->condjmp || !dc->is_jmp) {
|
||||||
gen_op_movl_T0_im((long)dc->pc);
|
gen_op_movl_T0_im((long)dc->pc);
|
||||||
gen_op_movl_reg_TN[0][15]();
|
gen_op_movl_reg_TN[0][15]();
|
||||||
|
dc->condjmp = 0;
|
||||||
}
|
}
|
||||||
gen_op_debug();
|
gen_op_debug();
|
||||||
} else {
|
} else {
|
||||||
switch(dc->is_jmp) {
|
switch(dc->is_jmp) {
|
||||||
case DISAS_JUMP_NEXT:
|
|
||||||
case DISAS_NEXT:
|
case DISAS_NEXT:
|
||||||
gen_op_jmp((long)dc->tb, (long)dc->pc);
|
gen_op_jmp1((long)dc->tb, (long)dc->pc);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case DISAS_JUMP:
|
case DISAS_JUMP:
|
||||||
@ -2088,6 +2116,11 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
|||||||
/* nothing more to generate */
|
/* nothing more to generate */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (dc->condjmp) {
|
||||||
|
gen_set_label(dc->condlabel);
|
||||||
|
gen_op_jmp1((long)dc->tb, (long)dc->pc);
|
||||||
|
dc->condjmp = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*gen_opc_ptr = INDEX_op_end;
|
*gen_opc_ptr = INDEX_op_end;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user