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:
ths 2007-12-02 06:10:04 +00:00
parent a36e69ddfe
commit 823029f909
5 changed files with 104 additions and 94 deletions

View File

@ -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;

View File

@ -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 {

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}