Skip to content

Commit dc8b74c

Browse files
authored
Merge pull request #2060 from Dolu1990/efinix-rework
build/efinix: add a few IO primitives, IO constraints, sdc rework
2 parents 458e005 + a80f290 commit dc8b74c

File tree

5 files changed

+186
-36
lines changed

5 files changed

+186
-36
lines changed

litex/build/efinix/common.py

Lines changed: 123 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def __init__(self, platform, i, o):
9494
"size" : 1,
9595
"location" : platform.get_pin_location(o)[0],
9696
"properties" : platform.get_pin_properties(o),
97-
"name" : i, # FIXME.
97+
"name" : i.name_override, # FIXME
9898
"mode" : "OUTPUT_CLK",
9999
}
100100
platform.toolchain.ifacewriter.blocks.append(block)
@@ -139,24 +139,7 @@ class EfinixTristate(Module):
139139
def lower(dr):
140140
return EfinixTristateImpl(dr.platform, dr.target, dr.o, dr.oe, dr.i)
141141

142-
# Efinix SDRTristate -------------------------------------------------------------------------------
143142

144-
class EfinixSDRTristateImpl(Module):
145-
def __init__(self, platform, io, o, oe, i, clk):
146-
_o = Signal()
147-
_oe = Signal()
148-
_i = Signal()
149-
self.specials += SDROutput(o, _o, clk)
150-
self.specials += SDRInput(_i, i, clk)
151-
self.submodules += InferedSDRIO(oe, _oe, clk)
152-
tristate = Tristate(io, _o, _oe, _i)
153-
tristate.platform = platform
154-
self.specials += tristate
155-
156-
class EfinixSDRTristate(Module):
157-
@staticmethod
158-
def lower(dr):
159-
return EfinixSDRTristateImpl(dr.platform, dr.io, dr.o, dr.oe, dr.i, dr.clk)
160143

161144
# Efinix DifferentialOutput ------------------------------------------------------------------------
162145

@@ -261,13 +244,130 @@ class EfinixDifferentialInput:
261244
def lower(dr):
262245
return EfinixDifferentialInputImpl(dr.platform, dr.i_p, dr.i_n, dr.o)
263246

