1 # This file is Copyright (c) 2013 Florent Kermarrec <florent@enjoy-digital.fr>
7 from migen
.fhdl
.structure
import _Fragment
9 from migen
.build
.generic_platform
import Pins
, IOStandard
, Misc
10 from migen
.build
import tools
13 def _format_constraint(c
, signame
, fmt_r
):
14 if isinstance(c
, Pins
):
15 return "set_location_assignment -comment \"{name}\" " \
16 "-to {signame} Pin_{pin}".format(
20 elif isinstance(c
, IOStandard
):
21 return "set_instance_assignment -name io_standard " \
22 "-comment \"{name}\" \"{std}\" -to {signame}".format(
26 elif isinstance(c
, Misc
):
27 if not isinstance(c
.misc
, str) and len(c
.misc
) == 2:
28 return "set_instance_assignment -comment \"{name}\" " \
29 "-name {misc[0]} \"{misc[1]}\" -to {signame}".format(
34 return "set_instance_assignment -comment \"{name}\" " \
36 "-to {signame}".format(
42 def _format_qsf(signame
, pin
, others
, resname
):
43 fmt_r
= "{}:{}".format(*resname
[:2])
44 if resname
[2] is not None:
45 fmt_r
+= "." + resname
[2]
47 fmt_c
= [_format_constraint(c
, signame
, fmt_r
) for c
in
48 ([Pins(pin
)] + others
)]
50 return '\n'.join(fmt_c
)
53 def _build_qsf(named_sc
, named_pc
):
55 for sig
, pins
, others
, resname
in named_sc
:
57 for i
, p
in enumerate(pins
):
59 _format_qsf("{}[{}]".format(sig
, i
), p
, others
, resname
))
61 lines
.append(_format_qsf(sig
, pins
[0], others
, resname
))
65 lines
.append("\n\n".join(named_pc
))
67 lines
.append("set_global_assignment -name top_level_entity top")
68 return "\n".join(lines
)
71 def _build_files(device
, sources
, vincpaths
, named_sc
, named_pc
, build_name
):
73 for filename
, language
, library
in sources
:
74 # Enforce use of SystemVerilog
75 # (Quartus does not support global parameters in Verilog)
76 if language
== "verilog":
77 language
= "systemverilog"
79 "set_global_assignment -name {lang}_FILE {path} "
80 "-library {lib}".format(
81 lang
=language
.upper(),
82 path
=filename
.replace("\\", "/"),
85 for path
in vincpaths
:
86 lines
.append("set_global_assignment -name SEARCH_PATH {}".format(
87 path
.replace("\\", "/")))
89 lines
.append(_build_qsf(named_sc
, named_pc
))
90 lines
.append("set_global_assignment -name DEVICE {}".format(device
))
91 tools
.write_to_file("{}.qsf".format(build_name
), "\n".join(lines
))
94 def _run_quartus(build_name
, quartus_path
):
95 build_script_contents
= """# Autogenerated by Migen
99 quartus_map --read_settings_files=on --write_settings_files=off {build_name} -c {build_name}
100 quartus_fit --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
101 quartus_asm --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
102 quartus_sta {build_name} -c {build_name}
104 """.format(build_name
=build_name
) # noqa
105 build_script_file
= "build_" + build_name
+ ".sh"
106 tools
.write_to_file(build_script_file
,
107 build_script_contents
,
110 if subprocess
.call(["bash", build_script_file
]):
111 raise OSError("Subprocess failed")
114 class AlteraQuartusToolchain
:
115 def build(self
, platform
, fragment
, build_dir
="build", build_name
="top",
116 toolchain_path
="/opt/Altera", run
=True):
117 tools
.mkdir_noerror(build_dir
)
120 if not isinstance(fragment
, _Fragment
):
121 fragment
= fragment
.get_fragment()
122 platform
.finalize(fragment
)
124 v_output
= platform
.get_verilog(fragment
)
125 named_sc
, named_pc
= platform
.resolve_signals(v_output
.ns
)
126 v_file
= build_name
+ ".v"
127 v_output
.write(v_file
)
128 sources
= platform
.sources |
{(v_file
, "verilog", "work")}
129 _build_files(platform
.device
,
131 platform
.verilog_include_paths
,
136 _run_quartus(build_name
, toolchain_path
)
142 def add_period_constraint(self
, platform
, clk
, period
):
143 # TODO: handle differential clk
144 platform
.add_platform_command(
145 "set_global_assignment -name duty_cycle 50 -section_id {clk}",
147 platform
.add_platform_command(
148 "set_global_assignment -name fmax_requirement \"{freq} MHz\" "
149 "-section_id {clk}".format(freq
=(1. / period
) * 1000,