c3065fe20cecbf8fa91b5c521bef791d9f94cd28
[litex.git] / litex / 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 litex.gen.fhdl.structure import _Fragment
10 from litex.gen.fhdl.verilog import DummyAttrTranslate
11
12 from litex.build.generic_platform import *
13 from litex.build import tools
14 from litex.build.lattice import common
15
16
17 def _format_constraint(c):
18 if isinstance(c, Pins):
19 return ("LOCATE COMP ", " SITE " + "\"" + c.identifiers[0] + "\"")
20 elif isinstance(c, IOStandard):
21 return ("IOBUF PORT ", " IO_TYPE=" + c.name)
22 elif isinstance(c, Misc):
23 return c.misc
24
25
26 def _format_lpf(signame, pin, others, resname):
27 fmt_c = [_format_constraint(c) for c in ([Pins(pin)] + others)]
28 r = ""
29 for pre, suf in fmt_c:
30 r += pre + "\"" + signame + "\"" + suf + ";\n"
31 return r
32
33
34 def _build_lpf(named_sc, named_pc):
35 r = "BLOCK RESETPATHS;\n"
36 r += "BLOCK ASYNCPATHS;\n"
37 for sig, pins, others, resname in named_sc:
38 if len(pins) > 1:
39 for i, p in enumerate(pins):
40 r += _format_lpf(sig + "[" + str(i) + "]", p, others, resname)
41 else:
42 r += _format_lpf(sig, pins[0], others, resname)
43 if named_pc:
44 r += "\n" + "\n\n".join(named_pc)
45 return r
46
47
48 def _build_files(device, sources, vincpaths, build_name):
49 tcl = []
50 tcl.append("prj_project new -name \"{}\" -impl \"implementation\" -dev {} -synthesis \"synplify\"".format(build_name, device))
51 for path in vincpaths:
52 tcl.append("prj_impl option {include path} {\"" + path + "\"}")
53 for filename, language, library in sources:
54 tcl.append("prj_src add \"" + filename + "\" -work " + library)
55 tcl.append("prj_run Synthesis -impl implementation -forceOne")
56 tcl.append("prj_run Translate -impl implementation")
57 tcl.append("prj_run Map -impl implementation")
58 tcl.append("prj_run PAR -impl implementation")
59 tcl.append("prj_run Export -impl implementation -task Bitgen")
60 tools.write_to_file(build_name + ".tcl", "\n".join(tcl))
61
62
63 def _run_diamond(build_name, toolchain_path, ver=None):
64 if sys.platform == "win32" or sys.platform == "cygwin":
65 build_script_contents = "REM Autogenerated by LiteX\n"
66 build_script_contents += "pnmainc " + build_name + ".tcl\n"
67 build_script_file = "build_" + build_name + ".bat"
68 tools.write_to_file(build_script_file, build_script_contents)
69 r = subprocess.call([build_script_file])
70 shutil.copy(os.path.join("implementation", build_name + "_implementation.bit"), build_name + ".bit")
71 shutil.copy(os.path.join("implementation", build_name + "_implementation.jed"), build_name + ".jed")
72 elif sys.platform == "linux":
73 bindir = os.path.join(toolchain_path, 'bin/lin64')
74 envfile = os.path.join(bindir, 'diamond_env')
75 build_script_contents = "# Autogenerated by LiteX\n"
76 build_script_contents += "set -e\n"
77 build_script_contents += "bindir='{}/'\n".format(bindir)
78 build_script_contents += "source {}\n".format(envfile)
79 build_script_contents += "diamondc {}.tcl | tee build.log\n".format(build_name)
80 build_script_file = "build_{}.sh".format(build_name)
81
82 tools.write_to_file(build_script_file, build_script_contents)
83 r = subprocess.call(['/bin/sh', build_script_file])
84 shutil.copy(os.path.join("implementation", build_name + "_implementation.bit"), build_name + ".bit")
85 else:
86 raise NotImplementedError
87
88 if r != 0:
89 raise OSError("Subprocess failed")
90
91
92 class LatticeDiamondToolchain:
93 attr_translate = DummyAttrTranslate()
94
95 special_overrides = common.diamond_special_overrides
96
97 def build(self, platform, fragment, build_dir="build", build_name="top",
98 toolchain_path="/opt/Diamond", run=True, **kwargs):
99 os.makedirs(build_dir, exist_ok=True)
100 cwd = os.getcwd()
101 os.chdir(build_dir)
102
103 if not isinstance(fragment, _Fragment):
104 fragment = fragment.get_fragment()
105 platform.finalize(fragment)
106
107 v_output = platform.get_verilog(fragment, name=build_name, **kwargs)
108 named_sc, named_pc = platform.resolve_signals(v_output.ns)
109 v_file = build_name + ".v"
110 v_output.write(v_file)
111 sources = platform.sources | {(v_file, "verilog", "work")}
112 _build_files(platform.device, sources, platform.verilog_include_paths, build_name)
113
114 tools.write_to_file(build_name + ".lpf", _build_lpf(named_sc, named_pc))
115
116 if run:
117 _run_diamond(build_name, toolchain_path)
118
119 os.chdir(cwd)
120
121 return v_output.ns
122
123 def add_period_constraint(self, platform, clk, period):
124 # TODO: handle differential clk
125 platform.add_platform_command("""FREQUENCY PORT "{clk}" {freq} MHz;""".format(freq=str(float(1/period)*1000), clk="{clk}"), clk=clk)