1 # This file is Copyright (c) 2015-2016 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
):
69 #include <verilated.h>
70 #include "dut_header.h"
72 extern "C" void litex_sim_init(void **out)
79 for args
in platform
.sim_requested
:
80 content
+= _generate_sim_cpp_struct(*args
)
86 tools
.write_to_file("dut_init.cpp", content
)
89 def _generate_sim_variables(include_paths
):
91 for path
in include_paths
:
92 include
+= "-I"+path
+" "
97 """.format(core_directory
, include
)
98 tools
.write_to_file("variables.mak", content
)
101 def _generate_sim_config(config
):
102 content
= config
.get_json()
103 tools
.write_to_file("sim_config.js", content
)
106 def _build_sim(platform
, build_name
, verbose
):
107 makefile
= os
.path
.join(core_directory
, 'Makefile')
108 build_script_contents
= """\
111 mkdir -p modules && cp obj_dir/*.so modules
113 build_script_file
= "build_" + build_name
+ ".sh"
114 tools
.write_to_file(build_script_file
, build_script_contents
, force_unix
=True)
116 p
= subprocess
.Popen(["bash", build_script_file
], stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
117 output
, _
= p
.communicate()
118 output
= output
.decode('utf-8')
119 if p
.returncode
!= 0:
121 for l
in output
.splitlines():
122 if verbose
or "error" in l
.lower():
123 error_messages
.append(l
)
124 raise OSError("Subprocess failed with {}\n{}".format(p
.returncode
, "\n".join(error_messages
)))
129 def _run_sim(build_name
):
130 run_script_contents
= """\
133 run_script_file
= "run_" + build_name
+ ".sh"
134 tools
.write_to_file(run_script_file
, run_script_contents
, force_unix
=True)
135 if sys
.platform
!= "win32":
137 termios_settings
= termios
.tcgetattr(sys
.stdin
.fileno())
139 r
= subprocess
.call(["bash", run_script_file
])
141 raise OSError("Subprocess failed")
143 if sys
.platform
!= "win32":
144 termios
.tcsetattr(sys
.stdin
.fileno(), termios
.TCSAFLUSH
, termios_settings
)
147 class SimVerilatorToolchain
:
148 def build(self
, platform
, fragment
, build_dir
="build", build_name
="dut",
149 toolchain_path
=None, serial
="console", run
=True, verbose
=True,
151 os
.makedirs(build_dir
, exist_ok
=True)
154 if not isinstance(fragment
, _Fragment
):
155 fragment
= fragment
.get_fragment()
156 platform
.finalize(fragment
)
158 v_output
= platform
.get_verilog(fragment
, name
=build_name
)
159 named_sc
, named_pc
= platform
.resolve_signals(v_output
.ns
)
160 v_output
.write(build_name
+ ".v")
163 for source
in platform
.sources
:
164 path
= os
.path
.dirname(source
[0]).replace("\\", "\/")
165 if path
not in include_paths
:
166 include_paths
.append(path
)
167 include_paths
+= platform
.verilog_include_paths
168 _generate_sim_h(platform
)
169 _generate_sim_cpp(platform
)
170 _generate_sim_variables(include_paths
)
172 _generate_sim_config(sim_config
)
173 _build_sim(platform
, build_name
, verbose
)