Implement Configuration and Control register. Handle STACKALIGN and USERSETMPEND bits.
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com> --- hw/intc/armv7m_nvic.c | 15 +++++++++++---- target-arm/cpu.h | 1 + target-arm/helper.c | 8 +++----- target-arm/machine.c | 1 + 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index a75dd3c..ca8c93c 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -474,8 +474,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) /* TODO: Implement SLEEPONEXIT. */ return 0; case 0xd14: /* Configuration Control. */ - /* TODO: Implement Configuration Control bits. */ - return 0; + return cpu->env.v7m.ccr; case 0xd24: /* System Handler Status. */ val = 0; if (s->vectors[ARMV7M_EXCP_MEM].active) val |= (1 << 0); @@ -619,9 +618,17 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) } break; case 0xd10: /* System Control. */ - case 0xd14: /* Configuration Control. */ /* TODO: Implement control registers. */ - qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n"); + qemu_log_mask(LOG_UNIMP, "NVIC: SCR unimplemented\n"); + break; + case 0xd14: /* Configuration Control. */ + value &= 0x31b; + if (value&0x118) { + qemu_log_mask(LOG_UNIMP, "CCR unimplemented bits" + " BFHFNMIGN, DIV_0_TRP, UNALIGN_TRP"); + value &= ~0x118; + } + cpu->env.v7m.ccr = value; break; case 0xd24: /* System Handler Control. */ /* TODO: Real hardware allows you to set/clear the active bits diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 72b0b32..90ccdcd 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -396,6 +396,7 @@ typedef struct CPUARMState { uint32_t vecbase; uint32_t basepri; uint32_t control; + uint32_t ccr; /* Configuration and Control */ uint32_t cfsr; /* Configurable Fault Status */ uint32_t hfsr; /* HardFault Status */ int current_sp; diff --git a/target-arm/helper.c b/target-arm/helper.c index 3993f77..402bfc5 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5412,7 +5412,7 @@ static void do_v7m_exception_exit(CPUARMState *env) break; case 0x9: /* Return to Thread mode w/ Main stack */ case 0xd: /* Return to Thread mode w/ Process stack */ - if (env->v7m.exception != 0) { + if ((env->v7m.exception != 0) && !(env->v7m.ccr&1)) { /* Attempt to return to Thread mode * from nested handler while NONBASETHRDENA not set. */ @@ -5564,10 +5564,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "... as %d\n", env->v7m.exception); - /* Align stack pointer. */ - /* ??? Should only do this if Configuration Control Register - STACKALIGN bit is set. */ - if (env->regs[13] & 4) { + /* Align stack pointer (STACKALIGN) */ + if (env->v7m.ccr&(1<<9)) { env->regs[13] -= 4; xpsr |= 0x200; } diff --git a/target-arm/machine.c b/target-arm/machine.c index d7c2034..e8b710d 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -100,6 +100,7 @@ static const VMStateDescription vmstate_m = { VMSTATE_UINT32(env.v7m.vecbase, ARMCPU), VMSTATE_UINT32(env.v7m.basepri, ARMCPU), VMSTATE_UINT32(env.v7m.control, ARMCPU), + VMSTATE_UINT32(env.v7m.ccr, ARMCPU), VMSTATE_UINT32(env.v7m.cfsr, ARMCPU), VMSTATE_UINT32(env.v7m.hfsr, ARMCPU), VMSTATE_INT32(env.v7m.current_sp, ARMCPU), -- 2.1.4