systemc-clang 2.0.0
Parsing SystemC constructs
Loading...
Searching...
No Matches
systemc-clang.py
Go to the documentation of this file.
1"""
2systemc-clang driver, a commandline utility for calling systemc-clang end-to-end from c++ to Verilog
3
4Usage:
5 python /path/to/systemc-clang.py SYSTEMC_CLANG_PARAMS --- [options]
6 options include:
7 -o, --output: specify Verilog output folder
8
9Example:
10 python ../llnl/systemc-clang.py ~/working/systemc-clang/examples/llnl-examples/zfpsynth/zfp3/z3test.cpp \
11 --debug -- -I ../systemc/include/ -I ../systemc-clang/examples/llnl-examples/zfpsynth/shared2/ -x c++ -w -c \
12 -std=c++17 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DRVD \
13 --- -o ./z3test_hdl.txt.v
14"""
15import os
16import sys
17import re
18import subprocess
19import logging
20
21from argparse import ArgumentParser
22from hcode2verilog import translate_text
23from pathlib import Path
24
25parser = ArgumentParser()
26parser.add_argument("-o", "--output", help="The output file name")
27parser.add_argument(
28 "-k",
29 "--keep",
30 action="store_true",
31 default=False,
32 help="keeps the intermediate _hdl.txt file, currently this option is not used",
33)
34
35
36class UnconfiguredEnvironment(Exception):
37 """raised when an environment variable is not set"""
38
39 def __init__(self, env):
40 super().__init__("Environmental variable {} not found.".format(env))
41
42
43class MissingSystemCClang(Exception):
44 """raised when the systemc-clang binary is not found"""
45
46
47class InvalidCommandlineFormat(Exception):
48 """raised when the number of --- in the commandline option is greater than or equal to 2"""
49
50
51class SystemCClangFatalError(Exception):
52 """raised when running of systemc-clang triggers a fatal error"""
53
54
55class SystemCClang:
56 """A class that encapsulate the execution of systemc-clang binary"""
57
58 def __check_systemc_clang_executable_exists(self):
59 if not os.path.isfile(self.systemc_clang_binary):
60 raise MissingSystemCClang
61
62 def __init__(
63 self, systemc_clang_build_dir=None, llvm_install_path=None, systemc_path=None
64 ):
65 if systemc_clang_build_dir:
66 self._systemc_clang_build_dir = systemc_clang_build_dir
67 else:
68 self._systemc_clang_build_dir = os.environ["SYSTEMC_CLANG_BUILD_DIR"]
69
70 if llvm_install_path:
71 self._llvm_install_path = llvm_install_path
72 else:
73 self._llvm_install_path = os.environ["LLVM_INSTALL_DIR"]
74
75 if systemc_path:
76 self._systemc_path = systemc_path
77 else:
78 self._systemc_path = os.environ["SYSTEMC"]
79
80 self.__check_systemc_clang_executable_exists()
81
82 @property
83 def systemc_clang_build_dir(self):
84 return self._systemc_clang_build_dir
85
86 @property
87 def systemc_clang_binary(self):
88 executable_path = os.path.join(self.systemc_clang_build_dir, "systemc-clang")
89 return executable_path
90
91 @property
92 def llvm_install_path(self):
93 return self._llvm_install_path
94
95 @property
96 def llvm_inc_dir(self):
97 """
98 returns the include directory necessary for systemc-clang to locate headers.
99 Currently, it only supports version 12.0.0
100 """
101 # TDOO: dynamically determines clang version
102 return os.path.join(self.llvm_install_path, "lib/clang/12.0.0/include")
103
104 @property
105 def systemc_path(self):
106 return self._systemc_path
107
108 @property
109 def systemc_inc_dir(self):
110 return os.path.join(self.systemc_path, "include")
111
112 def execute(self, args, target_name=None):
113 """
114 executes systemc-clang as if it is on the commandline
115 """
116 bin_path = self.systemc_clang_binary
117 args_to_sysc = args
118 cmd = [bin_path, *args_to_sysc]
119 result = subprocess.run(
120 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
121 ) # in case the command fail, an exception will be raised
122 print(' '.join(cmd))
123 err = result.stderr.decode("utf-8")
124 res = list(re.finditer(r"^.*fatal error.*$", err, re.MULTILINE))
125 if result.returncode != 0:
126 raise SystemCClangFatalError('systemc-clang binary exits with non-zero return code: \n{}'.format(err))
127 if res:
128 msg = "\n".join(x.group() for x in res)
129 raise SystemCClangFatalError(
130 """Fatal error captured in systemc-clang stderr, try run systemc-clang separately to identify the error:\n"""
131 """{}""".format(msg)
132 )
133
134 result = SystemCClang.__get_systemc_clang_output_files(args)
135 for t in result:
136 if not Path(t).exists():
137 raise SystemCClangFatalError('Target file: {} is not generated by systemc-clang binary'.format(t))
138 return result
139
140 @staticmethod
141 def __get_systemc_clang_output_files(argv):
142 sources = SystemCClang.__get_sources_from_args(argv)
143 target = SystemCClang.__get_hdl_file_out(argv)
144 if target is None:
145 target = [x.replace(".cpp", "_hdl.txt") for x in sources]
146 else:
147 target = [str(Path(target).absolute()) + '.txt']
148 return target
149
150 @staticmethod
151 def __get_hdl_file_out(argv):
152 if len(argv) == 1:
153 return None
154 for idx, arg in enumerate(argv):
155 if arg == '-hdl-file-out':
156 if idx + 1 >= len(argv):
157 raise ValueError('-hdl-file-out option is specified but no output file is specified')
158 return argv[idx + 1]
159 return None
160
161 @staticmethod
162 def __get_sources_from_args(argv):
163 sources = []
164 if len(argv) == 1:
165 sources.append(argv[0])
166 elif len(argv) > 1:
167 for idx, arg in enumerate(argv):
168 if idx == 0:
169 if arg != '-hdl-file-out':
170 sources.append(arg)
171 elif not arg.startswith('--'):
172 if argv[idx - 1] != '-hdl-file-out':
173 sources.append(arg)
174 else:
175 break
176 return sources
177
178
179def environment_check():
180 check_list = [
181 "LLVM_INSTALL_DIR", # determines the correct location and headers for systemc-clang
182 "SYSTEMC", # determines the correct include directory for SystemC,
183 "SYSTEMC_CLANG_BUILD_DIR", # determines the build directory for systemc-clang binary,
184 "SYSTEMC_CLANG", # determines the python script location
185 ]
186 for env in check_list:
187 if env not in os.environ:
188 raise UnconfiguredEnvironment(env)
189
190
191def get_argv():
192 """
193 returns the source file paths to translate, arguments for systemc-clang and argument for this script
194 returns: sources, argv_sysc, argv_python
195 """
196 argv = sys.argv[1:] # we don't care the script name
197
198 if argv.count("---") == 1:
199 sep_idx = argv.index("---")
200 argv_sysc = argv[:sep_idx]
201 argv_python = argv[sep_idx + 1:]
202 elif argv.count("---") == 0:
203 argv_sysc = argv
204 argv_python = []
205 else:
206 raise InvalidCommandlineFormat
207 return argv_sysc, argv_python
208
209
210def invoke_sysc(argv_sysc):
211 wrapper = SystemCClang()
212 targets = wrapper.execute(argv_sysc)
213 if len(targets) > 1:
214 logging.warning("Up to 1 target is translated currently")
215 target = targets[0]
216 return target
217
218
219def invoke_translation(target, argv_python):
220 args = parser.parse_args(argv_python)
221 with open(target, "r") as fin:
222 res = translate_text(fin.read())
223
224 outfile = args.output
225 if not outfile:
226 outfile = target + ".v"
227 with open(outfile, "w") as fout:
228 fout.writelines(res)
229
230
231def main(argv_sysc, argv_python):
232 target = invoke_sysc(argv_sysc)
233 invoke_translation(target, argv_python)
234
235
236if __name__ == "__main__":
237 environment_check()
238 main(*get_argv())