target-arm queue:

* Fix a bug causing an assertion in the NVIC on ARMv7M models
  * More A64 Neon instructions
  * Refactor cpreg API to separate out access check functions, as
    groundwork for AArch64 system mode
  * Fix bug in linux-user A64 store-exclusive of XZR
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABCAAGBQJTBeM5AAoJEDwlJe0UNgzecwwP/1mujaECNj2BPWxGMLTzF4M5
 2PCLYbTNPZumb1b6Z1qrCVbrGBS7bKL1lSCKA5Isji1HHyRnNtaJNGMqI7p2AzaE
 pPvI+0jhrmdbG2cqgeGbbYMabNdzBTEAhwPo5LQO7wP6CYQDlYH3JVVlcYc6Vl7b
 hahAI49AV1HM+Xo9z7DSI2VSA2rI2tgbHpIHrvYwtp2exQnPNZBMyZu42yJdK2Lb
 1gsVvnni/mA71KydbM6drhHzk2wd9OrrkFxZG94kOIWUxzarDxIapWUPWr006j7c
 wd2jA639OM9wGwyLgmO537smxr+iV7iLAdz6JkI026po3GFxrrmSjVXS93vL9GHP
 716kvTKHeG2WRJW1H0uJjUpzw4tFoKv8EQq3rv8McBwe6Cf+nJtfsY5OLa2GpzG5
 bro6jeJmogoInfMxGxYPezeWFg0olBa17RgAZk9+Y33vPjQVbgGb9Xna1dndtbrU
 e2/T6CAGIGXL3kXLFIiFGB1JBST4UGlGVX2kJLJU+Yv8nzdAZjwQ3gZFJno5DyFU
 K9BZQGX932VCf4bgy1MPvZXO3pMN2iF7prDeHVZeGcw/zFTBDQHje32fCLFAGeuz
 1qnIGvE/vXZQoaw52qv/kIGLmcBZiXiBNCm+ImttfGu5fjAhODEuAhBBU1Zjv3j7
 1qnBhXlVSxOpLMpuJTIJ
 =h/1p
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20140220' into staging

target-arm queue:
 * Fix a bug causing an assertion in the NVIC on ARMv7M models
 * More A64 Neon instructions
 * Refactor cpreg API to separate out access check functions, as
   groundwork for AArch64 system mode
 * Fix bug in linux-user A64 store-exclusive of XZR

# gpg: Signature made Thu 20 Feb 2014 11:12:57 GMT using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20140220: (30 commits)
  linux-user: AArch64: Fix exclusive store of the zero register
  target-arm: A64: Implement unprivileged load/store
  target-arm: A64: Implement narrowing three-reg-diff operations
  target-arm: A64: Implement the wide 3-reg-different operations
  target-arm: A64: Add most remaining three-reg-diff widening ops
  target-arm: A64: Add opcode comments to disas_simd_three_reg_diff
  target-arm: A64: Implement store-exclusive for system mode
  target-arm: Fix incorrect type for value argument to write_raw_cp_reg
  target-arm: Remove failure status return from read/write_raw_cp_reg
  target-arm: Remove unnecessary code now read/write fns can't fail
  target-arm: Drop success/fail return from cpreg read and write functions
  target-arm: Convert miscellaneous reginfo structs to accessfn
  target-arm: Convert generic timer reginfo to accessfn
  target-arm: Convert performance monitor reginfo to accessfn
  target-arm: Split cpreg access checks out from read/write functions
  target-arm: Stop underdecoding ARM946 PRBS registers
  target-arm: Log bad system register accesses with LOG_UNIMP
  target-arm: Remove unused ARMCPUState sr substruct
  target-arm: Restrict check_ap() use of S and R bits to v6 and earlier
  target-arm: Define names for SCTLR bits
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-02-21 15:04:57 +00:00
commit 105a060188
17 changed files with 1792 additions and 572 deletions

View File

