1 # This file is Copyright (c) 2015-2018 Florent Kermarrec <florent@enjoy-digital.fr>
2 # 2017 Pierre-Olivier Vauboin <po@lambdaconcept.com>
9 from migen
.fhdl
.structure
import _Fragment
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("dut_header.h", content
)
51 def _generate_sim_cpp_struct(name
, index
, siglist
):
54 for i
, (signame
, sigbits
, sigfname
) in enumerate(siglist
):
55 content
+= ' {}{}[{}].signal = &dut->{};\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):
69 #include <verilated.h>
70 #include "dut_header.h"
72 extern "C" void litex_sim_init_tracer(void *vdut);
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(dut);
94 for args
in platform
.sim_requested
:
95 content
+= _generate_sim_cpp_struct(*args
)
101 tools
.write_to_file("dut_init.cpp", content
)
104 def _generate_sim_variables(include_paths
):
106 for path
in include_paths
:
107 include
+= "-I"+path
+" "
111 """.format(core_directory
, include
)
112 tools
.write_to_file("variables.mak", content
)
115 def _generate_sim_config(config
):
116 content
= config
.get_json()
117 tools
.write_to_file("sim_config.js", content
)
120 def _build_sim(platform
, build_name
, sources
, threads
, coverage
, verbose
):
121 makefile
= os
.path
.join(core_directory
, 'Makefile')
123 for filename
, language
, library
in sources
:
124 cc_srcs
.append("--cc " + filename
+ " ")
125 build_script_contents
= """\
127 make -C . -f {} {} {} {}
128 mkdir -p modules && cp obj_dir/*.so modules
130 "CC_SRCS=\"{}\"".format("".join(cc_srcs
)),
131 "THREADS={}".format(threads
) if int(threads
) > 1 else "",
132 "COVERAGE=1" if coverage
else "",
134 build_script_file
= "build_" + build_name
+ ".sh"
135 tools
.write_to_file(build_script_file
, build_script_contents
, force_unix
=True)
137 p
= subprocess
.Popen(["bash", build_script_file
], stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
138 output
, _
= p
.communicate()
139 output
= output
.decode('utf-8')
140 if p
.returncode
!= 0:
142 for l
in output
.splitlines():
143 if verbose
or "error" in l
.lower():
144 error_messages
.append(l
)
145 raise OSError("Subprocess failed with {}\n{}".format(p
.returncode
, "\n".join(error_messages
)))
150 def _run_sim(build_name
, as_root
=False):
151 run_script_contents
= "sudo " if as_root
else ""
152 run_script_contents
+= "obj_dir/Vdut"
153 run_script_file
= "run_" + build_name
+ ".sh"
154 tools
.write_to_file(run_script_file
, run_script_contents
, force_unix
=True)
155 if sys
.platform
!= "win32":
157 termios_settings
= termios
.tcgetattr(sys
.stdin
.fileno())
159 r
= subprocess
.call(["bash", run_script_file
])
161 raise OSError("Subprocess failed")
164 if sys
.platform
!= "win32":
165 termios
.tcsetattr(sys
.stdin
.fileno(), termios
.TCSAFLUSH
, termios_settings
)
168 class SimVerilatorToolchain
:
169 def build(self
, platform
, fragment
, build_dir
="build", build_name
="dut",
170 toolchain_path
=None, serial
="console", build
=True, run
=True, threads
=1,
171 verbose
=True, sim_config
=None, trace
=False, coverage
=False):
173 # create build directory
174 os
.makedirs(build_dir
, exist_ok
=True)
179 if not isinstance(fragment
, _Fragment
):
180 fragment
= fragment
.get_fragment()
181 platform
.finalize(fragment
)
183 # generate top module
184 top_output
= platform
.get_verilog(fragment
,
185 name
=build_name
, dummy_signal
=False, regular_comb
=False, blocking_assign
=True)
186 named_sc
, named_pc
= platform
.resolve_signals(top_output
.ns
)
187 top_file
= build_name
+ ".v"
188 top_output
.write(top_file
)
189 platform
.add_source(top_file
)
191 # generate cpp header/main/variables
192 _generate_sim_h(platform
)
193 _generate_sim_cpp(platform
, trace
)
194 _generate_sim_variables(platform
.verilog_include_paths
)
196 # generate sim config
198 _generate_sim_config(sim_config
)
201 _build_sim(platform
, build_name
, platform
.sources
, threads
, coverage
, verbose
)
205 _run_sim(build_name
, as_root
=sim_config
.has_module("ethernet"))