soc/integration/csr_bridge: use registered version only when SDRAM is present.
[litex.git] / litex / build / sim / verilator.py
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>
3 # License: BSD
4
5 import os
6 import sys
7 import subprocess
8
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 *
13
14
15 sim_directory = os.path.abspath(os.path.dirname(__file__))
16 core_directory = os.path.join(sim_directory, 'core')
17
18
19 def _generate_sim_h_struct(name, index, siglist):
20 content = ''
21
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'
26 content += '};\n\n'
27
28 return content
29
30
31 def _generate_sim_h(platform):
32 content = """\
33 #ifndef __SIM_CORE_H_
34 #define __SIM_CORE_H_
35 #include "pads.h"
36
37 """
38 for args in platform.sim_requested:
39 content += _generate_sim_h_struct(*args)
40
41 content += """\
42 #ifndef __cplusplus
43 void litex_sim_init(void **out);
44 #endif
45
46 #endif /* __SIM_CORE_H_ */
47 """
48 tools.write_to_file("sim_header.h", content)
49
50
51 def _generate_sim_cpp_struct(name, index, siglist):
52 content = ''
53
54 for i, (signame, sigbits, sigfname) in enumerate(siglist):
55 content += ' {}{}[{}].signal = &sim->{};\n'.format(name, index, i, sigfname)
56
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)
59
60 return content
61
62
63 def _generate_sim_cpp(platform, trace=False, trace_start=0, trace_end=-1):
64 content = """\
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include "Vsim.h"
69 #include <verilated.h>
70 #include "sim_header.h"
71
72 extern "C" void litex_sim_init_tracer(void *vsim, long start, long end);
73 extern "C" void litex_sim_tracer_dump();
74
75 extern "C" void litex_sim_dump()
76 {
77 """
78 if trace:
79 content += """\
80 litex_sim_tracer_dump();
81 """
82 content += """\
83 }}
84
85 extern "C" void litex_sim_init(void **out)
86 {{
87 Vsim *sim;
88
89 sim = new Vsim;
90
91 litex_sim_init_tracer(sim, {}, {});
92
93 """.format(trace_start, trace_end)
94 for args in platform.sim_requested:
95 content += _generate_sim_cpp_struct(*args)
96
97 content += """\
98 *out=sim;
99 }
100 """
101 tools.write_to_file("sim_init.cpp", content)
102
103
104 def _generate_sim_variables(include_paths):
105 tapcfg_dir = get_data_mod("misc", "tapcfg").data_location
106 include = ""
107 for path in include_paths:
108 include += "-I"+path+" "
109 content = """\
110 SRC_DIR = {}
111 INC_DIR = {}
112 TAPCFG_DIRECTORY = {}
113 """.format(core_directory, include, tapcfg_dir)
114 tools.write_to_file("variables.mak", content)
115
116
117 def _generate_sim_config(config):
118 content = config.get_json()
119 tools.write_to_file("sim_config.js", content)
120
121
122 def _build_sim(build_name, sources, threads, coverage, opt_level="O3", trace_fst=False):
123 makefile = os.path.join(core_directory, 'Makefile')
124 cc_srcs = []
125 for filename, language, library in sources:
126 cc_srcs.append("--cc " + filename + " ")
127 build_script_contents = """\
128 rm -rf obj_dir/
129 make -C . -f {} {} {} {} {} {}
130 """.format(makefile,
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 "",
136 )
137 build_script_file = "build_" + build_name + ".sh"
138 tools.write_to_file(build_script_file, build_script_contents, force_unix=True)
139
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:
146 error_messages = []
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)))
151 if verbose:
152 print(output)
153
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":
160 import termios
161 termios_settings = termios.tcgetattr(sys.stdin.fileno())
162 try:
163 r = subprocess.call(["bash", run_script_file])
164 if r != 0:
165 raise OSError("Subprocess failed")
166 except:
167 pass
168 if sys.platform != "win32":
169 termios.tcsetattr(sys.stdin.fileno(), termios.TCSAFLUSH, termios_settings)
170
171
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,
177 regular_comb=False):
178
179 # create build directory
180 os.makedirs(build_dir, exist_ok=True)
181 os.chdir(build_dir)
182
183 if build:
184 # finalize design
185 if not isinstance(fragment, _Fragment):
186 fragment = fragment.get_fragment()
187 platform.finalize(fragment)
188
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)
196
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)
201
202 # generate sim config
203 if sim_config:
204 _generate_sim_config(sim_config)
205
206 # build
207 _build_sim(build_name, platform.sources, threads, coverage, opt_level, trace_fst)
208
209 # run
210 if run:
211 _compile_sim(build_name, verbose)
212 run_as_root = False
213 if sim_config.has_module("ethernet"):
214 run_as_root = True
215 if sim_config.has_module("xgmii_ethernet"):
216 run_as_root = True
217 _run_sim(build_name, as_root=run_as_root)
218
219 os.chdir("../../")
220
221 if build:
222 return top_output.ns