aboutsummaryrefslogtreecommitdiff
path: root/hw/intc/armv7m_nvic.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-04-29 17:35:58 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-04-29 17:35:58 +0100
commitd33abe82c7c9847284a23e575e1078cccab540b5 (patch)
tree9878dcce1f87a2ac46c0e89044829392c240e64b /hw/intc/armv7m_nvic.c
parent84d2e3e2ae76fdb0c8f3063fa8c46c8ce14ab201 (diff)
downloadqemu-d33abe82c7c9847284a23e575e1078cccab540b5.zip
qemu-d33abe82c7c9847284a23e575e1078cccab540b5.tar.gz
qemu-d33abe82c7c9847284a23e575e1078cccab540b5.tar.bz2
target/arm: Implement dummy versions of M-profile FP-related registers
The M-profile floating point support has three associated config registers: FPCAR, FPCCR and FPDSCR. It also makes the registers CPACR and NSACR have behaviour other than reads-as-zero. Add support for all of these as simple reads-as-written registers. We will hook up actual functionality later. The main complexity here is handling the FPCCR register, which has a mix of banked and unbanked bits. Note that we don't share storage with the A-profile cpu->cp15.nsacr and cpu->cp15.cpacr_el1, though the behaviour is quite similar, for two reasons: * the M profile CPACR is banked between security states * it preserves the invariant that M profile uses no state inside the cp15 substruct Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20190416125744.27770-4-peter.maydell@linaro.org
Diffstat (limited to 'hw/intc/armv7m_nvic.c')
-rw-r--r--hw/intc/armv7m_nvic.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 45d72f8..5eb438f 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -1077,6 +1077,16 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
}
case 0xd84: /* CSSELR */
return cpu->env.v7m.csselr[attrs.secure];
+ case 0xd88: /* CPACR */
+ if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ return 0;
+ }
+ return cpu->env.v7m.cpacr[attrs.secure];
+ case 0xd8c: /* NSACR */
+ if (!attrs.secure || !arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ return 0;
+ }
+ return cpu->env.v7m.nsacr;
/* TODO: Implement debug registers. */
case 0xd90: /* MPU_TYPE */
/* Unified MPU; if the MPU is not present this value is zero */
@@ -1222,6 +1232,43 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
return 0;
}
return cpu->env.v7m.sfar;
+ case 0xf34: /* FPCCR */
+ if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ return 0;
+ }
+ if (attrs.secure) {
+ return cpu->env.v7m.fpccr[M_REG_S];
+ } else {
+ /*
+ * NS can read LSPEN, CLRONRET and MONRDY. It can read
+ * BFRDY and HFRDY if AIRCR.BFHFNMINS != 0;
+ * other non-banked bits RAZ.
+ * TODO: MONRDY should RAZ/WI if DEMCR.SDME is set.
+ */
+ uint32_t value = cpu->env.v7m.fpccr[M_REG_S];
+ uint32_t mask = R_V7M_FPCCR_LSPEN_MASK |
+ R_V7M_FPCCR_CLRONRET_MASK |
+ R_V7M_FPCCR_MONRDY_MASK;
+
+ if (s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) {
+ mask |= R_V7M_FPCCR_BFRDY_MASK | R_V7M_FPCCR_HFRDY_MASK;
+ }
+
+ value &= mask;
+
+ value |= cpu->env.v7m.fpccr[M_REG_NS];
+ return value;
+ }
+ case 0xf38: /* FPCAR */
+ if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ return 0;
+ }
+ return cpu->env.v7m.fpcar[attrs.secure];
+ case 0xf3c: /* FPDSCR */
+ if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ return 0;
+ }
+ return cpu->env.v7m.fpdscr[attrs.secure];
case 0xf40: /* MVFR0 */
return cpu->isar.mvfr0;
case 0xf44: /* MVFR1 */
@@ -1475,6 +1522,18 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
cpu->env.v7m.csselr[attrs.secure] = value & R_V7M_CSSELR_INDEX_MASK;
}
break;
+ case 0xd88: /* CPACR */
+ if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ /* We implement only the Floating Point extension's CP10/CP11 */
+ cpu->env.v7m.cpacr[attrs.secure] = value & (0xf << 20);
+ }
+ break;
+ case 0xd8c: /* NSACR */
+ if (attrs.secure && arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ /* We implement only the Floating Point extension's CP10/CP11 */
+ cpu->env.v7m.nsacr = value & (3 << 10);
+ }
+ break;
case 0xd90: /* MPU_TYPE */
return; /* RO */
case 0xd94: /* MPU_CTRL */
@@ -1703,6 +1762,72 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
}
break;
}
+ case 0xf34: /* FPCCR */
+ if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ /* Not all bits here are banked. */
+ uint32_t fpccr_s;
+
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
+ /* Don't allow setting of bits not present in v7M */
+ value &= (R_V7M_FPCCR_LSPACT_MASK |
+ R_V7M_FPCCR_USER_MASK |
+ R_V7M_FPCCR_THREAD_MASK |
+ R_V7M_FPCCR_HFRDY_MASK |
+ R_V7M_FPCCR_MMRDY_MASK |
+ R_V7M_FPCCR_BFRDY_MASK |
+ R_V7M_FPCCR_MONRDY_MASK |
+ R_V7M_FPCCR_LSPEN_MASK |
+ R_V7M_FPCCR_ASPEN_MASK);
+ }
+ value &= ~R_V7M_FPCCR_RES0_MASK;
+
+ if (!attrs.secure) {
+ /* Some non-banked bits are configurably writable by NS */
+ fpccr_s = cpu->env.v7m.fpccr[M_REG_S];
+ if (!(fpccr_s & R_V7M_FPCCR_LSPENS_MASK)) {
+ uint32_t lspen = FIELD_EX32(value, V7M_FPCCR, LSPEN);
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, LSPEN, lspen);
+ }
+ if (!(fpccr_s & R_V7M_FPCCR_CLRONRETS_MASK)) {
+ uint32_t cor = FIELD_EX32(value, V7M_FPCCR, CLRONRET);
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, CLRONRET, cor);
+ }
+ if ((s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
+ uint32_t hfrdy = FIELD_EX32(value, V7M_FPCCR, HFRDY);
+ uint32_t bfrdy = FIELD_EX32(value, V7M_FPCCR, BFRDY);
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
+ }
+ /* TODO MONRDY should RAZ/WI if DEMCR.SDME is set */
+ {
+ uint32_t monrdy = FIELD_EX32(value, V7M_FPCCR, MONRDY);
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, MONRDY, monrdy);
+ }
+
+ /*
+ * All other non-banked bits are RAZ/WI from NS; write
+ * just the banked bits to fpccr[M_REG_NS].
+ */
+ value &= R_V7M_FPCCR_BANKED_MASK;
+ cpu->env.v7m.fpccr[M_REG_NS] = value;
+ } else {
+ fpccr_s = value;
+ }
+ cpu->env.v7m.fpccr[M_REG_S] = fpccr_s;
+ }
+ break;
+ case 0xf38: /* FPCAR */
+ if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ value &= ~7;
+ cpu->env.v7m.fpcar[attrs.secure] = value;
+ }
+ break;
+ case 0xf3c: /* FPDSCR */
+ if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ value &= 0x07c00000;
+ cpu->env.v7m.fpdscr[attrs.secure] = value;
+ }
+ break;
case 0xf50: /* ICIALLU */
case 0xf58: /* ICIMVAU */
case 0xf5c: /* DCIMVAC */