nsdk_utils.py 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212
  1. #!/usr/bin/env python3
  2. import os
  3. import sys
  4. SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
  5. requirement_file = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "requirements.txt"))
  6. try:
  7. import time
  8. import datetime
  9. import random
  10. import shutil
  11. import signal
  12. import psutil
  13. import re
  14. import copy
  15. import serial
  16. import serial.tools.list_ports
  17. import tempfile
  18. import collections
  19. from threading import Thread
  20. import subprocess
  21. import asyncio
  22. import glob
  23. import json
  24. import yaml
  25. import importlib.util
  26. import fcntl
  27. import stat
  28. except Exception as exc:
  29. print("Import Error: %s" % (exc))
  30. print("Please install requried packages using: pip3 install -r %s" % (requirement_file))
  31. sys.exit(1)
  32. try:
  33. from collections.abc import Mapping
  34. except ImportError: # Python 2.7 compatibility
  35. from collections import Mapping
  36. SDK_GLOBAL_VARIABLES = {
  37. "sdk_checktag": "Nuclei SDK Build Time:",
  38. "sdk_check": True,
  39. "sdk_banner_tmout": 15,
  40. "sdk_copy_objects": "elf,map",
  41. "sdk_copy_objects_flag": False,
  42. "sdk_ttyerr_maxcnt": 3,
  43. "sdk_fpgaprog_maxcnt": 3,
  44. "sdk_gdberr_maxcnt": 10,
  45. "sdk_uploaderr_maxcnt": 10,
  46. "sdk_bannertmout_maxcnt": 100,
  47. "sdk_verb_buildmsg": True,
  48. "sdk_copy_failobj": True
  49. }
  50. INVAILD_SERNO = "xxxxx"
  51. BANNER_TMOUT = "banner_timeout"
  52. TTY_OP_ERR = "tty_operate_error"
  53. TTY_UNKNOWN_ERR = "tty_unknown_error"
  54. FILE_LOCK_NAME = "fpga_program.lock"
  55. DATE_FORMATE = "%Y-%m-%d %H:%M:%S"
  56. def get_tmpdir():
  57. tempdir = tempfile.gettempdir()
  58. if sys.platform == "win32":
  59. wintempdir = "C:\\Users\\Public\\Temp"
  60. if os.path.isdir(wintempdir) == False:
  61. os.makedirs(wintempdir)
  62. tempdir = wintempdir
  63. return tempdir
  64. # get ci url information
  65. def get_ci_info():
  66. cijoburl = os.environ.get("CI_JOB_URL")
  67. cipipelineurl = os.environ.get("CI_PIPELINE_URL")
  68. if cijoburl and cipipelineurl:
  69. return {"joburl": cijoburl, "pipelineurl": cipipelineurl}
  70. else:
  71. return {}
  72. def get_global_variables():
  73. return SDK_GLOBAL_VARIABLES
  74. def get_sdk_checktag():
  75. checktag = os.environ.get("SDK_CHECKTAG")
  76. if checktag is None:
  77. checktag = SDK_GLOBAL_VARIABLES.get("sdk_checktag")
  78. return checktag
  79. def get_sdk_copyobjects():
  80. cpobjs = os.environ.get("SDK_COPY_OBJECTS")
  81. if cpobjs is None:
  82. cpobjs = SDK_GLOBAL_VARIABLES.get("sdk_copy_objects")
  83. return cpobjs
  84. def get_env_flag(envar, deft=None):
  85. flag = os.environ.get(envar)
  86. if flag is None:
  87. return deft
  88. return flag.lower() in ('true', '1', 't')
  89. def get_sdk_check():
  90. check = get_env_flag("SDK_CHECK")
  91. if check is None:
  92. check = SDK_GLOBAL_VARIABLES.get("sdk_check")
  93. return check
  94. def get_sdk_verb_buildmsg():
  95. check = get_env_flag("SDK_VERB_BUILDMSG")
  96. if check is None:
  97. check = SDK_GLOBAL_VARIABLES.get("sdk_verb_buildmsg")
  98. return check
  99. def get_sdk_copyobjects_flag():
  100. cpflag = get_env_flag("SDK_COPY_OBJECTS_FLAG")
  101. if cpflag is None:
  102. cpflag = SDK_GLOBAL_VARIABLES.get("sdk_copy_objects_flag")
  103. return cpflag
  104. def get_sdk_need_copyobjects(appconfig):
  105. try:
  106. needed = appconfig.get("copy_objects")
  107. except:
  108. needed = False
  109. if needed != True:
  110. # use global flag
  111. needed = get_sdk_copyobjects_flag()
  112. return needed
  113. def get_sdk_copy_failobj():
  114. cpflag = get_env_flag("SDK_COPY_FAILOBJ")
  115. if cpflag is None:
  116. cpflag = SDK_GLOBAL_VARIABLES.get("sdk_copy_failobj")
  117. return cpflag
  118. def get_sdk_banner_tmout():
  119. tmout = os.environ.get("SDK_BANNER_TMOUT")
  120. if tmout is not None:
  121. tmout = int(tmout)
  122. else:
  123. tmout = SDK_GLOBAL_VARIABLES.get("sdk_banner_tmout")
  124. return tmout
  125. def get_sdk_fpga_prog_tmout():
  126. tmout = os.environ.get("FPGA_PROG_TMOUT")
  127. return tmout
  128. def get_sdk_ttyerr_maxcnt():
  129. num = os.environ.get("SDK_TTYERR_MAXCNT")
  130. if num is not None:
  131. num = int(num)
  132. else:
  133. num = SDK_GLOBAL_VARIABLES.get("sdk_ttyerr_maxcnt")
  134. return num
  135. def get_sdk_fpgaprog_maxcnt():
  136. num = os.environ.get("SDK_FPGAPROG_MAXCNT")
  137. if num is not None:
  138. num = int(num)
  139. else:
  140. num = SDK_GLOBAL_VARIABLES.get("sdk_fpgaprog_maxcnt")
  141. return num
  142. def get_sdk_gdberr_maxcnt():
  143. num = os.environ.get("SDK_GDBERR_MAXCNT")
  144. if num is not None:
  145. num = int(num)
  146. else:
  147. num = SDK_GLOBAL_VARIABLES.get("sdk_gdberr_maxcnt")
  148. return num
  149. def get_sdk_bannertmout_maxcnt():
  150. num = os.environ.get("SDK_BANNERTMOUT_MAXCNT")
  151. if num is not None:
  152. num = int(num)
  153. else:
  154. num = SDK_GLOBAL_VARIABLES.get("sdk_bannertmout_maxcnt")
  155. return num
  156. def get_sdk_uploaderr_maxcnt():
  157. num = os.environ.get("SDK_UPLOADERR_MAXCNT")
  158. if num is not None:
  159. num = int(num)
  160. else:
  161. num = SDK_GLOBAL_VARIABLES.get("sdk_uploaderr_maxcnt")
  162. return num
  163. class NThread(Thread):
  164. def __init__(self, func, args):
  165. super(NThread, self).__init__()
  166. self.func = func
  167. self.args = args
  168. def run(self):
  169. self.result = self.func(*self.args)
  170. def get_result(self):
  171. try:
  172. return self.result
  173. except Exception:
  174. return None
  175. YAML_OK=0
  176. YAML_NOFILE=1
  177. YAML_INVAILD=2
  178. def load_yaml(file):
  179. if isinstance(file, str) == False or os.path.isfile(file) == False:
  180. return YAML_NOFILE, None
  181. try:
  182. data = yaml.load(open(file, 'r'), Loader=yaml.FullLoader)
  183. return YAML_OK, data
  184. except:
  185. print("Error: %s is an invalid yaml file!" % (file))
  186. return YAML_INVAILD, None
  187. def save_yaml(file, data):
  188. if isinstance(file, str) == False:
  189. return False
  190. try:
  191. with open(file, "w") as cf:
  192. yaml.dump(data, cf, indent=4)
  193. return True
  194. except:
  195. print("Error: Data can't be serialized to yaml file!")
  196. return False
  197. def get_specific_key_value(dictdata:dict, key):
  198. if not dictdata:
  199. print("Error: dictdata doesn't exist!")
  200. return None
  201. value = dictdata.get(key, None)
  202. if not value:
  203. print("Error, key %s has no value!" % (key))
  204. return None
  205. return value
  206. JSON_OK=0
  207. JSON_NOFILE=1
  208. JSON_INVAILD=2
  209. def load_json(file):
  210. if isinstance(file, str) == False or os.path.isfile(file) == False:
  211. return JSON_NOFILE, None
  212. try:
  213. data = json.load(open(file, 'r'))
  214. return JSON_OK, data
  215. except:
  216. print("Error: %s is an invalid json file!" % (file))
  217. return JSON_INVAILD, None
  218. def save_json(file, data):
  219. if isinstance(file, str) == False:
  220. return False
  221. try:
  222. with open(file, "w") as cf:
  223. json.dump(data, cf, indent=4)
  224. return True
  225. except:
  226. print("Error: Data can't be serialized to json file!")
  227. return False
  228. def save_csv(file, csvlines, display=True):
  229. if isinstance(csvlines, list) == False:
  230. return False
  231. # Flush stdout buffer
  232. sys.stdout.flush()
  233. try:
  234. with open(file, "w") as cf:
  235. for line in csvlines:
  236. csvline = line + "\n"
  237. cf.write(csvline)
  238. cf.flush()
  239. if display:
  240. try:
  241. # sometimes facing issue BlockingIOError: [Errno 11] write could not complete without blocking here
  242. # maybe related to https://bugs.python.org/issue40634 since we are using async in this tool
  243. sys.stdout.flush()
  244. print("CSV, %s" % line)
  245. except:
  246. pass
  247. return True
  248. except:
  249. print("Error: Data can't be saved to file!")
  250. return False
  251. # Return possible serports, return a list of possible serports
  252. def find_possible_serports():
  253. comports = serial.tools.list_ports.comports()
  254. serports = [ port.device for port in comports ]
  255. return serports
  256. def find_serport_by_no(serno):
  257. comports = serial.tools.list_ports.comports()
  258. serport = None
  259. for port in comports:
  260. cur_serno = port.serial_number
  261. cur_dev = port.device
  262. cur_loc = port.location
  263. if cur_serno is None:
  264. continue
  265. if sys.platform == "win32":
  266. if (serno + 'B') == cur_serno:
  267. serport = cur_dev
  268. break
  269. else:
  270. if serno != cur_serno:
  271. continue
  272. # serial is the second device of the composite device
  273. if cur_loc.endswith(".1"):
  274. serport = cur_dev
  275. break
  276. # serport founded
  277. return serport
  278. def find_most_possible_serport():
  279. serports = find_possible_serports()
  280. if len(serports) > 0:
  281. # sort the ports
  282. serports.sort()
  283. # get the biggest port
  284. # for /dev/ttyUSB0, /dev/ttyUSB1, get /dev/ttyUSB1
  285. # for COM16, COM17, get COM17
  286. return serports[-1]
  287. else:
  288. return None
  289. # get from https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
  290. def dict_merge(dct, merge_dct):
  291. """ Recursive dict merge. Inspired by :meth:``dict.update()``, instead of
  292. updating only top-level keys, dict_merge recurses down into dicts nested
  293. to an arbitrary depth, updating keys. The ``merge_dct`` is merged into
  294. ``dct``.
  295. :param dct: dict onto which the merge is executed
  296. :param merge_dct: dct merged into dct
  297. :return: None
  298. """
  299. for k, v in merge_dct.items():
  300. if (k in dct and isinstance(dct[k], dict)
  301. and isinstance(merge_dct[k], Mapping)):
  302. dict_merge(dct[k], merge_dct[k])
  303. else:
  304. dct[k] = merge_dct[k]
  305. def get_make_csv(app, config):
  306. make_options = " "
  307. SUPPORT_KEYS = ["SOC", "BOARD", "CORE", "DOWNLOAD", "VARIANT", \
  308. "BENCH_UNIT", "BENCH_FLAGS", "ARCH_EXT", "STDCLIB", "SILENT", "V"]
  309. csv_print = "CSV, APP=%s" % (app)
  310. if isinstance(config, dict):
  311. for key in config:
  312. if key not in SUPPORT_KEYS:
  313. continue
  314. option = "%s=%s"%(key, config[key])
  315. make_options = " %s %s " % (make_options, option)
  316. csv_print = "%s, %s" % (csv_print, option)
  317. return make_options, csv_print
  318. def try_decode_bytes(bytes):
  319. ENCODING_LIST = ['utf-8', 'gbk', 'gb18030']
  320. destr = ""
  321. for encoding in ENCODING_LIST:
  322. try:
  323. destr = bytes.decode(encoding)
  324. break
  325. except:
  326. continue
  327. return destr
  328. def kill_async_subprocess(proc):
  329. startticks = time.time()
  330. if proc is not None:
  331. try:
  332. kill_sig = signal.SIGTERM
  333. if sys.platform != "win32":
  334. kill_sig = signal.SIGKILL
  335. print("Try to Kill process id %d now" %(proc.pid))
  336. parent_proc = psutil.Process(proc.pid)
  337. try:
  338. # This might cause PermissionError: [Errno 1] Operation not permitted: '/proc/1/stat' issue
  339. child_procs = parent_proc.children(recursive=True)
  340. for child_proc in child_procs:
  341. print("Kill child process %s, pid %d" %(child_proc.name(), child_proc.pid))
  342. try:
  343. os.kill(child_proc.pid, kill_sig) # kill child process
  344. except:
  345. continue
  346. except Exception as exc:
  347. print("Warning: kill child process failed with %s" %(exc))
  348. if parent_proc.is_running():
  349. print("Kill parent process %s, pid %d" %(parent_proc.name(), parent_proc.pid))
  350. if sys.platform != "win32":
  351. try:
  352. os.killpg(parent_proc.pid, kill_sig) # kill parent process
  353. except:
  354. os.kill(parent_proc.pid, kill_sig) # kill parent process
  355. else:
  356. os.kill(parent_proc.pid, kill_sig) # kill parent process
  357. # kill using process.kill again
  358. if parent_proc.is_running():
  359. proc.kill()
  360. except psutil.NoSuchProcess:
  361. pass
  362. except Exception as exc:
  363. print("Warning: kill process failed with %s" %(exc))
  364. # show time cost for kill process
  365. print("kill process used %.2f seconds" %((time.time() - startticks)))
  366. sys.stdout.flush()
  367. pass
  368. def kill_subprocess(proc):
  369. try:
  370. if proc.poll() is None: # process is still running
  371. kill_async_subprocess(proc)
  372. except:
  373. pass
  374. pass
  375. def import_module(module_name, file_path):
  376. if file_path is None or os.path.isfile(file_path) == False:
  377. return None
  378. try:
  379. spec = importlib.util.spec_from_file_location(module_name, file_path)
  380. module = importlib.util.module_from_spec(spec)
  381. spec.loader.exec_module(module)
  382. except:
  383. module = None
  384. return module
  385. def import_function(func_name, file_path):
  386. module_name = "tempmodule_%s" % (random.randint(0, 10000))
  387. tmpmodule = import_module(module_name, file_path)
  388. if tmpmodule is None:
  389. return None
  390. if func_name not in dir(tmpmodule):
  391. return None
  392. return getattr(tmpmodule, func_name)
  393. COMMAND_RUNOK=0
  394. COMMAND_INVALID=1
  395. COMMAND_FAIL=2
  396. COMMAND_INTERRUPTED=3
  397. COMMAND_EXCEPTION=4
  398. COMMAND_NOTAPP=5
  399. COMMAND_TIMEOUT=6
  400. COMMAND_TIMEOUT_READ=7
  401. RUNSTATUS_OK=0
  402. RUNSTATUS_FAIL=1
  403. RUNSTATUS_NOTSTART=2
  404. def run_command(command, show_output=True, logfile=None, append=False):
  405. logfh = None
  406. ret = COMMAND_RUNOK
  407. cmd_elapsed_ticks = 0
  408. if isinstance(command, str) == False:
  409. return COMMAND_INVALID, cmd_elapsed_ticks
  410. startticks = time.time()
  411. process = None
  412. try:
  413. if isinstance(logfile, str):
  414. if append:
  415. logfh = open(logfile, "ab")
  416. else:
  417. logfh = open(logfile, "wb")
  418. if logfh:
  419. # record command run in log file
  420. logfh.write(("Execute Command %s\n" % (command)).encode())
  421. process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, \
  422. stderr=subprocess.STDOUT)
  423. while True:
  424. line = process.stdout.readline()
  425. if (not line) and process.poll() is not None:
  426. break
  427. if show_output:
  428. print(try_decode_bytes(line), end="")
  429. if logfh:
  430. logfh.write(line)
  431. time.sleep(0.01)
  432. process.communicate(30)
  433. if process.returncode != 0:
  434. ret = COMMAND_FAIL
  435. except (KeyboardInterrupt):
  436. print("Key CTRL-C pressed, command executing stopped!")
  437. ret = COMMAND_INTERRUPTED
  438. except subprocess.TimeoutExpired:
  439. ret = COMMAND_TIMEOUT
  440. except Exception as exc:
  441. print("Unexpected exception happened: %s" %(str(exc)))
  442. ret = COMMAND_EXCEPTION
  443. finally:
  444. kill_subprocess(process)
  445. if process:
  446. del process
  447. if logfh:
  448. logfh.close()
  449. cmd_elapsed_ticks = time.time() - startticks
  450. return ret, cmd_elapsed_ticks
  451. async def run_cmd_and_check_async(command, timeout:int, checks:dict, checktime=time.time(), sdk_check=False, logfile=None, show_output=False, banner_timeout=3):
  452. logfh = None
  453. ret = COMMAND_FAIL
  454. cmd_elapsed_ticks = 0
  455. if isinstance(command, str) == False:
  456. return COMMAND_INVALID, cmd_elapsed_ticks
  457. startticks = time.time()
  458. process = None
  459. check_status = False
  460. pass_checks = checks.get("PASS", [])
  461. fail_checks = checks.get("FAIL", [])
  462. def test_in_check(string, checks):
  463. if type(checks) == list:
  464. for check in checks:
  465. if check in string:
  466. return True
  467. return False
  468. NSDK_CHECK_TAG = get_sdk_checktag()
  469. if get_sdk_verb_buildmsg():
  470. print("Checker used: ", checks)
  471. print("SDK Checker Tag \"%s\", checker enable %s" % (NSDK_CHECK_TAG, sdk_check))
  472. print("SDK run timeout %s, banner timeout %s" % (timeout, banner_timeout))
  473. check_finished = False
  474. start_time = time.time()
  475. serial_log = ""
  476. nsdk_check_timeout = banner_timeout
  477. sdk_checkstarttime = time.time()
  478. try:
  479. if isinstance(logfile, str):
  480. logfh = open(logfile, "wb")
  481. if sys.platform != "win32":
  482. # add exec to running command to avoid create a process called /bin/sh -c
  483. # and if you kill that process it will kill this sh process not the really
  484. # command process you want to kill
  485. process = await asyncio.create_subprocess_shell("exec " + command, \
  486. stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT)
  487. else:
  488. process = await asyncio.create_subprocess_shell(command, \
  489. stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT)
  490. while (time.time() - start_time) < timeout:
  491. try:
  492. linebytes = await asyncio.wait_for(process.stdout.readline(), 1)
  493. except asyncio.TimeoutError:
  494. if sdk_check == True:
  495. linebytes = None
  496. else:
  497. continue
  498. except KeyboardInterrupt:
  499. print("Key CTRL-C pressed, command executing stopped!")
  500. break
  501. except:
  502. break
  503. if linebytes:
  504. line = str(try_decode_bytes(linebytes)).replace('\r', '')
  505. else:
  506. line = ""
  507. if sdk_check == True:
  508. if (time.time() - sdk_checkstarttime) > nsdk_check_timeout:
  509. print("No SDK banner found in %s s, quit now!" % (nsdk_check_timeout))
  510. ret = COMMAND_TIMEOUT
  511. check_status = False
  512. break
  513. if line == "":
  514. continue
  515. if show_output:
  516. print("XXX Check " + line, end='')
  517. if NSDK_CHECK_TAG in line:
  518. timestr = line.split(NSDK_CHECK_TAG)[-1].strip()
  519. cur_time = time.mktime(time.strptime(timestr, "%b %d %Y, %H:%M:%S"))
  520. if int(cur_time) >= int(checktime):
  521. sdk_check = False
  522. line = NSDK_CHECK_TAG + " " + timestr + "\n"
  523. serial_log = serial_log + str(line)
  524. else:
  525. serial_log = serial_log + str(line)
  526. if show_output:
  527. print(line, end='')
  528. if check_finished == False:
  529. if test_in_check(line, fail_checks):
  530. check_status = False
  531. check_finished = True
  532. if test_in_check(line, pass_checks):
  533. check_status = True
  534. check_finished = True
  535. if check_finished:
  536. ret = COMMAND_RUNOK
  537. # record another 2 seconds by reset start_time and timeout to 2
  538. start_time = time.time()
  539. timeout = 1
  540. if logfh and linebytes:
  541. logfh.write(linebytes)
  542. time.sleep(0.01)
  543. except (KeyboardInterrupt):
  544. print("Key CTRL-C pressed, command executing stopped!")
  545. ret = COMMAND_INTERRUPTED
  546. except Exception as exc:
  547. print("Unexpected exception happened: %s" %(str(exc)))
  548. ret = COMMAND_EXCEPTION
  549. finally:
  550. # kill this process
  551. kill_async_subprocess(process)
  552. if logfh:
  553. logfh.close()
  554. cmd_elapsed_ticks = time.time() - startticks
  555. return check_status, cmd_elapsed_ticks
  556. def run_cmd_and_check(command, timeout:int, checks:dict, checktime=time.time(), sdk_check=False, logfile=None, show_output=False, banner_timeout=30):
  557. loop = asyncio.get_event_loop()
  558. try:
  559. ret, cmd_elapsed_ticks = loop.run_until_complete( \
  560. run_cmd_and_check_async(command, timeout, checks, checktime, sdk_check, logfile, show_output, banner_timeout))
  561. except KeyboardInterrupt:
  562. print("Key CTRL-C pressed, command executing stopped!")
  563. ret, cmd_elapsed_ticks = False, 0
  564. finally:
  565. if sys.platform != "win32":
  566. os.system("stty echo 2> /dev/null")
  567. return ret, cmd_elapsed_ticks
  568. def find_files(fndir, pattern, recursive=False):
  569. fndir = os.path.normpath(fndir)
  570. files = glob.glob(os.path.join(fndir, pattern), recursive=recursive)
  571. return files
  572. def get_logfile(appdir, startdir, logdir, logname):
  573. relpath = os.path.relpath(appdir, startdir)
  574. _, startdir_basename = os.path.splitdrive(startdir)
  575. applogdir = os.path.join(os.path.relpath(logdir + os.sep + startdir_basename), relpath)
  576. applog = os.path.relpath(os.path.join(applogdir, logname))
  577. applogdir = os.path.dirname(applog)
  578. if os.path.isdir(applogdir) == False:
  579. os.makedirs(applogdir)
  580. return applog
  581. def strtofloat(value):
  582. fval = 0.0
  583. try:
  584. match = re.search(r'[+-]?\d*\.?\d+([Ee][+-]?\d+)?', value.strip())
  585. if match:
  586. fval = float(match.group())
  587. except:
  588. pass
  589. return fval
  590. def check_tool_version(ver_cmd, ver_check):
  591. vercmd_log = tempfile.mktemp()
  592. ret, _ = run_command(ver_cmd, show_output=False, logfile=vercmd_log)
  593. check_sts = False
  594. verstr = None
  595. if ret == COMMAND_RUNOK:
  596. with open(vercmd_log, 'r', errors='ignore') as vlf:
  597. for line in vlf.readlines():
  598. if ver_check in line:
  599. verstr = line.strip()
  600. check_sts = True
  601. break
  602. os.remove(vercmd_log)
  603. return check_sts, verstr
  604. def get_elfsize(elf):
  605. sizeinfo = {"text": -1, "data": -1, "bss": -1, "total": -1}
  606. if os.path.isfile(elf) == False:
  607. return sizeinfo
  608. for sizetool in [ "riscv-nuclei-elf-size", "riscv64-unknown-elf-size", "size" ]:
  609. sizecmd = "%s %s" % (sizetool, elf)
  610. sizelog = tempfile.mktemp()
  611. ret, _ = run_command(sizecmd, show_output=False, logfile=sizelog)
  612. if ret == COMMAND_RUNOK:
  613. with open(sizelog, "r", errors='ignore') as sf:
  614. lines = sf.readlines()
  615. datas = lines[-1].strip().split()
  616. sizeinfo["text"] = int(datas[0])
  617. sizeinfo["data"] = int(datas[1])
  618. sizeinfo["bss"] = int(datas[2])
  619. sizeinfo["total"] = int(datas[3])
  620. os.remove(sizelog)
  621. break
  622. else:
  623. os.remove(sizelog)
  624. return sizeinfo
  625. def merge_config_with_makeopts(config, make_options):
  626. opt_splits=make_options.strip().split()
  627. passed_buildcfg = dict()
  628. for opt in opt_splits:
  629. if "=" in opt:
  630. values = opt.split("=")
  631. # Make new build config
  632. if (len(values) == 2):
  633. passed_buildcfg[values[0]] = values[1]
  634. build_cfg = config.get("build_config", None)
  635. if build_cfg is None:
  636. config["build_config"] = passed_buildcfg
  637. else:
  638. # update build_config using parsed config via values specified in make_options
  639. config["build_config"].update(passed_buildcfg)
  640. return config
  641. # merge config dict and args dict
  642. # args will overwrite config
  643. def merge_config_with_args(config, args_dict):
  644. if isinstance(config, dict) == False:
  645. return None
  646. if isinstance(args_dict, dict) == False:
  647. return config
  648. serport = args_dict.get("serport", None)
  649. baudrate = args_dict.get("baudrate", None)
  650. make_options = args_dict.get("make_options", None)
  651. parallel = args_dict.get("parallel", None)
  652. build_target = args_dict.get("build_target", None)
  653. run_target = args_dict.get("run_target", None)
  654. timeout = args_dict.get("timeout", None)
  655. ncycm = args_dict.get("ncycm", None)
  656. if isinstance(config, dict) == False:
  657. return None
  658. new_config = copy.deepcopy(config)
  659. if serport or baudrate or run_target:
  660. run_cfg = new_config.get("run_config", None)
  661. if run_cfg is None:
  662. new_config["run_config"] = {"hardware":{}}
  663. elif "hardware" not in run_cfg:
  664. new_config["run_config"]["hardware"] = {}
  665. if serport:
  666. new_config["run_config"]["hardware"]["serport"] = str(serport)
  667. if baudrate:
  668. new_config["run_config"]["hardware"]["serport"] = int(baudrate)
  669. if run_target:
  670. new_config["run_config"]["target"] = str(run_target)
  671. run_target = new_config["run_config"].get("target", "hardware")
  672. if run_target not in new_config["run_config"]:
  673. new_config["run_config"][run_target] = dict()
  674. if ncycm:
  675. if "ncycm" not in new_config["run_config"]:
  676. new_config["run_config"]["ncycm"] = dict()
  677. new_config["run_config"]["ncycm"]["ncycm"] = os.path.abspath(ncycm)
  678. if timeout: # set timeout
  679. try:
  680. timeout = int(timeout)
  681. except:
  682. timeout = 60
  683. new_config["run_config"][run_target]["timeout"] = timeout
  684. if build_target is not None:
  685. new_config["build_target"] = build_target
  686. if parallel is not None:
  687. new_config["parallel"] = parallel
  688. if make_options:
  689. new_config = merge_config_with_makeopts(new_config, make_options)
  690. return new_config
  691. # merge two config, now is appcfg, another is hwcfg
  692. # hwcfg will overwrite configuration in appcfg
  693. def merge_two_config(appcfg, hwcfg):
  694. if isinstance(appcfg, dict) == True and isinstance(hwcfg, dict) == False:
  695. return appcfg
  696. if isinstance(appcfg, dict) == False and isinstance(hwcfg, dict) == True:
  697. return hwcfg
  698. merged_appcfg = copy.deepcopy(appcfg)
  699. dict_merge(merged_appcfg, hwcfg)
  700. return merged_appcfg
  701. def set_global_variables(config):
  702. global SDK_GLOBAL_VARIABLES
  703. if isinstance(config, dict) == False:
  704. return False
  705. if "global_variables" in config:
  706. dict_merge(SDK_GLOBAL_VARIABLES, config["global_variables"])
  707. print("Using global variables: %s" % SDK_GLOBAL_VARIABLES)
  708. return True
  709. def get_app_runresult(apprst):
  710. if not isinstance(apprst, dict):
  711. return "unknown", "-"
  712. if "type" not in apprst:
  713. return "unknown", "-"
  714. rsttype = apprst["type"]
  715. rstvaluedict = apprst.get("value", dict())
  716. if rstvaluedict and len(rstvaluedict) < 3:
  717. rstval = ""
  718. for key in rstvaluedict:
  719. rstval += "%s : %s;" %(key, rstvaluedict[key])
  720. rstval = rstval.rstrip(';')
  721. else:
  722. rstval = "-"
  723. return rsttype, rstval
  724. def save_execute_csv(result, csvfile):
  725. if isinstance(result, dict) == False:
  726. return False
  727. csvlines = ["App, buildstatus, runstatus, buildtime, runtime, type, value, total, text, data, bss"]
  728. for app in result:
  729. size = result[app]["size"]
  730. app_status = result[app]["status"]
  731. app_time = result[app]["time"]
  732. apprsttype, apprstval = get_app_runresult(result[app].get("result", dict()))
  733. csvline ="%s, %s, %s, %s, %s, %s, %s, %d, %d, %d, %d" % (app, app_status["build"], \
  734. app_status.get("run", False), app_time.get("build", "-"), app_time.get("run", "-"), \
  735. apprsttype, apprstval, size["total"], size["text"], size["data"], size["bss"])
  736. csvlines.append(csvline)
  737. display = get_sdk_verb_buildmsg()
  738. save_csv(csvfile, csvlines, display)
  739. return True
  740. def save_bench_csv(result, csvfile):
  741. if isinstance(result, dict) == False:
  742. return False
  743. csvlines = ["App, case, buildstatus, runstatus, buildtime, runtime, type, value, total, text, data, bss"]
  744. for app in result:
  745. appresult = result[app]
  746. for case in appresult:
  747. size = appresult[case]["size"]
  748. app_status = appresult[case]["status"]
  749. app_time = appresult[case]["time"]
  750. apprsttype, apprstval = get_app_runresult(appresult[case].get("result", dict()))
  751. csvline = "%s, %s, %s, %s, %s, %s, %s, %s, %d, %d, %d, %d" % (app, case, app_status["build"], \
  752. app_status.get("run", False), app_time.get("build", "-"), app_time.get("run", "-"), \
  753. apprsttype, apprstval, size["total"], size["text"], size["data"], size["bss"])
  754. csvlines.append(csvline)
  755. # save csv file
  756. display = get_sdk_verb_buildmsg()
  757. save_csv(csvfile, csvlines, display)
  758. return True
  759. def find_local_appconfig(appdir, localcfgs):
  760. if isinstance(appdir, str) and isinstance(localcfgs, dict):
  761. if appdir in localcfgs:
  762. return appdir
  763. else:
  764. foundcfg = None
  765. for localcfg in localcfgs:
  766. localcfgtp = localcfg.strip('/')
  767. striped_dir = appdir.split(localcfgtp, 1)
  768. if len(striped_dir) == 2:
  769. striped_dir = striped_dir[1]
  770. else:
  771. striped_dir = appdir
  772. if striped_dir != appdir:
  773. if striped_dir.startswith('/'):
  774. if foundcfg is None:
  775. foundcfg = localcfg
  776. else:
  777. if len(foundcfg) < len(localcfg):
  778. foundcfg = localcfg
  779. return foundcfg
  780. else:
  781. return None
  782. def fix_evalsoc_verilog_ncycm(verilog):
  783. if os.path.isfile(verilog) == False:
  784. return ""
  785. vfct = ""
  786. with open(verilog, "r", errors='ignore') as vf:
  787. for line in vf.readlines():
  788. line = line.replace("@80", "@00").replace("@90", "@08")
  789. vfct += line
  790. verilog_new = verilog + ".ncycm"
  791. with open(verilog_new, "w") as vf:
  792. vf.write(vfct)
  793. return verilog_new
  794. PROGRAM_UNKNOWN="unknown"
  795. PROGRAM_BAREBENCH="barebench"
  796. PROGRAM_COREMARK="coremark"
  797. PROGRAM_DHRYSTONE="dhrystone"
  798. PROGRAM_WHETSTONE="whetstone"
  799. def parse_benchmark_compatiable(lines):
  800. result = None
  801. program_type = PROGRAM_UNKNOWN
  802. subtype = PROGRAM_UNKNOWN
  803. try:
  804. for line in lines:
  805. # Coremark
  806. if "CoreMark" in line:
  807. program_type = PROGRAM_BAREBENCH
  808. subtype = PROGRAM_COREMARK
  809. if "Iterations*1000000/total_ticks" in line:
  810. value = line.split("=")[1].strip().split()[0]
  811. result = dict()
  812. result["CoreMark/MHz"] = strtofloat(value)
  813. # Dhrystone
  814. if "Dhrystone" in line:
  815. program_type = PROGRAM_BAREBENCH
  816. subtype = PROGRAM_DHRYSTONE
  817. if "1000000/(User_Cycle/Number_Of_Runs)" in line:
  818. value = line.split("=")[1].strip().split()[0]
  819. result = dict()
  820. result["DMIPS/MHz"] = strtofloat(value)
  821. # Whetstone
  822. if "Whetstone" in line:
  823. program_type = PROGRAM_BAREBENCH
  824. subtype = PROGRAM_WHETSTONE
  825. if "MWIPS/MHz" in line:
  826. value = line.split("MWIPS/MHz")[-1].strip().split()[0]
  827. result = dict()
  828. result["MWIPS/MHz"] = strtofloat(value)
  829. except:
  830. return program_type, subtype, result
  831. return program_type, subtype, result
  832. def parse_benchmark_baremetal(lines):
  833. result = None
  834. program_type = PROGRAM_UNKNOWN
  835. subtype = PROGRAM_UNKNOWN
  836. try:
  837. unit = "unknown"
  838. for line in lines:
  839. stripline = line.strip()
  840. if "csv," in stripline.lower():
  841. csv_values = stripline.split(',')
  842. if len(csv_values) >= 3:
  843. key = csv_values[1].strip()
  844. value = csv_values[-1].strip()
  845. if key.lower() == "benchmark":
  846. program_type = PROGRAM_BAREBENCH
  847. unit = value
  848. else:
  849. subtype = key.lower()
  850. result = dict()
  851. result[unit] = strtofloat(value)
  852. break
  853. except:
  854. return program_type, subtype, result
  855. return program_type, subtype, result
  856. def parse_benchmark_baremetal_csv(lines):
  857. result = None
  858. program_type = PROGRAM_UNKNOWN
  859. try:
  860. result = dict()
  861. for line in lines:
  862. stripline = line.strip()
  863. if "csv," in stripline.lower():
  864. csv_values = stripline.split(',')
  865. if len(csv_values) >= 3:
  866. key = csv_values[1].strip()
  867. value = csv_values[-1].strip()
  868. if "BENCH" not in key.upper():
  869. result[key] = value
  870. except:
  871. return program_type, result
  872. return program_type, result
  873. def find_index(key, arr):
  874. try:
  875. index = arr.index(key)
  876. except:
  877. index = -1
  878. return index
  879. def parse_benchmark_runlog(lines, lgf=""):
  880. if isinstance(lines, list) == False:
  881. return PROGRAM_UNKNOWN, PROGRAM_UNKNOWN, None
  882. if len(lines) == 0:
  883. return PROGRAM_UNKNOWN, PROGRAM_UNKNOWN, None
  884. subtype = ""
  885. if lgf.strip() == "": # old style
  886. program_type, subtype, result = parse_benchmark_compatiable(lines)
  887. else:
  888. lgf = lgf.replace("\\", "/")
  889. appnormdirs = os.path.dirname(os.path.normpath(lgf)).replace('\\', '/').split('/')
  890. if "baremetal/benchmark" in lgf:
  891. # baremetal benchmark
  892. program_type, subtype, result = parse_benchmark_baremetal(lines)
  893. if program_type == PROGRAM_UNKNOWN:
  894. # fallback to previous parser
  895. program_type, subtype, result = parse_benchmark_compatiable(lines)
  896. elif "baremetal/demo_dsp" in lgf:
  897. program_type, result = parse_benchmark_baremetal_csv(lines)
  898. program_type = "demo_dsp"
  899. elif "DSP/Examples/RISCV" in lgf:
  900. program_type, result = parse_benchmark_baremetal_csv(lines)
  901. program_type = "nmsis_dsp_example"
  902. index = find_index("RISCV", appnormdirs)
  903. if index >= 0:
  904. subtype = appnormdirs[index + 1]
  905. elif "DSP/Test" in lgf:
  906. program_type, result = parse_benchmark_baremetal_csv(lines)
  907. program_type = "nmsis_dsp_tests"
  908. index = find_index("Test", appnormdirs)
  909. if index >= 0:
  910. subtype = appnormdirs[index + 1]
  911. elif "NN/Examples/RISCV" in lgf:
  912. program_type, result = parse_benchmark_baremetal_csv(lines)
  913. program_type = "nmsis_nn_example"
  914. index = find_index("RISCV", appnormdirs)
  915. if index >= 0:
  916. subtype = appnormdirs[index + 1]
  917. elif "NN/Tests" in lgf:
  918. program_type, result = parse_benchmark_baremetal_csv(lines)
  919. if "full" in appnormdirs:
  920. program_type = "nmsis_nn_test_full"
  921. subtype = "full"
  922. else:
  923. program_type = "nmsis_nn_test_percase"
  924. index = find_index("percase", appnormdirs)
  925. if index >= 0:
  926. subtype = appnormdirs[index + 1]
  927. else:
  928. program_type, subtype, result = parse_benchmark_compatiable(lines)
  929. return program_type, subtype, result
  930. def parse_benchmark_use_pyscript(lines, lgf, pyscript):
  931. if isinstance(lines, list) == False:
  932. return PROGRAM_UNKNOWN, PROGRAM_UNKNOWN, None
  933. if len(lines) == 0:
  934. return PROGRAM_UNKNOWN, PROGRAM_UNKNOWN, None
  935. # function should named parse_benchmark
  936. # function argument and return like parse_benchmark_runlog
  937. parsefunc = import_function("parse_benchmark", pyscript)
  938. if parsefunc is None:
  939. return PROGRAM_UNKNOWN, PROGRAM_UNKNOWN, None
  940. try:
  941. program_type, subtype, result = parsefunc(lines, lgf)
  942. return program_type, subtype, result
  943. except Exception as exc:
  944. print("ERROR: Parse using %s script error: %s" %(pyscript, exc))
  945. return PROGRAM_UNKNOWN, PROGRAM_UNKNOWN, None
  946. def check_tool_exist(tool):
  947. exist = False
  948. if sys.platform == 'win32':
  949. if os.system("where %s" % (tool)) == 0:
  950. exist = True
  951. else:
  952. if os.system("which %s" % (tool)) == 0:
  953. exist = True
  954. return exist
  955. def find_vivado_cmd():
  956. for vivado_cmd in ("vivado", "vivado_lab"):
  957. if sys.platform == 'win32':
  958. if os.system("where %s" % (vivado_cmd)) == 0:
  959. return vivado_cmd
  960. else:
  961. if os.system("which %s" % (vivado_cmd)) == 0:
  962. return vivado_cmd
  963. return None
  964. def datetime_now():
  965. return datetime.datetime.now().strftime(DATE_FORMATE)
  966. def program_fpga(bit, target):
  967. if os.path.isfile(bit) == False:
  968. print("Can't find bitstream in %s" % (bit))
  969. return False
  970. print("Try to program fpga bitstream %s to target board %s" % (bit, target))
  971. sys.stdout.flush()
  972. FILE_LOCK = os.path.join(get_tmpdir(), FILE_LOCK_NAME)
  973. # TODO: use portable filelock for win32
  974. with open(FILE_LOCK, 'w+') as filelock:
  975. if sys.platform != "win32":
  976. print("%s, Wait another board's programing fpga to finished" %(datetime_now()))
  977. fcntl.flock(filelock, fcntl.LOCK_EX)
  978. # set to 666, in case that other user can't access this file causing exception
  979. if os.stat(FILE_LOCK).st_uid == os.getuid():
  980. os.chmod(FILE_LOCK, stat.S_IWGRP | stat.S_IRGRP | stat.S_IWUSR | stat.S_IRUSR | stat.S_IWOTH | stat.S_IROTH)
  981. print("%s, Has acquired the chance to do fpga programing!" %(datetime_now()))
  982. vivado_cmd = find_vivado_cmd()
  983. # check vivado is found or not
  984. if vivado_cmd == None:
  985. print("vivado is not found in PATH, please check!")
  986. return False
  987. tcl = os.path.join(os.path.dirname(os.path.realpath(__file__)), "program_bit.tcl")
  988. target = "*%s" % (target)
  989. progcmd = "%s -mode batch -nolog -nojournal -source %s -tclargs %s %s" % (vivado_cmd, tcl, bit, target)
  990. tmout = get_sdk_fpga_prog_tmout()
  991. if sys.platform != 'win32' and tmout is not None and tmout.strip() != "":
  992. print("Timeout %s do fpga program" % (tmout))
  993. progcmd = "timeout --foreground -s SIGKILL %s %s" % (tmout, progcmd)
  994. print("Do fpga program using command: %s" % (progcmd))
  995. sys.stdout.flush()
  996. ret = os.system(progcmd)
  997. sys.stdout.flush()
  998. if ret != 0:
  999. print("Program fpga bit failed, error code %d" % ret)
  1000. return False
  1001. print("Program fpga bit successfully")
  1002. return True
  1003. def find_fpgas():
  1004. vivado_cmd = find_vivado_cmd()
  1005. if vivado_cmd == None:
  1006. print("vivado is not found in PATH, please check!")
  1007. return dict()
  1008. tcl = os.path.join(os.path.dirname(os.path.realpath(__file__)), "find_devices.tcl")
  1009. sys.stdout.flush()
  1010. tmp_log = tempfile.mktemp()
  1011. os.system("%s -mode batch -nolog -nojournal -source %s -notrace > %s" % (vivado_cmd, tcl, tmp_log))
  1012. sys.stdout.flush()
  1013. fpgadevices = dict()
  1014. with open(tmp_log, "r", errors='ignore') as tf:
  1015. for line in tf.readlines():
  1016. line = line.strip()
  1017. if line.startswith("CSV,") == False:
  1018. continue
  1019. splits = line.split(",")
  1020. if len(splits) != 3:
  1021. continue
  1022. fpga_serial = "/".join(splits[1].split("/")[2:])
  1023. fpgadevices[fpga_serial] = splits[2].strip()
  1024. return fpgadevices
  1025. def check_serial_port(serport):
  1026. if serport in find_possible_serports():
  1027. return True
  1028. return False
  1029. def modify_openocd_cfg(cfg, ftdi_serial):
  1030. cfg_bk = cfg + ".backup"
  1031. if (os.path.isfile(cfg)) == False:
  1032. return False
  1033. if os.path.isfile(cfg_bk) == True:
  1034. print("Restore openocd cfg %s" %(cfg))
  1035. shutil.copyfile(cfg_bk, cfg)
  1036. else:
  1037. print("Backup openocd cfg %s" %(cfg))
  1038. shutil.copyfile(cfg, cfg_bk)
  1039. found = False
  1040. contents = []
  1041. index = 0
  1042. with open(cfg, 'r', errors='ignore') as cf:
  1043. contents = cf.readlines()
  1044. for line in contents:
  1045. if line.strip().startswith("transport select"):
  1046. found = True
  1047. break
  1048. index += 1
  1049. if found == False:
  1050. return False
  1051. if sys.platform == 'win32':
  1052. ftdi_serial = "%sA" % (ftdi_serial)
  1053. contents.insert(index, "ftdi_serial %s\ntcl_port disabled\ntelnet_port disabled\n" %(ftdi_serial))
  1054. with open(cfg, 'w') as cf:
  1055. contents = "".join(contents)
  1056. cf.write(contents)
  1057. return True
  1058. GL_CPUCFGs = os.path.join(SCRIPT_DIR, "configs", "cpu")
  1059. def gen_runcfg(cpucfg, runcfg, buildconfig=dict()):
  1060. _, cpucfgdict = load_json(cpucfg)
  1061. _, runcfgdict = load_json(runcfg)
  1062. if cpucfgdict is None:
  1063. return { "build_configs": { "default": {} } }
  1064. if runcfgdict is None:
  1065. return cpucfgdict
  1066. matrixcfgs = runcfgdict.get("matrix", None)
  1067. expectedcfg = runcfgdict.get("expected", dict())
  1068. expectedscfg = runcfgdict.get("expecteds", dict())
  1069. finalruncfg = copy.deepcopy(cpucfgdict)
  1070. # merge buildconfig
  1071. finalruncfg["build_config"] = merge_two_config(finalruncfg.get("build_config", dict()), buildconfig)
  1072. finalruncfg["expected"] = merge_two_config(finalruncfg.get("expected", dict()), expectedcfg)
  1073. finalruncfg["expecteds"] = merge_two_config(finalruncfg.get("expecteds", dict()), expectedscfg)
  1074. if matrixcfgs is None:
  1075. return finalruncfg
  1076. bcfgs = cpucfgdict.get("build_configs", dict())
  1077. newbcfgs = dict()
  1078. for bkey in bcfgs:
  1079. for key in matrixcfgs:
  1080. cfgkey = "%s-%s" % (bkey, key)
  1081. newbcfgs[cfgkey] = merge_two_config(bcfgs[bkey], matrixcfgs[key])
  1082. if len(newbcfgs) > 1:
  1083. finalruncfg["build_configs"] = newbcfgs
  1084. else:
  1085. finalruncfg["build_configs"] = bcfgs
  1086. return finalruncfg
  1087. def gen_coreruncfg(core, runcfg, choice="mini", buildconfig=dict(), casedir=None):
  1088. cpucfgsloc = os.path.join(GL_CPUCFGs, choice)
  1089. if casedir is not None:
  1090. tmp = os.path.join(casedir, choice)
  1091. if os.path.isdir(tmp) == True:
  1092. cpucfgsloc = os.path.realpath(tmp)
  1093. print("Use cpu configs in location %s directory" % (cpucfgsloc))
  1094. cpucfg = os.path.join(cpucfgsloc, "%s.json" % (core))
  1095. return gen_runcfg(cpucfg, runcfg, buildconfig)
  1096. def gen_coreruncfg_custom(core, runcfg, customcfgdir, buildconfig=dict()):
  1097. cpucfg = os.path.join(customcfgdir, "%s.json" % (core))
  1098. return gen_runcfg(cpucfg, runcfg, buildconfig)
  1099. def gen_runyaml(core, locs, fpga_serial, ftdi_serial, cycm, fpgabit, boardtype, ocdcfg, appcfg, hwcfg):
  1100. runyaml = { "runcfg": {"runner": "fpga"},
  1101. "fpga_runners": { core: {
  1102. "board_type": boardtype, "fpga_serial": fpga_serial,
  1103. "ftdi_serial": ftdi_serial, "serial_port": ""}
  1104. },
  1105. "ncycm_runners": { core: {
  1106. "model": cycm if cycm else "" }
  1107. },
  1108. "configs": { core: {
  1109. "fpga": boardtype, "bitstream": fpgabit,
  1110. "ncycm": core, "openocd_cfg": ocdcfg,
  1111. "appcfg": appcfg, "hwcfg": hwcfg }
  1112. },
  1113. "environment": {
  1114. "fpgaloc": locs.get("fpgaloc", ""),
  1115. "ncycmloc": locs.get("ncycmloc", ""),
  1116. "cfgloc": locs.get("cfgloc", "")
  1117. }
  1118. }
  1119. if cycm is not None:
  1120. runyaml["runcfg"]["runner"] = "ncycm"
  1121. return runyaml