247+
248+
249+
250+
251+
# Efinix DDRTristate ---------------------------------------------------------------------------------
252+
253+
class EfinixDDRTristateImpl(Module):
254+
def __init__(self, platform, io, o1, o2, oe1, oe2, i1, i2, clk):
255+
assert oe1 == oe2
256+
io_name = platform.get_pin_name(io)
257+
io_pad = platform.get_pin_location(io)
258+
io_prop = platform.get_pin_properties(io)
259+
io_prop_dict = dict(io_prop)
260+
io_data_i_h = platform.add_iface_io(io_name + "_OUT_HI")
261+
io_data_i_l = platform.add_iface_io(io_name + "_OUT_LO")
262+
io_data_o_h = platform.add_iface_io(io_name + "_IN_HI")
263+
io_data_o_l = platform.add_iface_io(io_name + "_IN_LO")
264+
io_data_e = platform.add_iface_io(io_name + "_OE")
265+
self.comb += io_data_i_h.eq(o1)
266+
self.comb += io_data_i_l.eq(o2)
267+
self.comb += io_data_e.eq(oe1)
268+
self.comb += i1.eq(io_data_o_h)
269+
self.comb += i2.eq(io_data_o_l)
270+
block = {
271+
"type" : "GPIO",
272+
"mode" : "INOUT",
273+
"name" : io_name,
274+
"location" : io_pad,
275+
"properties" : io_prop,
276+
"size" : 1,
277+
"in_reg" : "DDIO_RESYNC",
278+
"in_clk_pin" : clk.name_override, # FIXME.
279+
"out_reg" : "DDIO_RESYNC",
280+
"out_clk_pin" : clk.name_override, # FIXME.
281+
"oe_reg" : "REG",
282+
"is_inclk_inverted" : False,
283+
"drive_strength" : io_prop_dict.get("DRIVE_STRENGTH", "4")
284+
}
285+
platform.toolchain.ifacewriter.blocks.append(block)
286+
platform.toolchain.excluded_ios.append(platform.get_pin(io))
287+
288+
class EfinixDDRTristate:
289+
@staticmethod
290+
def lower(dr):
291+
return EfinixDDRTristateImpl(dr.platform, dr.io, dr.o1, dr.o2, dr.oe1, dr.oe2, dr.i1, dr.i2, dr.clk)
292+
293+
# Efinix SDRTristate -------------------------------------------------------------------------------
294+
295+
class EfinixSDRTristateImpl(EfinixDDRTristateImpl):
296+
def __init__(self, platform, io, o, oe, i, clk):
297+
io_name = platform.get_pin_name(io)
298+
io_pad = platform.get_pin_location(io)
299+
io_prop = platform.get_pin_properties(io)
300+
io_prop_dict = dict(io_prop)
301+
io_data_i = platform.add_iface_io(io_name + "_OUT")
302+
io_data_o = platform.add_iface_io(io_name + "_IN")
303+
io_data_e = platform.add_iface_io(io_name + "_OE")
304+
self.comb += io_data_i.eq(o)
305+
self.comb += io_data_e.eq(oe)
306+
self.comb += i.eq(io_data_o)
307+
block = {
308+
"type" : "GPIO",
309+
"mode" : "INOUT",
310+
"name" : io_name,
311+
"location" : io_pad,
312+
"properties" : io_prop,
313+
"size" : 1,
314+
"in_reg" : "REG",
315+
"in_clk_pin" : clk.name_override, # FIXME.
316+
"out_reg" : "REG",
317+
"out_clk_pin" : clk.name_override, # FIXME.
318+
"oe_reg" : "REG",
319+
"is_inclk_inverted" : False,
320+
"drive_strength" : io_prop_dict.get("DRIVE_STRENGTH", "4")
321+
}
322+
platform.toolchain.ifacewriter.blocks.append(block)
323+
platform.toolchain.excluded_ios.append(platform.get_pin(io))
324+
325+
326+
class EfinixSDRTristate(Module):
327+
@staticmethod
328+
def lower(dr):
329+
return EfinixSDRTristateImpl(dr.platform, dr.io, dr.o, dr.oe, dr.i, dr.clk)
330+
331+
# Efinix SDROutput -------------------------------------------------------------------------------
332+
333+
class EfinixSDROutputImpl(Module):
334+
def __init__(self, platform, i, o, clk):
335+
io_name = platform.get_pin_name(o)
336+
io_pad = platform.get_pin_location(o)
337+
io_prop = platform.get_pin_properties(o)
338+
io_prop_dict = dict(io_prop)
339+
io_data_i = platform.add_iface_io(io_name)
340+
self.comb += io_data_i.eq(i)
341+
block = {
342+
"type" : "GPIO",
343+
"mode" : "OUTPUT",
344+
"name" : io_name,
345+
"location" : io_pad,
346+
"properties" : io_prop,
347+
"size" : 1,
348+
"out_reg" : "REG",
349+
"out_clk_pin" : clk.name_override, # FIXME.
350+
"is_inclk_inverted" : False,
351+
"drive_strength" : io_prop_dict.get("DRIVE_STRENGTH", "4")
352+
}
353+
platform.toolchain.ifacewriter.blocks.append(block)
354+
platform.toolchain.excluded_ios.append(platform.get_pin(o))
355+
356+
357+
class EfinixSDROutput(Module):
358+
@staticmethod
359+
def lower(dr):
360+
return EfinixSDROutputImpl(dr.platform, dr.i, dr.o, dr.clk)
361+
362+
264363
# Efinix DDROutput ---------------------------------------------------------------------------------
265364

266365
class EfinixDDROutputImpl(Module):
267366
def __init__(self, platform, i1, i2, o, clk):
268367
io_name = platform.get_pin_name(o)
269368
io_pad = platform.get_pin_location(o)
270369
io_prop = platform.get_pin_properties(o)
370+
io_prop_dict = dict(io_prop)
271371
io_data_h = platform.add_iface_io(io_name + "_HI")
272372
io_data_l = platform.add_iface_io(io_name + "_LO")
273373
self.comb += io_data_h.eq(i1)
@@ -280,9 +380,9 @@ def __init__(self, platform, i1, i2, o, clk):
280380
"properties" : io_prop,
281381
"size" : 1,
282382
"out_reg" : "DDIO_RESYNC",
283-
"out_clk_pin" : clk, # FIXME.
383+
"out_clk_pin" : clk.name_override, # FIXME.
284384
"is_inclk_inverted" : False,
285-
"drive_strength" : 4 # FIXME: Get it from constraints.
385+
"drive_strength" : io_prop_dict.get("DRIVE_STRENGTH", "4")
286386
}
287387
platform.toolchain.ifacewriter.blocks.append(block)
288388
platform.toolchain.excluded_ios.append(platform.get_pin(o))
@@ -311,7 +411,7 @@ def __init__(self, platform, i, o1, o2, clk):
311411
"properties" : io_prop,
312412
"size" : 1,
313413
"in_reg" : "DDIO_RESYNC",
314-
"in_clk_pin" : clk, # FIXME.
414+
"in_clk_pin" : clk.name_override, # FIXME.
315415
"is_inclk_inverted" : False
316416
}
317417
platform.toolchain.ifacewriter.blocks.append(block)
@@ -331,7 +431,9 @@ def lower(dr):
331431
Tristate : EfinixTristate,
332432
DifferentialOutput : EfinixDifferentialOutput,
333433
DifferentialInput : EfinixDifferentialInput,
434+
SDROutput : EfinixSDROutput,
334435
SDRTristate : EfinixSDRTristate,
335436
DDROutput : EfinixDDROutput,
336437
DDRInput : EfinixDDRInput,
438+
DDRTristate : EfinixDDRTristate,
337439
}

