SH4 delay slot code update, by Magnus Damm.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3761 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
a36e69ddfe
commit
823029f909
@ -202,8 +202,8 @@ static inline TranslationBlock *tb_find_fast(void)
|
||||
cs_base = 0;
|
||||
pc = env->pc;
|
||||
#elif defined(TARGET_SH4)
|
||||
flags = env->sr & (SR_MD | SR_RB);
|
||||
cs_base = 0; /* XXXXX */
|
||||
flags = env->flags;
|
||||
cs_base = 0;
|
||||
pc = env->pc;
|
||||
#elif defined(TARGET_ALPHA)
|
||||
flags = env->ps;
|
||||
|
@ -46,16 +46,16 @@
|
||||
#define FPSCR_SZ (1 << 20)
|
||||
#define FPSCR_PR (1 << 19)
|
||||
#define FPSCR_DN (1 << 18)
|
||||
|
||||
#define DELAY_SLOT (1 << 0) /* Must be the same as SR_T. */
|
||||
/* This flag is set if the next insn is a delay slot for a conditional jump.
|
||||
The dynamic value of the DELAY_SLOT determines whether the jup is taken. */
|
||||
#define DELAY_SLOT (1 << 0)
|
||||
#define DELAY_SLOT_CONDITIONAL (1 << 1)
|
||||
/* Those are used in contexts only */
|
||||
#define BRANCH (1 << 2)
|
||||
#define BRANCH_CONDITIONAL (1 << 3)
|
||||
#define MODE_CHANGE (1 << 4) /* Potential MD|RB change */
|
||||
#define BRANCH_EXCEPTION (1 << 5) /* Branch after exception */
|
||||
#define DELAY_SLOT_TRUE (1 << 2)
|
||||
#define DELAY_SLOT_CLEARME (1 << 3)
|
||||
/* The dynamic value of the DELAY_SLOT_TRUE flag determines whether the jump
|
||||
* after the delay slot should be taken or not. It is calculated from SR_T.
|
||||
*
|
||||
* It is unclear if it is permitted to modify the SR_T flag in a delay slot.
|
||||
* The use of DELAY_SLOT_TRUE flag makes us accept such SR_T modification.
|
||||
*/
|
||||
|
||||
/* XXXXX The structure could be made more compact */
|
||||
typedef struct tlb_t {
|
||||
|
@ -19,16 +19,6 @@
|
||||
*/
|
||||
#include "exec.h"
|
||||
|
||||
static inline void set_flag(uint32_t flag)
|
||||
{
|
||||
env->flags |= flag;
|
||||
}
|
||||
|
||||
static inline void clr_flag(uint32_t flag)
|
||||
{
|
||||
env->flags &= ~flag;
|
||||
}
|
||||
|
||||
static inline void set_t(void)
|
||||
{
|
||||
env->sr |= SR_T;
|
||||
@ -110,28 +100,37 @@ void OPPROTO op_not_T0(void)
|
||||
void OPPROTO op_bf_s(void)
|
||||
{
|
||||
env->delayed_pc = PARAM1;
|
||||
set_flag(DELAY_SLOT_CONDITIONAL | ((~env->sr) & SR_T));
|
||||
if (!(env->sr & SR_T)) {
|
||||
env->flags |= DELAY_SLOT_TRUE;
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_bt_s(void)
|
||||
{
|
||||
env->delayed_pc = PARAM1;
|
||||
set_flag(DELAY_SLOT_CONDITIONAL | (env->sr & SR_T));
|
||||
if (env->sr & SR_T) {
|
||||
env->flags |= DELAY_SLOT_TRUE;
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_store_flags(void)
|
||||
{
|
||||
env->flags &= DELAY_SLOT_TRUE;
|
||||
env->flags |= PARAM1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_bra(void)
|
||||
{
|
||||
env->delayed_pc = PARAM1;
|
||||
set_flag(DELAY_SLOT);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_braf_T0(void)
|
||||
{
|
||||
env->delayed_pc = PARAM1 + T0;
|
||||
set_flag(DELAY_SLOT);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -139,7 +138,6 @@ void OPPROTO op_bsr(void)
|
||||
{
|
||||
env->pr = PARAM1;
|
||||
env->delayed_pc = PARAM2;
|
||||
set_flag(DELAY_SLOT);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -147,7 +145,6 @@ void OPPROTO op_bsrf_T0(void)
|
||||
{
|
||||
env->pr = PARAM1;
|
||||
env->delayed_pc = PARAM1 + T0;
|
||||
set_flag(DELAY_SLOT);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -155,26 +152,12 @@ void OPPROTO op_jsr_T0(void)
|
||||
{
|
||||
env->pr = PARAM1;
|
||||
env->delayed_pc = T0;
|
||||
set_flag(DELAY_SLOT);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_rts(void)
|
||||
{
|
||||
env->delayed_pc = env->pr;
|
||||
set_flag(DELAY_SLOT);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_clr_delay_slot(void)
|
||||
{
|
||||
clr_flag(DELAY_SLOT);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_clr_delay_slot_conditional(void)
|
||||
{
|
||||
clr_flag(DELAY_SLOT_CONDITIONAL);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -242,7 +225,6 @@ void OPPROTO op_rte(void)
|
||||
{
|
||||
env->sr = env->ssr;
|
||||
env->delayed_pc = env->spc;
|
||||
set_flag(DELAY_SLOT);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -458,7 +440,6 @@ void OPPROTO op_cmp_pz_T0(void)
|
||||
void OPPROTO op_jmp_T0(void)
|
||||
{
|
||||
env->delayed_pc = T0;
|
||||
set_flag(DELAY_SLOT);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -993,11 +974,10 @@ void OPPROTO op_jT(void)
|
||||
|
||||
void OPPROTO op_jdelayed(void)
|
||||
{
|
||||
uint32_t flags;
|
||||
flags = env->flags;
|
||||
env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
|
||||
if (flags & DELAY_SLOT)
|
||||
GOTO_LABEL_PARAM(1);
|
||||
if (env->flags & DELAY_SLOT_TRUE) {
|
||||
env->flags &= ~DELAY_SLOT_TRUE;
|
||||
GOTO_LABEL_PARAM(1);
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -57,11 +57,21 @@ typedef struct DisasContext {
|
||||
uint32_t fpscr;
|
||||
uint16_t opcode;
|
||||
uint32_t flags;
|
||||
int bstate;
|
||||
int memidx;
|
||||
uint32_t delayed_pc;
|
||||
int singlestep_enabled;
|
||||
} DisasContext;
|
||||
|
||||
enum {
|
||||
BS_NONE = 0, /* We go out of the TB without reaching a branch or an
|
||||
* exception condition
|
||||
*/
|
||||
BS_STOP = 1, /* We want to stop translation for any reason */
|
||||
BS_BRANCH = 2, /* We reached a branch condition */
|
||||
BS_EXCP = 3, /* We reached an exception condition */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
|
||||
#define GEN_OP_LD(width, reg) \
|
||||
@ -176,15 +186,6 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest)
|
||||
gen_op_exit_tb();
|
||||
}
|
||||
|
||||
/* Jump to pc after an exception */
|
||||
static void gen_jump_exception(DisasContext * ctx)
|
||||
{
|
||||
gen_op_movl_imm_T0(0);
|
||||
if (ctx->singlestep_enabled)
|
||||
gen_op_debug();
|
||||
gen_op_exit_tb();
|
||||
}
|
||||
|
||||
static void gen_jump(DisasContext * ctx)
|
||||
{
|
||||
if (ctx->delayed_pc == (uint32_t) - 1) {
|
||||
@ -220,7 +221,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
|
||||
|
||||
l1 = gen_new_label();
|
||||
gen_op_jdelayed(l1);
|
||||
gen_goto_tb(ctx, 1, ctx->pc);
|
||||
gen_goto_tb(ctx, 1, ctx->pc + 2);
|
||||
gen_set_label(l1);
|
||||
gen_jump(ctx);
|
||||
}
|
||||
@ -248,10 +249,10 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
|
||||
|
||||
#define CHECK_NOT_DELAY_SLOT \
|
||||
if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
|
||||
{gen_op_raise_slot_illegal_instruction (); ctx->flags |= BRANCH_EXCEPTION; \
|
||||
{gen_op_raise_slot_illegal_instruction (); ctx->bstate = BS_EXCP; \
|
||||
return;}
|
||||
|
||||
void decode_opc(DisasContext * ctx)
|
||||
void _decode_opc(DisasContext * ctx)
|
||||
{
|
||||
#if 0
|
||||
fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode);
|
||||
@ -290,11 +291,11 @@ void decode_opc(DisasContext * ctx)
|
||||
return;
|
||||
case 0xfbfb: /* frchg */
|
||||
gen_op_frchg();
|
||||
ctx->flags |= MODE_CHANGE;
|
||||
ctx->bstate = BS_STOP;
|
||||
return;
|
||||
case 0xf3fb: /* fschg */
|
||||
gen_op_fschg();
|
||||
ctx->flags |= MODE_CHANGE;
|
||||
ctx->bstate = BS_STOP;
|
||||
return;
|
||||
case 0x0009: /* nop */
|
||||
return;
|
||||
@ -805,7 +806,7 @@ void decode_opc(DisasContext * ctx)
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
gen_conditional_jump(ctx, ctx->pc + 2,
|
||||
ctx->pc + 4 + B7_0s * 2);
|
||||
ctx->flags |= BRANCH_CONDITIONAL;
|
||||
ctx->bstate = BS_BRANCH;
|
||||
return;
|
||||
case 0x8f00: /* bf/s label */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
@ -816,7 +817,7 @@ void decode_opc(DisasContext * ctx)
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2,
|
||||
ctx->pc + 2);
|
||||
ctx->flags |= BRANCH_CONDITIONAL;
|
||||
ctx->bstate = BS_BRANCH;
|
||||
return;
|
||||
case 0x8d00: /* bt/s label */
|
||||
CHECK_NOT_DELAY_SLOT
|
||||
@ -908,7 +909,7 @@ void decode_opc(DisasContext * ctx)
|
||||
case 0xc300: /* trapa #imm */
|
||||
CHECK_NOT_DELAY_SLOT gen_op_movl_imm_PC(ctx->pc);
|
||||
gen_op_trapa(B7_0);
|
||||
ctx->flags |= BRANCH;
|
||||
ctx->bstate = BS_BRANCH;
|
||||
return;
|
||||
case 0xc800: /* tst #imm,R0 */
|
||||
gen_op_tst_imm_rN(B7_0, REG(0));
|
||||
@ -1012,8 +1013,8 @@ void decode_opc(DisasContext * ctx)
|
||||
gen_op_movl_rN_T1 (REG(B11_8)); \
|
||||
gen_op_stl_T0_T1 (ctx); \
|
||||
return;
|
||||
LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->flags |=
|
||||
MODE_CHANGE;)
|
||||
LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->bstate =
|
||||
BS_STOP;)
|
||||
LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,)
|
||||
LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,)
|
||||
LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,)
|
||||
@ -1023,8 +1024,8 @@ void decode_opc(DisasContext * ctx)
|
||||
LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,)
|
||||
LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,)
|
||||
LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,)
|
||||
LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->flags |=
|
||||
MODE_CHANGE;)
|
||||
LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->bstate =
|
||||
BS_STOP;)
|
||||
case 0x00c3: /* movca.l R0,@Rm */
|
||||
gen_op_movl_rN_T0(REG(0));
|
||||
gen_op_movl_rN_T1(REG(B11_8));
|
||||
@ -1141,7 +1142,28 @@ void decode_opc(DisasContext * ctx)
|
||||
fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
|
||||
ctx->opcode, ctx->pc);
|
||||
gen_op_raise_illegal_instruction();
|
||||
ctx->flags |= BRANCH_EXCEPTION;
|
||||
ctx->bstate = BS_EXCP;
|
||||
}
|
||||
|
||||
void decode_opc(DisasContext * ctx)
|
||||
{
|
||||
uint32_t old_flags = ctx->flags;
|
||||
|
||||
_decode_opc(ctx);
|
||||
|
||||
if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) {
|
||||
if (ctx->flags & DELAY_SLOT_CLEARME) {
|
||||
gen_op_store_flags(0);
|
||||
}
|
||||
ctx->flags = 0;
|
||||
ctx->bstate = BS_BRANCH;
|
||||
if (old_flags & DELAY_SLOT_CONDITIONAL) {
|
||||
gen_delayed_conditional_jump(ctx);
|
||||
} else if (old_flags & DELAY_SLOT) {
|
||||
gen_jump(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -1151,7 +1173,6 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
DisasContext ctx;
|
||||
target_ulong pc_start;
|
||||
static uint16_t *gen_opc_end;
|
||||
uint32_t old_flags;
|
||||
int i, ii;
|
||||
|
||||
pc_start = tb->pc;
|
||||
@ -1159,14 +1180,14 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
ctx.pc = pc_start;
|
||||
ctx.flags = env->flags;
|
||||
old_flags = 0;
|
||||
ctx.flags = (uint32_t)tb->flags;
|
||||
ctx.bstate = BS_NONE;
|
||||
ctx.sr = env->sr;
|
||||
ctx.fpscr = env->fpscr;
|
||||
ctx.memidx = (env->sr & SR_MD) ? 1 : 0;
|
||||
/* We don't know if the delayed pc came from a dynamic or static branch,
|
||||
so assume it is a dynamic branch. */
|
||||
ctx.delayed_pc = -1;
|
||||
ctx.delayed_pc = -1; /* use delayed pc from env pointer */
|
||||
ctx.tb = tb;
|
||||
ctx.singlestep_enabled = env->singlestep_enabled;
|
||||
nb_gen_labels = 0;
|
||||
@ -1180,18 +1201,14 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
#endif
|
||||
|
||||
ii = -1;
|
||||
while ((old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) == 0 &&
|
||||
(ctx.flags & (BRANCH | BRANCH_CONDITIONAL | MODE_CHANGE |
|
||||
BRANCH_EXCEPTION)) == 0 &&
|
||||
gen_opc_ptr < gen_opc_end && ctx.sr == env->sr) {
|
||||
old_flags = ctx.flags;
|
||||
while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
|
||||
if (env->nb_breakpoints > 0) {
|
||||
for (i = 0; i < env->nb_breakpoints; i++) {
|
||||
if (ctx.pc == env->breakpoints[i]) {
|
||||
/* We have hit a breakpoint - make sure PC is up-to-date */
|
||||
gen_op_movl_imm_PC(ctx.pc);
|
||||
gen_op_debug();
|
||||
ctx.flags |= BRANCH_EXCEPTION;
|
||||
ctx.bstate = BS_EXCP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1204,6 +1221,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
gen_opc_instr_start[ii++] = 0;
|
||||
}
|
||||
gen_opc_pc[ii] = ctx.pc;
|
||||
gen_opc_hflags[ii] = ctx.flags;
|
||||
gen_opc_instr_start[ii] = 1;
|
||||
}
|
||||
#if 0
|
||||
@ -1221,21 +1239,30 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (old_flags & DELAY_SLOT_CONDITIONAL) {
|
||||
gen_delayed_conditional_jump(&ctx);
|
||||
} else if (old_flags & DELAY_SLOT) {
|
||||
gen_op_clr_delay_slot();
|
||||
gen_jump(&ctx);
|
||||
} else if (ctx.flags & BRANCH_EXCEPTION) {
|
||||
gen_jump_exception(&ctx);
|
||||
} else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) {
|
||||
gen_goto_tb(&ctx, 0, ctx.pc);
|
||||
}
|
||||
|
||||
if (env->singlestep_enabled) {
|
||||
gen_op_debug();
|
||||
gen_op_debug();
|
||||
} else {
|
||||
switch (ctx.bstate) {
|
||||
case BS_STOP:
|
||||
/* gen_op_interrupt_restart(); */
|
||||
/* fall through */
|
||||
case BS_NONE:
|
||||
if (ctx.flags) {
|
||||
gen_op_store_flags(ctx.flags | DELAY_SLOT_CLEARME);
|
||||
}
|
||||
gen_goto_tb(&ctx, 0, ctx.pc);
|
||||
break;
|
||||
case BS_EXCP:
|
||||
/* gen_op_interrupt_restart(); */
|
||||
gen_op_movl_imm_T0(0);
|
||||
gen_op_exit_tb();
|
||||
break;
|
||||
case BS_BRANCH:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
if (search_pc) {
|
||||
i = gen_opc_ptr - gen_opc_buf;
|
||||
|
@ -53,7 +53,7 @@ uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||
#elif defined(TARGET_SPARC)
|
||||
target_ulong gen_opc_npc[OPC_BUF_SIZE];
|
||||
target_ulong gen_opc_jump_pc[2];
|
||||
#elif defined(TARGET_MIPS)
|
||||
#elif defined(TARGET_MIPS) || defined(TARGET_SH4)
|
||||
uint32_t gen_opc_hflags[OPC_BUF_SIZE];
|
||||
#endif
|
||||
|
||||
@ -298,6 +298,9 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
env->hflags |= gen_opc_hflags[j];
|
||||
#elif defined(TARGET_ALPHA)
|
||||
env->pc = gen_opc_pc[j];
|
||||
#elif defined(TARGET_SH4)
|
||||
env->pc = gen_opc_pc[j];
|
||||
env->flags = gen_opc_hflags[j];
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user