mirror of https://github.com/xemu-project/xemu.git
direct chaining support for SPARC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@607 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
34f715e754
commit
72cbca10e1
|
@ -643,6 +643,36 @@ void OPPROTO op_next_insn(void)
|
||||||
env->npc = env->npc + 4;
|
env->npc = env->npc + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_branch(void)
|
||||||
|
{
|
||||||
|
env->npc = PARAM3; /* XXX: optimize */
|
||||||
|
JUMP_TB(op_branch, PARAM1, 0, PARAM2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_branch2(void)
|
||||||
|
{
|
||||||
|
if (T2) {
|
||||||
|
env->npc = PARAM2 + 4;
|
||||||
|
JUMP_TB(op_branch2, PARAM1, 0, PARAM2);
|
||||||
|
} else {
|
||||||
|
env->npc = PARAM3 + 4;
|
||||||
|
JUMP_TB(op_branch2, PARAM1, 1, PARAM3);
|
||||||
|
}
|
||||||
|
FORCE_RET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_branch_a(void)
|
||||||
|
{
|
||||||
|
if (T2) {
|
||||||
|
env->npc = PARAM2; /* XXX: optimize */
|
||||||
|
JUMP_TB(op_generic_branch_a, PARAM1, 0, PARAM3);
|
||||||
|
} else {
|
||||||
|
env->npc = PARAM3 + 8; /* XXX: optimize */
|
||||||
|
JUMP_TB(op_generic_branch_a, PARAM1, 1, PARAM3 + 4);
|
||||||
|
}
|
||||||
|
FORCE_RET();
|
||||||
|
}
|
||||||
|
|
||||||
void OPPROTO op_generic_branch(void)
|
void OPPROTO op_generic_branch(void)
|
||||||
{
|
{
|
||||||
if (T2) {
|
if (T2) {
|
||||||
|
@ -653,14 +683,3 @@ void OPPROTO op_generic_branch(void)
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_generic_branch_a(void)
|
|
||||||
{
|
|
||||||
if (T2) {
|
|
||||||
env->pc = PARAM2;
|
|
||||||
env->npc = PARAM1;
|
|
||||||
} else {
|
|
||||||
env->pc = PARAM2 + 4;
|
|
||||||
env->npc = PARAM2 + 8;
|
|
||||||
}
|
|
||||||
FORCE_RET();
|
|
||||||
}
|
|
||||||
|
|
|
@ -42,9 +42,14 @@
|
||||||
|
|
||||||
#define DEBUG_DISAS
|
#define DEBUG_DISAS
|
||||||
|
|
||||||
|
#define DYNAMIC_PC 1 /* dynamic pc value */
|
||||||
|
#define JUMP_PC 2 /* dynamic pc value which takes only two values
|
||||||
|
according to jump_pc[T2] */
|
||||||
|
|
||||||
typedef struct DisasContext {
|
typedef struct DisasContext {
|
||||||
uint8_t *pc; /* NULL means dynamic value */
|
target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */
|
||||||
uint8_t *npc; /* NULL means dynamic value */
|
target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */
|
||||||
|
target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */
|
||||||
int is_br;
|
int is_br;
|
||||||
struct TranslationBlock *tb;
|
struct TranslationBlock *tb;
|
||||||
} DisasContext;
|
} DisasContext;
|
||||||
|
@ -306,6 +311,31 @@ static inline void gen_movl_T1_reg(int reg)
|
||||||
gen_movl_TN_reg(reg, 1);
|
gen_movl_TN_reg(reg, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* call this function before using T2 as it may have been set for a jump */
|
||||||
|
static inline void flush_T2(DisasContext * dc)
|
||||||
|
{
|
||||||
|
if (dc->npc == JUMP_PC) {
|
||||||
|
gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
|
||||||
|
dc->npc = DYNAMIC_PC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void save_npc(DisasContext * dc)
|
||||||
|
{
|
||||||
|
if (dc->npc == JUMP_PC) {
|
||||||
|
gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
|
||||||
|
dc->npc = DYNAMIC_PC;
|
||||||
|
} else if (dc->npc != DYNAMIC_PC) {
|
||||||
|
gen_op_movl_npc_im(dc->npc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void save_state(DisasContext * dc)
|
||||||
|
{
|
||||||
|
gen_op_jmp_im((uint32_t)dc->pc);
|
||||||
|
save_npc(dc);
|
||||||
|
}
|
||||||
|
|
||||||
static void gen_cond(int cond)
|
static void gen_cond(int cond)
|
||||||
{
|
{
|
||||||
switch (cond) {
|
switch (cond) {
|
||||||
|
@ -378,25 +408,23 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn)
|
||||||
} else if (cond == 0x8) {
|
} else if (cond == 0x8) {
|
||||||
/* unconditional taken */
|
/* unconditional taken */
|
||||||
if (a) {
|
if (a) {
|
||||||
dc->pc = (uint8_t *) target;
|
dc->pc = target;
|
||||||
dc->npc = dc->pc + 4;
|
dc->npc = dc->pc + 4;
|
||||||
} else {
|
} else {
|
||||||
dc->pc = dc->npc;
|
dc->pc = dc->npc;
|
||||||
dc->npc = (uint8_t *) target;
|
dc->npc = target;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
flush_T2(dc);
|
||||||
gen_cond(cond);
|
gen_cond(cond);
|
||||||
if (a) {
|
if (a) {
|
||||||
gen_op_generic_branch_a((uint32_t) target,
|
gen_op_branch_a((long)dc->tb, target, dc->npc);
|
||||||
(uint32_t) (dc->npc));
|
|
||||||
dc->is_br = 1;
|
dc->is_br = 1;
|
||||||
dc->pc = NULL;
|
|
||||||
dc->npc = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
dc->pc = dc->npc;
|
dc->pc = dc->npc;
|
||||||
gen_op_generic_branch((uint32_t) target,
|
dc->jump_pc[0] = target;
|
||||||
(uint32_t) (dc->npc + 4));
|
dc->jump_pc[1] = dc->npc + 4;
|
||||||
dc->npc = NULL;
|
dc->npc = JUMP_PC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,18 +437,11 @@ static int sign_extend(int x, int len)
|
||||||
return (x << len) >> len;
|
return (x << len) >> len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void save_state(DisasContext * dc)
|
|
||||||
{
|
|
||||||
gen_op_jmp_im((uint32_t)dc->pc);
|
|
||||||
if (dc->npc != NULL)
|
|
||||||
gen_op_movl_npc_im((long) dc->npc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void disas_sparc_insn(DisasContext * dc)
|
static void disas_sparc_insn(DisasContext * dc)
|
||||||
{
|
{
|
||||||
unsigned int insn, opc, rs1, rs2, rd;
|
unsigned int insn, opc, rs1, rs2, rd;
|
||||||
|
|
||||||
insn = ldl_code(dc->pc);
|
insn = ldl_code((uint8_t *)dc->pc);
|
||||||
opc = GET_FIELD(insn, 0, 1);
|
opc = GET_FIELD(insn, 0, 1);
|
||||||
|
|
||||||
rd = GET_FIELD(insn, 2, 6);
|
rd = GET_FIELD(insn, 2, 6);
|
||||||
|
@ -458,9 +479,9 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
|
|
||||||
gen_op_movl_T0_im((long) (dc->pc));
|
gen_op_movl_T0_im((long) (dc->pc));
|
||||||
gen_movl_T0_reg(15);
|
gen_movl_T0_reg(15);
|
||||||
target = (long) dc->pc + target;
|
target = dc->pc + target;
|
||||||
dc->pc = dc->npc;
|
dc->pc = dc->npc;
|
||||||
dc->npc = (uint8_t *) target;
|
dc->npc = target;
|
||||||
}
|
}
|
||||||
goto jmp_insn;
|
goto jmp_insn;
|
||||||
case 2: /* FPU & Logical Operations */
|
case 2: /* FPU & Logical Operations */
|
||||||
|
@ -625,7 +646,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_movl_T0_reg(rd);
|
gen_movl_T0_reg(rd);
|
||||||
}
|
}
|
||||||
dc->pc = dc->npc;
|
dc->pc = dc->npc;
|
||||||
dc->npc = NULL;
|
dc->npc = DYNAMIC_PC;
|
||||||
}
|
}
|
||||||
goto jmp_insn;
|
goto jmp_insn;
|
||||||
case 0x3b: /* flush */
|
case 0x3b: /* flush */
|
||||||
|
@ -705,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_sth();
|
gen_op_sth();
|
||||||
break;
|
break;
|
||||||
case 0x7:
|
case 0x7:
|
||||||
|
flush_T2(dc);
|
||||||
gen_movl_reg_T2(rd + 1);
|
gen_movl_reg_T2(rd + 1);
|
||||||
gen_op_std();
|
gen_op_std();
|
||||||
break;
|
break;
|
||||||
|
@ -713,19 +735,21 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* default case for non jump instructions */
|
/* default case for non jump instructions */
|
||||||
if (dc->npc != NULL) {
|
if (dc->npc == DYNAMIC_PC) {
|
||||||
|
dc->pc = DYNAMIC_PC;
|
||||||
|
gen_op_next_insn();
|
||||||
|
} else if (dc->npc == JUMP_PC) {
|
||||||
|
/* we can do a static jump */
|
||||||
|
gen_op_branch2((long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]);
|
||||||
|
dc->is_br = 1;
|
||||||
|
} else {
|
||||||
dc->pc = dc->npc;
|
dc->pc = dc->npc;
|
||||||
dc->npc = dc->npc + 4;
|
dc->npc = dc->npc + 4;
|
||||||
} else {
|
|
||||||
dc->pc = NULL;
|
|
||||||
gen_op_next_insn();
|
|
||||||
}
|
}
|
||||||
jmp_insn:;
|
jmp_insn:;
|
||||||
return;
|
return;
|
||||||
illegal_insn:
|
illegal_insn:
|
||||||
gen_op_jmp_im((uint32_t)dc->pc);
|
save_state(dc);
|
||||||
if (dc->npc != NULL)
|
|
||||||
gen_op_movl_npc_im((long) dc->npc);
|
|
||||||
gen_op_exception(TT_ILL_INSN);
|
gen_op_exception(TT_ILL_INSN);
|
||||||
dc->is_br = 1;
|
dc->is_br = 1;
|
||||||
}
|
}
|
||||||
|
@ -733,7 +757,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||||
int spc)
|
int spc)
|
||||||
{
|
{
|
||||||
uint8_t *pc_start, *last_pc;
|
target_ulong pc_start, last_pc;
|
||||||
uint16_t *gen_opc_end;
|
uint16_t *gen_opc_end;
|
||||||
DisasContext dc1, *dc = &dc1;
|
DisasContext dc1, *dc = &dc1;
|
||||||
|
|
||||||
|
@ -743,9 +767,9 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
dc->tb = tb;
|
dc->tb = tb;
|
||||||
pc_start = (uint8_t *) tb->pc;
|
pc_start = tb->pc;
|
||||||
dc->pc = pc_start;
|
dc->pc = pc_start;
|
||||||
dc->npc = (uint8_t *) tb->cs_base;
|
dc->npc = (target_ulong) tb->cs_base;
|
||||||
|
|
||||||
gen_opc_ptr = gen_opc_buf;
|
gen_opc_ptr = gen_opc_buf;
|
||||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||||
|
@ -761,19 +785,25 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||||
break;
|
break;
|
||||||
} while ((gen_opc_ptr < gen_opc_end) &&
|
} while ((gen_opc_ptr < gen_opc_end) &&
|
||||||
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||||
if (dc->pc != NULL)
|
if (!dc->is_br) {
|
||||||
gen_op_jmp_im((long) dc->pc);
|
if (dc->pc != DYNAMIC_PC &&
|
||||||
if (dc->npc != NULL)
|
(dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
|
||||||
gen_op_movl_npc_im((long) dc->npc);
|
/* static PC and NPC: we can use direct chaining */
|
||||||
gen_op_movl_T0_0();
|
gen_op_branch((long)tb, dc->pc, dc->npc);
|
||||||
gen_op_exit_tb();
|
} else {
|
||||||
|
if (dc->pc != DYNAMIC_PC)
|
||||||
|
gen_op_jmp_im(dc->pc);
|
||||||
|
save_npc(dc);
|
||||||
|
gen_op_movl_T0_0();
|
||||||
|
gen_op_exit_tb();
|
||||||
|
}
|
||||||
|
}
|
||||||
*gen_opc_ptr = INDEX_op_end;
|
*gen_opc_ptr = INDEX_op_end;
|
||||||
#ifdef DEBUG_DISAS
|
#ifdef DEBUG_DISAS
|
||||||
if (loglevel) {
|
if (loglevel) {
|
||||||
fprintf(logfile, "--------------\n");
|
fprintf(logfile, "--------------\n");
|
||||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
fprintf(logfile, "IN: %s\n", lookup_symbol((uint8_t *)pc_start));
|
||||||
disas(logfile, pc_start, last_pc + 4 - pc_start, 0, 0);
|
disas(logfile, (uint8_t *)pc_start, last_pc + 4 - pc_start, 0, 0);
|
||||||
fprintf(logfile, "\n");
|
fprintf(logfile, "\n");
|
||||||
fprintf(logfile, "OP:\n");
|
fprintf(logfile, "OP:\n");
|
||||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||||
|
|
Loading…
Reference in New Issue