1 # This file is Copyright (c) 2014-2019 Florent Kermarrec <florent@enjoy-digital.fr>
2 # This file is Copyright (c) 2014-2015 Robert Jordens <jordens@gmail.com>
3 # This file is Copyright (c) 2014-2015 Sebastien Bourdeauducq <sb@m-labs.hk>
4 # This file is Copyright (c) 2017 bunnie <bunnie@kosagi.com>
5 # This file is Copyright (c) 2018-2017 Tim 'mithro' Ansell <me@mith.ro>
6 # This file is Copyright (c) 2018 William D. Jones <thor0505@comcast.net>
7 # This file is Copyright (c) 2019 Larry Doolittle <ldoolitt@recycle.lbl.gov>
16 from migen
.fhdl
.structure
import _Fragment
18 from litex
.build
.generic_platform
import *
19 from litex
.build
import tools
20 from litex
.build
.xilinx
import common
23 def _format_constraint(c
):
24 if isinstance(c
, Pins
):
25 return "LOC=" + c
.identifiers
[0]
26 elif isinstance(c
, IOStandard
):
27 return "IOSTANDARD=" + c
.name
28 elif isinstance(c
, Drive
):
29 return "DRIVE=" + str(c
.strength
)
30 elif isinstance(c
, Misc
):
34 def _format_ucf(signame
, pin
, others
, resname
):
36 for c
in [Pins(pin
)] + others
:
37 fc
= _format_constraint(c
)
40 fmt_r
= resname
[0] + ":" + str(resname
[1])
41 if resname
[2] is not None:
42 fmt_r
+= "." + resname
[2]
43 return "NET \"" + signame
+ "\" " + " | ".join(fmt_c
) + "; # " + fmt_r
+ "\n"
46 def _build_ucf(named_sc
, named_pc
):
48 for sig
, pins
, others
, resname
in named_sc
:
50 for i
, p
in enumerate(pins
):
51 r
+= _format_ucf(sig
+ "(" + str(i
) + ")", p
, others
, resname
)
53 r
+= _format_ucf(sig
, pins
[0], others
, resname
)
55 r
+= "\n" + "\n\n".join(named_pc
)
59 def _build_xst_files(device
, sources
, vincpaths
, build_name
, xst_opt
):
61 for filename
, language
, library
in sources
:
62 prj_contents
+= language
+ " " + library
+ " " + tools
.cygpath(filename
) + "\n"
63 tools
.write_to_file(build_name
+ ".prj", prj_contents
)
71 """.format(build_name
=build_name
, xst_opt
=xst_opt
, device
=device
)
73 xst_contents
+= "-vlgincdir {"
74 for path
in vincpaths
:
75 xst_contents
+= tools
.cygpath(path
) + " "
77 tools
.write_to_file(build_name
+ ".xst", xst_contents
)
80 def _run_yosys(device
, sources
, vincpaths
, build_name
):
83 for path
in vincpaths
:
84 incflags
+= " -I" + path
85 for filename
, language
, library
in sources
:
86 ys_contents
+= "read_{}{} {}\n".format(language
, incflags
, filename
)
88 ys_contents
+= """hierarchy -check -top top
89 proc; memory; opt; fsm; opt
90 synth_xilinx -top top -edif {build_name}.edif""".format(build_name
=build_name
)
92 ys_name
= build_name
+ ".ys"
93 tools
.write_to_file(ys_name
, ys_contents
)
94 r
= subprocess
.call(["yosys", ys_name
])
96 raise OSError("Subprocess failed")
99 def _run_ise(build_name
, ise_path
, source
, mode
, ngdbuild_opt
,
100 toolchain
, platform
, ver
=None):
101 if sys
.platform
== "win32" or sys
.platform
== "cygwin":
104 shell
= ["cmd", "/c"]
105 build_script_contents
= "@echo off\nrem Autogenerated by LiteX / git: " + tools
.get_litex_git_revision() + "\n"
106 fail_stmt
= " || exit /b"
108 source_cmd
= "source "
111 build_script_contents
= "# Autogenerated by LiteX / git: " + tools
.get_litex_git_revision() + "\nset -e\n"
114 settings
= common
.settings(ise_path
, ver
, "ISE_DS")
115 build_script_contents
+= source_cmd
+ tools
.cygpath(settings
) + "\n"
120 build_script_contents
+= """
121 xst -ifn {build_name}.xst{fail_stmt}
124 # This generates a .v file for post synthesis simulation
125 build_script_contents
+= """
126 netgen -ofmt verilog -w -sim {build_name}.{ext} {build_name}_synth.v
129 build_script_contents
+= """
130 ngdbuild {ngdbuild_opt} -uc {build_name}.ucf {build_name}.{ext} {build_name}.ngd{fail_stmt}
133 build_script_contents
+= """
134 cpldfit -ofmt verilog {par_opt} -p {device} {build_name}.ngd{fail_stmt}
135 taengine -f {build_name}.vm6 -detail -iopath -l {build_name}.tim{fail_stmt}
136 hprep6 -s IEEE1532 -i {build_name}.vm6{fail_stmt}
139 build_script_contents
+= """
140 map {map_opt} -o {build_name}_map.ncd {build_name}.ngd {build_name}.pcf{fail_stmt}
141 par {par_opt} {build_name}_map.ncd {build_name}.ncd {build_name}.pcf{fail_stmt}
142 bitgen {bitgen_opt} {build_name}.ncd {build_name}.bit{fail_stmt}
144 build_script_contents
= build_script_contents
.format(build_name
=build_name
,
145 ngdbuild_opt
=ngdbuild_opt
, bitgen_opt
=toolchain
.bitgen_opt
, ext
=ext
,
146 par_opt
=toolchain
.par_opt
, map_opt
=toolchain
.map_opt
,
147 device
=platform
.device
, fail_stmt
=fail_stmt
)
148 build_script_contents
+= toolchain
.ise_commands
.format(build_name
=build_name
)
149 build_script_file
= "build_" + build_name
+ script_ext
150 tools
.write_to_file(build_script_file
, build_script_contents
, force_unix
=False)
151 command
= shell
+ [build_script_file
]
152 r
= tools
.subprocess_call_filtered(command
, common
.colors
)
154 raise OSError("Subprocess failed")
157 class XilinxISEToolchain
:
159 "keep": ("keep", "true"),
160 "no_retiming": ("register_balancing", "no"),
165 "no_shreg_extract": ("shreg_extract", "no")
169 self
.xst_opt
= """-ifmt MIXED
172 -register_balancing yes"""
173 self
.map_opt
= "-ol high -w"
174 self
.par_opt
= "-ol high -w"
175 self
.ngdbuild_opt
= ""
176 self
.bitgen_opt
= "-g Binary:Yes -w"
177 self
.ise_commands
= ""
179 def build(self
, platform
, fragment
, build_dir
="build", build_name
="top",
180 toolchain_path
=None, source
=True, run
=True, mode
="xst", **kwargs
):
181 if not isinstance(fragment
, _Fragment
):
182 fragment
= fragment
.get_fragment()
183 if toolchain_path
is None:
184 if sys
.platform
== "win32":
185 toolchain_path
= "C:\\Xilinx"
186 elif sys
.platform
== "cygwin":
187 toolchain_path
= "/cygdrive/c/Xilinx"
189 toolchain_path
= "/opt/Xilinx"
191 platform
.finalize(fragment
)
192 ngdbuild_opt
= self
.ngdbuild_opt
195 os
.makedirs(build_dir
, exist_ok
=True)
199 if mode
in ("xst", "yosys", "cpld"):
200 v_output
= platform
.get_verilog(fragment
, name
=build_name
, **kwargs
)
202 named_sc
, named_pc
= platform
.resolve_signals(vns
)
203 v_file
= build_name
+ ".v"
204 v_output
.write(v_file
)
205 sources
= platform
.sources |
{(v_file
, "verilog", "work")}
206 if mode
in ("xst", "cpld"):
207 _build_xst_files(platform
.device
, sources
, platform
.verilog_include_paths
, build_name
, self
.xst_opt
)
210 _run_yosys(platform
.device
, sources
, platform
.verilog_include_paths
, build_name
)
212 ngdbuild_opt
+= "-p " + platform
.device
215 from mist
import synthesize
216 synthesize(fragment
, platform
.constraint_manager
.get_io_signals())
218 if mode
== "edif" or mode
== "mist":
219 e_output
= platform
.get_edif(fragment
)
221 named_sc
, named_pc
= platform
.resolve_signals(vns
)
222 e_file
= build_name
+ ".edif"
223 e_output
.write(e_file
)
226 tools
.write_to_file(build_name
+ ".ucf", _build_ucf(named_sc
, named_pc
))
228 _run_ise(build_name
, toolchain_path
, source
, isemode
,
229 ngdbuild_opt
, self
, platform
)
235 # ISE is broken and you must use *separate* TNM_NET objects for period
236 # constraints and other constraints otherwise it will be unable to trace
237 # them through clock objects like DCM and PLL objects.
239 def add_period_constraint(self
, platform
, clk
, period
):
240 platform
.add_platform_command(
242 NET "{clk}" TNM_NET = "PRD{clk}";
243 TIMESPEC "TS{clk}" = PERIOD "PRD{clk}" """ + str(period
) + """ ns HIGH 50%;
248 def add_false_path_constraint(self
, platform
, from_
, to
):
249 platform
.add_platform_command(
251 NET "{from_}" TNM_NET = "TIG{from_}";
252 NET "{to}" TNM_NET = "TIG{to}";
253 TIMESPEC "TS{from_}TO{to}" = FROM "TIG{from_}" TO "TIG{to}" TIG;