Make it harder to have conflicting interrupts.
authorTim 'mithro' Ansell <mithro@mithis.com>
Sun, 29 Oct 2017 17:52:46 +0000 (10:52 -0700)
committerTim 'mithro' Ansell <mithro@mithis.com>
Mon, 30 Oct 2017 02:45:52 +0000 (19:45 -0700)
litex/soc/integration/soc_core.py

index 9e4daac3cfc202f63b72c131022ef83388fd53cb..f899bac4ac0a63263538383d760f11fff333ed72 100644 (file)
@@ -35,7 +35,8 @@ class SoCCore(Module):
         "buttons":        5,  # user
         "leds":           6,  # user
     }
-    interrupt_map = {
+    interrupt_map = {}
+    soc_interrupt_map = {
         "nmi":    0, # Reserve zero for "non-maskable interrupt"
         "timer0": 1, # LiteX Timer
         "uart":   2, # LiteX UART (IRQ 2 for UART matches mor1k standard config).
@@ -124,6 +125,8 @@ class SoCCore(Module):
             else:
                 self.submodules.uart_phy = uart.RS232PHY(platform.request("serial"), clk_freq, uart_baudrate)
                 self.submodules.uart = uart.UART(self.uart_phy)
+        else:
+            del self.soc_interrupt_map["uart"]
 
         if ident:
             if ident_version:
@@ -134,6 +137,33 @@ class SoCCore(Module):
 
         if with_timer:
             self.submodules.timer0 = timer.Timer()
+        else:
+            del self.soc_interrupt_map["timer0"]
+
+        # Invert the interrupt map.
+        interrupt_rmap = {}
+        for mod_name, interrupt in self.interrupt_map.items():
+            assert interrupt not in interrupt_rmap, (
+                "Interrupt vector conflict for IRQ %s, user defined %s conflicts with user defined %s" % (
+                    interrupt, mod_name, interrupt_rmap[interrupt]))
+
+            interrupt_rmap[interrupt] = mod_name
+
+        # Add the base SoC's interrupt map
+        for mod_name, interrupt in self.soc_interrupt_map.items():
+            assert interrupt not in interrupt_rmap, (
+                "Interrupt vector conflict for IRQ %s, user defined %s conflicts with SoC inbuilt %s" % (
+                    interrupt, mod_name, interrupt_rmap[interrupt]))
+
+            self.interrupt_map[mod_name] = interrupt
+            interrupt_rmap[interrupt] = mod_name
+
+        # Make sure other functions are not using this value.
+        self.soc_interrupt_map = None
+
+        # Save the interrupt reverse map
+        self.interrupt_rmap = interrupt_rmap
+
 
     def add_cpu_or_bridge(self, cpu_or_bridge):
         if self.finalized:
@@ -193,7 +223,7 @@ class SoCCore(Module):
 
     def get_constants(self):
         r = []
-        for name, interrupt in sorted(self.interrupt_map.items(), key=itemgetter(1)):
+        for interrupt, name in sorted(self.interrupt_rmap.items()):
             r.append((name.upper() + "_INTERRUPT", interrupt))
         r += self._constants
         return r
@@ -235,9 +265,13 @@ class SoCCore(Module):
 
             # Interrupts
             if hasattr(self.cpu_or_bridge, "interrupt"):
-                for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)):
-                    if hasattr(self, k):
-                        self.comb += self.cpu_or_bridge.interrupt[v].eq(getattr(self, k).ev.irq)
+                for interrupt, mod_name in sorted(self.interrupt_rmap.items()):
+                    if mod_name == "nmi":
+                        continue
+                    assert hasattr(self, mod_name), "Missing module for interrupt %s" % mod_name
+                    mod_impl = getattr(self, mod_name)
+                    assert hasattr(mod_impl, 'ev'), "Submodule %s does not have EventManager (xx.ev) module" % mod_name
+                    self.comb += self.cpu_or_bridge.interrupt[interrupt].eq(mod_impl.ev.irq)
 
     def build(self, *args, **kwargs):
         return self.platform.build(self, *args, **kwargs)