1 # This file is Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
2 # This file is Copyright (c) 2017 Pierre-Olivier Vauboin <po@lambdaconcept>
9 from migen
.fhdl
.structure
import _Fragment
10 from litex
import get_data_mod
11 from litex
.build
import tools
12 from litex
.build
.generic_platform
import *
15 sim_directory
= os
.path
.abspath(os
.path
.dirname(__file__
))
16 core_directory
= os
.path
.join(sim_directory
, 'core')
19 def _generate_sim_h_struct(name
, index
, siglist
):
22 content
+= 'struct pad_s {}{}[] = {{\n'.format(name
, index
)
23 for signame
, sigbits
, dummy
in siglist
:
24 content
+= ' {{ (char*)"{}", {}, NULL }},\n'.format(signame
, sigbits
)
25 content
+= ' { NULL, 0, NULL }\n'
31 def _generate_sim_h(platform
):
38 for args
in platform
.sim_requested
:
39 content
+= _generate_sim_h_struct(*args
)
43 void litex_sim_init(void **out);
46 #endif /* __SIM_CORE_H_ */
48 tools
.write_to_file("sim_header.h", content
)
51 def _generate_sim_cpp_struct(name
, index
, siglist
):
54 for i
, (signame
, sigbits
, sigfname
) in enumerate(siglist
):
55 content
+= ' {}{}[{}].signal = &sim->{};\n'.format(name
, index
, i
, sigfname
)
57 idx_int
= 0 if not index
else int(index
)
58 content
+= ' litex_sim_register_pads({}{}, (char*)"{}", {});\n\n'.format(name
, index
, name
, idx_int
)
63 def _generate_sim_cpp(platform
, trace
=False, trace_start
=0, trace_end
=-1):
69 #include <verilated.h>
70 #include "sim_header.h"
72 extern "C" void litex_sim_init_tracer(void *vsim, long start, long end);
73 extern "C" void litex_sim_tracer_dump();
75 extern "C" void litex_sim_dump()
80 litex_sim_tracer_dump();
85 extern "C" void litex_sim_init(void **out)
91 litex_sim_init_tracer(sim, {}, {});
93 """.format(trace_start
, trace_end
)
94 for args
in platform
.sim_requested
:
95 content
+= _generate_sim_cpp_struct(*args
)
101 tools
.write_to_file("sim_init.cpp", content
)
104 def _generate_sim_variables(include_paths
):
105 tapcfg_dir
= get_data_mod("misc", "tapcfg").data_location
107 for path
in include_paths
:
108 include
+= "-I"+path
+" "
112 TAPCFG_DIRECTORY = {}
113 """.format(core_directory
, include
, tapcfg_dir
)
114 tools
.write_to_file("variables.mak", content
)
117 def _generate_sim_config(config
):
118 content
= config
.get_json()
119 tools
.write_to_file("sim_config.js", content
)
122 def _build_sim(build_name
, sources
, threads
, coverage
, opt_level
="O3", trace_fst
=False):
123 makefile
= os
.path
.join(core_directory
, 'Makefile')
125 for filename
, language
, library
in sources
:
126 cc_srcs
.append("--cc " + filename
+ " ")
127 build_script_contents
= """\
129 make -C . -f {} {} {} {} {} {}
131 "CC_SRCS=\"{}\"".format("".join(cc_srcs
)),
132 "THREADS={}".format(threads
) if int(threads
) > 1 else "",
133 "COVERAGE=1" if coverage
else "",
134 "OPT_LEVEL={}".format(opt_level
),
135 "TRACE_FST=1" if trace_fst
else "",
137 build_script_file
= "build_" + build_name
+ ".sh"
138 tools
.write_to_file(build_script_file
, build_script_contents
, force_unix
=True)
140 def _compile_sim(build_name
, verbose
):
141 build_script_file
= "build_" + build_name
+ ".sh"
142 p
= subprocess
.Popen(["bash", build_script_file
], stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
143 output
, _
= p
.communicate()
144 output
= output
.decode('utf-8')
145 if p
.returncode
!= 0:
147 for l
in output
.splitlines():
148 if verbose
or "error" in l
.lower():
149 error_messages
.append(l
)
150 raise OSError("Subprocess failed with {}\n{}".format(p
.returncode
, "\n".join(error_messages
)))
154 def _run_sim(build_name
, as_root
=False):
155 run_script_contents
= "sudo " if as_root
else ""
156 run_script_contents
+= "obj_dir/Vsim"
157 run_script_file
= "run_" + build_name
+ ".sh"
158 tools
.write_to_file(run_script_file
, run_script_contents
, force_unix
=True)
159 if sys
.platform
!= "win32":
161 termios_settings
= termios
.tcgetattr(sys
.stdin
.fileno())
163 r
= subprocess
.call(["bash", run_script_file
])
165 raise OSError("Subprocess failed")
168 if sys
.platform
!= "win32":
169 termios
.tcsetattr(sys
.stdin
.fileno(), termios
.TCSAFLUSH
, termios_settings
)
172 class SimVerilatorToolchain
:
173 def build(self
, platform
, fragment
, build_dir
="build", build_name
="sim",
174 serial
="console", build
=True, run
=True, threads
=1,
175 verbose
=True, sim_config
=None, coverage
=False, opt_level
="O0",
176 trace
=False, trace_fst
=False, trace_start
=0, trace_end
=-1,
179 # create build directory
180 os
.makedirs(build_dir
, exist_ok
=True)
185 if not isinstance(fragment
, _Fragment
):
186 fragment
= fragment
.get_fragment()
187 platform
.finalize(fragment
)
189 # generate top module
190 top_output
= platform
.get_verilog(fragment
,
191 name
=build_name
, dummy_signal
=False, regular_comb
=regular_comb
, blocking_assign
=True)
192 named_sc
, named_pc
= platform
.resolve_signals(top_output
.ns
)
193 top_file
= build_name
+ ".v"
194 top_output
.write(top_file
)
195 platform
.add_source(top_file
)
197 # generate cpp header/main/variables
198 _generate_sim_h(platform
)
199 _generate_sim_cpp(platform
, trace
, trace_start
, trace_end
)
200 _generate_sim_variables(platform
.verilog_include_paths
)
202 # generate sim config
204 _generate_sim_config(sim_config
)
207 _build_sim(build_name
, platform
.sources
, threads
, coverage
, opt_level
, trace_fst
)
211 _compile_sim(build_name
, verbose
)
213 if sim_config
.has_module("ethernet"):
215 if sim_config
.has_module("xgmii_ethernet"):
217 _run_sim(build_name
, as_root
=run_as_root
)