Skip to content

Commit

Permalink
Merge pull request #2060 from Dolu1990/efinix-rework
Browse files Browse the repository at this point in the history
build/efinix: add a few IO primitives, IO constraints, sdc rework
  • Loading branch information
trabucayre authored Sep 10, 2024
2 parents 458e005 + a80f290 commit dc8b74c
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 36 deletions.
144 changes: 123 additions & 21 deletions litex/build/efinix/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def __init__(self, platform, i, o):
"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)
Expand Down Expand Up @@ -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 ------------------------------------------------------------------------

Expand Down Expand Up @@ -261,13 +244,130 @@ 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):
def __init__(self, platform, i1, i2, 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_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)
Expand All @@ -280,9 +380,9 @@ def __init__(self, platform, i1, i2, o, clk):
"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))
Expand Down Expand Up @@ -311,7 +411,7 @@ def __init__(self, platform, i, o1, o2, clk):
"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)
Expand All @@ -331,7 +431,9 @@ def lower(dr):
Tristate : EfinixTristate,
DifferentialOutput : EfinixDifferentialOutput,
DifferentialInput : EfinixDifferentialInput,
SDROutput : EfinixSDROutput,
SDRTristate : EfinixSDRTristate,
DDROutput : EfinixDDROutput,
DDRInput : EfinixDDRInput,
DDRTristate : EfinixDDRTristate,
}
38 changes: 27 additions & 11 deletions litex/build/efinix/efinity.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ def _format_constraint(self, c, signame, fmt_r):
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]
Expand Down Expand Up @@ -267,7 +271,7 @@ def build_project(self):

# 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")
Expand Down Expand Up @@ -302,6 +306,26 @@ def build_script(self):
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}",
Expand Down Expand Up @@ -332,15 +356,7 @@ def run_script(self, script):
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}",
Expand All @@ -354,7 +370,7 @@ def run_script(self, script):
"--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",
Expand Down
17 changes: 16 additions & 1 deletion litex/build/efinix/ifacewriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ def generate_gpio(self, block, verbose=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:
Expand All @@ -189,6 +192,11 @@ def generate_gpio(self, block, verbose=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)
Expand Down Expand Up @@ -234,7 +242,9 @@ def generate_gpio(self, block, verbose=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:
Expand Down Expand Up @@ -429,6 +439,11 @@ def generate_lvds(self, block, verbose=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"]
Expand Down
5 changes: 5 additions & 0 deletions litex/build/efinix/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def __init__(self, *args, iobank_info=None, toolchain="efinity", spi_mode="activ
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:
Expand Down Expand Up @@ -109,6 +110,10 @@ def get_pin_properties(self, sig):
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]
Expand Down
18 changes: 15 additions & 3 deletions litex/soc/cores/clock/efinix.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,16 @@ def register_clkin(self, clkin, freq, name="", refclk_name="", lvds_input=False)
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"))
Expand All @@ -107,11 +114,16 @@ def create_clkout(self, cd, freq, phase=0, margin=0, name="", with_reset=True, d
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)
Expand Down

0 comments on commit dc8b74c

Please sign in to comment.