From e07bd71b16932a504b7435a96901a3b0eb5a99cd Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Mon, 16 Oct 2017 02:24:29 +1100 Subject: [PATCH 1/5] build/xilinx: Fixing settings finding. * Better error messages. * Search correct directories; - XXX/Vivado/ - XXX//ISE_DS/ --- litex/build/xilinx/common.py | 40 +++++++++++++++++++++++++----------- litex/build/xilinx/ise.py | 2 +- litex/build/xilinx/vivado.py | 8 ++++---- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/litex/build/xilinx/common.py b/litex/build/xilinx/common.py index c747945b1..170e67e25 100644 --- a/litex/build/xilinx/common.py +++ b/litex/build/xilinx/common.py @@ -31,33 +31,49 @@ if _have_colorama: ] -def settings(path, ver=None, sub=None): - if ver is None: - vers = list(tools.versions(path)) - if not vers: - raise OSError("no version directory for Xilinx tools found in " - + path) - ver = max(vers) +def settings(path, name=None, ver=None, first=None): + if first == "version": + if not ver: + vers = tools.versions(path) + ver = max(vers) - full = os.path.join(path, str(ver)) - if sub: - full = os.path.join(full, sub) + full = os.path.join(path, str(ver), name) + + elif first == "name": + path = os.path.join(path, name) + + if not ver: + vers = tools.versions(path) + ver = max(vers) + + full = os.path.join(path, str(ver)) + + if not vers: + raise OSError( + "no version directory for Xilinx tools found in {}".format( + path)) search = [64, 32] if tools.arch_bits() == 32: - search.reverse() + search = [32] if sys.platform == "win32" or sys.platform == "cygwin": script_ext = "bat" else: script_ext = "sh" + searched_in = [] for b in search: settings = os.path.join(full, "settings{0}.{1}".format(b, script_ext)) if os.path.exists(settings): return settings + searched_in.append(settings) - raise OSError("no Xilinx tools settings file found") + raise OSError( + "no Xilinx tools settings file found.\n" + "Looked in:\n" + " " + + "\n ".join(searched_in)) class XilinxMultiRegImpl(MultiRegImpl): diff --git a/litex/build/xilinx/ise.py b/litex/build/xilinx/ise.py index 0356f9644..171fbef0c 100644 --- a/litex/build/xilinx/ise.py +++ b/litex/build/xilinx/ise.py @@ -96,7 +96,7 @@ def _run_ise(build_name, ise_path, source, mode, ngdbuild_opt, build_script_contents = "# Autogenerated by LiteX\nset -e\n" fail_stmt = "" if source: - settings = common.settings(ise_path, ver, "ISE_DS") + settings = common.settings(ise_path, "ISE_DS", ver, first="version") build_script_contents += source_cmd + settings + "\n" ext = "ngc" diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 8051e1676..8511a5c50 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -59,7 +59,7 @@ def _run_vivado(build_name, vivado_path, source, ver=None): command = build_script_file else: build_script_contents = "# Autogenerated by LiteX\nset -e\n" - settings = common.settings(vivado_path, ver) + settings = common.settings(vivado_path, "Vivado", ver, first="name") build_script_contents += "source " + settings + "\n" build_script_contents += "vivado -mode batch -source " + build_name + ".tcl\n" build_script_file = "build_" + build_name + ".sh" @@ -172,11 +172,11 @@ class XilinxVivadoToolchain: toolchain_path=None, source=True, run=True, **kwargs): if toolchain_path is None: if sys.platform == "win32": - toolchain_path = "C:\\Xilinx\\Vivado" + toolchain_path = "C:\\Xilinx" elif sys.platform == "cygwin": - toolchain_path = "/cygdrive/c/Xilinx/Vivado" + toolchain_path = "/cygdrive/c/Xilinx" else: - toolchain_path = "/opt/Xilinx/Vivado" + toolchain_path = "/opt/Xilinx" os.makedirs(build_dir, exist_ok=True) cwd = os.getcwd() os.chdir(build_dir) From 73e0036b9926d69cdff974e8adef707af42f1611 Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Sun, 29 Oct 2017 08:13:11 -0700 Subject: [PATCH 2/5] Change the default IRQs. * Reserve IRQ 0 to be used as a "non-maskable interrupt" (NMI) in the future. * Use IRQ 2 for the LiteX. This matches the standard mor1k config which connects the UART to IRQ 2. This change is needed for Linux running on LiteX as it gets grumpy with using IRQ 0 for anything other other than an NMI. --- litex/soc/integration/soc_core.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index 13723e4ef..9e4daac3c 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -36,8 +36,9 @@ class SoCCore(Module): "leds": 6, # user } interrupt_map = { - "uart": 0, - "timer0": 1, + "nmi": 0, # Reserve zero for "non-maskable interrupt" + "timer0": 1, # LiteX Timer + "uart": 2, # LiteX UART (IRQ 2 for UART matches mor1k standard config). } mem_map = { "rom": 0x00000000, # (default shadow @0x80000000) From ff72757b870d6ac810cba7fcf8c5400a163e8340 Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Sun, 29 Oct 2017 10:39:01 -0700 Subject: [PATCH 3/5] Bump the IRQ for liteeth based targets. --- litex/boards/targets/arty.py | 2 +- litex/boards/targets/kc705.py | 2 +- litex/boards/targets/nexys_video.py | 2 +- litex/boards/targets/sim.py | 2 +- litex/boards/targets/simple.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/boards/targets/arty.py b/litex/boards/targets/arty.py index 75d58a9b5..64d892f87 100755 --- a/litex/boards/targets/arty.py +++ b/litex/boards/targets/arty.py @@ -124,7 +124,7 @@ class MiniSoC(BaseSoC): csr_map.update(BaseSoC.csr_map) interrupt_map = { - "ethmac": 2, + "ethmac": 3, } interrupt_map.update(BaseSoC.interrupt_map) diff --git a/litex/boards/targets/kc705.py b/litex/boards/targets/kc705.py index 37297f330..541d3dea9 100755 --- a/litex/boards/targets/kc705.py +++ b/litex/boards/targets/kc705.py @@ -104,7 +104,7 @@ class MiniSoC(BaseSoC): csr_map.update(BaseSoC.csr_map) interrupt_map = { - "ethmac": 2, + "ethmac": 3, } interrupt_map.update(BaseSoC.interrupt_map) diff --git a/litex/boards/targets/nexys_video.py b/litex/boards/targets/nexys_video.py index 75774e945..77b54688b 100755 --- a/litex/boards/targets/nexys_video.py +++ b/litex/boards/targets/nexys_video.py @@ -113,7 +113,7 @@ class MiniSoC(BaseSoC): csr_map.update(BaseSoC.csr_map) interrupt_map = { - "ethmac": 2, + "ethmac": 3, } interrupt_map.update(BaseSoC.interrupt_map) diff --git a/litex/boards/targets/sim.py b/litex/boards/targets/sim.py index 1624441fc..04371fd9f 100755 --- a/litex/boards/targets/sim.py +++ b/litex/boards/targets/sim.py @@ -68,7 +68,7 @@ class MiniSoC(BaseSoC): csr_map.update(BaseSoC.csr_map) interrupt_map = { - "ethmac": 2, + "ethmac": 3, } interrupt_map.update(BaseSoC.interrupt_map) diff --git a/litex/boards/targets/simple.py b/litex/boards/targets/simple.py index 179581b43..88c8afd37 100755 --- a/litex/boards/targets/simple.py +++ b/litex/boards/targets/simple.py @@ -30,7 +30,7 @@ class MiniSoC(BaseSoC): csr_map.update(BaseSoC.csr_map) interrupt_map = { - "ethmac": 2, + "ethmac": 3, } interrupt_map.update(BaseSoC.interrupt_map) From 295e78ee9ea2e9ccf12655cac697457dfd7185cc Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Sun, 29 Oct 2017 10:52:46 -0700 Subject: [PATCH 4/5] Make it harder to have conflicting interrupts. --- litex/soc/integration/soc_core.py | 44 +++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index 9e4daac3c..f899bac4a 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -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) From 56ef22902926e5edfdb524a064804823fe449502 Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Sun, 29 Oct 2017 11:11:53 -0700 Subject: [PATCH 5/5] Make the interrupt dicts read only. --- litex/soc/integration/soc_core.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index f899bac4a..6274216a2 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -25,6 +25,19 @@ def mem_decoder(address, start=26, end=29): return lambda a: a[start:end] == ((address >> (start+2)) & (2**(end-start))-1) +class ReadOnlyDict(dict): + def __readonly__(self, *args, **kwargs): + raise RuntimeError("Cannot modify ReadOnlyDict") + __setitem__ = __readonly__ + __delitem__ = __readonly__ + pop = __readonly__ + popitem = __readonly__ + clear = __readonly__ + update = __readonly__ + setdefault = __readonly__ + del __readonly__ + + class SoCCore(Module): csr_map = { "crg": 0, # user @@ -161,8 +174,11 @@ class SoCCore(Module): # Make sure other functions are not using this value. self.soc_interrupt_map = None + # Make the interrupt vector read only + self.interrupt_map = ReadOnlyDict(self.interrupt_map) + # Save the interrupt reverse map - self.interrupt_rmap = interrupt_rmap + self.interrupt_rmap = ReadOnlyDict(interrupt_rmap) def add_cpu_or_bridge(self, cpu_or_bridge):