提交 a51568b7 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/aurel/tags/pull-target-sh4-20170718' into staging

Queued target/sh4 patches

# gpg: Signature made Tue 18 Jul 2017 22:44:25 BST
# gpg:                using RSA key 0xBA9C78061DDD8C9B
# gpg: Good signature from "Aurelien Jarno <aurelien@aurel32.net>"
# gpg:                 aka "Aurelien Jarno <aurelien@jarno.fr>"
# gpg:                 aka "Aurelien Jarno <aurel32@debian.org>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 7746 2642 A9EF 94FD 0F77  196D BA9C 7806 1DDD 8C9B

* remotes/aurel/tags/pull-target-sh4-20170718: (31 commits)
  target/sh4: Use tcg_gen_lookup_and_goto_ptr
  target/sh4: Implement fsrra
  target/sh4: Add missing FPSCR.PR == 0 checks
  target/sh4: Implement fpchg
  target/sh4: Introduce CHECK_SH4A
  target/sh4: Introduce CHECK_FPSCR_PR_*
  target/sh4: Tidy misc illegal insn checks
  target/sh4: Unify code for CHECK_FPU_ENABLED
  target/sh4: Unify code for CHECK_PRIVILEGED
  target/sh4: Unify code for CHECK_NOT_DELAY_SLOT
  target/sh4: Simplify 64-bit fp reg-reg move
  target/sh4: Load/store Dr as 64-bit quantities
  target/sh4: Merge DREG into fpr64 routines
  target/sh4: Eliminate unused XREG macro
  target/sh4: Hoist fp register bank selection
  target/sh4: Pass DisasContext to fpr64 routines
  target/sh4: Unify cpu_fregs into FREG
  target/sh4: Hoist register bank selection
  linux-user/sh4: Clean env->flags on signal boundaries
  linux-user/sh4: Notice gUSA regions during signal delivery
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
......@@ -3471,6 +3471,30 @@ static abi_ulong get_sigframe(struct target_sigaction *ka,
return (sp - frame_size) & -8ul;
}
/* Notice when we're in the middle of a gUSA region and reset.
Note that this will only occur for !parallel_cpus, as we will
translate such sequences differently in a parallel context. */
static void unwind_gusa(CPUSH4State *regs)
{
/* If the stack pointer is sufficiently negative, and we haven't
completed the sequence, then reset to the entry to the region. */
/* ??? The SH4 kernel checks for and address above 0xC0000000.
However, the page mappings in qemu linux-user aren't as restricted
and we wind up with the normal stack mapped above 0xF0000000.
That said, there is no reason why the kernel should be allowing
a gUSA region that spans 1GB. Use a tighter check here, for what
can actually be enabled by the immediate move. */
if (regs->gregs[15] >= -128u && regs->pc < regs->gregs[0]) {
/* Reset the PC to before the gUSA region, as computed from
R0 = region end, SP = -(region size), plus one more for the
insn that actually initializes SP to the region size. */
regs->pc = regs->gregs[0] + regs->gregs[15] - 2;
/* Reset the SP to the saved version in R1. */
regs->gregs[15] = regs->gregs[1];
}
}
static void setup_sigcontext(struct target_sigcontext *sc,
CPUSH4State *regs, unsigned long mask)
{
......@@ -3525,6 +3549,7 @@ static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
__get_user(regs->fpul, &sc->sc_fpul);
regs->tra = -1; /* disable syscall checks */
regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
}
static void setup_frame(int sig, struct target_sigaction *ka,
......@@ -3534,6 +3559,8 @@ static void setup_frame(int sig, struct target_sigaction *ka,
abi_ulong frame_addr;
int i;
unwind_gusa(regs);
frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
trace_user_setup_frame(regs, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
......@@ -3566,6 +3593,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
regs->gregs[5] = 0;
regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
regs->pc = (unsigned long) ka->_sa_handler;
regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
unlock_user_struct(frame, frame_addr, 1);
return;
......@@ -3583,6 +3611,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
abi_ulong frame_addr;
int i;
unwind_gusa(regs);
frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
trace_user_setup_rt_frame(regs, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
......@@ -3626,6 +3656,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
regs->pc = (unsigned long) ka->_sa_handler;
regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
unlock_user_struct(frame, frame_addr, 1);
return;
......
......@@ -39,7 +39,7 @@ static void superh_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
SuperHCPU *cpu = SUPERH_CPU(cs);
cpu->env.pc = tb->pc;
cpu->env.flags = tb->flags;
cpu->env.flags = tb->flags & TB_FLAG_ENVFLAGS_MASK;
}
static bool superh_cpu_has_work(CPUState *cs)
......
......@@ -96,6 +96,21 @@
#define DELAY_SLOT_CONDITIONAL (1 << 1)
#define DELAY_SLOT_RTE (1 << 2)
#define TB_FLAG_PENDING_MOVCA (1 << 3)
#define GUSA_SHIFT 4
#ifdef CONFIG_USER_ONLY
#define GUSA_EXCLUSIVE (1 << 12)
#define GUSA_MASK ((0xff << GUSA_SHIFT) | GUSA_EXCLUSIVE)
#else
/* Provide dummy versions of the above to allow tests against tbflags
to be elided while avoiding ifdefs. */
#define GUSA_EXCLUSIVE 0
#define GUSA_MASK 0
#endif
#define TB_FLAG_ENVFLAGS_MASK (DELAY_SLOT_MASK | GUSA_MASK)
typedef struct tlb_t {
uint32_t vpn; /* virtual page number */
uint32_t ppn; /* physical page number */
......@@ -366,8 +381,6 @@ static inline int cpu_ptel_pr (uint32_t ptel)
#define PTEA_TC (1 << 3)
#define cpu_ptea_tc(ptea) (((ptea) & PTEA_TC) >> 3)
#define TB_FLAG_PENDING_MOVCA (1 << 4)
static inline target_ulong cpu_read_sr(CPUSH4State *env)
{
return env->sr | (env->sr_m << SR_M) |
......@@ -387,12 +400,13 @@ static inline void cpu_get_tb_cpu_state(CPUSH4State *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
*pc = env->pc;
*cs_base = 0;
*flags = (env->flags & DELAY_SLOT_MASK) /* Bits 0- 2 */
/* For a gUSA region, notice the end of the region. */
*cs_base = env->flags & GUSA_MASK ? env->gregs[0] : 0;
*flags = env->flags /* TB_FLAG_ENVFLAGS_MASK: bits 0-2, 4-12 */
| (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */
| (env->sr & ((1u << SR_MD) | (1u << SR_RB))) /* Bits 29-30 */
| (env->sr & (1u << SR_FD)) /* Bit 15 */
| (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */
| (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 3 */
}
#endif /* SH4_CPU_H */
......@@ -6,6 +6,7 @@ DEF_HELPER_1(raise_slot_fpu_disable, noreturn, env)
DEF_HELPER_1(debug, noreturn, env)
DEF_HELPER_1(sleep, noreturn, env)
DEF_HELPER_2(trapa, noreturn, env, i32)
DEF_HELPER_1(exclusive, noreturn, env)
DEF_HELPER_3(movcal, void, env, i32, i32)
DEF_HELPER_1(discard_movcal_backup, void, env)
......@@ -16,17 +17,15 @@ DEF_HELPER_3(macw, void, env, i32, i32)
DEF_HELPER_2(ld_fpscr, void, env, i32)
DEF_HELPER_FLAGS_1(fabs_FT, TCG_CALL_NO_RWG_SE, f32, f32)
DEF_HELPER_FLAGS_1(fabs_DT, TCG_CALL_NO_RWG_SE, f64, f64)
DEF_HELPER_FLAGS_3(fadd_FT, TCG_CALL_NO_WG, f32, env, f32, f32)
DEF_HELPER_FLAGS_3(fadd_DT, TCG_CALL_NO_WG, f64, env, f64, f64)
DEF_HELPER_FLAGS_2(fcnvsd_FT_DT, TCG_CALL_NO_WG, f64, env, f32)
DEF_HELPER_FLAGS_2(fcnvds_DT_FT, TCG_CALL_NO_WG, f32, env, f64)
DEF_HELPER_3(fcmp_eq_FT, void, env, f32, f32)
DEF_HELPER_3(fcmp_eq_DT, void, env, f64, f64)
DEF_HELPER_3(fcmp_gt_FT, void, env, f32, f32)
DEF_HELPER_3(fcmp_gt_DT, void, env, f64, f64)
DEF_HELPER_FLAGS_3(fcmp_eq_FT, TCG_CALL_NO_WG, i32, env, f32, f32)
DEF_HELPER_FLAGS_3(fcmp_eq_DT, TCG_CALL_NO_WG, i32, env, f64, f64)
DEF_HELPER_FLAGS_3(fcmp_gt_FT, TCG_CALL_NO_WG, i32, env, f32, f32)
DEF_HELPER_FLAGS_3(fcmp_gt_DT, TCG_CALL_NO_WG, i32, env, f64, f64)
DEF_HELPER_FLAGS_3(fdiv_FT, TCG_CALL_NO_WG, f32, env, f32, f32)
DEF_HELPER_FLAGS_3(fdiv_DT, TCG_CALL_NO_WG, f64, env, f64, f64)
DEF_HELPER_FLAGS_2(float_FT, TCG_CALL_NO_WG, f32, env, i32)
......@@ -34,11 +33,11 @@ DEF_HELPER_FLAGS_2(float_DT, TCG_CALL_NO_WG, f64, env, i32)
DEF_HELPER_FLAGS_4(fmac_FT, TCG_CALL_NO_WG, f32, env, f32, f32, f32)
DEF_HELPER_FLAGS_3(fmul_FT, TCG_CALL_NO_WG, f32, env, f32, f32)
DEF_HELPER_FLAGS_3(fmul_DT, TCG_CALL_NO_WG, f64, env, f64, f64)
DEF_HELPER_FLAGS_1(fneg_T, TCG_CALL_NO_RWG_SE, f32, f32)
DEF_HELPER_FLAGS_3(fsub_FT, TCG_CALL_NO_WG, f32, env, f32, f32)
DEF_HELPER_FLAGS_3(fsub_DT, TCG_CALL_NO_WG, f64, env, f64, f64)
DEF_HELPER_FLAGS_2(fsqrt_FT, TCG_CALL_NO_WG, f32, env, f32)
DEF_HELPER_FLAGS_2(fsqrt_DT, TCG_CALL_NO_WG, f64, env, f64)
DEF_HELPER_FLAGS_2(fsrra_FT, TCG_CALL_NO_WG, f32, env, f32)
DEF_HELPER_FLAGS_2(ftrc_FT, TCG_CALL_NO_WG, i32, env, f32)
DEF_HELPER_FLAGS_2(ftrc_DT, TCG_CALL_NO_WG, i32, env, f64)
DEF_HELPER_3(fipr, void, env, i32, i32)
......
......@@ -115,6 +115,12 @@ void helper_trapa(CPUSH4State *env, uint32_t tra)
raise_exception(env, 0x160, 0);
}
void helper_exclusive(CPUSH4State *env)
{
/* We do not want cpu_restore_state to run. */
cpu_loop_exit_atomic(ENV_GET_CPU(env), 0);
}
void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value)
{
if (cpu_sh4_is_cached (env, address))
......@@ -219,29 +225,29 @@ static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
xcpt = get_float_exception_flags(&env->fp_status);
/* Clear the flag entries */
env->fpscr &= ~FPSCR_FLAG_MASK;
/* Clear the cause entries */
env->fpscr &= ~FPSCR_CAUSE_MASK;
if (unlikely(xcpt)) {
if (xcpt & float_flag_invalid) {
env->fpscr |= FPSCR_FLAG_V;
env->fpscr |= FPSCR_CAUSE_V;
}
if (xcpt & float_flag_divbyzero) {
env->fpscr |= FPSCR_FLAG_Z;
env->fpscr |= FPSCR_CAUSE_Z;
}
if (xcpt & float_flag_overflow) {
env->fpscr |= FPSCR_FLAG_O;
env->fpscr |= FPSCR_CAUSE_O;
}
if (xcpt & float_flag_underflow) {
env->fpscr |= FPSCR_FLAG_U;
env->fpscr |= FPSCR_CAUSE_U;
}
if (xcpt & float_flag_inexact) {
env->fpscr |= FPSCR_FLAG_I;
env->fpscr |= FPSCR_CAUSE_I;
}
/* Accumulate in cause entries */
env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
<< (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
/* Accumulate in flag entries */
env->fpscr |= (env->fpscr & FPSCR_CAUSE_MASK)
>> (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
/* Generate an exception if enabled */
cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
......@@ -252,16 +258,6 @@ static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
}
}
float32 helper_fabs_FT(float32 t0)
{
return float32_abs(t0);
}
float64 helper_fabs_DT(float64 t0)
{
return float64_abs(t0);
}
float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1)
{
set_float_exception_flags(0, &env->fp_status);
......@@ -278,56 +274,44 @@ float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1)
return t0;
}
void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1)
uint32_t helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1)
{
int relation;
set_float_exception_flags(0, &env->fp_status);
relation = float32_compare(t0, t1, &env->fp_status);
if (unlikely(relation == float_relation_unordered)) {
update_fpscr(env, GETPC());
} else {
env->sr_t = (relation == float_relation_equal);
}
update_fpscr(env, GETPC());
return relation == float_relation_equal;
}
void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
uint32_t helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
{
int relation;
set_float_exception_flags(0, &env->fp_status);
relation = float64_compare(t0, t1, &env->fp_status);
if (unlikely(relation == float_relation_unordered)) {
update_fpscr(env, GETPC());
} else {
env->sr_t = (relation == float_relation_equal);
}
update_fpscr(env, GETPC());
return relation == float_relation_equal;
}
void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
uint32_t helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
{
int relation;
set_float_exception_flags(0, &env->fp_status);
relation = float32_compare(t0, t1, &env->fp_status);
if (unlikely(relation == float_relation_unordered)) {
update_fpscr(env, GETPC());
} else {
env->sr_t = (relation == float_relation_greater);
}
update_fpscr(env, GETPC());
return relation == float_relation_greater;
}
void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
uint32_t helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
{
int relation;
set_float_exception_flags(0, &env->fp_status);
relation = float64_compare(t0, t1, &env->fp_status);
if (unlikely(relation == float_relation_unordered)) {
update_fpscr(env, GETPC());
} else {
env->sr_t = (relation == float_relation_greater);
}
update_fpscr(env, GETPC());
return relation == float_relation_greater;
}
float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0)
......@@ -406,11 +390,6 @@ float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1)
return t0;
}
float32 helper_fneg_T(float32 t0)
{
return float32_chs(t0);
}
float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0)
{
set_float_exception_flags(0, &env->fp_status);
......@@ -427,6 +406,22 @@ float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0)
return t0;
}
float32 helper_fsrra_FT(CPUSH4State *env, float32 t0)
{
set_float_exception_flags(0, &env->fp_status);
/* "Approximate" 1/sqrt(x) via actual computation. */
t0 = float32_sqrt(t0, &env->fp_status);
t0 = float32_div(float32_one, t0, &env->fp_status);
/* Since this is supposed to be an approximation, an imprecision
exception is required. One supposes this also follows the usual
IEEE rule that other exceptions take precidence. */
if (get_float_exception_flags(&env->fp_status) == 0) {
set_float_exception_flags(float_flag_inexact, &env->fp_status);
}
update_fpscr(env, GETPC());
return t0;
}
float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1)
{
set_float_exception_flags(0, &env->fp_status);
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册