From 6ad6d1e414c727f1beea0f256c0fdff7665e13a5 Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Sat, 10 Sep 2022 10:13:18 +0200 Subject: [PATCH 01/24] =?UTF-8?q?cores/dma:=20Don=E2=80=99t=20drop=20data?= =?UTF-8?q?=20while=20idle.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- litex/soc/cores/dma.py | 1 - 1 file changed, 1 deletion(-) diff --git a/litex/soc/cores/dma.py b/litex/soc/cores/dma.py index 969109f6d..99b9b7dcc 100644 --- a/litex/soc/cores/dma.py +++ b/litex/soc/cores/dma.py @@ -182,7 +182,6 @@ class WishboneDMAWriter(Module, AutoCSR): self.submodules += fsm self.comb += fsm.reset.eq(~self._enable.storage) fsm.act("IDLE", - self.sink.ready.eq(1), NextValue(offset, 0), NextState("RUN"), ) From 3c4c12a72f7f36c6b662498bbfaa3cd483a341d8 Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Sat, 10 Sep 2022 10:15:23 +0200 Subject: [PATCH 02/24] cores/dma: End transfer when the last flag is set. --- litex/soc/cores/dma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/dma.py b/litex/soc/cores/dma.py index 99b9b7dcc..e45bf4400 100644 --- a/litex/soc/cores/dma.py +++ b/litex/soc/cores/dma.py @@ -187,7 +187,7 @@ class WishboneDMAWriter(Module, AutoCSR): ) fsm.act("RUN", self._sink.valid.eq(self.sink.valid), - self._sink.last.eq(offset == (length - 1)), + self._sink.last.eq(self.sink.last | (offset + 1 == length)), self._sink.address.eq(base + offset), self._sink.data.eq(self.sink.data), self.sink.ready.eq(self._sink.ready), From 0a380b9c3ba278830dc840314b9930c7eef589a2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 12 Sep 2022 19:19:35 +0200 Subject: [PATCH 03/24] cpu/NaxRiscv improve peripheral read/write speed by staying 32 bits --- litex/soc/cores/cpu/naxriscv/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index d857c63bb..3f44f998a 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -123,8 +123,8 @@ class NaxRiscv(CPU): self.human_name = self.human_name self.reset = Signal() self.interrupt = Signal(32) - self.ibus = ibus = axi.AXILiteInterface(address_width=32, data_width=64) - self.dbus = dbus = axi.AXILiteInterface(address_width=32, data_width=64) + self.ibus = ibus = axi.AXILiteInterface(address_width=32, data_width=32) + self.dbus = dbus = axi.AXILiteInterface(address_width=32, data_width=32) self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -228,8 +228,8 @@ class NaxRiscv(CPU): ndir = os.path.join(vdir, "ext", "NaxRiscv") sdir = os.path.join(vdir, "ext", "SpinalHDL") - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "cb2a598a") - NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev" , "a130f7b7") + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "15d2d10b") + NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev" , "5a0592d1") gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From 3cd4a3830c852cd34c2181e3b9ff1c6dbd69f258 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 14 Sep 2022 10:02:07 +0200 Subject: [PATCH 04/24] cores/dma/WishboneDMAWriter: Add ready_on_idle parameter and set it to 1 by default. This allows controlling ready behavior on idle state. --- litex/soc/cores/dma.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/soc/cores/dma.py b/litex/soc/cores/dma.py index e45bf4400..a6df58700 100644 --- a/litex/soc/cores/dma.py +++ b/litex/soc/cores/dma.py @@ -155,7 +155,7 @@ class WishboneDMAWriter(Module, AutoCSR): if with_csr: self.add_csr() - def add_csr(self, default_base=0, default_length=0, default_enable=0, default_loop=0): + def add_csr(self, default_base=0, default_length=0, default_enable=0, default_loop=0, ready_on_idle=1): self._sink = self.sink self.sink = stream.Endpoint([("data", self.bus.data_width)]) @@ -182,6 +182,7 @@ class WishboneDMAWriter(Module, AutoCSR): self.submodules += fsm self.comb += fsm.reset.eq(~self._enable.storage) fsm.act("IDLE", + self.sink.ready.eq(ready_on_idle), NextValue(offset, 0), NextState("RUN"), ) From bc385c73585fce3df03addc0e85bc9e0561e9d2d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 15 Sep 2022 15:25:59 +0200 Subject: [PATCH 05/24] interconnect/axi/axi_stream: Simplify by always adding id/dest/user to endpoints and add layout/name parameters for more flexibility. --- litex/soc/interconnect/axi/axi_stream.py | 61 ++++++++++-------------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_stream.py b/litex/soc/interconnect/axi/axi_stream.py index 5a7ad1f1d..195045a5d 100644 --- a/litex/soc/interconnect/axi/axi_stream.py +++ b/litex/soc/interconnect/axi/axi_stream.py @@ -17,7 +17,7 @@ from litex.soc.interconnect.axi.axi_common import * # AXI-Stream Definition ---------------------------------------------------------------------------- class AXIStreamInterface(stream.Endpoint): - def __init__(self, data_width=32, keep_width=0, id_width=0, dest_width=0, user_width=0): + def __init__(self, data_width=0, keep_width=0, id_width=0, dest_width=0, user_width=0, layout=None, name=None): self.data_width = data_width self.keep_width = keep_width self.id_width = id_width @@ -25,21 +25,20 @@ class AXIStreamInterface(stream.Endpoint): self.user_width = user_width # Define Payload Layout. - payload_layout = [("data", data_width)] - if self.keep_width: - payload_layout += [("keep", keep_width)] + if layout is not None: + payload_layout = layout + else: + payload_layout = [("data", max(1, data_width))] + payload_layout += [("keep", max(1, keep_width))] # Define Param Layout. - param_layout = [] - if self.id_width: - param_layout += [("id", id_width)] - if self.dest_width: - param_layout += [("dest", dest_width)] - if self.user_width: - param_layout += [("user", user_width)] + param_layout = [] + param_layout += [("id", max(1, id_width))] + param_layout += [("dest", max(1, dest_width))] + param_layout += [("user", max(1, user_width))] # Create Endpoint. - stream.Endpoint.__init__(self, stream.EndpointDescription(payload_layout, param_layout)) + stream.Endpoint.__init__(self, stream.EndpointDescription(payload_layout, param_layout), name=name) def get_ios(self, bus_name="axi"): # Control Signals. @@ -50,17 +49,13 @@ class AXIStreamInterface(stream.Endpoint): ] # Payload Signals. - subsignals += [Subsignal("tdata", Pins(self.data_width))] - if self.keep_width: - subsignals += [Subsignal("tkeep", Pins(self.keep_width))] + subsignals += [Subsignal("tdata", Pins(self.data_width))] + subsignals += [Subsignal("tkeep", Pins(self.keep_width))] # Param Signals. - if self.id_width: - subsignals += [Subsignal("tid", Pins(self.id_width))] - if self.dest_width: - subsignals += [Subsignal("tdest", Pins(self.dest_width))] - if self.user_width: - subsignals += [Subsignal("tuser", Pins(self.user_width))] + subsignals += [Subsignal("tid", Pins(self.id_width))] + subsignals += [Subsignal("tdest", Pins(self.dest_width))] + subsignals += [Subsignal("tuser", Pins(self.user_width))] ios = [(bus_name , 0) + tuple(subsignals)] return ios @@ -74,15 +69,11 @@ class AXIStreamInterface(stream.Endpoint): r.append(pads.tlast.eq(self.last)) # Payload Signals. r.append(pads.tdata.eq(self.data)) - if self.keep_width: - r.append(pads.tkeep.eq(self.keep)) + r.append(pads.tkeep.eq(self.keep)) # Param Signals. - if self.id_width: - r.append(pads.tid.eq(self.id)) - if self.dest_width: - r.append(pads.tdest.eq(self.dest)) - if self.user_width: - r.append(pads.tuser.eq(self.user)) + r.append(pads.tid.eq(self.id)) + r.append(pads.tdest.eq(self.dest)) + r.append(pads.tuser.eq(self.user)) if mode == "slave": # Control Signals. r.append(self.valid.eq(pads.tvalid)) @@ -90,13 +81,9 @@ class AXIStreamInterface(stream.Endpoint): r.append(self.last.eq(pads.tlast)) # Payload Signals. r.append(self.data.eq(pads.tdata)) - if self.keep_width: - r.append(self.keep.eq(pads.tkeep)) + r.append(self.keep.eq(pads.tkeep)) # Param Signals. - if self.id_width: - r.append(self.id.eq(pads.tid)) - if self.dest_width: - r.append(self.dest.eq(pads.tdest)) - if self.user_width: - r.append(self.user.eq(pads.tuser)) + r.append(self.id.eq(pads.tid)) + r.append(self.dest.eq(pads.tdest)) + r.append(self.user.eq(pads.tuser)) return r From d36f98bf45c20e2f1895abd4aadf528bf129db11 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 15 Sep 2022 15:52:03 +0200 Subject: [PATCH 06/24] axi/axi_full: Simplify by switching AXI channels to AXIStreamInterface. --- litex/soc/interconnect/axi/axi_full.py | 76 ++++++++++--------- .../interconnect/axi/axi_full_to_axi_lite.py | 7 +- test/test_axi.py | 6 +- 3 files changed, 49 insertions(+), 40 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index eed496363..34946f468 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -15,12 +15,13 @@ from litex.soc.interconnect import stream from litex.build.generic_platform import * from litex.soc.interconnect.axi.axi_common import * +from litex.soc.interconnect.axi.axi_stream import AXIStreamInterface # AXI Definition ----------------------------------------------------------------------------------- -def ax_description(address_width, id_width=0, user_width=0): +def ax_description(address_width): # * present for interconnect with others cores but not used by LiteX. - ax = [ + return [ ("addr", address_width), # Address Width. ("burst", 2), # Burst type. ("len", 8), # Number of data (-1) transfers (up to 256). @@ -31,41 +32,21 @@ def ax_description(address_width, id_width=0, user_width=0): ("qos", 4), # * ("region", 4), # * ] - if id_width: - ax += [("id", id_width)] # ID Width. - if user_width: - ax += [("user", user_width)] # * - return ax -def w_description(data_width, id_width=0, user_width=0): - w = [ +def w_description(data_width): + return [ ("data", data_width), ("strb", data_width//8), ] - if id_width: - w += [("id", id_width)] - if user_width: - w += [("user", user_width)] - return w -def b_description(id_width=0, user_width=0): - b = [("resp", 2)] - if id_width: - b += [("id", id_width)] - if user_width: - b += [("user", user_width)] - return b +def b_description(): + return [("resp", 2)] -def r_description(data_width, id_width=0, user_width=0): - r = [ +def r_description(data_width): + return [ ("resp", 2), ("data", data_width), ] - if id_width: - r += [("id", id_width)] - if user_width: - r += [("user", user_width)] - return r class AXIInterface: def __init__(self, data_width=32, address_width=32, id_width=1, clock_domain="sys", name=None, bursting=False, @@ -73,18 +54,45 @@ class AXIInterface: w_user_width = 0, b_user_width = 0, ar_user_width = 0, - r_user_width = 0): + r_user_width = 0 + ): + # Parameters. self.data_width = data_width self.address_width = address_width self.id_width = id_width self.clock_domain = clock_domain self.bursting = bursting # FIXME: Use or add check. - self.aw = stream.Endpoint(ax_description(address_width, id_width, aw_user_width), name=name) - self.w = stream.Endpoint(w_description(data_width, id_width, w_user_width), name=name) - self.b = stream.Endpoint(b_description(id_width, b_user_width), name=name) - self.ar = stream.Endpoint(ax_description(address_width, id_width, ar_user_width), name=name) - self.r = stream.Endpoint(r_description(data_width, id_width, r_user_width), name=name) + # Write Channels. + # --------------- + self.aw = AXIStreamInterface(name=name, + layout = ax_description(address_width), + id_width = id_width, + user_width = aw_user_width + ) + self.w = AXIStreamInterface(name=name, + layout = w_description(data_width), + id_width = id_width, + user_width = w_user_width + ) + self.b = AXIStreamInterface(name=name, + layout = b_description(), + id_width = id_width, + user_width = b_user_width + ) + + # Read Channels. + # -------------- + self.ar = AXIStreamInterface(name=name, + layout = ax_description(address_width), + id_width = id_width, + user_width = ar_user_width + ) + self.r = AXIStreamInterface(name=name, + layout = r_description(data_width), + id_width = id_width, + user_width = r_user_width + ) def connect_to_pads(self, pads, mode="master"): return connect_to_pads(self, pads, mode, axi_full=True) diff --git a/litex/soc/interconnect/axi/axi_full_to_axi_lite.py b/litex/soc/interconnect/axi/axi_full_to_axi_lite.py index 8468b8b88..6bb03d5ba 100644 --- a/litex/soc/interconnect/axi/axi_full_to_axi_lite.py +++ b/litex/soc/interconnect/axi/axi_full_to_axi_lite.py @@ -25,9 +25,10 @@ class AXI2AXILite(Module): assert axi.data_width == axi_lite.data_width assert axi.address_width == axi_lite.address_width - ax_buffer = stream.Buffer(ax_description(axi.address_width, axi.id_width)) - ax_burst = stream.Endpoint(ax_description(axi.address_width, axi.id_width)) - ax_beat = stream.Endpoint(ax_description(axi.address_width, axi.id_width)) + ax_burst = AXIStreamInterface(layout=ax_description(axi.address_width), id_width=axi.id_width) + ax_beat = AXIStreamInterface(layout=ax_description(axi.address_width), id_width=axi.id_width) + ax_buffer = stream.Buffer(ax_burst.description) + self.comb += ax_burst.connect(ax_buffer.sink) ax_burst2beat = AXIBurst2Beat(ax_buffer.source, ax_beat) self.submodules += ax_buffer, ax_burst2beat diff --git a/test/test_axi.py b/test/test_axi.py index ff2da770e..ee53199dd 100644 --- a/test/test_axi.py +++ b/test/test_axi.py @@ -96,9 +96,9 @@ class TestAXI(unittest.TestCase): yield # DUT - ax_burst = stream.Endpoint(ax_description(32, 32)) - ax_beat = stream.Endpoint(ax_description(32, 32)) - dut = AXIBurst2Beat(ax_burst, ax_beat) + ax_burst = AXIStreamInterface(layout=ax_description(32), id_width=32) + ax_beat = AXIStreamInterface(layout=ax_description(32), id_width=32) + dut = AXIBurst2Beat(ax_burst, ax_beat) # Generate DUT input (bursts). prng = random.Random(42) From fa902281aa77744b18f2cfb5ca78b9259789ea0a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 16 Sep 2022 14:05:20 +0200 Subject: [PATCH 07/24] integration/common/get_mem_data: Allow filemane_or_regions to be None and add endianness assertion. --- litex/soc/integration/common.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/litex/soc/integration/common.py b/litex/soc/integration/common.py index 1cdb9b0fa..00e572b43 100644 --- a/litex/soc/integration/common.py +++ b/litex/soc/integration/common.py @@ -41,6 +41,12 @@ def get_mem_regions(filename_or_regions, offset): def get_mem_data(filename_or_regions, data_width=32, endianness="big", mem_size=None, offset=0): assert data_width in [32, 64] + assert endianness in ["big", "little"] + + # Return empty list if no filename or regions. + if filename_or_regions is None: + return [] + # Create memory regions. regions = get_mem_regions(filename_or_regions, offset) From 1e1e75dba7b9db86ce10a0ea198ad5bc83a45547 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 16 Sep 2022 14:05:45 +0200 Subject: [PATCH 08/24] software/bios/boot: Fix missing CONFIG_BIOS_NO_DELAYS update. --- litex/soc/software/bios/boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index e79ce6e6b..d30df1385 100755 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -111,7 +111,7 @@ void romboot(void) static void timer0_load(unsigned int value) { timer0_en_write(0); timer0_reload_write(0); -#ifndef CONFIG_DISABLE_DELAYS +#ifndef CONFIG_BIOS_NO_DELAYS timer0_load_write(value); #else timer0_load_write(0); From c24bbedb68ee72d81159ff064c3a64ffe596429a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 16 Sep 2022 14:06:22 +0200 Subject: [PATCH 09/24] interconnect/axi/axi_full: Fix AXIUpConverter compilation. --- litex/soc/interconnect/axi/axi_full.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index 34946f468..bbca6c426 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -193,9 +193,11 @@ class AXIUpConverter(Module): description_to = [("data", dw_to), ("strb", dw_to//8)], ) self.submodules += w_converter - self.comb += axi_from.w.connect(w_converter.sink, omit={"id"}) + self.comb += axi_from.w.connect(w_converter.sink, omit={"id", "dest", "user"}) self.comb += w_converter.source.connect(axi_to.w) self.comb += axi_to.w.id.eq(axi_from.w.id) + self.comb += axi_to.w.dest.eq(axi_from.w.dest) + self.comb += axi_to.w.user.eq(axi_from.w.user) # B Channel. self.comb += axi_to.b.connect(axi_from.b) @@ -215,11 +217,12 @@ class AXIUpConverter(Module): description_to = [("data", dw_from)], ) self.submodules += r_converter - self.comb += axi_to.r.connect(r_converter.sink, omit={"id", "resp"}) + self.comb += axi_to.r.connect(r_converter.sink, omit={"id", "dest", "user", "resp"}) self.comb += r_converter.source.connect(axi_from.r) self.comb += axi_from.r.resp.eq(axi_to.r.resp) self.comb += axi_from.r.id.eq(axi_to.r.id) - + self.comb += axi_from.r.user.eq(axi_to.r.user) + self.comb += axi_from.r.dest.eq(axi_to.r.dest) class AXIDownConverter(Module): def __init__(self, axi_from, axi_to): From d7837f8751112bd99063987d453c293350ba82aa Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Sat, 17 Sep 2022 19:05:45 -0500 Subject: [PATCH 10/24] demo: fix minor build issues --- litex/soc/software/demo/demo.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litex/soc/software/demo/demo.py b/litex/soc/software/demo/demo.py index 3ab3fa90f..fbae89ccf 100755 --- a/litex/soc/software/demo/demo.py +++ b/litex/soc/software/demo/demo.py @@ -7,6 +7,7 @@ # SPDX-License-Identifier: BSD-2-Clause import os +import sys import argparse from litex.build.tools import replace_in_file @@ -23,6 +24,7 @@ def main(): # Copy contents to demo directory os.system(f"cp {os.path.abspath(os.path.dirname(__file__))}/* demo") + os.system("chmod -R u+w demo") # Update memory region. replace_in_file("demo/linker.ld", "main_ram", args.mem) @@ -35,7 +37,7 @@ def main(): os.system("cp demo/demo.bin ./") # Prepare flash boot image. - os.system("python3 -m litex.soc.software.crcfbigen demo.bin -o demo.fbi --fbi --little") # FIXME: Endianness. + os.system(f"{sys.executable or 'python3'} -m litex.soc.software.crcfbigen demo.bin -o demo.fbi --fbi --little") # FIXME: Endianness. if __name__ == "__main__": main() From 441042bef4345fccb8241f41e2bc6099287b64a7 Mon Sep 17 00:00:00 2001 From: Gabriel Somlo Date: Sun, 18 Sep 2022 08:25:32 -0400 Subject: [PATCH 11/24] yosys_nextpnr_toolchain: add flow3 option to abc9 mode Add "flow3" option to abc9 mode. This runs FPGA mapping several times, producing a generally better mapping at the cost of increased runtime (see https://github.com/Ravenslofty/yosys-cookbook/blob/master/ecp5.md). Also, add a "--yosys-flow3" build option to both "trellis" and "oxide". Signed-off-by: Gabriel Somlo --- litex/build/lattice/oxide.py | 2 ++ litex/build/lattice/trellis.py | 2 ++ litex/build/yosys_nextpnr_toolchain.py | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/litex/build/lattice/oxide.py b/litex/build/lattice/oxide.py index 5499b0227..1de078b80 100644 --- a/litex/build/lattice/oxide.py +++ b/litex/build/lattice/oxide.py @@ -65,6 +65,7 @@ def oxide_args(parser): toolchain_group = parser.add_argument_group(title="Toolchain options") toolchain_group.add_argument("--yosys-nowidelut", action="store_true", help="Use Yosys's nowidelut mode.") toolchain_group.add_argument("--yosys-abc9", action="store_true", help="Use Yosys's abc9 mode.") + toolchain_group.add_argument("--yosys-flow3", action="store_true", help="Use Yosys's abc9 mode with the flow3 script.") toolchain_group.add_argument("--nextpnr-timingstrict", action="store_true", help="Use strict Timing mode (Build will fail when Timings are not met).") toolchain_group.add_argument("--nextpnr-ignoreloops", action="store_true", help="Ignore combinatorial loops in Timing Analysis.") toolchain_group.add_argument("--nextpnr-seed", default=1, type=int, help="Set Nextpnr's seed.") @@ -74,6 +75,7 @@ def oxide_argdict(args): return { "nowidelut": args.yosys_nowidelut, "abc9": args.yosys_abc9, + "flow3": args.yosys_flow3, "timingstrict": args.nextpnr_timingstrict, "ignoreloops": args.nextpnr_ignoreloops, "seed": args.nextpnr_seed, diff --git a/litex/build/lattice/trellis.py b/litex/build/lattice/trellis.py index cb22f6755..6ef01096b 100644 --- a/litex/build/lattice/trellis.py +++ b/litex/build/lattice/trellis.py @@ -153,6 +153,7 @@ def trellis_args(parser): toolchain_group = parser.add_argument_group(title="Toolchain options") toolchain_group.add_argument("--yosys-nowidelut", action="store_true", help="Use Yosys's nowidelut mode.") toolchain_group.add_argument("--yosys-abc9", action="store_true", help="Use Yosys's abc9 mode.") + toolchain_group.add_argument("--yosys-flow3", action="store_true", help="Use Yosys's abc9 mode with the flow3 script.") toolchain_group.add_argument("--nextpnr-timingstrict", action="store_true", help="Use strict Timing mode (Build will fail when Timings are not met).") toolchain_group.add_argument("--nextpnr-ignoreloops", action="store_true", help="Ignore combinatorial loops in Timing Analysis.") toolchain_group.add_argument("--nextpnr-seed", default=1, type=int, help="Set Nextpnr's seed.") @@ -165,6 +166,7 @@ def trellis_argdict(args): return { "nowidelut": args.yosys_nowidelut, "abc9": args.yosys_abc9, + "flow3": args.yosys_flow3, "timingstrict": args.nextpnr_timingstrict, "ignoreloops": args.nextpnr_ignoreloops, "bootaddr": args.ecppack_bootaddr, diff --git a/litex/build/yosys_nextpnr_toolchain.py b/litex/build/yosys_nextpnr_toolchain.py index 3cb8b2e4d..b7e19ee9b 100644 --- a/litex/build/yosys_nextpnr_toolchain.py +++ b/litex/build/yosys_nextpnr_toolchain.py @@ -86,6 +86,7 @@ class YosysNextPNRToolchain(GenericToolchain): def build(self, platform, fragment, nowidelut = False, abc9 = False, + flow3 = False, timingstrict = False, ignoreloops = False, seed = 1, @@ -100,6 +101,8 @@ class YosysNextPNRToolchain(GenericToolchain): than native for the target (Yosys) abc9 : str use new ABC9 flow (Yosys) + flow3 : str + use ABC9 with flow3 (Yosys) timingstrict : list check timing failures (nextpnr) ignoreloops : str @@ -110,6 +113,9 @@ class YosysNextPNRToolchain(GenericToolchain): self._nowidelut = nowidelut self._abc9 = abc9 + if flow3: + self._abc9 = True + self._yosys_cmds.append("scratchpad -copy abc9.script.flow3 abc9.script") self.timingstrict = timingstrict self.ignoreloops = ignoreloops self.seed = seed From 32272ba855d719dedf13f62d3d3a1a0f096cefca Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 19 Sep 2022 13:26:36 +0200 Subject: [PATCH 12/24] axi/axi_stream: Set default keep_width to None and automatically set it to data_width//8 when not specified. --- litex/soc/interconnect/axi/axi_stream.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_stream.py b/litex/soc/interconnect/axi/axi_stream.py index 195045a5d..48a69a8ca 100644 --- a/litex/soc/interconnect/axi/axi_stream.py +++ b/litex/soc/interconnect/axi/axi_stream.py @@ -17,9 +17,9 @@ from litex.soc.interconnect.axi.axi_common import * # AXI-Stream Definition ---------------------------------------------------------------------------- class AXIStreamInterface(stream.Endpoint): - def __init__(self, data_width=0, keep_width=0, id_width=0, dest_width=0, user_width=0, layout=None, name=None): + def __init__(self, data_width=0, keep_width=None, id_width=0, dest_width=0, user_width=0, layout=None, name=None): self.data_width = data_width - self.keep_width = keep_width + self.keep_width = data_width//8 if keep_width is None else keep_width self.id_width = id_width self.dest_width = dest_width self.user_width = user_width @@ -28,14 +28,14 @@ class AXIStreamInterface(stream.Endpoint): if layout is not None: payload_layout = layout else: - payload_layout = [("data", max(1, data_width))] - payload_layout += [("keep", max(1, keep_width))] + payload_layout = [("data", max(1, self.data_width))] + payload_layout += [("keep", max(1, self.keep_width))] # Define Param Layout. param_layout = [] - param_layout += [("id", max(1, id_width))] - param_layout += [("dest", max(1, dest_width))] - param_layout += [("user", max(1, user_width))] + param_layout += [("id", max(1, self.id_width))] + param_layout += [("dest", max(1, self.dest_width))] + param_layout += [("user", max(1, self.user_width))] # Create Endpoint. stream.Endpoint.__init__(self, stream.EndpointDescription(payload_layout, param_layout), name=name) From e9f6642d8f62ef4d921b0a75154044f8145647fa Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 19 Sep 2022 19:08:25 +0200 Subject: [PATCH 13/24] build/yosys,nextpnr, lattice: refactor args --- litex/build/lattice/icestorm.py | 10 +++------- litex/build/lattice/oxide.py | 18 ++++-------------- litex/build/lattice/trellis.py | 16 +++------------- litex/build/nextpnr_wrapper.py | 12 ++++++++++++ litex/build/yosys_nextpnr_toolchain.py | 14 ++++++++++++-- litex/build/yosys_wrapper.py | 12 ++++++++++++ 6 files changed, 46 insertions(+), 36 deletions(-) diff --git a/litex/build/lattice/icestorm.py b/litex/build/lattice/icestorm.py index 9aa6f2ae0..c1a676137 100644 --- a/litex/build/lattice/icestorm.py +++ b/litex/build/lattice/icestorm.py @@ -17,7 +17,7 @@ from migen.fhdl.structure import _Fragment from litex.build.generic_platform import * from litex.build import tools from litex.build.lattice import common -from litex.build.yosys_nextpnr_toolchain import YosysNextPNRToolchain +from litex.build.yosys_nextpnr_toolchain import YosysNextPNRToolchain, yosys_nextpnr_args, yosys_nextpnr_argdict # LatticeIceStormToolchain ------------------------------------------------------------------------- @@ -107,13 +107,9 @@ class LatticeIceStormToolchain(YosysNextPNRToolchain): def icestorm_args(parser): toolchain_group = parser.add_argument_group(title="Toolchain options") - toolchain_group.add_argument("--nextpnr-timingstrict", action="store_true", help="Make the build fail when Timing is not met.") - toolchain_group.add_argument("--nextpnr-ignoreloops", action="store_true", help="Use strict Timing mode (Build will fail when Timings are not met).") - toolchain_group.add_argument("--nextpnr-seed", default=1, type=int, help="Set Nextpnr's seed.") + yosys_nextpnr_args(toolchain_group) def icestorm_argdict(args): return { - "timingstrict": args.nextpnr_timingstrict, - "ignoreloops": args.nextpnr_ignoreloops, - "seed": args.nextpnr_seed, + **yosys_nextpnr_argdict(args), } diff --git a/litex/build/lattice/oxide.py b/litex/build/lattice/oxide.py index 1de078b80..7bc2f094f 100644 --- a/litex/build/lattice/oxide.py +++ b/litex/build/lattice/oxide.py @@ -17,7 +17,7 @@ from litex.build.generic_platform import * from litex.build import tools from litex.build.lattice import common from litex.build.lattice.radiant import _format_constraint, _format_ldc, _build_pdc -from litex.build.yosys_nextpnr_toolchain import YosysNextPNRToolchain +from litex.build.yosys_nextpnr_toolchain import YosysNextPNRToolchain, yosys_nextpnr_args, yosys_nextpnr_argdict import math @@ -63,21 +63,11 @@ class LatticeOxideToolchain(YosysNextPNRToolchain): def oxide_args(parser): toolchain_group = parser.add_argument_group(title="Toolchain options") - toolchain_group.add_argument("--yosys-nowidelut", action="store_true", help="Use Yosys's nowidelut mode.") - toolchain_group.add_argument("--yosys-abc9", action="store_true", help="Use Yosys's abc9 mode.") - toolchain_group.add_argument("--yosys-flow3", action="store_true", help="Use Yosys's abc9 mode with the flow3 script.") - toolchain_group.add_argument("--nextpnr-timingstrict", action="store_true", help="Use strict Timing mode (Build will fail when Timings are not met).") - toolchain_group.add_argument("--nextpnr-ignoreloops", action="store_true", help="Ignore combinatorial loops in Timing Analysis.") - toolchain_group.add_argument("--nextpnr-seed", default=1, type=int, help="Set Nextpnr's seed.") - toolchain_group.add_argument("--nexus-es-device", action="store_true", help="Use Nexus-ES1 part.") + yosys_nextpnr_args(toolchain_group) + toolchain_group.add_argument("--nexus-es-device", action="store_true", help="Use Nexus-ES1 part.") def oxide_argdict(args): return { - "nowidelut": args.yosys_nowidelut, - "abc9": args.yosys_abc9, - "flow3": args.yosys_flow3, - "timingstrict": args.nextpnr_timingstrict, - "ignoreloops": args.nextpnr_ignoreloops, - "seed": args.nextpnr_seed, + **yosys_nextpnr_argdict(args), "es_device": args.nexus_es_device, } diff --git a/litex/build/lattice/trellis.py b/litex/build/lattice/trellis.py index 6ef01096b..0a833613d 100644 --- a/litex/build/lattice/trellis.py +++ b/litex/build/lattice/trellis.py @@ -17,7 +17,7 @@ from migen.fhdl.structure import _Fragment from litex.build.generic_platform import * from litex.build import tools from litex.build.lattice import common -from litex.build.yosys_nextpnr_toolchain import YosysNextPNRToolchain +from litex.build.yosys_nextpnr_toolchain import YosysNextPNRToolchain, yosys_nextpnr_args, yosys_nextpnr_argdict # LatticeTrellisToolchain -------------------------------------------------------------------------- @@ -151,12 +151,7 @@ class LatticeTrellisToolchain(YosysNextPNRToolchain): def trellis_args(parser): toolchain_group = parser.add_argument_group(title="Toolchain options") - toolchain_group.add_argument("--yosys-nowidelut", action="store_true", help="Use Yosys's nowidelut mode.") - toolchain_group.add_argument("--yosys-abc9", action="store_true", help="Use Yosys's abc9 mode.") - toolchain_group.add_argument("--yosys-flow3", action="store_true", help="Use Yosys's abc9 mode with the flow3 script.") - toolchain_group.add_argument("--nextpnr-timingstrict", action="store_true", help="Use strict Timing mode (Build will fail when Timings are not met).") - toolchain_group.add_argument("--nextpnr-ignoreloops", action="store_true", help="Ignore combinatorial loops in Timing Analysis.") - toolchain_group.add_argument("--nextpnr-seed", default=1, type=int, help="Set Nextpnr's seed.") + yosys_nextpnr_args(toolchain_group) toolchain_group.add_argument("--ecppack-bootaddr", default=0, help="Set boot address for next image.") toolchain_group.add_argument("--ecppack-spimode", default=None, help="Set slave SPI programming mode.") toolchain_group.add_argument("--ecppack-freq", default=None, help="Set SPI MCLK frequency.") @@ -164,14 +159,9 @@ def trellis_args(parser): def trellis_argdict(args): return { - "nowidelut": args.yosys_nowidelut, - "abc9": args.yosys_abc9, - "flow3": args.yosys_flow3, - "timingstrict": args.nextpnr_timingstrict, - "ignoreloops": args.nextpnr_ignoreloops, + **yosys_nextpnr_argdict(args), "bootaddr": args.ecppack_bootaddr, "spimode": args.ecppack_spimode, "freq": float(args.ecppack_freq) if args.ecppack_freq is not None else None, "compress": args.ecppack_compress, - "seed": args.nextpnr_seed, } diff --git a/litex/build/nextpnr_wrapper.py b/litex/build/nextpnr_wrapper.py index dc2949f38..91cdb3a6a 100755 --- a/litex/build/nextpnr_wrapper.py +++ b/litex/build/nextpnr_wrapper.py @@ -92,3 +92,15 @@ class NextPNRWrapper(): return base_cmd else: raise ValueError("Invalid target type") + +def nextpnr_args(parser): + parser.add_argument("--nextpnr-timingstrict", action="store_true", help="Use strict Timing mode (Build will fail when Timings are not met).") + parser.add_argument("--nextpnr-ignoreloops", action="store_true", help="Ignore combinatorial loops in Timing Analysis.") + parser.add_argument("--nextpnr-seed", default=1, type=int, help="Set Nextpnr's seed.") + +def nextpnr_argdict(args): + return { + "timingstrict": args.nextpnr_timingstrict, + "ignoreloops": args.nextpnr_ignoreloops, + "seed": args.nextpnr_seed, + } diff --git a/litex/build/yosys_nextpnr_toolchain.py b/litex/build/yosys_nextpnr_toolchain.py index b7e19ee9b..04fc3a65b 100644 --- a/litex/build/yosys_nextpnr_toolchain.py +++ b/litex/build/yosys_nextpnr_toolchain.py @@ -12,8 +12,8 @@ from shutil import which from litex.build import tools from litex.build.generic_toolchain import GenericToolchain -from litex.build.nextpnr_wrapper import NextPNRWrapper -from litex.build.yosys_wrapper import YosysWrapper +from litex.build.nextpnr_wrapper import NextPNRWrapper, nextpnr_args, nextpnr_argdict +from litex.build.yosys_wrapper import YosysWrapper, yosys_args, yosys_argdict # YosysNextPNRToolchain ---------------------------------------------------------------------------- @@ -216,3 +216,13 @@ class YosysNextPNRToolchain(GenericToolchain): def build_io_constraints(self): raise NotImplementedError("GenericToolchain.build_io_constraints must be overloaded.") + +def yosys_nextpnr_args(parser): + yosys_args(parser) + nextpnr_args(parser) + +def yosys_nextpnr_argdict(args): + return { + **yosys_argdict(args), + **nextpnr_argdict(args), + } diff --git a/litex/build/yosys_wrapper.py b/litex/build/yosys_wrapper.py index 0cfdbd9f8..bd85147bd 100755 --- a/litex/build/yosys_wrapper.py +++ b/litex/build/yosys_wrapper.py @@ -137,3 +137,15 @@ class YosysWrapper(): return base_cmd else: raise ValueError("Invalid script type") + +def yosys_args(parser): + parser.add_argument("--yosys-nowidelut", action="store_true", help="Use Yosys's nowidelut mode.") + parser.add_argument("--yosys-abc9", action="store_true", help="Use Yosys's abc9 mode.") + parser.add_argument("--yosys-flow3", action="store_true", help="Use Yosys's abc9 mode with the flow3 script.") + +def yosys_argdict(args): + return { + "nowidelut": args.yosys_nowidelut, + "abc9": args.yosys_abc9, + "flow3": args.yosys_flow3, + } From e12af4f0506423152cb28df3bf13d1622295ca0a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 20 Sep 2022 09:07:27 +0200 Subject: [PATCH 14/24] interconnect/axi/axi_stream: Fix get_ios and base it on length of created Endpoint's signals. --- litex/soc/interconnect/axi/axi_stream.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_stream.py b/litex/soc/interconnect/axi/axi_stream.py index 48a69a8ca..1f7a24d73 100644 --- a/litex/soc/interconnect/axi/axi_stream.py +++ b/litex/soc/interconnect/axi/axi_stream.py @@ -49,13 +49,13 @@ class AXIStreamInterface(stream.Endpoint): ] # Payload Signals. - subsignals += [Subsignal("tdata", Pins(self.data_width))] - subsignals += [Subsignal("tkeep", Pins(self.keep_width))] + subsignals += [Subsignal("tdata", Pins(len(self.data)))] + subsignals += [Subsignal("tkeep", Pins(len(self.keep)))] # Param Signals. - subsignals += [Subsignal("tid", Pins(self.id_width))] - subsignals += [Subsignal("tdest", Pins(self.dest_width))] - subsignals += [Subsignal("tuser", Pins(self.user_width))] + subsignals += [Subsignal("tid", Pins(len(self.id)))] + subsignals += [Subsignal("tdest", Pins(len(self.dest)))] + subsignals += [Subsignal("tuser", Pins(len(self.user)))] ios = [(bus_name , 0) + tuple(subsignals)] return ios From 162a0a4c1e2c4786e01fe843a5984335e1ddaaae Mon Sep 17 00:00:00 2001 From: Gabriel Somlo Date: Tue, 20 Sep 2022 09:29:46 -0400 Subject: [PATCH 15/24] cpu/rocket: fix variant typos The `fulld` and `fullq` variants point to the wrong (`LitexFullConfig`) verilog. Fix by pointing to the correct code (`LitexFullDConfig` and `LitexFullQConfig`, respectively). Reported-by: Ioannis Ioannou Signed-off-by: Gabriel Somlo --- litex/soc/cores/cpu/rocket/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/cpu/rocket/core.py b/litex/soc/cores/cpu/rocket/core.py index 9301d13df..7ae225960 100644 --- a/litex/soc/cores/cpu/rocket/core.py +++ b/litex/soc/cores/cpu/rocket/core.py @@ -51,9 +51,9 @@ CPU_VARIANTS = { "linuxq": "freechips.rocketchip.system.LitexLinuxQConfig", "linux2q": "freechips.rocketchip.system.LitexLinux2QConfig", "full": "freechips.rocketchip.system.LitexFullConfig", - "fulld": "freechips.rocketchip.system.LitexFullConfig", + "fulld": "freechips.rocketchip.system.LitexFullDConfig", "full4d": "freechips.rocketchip.system.LitexFull4DConfig", - "fullq": "freechips.rocketchip.system.LitexFullConfig", + "fullq": "freechips.rocketchip.system.LitexFullQConfig", "full4q": "freechips.rocketchip.system.LitexFull4QConfig", } From b8e22fcd799cac29c8c78bac7e2ec7fe97a3a35c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 22 Sep 2022 09:54:00 +0200 Subject: [PATCH 16/24] interconnect/axi: Simplify/Fix IOs generation. (Param signals were missing for AXIFull). --- litex/soc/interconnect/axi/axi_full.py | 7 ++++++- litex/soc/interconnect/axi/axi_stream.py | 12 ++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index bbca6c426..a79343889 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -100,9 +100,14 @@ class AXIInterface: def get_ios(self, bus_name="wb"): subsignals = [] for channel in ["aw", "w", "b", "ar", "r"]: + # Control Signals. for name in ["valid", "ready"] + (["last"] if channel in ["w", "r"] else []): subsignals.append(Subsignal(channel + name, Pins(1))) - for name, width in getattr(self, channel).description.payload_layout: + + # Payload/Params Signals. + channel_layout = (getattr(self, channel).description.payload_layout + + getattr(self, channel).description.param_layout) + for name, width in channel_layout: subsignals.append(Subsignal(channel + name, Pins(width))) ios = [(bus_name , 0) + tuple(subsignals)] return ios diff --git a/litex/soc/interconnect/axi/axi_stream.py b/litex/soc/interconnect/axi/axi_stream.py index 1f7a24d73..f928747d1 100644 --- a/litex/soc/interconnect/axi/axi_stream.py +++ b/litex/soc/interconnect/axi/axi_stream.py @@ -48,14 +48,10 @@ class AXIStreamInterface(stream.Endpoint): Subsignal("tready", Pins(1)), ] - # Payload Signals. - subsignals += [Subsignal("tdata", Pins(len(self.data)))] - subsignals += [Subsignal("tkeep", Pins(len(self.keep)))] - - # Param Signals. - subsignals += [Subsignal("tid", Pins(len(self.id)))] - subsignals += [Subsignal("tdest", Pins(len(self.dest)))] - subsignals += [Subsignal("tuser", Pins(len(self.user)))] + # Payload/Params Signals. + channel_layout = (self.description.payload_layout + self.description.param_layout) + for name, width in channel_layout: + subsignals.append(Subsignal(f"t{name}", Pins(width))) ios = [(bus_name , 0) + tuple(subsignals)] return ios From 7795fba3cf4fe34a786caa92cb9ced0500a31dd7 Mon Sep 17 00:00:00 2001 From: Christian Klarhorst Date: Sun, 25 Sep 2022 20:41:54 +0200 Subject: [PATCH 17/24] cpu/naxriscv: Add --update-repo option & check for update errors Allows different update strategies which I find useful. The git update process now checks the return code! So that problems in the update process can be noticed. --- litex/soc/cores/cpu/naxriscv/core.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 3f44f998a..18eb75289 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -98,12 +98,14 @@ class NaxRiscv(CPU): cpu_group.add_argument("--xlen", default=32, help="Specify the RISC-V data width.") cpu_group.add_argument("--with-jtag-tap", action="store_true", help="Add a embedded JTAG tap for debugging") cpu_group.add_argument("--with-jtag-instruction", action="store_true", help="Add a JTAG instruction port which implement tunneling for debugging (TAP not included)") + cpu_group.add_argument("--update-repo", default="recommended", choices=["latest","wipe+latest","recommended","wipe+recommended","no"], help="Specify how the NaxRiscv & SpinalHDL repo should be updated (latest: update to HEAD, recommended: Update to known compatible version, no: Don't update, wipe+*: Do clean&reset before checkout)") @staticmethod def args_read(args): print(args) NaxRiscv.jtag_tap = args.with_jtag_tap NaxRiscv.jtag_instruction = args.with_jtag_instruction + NaxRiscv.update_repo = args.update_repo if args.scala_file: NaxRiscv.scala_files = args.scala_file if args.scala_args: @@ -218,8 +220,11 @@ class NaxRiscv(CPU): options = dir ), shell=True) # Use specific SHA1 (Optional). + print(f"Updating {name} Git repository...") os.chdir(os.path.join(dir)) - os.system(f"cd {dir} && git checkout {branch} && git pull && git checkout {hash}") + wipe_cmd = "&& git clean --force -d -x && git reset --hard" if "wipe" in NaxRiscv.update_repo else "" + checkout_cmd = f"&& git checkout {hash}" if hash is not None else "" + subprocess.check_call(f"cd {dir} {wipe_cmd} && git checkout {branch} && git pull {checkout_cmd}", shell=True) # Netlist Generation. @staticmethod @@ -228,8 +233,9 @@ class NaxRiscv(CPU): ndir = os.path.join(vdir, "ext", "NaxRiscv") sdir = os.path.join(vdir, "ext", "SpinalHDL") - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "15d2d10b") - NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev" , "5a0592d1") + if NaxRiscv.update_repo != "no": + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "15d2d10b" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev" , "5a0592d1" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From 9c43fe85c63458e9df8b98fc649dee75e3135e8f Mon Sep 17 00:00:00 2001 From: Christian Klarhorst Date: Sun, 25 Sep 2022 21:00:03 +0200 Subject: [PATCH 18/24] cpu/naxriscv: Add --no-netlist-cache Ignores the netlist cache. When you hack on naxriscv code, you always want fresh results. --- litex/soc/cores/cpu/naxriscv/core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 18eb75289..ee14e5c23 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -99,6 +99,7 @@ class NaxRiscv(CPU): cpu_group.add_argument("--with-jtag-tap", action="store_true", help="Add a embedded JTAG tap for debugging") cpu_group.add_argument("--with-jtag-instruction", action="store_true", help="Add a JTAG instruction port which implement tunneling for debugging (TAP not included)") cpu_group.add_argument("--update-repo", default="recommended", choices=["latest","wipe+latest","recommended","wipe+recommended","no"], help="Specify how the NaxRiscv & SpinalHDL repo should be updated (latest: update to HEAD, recommended: Update to known compatible version, no: Don't update, wipe+*: Do clean&reset before checkout)") + cpu_group.add_argument("--no-netlist-cache", action="store_true", help="Always (re-)build the netlist") @staticmethod def args_read(args): @@ -106,6 +107,7 @@ class NaxRiscv(CPU): NaxRiscv.jtag_tap = args.with_jtag_tap NaxRiscv.jtag_instruction = args.with_jtag_instruction NaxRiscv.update_repo = args.update_repo + NaxRiscv.no_netlist_cache = args.no_netlist_cache if args.scala_file: NaxRiscv.scala_files = args.scala_file if args.scala_args: @@ -265,7 +267,7 @@ class NaxRiscv(CPU): def add_sources(self, platform): vdir = get_data_mod("cpu", "naxriscv").data_location print(f"NaxRiscv netlist : {self.netlist_name}") - if not os.path.exists(os.path.join(vdir, self.netlist_name + ".v")): + if NaxRiscv.no_netlist_cache or not os.path.exists(os.path.join(vdir, self.netlist_name + ".v")): self.generate_netlist(self.reset_address) # Add RAM. From dc0a4ea40bddcbc9f96b08a8eb46c39ec6bfff20 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 27 Sep 2022 08:07:31 +0200 Subject: [PATCH 19/24] soc/cores/video: swap red and blue channel --- litex/soc/cores/video.py | 46 +++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index 522c7c84e..61f5947e0 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -163,6 +163,9 @@ video_data_layout = [ ("b", 8), ] +# DVI Color <-> channel mapping -------------------------------------------------------------------- +_dvi_c2d = {"b": 0, "g": 1, "r": 2} + class VideoTimingGenerator(Module, AutoCSR): def __init__(self, default_video_timings="800x600@60Hz"): # Check / Get Video Timings (can be str or dict) @@ -790,18 +793,17 @@ class VideoHDMIPHY(Module): # Encode/Serialize Datas. for pol in drive_pols: - for color in ["r", "g", "b"]: + for color, channel in _dvi_c2d.items(): # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) setattr(self.submodules, f"{color}_encoder", encoder) self.comb += encoder.d.eq(getattr(sink, color)) - self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if color == "r" else 0) + self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if channel == 0 else 0) self.comb += encoder.de.eq(sink.de) # 10:1 Serialization + Pseudo Differential Signaling. - c2d = {"r": 0, "g": 1, "b": 2} data_i = encoder.out if color not in pn_swap else ~encoder.out - data_o = getattr(pads, f"data{c2d[color]}_{pol}") + data_o = getattr(pads, f"data{channel}_{pol}") serializer = VideoHDMI10to1Serializer( data_i = {"p":data_i, "n": ~data_i}[pol], data_o = data_o, @@ -828,12 +830,12 @@ class VideoGowinHDMIPHY(Module): o_OB = pads.clk_n, ) - for color in ["r", "g", "b"]: + for color, channel in _dvi_c2d.items(): # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) setattr(self.submodules, f"{color}_encoder", encoder) self.comb += encoder.d.eq(getattr(sink, color)) - self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if color == "r" else 0) + self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if channel == 0 else 0) self.comb += encoder.de.eq(sink.de) # 10:1 Serialization + Differential Signaling. @@ -847,11 +849,10 @@ class VideoGowinHDMIPHY(Module): o_Q = pad_o, ) - c2d = {"r": 0, "g": 1, "b": 2} self.specials += Instance("ELVDS_OBUF", i_I = pad_o, - o_O = getattr(pads, f"data{c2d[color]}_p"), - o_OB = getattr(pads, f"data{c2d[color]}_n"), + o_O = getattr(pads, f"data{channel}_p"), + o_OB = getattr(pads, f"data{channel}_n"), ) @@ -872,13 +873,13 @@ class VideoS6HDMIPHY(Module): self.specials += Instance("OBUFDS", i_I=pads_clk, o_O=pads.clk_p, o_OB=pads.clk_n) # Encode/Serialize Datas. - for color in ["r", "g", "b"]: + for color, channel in _dvi_c2d.items(): # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) setattr(self.submodules, f"{color}_encoder", encoder) self.comb += encoder.d.eq(getattr(sink, color)) - self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if color == "r" else 0) + self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if channel == 0 else 0) self.comb += encoder.de.eq(sink.de) # 10:1 Serialization + Differential Signaling. @@ -889,9 +890,8 @@ class VideoS6HDMIPHY(Module): clock_domain = clock_domain, ) setattr(self.submodules, f"{color}_serializer", serializer) - c2d = {"r": 0, "g": 1, "b": 2} - pad_p = getattr(pads, f"data{c2d[color]}_p") - pad_n = getattr(pads, f"data{c2d[color]}_n") + pad_p = getattr(pads, f"data{channel}_p") + pad_n = getattr(pads, f"data{channel}_n") self.specials += Instance("OBUFDS", i_I=pad_o, o_O=pad_p, o_OB=pad_n) # HDMI (Xilinx 7-Series). @@ -953,13 +953,13 @@ class VideoS7HDMIPHY(Module): self.specials += Instance("OBUFDS", i_I=pads_clk, o_O=pads.clk_p, o_OB=pads.clk_n) # Encode/Serialize Datas. - for color in ["r", "g", "b"]: + for color, channel in _dvi_c2d.items(): # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) self.submodules += encoder self.comb += encoder.d.eq(getattr(sink, color)) - self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if color == "r" else 0) + self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if channel == 0 else 0) self.comb += encoder.de.eq(sink.de) # 10:1 Serialization + Differential Signaling. @@ -970,9 +970,8 @@ class VideoS7HDMIPHY(Module): clock_domain = clock_domain, ) self.submodules += serializer - c2d = {"r": 0, "g": 1, "b": 2} - pad_p = getattr(pads, f"data{c2d[color]}_p") - pad_n = getattr(pads, f"data{c2d[color]}_n") + pad_p = getattr(pads, f"data{channel}_p") + pad_n = getattr(pads, f"data{channel}_n") self.specials += Instance("OBUFDS", i_I=pad_o, o_O=pad_p, o_OB=pad_n) @@ -1010,12 +1009,12 @@ class VideoS7GTPHDMIPHY(Module): self.submodules.pll = pll = GTPQuadPLL(refclk, clk_freq, 1.485e9) # Encode/Serialize Datas. - for color in ["r", "g", "b"]: + for color, channel in _dvi_c2d.items(): # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) self.submodules += encoder self.comb += encoder.d.eq(getattr(sink, color)) - self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if color == "r" else 0) + self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if channel == 0 else 0) self.comb += encoder.de.eq(sink.de) # 10:20 (SerDes has a minimal 20:1 Serialization ratio). @@ -1031,14 +1030,13 @@ class VideoS7GTPHDMIPHY(Module): self.comb += cdc.source.ready.eq(1) # No backpressure. # 20:1 Serialization + Differential Signaling. - c2d = {"r": 0, "g": 1, "b": 2} class GTPPads: def __init__(self, p, n): self.p = p self.n = n - tx_pads = GTPPads(p=getattr(pads, f"data{c2d[color]}_p"), n=getattr(pads, f"data{c2d[color]}_n")) + tx_pads = GTPPads(p=getattr(pads, f"data{channel}_p"), n=getattr(pads, f"data{channel}_n")) # FIXME: Find a way to avoid RX pads. - rx_pads = GTPPads(p=getattr(pads, f"rx{c2d[color]}_p"), n=getattr(pads, f"rx{c2d[color]}_n")) + rx_pads = GTPPads(p=getattr(pads, f"rx{channe}_p"), n=getattr(pads, f"rx{channel}_n")) gtp = GTP(pll, tx_pads, rx_pads=rx_pads, sys_clk_freq=sys_clk_freq, tx_polarity = 1, # FIXME: Specific to Decklink Mini 4K, make it configurable. tx_buffer_enable = True, From 8ffdc535d1f659fcbc2e909c530779d05f822813 Mon Sep 17 00:00:00 2001 From: Christian Klarhorst Date: Thu, 29 Sep 2022 15:42:15 +0200 Subject: [PATCH 20/24] Vivado: Make directives configurable via argparser + add option to limit vivado threads --- litex/build/xilinx/vivado.py | 40 +++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 8e5d9822c..55ec84438 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -105,12 +105,6 @@ class XilinxVivadoToolchain(GenericToolchain): self.pre_placement_commands = XilinxVivadoCommands() self.pre_routing_commands = XilinxVivadoCommands() self.incremental_implementation = False - self.vivado_synth_directive = "default" - self.opt_directive = "default" - self.vivado_place_directive = "default" - self.vivado_post_place_phys_opt_directive = None - self.vivado_route_directive = "default" - self.vivado_post_route_phys_opt_directive = "default" self._synth_mode = "vivado" self._enable_xpm = False @@ -122,11 +116,26 @@ class XilinxVivadoToolchain(GenericToolchain): def build(self, platform, fragment, synth_mode = "vivado", enable_xpm = False, + vivado_synth_directive = "default", + opt_directive = "default", + vivado_place_directive = "default", + vivado_post_place_phys_opt_directive = None, + vivado_route_directive = "default", + vivado_post_route_phys_opt_directive = "default", + vivado_max_threads = None, **kwargs): self._synth_mode = synth_mode self._enable_xpm = enable_xpm + self.vivado_synth_directive = vivado_synth_directive + self.opt_directive = opt_directive + self.vivado_place_directive = vivado_place_directive + self.vivado_post_place_phys_opt_directive = vivado_post_place_phys_opt_directive + self.vivado_route_directive = vivado_route_directive + self.vivado_post_route_phys_opt_directive = vivado_post_route_phys_opt_directive + self.vivado_max_threads = vivado_max_threads + return GenericToolchain.build(self, platform, fragment, **kwargs) # Constraints (.xdc) --------------------------------------------------------------------------- @@ -211,6 +220,9 @@ class XilinxVivadoToolchain(GenericToolchain): tcl.append(f"create_project -force -name {self._build_name} -part {self.platform.device}") tcl.append("set_msg_config -id {Common 17-55} -new_severity {Warning}") + if self.vivado_max_threads: + tcl.append(f"set_param general.maxThreads {self.vivado_max_threads}") + # Enable Xilinx Parameterized Macros if self._enable_xpm: tcl.append("\n# Enable Xilinx Parameterized Macros\n") @@ -376,6 +388,20 @@ class XilinxVivadoToolchain(GenericToolchain): def vivado_build_args(parser): toolchain_group = parser.add_argument_group(title="Toolchain options") toolchain_group.add_argument("--synth-mode", default="vivado", help="Synthesis mode (vivado or yosys).") + toolchain_group.add_argument("--vivado-synth-directive", default="default", help="Specify synthesis directive.") + toolchain_group.add_argument("--vivado-opt-directive", default="default", help="Specify opt directive.") + toolchain_group.add_argument("--vivado-place-directive", default="default", help="Specify place directive.") + toolchain_group.add_argument("--vivado-post-place-phys-opt-directive", default=None, help="Specify phys opt directive.") + toolchain_group.add_argument("--vivado-route-directive", default="default", help="Specify route directive.") + toolchain_group.add_argument("--vivado-post-route-phys-opt-directive", default="default", help="Specify phys opt directive.") + toolchain_group.add_argument("--vivado-max-threads", default=None, help="Limit the max threads vivado is allowed to use.") def vivado_build_argdict(args): - return {"synth_mode": args.synth_mode} + return {"synth_mode": args.synth_mode, + "vivado_synth_directive": args.vivado_synth_directive, + "opt_directive": args.vivado_opt_directive, + "vivado_place_directive": args.vivado_place_directive, + "vivado_post_place_phys_opt_directive": args.vivado_post_place_phys_opt_directive, + "vivado_route_directive": args.vivado_route_directive, + "vivado_post_route_phys_opt_directive": args.vivado_post_route_phys_opt_directive, + "vivado_max_threads": args.vivado_max_threads} \ No newline at end of file From c5eaac9c3eb97c998860f8b6ec96e535dbb8913e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 29 Sep 2022 17:16:16 +0200 Subject: [PATCH 21/24] build/xilinx/vivado: Cosmetic cleanup. --- litex/build/xilinx/vivado.py | 64 +++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 55ec84438..8535d2948 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -99,14 +99,14 @@ class XilinxVivadoToolchain(GenericToolchain): def __init__(self): super().__init__() - self.bitstream_commands = [] - self.additional_commands = [] - self.pre_synthesis_commands = XilinxVivadoCommands() - self.pre_placement_commands = XilinxVivadoCommands() - self.pre_routing_commands = XilinxVivadoCommands() - self.incremental_implementation = False - self._synth_mode = "vivado" - self._enable_xpm = False + self.bitstream_commands = [] + self.additional_commands = [] + self.pre_synthesis_commands = XilinxVivadoCommands() + self.pre_placement_commands = XilinxVivadoCommands() + self.pre_routing_commands = XilinxVivadoCommands() + self.incremental_implementation = False + self._synth_mode = "vivado" + self._enable_xpm = False def finalize(self): # Convert clocks and false path to platform commands @@ -114,27 +114,27 @@ class XilinxVivadoToolchain(GenericToolchain): self._build_false_path_constraints() def build(self, platform, fragment, - synth_mode = "vivado", - enable_xpm = False, + synth_mode = "vivado", + enable_xpm = False, vivado_synth_directive = "default", opt_directive = "default", vivado_place_directive = "default", vivado_post_place_phys_opt_directive = None, vivado_route_directive = "default", vivado_post_route_phys_opt_directive = "default", - vivado_max_threads = None, + vivado_max_threads = None, **kwargs): self._synth_mode = synth_mode self._enable_xpm = enable_xpm - self.vivado_synth_directive = vivado_synth_directive - self.opt_directive = opt_directive - self.vivado_place_directive = vivado_place_directive + self.vivado_synth_directive = vivado_synth_directive + self.opt_directive = opt_directive + self.vivado_place_directive = vivado_place_directive self.vivado_post_place_phys_opt_directive = vivado_post_place_phys_opt_directive - self.vivado_route_directive = vivado_route_directive + self.vivado_route_directive = vivado_route_directive self.vivado_post_route_phys_opt_directive = vivado_post_route_phys_opt_directive - self.vivado_max_threads = vivado_max_threads + self.vivado_max_threads = vivado_max_threads return GenericToolchain.build(self, platform, fragment, **kwargs) @@ -387,21 +387,23 @@ class XilinxVivadoToolchain(GenericToolchain): def vivado_build_args(parser): toolchain_group = parser.add_argument_group(title="Toolchain options") - toolchain_group.add_argument("--synth-mode", default="vivado", help="Synthesis mode (vivado or yosys).") - toolchain_group.add_argument("--vivado-synth-directive", default="default", help="Specify synthesis directive.") - toolchain_group.add_argument("--vivado-opt-directive", default="default", help="Specify opt directive.") - toolchain_group.add_argument("--vivado-place-directive", default="default", help="Specify place directive.") - toolchain_group.add_argument("--vivado-post-place-phys-opt-directive", default=None, help="Specify phys opt directive.") - toolchain_group.add_argument("--vivado-route-directive", default="default", help="Specify route directive.") + toolchain_group.add_argument("--synth-mode", default="vivado", help="Synthesis mode (vivado or yosys).") + toolchain_group.add_argument("--vivado-synth-directive", default="default", help="Specify synthesis directive.") + toolchain_group.add_argument("--vivado-opt-directive", default="default", help="Specify opt directive.") + toolchain_group.add_argument("--vivado-place-directive", default="default", help="Specify place directive.") + toolchain_group.add_argument("--vivado-post-place-phys-opt-directive", default=None, help="Specify phys opt directive.") + toolchain_group.add_argument("--vivado-route-directive", default="default", help="Specify route directive.") toolchain_group.add_argument("--vivado-post-route-phys-opt-directive", default="default", help="Specify phys opt directive.") - toolchain_group.add_argument("--vivado-max-threads", default=None, help="Limit the max threads vivado is allowed to use.") + toolchain_group.add_argument("--vivado-max-threads", default=None, help="Limit the max threads vivado is allowed to use.") def vivado_build_argdict(args): - return {"synth_mode": args.synth_mode, - "vivado_synth_directive": args.vivado_synth_directive, - "opt_directive": args.vivado_opt_directive, - "vivado_place_directive": args.vivado_place_directive, - "vivado_post_place_phys_opt_directive": args.vivado_post_place_phys_opt_directive, - "vivado_route_directive": args.vivado_route_directive, - "vivado_post_route_phys_opt_directive": args.vivado_post_route_phys_opt_directive, - "vivado_max_threads": args.vivado_max_threads} \ No newline at end of file + return { + "synth_mode" : args.synth_mode, + "vivado_synth_directive" : args.vivado_synth_directive, + "opt_directive" : args.vivado_opt_directive, + "vivado_place_directive" : args.vivado_place_directive, + "vivado_post_place_phys_opt_directive" : args.vivado_post_place_phys_opt_directive, + "vivado_route_directive" : args.vivado_route_directive, + "vivado_post_route_phys_opt_directive" : args.vivado_post_route_phys_opt_directive, + "vivado_max_threads" : args.vivado_max_threads + } From af582372030db380e570e17c20a53e4d0356b3b5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 29 Sep 2022 17:29:53 +0200 Subject: [PATCH 22/24] software/demo: Add comments for Nix specific changes (To ease future maintenance and avoid breaking it). --- litex/soc/software/demo/demo.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/litex/soc/software/demo/demo.py b/litex/soc/software/demo/demo.py index fbae89ccf..bb773b3b9 100755 --- a/litex/soc/software/demo/demo.py +++ b/litex/soc/software/demo/demo.py @@ -24,7 +24,7 @@ def main(): # Copy contents to demo directory os.system(f"cp {os.path.abspath(os.path.dirname(__file__))}/* demo") - os.system("chmod -R u+w demo") + os.system("chmod -R u+w demo") # Nix specific: Allow linker script to be modified. # Update memory region. replace_in_file("demo/linker.ld", "main_ram", args.mem) @@ -37,7 +37,8 @@ def main(): os.system("cp demo/demo.bin ./") # Prepare flash boot image. - os.system(f"{sys.executable or 'python3'} -m litex.soc.software.crcfbigen demo.bin -o demo.fbi --fbi --little") # FIXME: Endianness. + python3 = sys.executable or "python3" # Nix specific: Reuse current Python executable if available. + os.system(f"{python3} -m litex.soc.software.crcfbigen demo.bin -o demo.fbi --fbi --little") # FIXME: Endianness. if __name__ == "__main__": main() From cb0e9c23d32b91f0c024067477eb93dac288203e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 30 Sep 2022 11:48:07 +0200 Subject: [PATCH 23/24] Add Efinix JTAG support, with vexriscv-smp binding function --- litex/build/efinix/ifacewriter.py | 27 +++++++++++++++++ litex/soc/cores/jtag.py | 50 +++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index bfbb6f32c..6086e8f89 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -337,6 +337,31 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) cmd += "\n#---------- END PLL {} ---------\n\n".format(name) return cmd + def generate_jtag(self, block, verbose=True): + name = block["name"] + id = block["id"] + pins = block["pins"] + + cmd = f"# ---------- JTAG {id} ---------\n" + cmd += f'jtag = design.create_block("jtag_soc", block_type="JTAG")\n' + cmd += f'design.assign_resource(jtag, "JTAG_USER{id}", "JTAG")\n' + cmd += f'jtag_config = {{\n' + cmd += f' "CAPTURE": "{pins.CAPTURE.backtrace[-1][0]}",\n' + cmd += f' "DRCK": "{pins.DRCK.backtrace[-1][0]}",\n' + cmd += f' "RESET": "{pins.RESET.backtrace[-1][0]}",\n' + cmd += f' "RUNTEST": "{pins.RUNTEST.backtrace[-1][0]}",\n' + cmd += f' "SEL": "{pins.SEL.backtrace[-1][0]}",\n' + cmd += f' "SHIFT": "{pins.SHIFT.backtrace[-1][0]}",\n' + cmd += f' "TCK": "{pins.TCK.backtrace[-1][0]}",\n' + cmd += f' "TDI": "{pins.TDI.backtrace[-1][0]}",\n' + cmd += f' "TMS": "{pins.TMS.backtrace[-1][0]}",\n' + cmd += f' "UPDATE": "{pins.UPDATE.backtrace[-1][0]}",\n' + cmd += f' "TDO": "{pins.TDO.backtrace[-1][0]}"\n' + cmd += f'}}\n' + cmd += f'design.set_property("jtag_soc", jtag_config, block_type="JTAG")\n' + cmd += f"# ---------- END JTAG {id} ---------\n\n" + return cmd + def generate(self, partnumber): output = "" for block in self.blocks: @@ -351,6 +376,8 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) output += self.generate_mipi_tx(block) if block["type"] == "MIPI_RX_LANE": output += self.generate_mipi_rx(block) + if block["type"] == "JTAG": + output += self.generate_jtag(block) return output def footer(self): diff --git a/litex/soc/cores/jtag.py b/litex/soc/cores/jtag.py index 97b827ad6..11d6a2fae 100644 --- a/litex/soc/cores/jtag.py +++ b/litex/soc/cores/jtag.py @@ -12,6 +12,7 @@ from migen import * from migen.genlib.cdc import AsyncResetSynchronizer, MultiReg +from litex.build.generic_platform import * from litex.soc.interconnect import stream # JTAG TAP FSM ------------------------------------------------------------------------------------- @@ -491,3 +492,52 @@ class JTAGPHY(Module): NextState("XFER-READY") ) ) + +# Efinix / TRION ---------------------------------------------------------------------------------- + +class EFINIX_JTAG(Module): + # id refer to the JTAG_USER{id} + def __init__(self, platform, id = 1): + self.name = f"jtag_{id}" + self.platform = platform + self.id = id + + _io = [ + (self.name, 0, + Subsignal("CAPTURE", Pins(1)), + Subsignal("DRCK", Pins(1)), + Subsignal("RESET", Pins(1)), + Subsignal("RUNTEST", Pins(1)), + Subsignal("SEL", Pins(1)), + Subsignal("SHIFT", Pins(1)), + Subsignal("TCK", Pins(1)), + Subsignal("TDI", Pins(1)), + Subsignal("TMS", Pins(1)), + Subsignal("UPDATE", Pins(1)), + Subsignal("TDO", Pins(1)), + ), + ] + platform.add_extension(_io) + + self.pins = platform.request(self.name) + for pin in self.pins.flatten(): + self.platform.toolchain.excluded_ios.append(pin.backtrace[-1][0]) + + block = {} + block["type"] = "JTAG" + block["name"] = self.name + block["id"] = self.id + block["pins"] = self.pins + self.platform.toolchain.ifacewriter.blocks.append(block) + + def bind_vexriscv_smp(self, cpu): + self.comb += cpu.jtag_clk.eq(self.pins.TCK) + self.comb += cpu.jtag_enable.eq(self.pins.SEL) + self.comb += cpu.jtag_capture.eq(self.pins.CAPTURE) + self.comb += cpu.jtag_shift.eq(self.pins.SHIFT) + self.comb += cpu.jtag_update.eq(self.pins.UPDATE) + self.comb += cpu.jtag_reset.eq(self.pins.RESET) + self.comb += cpu.jtag_tdi.eq(self.pins.TDI) + self.comb += self.pins.TDO.eq(cpu.jtag_tdo) + + From 79392e6eb8231e81996f8df413aca5c4a3611e80 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 30 Sep 2022 13:34:00 +0200 Subject: [PATCH 24/24] soc/cores/jtag/Efinix: Cosmetic cleanups and rename EFINIX_JTAG to EfinixJTAG. --- litex/build/efinix/ifacewriter.py | 44 ++++++++++++---------- litex/soc/cores/jtag.py | 61 ++++++++++++++++--------------- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 6086e8f89..0d31c8506 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -339,28 +339,32 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) def generate_jtag(self, block, verbose=True): name = block["name"] - id = block["id"] + id = block["id"] pins = block["pins"] - cmd = f"# ---------- JTAG {id} ---------\n" - cmd += f'jtag = design.create_block("jtag_soc", block_type="JTAG")\n' - cmd += f'design.assign_resource(jtag, "JTAG_USER{id}", "JTAG")\n' - cmd += f'jtag_config = {{\n' - cmd += f' "CAPTURE": "{pins.CAPTURE.backtrace[-1][0]}",\n' - cmd += f' "DRCK": "{pins.DRCK.backtrace[-1][0]}",\n' - cmd += f' "RESET": "{pins.RESET.backtrace[-1][0]}",\n' - cmd += f' "RUNTEST": "{pins.RUNTEST.backtrace[-1][0]}",\n' - cmd += f' "SEL": "{pins.SEL.backtrace[-1][0]}",\n' - cmd += f' "SHIFT": "{pins.SHIFT.backtrace[-1][0]}",\n' - cmd += f' "TCK": "{pins.TCK.backtrace[-1][0]}",\n' - cmd += f' "TDI": "{pins.TDI.backtrace[-1][0]}",\n' - cmd += f' "TMS": "{pins.TMS.backtrace[-1][0]}",\n' - cmd += f' "UPDATE": "{pins.UPDATE.backtrace[-1][0]}",\n' - cmd += f' "TDO": "{pins.TDO.backtrace[-1][0]}"\n' - cmd += f'}}\n' - cmd += f'design.set_property("jtag_soc", jtag_config, block_type="JTAG")\n' - cmd += f"# ---------- END JTAG {id} ---------\n\n" - return cmd + def get_pin_name(pin): + return pin.backtrace[-1][0] + + cmds = [] + cmds.append(f"# ---------- JTAG {id} ---------") + cmds.append(f'jtag = design.create_block("jtag_soc", block_type="JTAG")') + cmds.append(f'design.assign_resource(jtag, "JTAG_USER{id}", "JTAG")') + cmds.append(f'jtag_config = {{') + cmds.append(f' "CAPTURE" : "{get_pin_name(pins.CAPTURE)}",') + cmds.append(f' "DRCK" : "{get_pin_name(pins.DRCK.backtrace)}",') + cmds.append(f' "RESET" : "{get_pin_name(pins.RESET.backtrace)}",') + cmds.append(f' "RUNTEST" : "{get_pin_name(pins.RUNTEST.backtrace)}",') + cmds.append(f' "SEL" : "{get_pin_name(pins.SEL.backtrace)}",') + cmds.append(f' "SHIFT" : "{get_pin_name(pins.SHIFT.backtrace)}",') + cmds.append(f' "TCK" : "{get_pin_name(pins.TCK.backtrace)}",') + cmds.append(f' "TDI" : "{get_pin_name(pins.TDI.backtrace)}",') + cmds.append(f' "TMS" : "{get_pin_name(pins.TMS.backtrace)}",') + cmds.append(f' "UPDATE" : "{get_pin_name(pins.UPDATE.backtrace)}",') + cmds.append(f' "TDO" : "{get_pin_name(pins.TDO.backtrace)}"') + cmds.append(f'}}') + cmds.append(f'design.set_property("jtag_soc", jtag_config, block_type="JTAG")') + cmds.append(f"# ---------- END JTAG {id} ---------\n") + return "\n".join(cmds) def generate(self, partnumber): output = "" diff --git a/litex/soc/cores/jtag.py b/litex/soc/cores/jtag.py index 11d6a2fae..937bf55f6 100644 --- a/litex/soc/cores/jtag.py +++ b/litex/soc/cores/jtag.py @@ -493,51 +493,54 @@ class JTAGPHY(Module): ) ) -# Efinix / TRION ---------------------------------------------------------------------------------- +# Efinix / TRION ----------------------------------------------------------------------------------- -class EFINIX_JTAG(Module): +class EfinixJTAG(Module): # id refer to the JTAG_USER{id} - def __init__(self, platform, id = 1): - self.name = f"jtag_{id}" + def __init__(self, platform, id=1): + self.name = f"jtag_{id}" self.platform = platform - self.id = id + self.id = id _io = [ (self.name, 0, - Subsignal("CAPTURE", Pins(1)), - Subsignal("DRCK", Pins(1)), - Subsignal("RESET", Pins(1)), - Subsignal("RUNTEST", Pins(1)), - Subsignal("SEL", Pins(1)), - Subsignal("SHIFT", Pins(1)), - Subsignal("TCK", Pins(1)), - Subsignal("TDI", Pins(1)), - Subsignal("TMS", Pins(1)), - Subsignal("UPDATE", Pins(1)), - Subsignal("TDO", Pins(1)), - ), + Subsignal("CAPTURE", Pins(1)), + Subsignal("DRCK", Pins(1)), + Subsignal("RESET", Pins(1)), + Subsignal("RUNTEST", Pins(1)), + Subsignal("SEL", Pins(1)), + Subsignal("SHIFT", Pins(1)), + Subsignal("TCK", Pins(1)), + Subsignal("TDI", Pins(1)), + Subsignal("TMS", Pins(1)), + Subsignal("UPDATE", Pins(1)), + Subsignal("TDO", Pins(1)), + ), ] platform.add_extension(_io) - self.pins = platform.request(self.name) - for pin in self.pins.flatten(): + self.pins = pins = platform.request(self.name) + for pin in pins.flatten(): self.platform.toolchain.excluded_ios.append(pin.backtrace[-1][0]) block = {} block["type"] = "JTAG" block["name"] = self.name block["id"] = self.id - block["pins"] = self.pins + block["pins"] = pins self.platform.toolchain.ifacewriter.blocks.append(block) def bind_vexriscv_smp(self, cpu): - self.comb += cpu.jtag_clk.eq(self.pins.TCK) - self.comb += cpu.jtag_enable.eq(self.pins.SEL) - self.comb += cpu.jtag_capture.eq(self.pins.CAPTURE) - self.comb += cpu.jtag_shift.eq(self.pins.SHIFT) - self.comb += cpu.jtag_update.eq(self.pins.UPDATE) - self.comb += cpu.jtag_reset.eq(self.pins.RESET) - self.comb += cpu.jtag_tdi.eq(self.pins.TDI) - self.comb += self.pins.TDO.eq(cpu.jtag_tdo) - + self.comb += [ + # JTAG -> CPU. + cpu.jtag_clk.eq( self.pins.TCK), + cpu.jtag_enable.eq( self.pins.SEL), + cpu.jtag_capture.eq( self.pins.CAPTURE), + cpu.jtag_shift.eq( self.pins.SHIFT), + cpu.jtag_update.eq( self.pins.UPDATE), + cpu.jtag_reset.eq( self.pins.RESET), + cpu.jtag_tdi.eq( self.pins.TDI), + # CPU -> JTAG. + self.pins.TDO.eq(cpu.jtag_tdo), + ]