@ -2372,6 +2372,17 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
}
}
/* Zero plus something non-zero : just return the something */
if (flags & float_muladd_halve_result) {
if (cExp == 0) {
normalizeFloat32Subnormal(cSig, &cExp, &cSig);
}
/* Subtract one to halve, and one again because roundAndPackFloat32
* wants one less than the true exponent.
*/
cExp -= 2;
cSig = (cSig | 0x00800000) << 7;
return roundAndPackFloat32(cSign ^ signflip, cExp, cSig STATUS_VAR);
}
return packFloat32(cSign ^ signflip, cExp, cSig);
}
@ -2408,6 +2419,9 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
/* Throw out the special case of c being an exact zero now */
shift64RightJamming(pSig64, 32, &pSig64);
pSig = pSig64;
if (flags & float_muladd_halve_result) {
pExp--;
}
return roundAndPackFloat32(zSign, pExp - 1,
pSig STATUS_VAR);
}
@ -2472,6 +2486,10 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
zSig64 <<= shiftcount;
zExp -= shiftcount;
}
if (flags & float_muladd_halve_result) {
zExp--;
}
shift64RightJamming(zSig64, 32, &zSig64);
return roundAndPackFloat32(zSign, zExp, zSig64 STATUS_VAR);
}
@ -4088,6 +4106,17 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
}
}
/* Zero plus something non-zero : just return the something */
if (flags & float_muladd_halve_result) {
if (cExp == 0) {
normalizeFloat64Subnormal(cSig, &cExp, &cSig);
}
/* Subtract one to halve, and one again because roundAndPackFloat64
* wants one less than the true exponent.
*/
cExp -= 2;
cSig = (cSig | 0x0010000000000000ULL) << 10;
return roundAndPackFloat64(cSign ^ signflip, cExp, cSig STATUS_VAR);
}
return packFloat64(cSign ^ signflip, cExp, cSig);
}
@ -4123,6 +4152,9 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
if (!cSig) {
/* Throw out the special case of c being an exact zero now */
shift128RightJamming(pSig0, pSig1, 64, &pSig0, &pSig1);
if (flags & float_muladd_halve_result) {
pExp--;
}
return roundAndPackFloat64(zSign, pExp - 1,
pSig1 STATUS_VAR);
}
@ -4159,6 +4191,9 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
zExp--;
}
shift128RightJamming(zSig0, zSig1, 64, &zSig0, &zSig1);
if (flags & float_muladd_halve_result) {
zExp--;
}
return roundAndPackFloat64(zSign, zExp, zSig1 STATUS_VAR);
} else {
/* Subtraction */
@ -4209,6 +4244,9 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
zExp -= (shiftcount + 64);
}
}
if (flags & float_muladd_halve_result) {
zExp--;
}
return roundAndPackFloat64(zSign, zExp, zSig0 STATUS_VAR);
}
}

View File

@ -224,27 +224,24 @@ static const VMStateDescription vmstate_pxa2xx_cm = {
}
};
static int pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t *value)
static uint64_t pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
PXA2xxState *s = (PXA2xxState *)ri->opaque;
*value = s->clkcfg;
return 0;
return s->clkcfg;
}
static int pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
static void pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
PXA2xxState *s = (PXA2xxState *)ri->opaque;
s->clkcfg = value & 0xf;
if (value & 2) {
printf("%s: CPU frequency change attempt\n", __func__);
}
return 0;
}
static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
PXA2xxState *s = (PXA2xxState *)ri->opaque;
static const char *pwrmode[8] = {
@ -310,36 +307,29 @@ static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
printf("%s: machine entered %s mode\n", __func__,
pwrmode[value & 7]);
}
return 0;
}
static int pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t *value)
static uint64_t pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
PXA2xxState *s = (PXA2xxState *)ri->opaque;
*value = s->pmnc;
return 0;
return s->pmnc;
}
static int pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
static void pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
PXA2xxState *s = (PXA2xxState *)ri->opaque;
s->pmnc = value;
return 0;
}
static int pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t *value)
static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
PXA2xxState *s = (PXA2xxState *)ri->opaque;
if (s->pmnc & 1) {
*value = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
} else {
*value = 0;
return 0;
}
return 0;
}
static const ARMCPRegInfo pxa_cp_reginfo[] = {

View File

@ -217,20 +217,17 @@ static const int pxa2xx_cp_reg_map[0x10] = {
[0xa] = ICPR2,
};
static int pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t *value)
static uint64_t pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
int offset = pxa2xx_cp_reg_map[ri->crn];
*value = pxa2xx_pic_mem_read(ri->opaque, offset, 4);
return 0;
return pxa2xx_pic_mem_read(ri->opaque, offset, 4);
}
static int pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
int offset = pxa2xx_cp_reg_map[ri->crn];
pxa2xx_pic_mem_write(ri->opaque, offset, value, 4);
return 0;
}
#define REGINFO_FOR_PIC_CP(NAME, CRN) \

View File

@ -189,7 +189,7 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu)
}
s->last_active[irq][cpu] = s->running_irq[cpu];
if (s->revision == REV_11MPCORE) {
if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
/* Clear pending flags for both level and edge triggered interrupts.
* Level triggered IRQs will be reasserted once they become inactive.
*/

View File

@ -249,11 +249,14 @@ void float_raise( int8 flags STATUS_PARAM);
| Using these differs from negating an input or output before calling
| the muladd function in that this means that a NaN doesn't have its
| sign bit inverted before it is propagated.
| We also support halving the result before rounding, as a special
| case to support the ARM fused-sqrt-step instruction FRSQRTS.
*----------------------------------------------------------------------------*/
enum {
float_muladd_negate_c = 1,
float_muladd_negate_product = 2,
float_muladd_negate_result = 4,
float_muladd_halve_result = 8,
};
/*----------------------------------------------------------------------------

View File

@ -953,7 +953,8 @@ static int do_strex_a64(CPUARMState *env)
goto finish;
}
}
val = env->xregs[rt];
/* handle the zero register */
val = rt == 31 ? 0 : env->xregs[rt];
switch (size) {
case 0:
segv = put_user_u8(val, addr);
@ -972,7 +973,8 @@ static int do_strex_a64(CPUARMState *env)
goto error;
}
if (is_pair) {
val = env->xregs[rt2];
/* handle the zero register */
val = rt2 == 31 ? 0 : env->xregs[rt2];
if (size == 2) {
segv = put_user_u32(val, addr + 4);
} else {

View File

@ -128,7 +128,7 @@ static void arm_cpu_reset(CPUState *s)
}
}
if (env->cp15.c1_sys & (1 << 13)) {
if (env->cp15.c1_sys & SCTLR_V) {
env->regs[15] = 0xFFFF0000;
}
@ -681,14 +681,12 @@ static void cortex_a9_initfn(Object *obj)
}
#ifndef CONFIG_USER_ONLY
static int a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t *value)
static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
/* Linux wants the number of processors from here.
* Might as well set the interrupt-controller bit too.
*/
*value = ((smp_cpus - 1) << 24) | (1 << 23);
return 0;
return ((smp_cpus - 1) << 24) | (1 << 23);
}
#endif

View File

