/*
* SH4 translation
- *
+ *
* Copyright (c) 2005 Samuel Tardieu
*
* This library is free software; you can redistribute it and/or
void cpu_sh4_reset(CPUSH4State * env)
{
+#if defined(CONFIG_USER_ONLY)
+ env->sr = SR_FD; /* FD - kernel does lazy fpu context switch */
+#else
env->sr = 0x700000F0; /* MD, RB, BL, I3-I0 */
+#endif
env->vbr = 0;
env->pc = 0xA0000000;
- env->fpscr = 0x00040001;
+#if defined(CONFIG_USER_ONLY)
+ env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */
+ env->fp_status.float_rounding_mode = float_round_nearest_even; /* ?! */
+#else
+ env->fpscr = 0x00040001; /* CPU reset value according to SH4 manual */
+ env->fp_status.float_rounding_mode = float_round_to_zero;
+#endif
env->mmucr = 0;
}
-CPUSH4State *cpu_sh4_init(void)
+CPUSH4State *cpu_sh4_init(const char *cpu_model)
{
CPUSH4State *env;
int l1;
l1 = gen_new_label();
- gen_op_jTT2(l1);
- gen_goto_tb(ctx, 0, ctx->pc);
+ gen_op_jdelayed(l1);
+ gen_goto_tb(ctx, 1, ctx->pc);
gen_set_label(l1);
- gen_goto_tb(ctx, 1, ctx->delayed_pc);
+ gen_jump(ctx);
}
#define B3_0 (ctx->opcode & 0xf)
? (x) + 16 : (x))
#define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x))
-#define XHACK(x) (((x) & 1 ) << 4 | ((x) & 0xe ) << 1)
+#define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe))
#define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x))
+#define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */
#define CHECK_NOT_DELAY_SLOT \
if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
#endif
switch (ctx->opcode) {
case 0x0019: /* div0u */
- printf("div0u\n");
gen_op_div0u();
return;
case 0x000b: /* rts */
case 0x0038: /* ldtlb */
assert(0); /* XXXXX */
return;
- case 0x004b: /* rte */
+ case 0x002b: /* rte */
CHECK_NOT_DELAY_SLOT gen_op_rte();
ctx->flags |= DELAY_SLOT;
ctx->delayed_pc = (uint32_t) - 1;
gen_op_cmp_str_T0_T1();
return;
case 0x2007: /* div0s Rm,Rn */
- printf("div0s\n");
gen_op_movl_rN_T0(REG(B7_4));
gen_op_movl_rN_T1(REG(B11_8));
gen_op_div0s_T0_T1();
gen_op_movl_rN_T0(REG(B7_4));
gen_op_xor_T0_rN(REG(B11_8));
return;
- case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_fmov_DT0_drN(XREG(B11_8));
- } else if (ctx->fpscr & FPSCR_SZ) {
+ case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */
+ if (ctx->fpscr & FPSCR_SZ) {
if (ctx->opcode & 0x0110)
break; /* illegal instruction */
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_fmov_DT0_drN(XREG(B11_8));
+ gen_op_fmov_drN_DT0(DREG(B7_4));
+ gen_op_fmov_DT0_drN(DREG(B11_8));
} else {
gen_op_fmov_frN_FT0(FREG(B7_4));
gen_op_fmov_FT0_frN(FREG(B11_8));
}
return;
- case 0xf00a: /* fmov {F,D,X}Rm,@Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stfq_DT0_T1(ctx);
- } else if (ctx->fpscr & FPSCR_SZ) {
+ case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */
+ if (ctx->fpscr & FPSCR_SZ) {
if (ctx->opcode & 0x0010)
break; /* illegal instruction */
- gen_op_fmov_drN_DT0(XREG(B7_4));
+ gen_op_fmov_drN_DT0(DREG(B7_4));
gen_op_movl_rN_T1(REG(B11_8));
gen_op_stfq_DT0_T1(ctx);
} else {
gen_op_stfl_FT0_T1(ctx);
}
return;
- case 0xf008: /* fmov @Rm,{F,D,X}Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
- } else if (ctx->fpscr & FPSCR_SZ) {
+ case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */
+ if (ctx->fpscr & FPSCR_SZ) {
if (ctx->opcode & 0x0100)
break; /* illegal instruction */
gen_op_movl_rN_T0(REG(B7_4));
gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
+ gen_op_fmov_DT0_drN(DREG(B11_8));
} else {
gen_op_movl_rN_T0(REG(B7_4));
gen_op_ldfl_T0_FT0(ctx);
- gen_op_fmov_FT0_frN(XREG(B11_8));
+ gen_op_fmov_FT0_frN(FREG(B11_8));
}
return;
- case 0xf009: /* fmov @Rm+,{F,D,X}Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
- gen_op_inc8_rN(REG(B7_4));
- } else if (ctx->fpscr & FPSCR_SZ) {
+ case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */
+ if (ctx->fpscr & FPSCR_SZ) {
if (ctx->opcode & 0x0100)
break; /* illegal instruction */
gen_op_movl_rN_T0(REG(B7_4));
gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
+ gen_op_fmov_DT0_drN(DREG(B11_8));
gen_op_inc8_rN(REG(B7_4));
} else {
gen_op_movl_rN_T0(REG(B7_4));
gen_op_ldfl_T0_FT0(ctx);
- gen_op_fmov_FT0_frN(XREG(B11_8));
+ gen_op_fmov_FT0_frN(FREG(B11_8));
gen_op_inc4_rN(REG(B7_4));
}
return;
- case 0xf00b: /* fmov {F,D,X}Rm,@-Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_dec8_rN(REG(B11_8));
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stfq_DT0_T1(ctx);
- } else if (ctx->fpscr & FPSCR_SZ) {
+ case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */
+ if (ctx->fpscr & FPSCR_SZ) {
if (ctx->opcode & 0x0100)
break; /* illegal instruction */
gen_op_dec8_rN(REG(B11_8));
- gen_op_fmov_drN_DT0(XREG(B7_4));
+ gen_op_fmov_drN_DT0(DREG(B7_4));
gen_op_movl_rN_T1(REG(B11_8));
gen_op_stfq_DT0_T1(ctx);
} else {
gen_op_stfl_FT0_T1(ctx);
}
return;
- case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_add_rN_T0(REG(0));
- gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
- } else if (ctx->fpscr & FPSCR_SZ) {
+ case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */
+ if (ctx->fpscr & FPSCR_SZ) {
if (ctx->opcode & 0x0100)
break; /* illegal instruction */
gen_op_movl_rN_T0(REG(B7_4));
gen_op_add_rN_T0(REG(0));
gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
+ gen_op_fmov_DT0_drN(DREG(B11_8));
} else {
gen_op_movl_rN_T0(REG(B7_4));
gen_op_add_rN_T0(REG(0));
gen_op_ldfl_T0_FT0(ctx);
- gen_op_fmov_FT0_frN(XREG(B11_8));
+ gen_op_fmov_FT0_frN(FREG(B11_8));
}
return;
- case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_add_rN_T1(REG(0));
- gen_op_stfq_DT0_T1(ctx);
- } else if (ctx->fpscr & FPSCR_SZ) {
+ case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */
+ if (ctx->fpscr & FPSCR_SZ) {
if (ctx->opcode & 0x0010)
break; /* illegal instruction */
- gen_op_fmov_drN_DT0(XREG(B7_4));
+ gen_op_fmov_drN_DT0(DREG(B7_4));
gen_op_movl_rN_T1(REG(B11_8));
gen_op_add_rN_T1(REG(0));
gen_op_stfq_DT0_T1(ctx);
gen_op_stfl_FT0_T1(ctx);
}
return;
+ case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+ case 0xf001: /* fsub Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+ case 0xf002: /* fmul Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+ case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+ case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+ case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+ if (ctx->fpscr & FPSCR_PR) {
+ if (ctx->opcode & 0x0110)
+ break; /* illegal instruction */
+ gen_op_fmov_drN_DT1(DREG(B7_4));
+ gen_op_fmov_drN_DT0(DREG(B11_8));
+ }
+ else {
+ gen_op_fmov_frN_FT1(FREG(B7_4));
+ gen_op_fmov_frN_FT0(FREG(B11_8));
+ }
+
+ switch (ctx->opcode & 0xf00f) {
+ case 0xf000: /* fadd Rm,Rn */
+ ctx->fpscr & FPSCR_PR ? gen_op_fadd_DT() : gen_op_fadd_FT();
+ break;
+ case 0xf001: /* fsub Rm,Rn */
+ ctx->fpscr & FPSCR_PR ? gen_op_fsub_DT() : gen_op_fsub_FT();
+ break;
+ case 0xf002: /* fmul Rm,Rn */
+ ctx->fpscr & FPSCR_PR ? gen_op_fmul_DT() : gen_op_fmul_FT();
+ break;
+ case 0xf003: /* fdiv Rm,Rn */
+ ctx->fpscr & FPSCR_PR ? gen_op_fdiv_DT() : gen_op_fdiv_FT();
+ break;
+ case 0xf004: /* fcmp/eq Rm,Rn */
+ return;
+ case 0xf005: /* fcmp/gt Rm,Rn */
+ return;
+ }
+
+ if (ctx->fpscr & FPSCR_PR) {
+ gen_op_fmov_DT0_drN(DREG(B11_8));
+ }
+ else {
+ gen_op_fmov_FT0_frN(FREG(B11_8));
+ }
+ return;
}
switch (ctx->opcode & 0xff00) {
gen_op_stw_T0_T1(ctx);
return;
case 0x8400: /* mov.b @(disp,Rn),R0 */
- gen_op_movl_rN_T0(REG(0));
- gen_op_movl_rN_T1(REG(B7_4));
- gen_op_addl_imm_T1(B3_0);
- gen_op_stb_T0_T1(ctx);
+ gen_op_movl_rN_T0(REG(B7_4));
+ gen_op_addl_imm_T0(B3_0);
+ gen_op_ldb_T0_T0(ctx);
+ gen_op_movl_T0_rN(REG(0));
return;
case 0x8500: /* mov.w @(disp,Rn),R0 */
gen_op_movl_rN_T0(REG(B7_4));
LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,)
LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,)
LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,)
- LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x0052, sts,)
- LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x0062, sts, ctx->flags |=
+ LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,)
+ LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->flags |=
MODE_CHANGE;)
case 0x00c3: /* movca.l R0,@Rm */
gen_op_movl_rN_T0(REG(0));
case 0x401b: /* tas.b @Rn */
gen_op_tasb_rN(REG(B11_8));
return;
- case 0xf00d: /* fsts FPUL,FRn */
+ case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */
gen_op_movl_fpul_FT0();
gen_op_fmov_FT0_frN(FREG(B11_8));
return;
- case 0xf01d: /* flds FRm.FPUL */
+ case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */
gen_op_fmov_frN_FT0(FREG(B11_8));
gen_op_movl_FT0_fpul();
return;
+ case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */
+ if (ctx->fpscr & FPSCR_PR) {
+ if (ctx->opcode & 0x0100)
+ break; /* illegal instruction */
+ gen_op_float_DT();
+ gen_op_fmov_DT0_drN(DREG(B11_8));
+ }
+ else {
+ gen_op_float_FT();
+ gen_op_fmov_FT0_frN(FREG(B11_8));
+ }
+ return;
+ case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+ if (ctx->fpscr & FPSCR_PR) {
+ if (ctx->opcode & 0x0100)
+ break; /* illegal instruction */
+ gen_op_fmov_drN_DT0(DREG(B11_8));
+ gen_op_ftrc_DT();
+ }
+ else {
+ gen_op_fmov_frN_FT0(FREG(B11_8));
+ gen_op_ftrc_FT();
+ }
+ return;
+ case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */
+ if (!(ctx->fpscr & FPSCR_PR)) {
+ gen_op_movl_imm_T0(0);
+ gen_op_fmov_T0_frN(FREG(B11_8));
+ return;
+ }
+ break;
+ case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */
+ if (!(ctx->fpscr & FPSCR_PR)) {
+ gen_op_movl_imm_T0(0x3f800000);
+ gen_op_fmov_T0_frN(FREG(B11_8));
+ return;
+ }
+ break;
}
fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
ctx->flags |= BRANCH_EXCEPTION;
}
-int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
- int search_pc)
+static inline int
+gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
+ int search_pc)
{
DisasContext ctx;
target_ulong pc_start;
#endif
}
- switch (old_flags & (DELAY_SLOT_CONDITIONAL | DELAY_SLOT)) {
- case DELAY_SLOT_CONDITIONAL:
- gen_op_clr_delay_slot_conditional();
+ if (old_flags & DELAY_SLOT_CONDITIONAL) {
gen_delayed_conditional_jump(&ctx);
- break;
- case DELAY_SLOT:
+ } else if (old_flags & DELAY_SLOT) {
gen_op_clr_delay_slot();
gen_jump(&ctx);
- break;
- case 0:
- if (ctx.flags & BRANCH_EXCEPTION) {
- gen_jump_exception(&ctx);
- } else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) {
- gen_goto_tb(&ctx, 0, ctx.pc);
- }
- break;
- default:
- /* Both cannot be set at the same time */
- assert(0);
+ } 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) {
ii++;
while (ii <= i)
gen_opc_instr_start[ii++] = 0;
- tb->size = 0;
} else {
tb->size = ctx.pc - pc_start;
}