#include "helpers.h"
#include "qemu-common.h"
#include "host-utils.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/loader.h"
+#endif
static uint32_t cortexa9_cp15_c0_c1[8] =
{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 };
cpu_reset_model_id(env, id);
#if defined (CONFIG_USER_ONLY)
env->uncached_cpsr = ARM_CPU_MODE_USR;
+ /* For user mode we must enable access to coprocessors */
env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ env->cp15.c15_cpar = 3;
+ } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ env->cp15.c15_cpar = 1;
+ }
#else
/* SVC mode with interrupts disabled. */
env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
/* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
- clear at reset. */
- if (IS_M(env))
+ clear at reset. Initial SP and PC are loaded from ROM. */
+ if (IS_M(env)) {
+ uint32_t pc;
+ uint8_t *rom;
env->uncached_cpsr &= ~CPSR_I;
+ rom = rom_ptr(0);
+ if (rom) {
+ /* We should really use ldl_phys here, in case the guest
+ modified flash and reset itself. However images
+ loaded via -kenrel have not been copied yet, so load the
+ values directly from there. */
+ env->regs[13] = ldl_p(rom);
+ pc = ldl_p(rom + 4);
+ env->thumb = pc & 1;
+ env->regs[15] = pc & ~1;
+ }
+ }
env->vfp.xregs[ARM_VFP_FPEXC] = 0;
env->cp15.c2_base_mask = 0xffffc000u;
#endif
- env->regs[15] = 0;
tlb_flush(env, 1);
}
{ 0, NULL}
};
-void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
{
int i;
type = env->regs[15];
if (env->v7m.exception != 0)
- armv7m_nvic_complete_irq(env->v7m.nvic, env->v7m.exception);
+ armv7m_nvic_complete_irq(env->nvic, env->v7m.exception);
/* Switch to the target stack. */
switch_v7m_sp(env, (type & 4) != 0);
one we're raising. */
switch (env->exception_index) {
case EXCP_UDEF:
- armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_USAGE);
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
return;
case EXCP_SWI:
env->regs[15] += 2;
- armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_SVC);
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC);
return;
case EXCP_PREFETCH_ABORT:
case EXCP_DATA_ABORT:
- armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_MEM);
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
return;
case EXCP_BKPT:
if (semihosting_enabled) {
return;
}
}
- armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_DEBUG);
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG);
return;
case EXCP_IRQ:
- env->v7m.exception = armv7m_nvic_acknowledge_irq(env->v7m.nvic);
+ env->v7m.exception = armv7m_nvic_acknowledge_irq(env->nvic);
break;
case EXCP_EXCEPTION_EXIT:
do_v7m_exception_exit(env);
static inline uint16_t sub16_usat(uint16_t a, uint16_t b)
{
- if (a < b)
+ if (a > b)
return a - b;
else
return 0;
static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
{
- if (a < b)
+ if (a > b)
return a - b;
else
return 0;
return fpscr;
}
+uint32_t vfp_get_fpscr(CPUState *env)
+{
+ return HELPER(vfp_get_fpscr)(env);
+}
+
/* Convert vfp exception flags to target form. */
static inline int vfp_exceptbits_to_host(int target_bits)
{
set_float_exception_flags(i, &env->vfp.fp_status);
}
+void vfp_set_fpscr(CPUState *env, uint32_t val)
+{
+ HELPER(vfp_set_fpscr)(env, val);
+}
+
#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
#define VFP_BINOP(name) \
/* Float to integer conversion. */
float32 VFP_HELPER(toui, s)(float32 x, CPUState *env)
{
+ if (float32_is_any_nan(x)) {
+ return float32_zero;
+ }
return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status));
}
float32 VFP_HELPER(toui, d)(float64 x, CPUState *env)
{
+ if (float64_is_any_nan(x)) {
+ return float32_zero;
+ }
return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status));
}
float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env)
{
+ if (float32_is_any_nan(x)) {
+ return float32_zero;
+ }
return vfp_itos(float32_to_int32(x, &env->vfp.fp_status));
}
float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env)
{
+ if (float64_is_any_nan(x)) {
+ return float32_zero;
+ }
return vfp_itos(float64_to_int32(x, &env->vfp.fp_status));
}
float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env)
{
+ if (float32_is_any_nan(x)) {
+ return float32_zero;
+ }
return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status));
}
float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env)
{
+ if (float64_is_any_nan(x)) {
+ return float32_zero;
+ }
return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status));
}
float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env)
{
+ if (float32_is_any_nan(x)) {
+ return float32_zero;
+ }
return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status));
}
float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env)
{
+ if (float64_is_any_nan(x)) {
+ return float32_zero;
+ }
return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status));
}
/* floating point conversion */
float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env)
{
- return float32_to_float64(x, &env->vfp.fp_status);
+ float64 r = float32_to_float64(x, &env->vfp.fp_status);
+ /* ARM requires that S<->D conversion of any kind of NaN generates
+ * a quiet NaN by forcing the most significant frac bit to 1.
+ */
+ return float64_maybe_silence_nan(r);
}
float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env)
{
- return float64_to_float32(x, &env->vfp.fp_status);
+ float32 r = float64_to_float32(x, &env->vfp.fp_status);
+ /* ARM requires that S<->D conversion of any kind of NaN generates
+ * a quiet NaN by forcing the most significant frac bit to 1.
+ */
+ return float32_maybe_silence_nan(r);
}
/* VFP3 fixed point conversion. */
ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \
{ \
ftype tmp; \
- tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \
+ tmp = sign##int32_to_##ftype ((itype##_t)vfp_##p##toi(x), \
&env->vfp.fp_status); \
return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \
} \
ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
{ \
ftype tmp; \
+ if (ftype##_is_any_nan(x)) { \
+ return ftype##_zero; \
+ } \
tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \
- return vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \
+ return vfp_ito##p(ftype##_to_##itype##_round_to_zero(tmp, \
&env->vfp.fp_status)); \
}