@ -217,11 +217,6 @@ typedef struct CPUARMState {
uint32_t c15_power_control; /* power control */
} cp15;
/* System registers (AArch64) */
struct {
uint64_t tpidr_el0;
} sr;
struct {
uint32_t other_sp;
uint32_t vecbase;
@ -337,6 +332,58 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
int mmu_idx);
#define cpu_handle_mmu_fault cpu_arm_handle_mmu_fault
/* SCTLR bit meanings. Several bits have been reused in newer
* versions of the architecture; in that case we define constants
* for both old and new bit meanings. Code which tests against those
* bits should probably check or otherwise arrange that the CPU
* is the architectural version it expects.
*/
#define SCTLR_M (1U << 0)
#define SCTLR_A (1U << 1)
#define SCTLR_C (1U << 2)
#define SCTLR_W (1U << 3) /* up to v6; RAO in v7 */
#define SCTLR_SA (1U << 3)
#define SCTLR_P (1U << 4) /* up to v5; RAO in v6 and v7 */
#define SCTLR_SA0 (1U << 4) /* v8 onward, AArch64 only */
#define SCTLR_D (1U << 5) /* up to v5; RAO in v6 */
#define SCTLR_CP15BEN (1U << 5) /* v7 onward */
#define SCTLR_L (1U << 6) /* up to v5; RAO in v6 and v7; RAZ in v8 */
#define SCTLR_B (1U << 7) /* up to v6; RAZ in v7 */
#define SCTLR_ITD (1U << 7) /* v8 onward */
#define SCTLR_S (1U << 8) /* up to v6; RAZ in v7 */
#define SCTLR_SED (1U << 8) /* v8 onward */
#define SCTLR_R (1U << 9) /* up to v6; RAZ in v7 */
#define SCTLR_UMA (1U << 9) /* v8 onward, AArch64 only */
#define SCTLR_F (1U << 10) /* up to v6 */
#define SCTLR_SW (1U << 10) /* v7 onward */
#define SCTLR_Z (1U << 11)
#define SCTLR_I (1U << 12)
#define SCTLR_V (1U << 13)
#define SCTLR_RR (1U << 14) /* up to v7 */
#define SCTLR_DZE (1U << 14) /* v8 onward, AArch64 only */
#define SCTLR_L4 (1U << 15) /* up to v6; RAZ in v7 */
#define SCTLR_UCT (1U << 15) /* v8 onward, AArch64 only */
#define SCTLR_DT (1U << 16) /* up to ??, RAO in v6 and v7 */
#define SCTLR_nTWI (1U << 16) /* v8 onward */
#define SCTLR_HA (1U << 17)
#define SCTLR_IT (1U << 18) /* up to ??, RAO in v6 and v7 */
#define SCTLR_nTWE (1U << 18) /* v8 onward */
#define SCTLR_WXN (1U << 19)
#define SCTLR_ST (1U << 20) /* up to ??, RAZ in v6 */
#define SCTLR_UWXN (1U << 20) /* v7 onward */
#define SCTLR_FI (1U << 21)
#define SCTLR_U (1U << 22)
#define SCTLR_XP (1U << 23) /* up to v6; v7 onward RAO */
#define SCTLR_VE (1U << 24) /* up to v7 */
#define SCTLR_E0E (1U << 24) /* v8 onward, AArch64 only */
#define SCTLR_EE (1U << 25)
#define SCTLR_L2 (1U << 26) /* up to v6, RAZ in v7 */
#define SCTLR_UCI (1U << 26) /* v8 onward, AArch64 only */
#define SCTLR_NMFI (1U << 27)
#define SCTLR_TRE (1U << 28)
#define SCTLR_AFE (1U << 29)
#define SCTLR_TE (1U << 30)
#define CPSR_M (0x1fU)
#define CPSR_T (1U << 5)
#define CPSR_F (1U << 6)
@ -764,14 +811,30 @@ static inline int arm_current_pl(CPUARMState *env)
typedef struct ARMCPRegInfo ARMCPRegInfo;
/* Access functions for coprocessor registers. These should return
* 0 on success, or one of the EXCP_* constants if access should cause
* an exception (in which case *value is not written).
typedef enum CPAccessResult {
/* Access is permitted */
CP_ACCESS_OK = 0,
/* Access fails due to a configurable trap or enable which would
* result in a categorized exception syndrome giving information about
* the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6,
* 0xc or 0x18).
*/
CP_ACCESS_TRAP = 1,
/* Access fails and results in an exception syndrome 0x0 ("uncategorized").
* Note that this is not a catch-all case -- the set of cases which may
* result in this failure is specifically defined by the architecture.
*/
CP_ACCESS_TRAP_UNCATEGORIZED = 2,
} CPAccessResult;
/* Access functions for coprocessor registers. These cannot fail and
* may not raise exceptions.
*/
typedef int CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque,
uint64_t *value);
typedef int CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
uint64_t value);
typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque);
typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
uint64_t value);
/* Access permission check functions for coprocessor registers. */
typedef CPAccessResult CPAccessFn(CPUARMState *env, const ARMCPRegInfo *opaque);
/* Hook function for register reset */
typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
@ -825,6 +888,12 @@ struct ARMCPRegInfo {
* 2. both readfn and writefn are specified
*/
ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */
/* Function for making any access checks for this register in addition to
* those specified by the 'access' permissions bits. If NULL, no extra
* checks required. The access check is performed at runtime, not at
* translate time.
*/
CPAccessFn *accessfn;
/* Function for handling reads of this register. If NULL, then reads
* will be done by loading from the offset into CPUARMState specified
* by fieldoffset.
@ -838,14 +907,14 @@ struct ARMCPRegInfo {
/* Function for doing a "raw" read; used when we need to copy
* coprocessor state to the kernel for KVM or out for
* migration. This only needs to be provided if there is also a
* readfn and it makes an access permission check.
* readfn and it has side effects (for instance clear-on-read bits).
*/
CPReadFn *raw_readfn;
/* Function for doing a "raw" write; used when we need to copy KVM
* kernel coprocessor state into userspace, or for inbound
* migration. This only needs to be provided if there is also a
* writefn and it makes an access permission check or masks out
* "unwritable" bits or has write-one-to-clear or similar behaviour.
* writefn and it masks out "unwritable" bits or has write-one-to-clear
* or similar behaviour.
*/
CPWriteFn *raw_writefn;
/* Function for resetting the register. If NULL, then reset will be done
@ -880,10 +949,10 @@ static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp);
/* CPWriteFn that can be used to implement writes-ignored behaviour */
int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value);
void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value);
/* CPReadFn that can be used for read-as-zero behaviour */
int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value);
uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri);
/* CPResetFn that does nothing, for use if no reset is required even
* if fieldoffset is non zero.

View File

@ -123,6 +123,32 @@ uint64_t HELPER(vfp_cmped_a64)(float64 x, float64 y, void *fp_status)
return float_rel_to_flags(float64_compare(x, y, fp_status));
}
float32 HELPER(vfp_mulxs)(float32 a, float32 b, void *fpstp)
{
float_status *fpst = fpstp;
if ((float32_is_zero(a) && float32_is_infinity(b)) ||
(float32_is_infinity(a) && float32_is_zero(b))) {
/* 2.0 with the sign bit set to sign(A) XOR sign(B) */
return make_float32((1U << 30) |
((float32_val(a) ^ float32_val(b)) & (1U << 31)));
}
return float32_mul(a, b, fpst);
}
float64 HELPER(vfp_mulxd)(float64 a, float64 b, void *fpstp)
{
float_status *fpst = fpstp;
if ((float64_is_zero(a) && float64_is_infinity(b)) ||
(float64_is_infinity(a) && float64_is_zero(b))) {
/* 2.0 with the sign bit set to sign(A) XOR sign(B) */
return make_float64((1ULL << 62) |
((float64_val(a) ^ float64_val(b)) & (1ULL << 63)));
}
return float64_mul(a, b, fpst);
}
uint64_t HELPER(simd_tbl)(CPUARMState *env, uint64_t result, uint64_t indices,
uint32_t rn, uint32_t numregs)
{
@ -153,3 +179,82 @@ uint64_t HELPER(simd_tbl)(CPUARMState *env, uint64_t result, uint64_t indices,
}
return result;
}
/* 64bit/double versions of the neon float compare functions */
uint64_t HELPER(neon_ceq_f64)(float64 a, float64 b, void *fpstp)
{
float_status *fpst = fpstp;
return -float64_eq_quiet(a, b, fpst);
}
uint64_t HELPER(neon_cge_f64)(float64 a, float64 b, void *fpstp)
{
float_status *fpst = fpstp;
return -float64_le(b, a, fpst);
}
uint64_t HELPER(neon_cgt_f64)(float64 a, float64 b, void *fpstp)
{
float_status *fpst = fpstp;
return -float64_lt(b, a, fpst);
}
/* Reciprocal step and sqrt step. Note that unlike the A32/T32
* versions, these do a fully fused multiply-add or
* multiply-add-and-halve.
*/
#define float32_two make_float32(0x40000000)
#define float32_three make_float32(0x40400000)
#define float32_one_point_five make_float32(0x3fc00000)
#define float64_two make_float64(0x4000000000000000ULL)
#define float64_three make_float64(0x4008000000000000ULL)
#define float64_one_point_five make_float64(0x3FF8000000000000ULL)
float32 HELPER(recpsf_f32)(float32 a, float32 b, void *fpstp)
{
float_status *fpst = fpstp;
a = float32_chs(a);
if ((float32_is_infinity(a) && float32_is_zero(b)) ||
(float32_is_infinity(b) && float32_is_zero(a))) {
return float32_two;
}
return float32_muladd(a, b, float32_two, 0, fpst);
}
float64 HELPER(recpsf_f64)(float64 a, float64 b, void *fpstp)
{
float_status *fpst = fpstp;
a = float64_chs(a);
if ((float64_is_infinity(a) && float64_is_zero(b)) ||
(float64_is_infinity(b) && float64_is_zero(a))) {
return float64_two;
}
return float64_muladd(a, b, float64_two, 0, fpst);
}
float32 HELPER(rsqrtsf_f32)(float32 a, float32 b, void *fpstp)
{
float_status *fpst = fpstp;
a = float32_chs(a);
if ((float32_is_infinity(a) && float32_is_zero(b)) ||
(float32_is_infinity(b) && float32_is_zero(a))) {
return float32_one_point_five;
}
return float32_muladd(a, b, float32_three, float_muladd_halve_result, fpst);
}
float64 HELPER(rsqrtsf_f64)(float64 a, float64 b, void *fpstp)
{
float_status *fpst = fpstp;
a = float64_chs(a);
if ((float64_is_infinity(a) && float64_is_zero(b)) ||
(float64_is_infinity(b) && float64_is_zero(a))) {
return float64_one_point_five;
}
return float64_muladd(a, b, float64_three, float_muladd_halve_result, fpst);
}

View File

@ -27,3 +27,12 @@ DEF_HELPER_3(vfp_cmpes_a64, i64, f32, f32, ptr)
DEF_HELPER_3(vfp_cmpd_a64, i64, f64, f64, ptr)
DEF_HELPER_3(vfp_cmped_a64, i64, f64, f64, ptr)
DEF_HELPER_FLAGS_5(simd_tbl, TCG_CALL_NO_RWG_SE, i64, env, i64, i64, i32, i32)
DEF_HELPER_FLAGS_3(vfp_mulxs, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
DEF_HELPER_FLAGS_3(vfp_mulxd, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
DEF_HELPER_FLAGS_3(neon_ceq_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
DEF_HELPER_FLAGS_3(neon_cge_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
DEF_HELPER_FLAGS_3(neon_cgt_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
DEF_HELPER_FLAGS_3(recpsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
DEF_HELPER_FLAGS_3(recpsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
DEF_HELPER_FLAGS_3(rsqrtsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
DEF_HELPER_FLAGS_3(rsqrtsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,7 @@ DEF_HELPER_1(cpsr_read, i32, env)
DEF_HELPER_3(v7m_msr, void, env, i32, i32)
DEF_HELPER_2(v7m_mrs, i32, env, i32)
DEF_HELPER_2(access_check_cp_reg, void, env, ptr)
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
DEF_HELPER_2(get_cp_reg, i32, env, ptr)
DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
@ -382,6 +383,8 @@ DEF_HELPER_3(neon_cge_f32, i32, i32, i32, ptr)
DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, ptr)
DEF_HELPER_3(neon_acge_f32, i32, i32, i32, ptr)
DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, ptr)
DEF_HELPER_3(neon_acge_f64, i64, i64, i64, ptr)
DEF_HELPER_3(neon_acgt_f64, i64, i64, i64, ptr)
/* iwmmxt_helper.c */
DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)

View File

@ -50,15 +50,29 @@ MISMATCH_CHECK(PSCI_FN_CPU_OFF, KVM_PSCI_FN_CPU_OFF)
MISMATCH_CHECK(PSCI_FN_CPU_ON, KVM_PSCI_FN_CPU_ON)
MISMATCH_CHECK(PSCI_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
/* Note that KVM uses overlapping values for AArch32 and AArch64
* target CPU numbers. AArch32 targets:
*/
#define QEMU_KVM_ARM_TARGET_CORTEX_A15 0
#define QEMU_KVM_ARM_TARGET_CORTEX_A7 1
/* AArch64 targets: */
#define QEMU_KVM_ARM_TARGET_AEM_V8 0
#define QEMU_KVM_ARM_TARGET_FOUNDATION_V8 1
#define QEMU_KVM_ARM_TARGET_CORTEX_A57 2
/* There's no kernel define for this: sentinel value which
* matches no KVM target value for either 64 or 32 bit
*/
#define QEMU_KVM_ARM_TARGET_NONE UINT_MAX
#ifndef TARGET_AARCH64
#ifdef TARGET_AARCH64
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_AEM_V8, KVM_ARM_TARGET_AEM_V8)
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8)
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57)
#else
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15)
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7)
#endif
#define CP_REG_ARM64 0x6000000000000000ULL

View File

@ -1823,6 +1823,22 @@ uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b, void *fpstp)
return -float32_lt(f1, f0, fpst);
}
uint64_t HELPER(neon_acge_f64)(uint64_t a, uint64_t b, void *fpstp)
{
float_status *fpst = fpstp;
float64 f0 = float64_abs(make_float64(a));
float64 f1 = float64_abs(make_float64(b));
return -float64_le(f1, f0, fpst);
}
uint64_t HELPER(neon_acgt_f64)(uint64_t a, uint64_t b, void *fpstp)
{
float_status *fpst = fpstp;
float64 f0 = float64_abs(make_float64(a));
float64 f1 = float64_abs(make_float64(b));
return -float64_lt(f1, f0, fpst);
}
#define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1))
void HELPER(neon_qunzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)

