Merge pull request #2060 from Dolu1990/efinix-rework

build/efinix: add a few IO primitives, IO constraints, sdc rework
This commit is contained in:
Gwenhael Goavec-Merou 2024-09-10 18:40:10 +02:00 committed by GitHub
commit dc8b74cc58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 186 additions and 36 deletions

View File

@ -94,7 +94,7 @@ class EfinixClkOutputImpl(Module):
"size" : 1,
"location" : platform.get_pin_location(o)[0],
"properties" : platform.get_pin_properties(o),
"name" : i, # FIXME.
"name" : i.name_override, # FIXME
"mode" : "OUTPUT_CLK",
}
platform.toolchain.ifacewriter.blocks.append(block)
@ -139,24 +139,7 @@ class EfinixTristate(Module):
def lower(dr):
return EfinixTristateImpl(dr.platform, dr.target, dr.o, dr.oe, dr.i)
# Efinix SDRTristate -------------------------------------------------------------------------------
class EfinixSDRTristateImpl(Module):
def __init__(self, platform, io, o, oe, i, clk):
_o = Signal()
_oe = Signal()
_i = Signal()
self.specials += SDROutput(o, _o, clk)
self.specials += SDRInput(_i, i, clk)
self.submodules += InferedSDRIO(oe, _oe, clk)
tristate = Tristate(io, _o, _oe, _i)
tristate.platform = platform
self.specials += tristate
class EfinixSDRTristate(Module):
@staticmethod
def lower(dr):
return EfinixSDRTristateImpl(dr.platform, dr.io, dr.o, dr.oe, dr.i, dr.clk)
# Efinix DifferentialOutput ------------------------------------------------------------------------
@ -261,6 +244,122 @@ class EfinixDifferentialInput:
def lower(dr):
return EfinixDifferentialInputImpl(dr.platform, dr.i_p, dr.i_n, dr.o)
# Efinix DDRTristate ---------------------------------------------------------------------------------
class EfinixDDRTristateImpl(Module):
def __init__(self, platform, io, o1, o2, oe1, oe2, i1, i2, clk):
assert oe1 == oe2
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_h = platform.add_iface_io(io_name + "_OUT_HI")
io_data_i_l = platform.add_iface_io(io_name + "_OUT_LO")
io_data_o_h = platform.add_iface_io(io_name + "_IN_HI")
io_data_o_l = platform.add_iface_io(io_name + "_IN_LO")
io_data_e = platform.add_iface_io(io_name + "_OE")
self.comb += io_data_i_h.eq(o1)
self.comb += io_data_i_l.eq(o2)
self.comb += io_data_e.eq(oe1)
self.comb += i1.eq(io_data_o_h)
self.comb += i2.eq(io_data_o_l)
block = {
"type" : "GPIO",
"mode" : "INOUT",
"name" : io_name,
"location" : io_pad,
"properties" : io_prop,
"size" : 1,
"in_reg" : "DDIO_RESYNC",
"in_clk_pin" : clk.name_override, # FIXME.
"out_reg" : "DDIO_RESYNC",
"out_clk_pin" : clk.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 EfinixDDRTristate:
@staticmethod
def lower(dr):
return EfinixDDRTristateImpl(dr.platform, dr.io, dr.o1, dr.o2, dr.oe1, dr.oe2, dr.i1, dr.i2, dr.clk)
# Efinix SDRTristate -------------------------------------------------------------------------------
class EfinixSDRTristateImpl(EfinixDDRTristateImpl):
def __init__(self, platform, io, o, oe, i, clk):
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")
io_data_o = platform.add_iface_io(io_name + "_IN")
io_data_e = platform.add_iface_io(io_name + "_OE")
self.comb += io_data_i.eq(o)
self.comb += io_data_e.eq(oe)
self.comb += i.eq(io_data_o)
block = {
"type" : "GPIO",
"mode" : "INOUT",
"name" : io_name,
"location" : io_pad,
"properties" : io_prop,
"size" : 1,
"in_reg" : "REG",
"in_clk_pin" : clk.name_override, # FIXME.
"out_reg" : "REG",
"out_clk_pin" : clk.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 EfinixSDRTristate(Module):
@staticmethod
def lower(dr):
return EfinixSDRTristateImpl(dr.platform, dr.io, dr.o, dr.oe, dr.i, dr.clk)
# Efinix SDROutput -------------------------------------------------------------------------------
class EfinixSDROutputImpl(Module):
def __init__(self, platform, i, o, clk):
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_i = platform.add_iface_io(io_name)
self.comb += io_data_i.eq(i)
block = {
"type" : "GPIO",
"mode" : "OUTPUT",
"name" : io_name,
"location" : io_pad,
"properties" : io_prop,
"size" : 1,
"out_reg" : "REG",
"out_clk_pin" : clk.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 EfinixSDROutput(Module):
@staticmethod
def lower(dr):
return EfinixSDROutputImpl(dr.platform, dr.i, dr.o, dr.clk)
# Efinix DDROutput ---------------------------------------------------------------------------------
class EfinixDDROutputImpl(Module):
@ -268,6 +367,7 @@ class EfinixDDROutputImpl(Module):
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_h = platform.add_iface_io(io_name + "_HI")
io_data_l = platform.add_iface_io(io_name + "_LO")
self.comb += io_data_h.eq(i1)
@ -280,9 +380,9 @@ class EfinixDDROutputImpl(Module):
"properties" : io_prop,
"size" : 1,
"out_reg" : "DDIO_RESYNC",
"out_clk_pin" : clk, # FIXME.
"out_clk_pin" : clk.name_override, # FIXME.
"is_inclk_inverted" : False,
"drive_strength" : 4 # FIXME: Get it from constraints.
"drive_strength" : io_prop_dict.get("DRIVE_STRENGTH", "4")
}
platform.toolchain.ifacewriter.blocks.append(block)
platform.toolchain.excluded_ios.append(platform.get_pin(o))
@ -311,7 +411,7 @@ class EfinixDDRInputImpl(Module):
"properties" : io_prop,
"size" : 1,
"in_reg" : "DDIO_RESYNC",
"in_clk_pin" : clk, # FIXME.
"in_clk_pin" : clk.name_override, # FIXME.
"is_inclk_inverted" : False
}
platform.toolchain.ifacewriter.blocks.append(block)
@ -331,7 +431,9 @@ efinix_special_overrides = {
Tristate : EfinixTristate,
DifferentialOutput : EfinixDifferentialOutput,
DifferentialInput : EfinixDifferentialInput,
SDROutput : EfinixSDROutput,
SDRTristate : EfinixSDRTristate,
DDROutput : EfinixDDROutput,
DDRInput : EfinixDDRInput,
DDRTristate : EfinixDDRTristate,
}

View File

@ -164,6 +164,10 @@ class EfinityToolchain(GenericToolchain):
prop = "PULL_OPTION"
val = c.misc
if c.misc == "SCHMITT_TRIGGER":
prop = "SCHMITT_TRIGGER"
val = "1"
if "DRIVE_STRENGTH" in c.misc:
prop = "DRIVE_STRENGTH"
val = c.misc.split("=")[1]
@ -267,7 +271,7 @@ class EfinityToolchain(GenericToolchain):
# Add Timing Constraints.
constraint_info = et.SubElement(root, "efx:constraint_info")
et.SubElement(constraint_info, "efx:sdc_file", name=f"{self._build_name}.sdc")
et.SubElement(constraint_info, "efx:sdc_file", name=f"{self._build_name}_merged.sdc")
# Add Misc Info.
misc_info = et.SubElement(root, "efx:misc_info")
@ -302,6 +306,26 @@ class EfinityToolchain(GenericToolchain):
return "" # not used
def run_script(self, script):
# Place and Route.
r = tools.subprocess_call_filtered([self.efinity_path + "/bin/python3",
self.efinity_path + "/scripts/efx_run_pt.py",
f"{self._build_name}",
self.platform.family,
self.platform.device
], common.colors)
if r != 0:
raise OSError("Error occurred during efx_run_pt execution.")
# Merge SDC
with open(f"{self._build_name}_merged.sdc", 'w') as outfile:
with open(f"outflow/{self._build_name}.pt.sdc") as infile:
outfile.write(infile.read())
outfile.write("\n")
outfile.write("#########################\n")
outfile.write("\n")
with open(f"{self._build_name}.sdc") as infile:
outfile.write(infile.read())
# Synthesis/Mapping.
r = tools.subprocess_call_filtered([self.efinity_path + "/bin/efx_map",
"--project", f"{self._build_name}",
@ -332,15 +356,7 @@ class EfinityToolchain(GenericToolchain):
if r != 0:
raise OSError("Error occurred during efx_map execution.")
# Place and Route.
r = tools.subprocess_call_filtered([self.efinity_path + "/bin/python3",
self.efinity_path + "/scripts/efx_run_pt.py",
f"{self._build_name}",
self.platform.family,
self.platform.device
], common.colors)
if r != 0:
raise OSError("Error occurred during efx_run_pt execution.")
r = tools.subprocess_call_filtered([self.efinity_path + "/bin/efx_pnr",
"--circuit", f"{self._build_name}",
@ -354,7 +370,7 @@ class EfinityToolchain(GenericToolchain):
"--use_vdb_file", "on",
"--place_file", f"outflow/{self._build_name}.place",
"--route_file", f"outflow/{self._build_name}.route",
"--sdc_file", f"{self._build_name}.sdc",
"--sdc_file", f"{self._build_name}_merged.sdc",
"--sync_file", f"outflow/{self._build_name}.interface.csv",
"--seed", "1",
"--work_dir", "work_pnr",

View File

@ -166,6 +166,9 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True)
cmd += f'design.assign_pkg_pin("{name}[{i}]","{pad}")\n'
if "out_reg" in block:
cmd += f'design.set_property("{name}","oe_REG","{block["out_reg"]}")\n'
if "oe_reg" in block:
cmd += f'design.set_property("{name}","OUT_REG","{block["out_reg"]}")\n'
cmd += f'design.set_property("{name}","OUT_CLK_PIN","{block["out_clk_pin"]}")\n'
if "out_delay" in block:
@ -189,6 +192,11 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True)
if "oe_clk_pin" in block:
cmd += f'design.set_property("{name}","OE_CLK_PIN","{block["oe_clk_pin"]}")\n'
if "drive_strength" in block:
cmd += 'design.set_property("{}","DRIVE_STRENGTH","{}")\n'.format(name, block["drive_strength"])
if "slewrate" in block:
cmd += 'design.set_property("{}","SLEWRATE","{}")\n'.format(name, block["slewrate"])
if prop:
for p, val in prop:
cmd += 'design.set_property("{}","{}","{}")\n'.format(name, p, val)
@ -234,7 +242,9 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True)
cmd += f'design.set_property("{name}","OE_CLK_PIN_INV","{block["out_clk_inv"]}")\n'
if "drive_strength" in block:
cmd += 'design.set_property("{}","DRIVE_STRENGTH","4")\n'.format(name, block["drive_strength"])
cmd += 'design.set_property("{}","DRIVE_STRENGTH","{}")\n'.format(name, block["drive_strength"])
if "slewrate" in block:
cmd += 'design.set_property("{}","SLEWRATE","{}")\n'.format(name, block["slewrate"])
if prop:
for p, val in prop:
@ -429,6 +439,11 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True)
half_rate= block.get("half_rate", "0")
tx_output_load=block.get("output_load", "3")
if type(slow_clk) == ClockSignal:
slow_clk = self.platform.clks[slow_clk.cd]
if type(fast_clk) == ClockSignal:
fast_clk = self.platform.clks[fast_clk.cd]
if mode == "OUTPUT":
block_type = "LVDS_TX"
tx_mode = block["tx_mode"]

View File

@ -31,6 +31,7 @@ class EfinixPlatform(GenericPlatform):
self.iobank_info = iobank_info
self.spi_mode = spi_mode
self.spi_width = spi_width
self.clks = {}
if self.device[:2] == "Ti":
self.family = "Titanium"
else:
@ -109,6 +110,10 @@ class EfinixPlatform(GenericPlatform):
prop = "PULL_OPTION"
val = o.misc
ret.append((prop, val))
if o.misc == "SCHMITT_TRIGGER":
prop = "SCHMITT_TRIGGER"
val = "1"
ret.append((prop, val))
if "DRIVE_STRENGTH" in o.misc:
prop = "DRIVE_STRENGTH"
val = o.misc.split("=")[1]

View File

@ -89,9 +89,16 @@ class EFINIXPLL(LiteXModule):
self.logger.info("Clock source: {}, using EXT_CLK{}".format(block["input_clock"], clock_no))
self.platform.get_pll_resource(pll_res)
else:
if name != "":
input_signal = name
elif clkin is not None:
input_signal = clkin.name_override
else:
self.logger.error("No clkin name nor clkin provided, can't continue")
quit()
block["input_clock"] = "INTERNAL" if self.type == "TITANIUMPLL" else "CORE"
block["resource"] = self.platform.get_free_pll_resource()
block["input_signal"] = name
block["input_signal"] = input_signal
self.logger.info("Clock source: {}".format(block["input_clock"]))
self.logger.info("PLL used : " + colorer(str(self.platform.pll_used), "cyan"))
@ -107,11 +114,16 @@ class EFINIXPLL(LiteXModule):
clk_out_name = f"{self.name}_clkout{self.nclkouts}" if name == "" else name
if cd is not None:
clk_name = f"{cd.name}_{self.name}_clk"
clk_out_name = clk_name # To unify constraints names
self.platform.add_extension([(clk_out_name, 0, Pins(1))])
clk_name = f"{cd.name}_clk"
clk_out = self.platform.request(clk_out_name)
self.comb += cd.clk.eq(clk_out)
self.platform.add_period_constraint(clk=clk_out, period=1e9/freq, name=clk_name)
# Efinity will generate xxx.pt.sdc constraints automaticaly,
# so, the user realy need to use the toplevel pin from the pll instead of an intermediate signal
# This is a dirty workaround. But i don't have any better
cd.clk = clk_out
self.platform.clks[cd.name] = clk_out_name
if with_reset:
self.specials += AsyncResetSynchronizer(cd, ~self.locked)
self.platform.toolchain.excluded_ios.append(clk_out_name)