import os, sys, getopt, shutil, tempfile
##yosys-sys-path##
-from sby_core import SbyJob
+from sby_core import SbyJob, SbyAbort
from time import localtime
sbyfile = None
opt_backup = False
opt_tmpdir = False
exe_paths = dict()
+throw_err = False
def usage():
print("""
-T taskname
add taskname (useful when sby file is read from stdin)
+ -E
+ throw an exception (incl stack trace) for most errors
+
--yosys <path_to_executable>
--abc <path_to_executable>
--smtbmc <path_to_executable>
sys.exit(1)
try:
- opts, args = getopt.getopt(sys.argv[1:], "d:btfT:", ["yosys=",
+ opts, args = getopt.getopt(sys.argv[1:], "d:btfT:E", ["yosys=",
"abc=", "smtbmc=", "suprove=", "aigbmc=", "avy="])
except:
usage()
opt_tmpdir = True
elif o == "-T":
tasknames.append(a)
+ elif o == "-E":
+ throw_err = True
elif o == "--yosys":
exe_paths["yosys"] = a
elif o == "--abc":
if len(args) > 0:
sbyfile = args[0]
- assert sbyfile.endswith(".sby")
+ if not sbyfile.endswith(".sby"):
+ print("ERROR: Sby file does not have .sby file extension.", file=sys.stderr)
+ sys.exit(1)
if len(args) > 1:
tasknames = args[1:]
if len(tasknames) == 0:
tasknames = [None]
-assert (workdir is None) or (len(tasknames) == 1)
-
+if (workdir is not None) and (len(tasknames) != 1):
+ print("ERROR: Exactly one task is required when workdir is specified.", file=sys.stderr)
+ sys.exit(1)
def run_job(taskname):
my_workdir = workdir
my_workdir = tempfile.mkdtemp()
sbyconfig, _ = read_sbyconfig(sbydata, taskname)
- job = SbyJob(sbyconfig, taskname, my_workdir, early_logmsgs)
+ job = SbyJob(sbyconfig, my_workdir, early_logmsgs)
for k, v in exe_paths.items():
job.exe_paths[k] = v
- job.run()
+ if throw_err:
+ job.run()
+ else:
+ try:
+ job.run()
+ except SbyAbort:
+ pass
if my_opt_tmpdir:
job.log("Removing direcory '%s'." % (my_workdir))
retcode = 0
for t in tasknames:
- assert (t is None) or (t in tasknames)
- retcode += run_job(t)
+ retcode |= run_job(t)
sys.exit(retcode)
return
+class SbyAbort(BaseException):
+ pass
+
+
class SbyJob:
- def __init__(self, sbyconfig, taskname, workdir, early_logs):
+ def __init__(self, sbyconfig, workdir, early_logs):
self.options = dict()
self.used_options = set()
self.engines = list()
self.models = dict()
self.workdir = workdir
self.status = "UNKNOWN"
+ self.expect = []
self.exe_paths = {
"yosys": "yosys",
print(line, file=self.logfile)
self.logfile.flush()
- mode = None
- key = None
-
with open("%s/config.sby" % workdir, "w") as f:
for line in sbyconfig:
print(line, file=f)
- with open("%s/config.sby" % workdir, "r") as f:
- for line in f:
- raw_line = line
- if mode in ["options", "engines", "files"]:
- line = re.sub(r"\s*(\s#.*)?$", "", line)
- if line == "" or line[0] == "#":
- continue
- else:
- line = line.rstrip()
- # print(line)
- if mode is None and (len(line) == 0 or line[0] == "#"):
- continue
- match = re.match(r"^\s*\[(.*)\]\s*$", line)
- if match:
- entries = match.group(1).split()
- assert len(entries) > 0
-
- if entries[0] == "options":
- mode = "options"
- assert len(self.options) == 0
- assert len(entries) == 1
- continue
-
- if entries[0] == "engines":
- mode = "engines"
- assert len(self.engines) == 0
- assert len(entries) == 1
- continue
-
- if entries[0] == "script":
- mode = "script"
- assert len(self.script) == 0
- assert len(entries) == 1
- continue
-
- if entries[0] == "file":
- mode = "file"
- assert len(entries) == 2
- current_verbatim_file = entries[1]
- assert current_verbatim_file not in self.verbatim_files
- self.verbatim_files[current_verbatim_file] = list()
- continue
-
- if entries[0] == "files":
- mode = "files"
- assert len(entries) == 1
- continue
-
- assert False
-
- if mode == "options":
- entries = line.split()
- assert len(entries) == 2
- self.options[entries[0]] = entries[1]
- continue
-
- if mode == "engines":
- entries = line.split()
- self.engines.append(entries)
- continue
-
- if mode == "script":
- self.script.append(line)
- continue
-
- if mode == "files":
- entries = line.split()
- if len(entries) == 1:
- self.files[os.path.basename(entries[0])] = entries[0]
- elif len(entries) == 2:
- self.files[entries[0]] = entries[1]
- else:
- assert False
- continue
-
- if mode == "file":
- self.verbatim_files[current_verbatim_file].append(raw_line)
- continue
-
- assert False
-
def taskloop(self):
for task in self.tasks_all:
task.poll()
print("SBY %2d:%02d:%02d [%s] %s" % (tm.tm_hour, tm.tm_min, tm.tm_sec, self.workdir, logmessage), file=self.logfile)
self.logfile.flush()
+ def error(self, logmessage):
+ tm = localtime()
+ print("SBY %2d:%02d:%02d [%s] ERROR: %s" % (tm.tm_hour, tm.tm_min, tm.tm_sec, self.workdir, logmessage))
+ print("SBY %2d:%02d:%02d [%s] ERROR: %s" % (tm.tm_hour, tm.tm_min, tm.tm_sec, self.workdir, logmessage), file=self.logfile)
+ self.logfile.flush()
+ self.status = "ERROR"
+ if "ERROR" not in self.expect:
+ self.retcode = 16
+ self.terminate()
+ with open("%s/%s" % (self.workdir, self.status), "w") as f:
+ print("ERROR: %s" % logmessage, file=f)
+ raise SbyAbort(logmessage)
+
def copy_src(self):
os.makedirs(self.workdir + "/src")
def handle_bool_option(self, option_name, default_value):
if option_name in self.options:
- assert self.options[option_name] in ["on", "off"]
+ if self.options[option_name] not in ["on", "off"]:
+ self.error("Invalid value '%s' for boolean option %s." % (self.options[option_name], option_name))
self.__dict__["opt_" + option_name] = self.options[option_name] == "on"
self.used_options.add(option_name)
else:
assert 0
def run(self):
+ mode = None
+ key = None
+
+ with open("%s/config.sby" % self.workdir, "r") as f:
+ for line in f:
+ raw_line = line
+ if mode in ["options", "engines", "files"]:
+ line = re.sub(r"\s*(\s#.*)?$", "", line)
+ if line == "" or line[0] == "#":
+ continue
+ else:
+ line = line.rstrip()
+ # print(line)
+ if mode is None and (len(line) == 0 or line[0] == "#"):
+ continue
+ match = re.match(r"^\s*\[(.*)\]\s*$", line)
+ if match:
+ entries = match.group(1).split()
+ if len(entries) == 0:
+ self.error("sby file syntax error: %s" % line)
+
+ if entries[0] == "options":
+ mode = "options"
+ if len(self.options) != 0 or len(entries) != 1:
+ self.error("sby file syntax error: %s" % line)
+ continue
+
+ if entries[0] == "engines":
+ mode = "engines"
+ if len(self.engines) != 0 or len(entries) != 1:
+ self.error("sby file syntax error: %s" % line)
+ continue
+
+ if entries[0] == "script":
+ mode = "script"
+ if len(self.script) != 0 or len(entries) != 1:
+ self.error("sby file syntax error: %s" % line)
+ continue
+
+ if entries[0] == "file":
+ mode = "file"
+ if len(entries) != 2:
+ self.error("sby file syntax error: %s" % line)
+ current_verbatim_file = entries[1]
+ if current_verbatim_file in self.verbatim_files:
+ self.error("duplicate file: %s" % entries[1])
+ self.verbatim_files[current_verbatim_file] = list()
+ continue
+
+ if entries[0] == "files":
+ mode = "files"
+ if len(entries) != 1:
+ self.error("sby file syntax error: %s" % line)
+ continue
+
+ self.error("sby file syntax error: %s" % line)
+
+ if mode == "options":
+ entries = line.split()
+ if len(entries) != 2:
+ self.error("sby file syntax error: %s" % line)
+ self.options[entries[0]] = entries[1]
+ continue
+
+ if mode == "engines":
+ entries = line.split()
+ self.engines.append(entries)
+ continue
+
+ if mode == "script":
+ self.script.append(line)
+ continue
+
+ if mode == "files":
+ entries = line.split()
+ if len(entries) == 1:
+ self.files[os.path.basename(entries[0])] = entries[0]
+ elif len(entries) == 2:
+ self.files[entries[0]] = entries[1]
+ else:
+ self.error("sby file syntax error: %s" % line)
+ continue
+
+ if mode == "file":
+ self.verbatim_files[current_verbatim_file].append(raw_line)
+ continue
+
+ self.error("sby file syntax error: %s" % line)
+
self.handle_str_option("mode", None)
- assert self.opt_mode in ["bmc", "prove", "cover", "live"]
+
+ if self.opt_mode not in ["bmc", "prove", "cover", "live"]:
+ self.error("Invalid mode: %s" % self.opt_mode)
self.expect = ["PASS"]
if "expect" in self.options:
self.used_options.add("expect")
for s in self.expect:
- assert s in ["PASS", "FAIL", "UNKNOWN", "ERROR", "TIMEOUT"]
+ if s not in ["PASS", "FAIL", "UNKNOWN", "ERROR", "TIMEOUT"]:
+ self.error("Invalid expect value: %s" % s)
self.handle_bool_option("multiclock", False)
self.handle_bool_option("wait", False)
if self.opt_smtc is not None:
for engine in self.engines:
- assert engine[0] == "smtbmc"
+ if engine[0] != "smtbmc":
+ self.error("Option smtc is only valid for smtbmc engine.")
self.copy_src()
assert False
for opt in self.options.keys():
- assert opt in self.used_options
+ if opt not in self.used_options:
+ self.error("Unused option: %s" % opt)
self.taskloop()
else:
if self.status == "PASS": self.retcode = 1
if self.status == "FAIL": self.retcode = 2
- if self.status == "ERROR": self.retcode = 3
if self.status == "UNKNOWN": self.retcode = 4
- if self.status == "TIMEOUT": self.retcode = 5
+ if self.status == "TIMEOUT": self.retcode = 8
+ if self.status == "ERROR": self.retcode = 16
with open("%s/%s" % (self.workdir, self.status), "w") as f:
for line in self.summary: