From 307a5253c8a824bfb5aae1ef59d05af466ed29a9 Mon Sep 17 00:00:00 2001 From: Lzzz666 Date: Thu, 12 Jun 2025 20:12:16 +0800 Subject: [PATCH 1/2] Enhance CI formatting checks for Python files Add Black-based formatting checks for Python files: - Update `.ci/check-format.sh` to include checks for Python files using Black 25.1.0. - Modify `.github/workflows/main.yml` to install Black for formatting. - Add `pyproject.toml` for configuring Black as the Python code formatter. - Enhance `CONTRIBUTING.md` with guidelines for Python formatting. --- .ci/check-format.sh | 12 +++++++++++- .github/workflows/main.yml | 3 ++- CONTRIBUTING.md | 21 +++++++++++++++++++-- pyproject.toml | 4 ++++ 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 pyproject.toml diff --git a/.ci/check-format.sh b/.ci/check-format.sh index 593145f0..1d98571f 100755 --- a/.ci/check-format.sh +++ b/.ci/check-format.sh @@ -21,4 +21,14 @@ for file in ${SH_SOURCES}; do done SH_MISMATCH_FILE_CNT=$(shfmt -l ${SH_SOURCES}) -exit $((C_MISMATCH_LINE_CNT + SH_MISMATCH_FILE_CNT)) +PY_SOURCES=$(find "${REPO_ROOT}" | egrep "\.py$") +for file in ${PY_SOURCES}; do + echo "Checking Python file: ${file}" + black --diff "${file}" +done +PY_MISMATCH_FILE_CNT=0 +if [ -n "${PY_SOURCES}" ]; then + PY_MISMATCH_FILE_CNT=$(echo "$(black --check ${PY_SOURCES} 2>&1)" | grep -c "^would reformat ") +fi + +exit $((C_MISMATCH_LINE_CNT + SH_MISMATCH_FILE_CNT + PY_MISMATCH_FILE_CNT)) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cccfa462..899fb470 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -505,7 +505,8 @@ jobs: - uses: actions/checkout@v4 - name: coding convention run: | - sudo apt-get install -q=2 clang-format-18 shfmt + sudo apt-get install -q=2 clang-format-18 shfmt python3-pip + pip3 install black==25.1.0 .ci/check-newline.sh .ci/check-format.sh shell: bash diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cf279ef1..b657654d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,6 +39,7 @@ However, participation requires adherence to fundamental ground rules: While there is some flexibility in basic style, it is crucial to stick to the current coding standards. Complex algorithmic constructs without proper comments will not be accepted. * Shell scripts must be formatted before submission. Use consistent flags across the project to ensure uniform formatting. +* Python scripts must be formatted before submission. Use consistent flags across the project to ensure uniform formatting. * External pull requests should include thorough documentation in the pull request comments for consideration. * When composing documentation, code comments, and other materials in English, please adhere to the American English (`en_US`) dialect. @@ -48,9 +49,12 @@ However, participation requires adherence to fundamental ground rules: Software requirement: * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) version 18 or later. * [shfmt](https://github.com/mvdan/sh). +* [black](https://github.com/psf/black) version 25.1.0. -This repository consistently contains an up-to-date `.clang-format` file with rules that match the explained ones and uses shell script formatting supported by `shfmt`. -For maintaining a uniform coding style, execute the command `clang-format -i *.{c,h}` and `shfmt -w $(find . -type f -name "*.sh")`. +To maintain a uniform style across languages, run: +* `clang-format -i *.{c,h}` to apply the project’s C/C++ formatting rules from the up-to-date .clang-format file. +* `shfmt -w $(find . -type f -name "*.sh")` to clean and standardize all shell scripts. +* `black .` to enforce a consistent, idiomatic layout for Python code. ## Coding Style for Shell Script @@ -65,6 +69,19 @@ Shell scripts must be clean, consistent, and portable. The following `shfmt` rul * Add spaces around redirection operators (e.g., `>`, `>>`). * Place binary operators (e.g., `&&`, `|`) on the next line when breaking lines. +## Coding Style for Python + +Python scripts must be clean, consistent, and adhere to modern Python best practices. The following formatting rules are enforced project-wide using `black`: + +* Use 4 spaces for indentation (never tabs). +* Limit lines to 80 characters maximum. +* Use double quotes for strings (unless single quotes avoid escaping). +* Use trailing commas in multi-line constructs. +* Format imports according to PEP 8 guidelines. +* Use Unix-style line endings (LF). +* Remove trailing whitespace at the end of lines. +* Ensure files end with a newline. + ## Coding Style for Modern C This coding style is a variant of the [K&R style](https://en.wikipedia.org/wiki/Indentation_style#K&R). diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..7e468ac0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,4 @@ +[tool.black] +line-length = 80 +target-version = ['py39', 'py310', 'py311','py312','py313'] +include = '\.pyi?$' From 58e975ecc36755ca743f241ffedf5c15e7931705 Mon Sep 17 00:00:00 2001 From: Lzzz666 Date: Thu, 12 Jun 2025 20:18:20 +0800 Subject: [PATCH 2/2] Refactor Python scripts to adhere to the new formatting rules --- tests/arch-test-target/constants.py | 20 +- .../rv32emu/riscof_rv32emu.py | 90 ++++++--- .../sail_cSim/riscof_sail_cSim.py | 164 ++++++++++------ tests/arch-test-target/setup.py | 87 +++++---- tests/bench-aggregator.py | 13 +- tests/coremark.py | 28 ++- tools/gen-elf-list-js.py | 4 +- tools/gen-jit-template.py | 179 +++++++++++------- 8 files changed, 363 insertions(+), 222 deletions(-) diff --git a/tests/arch-test-target/constants.py b/tests/arch-test-target/constants.py index 3761270e..7bc9c48e 100644 --- a/tests/arch-test-target/constants.py +++ b/tests/arch-test-target/constants.py @@ -1,19 +1,19 @@ import os -dutname = 'rv32emu' -refname = 'sail_cSim' +dutname = "rv32emu" +refname = "sail_cSim" root = os.path.abspath(os.path.dirname(__file__)) cwd = os.getcwd() -misa_A = (1 << 0) -misa_C = (1 << 2) -misa_E = (1 << 4) -misa_F = (1 << 5) -misa_I = (1 << 8) -misa_M = (1 << 12) +misa_A = 1 << 0 +misa_C = 1 << 2 +misa_E = 1 << 4 +misa_F = 1 << 5 +misa_I = 1 << 8 +misa_M = 1 << 12 -config_temp = '''[RISCOF] +config_temp = """[RISCOF] ReferencePlugin={0} ReferencePluginPath={1} DUTPlugin={2} @@ -29,4 +29,4 @@ [{0}] pluginpath={1} path={1} -''' +""" diff --git a/tests/arch-test-target/rv32emu/riscof_rv32emu.py b/tests/arch-test-target/rv32emu/riscof_rv32emu.py index 7a0fba68..4907eea6 100644 --- a/tests/arch-test-target/rv32emu/riscof_rv32emu.py +++ b/tests/arch-test-target/rv32emu/riscof_rv32emu.py @@ -15,6 +15,7 @@ logger = logging.getLogger() + class rv32emu(pluginTemplate): __model__ = "rv32emu" __version__ = "dev" @@ -22,7 +23,7 @@ class rv32emu(pluginTemplate): def __init__(self, *args, **kwargs): sclass = super().__init__(*args, **kwargs) - config = kwargs.get('config') + config = kwargs.get("config") # If the config node for this DUT is missing or empty. Raise an error. At minimum we need # the paths to the ispec and pspec files @@ -34,25 +35,27 @@ def __init__(self, *args, **kwargs): # test-bench produced by a simulator (like verilator, vcs, incisive, etc). In case of an iss or # emulator, this variable could point to where the iss binary is located. If 'PATH variable # is missing in the config.ini we can hardcode the alternate here. - self.dut_exe = os.path.join(config['PATH'] if 'PATH' in config else "","rv32emu") + self.dut_exe = os.path.join( + config["PATH"] if "PATH" in config else "", "rv32emu" + ) # Number of parallel jobs that can be spawned off by RISCOF # for various actions performed in later functions, specifically to run the tests in # parallel on the DUT executable. Can also be used in the build function if required. - self.num_jobs = str(config['jobs'] if 'jobs' in config else 1) + self.num_jobs = str(config["jobs"] if "jobs" in config else 1) # Path to the directory where this python file is located. Collect it from the config.ini - self.pluginpath=os.path.abspath(config['pluginpath']) + self.pluginpath = os.path.abspath(config["pluginpath"]) # Collect the paths to the riscv-config absed ISA and platform yaml files. One can choose # to hardcode these here itself instead of picking it from the config.ini file. - self.isa_spec = os.path.abspath(config['ispec']) - self.platform_spec = os.path.abspath(config['pspec']) + self.isa_spec = os.path.abspath(config["ispec"]) + self.platform_spec = os.path.abspath(config["pspec"]) # We capture if the user would like the run the tests on the target or # not. If you are interested in just compiling the tests and not running # them on the target, then following variable should be set to False - if 'target_run' in config and config['target_run']=='0': + if "target_run" in config and config["target_run"] == "0": self.target_run = False else: self.target_run = True @@ -72,36 +75,57 @@ def initialise(self, suite, work_dir, archtest_env): # Note the march is not hardwired here, because it will change for each # test. Similarly the output elf name and compile macros will be assigned later in the # runTests function - self.compile_cmd = os.getenv("CROSS_COMPILE") + 'gcc -march={0}\ + self.compile_cmd = ( + os.getenv("CROSS_COMPILE") + + "gcc -march={0}\ -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -g\ - -T '+self.pluginpath+'/env/link.ld\ - -I '+self.pluginpath+'/env/\ - -I ' + archtest_env + ' {2} -o {3} {4}' + -T " + + self.pluginpath + + "/env/link.ld\ + -I " + + self.pluginpath + + "/env/\ + -I " + + archtest_env + + " {2} -o {3} {4}" + ) def build(self, isa_yaml, platform_yaml): # load the isa yaml as a dictionary in python. - ispec = utils.load_yaml(isa_yaml)['hart0'] + ispec = utils.load_yaml(isa_yaml)["hart0"] # capture the XLEN value by picking the max value in 'supported_xlen' field of isa yaml. This # will be useful in setting integer value in the compiler string (if not already hardcoded); - self.xlen = ('64' if 64 in ispec['supported_xlen'] else '32') - - if 'E' not in ispec['ISA']: - self.compile_cmd = self.compile_cmd+' -mabi='+('lp64 ' if 64 in ispec['supported_xlen'] else 'ilp32 ') + self.xlen = "64" if 64 in ispec["supported_xlen"] else "32" + + if "E" not in ispec["ISA"]: + self.compile_cmd = ( + self.compile_cmd + + " -mabi=" + + ("lp64 " if 64 in ispec["supported_xlen"] else "ilp32 ") + ) else: - self.compile_cmd = self.compile_cmd+' -mabi='+('lp64e ' if 64 in ispec['supported_xlen'] else 'ilp32e ') - self.compile_cmd += '-D RV32E ' + self.compile_cmd = ( + self.compile_cmd + + " -mabi=" + + ("lp64e " if 64 in ispec["supported_xlen"] else "ilp32e ") + ) + self.compile_cmd += "-D RV32E " def runTests(self, testList): # Delete Makefile if it already exists. - if os.path.exists(self.work_dir+ "/Makefile." + self.name[:-1]): - os.remove(self.work_dir+ "/Makefile." + self.name[:-1]) + if os.path.exists(self.work_dir + "/Makefile." + self.name[:-1]): + os.remove(self.work_dir + "/Makefile." + self.name[:-1]) # create an instance the makeUtil class that we will use to create targets. - make = utils.makeUtil(makefilePath=os.path.join(self.work_dir, "Makefile." + self.name[:-1])) + make = utils.makeUtil( + makefilePath=os.path.join( + self.work_dir, "Makefile." + self.name[:-1] + ) + ) # set the make command that will be used. The num_jobs parameter was set in the __init__ # function earlier - make.makeCommand = 'make -j' + self.num_jobs + make.makeCommand = "make -j" + self.num_jobs # we will iterate over each entry in the testList. Each entry node will be refered to by the # variable testname. @@ -110,14 +134,14 @@ def runTests(self, testList): testentry = testList[testname] # we capture the path to the assembly file of this test - test = testentry['test_path'] + test = testentry["test_path"] # capture the directory where the artifacts of this test will be dumped/created. RISCOF is # going to look into this directory for the signature files - test_dir = testentry['work_dir'] + test_dir = testentry["work_dir"] # name of the elf file after compilation of the test - elf = 'my.elf' + elf = "my.elf" # name of the signature file as per requirement of RISCOF. RISCOF expects the signature to # be named as DUT-.signature. The below variable creates an absolute path of @@ -127,22 +151,26 @@ def runTests(self, testList): # for each test there are specific compile macros that need to be enabled. The macros in # the testList node only contain the macros/values. For the gcc toolchain we need to # prefix with "-D". The following does precisely that. - compile_macros = ' -D' + " -D".join(testentry['macros']) + compile_macros = " -D" + " -D".join(testentry["macros"]) # substitute all variables in the compile command that we created in the initialize function - cmd = self.compile_cmd.format(testentry['isa'].lower(), self.xlen, test, elf, compile_macros) + cmd = self.compile_cmd.format( + testentry["isa"].lower(), self.xlen, test, elf, compile_macros + ) - # if the user wants to disable running the tests and only compile the tests, then + # if the user wants to disable running the tests and only compile the tests, then # the "else" clause is executed below assigning the sim command to simple no action # echo statement. if self.target_run: - # set up the simulation command. Template is for spike. Please change. - simcmd = self.dut_exe + ' -a {0} {1}'.format(sig_file, elf) + # set up the simulation command. Template is for spike. Please change. + simcmd = self.dut_exe + " -a {0} {1}".format(sig_file, elf) else: simcmd = 'echo "NO RUN"' # concatenate all commands that need to be executed within a make-target. - execute = '@cd {0}; {1}; {2};'.format(testentry['work_dir'], cmd, simcmd) + execute = "@cd {0}; {1}; {2};".format( + testentry["work_dir"], cmd, simcmd + ) # create a target. The makeutil will create a target with the name "TARGET" where num # starts from 0 and increments automatically for each new target that is added diff --git a/tests/arch-test-target/sail_cSim/riscof_sail_cSim.py b/tests/arch-test-target/sail_cSim/riscof_sail_cSim.py index c1ae8e41..a01c2e0a 100644 --- a/tests/arch-test-target/sail_cSim/riscof_sail_cSim.py +++ b/tests/arch-test-target/sail_cSim/riscof_sail_cSim.py @@ -15,6 +15,7 @@ logger = logging.getLogger() + class sail_cSim(pluginTemplate): __model__ = "sail_c_simulator" __version__ = "0.5.0" @@ -22,109 +23,162 @@ class sail_cSim(pluginTemplate): def __init__(self, *args, **kwargs): sclass = super().__init__(*args, **kwargs) - config = kwargs.get('config') + config = kwargs.get("config") if config is None: logger.error("Config node for sail_cSim missing.") raise SystemExit(1) - self.num_jobs = str(config['jobs'] if 'jobs' in config else 1) - self.pluginpath = os.path.abspath(config['pluginpath']) - self.sail_exe = { '32' : os.path.join(config['PATH'] if 'PATH' in config else "","riscv_sim_RV32"), - '64' : os.path.join(config['PATH'] if 'PATH' in config else "","riscv_sim_RV64")} - self.isa_spec = os.path.abspath(config['ispec']) if 'ispec' in config else '' - self.platform_spec = os.path.abspath(config['pspec']) if 'ispec' in config else '' - self.make = config['make'] if 'make' in config else 'make' - logger.debug("SAIL CSim plugin initialised using the following configuration.") + self.num_jobs = str(config["jobs"] if "jobs" in config else 1) + self.pluginpath = os.path.abspath(config["pluginpath"]) + self.sail_exe = { + "32": os.path.join( + config["PATH"] if "PATH" in config else "", "riscv_sim_RV32" + ), + "64": os.path.join( + config["PATH"] if "PATH" in config else "", "riscv_sim_RV64" + ), + } + self.isa_spec = ( + os.path.abspath(config["ispec"]) if "ispec" in config else "" + ) + self.platform_spec = ( + os.path.abspath(config["pspec"]) if "ispec" in config else "" + ) + self.make = config["make"] if "make" in config else "make" + logger.debug( + "SAIL CSim plugin initialised using the following configuration." + ) for entry in config: - logger.debug(entry+' : '+config[entry]) + logger.debug(entry + " : " + config[entry]) return sclass def initialise(self, suite, work_dir, archtest_env): self.suite = suite self.work_dir = work_dir - self.objdump_cmd = os.getenv("CROSS_COMPILE") + 'objdump -D {0} > {2};' - self.compile_cmd = os.getenv("CROSS_COMPILE") + 'gcc -march={0} \ + self.objdump_cmd = os.getenv("CROSS_COMPILE") + "objdump -D {0} > {2};" + self.compile_cmd = ( + os.getenv("CROSS_COMPILE") + + "gcc -march={0} \ -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles\ - -T '+self.pluginpath+'/env/link.ld\ - -I '+self.pluginpath+'/env/\ - -I ' + archtest_env + -T " + + self.pluginpath + + "/env/link.ld\ + -I " + + self.pluginpath + + "/env/\ + -I " + + archtest_env + ) def build(self, isa_yaml, platform_yaml): - ispec = utils.load_yaml(isa_yaml)['hart0'] - self.xlen = ('64' if 64 in ispec['supported_xlen'] else '32') - self.isa = 'rv' + self.xlen - if 'E' not in ispec['ISA']: - self.compile_cmd = self.compile_cmd+' -mabi='+('lp64 ' if 64 in ispec['supported_xlen'] else 'ilp32 ') + ispec = utils.load_yaml(isa_yaml)["hart0"] + self.xlen = "64" if 64 in ispec["supported_xlen"] else "32" + self.isa = "rv" + self.xlen + if "E" not in ispec["ISA"]: + self.compile_cmd = ( + self.compile_cmd + + " -mabi=" + + ("lp64 " if 64 in ispec["supported_xlen"] else "ilp32 ") + ) else: - self.compile_cmd = self.compile_cmd+' -mabi='+('lp64e ' if 64 in ispec['supported_xlen'] else 'ilp32e ') + self.compile_cmd = ( + self.compile_cmd + + " -mabi=" + + ("lp64e " if 64 in ispec["supported_xlen"] else "ilp32e ") + ) self.compile_cmd += "-D RV32E " if "I" in ispec["ISA"]: - self.isa += 'i' + self.isa += "i" if "E" in ispec["ISA"]: - self.isa += 'e' + self.isa += "e" if "M" in ispec["ISA"]: - self.isa += 'm' + self.isa += "m" if "C" in ispec["ISA"]: - self.isa += 'c' + self.isa += "c" if "F" in ispec["ISA"]: - self.isa += 'f' + self.isa += "f" if "D" in ispec["ISA"]: - self.isa += 'd' + self.isa += "d" objdump = os.getenv("CROSS_COMPILE") + "objdump".format(self.xlen) if shutil.which(objdump) is None: - logger.error(objdump+": executable not found. Please check environment setup.") + logger.error( + objdump + + ": executable not found. Please check environment setup." + ) raise SystemExit(1) compiler = os.getenv("CROSS_COMPILE") + "gcc".format(self.xlen) if shutil.which(compiler) is None: - logger.error(compiler+": executable not found. Please check environment setup.") + logger.error( + compiler + + ": executable not found. Please check environment setup." + ) raise SystemExit(1) if shutil.which(self.sail_exe[self.xlen]) is None: - logger.error(self.sail_exe[self.xlen]+ ": executable not found. Please check environment setup.") + logger.error( + self.sail_exe[self.xlen] + + ": executable not found. Please check environment setup." + ) raise SystemExit(1) if shutil.which(self.make) is None: - logger.error(self.make+": executable not found. Please check environment setup.") + logger.error( + self.make + + ": executable not found. Please check environment setup." + ) raise SystemExit(1) - def runTests(self, testList, cgf_file=None): - if os.path.exists(self.work_dir+ "/Makefile." + self.name[:-1]): - os.remove(self.work_dir+ "/Makefile." + self.name[:-1]) - make = utils.makeUtil(makefilePath=os.path.join(self.work_dir, "Makefile." + self.name[:-1])) - make.makeCommand = self.make + ' -j' + self.num_jobs + if os.path.exists(self.work_dir + "/Makefile." + self.name[:-1]): + os.remove(self.work_dir + "/Makefile." + self.name[:-1]) + make = utils.makeUtil( + makefilePath=os.path.join( + self.work_dir, "Makefile." + self.name[:-1] + ) + ) + make.makeCommand = self.make + " -j" + self.num_jobs for file in testList: testentry = testList[file] - test = testentry['test_path'] - test_dir = testentry['work_dir'] - test_name = test.rsplit('/',1)[1][:-2] + test = testentry["test_path"] + test_dir = testentry["work_dir"] + test_name = test.rsplit("/", 1)[1][:-2] - elf = 'ref.elf' + elf = "ref.elf" - execute = "@cd "+testentry['work_dir']+";" + execute = "@cd " + testentry["work_dir"] + ";" - cmd = self.compile_cmd.format(testentry['isa'].lower(), self.xlen) + ' ' + test + ' -o ' + elf - compile_cmd = cmd + ' -D' + " -D".join(testentry['macros']) - execute+=compile_cmd+";" + cmd = ( + self.compile_cmd.format(testentry["isa"].lower(), self.xlen) + + " " + + test + + " -o " + + elf + ) + compile_cmd = cmd + " -D" + " -D".join(testentry["macros"]) + execute += compile_cmd + ";" - execute += self.objdump_cmd.format(elf, self.xlen, 'ref.disass') + execute += self.objdump_cmd.format(elf, self.xlen, "ref.disass") sig_file = os.path.join(test_dir, self.name[:-1] + ".signature") - execute += self.sail_exe[self.xlen] + ' --test-signature={0} {1} > {2}.log 2>&1;'.format(sig_file, elf, test_name) + execute += self.sail_exe[ + self.xlen + ] + " --test-signature={0} {1} > {2}.log 2>&1;".format( + sig_file, elf, test_name + ) - cov_str = ' ' - for label in testentry['coverage_labels']: - cov_str+=' -l '+label + cov_str = " " + for label in testentry["coverage_labels"]: + cov_str += " -l " + label if cgf_file is not None: - coverage_cmd = 'riscv_isac --verbose info coverage -d \ + coverage_cmd = "riscv_isac --verbose info coverage -d \ -t {0}.log --parser-name c_sail -o coverage.rpt \ --sig-label begin_signature end_signature \ --test-label rvtest_code_begin rvtest_code_end \ - -e ref.elf -c {1} -x{2} {3};'.format(\ - test_name, ' -c '.join(cgf_file), self.xlen, cov_str) + -e ref.elf -c {1} -x{2} {3};".format( + test_name, " -c ".join(cgf_file), self.xlen, cov_str + ) else: - coverage_cmd = '' - + coverage_cmd = "" - execute+=coverage_cmd + execute += coverage_cmd make.add_target(execute) make.execute_all(self.work_dir) diff --git a/tests/arch-test-target/setup.py b/tests/arch-test-target/setup.py index f7c718ef..0f682653 100644 --- a/tests/arch-test-target/setup.py +++ b/tests/arch-test-target/setup.py @@ -2,62 +2,64 @@ import argparse import ruamel.yaml + # setup the ISA config file def setup_testlist(riscv_device, hw_data_misaligned_support): # ISA config file path - ispec = constants.root + '/rv32emu/rv32emu_isa.yaml' + ispec = constants.root + "/rv32emu/rv32emu_isa.yaml" misa = 0x40000000 - ISA = 'RV32' + ISA = "RV32" if not riscv_device: - raise AssertionError('There is not any ISA.') + raise AssertionError("There is not any ISA.") - if 'E' in riscv_device: + if "E" in riscv_device: misa |= constants.misa_E - ISA += 'E' + ISA += "E" else: misa |= constants.misa_I - ISA += 'I' - if 'M' in riscv_device: + ISA += "I" + if "M" in riscv_device: misa |= constants.misa_M - ISA += 'M' - if 'A' in riscv_device: + ISA += "M" + if "A" in riscv_device: misa |= constants.misa_A - ISA += 'A' - if 'F' in riscv_device: + ISA += "A" + if "F" in riscv_device: misa |= constants.misa_F - ISA += 'F' - if 'C' in riscv_device: + ISA += "F" + if "C" in riscv_device: misa |= constants.misa_C - ISA += 'C' - if 'Zba' in riscv_device: - ISA += '_Zba' if 'Z' in ISA else 'Zba' - if 'Zbb' in riscv_device: - ISA += '_Zbb' if 'Z' in ISA else 'Zbb' - if 'Zbc' in riscv_device: - ISA += '_Zbc' if 'Z' in ISA else 'Zbc' - if 'Zbs' in riscv_device: - ISA += '_Zbs' if 'Z' in ISA else 'Zbs' - if 'Zicsr' in riscv_device: - ISA += '_Zicsr' if 'Z' in ISA else 'Zicsr' - if 'Zifencei' in riscv_device: - ISA += '_Zifencei' if 'Z' in ISA else 'Zifencei' - - with open(ispec, 'r') as file: + ISA += "C" + if "Zba" in riscv_device: + ISA += "_Zba" if "Z" in ISA else "Zba" + if "Zbb" in riscv_device: + ISA += "_Zbb" if "Z" in ISA else "Zbb" + if "Zbc" in riscv_device: + ISA += "_Zbc" if "Z" in ISA else "Zbc" + if "Zbs" in riscv_device: + ISA += "_Zbs" if "Z" in ISA else "Zbs" + if "Zicsr" in riscv_device: + ISA += "_Zicsr" if "Z" in ISA else "Zicsr" + if "Zifencei" in riscv_device: + ISA += "_Zifencei" if "Z" in ISA else "Zifencei" + + with open(ispec, "r") as file: try: - file = ruamel.yaml.YAML(typ='safe', pure=True).load(file) + file = ruamel.yaml.YAML(typ="safe", pure=True).load(file) except ruamel.yaml.YAMLError as msg: print(msg) raise SystemExit(1) - file['hart0']['ISA'] = ISA - file['hart0']['hw_data_misaligned_support'] = ( + file["hart0"]["ISA"] = ISA + file["hart0"]["hw_data_misaligned_support"] = ( True if hw_data_misaligned_support == "1" else False ) - file['hart0']['misa']['reset-val'] = misa + file["hart0"]["misa"]["reset-val"] = misa + + with open(ispec, "w+") as outfile: + ruamel.yaml.YAML(typ="unsafe", pure=True).dump(file, outfile) - with open(ispec, 'w+') as outfile: - ruamel.yaml.YAML(typ='unsafe', pure=True).dump(file, outfile) # setup the riscof config file def setup_config(): @@ -67,15 +69,20 @@ def setup_config(): dutname = constants.dutname # create config file - configfile = open(root + '/config.ini','w') - configfile.write(constants.config_temp.format(refname, \ - root+'/'+refname, dutname, root+'/'+dutname, cwd)) + configfile = open(root + "/config.ini", "w") + configfile.write( + constants.config_temp.format( + refname, root + "/" + refname, dutname, root + "/" + dutname, cwd + ) + ) configfile.close() -if __name__=="__main__": + +if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('--riscv_device', help='the ISA will test', - default='IMACZicsrZifencei') + parser.add_argument( + "--riscv_device", help="the ISA will test", default="IMACZicsrZifencei" + ) parser.add_argument( "--hw_data_misaligned_support", help="whether the hardware data misalgnment is implemented or not", diff --git a/tests/bench-aggregator.py b/tests/bench-aggregator.py index e3ba8430..c8242671 100755 --- a/tests/bench-aggregator.py +++ b/tests/bench-aggregator.py @@ -3,6 +3,7 @@ import json import subprocess + def run_benchmark(b): interp = None if "sh" in b: @@ -12,23 +13,19 @@ def run_benchmark(b): subprocess.run(args=[interp, b], shell=False, check=True) + def load_benchmark(file): f = open(file, "r") return json.load(f) + # run benchmarks -benchmarks = [ - "tests/dhrystone.sh", - "tests/coremark.py" -] +benchmarks = ["tests/dhrystone.sh", "tests/coremark.py"] for b in benchmarks: run_benchmark(b) # combine benchmarks output data -benchmarks_output = [ - "dhrystone_output.json", - "coremark_output.json" -] +benchmarks_output = ["dhrystone_output.json", "coremark_output.json"] benchmark_data = [load_benchmark(bo) for bo in benchmarks_output] benchmark_output = "benchmark_output.json" diff --git a/tests/coremark.py b/tests/coremark.py index a759a9e9..6c75a8d8 100755 --- a/tests/coremark.py +++ b/tests/coremark.py @@ -8,13 +8,14 @@ iter = 1 coremark_param = "0x0 0x0 0x66 30000 7 1 2000" res = [] -file_exist = os.path.exists('build/rv32emu') +file_exist = os.path.exists("build/rv32emu") if not file_exist: print("Please compile before running test") exit(1) print("Start Test CoreMark benchmark") comp_proc = subprocess.check_output( - "build/rv32emu build/riscv32/coremark {}".format(coremark_param), shell=True).decode("utf-8") + "build/rv32emu build/riscv32/coremark {}".format(coremark_param), shell=True +).decode("utf-8") if not comp_proc or comp_proc.find("Error") != -1: print("Test Error") exit(1) @@ -24,28 +25,35 @@ for i in range(iter): print("Running CoreMark benchmark - Run #{}".format(i + 1)) comp_proc = subprocess.check_output( - "build/rv32emu build/riscv32/coremark {}".format(coremark_param), shell=True).decode("utf-8") + "build/rv32emu build/riscv32/coremark {}".format(coremark_param), + shell=True, + ).decode("utf-8") if not comp_proc: print("Fail\n") exit(1) else: - res.append(float(re.findall( - r'Iterations/Sec : [0-9]+.[0-9]+', comp_proc)[0][19:])) + res.append( + float( + re.findall(r"Iterations/Sec : [0-9]+.[0-9]+", comp_proc)[0][ + 19: + ] + ) + ) mean = numpy.mean(res, dtype=numpy.float64) deviation = numpy.std(res, dtype=numpy.float64) for n in res: - if (abs(n - mean) > (deviation * 2)): + if abs(n - mean) > (deviation * 2): res.remove(n) print("{:.3f}".format(numpy.mean(res, dtype=numpy.float64))) -#save Average Iterations/Sec in JSON format for benchmark action workflow +# save Average Iterations/Sec in JSON format for benchmark action workflow benchmark_output = "coremark_output.json" benchmark_data = { - "name":"Coremark", - "unit":"Average iterations/sec over 10 runs", - "value":float("{:.3f}".format(numpy.mean(res, dtype=numpy.float64))) + "name": "Coremark", + "unit": "Average iterations/sec over 10 runs", + "value": float("{:.3f}".format(numpy.mean(res, dtype=numpy.float64))), } f = open(benchmark_output, "w") f.write(json.dumps(benchmark_data)) diff --git a/tools/gen-elf-list-js.py b/tools/gen-elf-list-js.py index 213b2259..d5ccbe5c 100755 --- a/tools/gen-elf-list-js.py +++ b/tools/gen-elf-list-js.py @@ -13,7 +13,9 @@ def list_files(d, ignore_list=None): for f in os.listdir(d) if os.path.isfile(os.path.join(d, f)) and f.endswith(".elf") - and not any(f.endswith(ign) or f.startswith(ign) for ign in ignore_list) + and not any( + f.endswith(ign) or f.startswith(ign) for ign in ignore_list + ) ] else: parent_dir = os.path.dirname(d) diff --git a/tools/gen-jit-template.py b/tools/gen-jit-template.py index 3318bc76..6ee1edc1 100755 --- a/tools/gen-jit-template.py +++ b/tools/gen-jit-template.py @@ -1,32 +1,18 @@ #!/usr/bin/env python3 -''' +""" This script serves as a code generator for creating JIT code templates based on existing code files in the 'src' directory, eliminating the need for writing duplicated code. -''' +""" import re import sys INSN = { "Zifencei": ["fencei"], - "Zicsr": [ - "csrrw", - "csrrs", - "csrrc", - "csrrwi", - "csrrsi", - "csrrci"], - "EXT_M": [ - "mul", - "mulh", - "mulhsu", - "mulhu", - "div", - "divu", - "rem", - "remu"], + "Zicsr": ["csrrw", "csrrs", "csrrc", "csrrwi", "csrrsi", "csrrci"], + "EXT_M": ["mul", "mulh", "mulhsu", "mulhu", "div", "divu", "rem", "remu"], "EXT_A": [ "lrw", "scw", @@ -38,7 +24,8 @@ "amominw", "amomaxw", "amominuw", - "amomaxuw"], + "amomaxuw", + ], "EXT_F": [ "flw", "fsw", @@ -65,7 +52,8 @@ "fclasss", "fcvtsw", "fcvtswu", - "fmvwx"], + "fmvwx", + ], "EXT_C": [ "caddi4spn", "clw", @@ -143,7 +131,19 @@ "bclr", ], } -EXT_LIST = ["Zifencei", "Zicsr", "EXT_M", "EXT_A", "EXT_F", "EXT_C", "SYSTEM", "Zba", "Zbb", "Zbc", "Zbs"] +EXT_LIST = [ + "Zifencei", + "Zicsr", + "EXT_M", + "EXT_A", + "EXT_F", + "EXT_C", + "SYSTEM", + "Zba", + "Zbb", + "Zbc", + "Zbs", +] SKIP_LIST = [] # check enabled extension in Makefile @@ -151,7 +151,7 @@ def parse_argv(EXT_LIST, SKIP_LIST): for argv in sys.argv: if argv.find("RV32_FEATURE_") != -1: - ext = argv[argv.find("RV32_FEATURE_") + 13:-2] + ext = argv[argv.find("RV32_FEATURE_") + 13 : -2] if argv[-1:] == "1" and EXT_LIST.count(ext): EXT_LIST.remove(ext) for ext in EXT_LIST: @@ -159,37 +159,47 @@ def parse_argv(EXT_LIST, SKIP_LIST): if "EXT_F" in EXT_LIST or "EXT_C" in EXT_LIST: SKIP_LIST += INSN["EXT_FC"] + parse_argv(EXT_LIST, SKIP_LIST) # prepare PROLOGUE output = "" -f = open('src/rv32_template.c', 'r') +f = open("src/rv32_template.c", "r") lines = f.read() # remove_comment -lines = re.sub(r'/\*[\s|\S]+?\*/', "", lines) +lines = re.sub(r"/\*[\s|\S]+?\*/", "", lines) # remove exception handler -lines = re.sub(r'RV_EXC[\S]+?\([\S|\s]+?\);\s', "", lines) +lines = re.sub(r"RV_EXC[\S]+?\([\S|\s]+?\);\s", "", lines) # collect functions -emulate_funcs = re.findall(r'RVOP\([\s|\S]+?}\)', lines) -codegen_funcs = re.findall(r'GEN\([\s|\S]+?}\)', lines) +emulate_funcs = re.findall(r"RVOP\([\s|\S]+?}\)", lines) +codegen_funcs = re.findall(r"GEN\([\s|\S]+?}\)", lines) op = [] impl = [] for i in range(len(emulate_funcs)): - op.append(emulate_funcs[i][5:emulate_funcs[i].find(',')].strip()) + op.append(emulate_funcs[i][5 : emulate_funcs[i].find(",")].strip()) impl.append(codegen_funcs[i]) f.close() -fields = {"imm", "pc", "rs1", "rs2", "rd", "shamt", "branch_taken", "branch_untaken"} +fields = { + "imm", + "pc", + "rs1", + "rs2", + "rd", + "shamt", + "branch_taken", + "branch_untaken", +} virt_regs = {"VR0", "VR1", "VR2"} # generate jit template for i in range(len(op)): - if (not SKIP_LIST.count(op[i])): + if not SKIP_LIST.count(op[i]): output += impl[i][0:4] + op[i] + ", {" - IRs = re.findall(r'[\s|\S]+?;', impl[i][5:]) + IRs = re.findall(r"[\s|\S]+?;", impl[i][5:]) # parse_and_translate_IRs for i in range(len(IRs)): IR = IRs[i].strip()[:-1] - items = [s.strip() for s in IR.split(',')] + items = [s.strip() for s in IR.split(",")] asm = "" for i in range(len(items)): if items[i] in fields: @@ -197,87 +207,118 @@ def parse_argv(EXT_LIST, SKIP_LIST): if items[i] in virt_regs: items[i] = "vm_reg[" + items[i][-1] + "]" if items[i] == "TMP": - items[i] = "temp_reg" + items[i] = "temp_reg" if items[0] == "alu32imm": if len(items) == 8: asm = "emit_alu32_imm{}(state, {}, {}, {}, ({}{}_t) {});".format( - items[1], items[2], items[3], items[4], items[5], items[6], items[7]) + items[1], + items[2], + items[3], + items[4], + items[5], + items[6], + items[7], + ) elif len(items) == 7: - asm = "emit_alu32_imm{}(state, {}, {}, {}, {} & {});".format( - items[1], items[2], items[3], items[4], items[5], items[6]) + asm = ( + "emit_alu32_imm{}(state, {}, {}, {}, {} & {});".format( + items[1], + items[2], + items[3], + items[4], + items[5], + items[6], + ) + ) else: asm = "emit_alu32_imm{}(state, {}, {}, {}, {});".format( - items[1], items[2], items[3], items[4], items[5]) + items[1], items[2], items[3], items[4], items[5] + ) elif items[0] == "alu64imm": asm = "emit_alu64_imm{}(state, {}, {}, {}, {});".format( - items[1], items[2], items[3], items[4], items[5]) + items[1], items[2], items[3], items[4], items[5] + ) elif items[0] == "alu64": asm = "emit_alu64(state, {}, {}, {});".format( - items[1], items[2], items[3]) + items[1], items[2], items[3] + ) elif items[0] == "alu32": asm = "emit_alu32(state, {}, {}, {});".format( - items[1], items[2], items[3]) + items[1], items[2], items[3] + ) elif items[0] == "ldimm": if len(items) == 4: asm = "emit_load_imm(state, {}, {} + {});".format( - items[1], items[2], items[3]) + items[1], items[2], items[3] + ) else: asm = "emit_load_imm(state, {}, {});".format( - items[1], items[2]) + items[1], items[2] + ) elif items[0] == "ldimms": if items[2] == "mem": asm = "emit_load_imm_sext(state, {}, (intptr_t) (m->mem_base + ir->imm));".format( - items[1]) + items[1] + ) elif len(items) == 4: asm = "emit_load_imm_sext(state, {}, {} + {});".format( - items[1], items[2], items[3]) + items[1], items[2], items[3] + ) else: asm = "emit_load_imm_sext(state, {}, {});".format( - items[1], items[2]) + items[1], items[2] + ) elif items[0] == "lds": - if (items[3] == "X"): + if items[3] == "X": asm = "emit_load_sext(state, {}, parameter_reg[0], {}, offsetof(riscv_t, X) + 4 * {});".format( - items[1], items[2], items[4]) + items[1], items[2], items[4] + ) else: asm = "emit_load_sext(state, {}, {}, {}, {});".format( - items[1], items[2], items[3], items[4]) + items[1], items[2], items[3], items[4] + ) elif items[0] == "rald": asm = "{} = ra_load(state, {});".format(items[1], items[2]) elif items[0] == "rald2": asm = "ra_load2(state, {}, {});".format(items[1], items[2]) elif items[0] == "rald2s": - asm = "ra_load2_sext(state, {}, {}, {}, {});".format(items[1], items[2], items[3], items[4]) + asm = "ra_load2_sext(state, {}, {}, {}, {});".format( + items[1], items[2], items[3], items[4] + ) elif items[0] == "map": asm = "{} = map_vm_reg(state, {});".format(items[1], items[2]) elif items[0] == "ld": - if (items[3] == "X"): + if items[3] == "X": asm = "emit_load(state, {}, parameter_reg[0], {}, offsetof(riscv_t, X) + 4 * {});".format( - items[1], items[2], items[4]) + items[1], items[2], items[4] + ) else: asm = "emit_load(state, {}, {}, {}, {});".format( - items[1], items[2], items[3], items[4]) + items[1], items[2], items[3], items[4] + ) elif items[0] == "st": - if (items[3] == "X"): + if items[3] == "X": asm = "emit_store(state, {}, {}, parameter_reg[0], offsetof(riscv_t, X) + 4 * {});".format( - items[1], items[2], items[4]) + items[1], items[2], items[4] + ) elif items[3] == "PC" or items[3] == "compressed": asm = "emit_store(state, {}, {}, parameter_reg[0], offsetof(riscv_t, {}));".format( - items[1], items[2], items[3]) + items[1], items[2], items[3] + ) else: asm = "emit_store(state, {}, {}, {}, {});".format( - items[1], items[2], items[3], items[4]) + items[1], items[2], items[3], items[4] + ) elif items[0] == "mov": - asm = "emit_mov(state, {}, {});".format( - items[1], items[2]) + asm = "emit_mov(state, {}, {});".format(items[1], items[2]) elif items[0] == "cmp": - asm = "emit_cmp32(state, {}, {});".format( - items[1], items[2]) + asm = "emit_cmp32(state, {}, {});".format(items[1], items[2]) elif items[0] == "cmpimm": asm = "emit_cmp_imm32(state, {}, {});".format( - items[1], items[2]) + items[1], items[2] + ) elif items[0] == "jmp": - asm = "emit_jmp(state, {} + {});".format( - items[1], items[2]) + asm = "emit_jmp(state, {} + {});".format(items[1], items[2]) elif items[0] == "jcc": asm = "emit_jcc_offset(state, {});".format(items[1]) elif items[0] == "setjmpoff": @@ -288,18 +329,22 @@ def parse_argv(EXT_LIST, SKIP_LIST): asm = "memory_t *m = PRIV(rv)->mem;" elif items[0] == "call": asm = "emit_call(state, (intptr_t) rv->io.on_{});".format( - items[1]) + items[1] + ) elif items[0] == "exit": asm = "emit_exit(state);" elif items[0] == "mul": asm = "muldivmod(state, {}, {}, {}, {});".format( - items[1], items[2], items[3], items[4]) + items[1], items[2], items[3], items[4] + ) elif items[0] == "div": asm = "muldivmod(state, {}, {}, {}, {});".format( - items[1], items[2], items[3], items[4]) + items[1], items[2], items[3], items[4] + ) elif items[0] == "mod": asm = "muldivmod(state, {}, {}, {}, {});".format( - items[1], items[2], items[3], items[4]) + items[1], items[2], items[3], items[4] + ) elif items[0] == "cond": if items[1] == "regneq": items[1] = "vm_reg[0] != vm_reg[1]"