1334040bb306003e06a2e350bee36a3adb543566
[litex.git] / litex / gen / migen / build / lattice / diamond.py
1 # This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
2 # License: BSD
3
4 import os
5 import sys
6 import subprocess
7 import shutil
8
9 from migen.fhdl.structure import _Fragment
10
11 from migen.build.generic_platform import *
12 from migen.build import tools
13 from migen.build.lattice import common
14
15
16 def _format_constraint(c):
17 if isinstance(c, Pins):
18 return ("LOCATE COMP ", " SITE " + "\"" + c.identifiers[0] + "\"")
19 elif isinstance(c, IOStandard):
20 return ("IOBUF PORT ", " IO_TYPE=" + c.name)
21 elif isinstance(c, Misc):
22 return c.misc
23
24
25 def _format_lpf(signame, pin, others, resname):
26 fmt_c = [_format_constraint(c) for c in ([Pins(pin)] + others)]
27 r = ""
28 for pre, suf in fmt_c:
29 r += pre + "\"" + signame + "\"" + suf + ";\n"
30 return r
31
32
33 def _build_lpf(named_sc, named_pc):
34 r = "BLOCK RESETPATHS;\n"
35 r += "BLOCK ASYNCPATHS;\n"
36 for sig, pins, others, resname in named_sc:
37 if len(pins) > 1:
38 for i, p in enumerate(pins):
39 r += _format_lpf(sig + "[" + str(i) + "]", p, others, resname)
40 else:
41 r += _format_lpf(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_files(device, sources, vincpaths, build_name):
48 tcl = []
49 tcl.append("prj_project new -name \"{}\" -impl \"implementation\" -dev {} -synthesis \"synplify\"".format(build_name, device))
50 for path in vincpaths:
51 tcl.append("prj_impl option {include path} {\"" + path + "\"}")
52 for filename, language, library in sources:
53 tcl.append("prj_src add \"" + filename + "\" -work " + library)
54 tcl.append("prj_run Synthesis -impl implementation -forceOne")
55 tcl.append("prj_run Translate -impl implementation")
56 tcl.append("prj_run Map -impl implementation")
57 tcl.append("prj_run PAR -impl implementation")
58 tcl.append("prj_run Export -impl implementation -task Bitgen")
59 tools.write_to_file(build_name + ".tcl", "\n".join(tcl))
60
61
62 def _run_diamond(build_name, source, ver=None):
63 if sys.platform == "win32" or sys.platform == "cygwin":
64 build_script_contents = "REM Autogenerated by Migen\n"
65 build_script_contents = "pnmainc " + build_name + ".tcl\n"
66 build_script_file = "build_" + build_name + ".bat"
67 tools.write_to_file(build_script_file, build_script_contents)
68 r = subprocess.call([build_script_file])
69 shutil.copy(os.path.join("implementation", build_name + "_implementation.bit"), build_name + ".bit")
70 else:
71 raise NotImplementedError
72
73 if r != 0:
74 raise OSError("Subprocess failed")
75
76
77 class LatticeDiamondToolchain:
78 def build(self, platform, fragment, build_dir="build", build_name="top",
79 toolchain_path="/opt/Diamond", run=True):
80 tools.mkdir_noerror(build_dir)
81 os.chdir(build_dir)
82
83 if not isinstance(fragment, _Fragment):
84 fragment = fragment.get_fragment()
85 platform.finalize(fragment)
86
87 v_output = platform.get_verilog(fragment)
88 named_sc, named_pc = platform.resolve_signals(v_output.ns)
89 v_file = build_name + ".v"
90 v_output.write(v_file)
91 sources = platform.sources | {(v_file, "verilog", "work")}
92 _build_files(platform.device, sources, platform.verilog_include_paths, build_name)
93
94 tools.write_to_file(build_name + ".lpf", _build_lpf(named_sc, named_pc))
95
96 if run:
97 _run_diamond(build_name, toolchain_path)
98
99 os.chdir("..")
100
101 return v_output.ns
102
103 def add_period_constraint(self, platform, clk, period):
104 # TODO: handle differential clk
105 platform.add_platform_command("""FREQUENCY PORT "{clk}" {freq} MHz;""".format(freq=str(float(1/period)*1000), clk="{clk}"), clk=clk)