72e82a90aa50f123f57ef32b0982e9e3ea428209
[litex.git] / litex / gen / migen / build / xilinx / ise.py
1 import os
2 import subprocess
3 import sys
4
5 from migen.fhdl.structure import _Fragment
6 from migen.build.generic_platform import *
7 from migen.build import tools
8 from migen.build.xilinx import common
9
10
11 def _format_constraint(c):
12 if isinstance(c, Pins):
13 return "LOC=" + c.identifiers[0]
14 elif isinstance(c, IOStandard):
15 return "IOSTANDARD=" + c.name
16 elif isinstance(c, Drive):
17 return "DRIVE=" + str(c.strength)
18 elif isinstance(c, Misc):
19 return c.misc
20
21
22 def _format_ucf(signame, pin, others, resname):
23 fmt_c = []
24 for c in [Pins(pin)] + others:
25 fc = _format_constraint(c)
26 if fc is not None:
27 fmt_c.append(fc)
28 fmt_r = resname[0] + ":" + str(resname[1])
29 if resname[2] is not None:
30 fmt_r += "." + resname[2]
31 return "NET \"" + signame + "\" " + " | ".join(fmt_c) + "; # " + fmt_r + "\n"
32
33
34 def _build_ucf(named_sc, named_pc):
35 r = ""
36 for sig, pins, others, resname in named_sc:
37 if len(pins) > 1:
38 for i, p in enumerate(pins):
39 r += _format_ucf(sig + "(" + str(i) + ")", p, others, resname)
40 else:
41 r += _format_ucf(sig, pins[0], others, resname)
42 if named_pc:
43 r += "\n" + "\n\n".join(named_pc)
44 return r
45
46
47 def _build_xst_files(device, sources, vincpaths, build_name, xst_opt):
48 prj_contents = ""
49 for filename, language, library in sources:
50 prj_contents += language + " " + library + " " + filename + "\n"
51 tools.write_to_file(build_name + ".prj", prj_contents)
52
53 xst_contents = """run
54 -ifn {build_name}.prj
55 -top top
56 {xst_opt}
57 -ofn {build_name}.ngc
58 -p {device}
59 """.format(build_name=build_name, xst_opt=xst_opt, device=device)
60 for path in vincpaths:
61 xst_contents += "-vlgincdir " + path + "\n"
62 tools.write_to_file(build_name + ".xst", xst_contents)
63
64
65 def _run_yosys(device, sources, vincpaths, build_name):
66 ys_contents = ""
67 incflags = ""
68 for path in vincpaths:
69 incflags += " -I" + path
70 for filename, language, library in sources:
71 ys_contents += "read_{}{} {}\n".format(language, incflags, filename)
72
73 ys_contents += """hierarchy -check -top top
74 proc; memory; opt; fsm; opt
75 synth_xilinx -top top -edif {build_name}.edif""".format(build_name=build_name)
76
77 ys_name = build_name + ".ys"
78 tools.write_to_file(ys_name, ys_contents)
79 r = subprocess.call(["yosys", ys_name])
80 if r != 0:
81 raise OSError("Subprocess failed")
82
83
84 def _run_ise(build_name, ise_path, source, mode, ngdbuild_opt,
85 bitgen_opt, ise_commands, map_opt, par_opt, ver=None):
86 if sys.platform == "win32" or sys.platform == "cygwin":
87 source_cmd = "call "
88 script_ext = ".bat"
89 shell = ["cmd", "/c"]
90 build_script_contents = "@echo off\nrem Autogenerated by Migen\n"
91 else:
92 source_cmd = "source "
93 script_ext = ".sh"
94 shell = ["bash"]
95 build_script_contents = "# Autogenerated by Migen\nset -e\n"
96 if source:
97 settings = common.settings(ise_path, ver, "ISE_DS")
98 build_script_contents += source_cmd + settings + "\n"
99 if mode == "edif":
100 ext = "edif"
101 else:
102 ext = "ngc"
103 build_script_contents += """
104 xst -ifn {build_name}.xst
105 """
106
107 build_script_contents += """
108 ngdbuild {ngdbuild_opt} -uc {build_name}.ucf {build_name}.{ext} {build_name}.ngd
109 map {map_opt} -o {build_name}_map.ncd {build_name}.ngd {build_name}.pcf
110 par {par_opt} {build_name}_map.ncd {build_name}.ncd {build_name}.pcf
111 bitgen {bitgen_opt} {build_name}.ncd {build_name}.bit
112 """
113 build_script_contents = build_script_contents.format(build_name=build_name,
114 ngdbuild_opt=ngdbuild_opt, bitgen_opt=bitgen_opt, ext=ext,
115 par_opt=par_opt, map_opt=map_opt)
116 build_script_contents += ise_commands.format(build_name=build_name)
117 build_script_file = "build_" + build_name + script_ext
118 tools.write_to_file(build_script_file, build_script_contents, force_unix=False)
119 command = shell + [build_script_file]
120 r = subprocess.call(command)
121 if r != 0:
122 raise OSError("Subprocess failed")
123
124
125 class XilinxISEToolchain:
126 def __init__(self):
127 self.xst_opt = """-ifmt MIXED
128 -use_new_parser yes
129 -opt_mode SPEED
130 -register_balancing yes"""
131 self.map_opt = "-ol high -w"
132 self.par_opt = "-ol high -w"
133 self.ngdbuild_opt = ""
134 self.bitgen_opt = "-g Binary:Yes -w"
135 self.ise_commands = ""
136
137 def build(self, platform, fragment, build_dir="build", build_name="top",
138 toolchain_path=None, source=None, run=True, mode="xst"):
139 if not isinstance(fragment, _Fragment):
140 fragment = fragment.get_fragment()
141 if toolchain_path is None:
142 if sys.platform == "win32":
143 toolchain_path = "C:\\Xilinx"
144 elif sys.platform == "cygwin":
145 toolchain_path = "/cygdrive/c/Xilinx"
146 else:
147 toolchain_path = "/opt/Xilinx"
148 if source is None:
149 source = sys.platform != "win32"
150
151 platform.finalize(fragment)
152 ngdbuild_opt = self.ngdbuild_opt
153 vns = None
154
155 tools.mkdir_noerror(build_dir)
156 cwd = os.getcwd()
157 os.chdir(build_dir)
158 try:
159 if mode == "xst" or mode == "yosys":
160 v_output = platform.get_verilog(fragment)
161 vns = v_output.ns
162 named_sc, named_pc = platform.resolve_signals(vns)
163 v_file = build_name + ".v"
164 v_output.write(v_file)
165 sources = platform.sources | {(v_file, "verilog", "work")}
166 if mode == "xst":
167 _build_xst_files(platform.device, sources, platform.verilog_include_paths, build_name, self.xst_opt)
168 isemode = "xst"
169 else:
170 _run_yosys(platform.device, sources, platform.verilog_include_paths, build_name)
171 isemode = "edif"
172 ngdbuild_opt += "-p " + platform.device
173
174 if mode == "mist":
175 from mist import synthesize
176 synthesize(fragment, platform.constraint_manager.get_io_signals())
177
178 if mode == "edif" or mode == "mist":
179 e_output = platform.get_edif(fragment)
180 vns = e_output.ns
181 named_sc, named_pc = platform.resolve_signals(vns)
182 e_file = build_name + ".edif"
183 e_output.write(e_file)
184 isemode = "edif"
185
186 tools.write_to_file(build_name + ".ucf", _build_ucf(named_sc, named_pc))
187 if run:
188 _run_ise(build_name, toolchain_path, source, isemode,
189 ngdbuild_opt, self.bitgen_opt, self.ise_commands,
190 self.map_opt, self.par_opt)
191 finally:
192 os.chdir(cwd)
193
194 return vns
195
196 def add_period_constraint(self, platform, clk, period):
197 platform.add_platform_command("""NET "{clk}" TNM_NET = "GRP{clk}";
198 TIMESPEC "TS{clk}" = PERIOD "GRP{clk}" """+str(period)+""" ns HIGH 50%;""", clk=clk)