build/efinix: add a few IO primitives, IO constraints, but mainly it rework how the SDC are handled

This commit is contained in:
Dolu1990 2024-09-05 15:21:12 +02:00
parent e62d84b77b
commit c0fddb6561
5 changed files with 169 additions and 34 deletions

View File

@ -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,6 +431,7 @@ efinix_special_overrides = {
Tristate : EfinixTristate,
DifferentialOutput : EfinixDifferentialOutput,
DifferentialInput : EfinixDifferentialInput,
SDROutput : EfinixSDROutput,
SDRTristate : EfinixSDRTristate,
DDROutput : EfinixDDROutput,
DDRInput : EfinixDDRInput,

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:

View File

@ -109,6 +109,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

@ -107,11 +107,15 @@ class EFINIXPLL(LiteXModule):
clk_out_name = f"{self.name}_clkout{self.nclkouts}" if name == "" else name
if cd is not None:
self.platform.add_extension([(clk_out_name, 0, Pins(1))])
clk_name = f"{cd.name}_clk"
clk_out_name = clk_name # To unify constraints names
self.platform.add_extension([(clk_out_name, 0, Pins(1))])
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
if with_reset:
self.specials += AsyncResetSynchronizer(cd, ~self.locked)
self.platform.toolchain.excluded_ios.append(clk_out_name)