View File

@ -273,44 +273,50 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
}
}
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip)
{
const ARMCPRegInfo *ri = rip;
switch (ri->accessfn(env, ri)) {
case CP_ACCESS_OK:
return;
case CP_ACCESS_TRAP:
case CP_ACCESS_TRAP_UNCATEGORIZED:
/* These cases will eventually need to generate different
* syndrome information.
*/
break;
default:
g_assert_not_reached();
}
raise_exception(env, EXCP_UDEF);
}
void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
{
const ARMCPRegInfo *ri = rip;
int excp = ri->writefn(env, ri, value);
if (excp) {
raise_exception(env, excp);
}
ri->writefn(env, ri, value);
}
uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
{
const ARMCPRegInfo *ri = rip;
uint64_t value;
int excp = ri->readfn(env, ri, &value);
if (excp) {
raise_exception(env, excp);
}
return value;
return ri->readfn(env, ri);
}
void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
{
const ARMCPRegInfo *ri = rip;
int excp = ri->writefn(env, ri, value);
if (excp) {
raise_exception(env, excp);
}
ri->writefn(env, ri, value);
}
uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
{
const ARMCPRegInfo *ri = rip;
uint64_t value;
int excp = ri->readfn(env, ri, &value);
if (excp) {
raise_exception(env, excp);
}
return value;
return ri->readfn(env, ri);
}
/* ??? Flag setting arithmetic is awkward because we need to do comparisons.

File diff suppressed because it is too large Load Diff

View File

@ -6837,6 +6837,17 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
return 1;
}
if (ri->accessfn) {
/* Emit code to perform further access permissions checks at
* runtime; this may result in an exception.
*/
TCGv_ptr tmpptr;
gen_set_pc_im(s, s->pc);
tmpptr = tcg_const_ptr(ri);
gen_helper_access_check_cp_reg(cpu_env, tmpptr);
tcg_temp_free_ptr(tmpptr);
}
/* Handle special cases first */
switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
case ARM_CP_NOP:
@ -6865,7 +6876,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
tmp64 = tcg_const_i64(ri->resetvalue);
} else if (ri->readfn) {
TCGv_ptr tmpptr;
gen_set_pc_im(s, s->pc);
tmp64 = tcg_temp_new_i64();
tmpptr = tcg_const_ptr(ri);
gen_helper_get_cp_reg64(tmp64, cpu_env, tmpptr);
@ -6888,7 +6898,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
tmp = tcg_const_i32(ri->resetvalue);
} else if (ri->readfn) {
TCGv_ptr tmpptr;
gen_set_pc_im(s, s->pc);
tmp = tcg_temp_new_i32();
tmpptr = tcg_const_ptr(ri);
gen_helper_get_cp_reg(tmp, cpu_env, tmpptr);
@ -6923,7 +6932,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
tcg_temp_free_i32(tmphi);
if (ri->writefn) {
TCGv_ptr tmpptr = tcg_const_ptr(ri);
gen_set_pc_im(s, s->pc);
gen_helper_set_cp_reg64(cpu_env, tmpptr, tmp64);
tcg_temp_free_ptr(tmpptr);
} else {
@ -6934,7 +6942,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
if (ri->writefn) {
TCGv_i32 tmp;
TCGv_ptr tmpptr;
gen_set_pc_im(s, s->pc);
tmp = load_reg(s, rt);
tmpptr = tcg_const_ptr(ri);
gen_helper_set_cp_reg(cpu_env, tmpptr, tmp);
@ -6962,6 +6969,19 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
return 0;
}
/* Unknown register; this might be a guest error or a QEMU
* unimplemented feature.
*/
if (is64) {
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
"64 bit system register cp:%d opc1: %d crm:%d\n",
isread ? "read" : "write", cpnum, opc1, crm);
} else {
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
"system register cp:%d opc1:%d crn:%d crm:%d opc2:%d\n",
isread ? "read" : "write", cpnum, opc1, crn, crm, opc2);
}
return 1;
}