From b4c4e890e574e07968a5b59aae605c17a1dd8fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Thu, 19 Sep 2024 11:13:22 +0200 Subject: [PATCH] build: efinix: implement QDR input, output and tristade. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit implement QDR input, output and tristade for the titanium. Signed-off-by: Fin Maaß --- litex/build/efinix/common.py | 127 ++++++++++++++++++++++++++++++ litex/build/efinix/ifacewriter.py | 11 +++ 2 files changed, 138 insertions(+) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 0c9d014b7..eeee46967 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -422,6 +422,130 @@ class EfinixDDRInput: def lower(dr): return EfinixDDRInputImpl(dr.platform, dr.i, dr.o1, dr.o2, dr.clk) +# Efinix QDROutput --------------------------------------------------------------------------------- + +class EfinixQDROutputImpl(Module): + def __init__(self, platform, i1, i2, i3, i4, o, clk, fastclk): + assert fastclk is not None + io_name = platform.get_pin_name(o) + io_pad = platform.get_pin_location(o) + io_prop = platform.get_pin_properties(o) + io_prop_dict = dict(io_prop) + io_data = platform.add_iface_io(io_name, 4) + self.comb += io_data[0].eq(i1) + self.comb += io_data[1].eq(i2) + self.comb += io_data[2].eq(i3) + self.comb += io_data[3].eq(i4) + block = { + "type" : "GPIO", + "mode" : "OUTPUT", + "name" : io_name, + "location" : io_pad, + "properties" : io_prop, + "size" : 1, + "out_reg" : "SERIAL", + "out_clk_pin" : clk.name_override, # FIXME. + "outfastclk_pin" : fastclk.name_override, # FIXME. + "is_inclk_inverted" : False, + "drive_strength" : io_prop_dict.get("DRIVE_STRENGTH", "4") + } + platform.toolchain.ifacewriter.blocks.append(block) + platform.toolchain.excluded_ios.append(platform.get_pin(o)) + +class EfinixQDROutput: + @staticmethod + def lower(dr): + if dr.platform.family == "Trion": + raise NotImplementedError("Attempted to use a QDR output, but platform does not support them") + return EfinixQDROutputImpl(dr.platform, dr.i1, dr.i2, dr.i3, dr.i4, dr.o, dr.clk, dr.fastclk) + +# Efinix QDRInput ---------------------------------------------------------------------------------- + +class EfinixQDRInputImpl(Module): + def __init__(self, platform, i, o1, o2, o3, o4, clk, fastclk): + assert fastclk is not None + io_name = platform.get_pin_name(i) + io_pad = platform.get_pin_location(i) + io_prop = platform.get_pin_properties(i) + io_data = platform.add_iface_io(io_name, 4) + self.comb += o1.eq(io_data[0]) + self.comb += o2.eq(io_data[1]) + self.comb += o3.eq(io_data[2]) + self.comb += o4.eq(io_data[3]) + block = { + "type" : "GPIO", + "mode" : "INPUT", + "name" : io_name, + "location" : io_pad, + "properties" : io_prop, + "size" : 1, + "in_reg" : "SERIAL", + "in_clk_pin" : clk.name_override, # FIXME. + "infastclk_pin" : fastclk.name_override, # FIXME. + "is_inclk_inverted" : False, + } + platform.toolchain.ifacewriter.blocks.append(block) + platform.toolchain.excluded_ios.append(platform.get_pin(i)) + +class EfinixQDRInput: + @staticmethod + def lower(dr): + if dr.platform.family == "Trion": + raise NotImplementedError("Attempted to use a QDR input, but platform does not support them") + return EfinixQDRInputImpl(dr.platform, dr.i, dr.o1, dr.o2, dr.o3, dr.o4, dr.clk, dr.fastclk) + +# Efinix QDRTristate --------------------------------------------------------------------------------- + +class EfinixQDRTristateImpl(Module): + def __init__(self, platform, io, o1, o2, o3, o4, oe, i1, i2, i3, i4, clk, fastclk_in, fastclk_out): + assert fastclk_in is not None + assert fastclk_out is not None + io_name = platform.get_pin_name(io) + io_pad = platform.get_pin_location(io) + io_prop = platform.get_pin_properties(io) + io_prop_dict = dict(io_prop) + io_data_i = platform.add_iface_io(io_name + "_OUT", 4) + io_data_o = platform.add_iface_io(io_name + "_IN", 4) + io_data_e = platform.add_iface_io(io_name + "_OE") + self.comb += io_data_i[0].eq(o1) + self.comb += io_data_i[1].eq(o2) + self.comb += io_data_i[2].eq(o3) + self.comb += io_data_i[3].eq(o4) + self.comb += io_data_e.eq(oe) + self.comb += i1.eq(io_data_o[0]) + self.comb += i2.eq(io_data_o[1]) + self.comb += i3.eq(io_data_o[2]) + self.comb += i4.eq(io_data_o[3]) + block = { + "type" : "GPIO", + "mode" : "INOUT", + "name" : io_name, + "location" : io_pad, + "properties" : io_prop, + "size" : 1, + "in_reg" : "SERIAL", + "in_clk_pin" : clk.name_override, # FIXME. + "infastclk_pin" : fastclk_in.name_override, # FIXME. + "out_reg" : "SERIAL", + "out_clk_pin" : clk.name_override, # FIXME. + "outfastclk_pin" : fastclk_out.name_override, # FIXME. + "oe_reg" : "REG", + "is_inclk_inverted" : False, + "drive_strength" : io_prop_dict.get("DRIVE_STRENGTH", "4") + } + platform.toolchain.ifacewriter.blocks.append(block) + platform.toolchain.excluded_ios.append(platform.get_pin(io)) + +class EfinixQDRTristate: + @staticmethod + def lower(dr): + assert dr.oe2 is None + assert dr.oe3 is None + assert dr.oe4 is None + if dr.platform.family == "Trion": + raise NotImplementedError("Attempted to use a QDR tristate, but platform does not support them") + return EfinixQDRTristateImpl(dr.platform, dr.io, dr.o1, dr.o2, dr.o3, dr.o4, dr.oe1, dr.i1, dr.i2, dr.i3, dr.i4, dr.clk, dr.fastclk_in, dr.fastclk_out) + # Efinix Special Overrides ------------------------------------------------------------------------- efinix_special_overrides = { @@ -436,4 +560,7 @@ efinix_special_overrides = { DDROutput : EfinixDDROutput, DDRInput : EfinixDDRInput, DDRTristate : EfinixDDRTristate, + QDRInput : EfinixQDRInput, + QDROutput : EfinixQDROutput, + QDRTristate : EfinixQDRTristate, } diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index f9e9cae78..6d7559c96 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -174,6 +174,9 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) if "out_delay" in block: cmd += f'design.set_property("{name}","OUTDELAY","{block["out_delay"]}")\n' + if "outfastclk_pin" in block: + cmd += 'design.set_property("{}","OUTFASTCLK_PIN","{}")\n'.format(name, block["outfastclk_pin"]) + if "out_clk_inv" in block: cmd += f'design.set_property("{name}","IS_OUTCLK_INVERTED","{block["out_clk_inv"]}")\n' cmd += f'design.set_property("{name}","OE_CLK_PIN_INV","{block["out_clk_inv"]}")\n' @@ -184,6 +187,9 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) if "in_delay" in block: cmd += f'design.set_property("{name}","INDELAY","{block["in_delay"]}")\n' + if "infastclk_pin" in block: + cmd += 'design.set_property("{}","INFASTCLK_PIN","{}")\n'.format(name, block["infastclk_pin"]) + if "in_clk_inv" in block: cmd += f'design.set_property("{name}","IS_INCLK_INVERTED","{block["in_clk_inv"]}")\n' @@ -216,6 +222,8 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) cmd += f'design.set_property("{name}","IN_CLK_PIN","{block["in_clk_pin"]}")\n' if "in_delay" in block: cmd += f'design.set_property("{name}","INDELAY","{block["in_delay"]}")\n' + if "infastclk_pin" in block: + cmd += 'design.set_property("{}","INFASTCLK_PIN","{}")\n'.format(name, block["infastclk_pin"]) if prop: for p, val in prop: cmd += 'design.set_property("{}","{}","{}")\n'.format(name, p, val) @@ -237,6 +245,9 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) if "out_delay" in block: cmd += 'design.set_property("{}","OUTDELAY","{}")\n'.format(name, block["out_delay"]) + if "outfastclk_pin" in block: + cmd += 'design.set_property("{}","OUTFASTCLK_PIN","{}")\n'.format(name, block["outfastclk_pin"]) + if "out_clk_inv" in block: cmd += f'design.set_property("{name}","IS_OUTCLK_INVERTED","{block["out_clk_inv"]}")\n' cmd += f'design.set_property("{name}","OE_CLK_PIN_INV","{block["out_clk_inv"]}")\n'