qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-arm] [PATCH 07/18] armv7m: Update NVIC registers


From: Michael Davidsaver
Subject: [Qemu-arm] [PATCH 07/18] armv7m: Update NVIC registers
Date: Sun, 8 Nov 2015 20:11:34 -0500

Replace use of GIC state/functions with new NVIC.

Signed-off-by: Michael Davidsaver <address@hidden>
---
 hw/intc/armv7m_nvic.c | 233 ++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 168 insertions(+), 65 deletions(-)

diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index ebb4d4e..30e349e 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -394,13 +394,13 @@ void set_irq_level(void *opaque, int n, int level)
 
 static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
 {
-    ARMCPU *cpu;
+    ARMCPU *cpu = s->cpu;
     uint32_t val;
     int irq;
 
     switch (offset) {
     case 4: /* Interrupt Control Type.  */
-        return (s->num_irq / 32) - 1;
+        return ((s->num_irq - 16) / 32) - 1;
     case 0x10: /* SysTick Control and Status.  */
         val = s->systick.control;
         s->systick.control &= ~SYSTICK_COUNTFLAG;
@@ -426,45 +426,39 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
     case 0x1c: /* SysTick Calibration Value.  */
         return 10000;
     case 0xd00: /* CPUID Base.  */
-        cpu = ARM_CPU(current_cpu);
         return cpu->midr;
     case 0xd04: /* Interrupt Control State.  */
         /* VECTACTIVE */
-        cpu = ARM_CPU(current_cpu);
         val = cpu->env.v7m.exception;
-        if (val == 1023) {
-            val = 0;
-        } else if (val >= 32) {
-            val -= 16;
-        }
         /* VECTPENDING */
-        if (s->gic.current_pending[0] != 1023)
-            val |= (s->gic.current_pending[0] << 12);
+        val |= (cpu->env.v7m.pending << 12)&0x1ff;
         /* ISRPENDING and RETTOBASE */
-        for (irq = 32; irq < s->num_irq; irq++) {
-            if (s->gic.irq_state[irq].pending) {
+        for (irq = 16; irq < s->num_irq; irq++) {
+            if (s->vectors[irq].pending) {
                 val |= (1 << 22);
                 break;
             }
-            if (irq != cpu->env.v7m.exception && s->gic.irq_state[irq].active) 
{
+            if (irq != cpu->env.v7m.exception && s->vectors[irq].active) {
                 val |= (1 << 11);
             }
         }
         /* PENDSTSET */
-        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
+        if (s->vectors[ARMV7M_EXCP_SYSTICK].pending) {
             val |= (1 << 26);
+        }
         /* PENDSVSET */
-        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
+        if (s->vectors[ARMV7M_EXCP_PENDSV].pending) {
             val |= (1 << 28);
+        }
         /* NMIPENDSET */
-        if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
+        if (s->vectors[ARMV7M_EXCP_NMI].pending) {
             val |= (1 << 31);
+        }
         return val;
     case 0xd08: /* Vector Table Offset.  */
-        cpu = ARM_CPU(current_cpu);
         return cpu->env.v7m.vecbase;
     case 0xd0c: /* Application Interrupt/Reset Control.  */
-        return 0xfa050000;
+        return 0xfa050000 | (s->prigroup<<8);
     case 0xd10: /* System Control.  */
         /* TODO: Implement SLEEPONEXIT.  */
         return 0;
@@ -473,20 +467,20 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
         return 0;
     case 0xd24: /* System Handler Status.  */
         val = 0;
-        if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
-        if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
-        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
-        if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
-        if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
-        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
-        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
-        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
-        if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
-        if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
-        if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
-        if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
-        if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
-        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
+        if (s->vectors[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
+        if (s->vectors[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
+        if (s->vectors[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
+        if (s->vectors[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
+        if (s->vectors[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
+        if (s->vectors[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
+        if (s->vectors[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
+        if (s->vectors[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
+        if (s->vectors[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
+        if (s->vectors[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
+        if (s->vectors[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
+        if (s->vectors[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
+        if (s->vectors[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
+        if (s->vectors[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
         return val;
     case 0xd28: /* Configurable Fault Status.  */
         /* TODO: Implement Fault Status.  */
@@ -535,7 +529,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
 
 static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
 {
-    ARMCPU *cpu;
+    ARMCPU *cpu = s->cpu;
     uint32_t oldval;
     switch (offset) {
     case 0x10: /* SysTick Control and Status.  */
@@ -577,18 +571,15 @@ static void nvic_writel(nvic_state *s, uint32_t offset, 
uint32_t value)
         if (value & (1 << 28)) {
             armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
         } else if (value & (1 << 27)) {
-            s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
-            gic_update(&s->gic);
+            armv7m_nvic_clear_pending(s, ARMV7M_EXCP_PENDSV);
         }
         if (value & (1 << 26)) {
             armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
         } else if (value & (1 << 25)) {
-            s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
-            gic_update(&s->gic);
+            armv7m_nvic_clear_pending(s, ARMV7M_EXCP_SYSTICK);
         }
         break;
     case 0xd08: /* Vector Table Offset.  */
-        cpu = ARM_CPU(current_cpu);
         cpu->env.v7m.vecbase = value & 0xffffff80;
         break;
     case 0xd0c: /* Application Interrupt/Reset Control.  */
@@ -603,7 +594,13 @@ static void nvic_writel(nvic_state *s, uint32_t offset, 
uint32_t value)
                 qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
             }
             if (value & 0x700) {
-                qemu_log_mask(LOG_UNIMP, "PRIGROUP unimplemented\n");
+                unsigned i;
+                s->prigroup = (value>>8)&0xf;
+                /* recalculate prio_ord for exceptions w/ configurable prio */
+                for (i = 4; i < s->num_irq; i++) {
+                    set_prio(s, i, s->vectors[i].raw_prio);
+                }
+                nvic_irq_update(s, 0);
             }
         }
         break;
@@ -615,9 +612,12 @@ static void nvic_writel(nvic_state *s, uint32_t offset, 
uint32_t value)
     case 0xd24: /* System Handler Control.  */
         /* TODO: Real hardware allows you to set/clear the active bits
            under some circumstances.  We don't implement this.  */
-        s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
-        s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
-        s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
+        s->vectors[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
+        s->vectors[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
+        s->vectors[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
+        /* no need to call nvic_irq_update() since any pending while
+         * disabled would have been escalated to HardFault
+         */
         break;
     case 0xd28: /* Configurable Fault Status.  */
     case 0xd2c: /* Hard Fault Status.  */
@@ -629,8 +629,8 @@ static void nvic_writel(nvic_state *s, uint32_t offset, 
uint32_t value)
                       "NVIC: fault status registers unimplemented\n");
         break;
     case 0xf00: /* Software Triggered Interrupt Register */
-        if ((value & 0x1ff) < s->num_irq) {
-            gic_set_pending_private(&s->gic, 0, value & 0x1ff);
+        if ((value & 0x1ff) < NVIC_MAX_IRQ) {
+            armv7m_nvic_set_pending(s, (value&0x1ff)+16);
         }
         break;
     default:
@@ -644,28 +644,81 @@ static uint64_t nvic_sysreg_read(void *opaque, hwaddr 
addr,
 {
     nvic_state *s = (nvic_state *)opaque;
     uint32_t offset = addr;
-    int i;
+    unsigned i, end;
     uint32_t val;
 
     switch (offset) {
+    /* reads of set and clear both return the status */
+    case 0x100 ... 0x13c: /* NVIC Set enable */
+        offset += 0x80;
+        /* fall through */
+    case 0x180 ... 0x1bc: /* NVIC Clear enable */
+        val = 0;
+        offset = offset-0x180+16; /* vector # */
+
+        for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+            if (s->vectors[offset+i].enabled) {
+                val |= (1<<i);
+            }
+        }
+        break;
+    case 0x200 ... 0x23c: /* NVIC Set pend */
+        offset += 0x80;
+        /* fall through */
+    case 0x280 ... 0x2bc: /* NVIC Clear pend */
+        val = 0;
+        offset = offset-0x280+16; /* vector # */
+
+        for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+            if (s->vectors[offset+i].pending) {
+                val |= (1<<i);
+            }
+        }
+        break;
+    case 0x300 ... 0x37c: /* NVIC Active */
+        val = 0;
+        offset = offset-0x300+16; /* vector # */
+
+        for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+            if (s->vectors[offset+i].active) {
+                val |= (1<<i);
+            }
+        }
+        break;
+    case 0x400 ... 0x7ec: /* NVIC Priority */
+        val = 0;
+        offset = offset-0x400+16; /* vector # */
+
+        for (i = 0; i < size && offset+i < s->num_irq; i++) {
+            val |= s->vectors[offset+i].raw_prio<<(8*i);
+        }
+        break;
     case 0xd18 ... 0xd23: /* System Handler Priority.  */
         val = 0;
         for (i = 0; i < size; i++) {
-            val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
+            val |= s->vectors[(offset - 0xd14) + i].raw_prio << (i * 8);
         }
-        return val;
+        break;
     case 0xfe0 ... 0xfff: /* ID.  */
         if (offset & 3) {
             return 0;
         }
-        return nvic_id[(offset - 0xfe0) >> 2];
-    }
-    if (size == 4) {
-        return nvic_readl(s, offset);
+        val = nvic_id[(offset - 0xfe0) >> 2];
+        break;
+    default:
+        if (size == 4) {
+            val = nvic_readl(s, offset);
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "NVIC: Bad read of size %d at offset 0x%x\n",
+                          size, offset);
+            val = 0;
+        }
     }
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
-    return 0;
+
+    DPRINTF(0, "sysreg read%u "TARGET_FMT_plx" -> %08x\n",
+            size*8, addr, (unsigned)val);
+    return val;
 }
 
 static void nvic_sysreg_write(void *opaque, hwaddr addr,
@@ -673,23 +726,73 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr,
 {
     nvic_state *s = (nvic_state *)opaque;
     uint32_t offset = addr;
-    int i;
+    unsigned i, end;
+    unsigned setval = 0;
+
+    DPRINTF(0, "sysreg write%u "TARGET_FMT_plx" <- %08x\n",
+            size*8, addr, (unsigned)value);
 
     switch (offset) {
-    case 0xd18 ... 0xd23: /* System Handler Priority.  */
+    case 0x100 ... 0x13c: /* NVIC Set enable */
+        offset += 0x80;
+        setval = 1;
+        /* fall through */
+    case 0x180 ... 0x1bc: /* NVIC Clear enable */
+        offset = offset-0x180+16; /* vector # */
+
+        for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+            if (value&(1<<i)) {
+                s->vectors[offset+i].enabled = setval;
+            }
+        }
+        nvic_irq_update(s, 0);
+        return;
+    case 0x200 ... 0x23c: /* NVIC Set pend */
+        /* the special logic in armv7m_nvic_set_pending()
+         * is not needed since IRQs are never escalated
+         */
+        offset += 0x80;
+        setval = 1;
+        /* fall through */
+    case 0x280 ... 0x2bc: /* NVIC Clear pend */
+        offset = offset-0x280+16; /* vector # */
+
+        for (i = 0, end = size*8; i < end && offset+i < s->num_irq; i++) {
+            if (value&(1<<i)) {
+                s->vectors[offset+i].pending = setval;
+            }
+        }
+        nvic_irq_update(s, 0);
+        return;
+    case 0x300 ... 0x37c: /* NVIC Active */
+        return; /* R/O */
+    case 0x400 ... 0x7ec: /* NVIC Priority */
+        offset = offset-0x400+16; /* vector # */
+
         for (i = 0; i < size; i++) {
-            s->gic.priority1[(offset - 0xd14) + i][0] =
-                (value >> (i * 8)) & 0xff;
+            set_prio(s, offset+i, (value>>(i*8))&0xff);
         }
-        gic_update(&s->gic);
+        nvic_irq_update(s, 0);
         return;
-    }
-    if (size == 4) {
-        nvic_writel(s, offset, value);
+    case 0xd18 ... 0xd23: /* System Handler Priority.  */
+        for (i = 0; i < size; i++) {
+            unsigned hdlidx = (offset - 0xd14) + i;
+            set_prio(s, hdlidx, (value >> (i * 8)) & 0xff);
+            DPRINTF(0, "Set Handler prio %u = %u\n",
+                    (unsigned)hdlidx,
+                    (unsigned)s->vectors[hdlidx].raw_prio);
+        }
+        nvic_irq_update(s, 0);
         return;
+    default:
+        if (size == 4) {
+            nvic_writel(s, offset, value);
+            return;
+        }
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "NVIC: Bad write of size %d at offset 0x%x\n",
+                      size, offset);
     }
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
 }
 
 static const MemoryRegionOps nvic_sysreg_ops = {
-- 
2.1.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]