litex/build/efinix/efinity.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ def _format_constraint(self, c, signame, fmt_r):
164164
prop = "PULL_OPTION"
165165
val = c.misc
166166

167+
if c.misc == "SCHMITT_TRIGGER":
168+
prop = "SCHMITT_TRIGGER"
169+
val = "1"
170+
167171
if "DRIVE_STRENGTH" in c.misc:
168172
prop = "DRIVE_STRENGTH"
169173
val = c.misc.split("=")[1]
@@ -267,7 +271,7 @@ def build_project(self):
267271

268272
# Add Timing Constraints.
269273
constraint_info = et.SubElement(root, "efx:constraint_info")
270-
et.SubElement(constraint_info, "efx:sdc_file", name=f"{self._build_name}.sdc")
274+
et.SubElement(constraint_info, "efx:sdc_file", name=f"{self._build_name}_merged.sdc")
271275

272276
# Add Misc Info.
273277
misc_info = et.SubElement(root, "efx:misc_info")
@@ -302,6 +306,26 @@ def build_script(self):
302306
return "" # not used
303307

304308
def run_script(self, script):
309+
# Place and Route.
310+
r = tools.subprocess_call_filtered([self.efinity_path + "/bin/python3",
311+
self.efinity_path + "/scripts/efx_run_pt.py",
312+
f"{self._build_name}",
313+
self.platform.family,
314+
self.platform.device
315+
], common.colors)
316+
if r != 0:
317+
raise OSError("Error occurred during efx_run_pt execution.")
318+
319+
# Merge SDC
320+
with open(f"{self._build_name}_merged.sdc", 'w') as outfile:
321+
with open(f"outflow/{self._build_name}.pt.sdc") as infile:
322+
outfile.write(infile.read())
323+
outfile.write("\n")
324+
outfile.write("#########################\n")
325+
outfile.write("\n")
326+
with open(f"{self._build_name}.sdc") as infile:
327+
outfile.write(infile.read())
328+
305329
# Synthesis/Mapping.
306330
r = tools.subprocess_call_filtered([self.efinity_path + "/bin/efx_map",
307331
"--project", f"{self._build_name}",
@@ -332,15 +356,7 @@ def run_script(self, script):
332356
if r != 0:
333357
raise OSError("Error occurred during efx_map execution.")
334358

335-
# Place and Route.
336-
r = tools.subprocess_call_filtered([self.efinity_path + "/bin/python3",
337-
self.efinity_path + "/scripts/efx_run_pt.py",
338-
f"{self._build_name}",
339-
self.platform.family,
340-
self.platform.device
341-
], common.colors)
342-
if r != 0:
343-
raise OSError("Error occurred during efx_run_pt execution.")
359+
344360

345361
r = tools.subprocess_call_filtered([self.efinity_path + "/bin/efx_pnr",
346362
"--circuit", f"{self._build_name}",
@@ -354,7 +370,7 @@ def run_script(self, script):
354370
"--use_vdb_file", "on",
355371
"--place_file", f"outflow/{self._build_name}.place",
356372
"--route_file", f"outflow/{self._build_name}.route",
357-
"--sdc_file", f"{self._build_name}.sdc",
373+
"--sdc_file", f"{self._build_name}_merged.sdc",
358374
"--sync_file", f"outflow/{self._build_name}.interface.csv",
359375
"--seed", "1",
360376
"--work_dir", "work_pnr",

litex/build/efinix/ifacewriter.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ def generate_gpio(self, block, verbose=True):
166166
cmd += f'design.assign_pkg_pin("{name}[{i}]","{pad}")\n'
167167

168168
if "out_reg" in block:
169+
cmd += f'design.set_property("{name}","oe_REG","{block["out_reg"]}")\n'
170+
171+
if "oe_reg" in block:
169172
cmd += f'design.set_property("{name}","OUT_REG","{block["out_reg"]}")\n'
170173
cmd += f'design.set_property("{name}","OUT_CLK_PIN","{block["out_clk_pin"]}")\n'
171174
if "out_delay" in block:
@@ -189,6 +192,11 @@ def generate_gpio(self, block, verbose=True):
189192
if "oe_clk_pin" in block:
190193
cmd += f'design.set_property("{name}","OE_CLK_PIN","{block["oe_clk_pin"]}")\n'
191194

195+
if "drive_strength" in block:
196+
cmd += 'design.set_property("{}","DRIVE_STRENGTH","{}")\n'.format(name, block["drive_strength"])
197+
if "slewrate" in block:
198+
cmd += 'design.set_property("{}","SLEWRATE","{}")\n'.format(name, block["slewrate"])
199+
192200
if prop:
193201
for p, val in prop:
194202
cmd += 'design.set_property("{}","{}","{}")\n'.format(name, p, val)
@@ -234,7 +242,9 @@ def generate_gpio(self, block, verbose=True):
234242
cmd += f'design.set_property("{name}","OE_CLK_PIN_INV","{block["out_clk_inv"]}")\n'
235243

236244
if "drive_strength" in block:
237-
cmd += 'design.set_property("{}","DRIVE_STRENGTH","4")\n'.format(name, block["drive_strength"])
245+
cmd += 'design.set_property("{}","DRIVE_STRENGTH","{}")\n'.format(name, block["drive_strength"])
246+
if "slewrate" in block:
247+
cmd += 'design.set_property("{}","SLEWRATE","{}")\n'.format(name, block["slewrate"])
238248

239249
if prop:
240250
for p, val in prop:
@@ -429,6 +439,11 @@ def generate_lvds(self, block, verbose=True):
429439
half_rate= block.get("half_rate", "0")
430440
tx_output_load=block.get("output_load", "3")
431441

442+
if type(slow_clk) == ClockSignal:
443+
slow_clk = self.platform.clks[slow_clk.cd]
444+
if type(fast_clk) == ClockSignal:
445+
fast_clk = self.platform.clks[fast_clk.cd]
446+
432447
if mode == "OUTPUT":
433448
block_type = "LVDS_TX"
434449
tx_mode = block["tx_mode"]

litex/build/efinix/platform.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def __init__(self, *args, iobank_info=None, toolchain="efinity", spi_mode="activ
3131
self.iobank_info = iobank_info
3232
self.spi_mode = spi_mode
3333
self.spi_width = spi_width
34+
self.clks = {}
3435
if self.device[:2] == "Ti":
3536
self.family = "Titanium"
3637
else:
@@ -109,6 +110,10 @@ def get_pin_properties(self, sig):
109110
prop = "PULL_OPTION"
110111
val = o.misc
111112
ret.append((prop, val))
113+
if o.misc == "SCHMITT_TRIGGER":
114+
prop = "SCHMITT_TRIGGER"
115+
val = "1"
116+
ret.append((prop, val))
112117
if "DRIVE_STRENGTH" in o.misc:
113118
prop = "DRIVE_STRENGTH"
114119
val = o.misc.split("=")[1]

litex/soc/cores/clock/efinix.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,16 @@ def register_clkin(self, clkin, freq, name="", refclk_name="", lvds_input=False)
8989
self.logger.info("Clock source: {}, using EXT_CLK{}".format(block["input_clock"], clock_no))
9090
self.platform.get_pll_resource(pll_res)
9191
else:
92+
if name != "":
93+
input_signal = name
94+
elif clkin is not None:
95+
input_signal = clkin.name_override
96+
else:
97+
self.logger.error("No clkin name nor clkin provided, can't continue")
98+
quit()
9299
block["input_clock"] = "INTERNAL" if self.type == "TITANIUMPLL" else "CORE"
93100
block["resource"] = self.platform.get_free_pll_resource()
94-
block["input_signal"] = name
101+
block["input_signal"] = input_signal
95102
self.logger.info("Clock source: {}".format(block["input_clock"]))
96103

97104
self.logger.info("PLL used : " + colorer(str(self.platform.pll_used), "cyan"))
@@ -107,11 +114,16 @@ def create_clkout(self, cd, freq, phase=0, margin=0, name="", with_reset=True, d
107114
clk_out_name = f"{self.name}_clkout{self.nclkouts}" if name == "" else name
108115

109116
if cd is not None:
117+
clk_name = f"{cd.name}_{self.name}_clk"
118+
clk_out_name = clk_name # To unify constraints names
110119
self.platform.add_extension([(clk_out_name, 0, Pins(1))])
111-
clk_name = f"{cd.name}_clk"
112120
clk_out = self.platform.request(clk_out_name)
113121
self.comb += cd.clk.eq(clk_out)
114-
self.platform.add_period_constraint(clk=clk_out, period=1e9/freq, name=clk_name)
122+
# Efinity will generate xxx.pt.sdc constraints automaticaly,
123+
# so, the user realy need to use the toplevel pin from the pll instead of an intermediate signal
124+
# This is a dirty workaround. But i don't have any better
125+
cd.clk = clk_out
126+
self.platform.clks[cd.name] = clk_out_name
115127
if with_reset:
116128
self.specials += AsyncResetSynchronizer(cd, ~self.locked)
117129
self.platform.toolchain.excluded_ios.append(clk_out_name)

0 commit comments

Comments
 (0)