aboutsummaryrefslogtreecommitdiff
path: root/target/xtensa
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2020-07-05 17:31:59 -0700
committerMax Filippov <jcmvbkbc@gmail.com>2020-08-21 12:48:14 -0700
commita7d479ee51c5911c93ee931efe4c2413b54c8756 (patch)
treeb20ef102ab90ee39b39f71df5208f08899bf5c42 /target/xtensa
parent91dc2b2d12a0343f37a3ab425f2912ae0ce18187 (diff)
target/xtensa: implement NMI support
When NMI is configured it is taken regardless of INTENABLE SR contents, PS.INTLEVEL or PS.EXCM. It is cleared automatically once it's taken. Add nmi_level to XtensaConfig, puth there NMI level from the overlay or XCHAL_NUM_INTLEVELS + 1 when NMI is not configured. Add NMI mask to INTENABLE SR and limit CINTLEVEL to nmi_level - 1 when determining pending IRQ level in check_interrupt(). Always take and clear pending interrupt at nmi_level in the handle_interrupt(). Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'target/xtensa')
-rw-r--r--target/xtensa/cpu.h1
-rw-r--r--target/xtensa/exc_helper.c23
-rw-r--r--target/xtensa/overlay_tool.h6
3 files changed, 21 insertions, 9 deletions
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 65f0002850..0c96181212 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -433,6 +433,7 @@ struct XtensaConfig {
uint32_t exception_vector[EXC_MAX];
unsigned ninterrupt;
unsigned nlevel;
+ unsigned nmi_level;
uint32_t interrupt_vector[MAX_NLEVEL + MAX_NNMI + 1];
uint32_t level_mask[MAX_NLEVEL + MAX_NNMI + 1];
uint32_t inttype_mask[INTTYPE_MAX];
diff --git a/target/xtensa/exc_helper.c b/target/xtensa/exc_helper.c
index 601341d13a..58a64e6d62 100644
--- a/target/xtensa/exc_helper.c
+++ b/target/xtensa/exc_helper.c
@@ -132,11 +132,15 @@ void HELPER(intset)(CPUXtensaState *env, uint32_t v)
v & env->config->inttype_mask[INTTYPE_SOFTWARE]);
}
+static void intclear(CPUXtensaState *env, uint32_t v)
+{
+ atomic_and(&env->sregs[INTSET], ~v);
+}
+
void HELPER(intclear)(CPUXtensaState *env, uint32_t v)
{
- atomic_and(&env->sregs[INTSET],
- ~(v & (env->config->inttype_mask[INTTYPE_SOFTWARE] |
- env->config->inttype_mask[INTTYPE_EDGE])));
+ intclear(env, v & (env->config->inttype_mask[INTTYPE_SOFTWARE] |
+ env->config->inttype_mask[INTTYPE_EDGE]));
}
static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
@@ -159,11 +163,11 @@ static void handle_interrupt(CPUXtensaState *env)
{
int level = env->pending_irq_level;
- if (level > xtensa_get_cintlevel(env) &&
- level <= env->config->nlevel &&
- (env->config->level_mask[level] &
- env->sregs[INTSET] &
- env->sregs[INTENABLE])) {
+ if ((level > xtensa_get_cintlevel(env) &&
+ level <= env->config->nlevel &&
+ (env->config->level_mask[level] &
+ env->sregs[INTSET] & env->sregs[INTENABLE])) ||
+ level == env->config->nmi_level) {
CPUState *cs = env_cpu(env);
if (level > 1) {
@@ -173,6 +177,9 @@ static void handle_interrupt(CPUXtensaState *env)
(env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
env->pc = relocated_vector(env,
env->config->interrupt_vector[level]);
+ if (level == env->config->nmi_level) {
+ intclear(env, env->config->inttype_mask[INTTYPE_NMI]);
+ }
} else {
env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h
index a994e69b6e..eb9f08af0b 100644
--- a/target/xtensa/overlay_tool.h
+++ b/target/xtensa/overlay_tool.h
@@ -216,6 +216,9 @@
#define XTHAL_INTTYPE_IDMA_ERR INTTYPE_IDMA_ERR
#define XTHAL_INTTYPE_GS_ERR INTTYPE_GS_ERR
+#ifndef XCHAL_NMILEVEL
+#define XCHAL_NMILEVEL (XCHAL_NUM_INTLEVELS + 1)
+#endif
#define INTERRUPT(i) { \
.level = XCHAL_INT ## i ## _LEVEL, \
@@ -305,7 +308,8 @@
#define INTERRUPTS_SECTION \
.ninterrupt = XCHAL_NUM_INTERRUPTS, \
- .nlevel = XCHAL_NUM_INTLEVELS, \
+ .nlevel = XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI, \
+ .nmi_level = XCHAL_NMILEVEL, \
.interrupt_vector = INTERRUPT_VECTORS, \
.level_mask = LEVEL_MASKS, \
.inttype_mask = INTTYPE_MASKS, \