mirror of https://gitlab.com/qemu-project/qemu
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
5.1 KiB
C
156 lines
5.1 KiB
C
/*
|
|
* ARM VFP floating-point: handling of FPSCR/FPCR/FPSR
|
|
*
|
|
* Copyright (c) 2003 Fabrice Bellard
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "cpu.h"
|
|
#include "internals.h"
|
|
#include "cpu-features.h"
|
|
|
|
uint32_t vfp_get_fpcr(CPUARMState *env)
|
|
{
|
|
uint32_t fpcr = env->vfp.fpcr
|
|
| (env->vfp.vec_len << 16)
|
|
| (env->vfp.vec_stride << 20);
|
|
|
|
/*
|
|
* M-profile LTPSIZE is the same bits [18:16] as A-profile Len; whichever
|
|
* of the two is not applicable to this CPU will always be zero.
|
|
*/
|
|
fpcr |= env->v7m.ltpsize << 16;
|
|
|
|
return fpcr;
|
|
}
|
|
|
|
uint32_t vfp_get_fpsr(CPUARMState *env)
|
|
{
|
|
uint32_t fpsr = env->vfp.fpsr;
|
|
uint32_t i;
|
|
|
|
fpsr |= vfp_get_fpsr_from_host(env);
|
|
|
|
i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
|
|
fpsr |= i ? FPSR_QC : 0;
|
|
return fpsr;
|
|
}
|
|
|
|
uint32_t vfp_get_fpscr(CPUARMState *env)
|
|
{
|
|
return (vfp_get_fpcr(env) & FPSCR_FPCR_MASK) |
|
|
(vfp_get_fpsr(env) & FPSCR_FPSR_MASK);
|
|
}
|
|
|
|
void vfp_set_fpsr(CPUARMState *env, uint32_t val)
|
|
{
|
|
ARMCPU *cpu = env_archcpu(env);
|
|
|
|
if (arm_feature(env, ARM_FEATURE_NEON) ||
|
|
cpu_isar_feature(aa32_mve, cpu)) {
|
|
/*
|
|
* The bit we set within vfp.qc[] is arbitrary; the array as a
|
|
* whole being zero/non-zero is what counts.
|
|
*/
|
|
env->vfp.qc[0] = val & FPSR_QC;
|
|
env->vfp.qc[1] = 0;
|
|
env->vfp.qc[2] = 0;
|
|
env->vfp.qc[3] = 0;
|
|
}
|
|
|
|
/*
|
|
* NZCV lives only in env->vfp.fpsr. The cumulative exception flags
|
|
* IOC|DZC|OFC|UFC|IXC|IDC also live in env->vfp.fpsr, with possible
|
|
* extra pending exception information that hasn't yet been folded in
|
|
* living in the float_status values (for TCG).
|
|
* Since this FPSR write gives us the up to date values of the exception
|
|
* flags, we want to store into vfp.fpsr the NZCV and CEXC bits, zeroing
|
|
* anything else. We also need to clear out the float_status exception
|
|
* information so that the next vfp_get_fpsr does not fold in stale data.
|
|
*/
|
|
val &= FPSR_NZCV_MASK | FPSR_CEXC_MASK;
|
|
env->vfp.fpsr = val;
|
|
vfp_clear_float_status_exc_flags(env);
|
|
}
|
|
|
|
static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask)
|
|
{
|
|
/*
|
|
* We only set FPCR bits defined by mask, and leave the others alone.
|
|
* We assume the mask is sensible (e.g. doesn't try to set only
|
|
* part of a field)
|
|
*/
|
|
ARMCPU *cpu = env_archcpu(env);
|
|
|
|
/* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
|
|
if (!cpu_isar_feature(any_fp16, cpu)) {
|
|
val &= ~FPCR_FZ16;
|
|
}
|
|
if (!cpu_isar_feature(aa64_afp, cpu)) {
|
|
val &= ~(FPCR_FIZ | FPCR_AH | FPCR_NEP);
|
|
}
|
|
|
|
if (!cpu_isar_feature(aa64_ebf16, cpu)) {
|
|
val &= ~FPCR_EBF;
|
|
}
|
|
|
|
vfp_set_fpcr_to_host(env, val, mask);
|
|
|
|
if (mask & (FPCR_LEN_MASK | FPCR_STRIDE_MASK)) {
|
|
if (!arm_feature(env, ARM_FEATURE_M)) {
|
|
/*
|
|
* Short-vector length and stride; on M-profile these bits
|
|
* are used for different purposes.
|
|
* We can't make this conditional be "if MVFR0.FPShVec != 0",
|
|
* because in v7A no-short-vector-support cores still had to
|
|
* allow Stride/Len to be written with the only effect that
|
|
* some insns are required to UNDEF if the guest sets them.
|
|
*/
|
|
env->vfp.vec_len = extract32(val, 16, 3);
|
|
env->vfp.vec_stride = extract32(val, 20, 2);
|
|
} else if (cpu_isar_feature(aa32_mve, cpu)) {
|
|
env->v7m.ltpsize = extract32(val, FPCR_LTPSIZE_SHIFT,
|
|
FPCR_LTPSIZE_LENGTH);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We don't implement trapped exception handling, so the
|
|
* trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
|
|
*
|
|
* The FPCR bits we keep in vfp.fpcr are AHP, DN, FZ, RMode, EBF, FZ16,
|
|
* FIZ, AH, and NEP.
|
|
* Len, Stride and LTPSIZE we just handled. Store those bits
|
|
* there, and zero any of the other FPCR bits and the RES0 and RAZ/WI
|
|
* bits.
|
|
*/
|
|
val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16 |
|
|
FPCR_EBF | FPCR_FIZ | FPCR_AH | FPCR_NEP;
|
|
env->vfp.fpcr &= ~mask;
|
|
env->vfp.fpcr |= val;
|
|
}
|
|
|
|
void vfp_set_fpcr(CPUARMState *env, uint32_t val)
|
|
{
|
|
vfp_set_fpcr_masked(env, val, MAKE_64BIT_MASK(0, 32));
|
|
}
|
|
|
|
void vfp_set_fpscr(CPUARMState *env, uint32_t val)
|
|
{
|
|
vfp_set_fpcr_masked(env, val, FPSCR_FPCR_MASK);
|
|
vfp_set_fpsr(env, val & FPSCR_FPSR_MASK);
|
|
}
|