Merge pull request #2060 from Dolu1990/efinix-rework
build/efinix: add a few IO primitives, IO constraints, sdc rework
This commit is contained in:
commit
dc8b74cc58
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue