diff --git a/CHANGELOG.md b/CHANGELOG.md index bdf58fd..4681d80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.23.0] - 2021-10-14 +- Added support for new RVTEST_ISA macro +- Fixed decode error in Command util. + ## [1.22.1] - 2021-09-13 - Added return code of 1 on error diff --git a/riscof/__init__.py b/riscof/__init__.py index 88d9bc0..cad8afc 100644 --- a/riscof/__init__.py +++ b/riscof/__init__.py @@ -4,4 +4,4 @@ __author__ = """InCore Semiconductors Pvt Ltd""" __email__ = 'info@incoresemi.com' -__version__ = '1.22.1' +__version__ = '1.23.0' diff --git a/riscof/dbgen.py b/riscof/dbgen.py index 3738ee2..6aea4bb 100644 --- a/riscof/dbgen.py +++ b/riscof/dbgen.py @@ -87,7 +87,7 @@ def createdict(file): continue re_search = isa_regex.search(line) if re_search is not None: - isa = re_search.group('isa') + isa = [x.strip() for x in (re_search.group('isa')).split(",")] if "RVTEST_CASE(" in line: temp = '' lno = i @@ -132,7 +132,7 @@ def createdict(file): if len(part_dict.keys()) == 0: logger.warning("{}: Atleast one part must exist in the test.".format(file)) raise DbgenError - return {'isa': str(isa), 'parts': orderdict(part_dict)} + return {'isa': [str(x) for x in isa], 'parts': orderdict(part_dict)} def check_commit(repo, fpath, old_commit): commit = next( diff --git a/riscof/framework/test.py b/riscof/framework/test.py index a493d68..decdef0 100644 --- a/riscof/framework/test.py +++ b/riscof/framework/test.py @@ -17,6 +17,9 @@ logger = logging.getLogger(__name__) +class TestSelectError(Exception): + "Raised on an error while selecting Tests." + pass def compare_signature(file1, file2): ''' @@ -222,6 +225,69 @@ def eval_macro(macro, spec): else: return (False,[]) +def isa_set(string): + str_match = re.findall(r'([^\d]*?)(?!_)*(Z.*?)*(_|$)',string,re.M) + extension_list= [] + for match in str_match: + stdisa, z, ignore = match + if stdisa != '': + for e in stdisa: + extension_list.append(e) + if z != '': + extension_list.append(z) + return set(extension_list) + +def canonicalise(isa): + all_ext = ["M","A","F","D","Q","L","C","B","J","K","T","P","V","N","S","H","U","Zicsr", + "Zifencei","Zihintpause","Zmmul","Zam","Zbc","Zbb","Zbp","Zbm","Zbe","Zbf","Zkne", + "Zknd","Zknh","Zkse","Zksh","Zkg","Zkb","Zkr","Zks","Zkn","Ztso"] + canonical_string = "" + switch = False + for ext in all_ext: + if ext in isa: + if switch: + canonical_string += "_" + elif ext.startswith("Z"): + switch=True + canonical_string += ext + if ext.startswith("Z"): + switch=True + return canonical_string + + +def prod_isa(dut_isa, test_isa): + ''' + Function to generate the isa a test has to be compiled with. The various possible ISAs a + test can be compiled with is compared with the ISA defined in the DUT specification. + + :param dut_isa: The ISA field in the DUT specification. + + :param test_isa: A list of ISA strings from the test. + + :type dut_isa: str + + :type test_isa: list(str) + + :return: The maximal set of all the applicable ISA strings from the test in canonical form. + + :raises: TestSelectError + + ''' + dut_exts = isa_set(re.sub("RV(64|128|32)(I|E)","",dut_isa)) + isa = set([]) + last_prefix = '' + for entry in test_isa: + match = re.findall("(?PRV(64|128|32)(I|E))",entry) + prefix = match[0][0] + exts = isa_set(re.sub("RV(64|128|32)(I|E)","",entry)) + overlap = dut_exts & exts + if overlap == exts: + isa = isa | overlap + if last_prefix: + if last_prefix != prefix: + raise TestSelectError("Incompatiple prefix for valid ISA strings in test.") + last_prefix = prefix + return prefix+canonicalise(isa) def generate_test_pool(ispec, pspec, workdir, dbfile = None): ''' @@ -236,11 +302,8 @@ def generate_test_pool(ispec, pspec, workdir, dbfile = None): :type pspec: dict - :return: A list of 3 entry tuples. Each entry in a list corresponds to a - test which should be executed. In each tuple, the first entry is the - path to the test relative to the riscof root, the second entry is the - list of macros for the test and the third entry is the - isa(adhering to RISCV specifications) required for the test. + :return: A dictionary which contains all the necessary information for the selected tests. + Refer to Test List Format for further information. ''' spec = {**ispec, **pspec} @@ -267,7 +330,11 @@ def generate_test_pool(ispec, pspec, workdir, dbfile = None): if (temp[0]): macros.extend(temp[1]) if not macros == []: - isa = db[file]['isa'] + try: + isa = prod_isa(ispec['ISA'],db[file]['isa']) + except TestSelectError as e: + logger.error("Error in test: "+str(file)+"\n"+str(e)) + continue if '32' in isa: xlen = '32' elif '64' in isa: @@ -280,7 +347,7 @@ def generate_test_pool(ispec, pspec, workdir, dbfile = None): elif re.match(r"^[^(Z,z)]+F.*$",isa): macros.append("FLEN=32") test_pool.append( - (file, db[file]['commit_id'], macros, db[file]['isa'],cov_labels)) + (file, db[file]['commit_id'], macros,isa,cov_labels)) logger.info("Selecting Tests.") for entry in test_pool: # logger.info("Test file:" + entry[0]) diff --git a/riscof/requirements.txt b/riscof/requirements.txt index 6ae675f..e0e8ad2 100644 --- a/riscof/requirements.txt +++ b/riscof/requirements.txt @@ -1,5 +1,5 @@ GitPython==3.1.17 -click +click>=7.1.2 Jinja2>=2.10.1 pytz>=2019.1 riscv-config>=2.10.1 diff --git a/riscof/utils.py b/riscof/utils.py index 546651f..a5749c0 100644 --- a/riscof/utils.py +++ b/riscof/utils.py @@ -232,16 +232,30 @@ def run(self, **kwargs): logger.error("Process Killed.") logger.error("Command did not exit within {0} seconds: {1}".format(timeout,cmd)) - if x.returncode != 0: - if out: - logger.error(out.decode("ascii")) - if err: - logger.error(err.decode("ascii")) - else: + try: + fmt = sys.stdout.encoding if sys.stdout.encoding is not None else 'utf-8' if out: - logger.warning(out.decode("ascii")) + if x.returncode != 0: + logger.error(out.decode(fmt)) + else: + logger.debug(out.decode(fmt)) + except UnicodeError: + logger.warning("Unable to decode STDOUT for launched subprocess. Output written to:"+ + cwd+"/stdout.log") + with open(cwd+"/stdout.log") as f: + f.write(out) + try: + fmt = sys.stderr.encoding if sys.stdout.encoding is not None else 'utf-8' if err: - logger.warning(err.decode("ascii")) + if x.returncode != 0: + logger.error(err.decode(fmt)) + else: + logger.debug(err.decode(fmt)) + except UnicodeError: + logger.warning("Unable to decode STDERR for launched subprocess. Output written to:"+ + cwd+"/stderr.log") + with open(cwd+"/stderr.log") as f: + f.write(out) return x.returncode def _is_shell_command(self): diff --git a/setup.cfg b/setup.cfg index 90e26cd..c5555e9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.22.1 +current_version = 1.23.0 commit = True tag = True diff --git a/setup.py b/setup.py index 48d72a1..b35b6eb 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ def read_requires(): test_requirements = [ ] setup(name="riscof", - version='1.22.1', + version='1.23.0', description="RISC-V Architectural Test Framework", long_description=readme + '\n\n', classifiers=[