From df34b3ae6a36a36e82c785fd8ab2cf47f2b06102 Mon Sep 17 00:00:00 2001 From: Franck Jullien Date: Fri, 17 Dec 2021 10:14:43 +0100 Subject: [PATCH 1/3] efinix: supports for EfinixTristateImpl with nbits > 1 --- litex/build/efinix/common.py | 48 +++++++++++++++++++++------------- litex/build/efinix/platform.py | 5 +++- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 6dbcde953..0c62ac34e 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -65,24 +65,36 @@ class EfinixAsyncResetSynchronizer: class EfinixTristateImpl(Module): def __init__(self, platform, io, o, oe, i=None): nbits, sign = value_bits_sign(io) - assert nbits == 1 - io_name = platform.get_pin_name(io) - io_loc = platform.get_pin_location(io) - io_o = platform.add_iface_io(io_name + "_OUT") - io_oe = platform.add_iface_io(io_name + "_OE") - io_i = platform.add_iface_io(io_name + "_IN") - self.comb += io_o.eq(o) - self.comb += io_oe.eq(oe) - if i is not None: - self.comb += i.eq(io_i) - block = { - "type" : "GPIO", - "mode" : "INOUT", - "name" : io_name, - "location" : [io_loc[0]], - } - platform.toolchain.ifacewriter.blocks.append(block) - platform.toolchain.excluded_ios.append(io_name) + + for bit in range(nbits): + io_name = platform.get_pin_name(io[bit]) + io_loc = platform.get_pin_location(io[bit]) + io_o = platform.add_iface_io(io_name + "_OUT") + io_oe = platform.add_iface_io(io_name + "_OE") + io_i = platform.add_iface_io(io_name + "_IN") + self.comb += io_o.eq(o[bit]) + self.comb += io_oe.eq(oe) + if i[bit] is not None: + self.comb += i[bit].eq(io_i) + block = { + "type" : "GPIO", + "mode" : "INOUT", + "name" : io_name, + "location" : [io_loc[0]], + } + + platform.toolchain.ifacewriter.blocks.append(block) + + # Remove the group from the io list + exclude = platform.get_pin_name(io[0], without_index=True) + + # In case of a single signal, there is still a '0' index + # to be remove at the end + if (nbits == 1) and (exclude[:-1] == '0'): + exclude = exclude[:-1] + + platform.toolchain.excluded_ios.append(exclude) + class EfinixTristate(Module): @staticmethod diff --git a/litex/build/efinix/platform.py b/litex/build/efinix/platform.py index b267f57c7..81f36d6c7 100644 --- a/litex/build/efinix/platform.py +++ b/litex/build/efinix/platform.py @@ -100,7 +100,10 @@ class EfinixPlatform(GenericPlatform): for s, pins, others, resource in sc: if s == sig: if resource[2]: - return resource[0] + "_" + resource[2] + (f"{idx}" if slc else "") + name = resource[0] + "_" + resource[2] + if without_index is False: + name = name + (f"{idx}" if slc else "") + return name else: return resource[0] + (f"{idx}" if slc else "") return None From df20ea5aa8b04f7685ed5757abaa82185b6030b9 Mon Sep 17 00:00:00 2001 From: Franck Jullien Date: Fri, 17 Dec 2021 10:20:06 +0100 Subject: [PATCH 2/3] efinix: when a GPIO block is added, also add pin properties --- litex/build/efinix/common.py | 2 ++ litex/build/efinix/ifacewriter.py | 19 +++++++++++++++++++ litex/build/efinix/platform.py | 31 ++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 0c62ac34e..2ee986884 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -69,6 +69,7 @@ class EfinixTristateImpl(Module): for bit in range(nbits): io_name = platform.get_pin_name(io[bit]) io_loc = platform.get_pin_location(io[bit]) + io_prop = platform.get_pin_properties(io[bit]) io_o = platform.add_iface_io(io_name + "_OUT") io_oe = platform.add_iface_io(io_name + "_OE") io_i = platform.add_iface_io(io_name + "_IN") @@ -81,6 +82,7 @@ class EfinixTristateImpl(Module): "mode" : "INOUT", "name" : io_name, "location" : [io_loc[0]], + "properties" : io_prop } platform.toolchain.ifacewriter.blocks.append(block) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 4fed01f40..5957d138f 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -108,6 +108,7 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) def generate_gpio(self, block, verbose=True): name = block["name"] mode = block["mode"] + prop = block["properties"] cmd = "" if mode == "INOUT": @@ -118,6 +119,9 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) cmd += f'design.create_inout_gpio("{name}",{block["size"]-1},0)\n' for i, pad in enumerate(block["location"]): cmd += f'design.assign_pkg_pin("{name}[{i}]","{pad}")\n' + if prop: + for p, val in prop: + cmd += 'design.set_property("{}","{}","{}")\n'.format(name, p, val) cmd += "\n" return cmd @@ -132,6 +136,10 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) if "in_reg" in block: cmd += f'design.set_property("{name}","IN_REG","{block["in_reg"]}")\n' cmd += f'design.set_property("{name}","IN_CLK_PIN","{block["in_clk_pin"]}")\n' + if prop: + for p, val in prop: + cmd += 'design.set_property("{}","{}","{}")\n'.format(name, p, val) + cmd += "\n" return cmd if mode == "OUTPUT": @@ -150,6 +158,9 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) if "drive_strength" in block: cmd += 'design.set_property("{}","DRIVE_STRENGTH","4")\n'.format(name, block["drive_strength"]) + if prop: + for p, val in prop: + cmd += 'design.set_property("{}","{}","{}")\n'.format(name, p, val) cmd += "\n" return cmd @@ -157,12 +168,20 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) cmd += 'design.create_input_clock_gpio("{}")\n'.format(name) cmd += 'design.set_property("{}","IN_PIN","{}")\n'.format(name, name) cmd += 'design.assign_pkg_pin("{}","{}")\n\n'.format(name, block["location"]) + if prop: + for p, val in prop: + cmd += 'design.set_property("{}","{}","{}")\n'.format(name, p, val) + cmd += "\n" return cmd if mode == "OUTPUT_CLK": cmd += 'design.create_clockout_gpio("{}")\n'.format(name) cmd += 'design.set_property("{}","OUT_CLK_PIN","{}")\n'.format(name, name) cmd += 'design.assign_pkg_pin("{}","{}")\n\n'.format(name, block["location"]) + if prop: + for p, val in prop: + cmd += 'design.set_property("{}","{}","{}")\n'.format(name, p, val) + cmd += "\n" return cmd cmd = "# TODO: " + str(block) +"\n" diff --git a/litex/build/efinix/platform.py b/litex/build/efinix/platform.py index 81f36d6c7..67ed060cb 100644 --- a/litex/build/efinix/platform.py +++ b/litex/build/efinix/platform.py @@ -86,7 +86,36 @@ class EfinixPlatform(GenericPlatform): return [pins[idx]] return None - def get_pin_name(self, sig): + def get_pin_properties(self, sig): + ret = [] + if sig is None: + return None + assert len(sig) == 1 + + if isinstance(sig, _Slice): + sig = sig.value + sc = self.constraint_manager.get_sig_constraints() + for s, pins, others, resource in sc: + if (s == sig) and (pins[0] != 'X'): + for o in others: + if isinstance(o, IOStandard): + ret.append(('IO_STANDARD', o.name)) + if isinstance(o, Misc): + if o.misc in ["WEAK_PULLUP", "WEAK_PULLDOWN"]: + prop = "PULL_OPTION" + val = o.misc + if "DRIVE_STRENGTH" in o.misc: + prop = "DRIVE_STRENGTH" + val = o.misc.split("=")[1] + ret.append((prop, val)) + if "SLEWRATE" in o.misc: + prop = "SLEW_RATE" + val = "1" + ret.append((prop, val)) + return ret + return None + + def get_pin_name(self, sig, without_index=False): if sig is None: return None assert len(sig) == 1 From ca67ed8c1323a675834e0caa19a34dc9805e5e6d Mon Sep 17 00:00:00 2001 From: Franck Jullien Date: Fri, 17 Dec 2021 10:32:41 +0100 Subject: [PATCH 3/3] efinix: check SLEWRATE property when adding a 'normal' GPIO --- litex/build/efinix/efinity.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index 499bb3c1e..6d315ae15 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -115,6 +115,10 @@ def _format_constraint(c, signame, fmt_r, fragment, platform): prop = "DRIVE_STRENGTH" val = c.misc.split("=")[1] + if "SLEWRATE" in c.misc: + prop = "SLEW_RATE" + val = "1" + if prop == "": # Print error, warning ?? return ""