31 from docopt
import docopt
35 docstr =
"""sra tools -- cloudFPGA Project Build & Management Framework
39 sra config (add-role <path-to-role-dir> <name> | use-role <name> | del-role <name> | show )
40 sra build (proj | monolithic | pr) [--role=<name>] [--incr] [--debug]
42 sra admin (build (pr_full | pr_flash) | full_clean | set-2nd-role <name> | write-to-json)
49 update-shell Checks for a new static DCP of the selected shell and downloads it if necessary.
50 config Changes the project configuration (cFp.json) by adding, deleting and selecting Roles.
51 build Builds a new FPGA design, if not specified otherwise, the last selected/activated Role will be used.
52 clean Deletes temporary build files.
53 admin Provide additional commands for cFDK Shell developers.
54 open-gui Opens the graphical user interface of the design (i.e. Vivado).
57 -h --help Show this screen.
58 -v --version Show version.
60 add-role <path-to-role-dir> <name> Adds a new Role to the project configuration (cFp.json), to be used for builds.
61 The <path-to-role-dir> *must* be within the <cFp-Root>/ROLE/ directory.
62 use-role <name> Sets the specified Role as active. Only one Role can be active at a time, so
63 the previous activated Role will be deactivated. By default, the activated Role
64 will be used for the build process.
65 del-role <name> Deletes a Role from the configuration, it wil *not* delete files.
66 show Show current project configuration.
68 proj Create only the Vivado project files for a monolithic build and exit (useful if
69 one wants to use the Vivado GUI).
70 monolithic Invokes the `monolithic` build flow, using the activated Role.
71 pr Invokes the `pr` (partial reconfiguration) build flow, using the activated
72 Role and the latest downloaded static DCP (downloads a new DCP, if none is
74 --role=<name> Uses the specified Role for the build process, not the current active Role.
75 --incr Enables the incremental build feature for monolithic designs.
76 --debug Adds debug probes during the build process, as specified in TOP/xdc/debug.xdc.
78 --full Makes a full clean, also removing generated HLS cores from the IP library.
80 Copyright IBM Research, licensed under the Apache License 2.0.
81 Contact: {ngl,fab,wei, did, hle}@zurich.ibm.com
84 __cfp_json_name__ =
'cFp.json'
85 __to_be_defined_key__ =
'to-be-defined'
87 __sra_key__ =
'srat-conf'
88 __role_config_dict_templ__ = {
'name':
"",
'path':
""}
89 __default_role_entry__ = {
'name':
'default',
'path':
""}
90 __sra_dict_template__ = {
'version': __version__,
'roles': [__default_role_entry__],
91 'active_role': __to_be_defined_key__}
92 __admin_key__ =
'admin'
93 __admin_dict_template__ = {
'2nd-role': __to_be_defined_key__}
94 __shell_type_key__ =
'cFpSRAtype'
95 __mod_type_key__ =
'cFpMOD'
96 __dcps_folder_name__ =
'/dcps/'
97 __sratool_user_env_key__ =
'cFpSraToolsUserFlowActive'
101 role_path = os.path.abspath(cfp_root +
'/ROLE/' + role_entry[
'path'])
105 def handle_arguments(arguments, cfenv_small_py_bin, cfp_env_folder, cfp_root, cFp_data, dcp_file_path, meta_file_path):
106 if arguments[
'update-shell']:
108 rc = os.system(
"{} {}/get_latest_dcp.py".format(cfenv_small_py_bin, cfp_env_folder))
109 return cFp_data,
False, rc
110 if arguments[
'clean']:
111 if arguments[
'--full']:
112 rc = os.system(
'cd {}; make full_clean'.format(cfp_root))
114 rc = os.system(
'cd {}; make clean'.format(cfp_root))
115 return cFp_data,
False, rc
116 if arguments[
'open-gui']:
117 rc = os.system(
'cd; vivado xpr/top{}.xpr'.format(cfp_root, cFp_data[__mod_type_key__]))
118 return cFp_data,
False, rc
120 if arguments[
'config']:
121 if arguments[
'show']:
122 print(
"[sra:INFO] The following roles are currently defined:")
123 if len(cFp_data[__sra_key__][
'roles']) == 0:
126 for e
in cFp_data[__sra_key__][
'roles']:
127 print(
"\tRole {} in directory {}".format(e[
'name'],
128 os.path.abspath(cfp_root +
'/ROLE/' + e[
'path'])))
129 if cFp_data[__sra_key__][
'active_role'] != __to_be_defined_key__:
130 print(
"\tCurrent active role: {}".format(cFp_data[__sra_key__][
'active_role']))
131 return cFp_data,
False, 0
132 if arguments[
'add-role']:
134 path_parts = arguments[
'<path-to-role-dir>'].
split(
'/')
135 for pp
in path_parts:
143 relative_path += pp +
'/'
144 new_abs_path = os.path.abspath(cfp_root +
'/ROLE/' + relative_path)
145 if not os.path.isdir(new_abs_path):
146 print(
"[ERROR] The specified path {} seems not to be a valid directory.".format(new_abs_path))
147 print(
"\t(Hint: All roles for this project must be in/below the {} directory.)"
148 .format(os.path.abspath(cfp_root +
'/ROLE/')))
149 return cFp_data,
False, -1
150 new_role_dict = {
'name': arguments[
'<name>'],
'path': relative_path}
151 for existing_entry
in cFp_data[__sra_key__][
'roles']:
152 if existing_entry[
'name'] == new_role_dict[
'name']:
153 print(
"[sra:ERROR] A role with the name {} exists already.".format(new_role_dict[
'name']))
154 return cFp_data,
False, -1
155 cFp_data[__sra_key__][
'roles'].append(new_role_dict)
156 return cFp_data,
True, 0
157 if arguments[
'use-role']:
158 new_active_role = arguments[
'<name>']
160 for existing_entry
in cFp_data[__sra_key__][
'roles']:
161 if existing_entry[
'name'] == new_active_role:
165 cFp_data[__sra_key__][
'active_role'] = new_active_role
166 return cFp_data,
True, 0
168 print(
"[sra:ERROR] No role with name {} is defined.".format(new_active_role))
169 return cFp_data,
False, -1
170 if arguments[
'del-role']:
171 del_role = arguments[
'<name>']
173 entry_to_delete =
None
174 for existing_entry
in cFp_data[__sra_key__][
'roles']:
175 if existing_entry[
'name'] == del_role:
177 entry_to_delete = existing_entry
180 idx_to_del = cFp_data[__sra_key__][
'roles'].index(entry_to_delete)
181 del cFp_data[__sra_key__][
'roles'][idx_to_del]
182 return cFp_data,
True, 0
184 print(
"[sra:ERROR] No role with name {} is defined.".format(del_role))
185 return cFp_data,
False, -1
187 if arguments[
'build']
and not arguments[
'admin']:
189 cur_active_role = cFp_data[__sra_key__][
'active_role']
190 if arguments[
'--role']
is not None:
191 cur_active_role = arguments[
'--role']
192 if cur_active_role == __none_key__
or cur_active_role == __to_be_defined_key__:
193 print(
"[sra:ERROR] A role must be set active first, or defined using the --role option.")
194 return cFp_data,
False, -1
196 cur_active_role_dict =
None
197 for existing_entry
in cFp_data[__sra_key__][
'roles']:
198 if existing_entry[
'name'] == cur_active_role:
200 cur_active_role_dict = existing_entry
203 print(
"[sra:ERROR] No role with name {} is defined.".format(cur_active_role))
204 return cFp_data,
False, -1
207 if arguments[
'--debug']:
209 if arguments[
'--incr']:
211 if arguments[
'proj']:
212 print(
"[sra:INFO] Starting to create the project files for a monolithic design with role {}..."
213 .format(cur_active_role))
215 rc = os.system(
'cd {}; export {}=true; export roleName1={}; export usedRoleDir={}; make monolithic_proj'
216 .format(cfp_root, __sratool_user_env_key__, cur_active_role_dict[
'name'],
218 elif arguments[
'monolithic']:
219 info_str =
"[sra:INFO] Starting to to build a monolithic design with role {}" \
220 .format(cur_active_role)
221 make_cmd =
'monolithic'
224 info_str +=
' using the incremental build feature'
227 info_str +=
' and inserting debug probes (as defined in {})' \
228 .format(os.path.abspath(cfp_root +
'/TOP/xdc/debug.xdc'))
232 rc = os.system(
'cd {}; export {}=true; export roleName1={}; export usedRoleDir={}; make {}'
233 .format(cfp_root, __sratool_user_env_key__, cur_active_role_dict[
'name'],
235 elif arguments[
'pr']:
237 print(
"[sra:INFO] Incremental compile with a partial reconfiguration design is not (yet) " +
238 "supported (but anyhow, just the role is build).")
239 info_str =
"[sra:INFO] Starting to to build a partial reconfiguration design for role {}" \
240 .format(cur_active_role)
241 make_cmd =
'pr2_only'
243 print(
"[sra:ERROR] NOT-YET-IMPLEMENTED (pr build with debug probes).")
244 return cFp_data,
False, -1
246 if not os.path.isfile(dcp_file_path)
or not os.path.isfile(meta_file_path):
248 rc = os.system(
"{} {}/get_latest_dcp.py".format(cfenv_small_py_bin, cfp_env_folder))
249 if (
not os.path.isfile(dcp_file_path))
or (rc != 0):
250 print(
"sra:ERROR] No DCP present, can not build pr designs. Stop.")
251 return cFp_data,
False, -1
255 rc = os.system(
'cd {}; export {}=true; export roleName1={}; export usedRoleDir={}; \
256 export roleName2={}; export usedRole2Dir={}; make {}'
257 .format(cfp_root, __sratool_user_env_key__,
259 __to_be_defined_key__, __to_be_defined_key__,
262 return cFp_data,
False, rc
264 if arguments[
'admin']:
265 if arguments[
'full_clean']:
266 rc = os.system(
'cd {}; make full_clean'.format(cfp_root))
267 return cFp_data,
False, rc
268 if arguments[
'set-2nd-role']:
269 cFp_data[__sra_key__][__admin_key__][
'2nd-role'] = arguments[
'<name>']
270 return cFp_data,
True, 0
271 if arguments[
'write-to-json']:
272 print(
"[sra:INFO] Writing current role setting to cFp.json.")
273 cur_active_role_1 = cFp_data[__sra_key__][
'active_role']
274 if cur_active_role_1 == __none_key__
or cur_active_role_1 == __to_be_defined_key__:
275 print(
"[sra:ERROR] A role must be set active first.")
276 return cFp_data,
False, -1
278 cur_active_role_dict_1 =
None
279 for existing_entry
in cFp_data[__sra_key__][
'roles']:
280 if existing_entry[
'name'] == cur_active_role_1:
282 cur_active_role_dict_1 = existing_entry
285 print(
"[sra:ERROR] No role with name {} is defined.".format(cur_active_role_1))
286 return cFp_data,
False, -1
287 write_2nd_role =
True
288 cur_active_role_2 = cFp_data[__sra_key__][__admin_key__][
'2nd-role']
289 cur_active_role_dict_2 =
None
290 if cur_active_role_2 == __none_key__
or cur_active_role_2 == __to_be_defined_key__:
291 write_2nd_role =
False
293 for existing_entry
in cFp_data[__sra_key__][
'roles']:
294 if existing_entry[
'name'] == cur_active_role_2:
296 cur_active_role_dict_2 = existing_entry
299 write_2nd_role =
False
301 cFp_data[
'roleName1'] = cur_active_role_dict_1[
'name']
302 cFp_data[
'usedRoleDir'] = cur_active_role_dict_1[
'path']
304 cFp_data[
'roleName2'] = cur_active_role_dict_2[
'name']
305 cFp_data[
'usedRoleDir2'] = cur_active_role_dict_2[
'path']
306 return cFp_data,
True, 0
307 elif arguments[
'build']:
308 cur_active_role = cFp_data[__sra_key__][
'active_role']
311 if cur_active_role == __none_key__
or cur_active_role == __to_be_defined_key__:
313 print(
"[sra:ERROR] A role must be set active first.")
314 return cFp_data,
False, -1
316 cur_active_role_dict =
None
317 for existing_entry
in cFp_data[__sra_key__][
'roles']:
318 if existing_entry[
'name'] == cur_active_role:
320 cur_active_role_dict = existing_entry
323 print(
"[sra:ERROR] No role with name {} is defined.".format(cur_active_role))
324 return cFp_data,
False, -1
325 if arguments[
'pr_flash']:
327 info_str =
"[sra:INFO] Starting to build all files for a new platform logic, using role {}" \
328 .format(cur_active_role)
329 make_cmd =
'pr_flash'
334 rc = os.system(
'cd {}; export roleName1={}; export usedRoleDir={}; \
335 export roleName2={}; export usedRole2Dir={}; make {}'
338 __to_be_defined_key__, __to_be_defined_key__,
342 return cFp_data,
False, rc
343 elif arguments[
'pr_full']:
345 cur_active_role_2 = cFp_data[__sra_key__][__admin_key__][
'2nd-role']
346 if cur_active_role_2 == __none_key__
or cur_active_role_2 == __to_be_defined_key__:
347 print(
"[sra:ERROR] A 2nd role must be set active first.")
348 return cFp_data,
False, -1
350 cur_active_role_dict_2 =
None
351 for existing_entry
in cFp_data[__sra_key__][
'roles']:
352 if existing_entry[
'name'] == cur_active_role_2:
354 cur_active_role_dict_2 = existing_entry
357 print(
"[sra:ERROR] No role with name {} is defined.".format(cur_active_role_2))
358 return cFp_data,
False, -1
359 info_str =
"[sra:INFO] Starting to build a *complete* partial reconfiguration design, " + \
360 "using roles {} and {}" \
361 .format(cur_active_role, cur_active_role_2)
367 rc = os.system(
'cd {}; export roleName1={}; export usedRoleDir={}; \
368 export roleName2={}; export usedRole2Dir={}; make {}'
371 cur_active_role_dict_2[
'name'],
374 return cFp_data,
False, rc
375 return cFp_data,
False, 0
379 arguments = docopt(docstr, version=__version__)
382 cfp_root = os.environ[
'cFpRootDir']
383 cfp_env_folder = os.path.abspath(cfp_root +
'/env/')
384 cfenv_small_py_bin = os.path.abspath(cfp_root +
'env/cfenv-small/bin/python3')
385 cfp_json_file = os.path.abspath(cfp_root +
'/' + __cfp_json_name__)
386 with open(cfp_json_file,
'r')
as json_file:
387 cFp_data = json.load(json_file)
389 store_updated_cfp_json =
False
391 if __sra_key__
not in cFp_data:
392 cFp_data[__sra_key__] = __sra_dict_template__
393 store_updated_cfp_json =
True
395 if arguments[
'admin']:
396 if __admin_key__
not in cFp_data[__sra_key__]:
397 cFp_data[__sra_key__][__admin_key__] = __admin_dict_template__
398 store_updated_cfp_json =
True
401 if cFp_data[
'roleName1'] == __to_be_defined_key__:
402 store_updated_cfp_json =
True
403 cFp_data[
'roleName1'] =
'default'
404 cFp_data[
'usedRoleDir'] =
''
406 dcps_folder = os.path.abspath(cfp_root + __dcps_folder_name__)
407 dcp_file_name =
"3_top{}_STATIC.dcp".format(cFp_data[__mod_type_key__])
408 dcp_file_path = os.path.abspath(dcps_folder +
"/" + dcp_file_name)
409 meta_file_name =
"3_top{}_STATIC.json".format(cFp_data[__mod_type_key__])
410 meta_file_path = os.path.abspath(dcps_folder +
"/" + meta_file_name)
413 cFp_data_new, data_updated, rc =
handle_arguments(arguments, cfenv_small_py_bin, cfp_env_folder, cfp_root,
414 cFp_data, dcp_file_path, meta_file_path)
417 if store_updated_cfp_json
or data_updated:
420 cFp_data_new[__sra_key__][
'version'] = __version__
421 with open(cfp_json_file,
'w')
as json_file:
423 json.dump(cFp_data_new, json_file, indent=4)
425 if 'SraToolShowHint' in os.environ:
426 if os.environ[
'SraToolShowHint'] ==
"True" and not 'SraToolHintWasShown' in os.environ:
427 srat_fyi =
"\npsst...just FYI: If you want to use the new 'sra' command without typing always " \
428 "'./' first, \nyou can add the following to your '~/.bashrc' and activate it with 'source " \
431 srat_bashrc =
'--------------\n' \
432 'srafunc(){\n\tcur_pwd=$(pwd)\n\tsrat=$cur_pwd/sra\n\tif [ -f "$srat" ]; then\n\t\t$srat ' \
434 '\n\t\techo "Error: No cloudFPGA sra tools present in this folder."\n\tfi\n}\n\nalias ' \
437 print(srat_fyi + srat_bashrc)
438 os.system(
'cd {}/env; echo "export SraToolHintWasShown=1" >> this_machine_env.sh'
443 if __name__ ==
'__main__':
445 if not (hasattr(sys,
'real_prefix')
or (hasattr(sys,
'base_prefix')
and sys.base_prefix != sys.prefix)):
447 print(
"[sra:ERROR] It looks like this sra isn't running in a virtual environment. STOP.")
451 if mrc != -1
and mrc != 1:
452 print(
"[sra:DEBUG] Internal error code returned: {}\n".format(mrc))