├── .git_hooks ├── pre-commit └── setup.sh ├── .github └── workflows │ ├── main.yml │ └── test.yml ├── .gitignore ├── .gitlab-ci.yml ├── CHANGELOG.md ├── CONTRIBUTING.rst ├── LICENSE.incore ├── MANIFEST.in ├── README.rst ├── docs ├── Makefile ├── README.md ├── requirements.txt ├── source │ ├── Cross_coverage.rst │ ├── _static │ │ ├── custom.css │ │ ├── incore_logo.png │ │ ├── l1cache.png │ │ ├── onlyC.png │ │ ├── riscv-isac.png │ │ └── theme_overrides.css │ ├── _templates │ │ ├── breadcrumbs.html │ │ ├── layout.html │ │ └── versions.html │ ├── add_instr.rst │ ├── cgf.rst │ ├── code.rst │ ├── conf.py │ ├── contributing.rst │ ├── diagrams │ │ └── git_flow.png │ ├── dpr.rst │ ├── index.rst │ ├── index_bkp │ ├── isac_cov_calc.rst │ ├── licensing.rst │ ├── overview.rst │ ├── pseudo_op_support.rst │ ├── python_plugins.rst │ ├── quickstart.rst │ ├── refs.bib │ ├── revisions.rst │ └── rvopcodesdecoder.rst └── sphinxext │ └── cairosvgconverter.py ├── interface.py ├── riscv_isac ├── InstructionObject.py ├── __init__.py ├── cgf_normalize.py ├── constants.py ├── coverage.py ├── data │ ├── __init__.py │ ├── constants.py │ ├── instr_alias.yaml │ └── rvopcodesdecoder.py ├── fp_dataset.py ├── isac.py ├── log.py ├── main.py ├── plugins │ ├── __init__.py │ ├── c_sail.py │ ├── internaldecoder.py │ ├── specification.py │ ├── spike.py │ └── translator_cgf.py ├── requirements.txt ├── test_requirements.txt └── utils.py ├── setup.cfg ├── setup.py └── tests ├── __init__.py └── test_riscv_isac.py /.git_hooks/pre-commit: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | #!/bin/bash 3 | 4 | ### Pre Commit Hook For riscv_ctg codebase 5 | status=0; 6 | ### Check for Dependencies 7 | yapf --help 8 | status=$?; 9 | if [ $status -ne 0 ]; then 10 | echo "Please install yapf from :: https://github.com/google/yapf " 11 | exit $status; 12 | fi 13 | 14 | ### Hook Script Body 15 | echo "Running Pre-Commit YAPF Hook"; 16 | 17 | files=`git diff --cached --name-status | awk '$1 != "D" { print $2 }'` 18 | 19 | echo "$files" 20 | 21 | 22 | for f in $files 23 | do 24 | if [[ $f == *.py ]]; then 25 | echo "Formatting $f using YAPF." 26 | yapf -i --style google $f 27 | git add $f 28 | fi 29 | done 30 | 31 | status=$?; 32 | exit $status; 33 | -------------------------------------------------------------------------------- /.git_hooks/setup.sh: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | 3 | #!/usr/bin/env bash 4 | 5 | # Setup the git hooks 6 | echo "Setting up git-hooks" 7 | echo "====================" 8 | 9 | echo "Launched from" $(pwd) 10 | echo "" 11 | 12 | echo "Setting up pre-commit" 13 | ln -s -f ../../.git_hooks/pre-commit ./.git/hooks/pre-commit 14 | chmod a+x ./.git/hooks/pre-commit 15 | echo "Done" 16 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | push: 9 | branches: [ master ] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 15 | jobs: 16 | # This workflow contains a single job called "build" 17 | build: 18 | # The type of runner that the job will run on 19 | runs-on: ubuntu-latest 20 | 21 | # Steps represent a sequence of tasks that will be executed as part of the job 22 | steps: 23 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 24 | - uses: actions/checkout@v2 25 | 26 | - name: Get version 27 | id: get_version 28 | run: | 29 | echo "::set-output name=version::$(grep -P -o '(?<=## \[).*(?=\])' -m1 CHANGELOG.md)" 30 | 31 | - name: Set up Python 32 | uses: actions/setup-python@v2 33 | with: 34 | python-version: '3.7' 35 | 36 | - name: Install dependencies 37 | run: | 38 | pip install -r riscv_isac/requirements.txt 39 | python -m pip install --upgrade pip 40 | pip install setuptools wheel twine 41 | 42 | - name: Publish package 43 | if: github.ref == 'refs/heads/master' 44 | env: 45 | TWINE_USERNAME: ${{ secrets.PYPIUSERNAME }} 46 | TWINE_PASSWORD: ${{ secrets.PYPIPASSWORD }} 47 | run: | 48 | python setup.py sdist bdist_wheel 49 | twine upload dist/* 50 | 51 | 52 | - name: Extract release notes 53 | id: extract-release-notes 54 | if: github.ref == 'refs/heads/master' 55 | uses: ffurrer2/extract-release-notes@v1 56 | 57 | - name: Tag 58 | if: github.ref == 'refs/heads/master' 59 | run: | 60 | git tag ${{ steps.get_version.outputs.version }} 61 | git push origin ${{ steps.get_version.outputs.version }} 62 | 63 | - name: Create Release 64 | id: create_release 65 | if: github.ref == 'refs/heads/master' 66 | uses: actions/create-release@v1 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token 69 | with: 70 | release_branch: refs/heads/master 71 | release_name: ${{ steps.get_version.outputs.version }} 72 | tag_name: ${{ steps.get_version.outputs.version }} 73 | body: ${{ steps.extract-release-notes.outputs.release_notes }} 74 | draft: false 75 | prerelease: false 76 | 77 | # - name: Script 78 | # uses: ammaraskar/sphinx-action@master 79 | # with: 80 | # docs-folder: "docs/" 81 | # pre-build-command: " apt-get update -y && apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended" 82 | # build-command: " make latexpdf " 83 | 84 | 85 | # - name: Upload Release Asset 86 | # id: upload-release-asset 87 | # if: github.ref == 'refs/heads/master' 88 | # uses: actions/upload-release-asset@v1 89 | # env: 90 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 91 | # with: 92 | # upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 93 | # asset_path: ./docs/build/latex/riscv_config.pdf 94 | # asset_name: riscv_config.pdf 95 | # asset_content_type: application/pdf 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: test 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | pull_request: 9 | branches: [ master ] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 15 | jobs: 16 | check-version: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: version check 22 | run: | 23 | export CHNGVER=$(grep -P -o '(?<=## \[).*(?=\])' -m1 CHANGELOG.md); 24 | echo "CHANGELOG VERSION: $CHNGVER" 25 | export INITVER=$(grep -P "__version__ = '.*?'" riscv_isac/__init__.py | awk '{print $3}'|sed "s/'//g"); 26 | echo "INIT VERSION: $INITVER" 27 | if [ "$CHNGVER" = "$INITVER" ]; then 28 | echo "Versions are equal in Changelog and init.py." 29 | else 30 | echo "Versions are not equal in Changelog and init.py." 31 | exit 1 32 | fi 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | .spyproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | 98 | # mkdocs documentation 99 | /site 100 | 101 | # mypy 102 | .mypy_cache/ 103 | 104 | # IDE settings 105 | .vscode/ -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: python:3.7-alpine 2 | stages: 3 | - pre-merge 4 | - deploy 5 | 6 | pre-merge: 7 | stage: pre-merge 8 | script: 9 | - pip install -r riscv_isac/requirements.txt 10 | - pip install --editable . 11 | - riscv_isac --help 12 | - riscv_isac coverage --help 13 | - riscv_isac merge --help 14 | - cd tests/ 15 | - pytest test_riscv_isac.py -v 16 | 17 | only: 18 | refs: 19 | - merge_requests 20 | 21 | deploy: 22 | stage: deploy 23 | script: 24 | - pip install twine 25 | - python setup.py sdist 26 | - python -m twine upload --username $pypiusername --password $pypipassword dist/* 27 | - python /scratch/version-extract-rst.py 28 | only: 29 | refs: 30 | - master 31 | tags: 32 | - incore-group 33 | except: 34 | - schedules 35 | 36 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 4 | 5 | Please note the header `WIP-DEV` is to always remain indicating the changes done on the dev branch. 6 | Only when a release to the main branch is done, the contents of the WIP-DEV are put under a 7 | versioned header while the `WIP-DEV` is left empty 8 | 9 | ## [WIP-DEV] 10 | - Updating CONTRIBUTING.rst to capture the new git strategy adopted to follow a monthly release 11 | cadence. 12 | - Add pluggy to install\_requires and move pytest to tests\_requirements.txt 13 | - Added `pmpaddr0` to `pmpaddr15` registers for coverage of Physical Memory Protection 14 | - Minor fix to compressed immediate decoding and compressed register decoding 15 | - Modified the regular expression to correctly match and return 'reg_commit' for registers x1 to x9. 16 | - Changed compressed immediate decoding and added comments for readability 17 | 18 | ## [0.18.0] - 2023-07-26 19 | - Add support to decode compressed instructions 20 | 21 | ## [0.17.0] - 2022-10-25 22 | - Improve data propagation reports to capture multiple signature updates per coverpoint 23 | - Add a CLI flag to explicitly log the redundant coverpoints while normalizing the CGF files 24 | 25 | ## [0.16.1] - 2022-10-20 26 | - Fix length of commitval to 32 bits if flen is 32 for f registers in sail parser. 27 | 28 | ## [0.16.0] - 2022-09-28 29 | - Refactored the instruction object class 30 | 31 | ## [0.15.0] - 2022-08-25 32 | - Added support for instruction aliases 33 | 34 | ## [0.14.0] - 2022-08-08 35 | - Add fields to instruction object 36 | - Enable generic coverage evaluation mechanisms for floating point instructions 37 | - Fix coverpoint generation to account for nan boxing of fp instructions. 38 | - Add fields(frm, fcsr, nan_prefix) for fp instructions 39 | 40 | ## [0.13.2] - 2022-05-23 41 | - Error reporting for missing coverlabel in cgf file 42 | 43 | ## [0.13.1] - 2022-05-07 44 | - Fix mistune version for doc builds. 45 | 46 | ## [0.13.0] - 2022-05-02 47 | - Covergroup format revised. 48 | - Added support for Pseudoinstructions for coverage computation. 49 | 50 | ## [0.12.0] - 2022-04-15 51 | - Parallelized coverage computation. 52 | - Added feature to remove coverpoints when hit. 53 | - Added CLI option to specify number of processes to be spawned. 54 | - Added CLI option to turn on/off feature to remove hit coverpoints. 55 | 56 | ## [0.11.0] - 2022-04-03 57 | - Added plugins to use new rvopcode format 58 | - Added CLI option to setup rvopcode plugin 59 | 60 | ## [0.10.2] - 2022-03-15 61 | - Added method to generate data patterns for bitmanip instructions 62 | 63 | ## [0.10.1] - 2022-02-10 64 | - Added vxsat to supported csr_regs 65 | - Added comments to coverpoint functions for P-ext 66 | - Removed unused tuple type for bit_width parameters in P-ext coverpoint functions 67 | 68 | ## [0.10.0] - 2022-01-27 69 | - Added support for instructions from B extension. 70 | - Bug fix for bgeu instruction. 71 | 72 | ## [0.9.0] - 2022-01-07 73 | - Added support for P extension cover point generation and instruction decoding. 74 | - Allowed an instruction to generate results in multiple registers. 75 | 76 | ## [0.8.0] - 2021-10-30 77 | - Added cross combination coverage support. 78 | 79 | ## [0.7.3] - 2021-09-02 80 | - Updated logger to enable logging for API calls. 81 | 82 | ## [0.7.2] - 2021-08-18 83 | - Added decoding support for K extension instructions based on latest spec 84 | 85 | ## [0.7.1] - 2021-08-12 86 | - Bug fix for error while using byte_count with overlap = Y. 87 | 88 | ## [0.7.0] - 2021-08-11 89 | - Adding support for floating point extension coverpoints 90 | - Bug fixes for instruction decoder and improved pretty printing. 91 | - fix for uninitialized total_categories variable in coverage. 92 | - fixed CONTRIBUTING.rst file 93 | 94 | ## [0.6.6] - 2021-08-03 95 | - Bug fix for error while decoding instruction name 96 | 97 | ## [0.6.5] - 2021-07-14 98 | - Bug fix for error while generating Data Propagation Report. 99 | 100 | ## [0.6.4] - 2021-07-08 101 | - Added support for CSR coverage and its architectural state 102 | - Updated the merge function to support multiprocessing 103 | - Added a parameter '-p' ( number of processes ) in merge command 104 | - Documentation update for CSR coverpoints 105 | - Return value of parsers changed from 5 independent values (hexcode, addr, reg commmit, csr commit, mnemonics) to instruction object updated with these values 106 | - Argument of decode and all decoding functions (in internaldecoder) changed from hexcode and addr to instruction object 107 | 108 | ## [0.6.3] - 2021-06-24 109 | - Documentation updates to reflect plugin usage. 110 | - Minor bug fixes in coverage reporting. 111 | - Improved CLI help messages. 112 | 113 | ## [0.6.2] - 2021-06-15 114 | - Added parser plugins for sail and spike 115 | - Added decoder plugin 116 | - Added arguments in main.py for custom plugin paths and names. 117 | 118 | ## [0.6.1] - 2021-06-11 119 | - Added initial support for F extension coverpoints based on IBM models. 120 | - Added support for F extension architectural state 121 | - Fixed author information and repo link in setup.py 122 | 123 | ## [0.6.0] - 2021-05-27 124 | - added support in parsers for K-scalar crypto instructions 125 | - added support for abstract functions: uniform random, byte-count, leading-ones, leading-zeros, 126 | trailing-ones, trailing-zeros 127 | - now maintain a separate list of instructions which require unsigned interpretation of rs1 and rs2. 128 | - restructured coverage report handling to preserve comments throughout processing and merging. 129 | - switched yaml to a round-trip parser for preserving comments 130 | 131 | ## [0.5.2] - 2021-02-23 132 | - Moved ci to github actions 133 | - fixed links in docs 134 | 135 | ## [0.5.1] - 2020-12-14 136 | - Fixed operand signedness for m ext ops. 137 | 138 | ## [0.5.0] - 2020-11-18 139 | - added support to take multiple cgf files as input. The order matters 140 | - added support for abstract function of special dataset 141 | 142 | ## [0.4.0] - 2020-11-10 143 | - added special data set for r-type instructions 144 | - fixed data propagation report generation and templates 145 | - using classes to manage architectural state and statistics 146 | - updated docs 147 | 148 | ## [0.3.1] - 2020-10-26 149 | - use logger instead of log in coverage.py 150 | 151 | 152 | ## [0.3.0] - 2020-10-26 153 | - Adding support for Data propagation report generation 154 | - Added 'sig-label' as the new cli option under coverage to capture DP reports 155 | - Added support in sail parsers to extract mnemonics also from the trace file 156 | - added pytablewriter as part of the requirements 157 | 158 | ## [0.2.0] - 2020-10-23 159 | - Added documentation for CGF and usage 160 | - Added normalization routine as cli 161 | - Added abstract functions 162 | - using click for cli 163 | - adding parsers for sail and spike 164 | - added support for filtering based on labels 165 | - added merge-reports cli command 166 | 167 | 168 | ## [0.1.0] - 2020-06-25 169 | - initial draft 170 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. See LICENSE.incore for details 2 | 3 | .. highlight:: shell 4 | 5 | ============ 6 | Contributing 7 | ============ 8 | 9 | Your inputs are welcome and greatly appreciated! We want to make contributing to this project as easy and transparent as possible, whether it's: 10 | 11 | - Reporting a bug 12 | - Discussing the current state of the code 13 | - Submitting a fix 14 | - Proposing new features 15 | - Becoming a maintainer 16 | 17 | We develop with Github 18 | ---------------------- 19 | 20 | We use github to host code, to track issues and feature requests, as well as accept pull requests. 21 | 22 | Git Strategy 23 | ------------ 24 | 25 | The repo adopts a simple git strategy where all contributions to the repo are made to the ``dev`` 26 | branch (i.e. all Pull-Requests must use ``dev`` as the target branch). On a monthly cadence (decided 27 | and controlled by the SIG-ARCH-TEST members) the ``dev`` branch will be merged to the ``main`` to by 28 | the official maintainers of the repo. This will create an official release capturing all the 29 | development over the month into a single release. 30 | 31 | To implement the above strategy successfully the following needs be followed: 32 | 33 | * Developers: All pull-requests from developers must target the ``dev`` branch and the PR must 34 | contain an entry in the CHANGELOG.md file under `[WIP-DEV]` section. 35 | * Maintainers: When a making a release the maintainers shall assign semantic version number by 36 | updating the CHANGELOG and the respective python files before raising a PR from the `dev` to `main`. 37 | 38 | All changes happen through Pull Requests 39 | ---------------------------------------- 40 | 41 | Pull requests are the best way to propose changes to the codebase. We actively welcome your pull requests: 42 | 43 | 1. Fork the repo and create your branch from `dev`. 44 | 2. If you have updated the docs, ensure that they render correctly in the respective format. 45 | 3. Make sure to create an entry in the CHANGELOG.md under the `WIP-DEV` section. 46 | 4. Ensure the existing framework is not broken and still passes the basic checks. 47 | 5. Please include a comment with the SPDX license identifier in all source files, for example: 48 | ``` 49 | // SPDX-License-Identifier: BSD-3-Clause 50 | ``` 51 | 6. Issue that pull request - make sure the target is to the dev branch. 52 | 53 | Checks for a PR 54 | --------------- 55 | 56 | Make sure your PR meets all the following requirements: 57 | 58 | 1. You have made an entry in the CHANGELOG.md undet the `WIP-DEV` section. 59 | 3. The commit messages are verbose. 60 | 4. You PR doesn't break existing framework. 61 | 62 | Versioning (for maintainers only) 63 | --------------------------------- 64 | 65 | When issuing pull requests from the `dev` branch to the `main` branch, an entry in the CHANGELOG.md 66 | is mandatory. The repo adheres to the [`Semantic Versioning`](https://semver.org/spec/v2.0.0.html) scheme. 67 | Following guidelines must be followed while assigning a new version number : 68 | 69 | - Patch-updates: all doc updates (like typos, more clarification,etc) will be patches. Beautification enhancements will also be treated as patch updates. Certain bug fixes to existing code may be treated as patches as well. 70 | - Minor-updates: Updates to code with new extensions, features, run time optimizations can be 71 | treated as minor updates. 72 | - Major-updates: Changes to the framework flow (backward compatible or incompatible) will be treated 73 | as major updates. 74 | 75 | Note: You can have either a patch or minor or major update. 76 | 77 | Each PR will also require the tools version to be bumped. This can be achieved using the following 78 | commands:: 79 | 80 | $ bumpversion --allow-dirty --no-tag --config-file setup.cfg patch #options: major / minor / patch 81 | 82 | bumpversion can be installed using `pip install bumpversion` 83 | 84 | All contributions will be under the permissive open-source License 85 | ------------------------------------------------------------------ 86 | 87 | In short, when you submit code changes, your submissions are understood to be under a permissive open source license like BSD-3, Apache-2.0 and CC, etc that covers the project. Feel free to contact the maintainers if that's a concern. 88 | 89 | Report bugs using Github's `issues `_ 90 | ------------------------------------------------------------------------------------ 91 | 92 | We use GitHub issues to track public bugs. Report a bug by `opening a new issue `_ it's that easy! 93 | 94 | Write bug reports with detail, background, and sample code 95 | ---------------------------------------------------------- 96 | 97 | **Great Bug Reports** tend to have: 98 | 99 | - A quick summary and/or background 100 | - Steps to reproduce 101 | - Be specific! 102 | - Give sample code if you can. 103 | - What you expected would happen 104 | - What actually happens 105 | - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) 106 | -------------------------------------------------------------------------------- /LICENSE.incore: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, InCore Semiconductors Pvt. Ltd. 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE.incore 2 | include README.rst 3 | include riscv_isac/requirements.txt 4 | recursive-include riscv_isac/data/* 5 | 6 | recursive-exclude * __pycache__ 7 | recursive-exclude * *.py[co] 8 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ##################################### 2 | **RISC-V ISA Coverage** : RISC-V ISAC 3 | ##################################### 4 | 5 | This repository now deprecated, the code already merged into `riscv-arch-test `_ 6 | ################################################# 7 | 8 | 9 | If make changes are required, please raise pull request against `riscv-arch-test `_ 10 | ################################################# -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | 3 | # Minimal makefile for Sphinx documentation 4 | # 5 | 6 | # You can set these variables from the command line. 7 | SPHINXOPTS = 8 | SPHINXBUILD = sphinx-build 9 | SPHINXPROJ = riscv_isac 10 | SOURCEDIR = source 11 | BUILDDIR = build 12 | 13 | # Put it first so that "make" without argument is like "make help". 14 | help: 15 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 16 | 17 | .PHONY: help Makefile 18 | 19 | # Catch-all target: route all unknown targets to Sphinx using the new 20 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 21 | %: Makefile 22 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 23 | 24 | clean: 25 | @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 26 | 27 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Build the docs 2 | 3 | ## For PDF 4 | ``` 5 | pip install -r requirements.txt 6 | make latexpdf 7 | evince build/latex/*.pdf 8 | ``` 9 | 10 | ## HTML 11 | ``` 12 | pip install -r requirements.txt 13 | make html 14 | firefox build/html/index.html 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | alabaster==0.7.12 2 | Babel==2.7.0 3 | Cerberus==1.3.1 4 | certifi==2019.6.16 5 | chardet==3.0.4 6 | doc8==0.8.0 7 | docutils==0.14 8 | gitdb2==2.0.5 9 | idna==2.8 10 | imagesize==1.1.0 11 | Jinja2==2.10.1 12 | MarkupSafe==1.1.1 13 | oyaml==0.9 14 | packaging==19.0 15 | pbr==5.3.1 16 | Pygments==2.4.2 17 | pyparsing==2.4.0 18 | python-dateutil==2.8.0 19 | pytz==2019.1 20 | PyYAML==5.1.1 21 | requests==2.22.0 22 | restructuredtext-lint==1.3.0 23 | ruamel.yaml==0.15.97 24 | six==1.12.0 25 | smmap2==2.0.5 26 | snowballstemmer==1.2.1 27 | Sphinx==3.0.4 28 | sphinx-rtd-theme==0.4.3 29 | sphinxcontrib-autoyaml==0.5.0 30 | sphinxcontrib-mermaid 31 | sphinxcontrib-websupport==1.1.2 32 | sphinxcontrib-bibtex==1.0.0 33 | stevedore==1.30.1 34 | urllib3==1.25.3 35 | twine==1.13.0 36 | sphinx_tabs 37 | m2r2==0.2.7 38 | mistune==0.8.4 39 | colorlog==4.1.0 40 | pyelftools==0.26 41 | -------------------------------------------------------------------------------- /docs/source/Cross_coverage.rst: -------------------------------------------------------------------------------- 1 | ############### 2 | Cross Coverage 3 | ############### 4 | 5 | ISAC supports extraction of data dependencies across different instructions in the log file. It can check for possible data hazards (RAW, WAW, WAR) between instructions. 6 | The hazards are checked for instructions belonging to the same window. The window size of the instruction is a parameter (by default taken as 32). 7 | The coverpoints are updated whenever the conditions mentioned in them are matched for a given instruction. 8 | 9 | Syntax for the coverpoints 10 | =========================== 11 | 12 | Each coverpoint is a string constituting of three sections - opcode list, assign list and condition list separated by ``::`` symbol. In each of these lists symbol 13 | ``?`` signifies a don't care condition. The delimiter for elements of the list is ``:`` symbol. The template of a generic coverpoint is shown below: 14 | 15 | ``[list of opcodes]::[list of assignment statements]::[list of condition statements]`` 16 | 17 | Opcode List: 18 | -------------- 19 | This is the list of instruction names against which we check the name of the current instruction in the queue. Here ``?`` signifies that we needn't check the name 20 | for that instruction as that won't affect the conditions of that coverpoint. Opcode list is a list of tuples and don't care conditions. 21 | 22 | An example of a opcode list : ``[(add,sub):?:?:(mul,mulh):?]`` 23 | 24 | Assign List: 25 | ------------- 26 | This list contains the assigning statements for registers. These statements are evaluated using ``exec`` command. The register numbers are assigned to variables. 27 | Under don't care conditions, no assignment is done. 28 | 29 | An example of assign list: ``[a=rd:?:?]`` 30 | 31 | Here a is any variable which is assigned the destination register number of the first instruction. 32 | 33 | Condition List: 34 | ---------------- 35 | This contains the evaluation statements to check the data dependencies. In case of don't care conditions, we don't check for data dependecies for that 36 | particular instruction. It conatins conditions for both source as well as destination registers. We can check for both consuming and non-consuming instructions. 37 | 38 | Example of condition list: ``[?:rs1==a or rs2==a]`` 39 | 40 | Here let a be the destination register of the first instruction (assigned by assign list). Then this checks whether any of the source registers are equal to the 41 | destination register of the previous instruction. It basically checks for read after write hazard. 42 | 43 | Cross Coverage Queue 44 | ===================== 45 | 46 | This is list of instruction objects in which the data is pushed in the sequence they are parsed. Whenever the queue size becomes equal to the window size, we check for all potential data hazards between the front element of the queue and the rest of the instructions according to the coverpoint and then pop the first element. 47 | 48 | Cross Coverage Class 49 | ===================== 50 | 51 | def __init__(self,label,coverpoint): 52 | --------------------------------------- 53 | 54 | The cross coverage class ``cross`` is initialized with the ``label`` and ``coverpoint``. ``result`` stores the coverage for that coverpoint. 55 | 56 | * Arguments: ``self`` instance of the class, ``label`` the instruction name, ``coverpoint`` the coverpoint to be evaluated. 57 | 58 | 59 | .. code-block:: python 60 | 61 | def __init__(self,label,coverpoint): 62 | self.label = label 63 | self.coverpoint = coverpoint 64 | self.result = 0 65 | 66 | An instance of a class is created for each ``(label,coverpoint)`` pair present in the CGF and all the relevant information about the coverpoint - opcode list, assign list and condition list are extracted. 67 | 68 | def process(self, queue, window_size, addr_pairs): 69 | ---------------------------------------------------- 70 | 71 | The ``process`` function of ``cross`` evaluates each coverpoint and updates ``result`` if there is a hit. The data in the coverpoint is evaluated against their corresponding instruction in the queue i.e. if the index of an instruction is i, then it will check and assign statments at index i of the three lists of the coverpoints. If the instruction address doesn't belong to any list of addresses in ``addr_pairs`` we treat is as a don't care. These coverpoints are checked in three steps. 72 | 73 | - First, the name of the first instruction is checked against the corresponding entry in the opcode list. 74 | - If the instruction is present, we assign its register value to a variable using ``exec`` command on the assign list elements. 75 | - Then we check for the conditions in the condition list using ``eval`` command. 76 | The above steps are repeated until the entire coverpoint is evaluated and it's a hit or the conditions are not satisfied and the loop breaks. 77 | 78 | * Arguments: ``self`` instance of the class, ``queue`` the list containing the instructions to be evaluated, ``window_size`` maximum number of instructions to be checked for any coverpoint, ``addr_pairs`` the addresses to be considered while evaluating an instruction 79 | * Returns: None 80 | 81 | def get_metric(self): 82 | ---------------------- 83 | 84 | It returns the coverage for that instance. 85 | 86 | * Arguments: ``self`` instance of the class 87 | * Returns: ``result`` the final coverage for that coverpoint 88 | 89 | Updating the CGF 90 | ======================== 91 | 92 | - An object dictionary ``obj_dict`` contains an instance of ``cross`` for each ``(label,coverpoint)`` pair. 93 | - As the instrcutions are parsed, they are appended to the ``cross_cover_queue`` which is the list of instructions to be checked. 94 | - When the size of queue becomes equal to the window size, for each entry in ``obj_dict``, the coverpoints are evaluated in ``process`` 95 | - The first element of the queue is popped and the process is repeated. 96 | - After all the instrcutions are parsed, all the instructions in the queue are again evaluated in the above manner till there is nothing to evaluate. 97 | - The final metric for each ``(label,coverpoint)`` instance is updated for each node in the CGF. 98 | 99 | **Examples of coverpoints** 100 | The window size is fixed and equal to 5. 101 | 102 | 1. RAW for an add instruction followed immediately by a subtract instruction. 103 | 104 | .. code-block:: python 105 | 106 | [(add,sub) : (add,sub) ] :: [a=rd : ? ] :: [? : rs1==a or rs2==a ] 107 | 108 | 2. RAW on x10 register for an add instruction followed by a subtract instruction with one non-consuming/non-updating instruction in between. 109 | No update happens to the rd register in between. 110 | 111 | .. code-block:: python 112 | 113 | [(add,sub) : ? : (add,sub) ] :: [a=rd : ? : ? ] :: [rd==x10 : rd!=a and rs1!=a and rs2!=a : rs1==a or rs2==a ] 114 | 115 | 3. WAW for an add instruction followed by a subtract instruction with 3 non-consuming instructions in between. 116 | 117 | .. code-block:: python 118 | 119 | [add : ? : ? : ? : sub] :: [a=rd : ? : ? : ? : ?] :: [? : ? : ? : ? : rd==a] 120 | 121 | 4. WAW for add followed by subtract with 3 consuming instructions in between. 122 | 123 | .. code-block:: python 124 | 125 | [(add,sub) : ? : ? : ? : (add,sub)] :: [a=rd : ? : ? : ? : ?] :: [? : rs1==a or rs2==a : rs1==a or rs2==a : rs1==a or rs2==a : rd==a] 126 | 127 | 5. WAR for an add instruction followed immediately by a subtract instruction. 128 | 129 | .. code-block:: python 130 | 131 | [(add,sub) : (add,sub) ] :: [a=rs1; b=rs2 : ? ] :: [? : rd==a or rd==b ] 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /docs/source/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* -- Extra CSS styles for Zephyr content (RTD theme) ----------------------- */ 2 | 3 | /* make the page width fill the window */ 4 | .wy-nav-content { 5 | max-width: none; 6 | } 7 | 8 | /* pygments tweak for white-on-black console */ 9 | /* hold off on this change for now 10 | 11 | .highlight-console .highlight { 12 | background-color: black; 13 | } 14 | .highlight-console .highlight .go, .highlight-console .highlight .gp { 15 | color: white; 16 | } 17 | .highlight-console .highlight .hll { 18 | background-color: white; 19 | } 20 | .highlight-console .highlight .hll .go, .highlight-console .highlight .hll .gp { 21 | color: black; 22 | font-weight: bold; 23 | } 24 | */ 25 | 26 | /* tweak doc version selection */ 27 | .rst-versions { 28 | position: static !important; 29 | } 30 | 31 | 32 | .rst-versions .rst-current-version { 33 | padding: 5px; 34 | background-color: #2980B9; 35 | color: #80FF80; 36 | } 37 | 38 | .rst-versions .rst-other-versions { 39 | padding: 5px; 40 | } 41 | 42 | div.rst-other-versions dl { 43 | margin-bottom: 0; 44 | } 45 | 46 | /* tweak spacing after a toctree, fixing issue from sphinx-tabs */ 47 | .toctree-wrapper ul, ul.simple ol.simple { 48 | margin-bottom: 24px !important; 49 | } 50 | 51 | /* code block highlight color in rtd changed to lime green, no no no */ 52 | 53 | .rst-content tt.literal, .rst-content code.literal, .highlight { 54 | background: #f0f0f0; 55 | } 56 | .rst-content tt.literal, .rst-content code.literal { 57 | color: #000000; 58 | } 59 | 60 | /* code literal links should be blue, and purple after visiting */ 61 | a.internal code.literal { 62 | color: #2980B9; 63 | } 64 | a.internal:visited code.literal { 65 | color: #9B59B9; 66 | } 67 | 68 | /* Make the version number more visible */ 69 | .wy-side-nav-search>div.version { 70 | color: rgba(255,255,255,1); 71 | } 72 | 73 | /* squish the space between a paragraph before a list */ 74 | div > p + ul, div > p + ol { 75 | margin-top: -20px; 76 | } 77 | 78 | /* squish space before an hlist in a list */ 79 | li table.hlist { 80 | margin-top: -10px; 81 | margin-bottom: 5px; 82 | } 83 | 84 | /* add some space before the figure caption */ 85 | p.caption { 86 | # border-top: 1px solid; 87 | margin-top: 1em; 88 | } 89 | 90 | /* decrease line leading a bit, 24px is too wide */ 91 | 92 | p { 93 | line-height: 22px; 94 | } 95 | 96 | /* add a colon after the figure/table number (before the caption) */ 97 | span.caption-number::after { 98 | content: ": "; 99 | } 100 | 101 | p.extrafooter { 102 | text-align: right; 103 | margin-top: -36px; 104 | } 105 | 106 | table.align-center { 107 | display: table !important; 108 | } 109 | 110 | /* put the table caption at the bottom, as done for figures */ 111 | table { 112 | caption-side: bottom; 113 | } 114 | 115 | .code-block-caption { 116 | color: #000; 117 | font: italic 85%/1 arial,sans-serif; 118 | padding: 1em 0; 119 | text-align: center; 120 | } 121 | 122 | /* make .. hlist:: tables fill the page */ 123 | table.hlist { 124 | width: 95% !important; 125 | table-layout: fixed; 126 | } 127 | 128 | /* override rtd theme white-space no-wrap in table heading and content */ 129 | th,td { 130 | white-space: normal !important; 131 | } 132 | 133 | /* dbk tweak for doxygen-generated API headings (for RTD theme) */ 134 | .rst-content dl.group>dt, .rst-content dl.group>dd>p { 135 | display:none !important; 136 | } 137 | .rst-content dl.group { 138 | margin: 0 0 12px 0px; 139 | } 140 | .rst-content dl.group>dd { 141 | margin-left: 0 !important; 142 | } 143 | .rst-content p.breathe-sectiondef-title { 144 | text-decoration: underline; /* dbk for API sub-headings */ 145 | font-size: 1.25rem; 146 | font-weight: bold; 147 | margin-bottom: 12px; 148 | } 149 | .rst-content div.breathe-sectiondef { 150 | padding-left: 0 !important; 151 | } 152 | 153 | /* doxygenXX item color tweaks, light blue background with dark blue top border */ 154 | .rst-content dl:not(.docutils) dl dt, dl:not(.docutils,.rst-other-versions) dt { 155 | background: #e7f2fa !important; 156 | border-top: none !important; 157 | border-left: none !important; */ 158 | } 159 | 160 | 161 | /* tweak display of option tables to make first column wider */ 162 | col.option { 163 | width: 25%; 164 | } 165 | 166 | /* tweak format for (:kbd:`F10`) */ 167 | kbd 168 | { 169 | -moz-border-radius:3px; 170 | -moz-box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset; 171 | -webkit-border-radius:3px; 172 | -webkit-box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset; 173 | background-color:#f7f7f7; 174 | border:1px solid #ccc; 175 | border-radius:3px; 176 | box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset; 177 | color:#333; 178 | display:inline-block; 179 | font-family:Arial,Helvetica,sans-serif; 180 | font-size:11px; 181 | line-height:1.4; 182 | margin:0 .1em; 183 | padding:.1em .6em; 184 | text-shadow:0 1px 0 #fff; 185 | } 186 | 187 | /* home page grid display */ 188 | 189 | .grid { 190 | list-style-type: none !important; 191 | display: -webkit-box; 192 | display: -ms-flexbox; 193 | display: flex; 194 | -ms-flex-wrap: wrap; 195 | flex-wrap: wrap; 196 | -webkit-box-pack: center; 197 | -ms-flex-pack: center; 198 | justify-content: center; 199 | margin: 1rem auto; 200 | max-width: calc((250px + 2rem) * 4); 201 | } 202 | 203 | .grid-item { 204 | list-style-type: none !important; 205 | -webkit-box-flex: 0; 206 | -ms-flex: 0 0 auto; 207 | flex: 0 0 auto; 208 | width: 200px; 209 | text-align: center; 210 | margin: 1rem; 211 | } 212 | 213 | .grid-item a { 214 | display: block; 215 | width: 200px; 216 | height: 200px; 217 | padding: 20px; 218 | display: -webkit-box; 219 | display: -ms-flexbox; 220 | display: flex; 221 | -webkit-box-orient: vertical; 222 | -webkit-box-direction: normal; 223 | -ms-flex-direction: column; 224 | flex-direction: column; 225 | -webkit-box-pack: center; 226 | -ms-flex-pack: center; 227 | justify-content: center; 228 | -webkit-box-align: center; 229 | -ms-flex-align: center; 230 | align-items: center; 231 | border: 1px solid #c6cbce; 232 | background-color: #1ab4e7; 233 | color: white; 234 | } 235 | 236 | .grid-item h2 { 237 | font-size: 1.1rem; 238 | } 239 | 240 | .grid-item img { 241 | margin-bottom: 1.1rem; 242 | max-width: 75%; 243 | } 244 | 245 | 246 | .grid-item a:hover { 247 | background-color: #1892BA; 248 | color: white; 249 | } 250 | 251 | 252 | .grid-item p { 253 | margin-top: 0.5rem; 254 | color: #333e48; 255 | } 256 | 257 | .grid-icon { 258 | line-height: 1.8; 259 | font-size: 4rem; 260 | color: white; 261 | } 262 | 263 | /* add a class for multi-column support 264 | * in docs to replace use of .hlist with 265 | * a .. rst-class:: rst-columns 266 | */ 267 | 268 | .rst-columns { 269 | column-width: 18em; 270 | } 271 | 272 | /* numbered "h2" steps */ 273 | 274 | body { 275 | counter-reset: step-count; 276 | } 277 | 278 | div.numbered-step h2::before { 279 | counter-increment: step-count; 280 | content: counter(step-count); 281 | background: #cccccc; 282 | border-radius: 0.8em; 283 | -moz-border-radius: 0.8em; 284 | -webkit-border-radius: 0.8em; 285 | color: #ffffff; 286 | display: inline-block; 287 | font-weight: bold; 288 | line-height: 1.6em; 289 | margin-right: 5px; 290 | text-align: center; 291 | width: 1.6em; 292 | } 293 | 294 | /* tweak bottom margin of a code block in a list */ 295 | 296 | .tab div[class^='highlight']:last-child { 297 | margin-bottom: 1em; 298 | } 299 | 300 | /* force table content font-size in responsive tables to be 100% 301 | * fixing larger font size for paragraphs in the kconfig tables */ 302 | 303 | .wy-table-responsive td p { 304 | font-size:100%; 305 | } 306 | .section #basic-2-flip-flop-synchronizer{ 307 | text-align:justify; 308 | } 309 | 310 | -------------------------------------------------------------------------------- /docs/source/_static/incore_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riscv-software-src/riscv-isac/777d2b47623d7eebdb8bbed06dbddedc33722346/docs/source/_static/incore_logo.png -------------------------------------------------------------------------------- /docs/source/_static/l1cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riscv-software-src/riscv-isac/777d2b47623d7eebdb8bbed06dbddedc33722346/docs/source/_static/l1cache.png -------------------------------------------------------------------------------- /docs/source/_static/onlyC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riscv-software-src/riscv-isac/777d2b47623d7eebdb8bbed06dbddedc33722346/docs/source/_static/onlyC.png -------------------------------------------------------------------------------- /docs/source/_static/riscv-isac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riscv-software-src/riscv-isac/777d2b47623d7eebdb8bbed06dbddedc33722346/docs/source/_static/riscv-isac.png -------------------------------------------------------------------------------- /docs/source/_static/theme_overrides.css: -------------------------------------------------------------------------------- 1 | /* override table width restrictions */ 2 | 3 | @media screen and (min-width: 767px) { 4 | 5 | .wy-table-responsive table td { 6 | /* !important prevents the common CSS stylesheets from overriding 7 | this as on RTD they are loaded after this stylesheet */ 8 | white-space: normal !important; 9 | } 10 | 11 | .wy-table-responsive { 12 | overflow: visible !important; 13 | } 14 | } 15 | 16 | .section #basic-2-flip-flop-synchronizer{ 17 | text-align:justify; 18 | } 19 | -------------------------------------------------------------------------------- /docs/source/_templates/breadcrumbs.html: -------------------------------------------------------------------------------- 1 | {% extends "!breadcrumbs.html" %} 2 | {% block breadcrumbs %} 3 | 4 | {# parameterize default name "Docs" in breadcrumb via docs_title in conf.py #} 5 | {% if not docs_title %} 6 | {% set docs_title = "Docs" %} 7 | {% endif %} 8 | 9 |
  • {{ docs_title }} »
  • 10 | {% for doc in parents %} 11 |
  • {{ doc.title }} »
  • 12 | {% endfor %} 13 |
  • {{ title }}
  • 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /docs/source/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | {% block document %} 3 | {% if is_release %} 4 |
    5 | The latest development version 6 | of this page may be more current than this released {{ version }} version. 7 |
    8 | {% endif %} 9 | {{ super() }} 10 | {% endblock %} 11 | {% block menu %} 12 | {% include "versions.html" %} 13 | {{ super() }} 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /docs/source/_templates/versions.html: -------------------------------------------------------------------------------- 1 | {# Add rst-badge after rst-versions for small badge style. #} 2 |
    3 | 4 | RISC-V ISA Coverage 5 | v: {{ current_version }} 6 | 7 | 8 |
    9 |
    10 |
    {{ _('Release Versions') }}
    11 | {% for slug, url in versions %} 12 |
    {{ slug }}
    13 | {% endfor %} 14 |
    15 |
    16 |
    {{ _('Quick Links') }}
    17 |
    18 | Project Home 19 |
    20 |
    21 | Releases 22 |
    23 |
    24 |
    25 |
    26 | -------------------------------------------------------------------------------- /docs/source/add_instr.rst: -------------------------------------------------------------------------------- 1 | .. _add_instr: 2 | 3 | ################################### 4 | Adding Support for new Instructions 5 | ################################### 6 | 7 | This section details the steps for adding support for new instructions in the native python plugins 8 | of RISCV-ISAC. 9 | 10 | .. note:: An alternative is to add support for the new instructions using the ``riscv/riscv-opcodes`` repository. Refer :here:`rvopcodes` for further information. 11 | 12 | Update the Parser-Module 13 | ======================== 14 | 15 | The first step is to update the parser-module to be able to deduce the relevant fields of the new 16 | instruction and create the required :meth:`~riscv_isac.parsers.instructionObject`. 17 | 18 | As part of this phase, the contributor will first have to add a function(s) which will decode the 19 | instruction hexadecimal encoding and extract the parameters of the :meth:`~riscv_isac.parsers.instructionObject`. 20 | Make sure to follow the same code structure as used by other functions in module. 21 | 22 | Currently the top level function that get's called by the coverage module is the 23 | :meth:`~riscv_isac.parsers.parseInstruction` function. This function based on the `instruction length 24 | encoding` scheme defined by the RISC-V ISA spec identifies the length of the instruction. If the 25 | instruction is compressed then the :meth:`~riscv_isac.parsers.parseCompressedInstruction` function 26 | is called, else the :meth:`~riscv_isac.parsers.parseInstruction` function is called. 27 | 28 | If the new instruction(s) being added belong to the non-compressed opcodes, then the particular 29 | entry in :meth:`~riscv_isac.parsers.OPCODES` needs to be updated to point to the new function(s) 30 | defined earlier. If there are instructions falling into the compressed op-code space then the 31 | functions :meth:`~riscv_isac.parsers.quad0`, :meth:`~riscv_isac.parsers.quad1` or :meth:`~riscv_isac.parsers.quad2` 32 | will need to be updated accordingly. 33 | 34 | Update the Architectural 35 | ======================== 36 | 37 | The coverage module maintains its own architectural state : integer register file, program counter, 38 | floating point register file, etc. If the new instruction(s) requires an additional architectural 39 | state, then that needs to be added in :meth:`~riscv_isac.coverage.archStats` and the usage needs to 40 | be updated in :meth:`~riscv_isac.coverage.compute_per_line`. 41 | -------------------------------------------------------------------------------- /docs/source/code.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _code: 3 | 4 | Code Docs 5 | ######### 6 | 7 | Normalizer-Module 8 | ================= 9 | 10 | .. automodule:: riscv_isac.cgf_normalize 11 | :members: 12 | :special-members: 13 | :private-members: 14 | 15 | Coverage-Module 16 | =============== 17 | 18 | .. automodule:: riscv_isac.coverage 19 | :members: 20 | :special-members: 21 | :private-members: 22 | 23 | Instruction Object 24 | ================== 25 | 26 | .. automodule:: riscv_isac.InstructionObject 27 | :members: 28 | :special-members: 29 | :private-members: 30 | 31 | FP-Abstract Functions 32 | ===================== 33 | 34 | 35 | .. automodule:: riscv_isac.fp_dataset 36 | :members: 37 | :special-members: 38 | :private-members: 39 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | 3 | 4 | # riscv_isac documentation build configuration file, created by 5 | # sphinx-quickstart on Fri Jun 9 13:47:02 2017. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | import sys 17 | import os 18 | import shlex 19 | import re 20 | 21 | def get_version(): 22 | changelog = open('../../CHANGELOG.md','r').read() 23 | x = re.findall(r'## \[(.*?)\] -',changelog)[0] 24 | return str(x) 25 | 26 | sys.path.insert(0, os.path.abspath('../..')) 27 | sys.setrecursionlimit(1500) 28 | 29 | # General information about the project. 30 | project = 'RISC-V ISA Coverage' 31 | copyright = u'2020 InCore Semiconductors Pvt. Ltd' 32 | 33 | author = '' 34 | 35 | version = str(get_version()) 36 | # The full version, including alpha/beta/rc tags 37 | release = version 38 | 39 | def setup(app): 40 | app.add_css_file("custom.css") 41 | 42 | # -- General configuration --------------------------------------------------- 43 | 44 | # If your documentation needs a minimal Sphinx version, state it here. 45 | #needs_sphinx = '1.0' 46 | 47 | # Add any Sphinx extension module names here, as strings. They can be 48 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 49 | # ones. 50 | needs_sphinx = '1.7.5' 51 | extensions = [ 52 | 'sphinx.ext.autodoc', 53 | 'sphinx.ext.doctest', 54 | 'sphinx.ext.intersphinx', 55 | 'sphinx.ext.todo', 56 | 'sphinx.ext.coverage', 57 | 'sphinx.ext.mathjax', 58 | 'sphinx.ext.viewcode', 59 | 'sphinxcontrib.autoyaml', 60 | 'sphinxcontrib.bibtex', 61 | 'sphinx_tabs.tabs', 62 | 'm2r2' 63 | ] 64 | # Add any paths that contain templates here, relative to this directory. 65 | templates_path = ['_templates'] 66 | 67 | # The suffix(es) of source filenames. 68 | # You can specify multiple suffix as a list of string: 69 | source_suffix = ['.rst', '.md'] 70 | #source_suffix = '.rst' 71 | 72 | # The encoding of source files. 73 | #source_encoding = 'utf-8-sig' 74 | 75 | # The master toctree document. 76 | master_doc = 'index' 77 | 78 | # The language for content autogenerated by Sphinx. Refer to documentation 79 | # for a list of supported languages. 80 | # 81 | # This is also used if you do content translation via gettext catalogs. 82 | # Usually you set "language" from the command line for these cases. 83 | language = 'en' 84 | 85 | # List of patterns, relative to source directory, that match files and 86 | # directories to ignore when looking for source files. 87 | exclude_patterns = ['_build'] 88 | 89 | # The name of the Pygments (syntax highlighting) style to use. 90 | pygments_style = 'sphinx' 91 | 92 | autodoc_member_order = 'bysource' 93 | 94 | #Mention the reference files 95 | bibtex_bibfiles = ['refs.bib'] 96 | 97 | # -- Options for HTML output ------------------------------------------------- 98 | 99 | # If true, `todo` and `todoList` produce output, else they produce nothing. 100 | todo_include_todos = True 101 | 102 | 103 | # -- Options for HTML output ---------------------------------------------- 104 | 105 | github_url = 'https://github.com/riscv/riscv-isac' 106 | html_show_sourcelink = True 107 | # The theme to use for HTML and HTML Help pages. See the documentation for 108 | # a list of builtin themes. 109 | # 110 | #html_theme = 'bootstrap' 111 | #html_theme = 'alabaster' 112 | import sphinx_rtd_theme 113 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 114 | html_theme = 'sphinx_rtd_theme' 115 | html_theme_options = { 116 | 'prev_next_buttons_location': 'both', 117 | 'display_version': True, 118 | 'includehidden': False, 119 | 'collapse_navigation':True, 120 | 'sticky_navigation': True, 121 | 'navigation_depth': 4, 122 | 'includehidden': True, 123 | 'titles_only': False 124 | } 125 | #html_sidebars = { 126 | # "**": ["about.html", "navigation.html", "searchbox.html", "donate.html"] 127 | #} 128 | 129 | # Add any paths that contain custom static files (such as style sheets) here, 130 | # relative to this directory. They are copied after the builtin static files, 131 | # so a file named "default.css" will overwrite the builtin "default.css". 132 | html_static_path = ['_static'] 133 | html_logo='_static/incore_logo.png' 134 | html_show_license = True 135 | docs_title = 'Docs / %s' %(version) 136 | # The name of an image file (within the static path) to use as favicon of the 137 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 138 | # pixels large. 139 | html_favicon = '_static/onlyC.png' 140 | html_context = { 141 | 'show_license': html_show_license, 142 | 'docs_title': docs_title, 143 | 'is_release': False, 144 | 'theme_logo_only': False, 145 | 'current_version': version, 146 | } 147 | html_last_updated_fmt = '%b %d, %Y' 148 | # If false, no module index is generated. 149 | html_domain_indices = False 150 | 151 | # If false, no index is generated. 152 | html_use_index = True 153 | 154 | # If true, the index is split into individual pages for each letter. 155 | html_split_index = True 156 | 157 | # If true, links to the reST sources are added to the pages. 158 | html_show_sourcelink = False 159 | 160 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 161 | html_show_sphinx = False 162 | 163 | # If true, license is shown in the HTML footer. Default is True. 164 | html_show_license = True 165 | 166 | # Custom sidebar templates, must be a dictionary that maps document names 167 | # to template names. 168 | # 169 | # The default sidebars (for documents that don't match any pattern) are 170 | # defined by theme itself. Builtin themes are using these templates by 171 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 172 | # 'searchbox.html']``. 173 | # 174 | # html_sidebars = {} 175 | 176 | 177 | # Output file base name for HTML help builder. 178 | htmlhelp_basename = 'RISC-V ISA Coverage' 179 | 180 | 181 | # -- Options for LaTeX output ------------------------------------------------ 182 | latex_engine='xelatex' 183 | numfig = True 184 | latex_elements = { 185 | # The paper size ('letterpaper' or 'a4paper'). 186 | # 187 | 'papersize': 'letterpaper', 188 | 'releasename':version, 189 | 'extraclassoptions': 'openany, twoside', 190 | 191 | # Sonny, Lenny, Glenn, Conny, Rejne, Bjarne and Bjornstrup 192 | #'fncychap': '\\usepackage[Bjornstrup]{fncychap}', 193 | 'fncychap': '\\usepackage{fancyhdr}', 194 | 'fontpkg': '\\usepackage{amsmath,amsfonts,amssymb,amsthm}', 195 | 196 | 'figure_align':'htbp', 197 | # The font size ('10pt', '11pt' or '12pt'). 198 | # 199 | 'pointsize': '12pt', 200 | 201 | # Additional stuff for the LaTeX preamble. 202 | # 203 | 'preamble': r''' 204 | % change the fon to san-serif 205 | %\renewcommand{\familydefault}{\sfdefault} 206 | 207 | %%%%%%%%%%%%%%%%%%%% Meher %%%%%%%%%%%%%%%%%% 208 | %%%add number to subsubsection 2=subsection, 3=subsubsection 209 | %%% below subsubsection is not good idea. 210 | \setcounter{secnumdepth}{3} 211 | % 212 | %%%% Table of content upto 2=subsection, 3=subsubsection 213 | \setcounter{tocdepth}{2} 214 | 215 | \usepackage{amsmath,amsfonts,amssymb,amsthm} 216 | \usepackage{graphicx} 217 | \usepackage{array, caption, tabularx, ragged2e, booktabs, longtable} 218 | \usepackage{stfloats} 219 | \usepackage{multirow} 220 | \usepackage{gensymb} 221 | \usepackage{fontspec} 222 | \setmainfont{Ubuntu Light} 223 | \definecolor{light-gray}{gray}{0.85} 224 | \usepackage{color,xesearch} 225 | \usepackage{soul} 226 | \sethlcolor{light-gray} 227 | \makeatletter 228 | 229 | %%% reduce spaces for Table of contents, figures and tables 230 | %%% it is used "\addtocontents{toc}{\vskip -1.2cm}" etc. in the document 231 | \usepackage[notlot,nottoc,notlof]{} 232 | 233 | \usepackage{color} 234 | \usepackage{transparent} 235 | \usepackage{eso-pic} 236 | \usepackage{lipsum} 237 | 238 | \usepackage{footnotebackref} %%link at the footnote to go to the place of footnote in the text 239 | 240 | %% spacing between line 241 | \usepackage{setspace} 242 | %%%%\onehalfspacing 243 | %%%%\doublespacing 244 | \singlespacing 245 | 246 | 247 | %%%%%%%%%%% datetime 248 | \usepackage{datetime} 249 | 250 | \newdateformat{MonthYearFormat}{% 251 | \monthname[\THEMONTH], \THEYEAR} 252 | 253 | 254 | %% RO, LE will not work for 'oneside' layout. 255 | %% Change oneside to twoside in document class 256 | \pagestyle{fancy} 257 | \makeatletter 258 | \fancypagestyle{normal}{ 259 | \fancyhf{} 260 | 261 | %%% Alternating Header for oneside 262 | %\fancyhead[L]{\ifthenelse{\isodd{\value{page}}}{ \small \nouppercase{\leftmark} }{}} 263 | %\fancyhead[R]{\ifthenelse{\isodd{\value{page}}}{}{ \small \nouppercase{\rightmark} }} 264 | 265 | %%% Alternating Header for two side 266 | \fancyhead[RO]{\small \nouppercase{\leftmark}} 267 | \fancyhead[RE]{\small \nouppercase{\leftmark}} 268 | \fancyhead[LE,LO]{\py@HeaderFamily \@title\sphinxheadercomma\releasename} 269 | %\fancyhead[RE,RO]{\py@HeaderFamily \c@chapter} 270 | 271 | %% for oneside: change footer at right side. If you want to use Left and right then use same as header defined above. 272 | %\fancyfoot[R]{\ifthenelse{\isodd{\value{page}}}{{\tiny Meher Krishna Patel} }{\href{http://pythondsp.readthedocs.io/en/latest/pythondsp/toc.html}{\tiny PythonDSP}}} 273 | 274 | %%% Alternating Footer for two side 275 | \fancyfoot[LO, LE]{\small \bf{Copyright \textcopyright \the\year \textbf{ } InCore Semiconductors Pvt. Ltd.}} 276 | %\fancyfoot[LO, LE]{\scriptsize \bf{RISC-V ISA Coverage}} 277 | 278 | %%% page number 279 | \fancyfoot[RO, RE]{\thepage} 280 | 281 | \renewcommand{\headrulewidth}{0.4pt} 282 | \renewcommand{\footrulewidth}{0.4pt} 283 | } 284 | \makeatother 285 | \RequirePackage{tocbibind} %%% comment this to remove page number for following 286 | \addto\captionsenglish{\renewcommand{\contentsname}{Table of contents}} 287 | \addto\captionsenglish{\renewcommand{\listfigurename}{List of figures}} 288 | \addto\captionsenglish{\renewcommand{\listtablename}{List of tables}} 289 | % \addto\captionsenglish{\renewcommand{\chaptername}{Chapter}} 290 | 291 | 292 | %%reduce spacing for itemize 293 | \usepackage{enumitem} 294 | \setlist{nosep} 295 | 296 | %%%%%%%%%%% Quote Styles at the top of chapter 297 | \usepackage{epigraph} 298 | \setlength{\epigraphwidth}{0.8\columnwidth} 299 | \newcommand{\chapterquote}[2]{\epigraphhead[60]{\epigraph{\textit{#1}}{\textbf {\textit{--#2}}}}} 300 | %%%%%%%%%%% Quote for all places except Chapter 301 | \newcommand{\sectionquote}[2]{{\quote{\textit{``#1''}}{\textbf {\textit{--#2}}}}} 302 | 303 | \linespread{1} 304 | ''', 305 | 306 | 307 | 'maketitle': r''' 308 | \pagenumbering{Roman} %%% to avoid page 1 conflict with actual page 1 309 | 310 | \begin{titlepage} 311 | \centering 312 | 313 | \begin{figure}[!h] 314 | \centering 315 | \includegraphics[scale=0.2]{incore_logo.png} 316 | \end{figure} 317 | \vspace*{40mm} %%% * is used to give space from top 318 | \textbf{\Huge {RISC-V ISA Coverage}} 319 | \vspace*{40mm} %%% * is used to give space from top 320 | 321 | 322 | \vspace{10mm} 323 | \Large \textbf{{Release: \releasename}} 324 | \vspace{10mm} 325 | 326 | Last update on : \today 327 | 328 | \vspace*{0mm} 329 | %\small Last updated : \MonthYearFormat\today 330 | 331 | 332 | %% \vfill adds at the bottom 333 | \vfill 334 | Copyright \textcopyright \the\year \textbf{ } InCore Semiconductors Pvt. Ltd. 335 | \end{titlepage} 336 | \sloppy 337 | 338 | \clearpage 339 | % \pagenumbering{roman} 340 | \tableofcontents 341 | \clearpage 342 | \listoffigures 343 | \clearpage 344 | \listoftables 345 | \clearpage 346 | \pagenumbering{arabic} 347 | ''', 348 | # Latex figure (float) alignment 349 | # 350 | # 'figure_align': 'htbp', 351 | 'sphinxsetup': \ 352 | 'hmargin={0.7in,0.7in}, vmargin={1in,1in}, \ 353 | verbatimwithframe=true, \ 354 | TitleColor={rgb}{0,0,0}, \ 355 | HeaderFamily=\\rmfamily\\bfseries, \ 356 | InnerLinkColor={rgb}{0,0,1}, \ 357 | OuterLinkColor={rgb}{0,0,1}', 358 | 359 | 'tableofcontents':' ', 360 | 361 | 362 | 363 | } 364 | 365 | #latex_elements = { 366 | # # The paper size ('letterpaper' or 'a4paper'). 367 | # # 368 | # 'papersize': 'letterpaper', 369 | # 370 | # # The font size ('10pt', '11pt' or '12pt'). 371 | # # 372 | # 'pointsize': '10pt', 373 | # 374 | # # Additional stuff for the LaTeX preamble. 375 | # # 376 | # 'preamble': '', 377 | # 378 | # # Latex figure (float) alignment 379 | # # 380 | # 'figure_align': 'htbp', 381 | # 382 | # 'atendofbody' : ' InCore Semiconductors Pvt. Ltd.' 383 | #} 384 | 385 | # Grouping the document tree into LaTeX files. List of tuples 386 | # (source start file, target name, title, 387 | # author, documentclass [howto, manual, or own class]). 388 | latex_documents = [ 389 | (master_doc, 'riscv_isac.tex', 'RISC-V ISAC Documentation', 390 | 'InCore Semiconductors Pvt. Ltd.', 'manual'), 391 | ] 392 | 393 | latex_logo = '_static/incore_logo.png' 394 | 395 | latex_show_pagerefs = True 396 | 397 | # -- Options for manual page output ------------------------------------------ 398 | 399 | # One entry per manual page. List of tuples 400 | # (source start file, name, description, authors, manual section). 401 | man_pages = [ 402 | (master_doc, 'riscv_isac', 'RISC-V ISAC Documentation', 403 | 'InCore Semiconductors Pvt. Ltd.', 1) 404 | ] 405 | 406 | 407 | # -- Options for Texinfo output ---------------------------------------------- 408 | 409 | # Grouping the document tree into Texinfo files. List of tuples 410 | # (source start file, target name, title, author, 411 | # dir menu entry, description, category) 412 | texinfo_documents = [ 413 | (master_doc, 'riscv_isac', 'RISC-V ISAC Documentation', 414 | 'InCore Semiconductors Pvt. Ltd.', 'One line description of project.', 415 | 'Miscellaneous'), 416 | ] 417 | 418 | # -- Options for Epub output ------------------------------------------------- 419 | 420 | # Bibliographic Dublin Core info. 421 | epub_title = project 422 | epub_author = author 423 | epub_publisher = author 424 | epub_copyright = copyright 425 | 426 | # The unique identifier of the text. This can be a ISBN number 427 | # or the project homepage. 428 | # 429 | # epub_identifier = '' 430 | 431 | # A unique identification for the text. 432 | # 433 | # epub_uid = '' 434 | 435 | # A list of files that should not be packed into the epub file. 436 | epub_exclude_files = ['search.html'] 437 | 438 | 439 | # -- Extension configuration ------------------------------------------------- 440 | 441 | # -- Options for intersphinx extension --------------------------------------- 442 | 443 | # Example configuration for intersphinx: refer to the Python standard library. 444 | intersphinx_mapping = {'https://docs.python.org/': None} 445 | 446 | # -- Options for todo extension ---------------------------------------------- 447 | 448 | # If true, `todo` and `todoList` produce output, else they produce nothing. 449 | todo_include_todos = True 450 | -------------------------------------------------------------------------------- /docs/source/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/source/diagrams/git_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riscv-software-src/riscv-isac/777d2b47623d7eebdb8bbed06dbddedc33722346/docs/source/diagrams/git_flow.png -------------------------------------------------------------------------------- /docs/source/dpr.rst: -------------------------------------------------------------------------------- 1 | *********************** 2 | Data Propagation Report 3 | *********************** 4 | 5 | The data propagation details quality analysis on the data propagation occurring within the test/application. It reports 6 | the following statistics about coverpoint hits and related signature updates: 7 | 8 | * **STAT1** : Number of instructions that hit unique coverpoints and update the signature 9 | * **STAT2** : Number of instructions that hit covepoints which are not unique but still update the signature (completely or partially) 10 | * **STAT3** : Number of instructions that hit a unique coverpoint but do not update the signature completely 11 | * **STAT4** : Number of multiple signature updates for the same coverpoint 12 | * **STAT5** : Number of times the signature was overwritten 13 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. See LICENSE.incore for details 2 | 3 | .. _home: 4 | 5 | RISC-V ISA Coverage Documentation 6 | ############################################### 7 | 8 | Welcome to RISC-V ISA Coverage documentation version: |version| 9 | 10 | For information about the changes and additions for releases, 11 | please refer to the :ref:`Revisions ` documentation. 12 | 13 | .. toctree:: 14 | :glob: 15 | :maxdepth: 1 16 | :numbered: 17 | 18 | overview 19 | quickstart 20 | cgf 21 | rvopcodesdecoder 22 | add_instr 23 | contributing 24 | revisions 25 | licensing 26 | python_plugins 27 | code 28 | -------------------------------------------------------------------------------- /docs/source/index_bkp: -------------------------------------------------------------------------------- 1 | .. See LICENSE.incore for details 2 | 3 | .. _home: 4 | 5 | RISC-V ISA Coverage Documentation 6 | ############################################### 7 | 8 | Welcome to RISC-V ISA Coverage documentation version: |version| 9 | 10 | For information about the changes and additions for releases, 11 | please refer to the :ref:`Revisions ` documentation. 12 | 13 | .. raw:: html 14 | 15 | 59 | 60 | .. include:: 61 | 62 | .. only:: latex 63 | 64 | .. note:: 65 | 66 | This document provides detailed information of the IPs generated and maintained by InCore 67 | Semiconductors Pvt. Ltd. 68 | 69 | **Proprietary Notice** 70 | 71 | Copyright (c) 2020, InCore Semiconductors Pvt. Ltd. 72 | 73 | Information in this document is provided "as is" with faults, if any. 74 | 75 | InCore expressly disclaims all warranties, representations, and conditions of any kind, whether 76 | express or implied, including, but not limited to, the implied warranties or conditions of 77 | merchantability, fitness for a particular purpose and non-infringement. 78 | 79 | InCore does not assume any liability rising out of the application or use of any product or circuit, 80 | and specifically disclaims any and all liability, including without limitation indirect, incidental, 81 | special, exemplary, or consequential damages. 82 | 83 | InCore reserves the right to make changes without further notice to any products herein. 84 | 85 | .. only:: html 86 | 87 | Sections 88 | ******** 89 | 90 | .. toctree:: 91 | :glob: 92 | :maxdepth: 1 93 | :numbered: 94 | 95 | overview 96 | getting_started 97 | features 98 | installation 99 | cli 100 | tests 101 | contriburing 102 | revisions 103 | licensing 104 | -------------------------------------------------------------------------------- /docs/source/isac_cov_calc.rst: -------------------------------------------------------------------------------- 1 | ******************************** 2 | Performance improvements to ISAC 3 | ******************************** 4 | 5 | Coverage computation in ISAC is an iterative process where all coverpoints 6 | are evaluated for every instruction. This causes an exponential increase in coverage 7 | computation time as the number of coverpoints increases. Following are methods leveraged to produce 8 | performance improvements to ISAC. 9 | 10 | Parallelized coverage calculation 11 | ################################# 12 | 13 | Parallelization is one way to reduce the time taken to compute the coverage. 14 | Parallelization of coverage computation is achieved by the parallelization of ``compute_per_line()`` 15 | method in ``coverage.py`` file. The implementation resorts to the use of queues to relay statistics of hit 16 | coverpoint back to the main process. 17 | 18 | Usage 19 | ***** 20 | The number of processes to be spawned for coverage computation can be provided using, 21 | ``--procs`` or ``-p`` option while running ISAC. As an example, :: 22 | 23 | riscv_isac --verbose info coverage -d -t add-01.log --parser-name c_sail --decoder-name internaldecoder -o coverage.rpt --sig-label begin_signature end_signature --test-label rvtest_code_begin rvtest_code_end -e add-01.elf -c dataset.cgf -c rv32i.cgf -x 32 -l add --procs 3 24 | 25 | The above command partitions the supplied CGF file into three different sets based on the coverlabels. Three processes would be 26 | spawned and are supplied with a part of the partitioned CGF file dictionary. Each of the processes are asynchronously supplied with ``instructionObject`` 27 | objects via independent queues. The processes compute coverage independently against the decoded ``instructionObject`` with its own set of coverlabels 28 | and its respective coverpoints. The updated cgf dictionary and coverpoint hit statistics are relayed back to the main process through a queue. 29 | The cgf dictionary and the statistics are merged before continuing further. 30 | 31 | The default number of processes spawned is 1 32 | 33 | Removal of Hit Coverpoints from CGF Dictionary 34 | ############################################## 35 | 36 | For architectural testing, it is enough if a coverpoint is hit just once and has impact on the signature. When this feature 37 | is enabled, coverpoints would be deleted from the working CGF dictionary once hit to avoid evaluating it for all subsequent 38 | instructions. 39 | 40 | Usage 41 | ***** 42 | This feature can be enabled using the ``--no-count`` option while running ISAC. As an example, :: 43 | 44 | riscv_isac --verbose info coverage -d -t add-01.log --parser-name c_sail --decoder-name internaldecoder -o coverage.rpt --sig-label begin_signature end_signature --test-label rvtest_code_begin rvtest_code_end -e add-01.elf -c dataset.cgf -c rv32i.cgf -x 32 -l add --no-count 45 | 46 | When ``--no-count`` option supplied, the hit coverpoints are stored and are then deleted from the CGF dictionary at the end of every iteration 47 | 48 | This feature is off by default. 49 | -------------------------------------------------------------------------------- /docs/source/licensing.rst: -------------------------------------------------------------------------------- 1 | .. See LICENSE.incore for details 2 | 3 | ##################### 4 | Licensing and Support 5 | ##################### 6 | 7 | Please review the LICENSE.* files in the `repository `_ for licensing details. 8 | 9 | For more information about support, customization and other IP developments 10 | please write to info@incoresemi.com. 11 | -------------------------------------------------------------------------------- /docs/source/overview.rst: -------------------------------------------------------------------------------- 1 | .. See LICENSE.incore for details 2 | 3 | ######## 4 | Overview 5 | ######## 6 | 7 | RISC-V ISAC is an ISA coverage extraction tool. Given a set of coverpoints and an execution trace of 8 | a test/application run on a model, ISAC can provide a report indicating in detail which of those 9 | coverpoints were covered by the test/application. ISAC also holds the capability to provide a 10 | detailed quality analysis on data propagation occurring within the test/application. 11 | The figure below shows the overall flow of RISCV-ISAC. 12 | 13 | 14 | .. _fig-isac: 15 | 16 | .. figure:: _static/riscv-isac.png 17 | :align: center 18 | :alt: riscv-isac 19 | 20 | 21 | RISCV-ISAC is primarily split into 2 major parts: the front-end parser and the backedn coverage 22 | analyser. This split enables RISCV-ISAC to support parsing of multiple different execution log 23 | formats and provide the same level of coverage and QA support. 24 | 25 | The following sections will provide details on the working and flow of both these modules. 26 | 27 | 28 | Cover Group Format 29 | ================== 30 | 31 | The coverpoints of interest are captured in an intuitive YAML format. This YAML structure is called 32 | Cover Group Format. A CGF File typically consists of a single dataset node and multiple covergroups. 33 | Each covergroups can define multiple coverpoints for differen set of instructions. Currently only 34 | cross-products of operand registers and operand values is supported. More details on CGF can be 35 | found in :ref:`cgf`. 36 | 37 | .. _exec_trace: 38 | 39 | Execution Trace Format 40 | ====================== 41 | 42 | RISCV-ISAC requires an execution trace of the test/application run on the RISC-V target (ISS or RTL) 43 | as an input. RISCV-ISAC uses this trace to analyse the coverpoints covered. The execution trace to 44 | be used or supported in RISCV-ISAC needs to meet the following criteria: 45 | 46 | - Every instruction that was committed/executed by the model (can be ISS or RTL) should be captured 47 | as an entry in the log in the order which they were committed. 48 | - Each instruction entry must include the program counter pointing to the begining of that 49 | intruction 50 | - Each instruction entry must include the hex encoding of the instruction that was 51 | committed/executed. 52 | - Each instruction entry must also include any architectural state update occuring due to the 53 | execution of that instruction. For eg, the destination register that was updated, the csr that was 54 | modified, mem regions that were written to, etc. 55 | - Each instruction entry can span multiple lines 56 | - Information of each instruction must be retrievable via regular-expression. 57 | - Mnemonics of the instruction is possible, should be provided as well. 58 | 59 | .. _parser: 60 | 61 | Parser-Module 62 | ============= 63 | 64 | The parser-module is designed to parse an execution trace to extract information on a per instruction 65 | commit basis. Given an execution trace adhering to the above format, the parser-module is capable of deducing and 66 | extracting the information to into a common instruction class object. This object is then passed onto the coverage-module for 67 | coverpoint analysis. 68 | 69 | With the parser-module being decoupled from the coverage-module, support for parsing different execution 70 | trace formats can be easily integrated into RISCV-ISAC. 71 | 72 | Currently the execution traces from the following RISC-V Models is support 73 | 74 | - SAIL: Generate a trace using the ``-v`` flag 75 | - SPIKE: Generate a trace using ``--log-commits`` flag 76 | 77 | .. See :ref:`add_parser` to know how to add your custom trace support to RISCV-ISAC. 78 | 79 | .. _normalizer: 80 | 81 | Normalizer-Module 82 | ================= 83 | 84 | The coverpoints defined in the input CGF file may contain abstract functions like ``walking_ones``, 85 | ``walking_zeros``, etc. which provide ease to the user in defining large datasets. 86 | The normalizer module is responsible for unrolling these abstract functions to individual 87 | coverpoints and generate a normalized CGF file which is used by the coverage-module. 88 | 89 | .. _cov_module: 90 | 91 | Coverage Module 92 | =============== 93 | 94 | The coverage-module is responsible for carrying out the coverage analysis and generating a YAML and 95 | HTML reports on the same. The coverage-module maintains a simple architectural state of RISC-V like 96 | PC, integer registerfile , etc. This state is updated based on the instructions encountered in the 97 | execution trace. 98 | 99 | Each time an instruction class object is presented by the parser, the coverage-module checks the 100 | normalized CGF file is any of the coverpoints were hit by that particular instruction. A single 101 | instruction can hit multiple coverpoints. 102 | 103 | The coverage-module also allows restricting the coverage to a specific region(s) of the test. These 104 | regions are specified by the user based on the labels available in the test. The coverage-module 105 | uses these labels and elf to deduce the exact address ranges. 106 | 107 | The coverage-module can be further restricted to collect coverage only on certain covergroups 108 | specified in the CGF file via the ``--cov-label (-l)`` argument. 109 | 110 | The coverage-module can also provided a data-propagation report which captures how coverpoints are 111 | the instructions contributing to them are being stored in a the memory region. This is particularly 112 | helpful when creating signature based tests. This feature however requires specifying labels of 113 | memory regions similar to how test-regions are specified using the ``--sig-label`` argument. 114 | 115 | The coverage-module at the end of execution generates 4 artifacts. 116 | 117 | - The first is an updated CGF file with frequencies added to each coverpoint. This file is useful 118 | when merging multiple coverpoints across different runs. 119 | - A YAML based report capturing the detailed and high-level coverpoint ratios. 120 | - An HTML based report capturing the same information as the YAML 121 | - A data propagation report in Markdown format. This is available only when signature/data regions 122 | are specified as an argument. 123 | 124 | Details on adding support for new instructions in ISAC is covered in :ref:`add_instr`. 125 | 126 | Merge Module 127 | ============ 128 | 129 | RISCV-ISAC also provides a simple merge-module which can merge multiple CGF reports to create a 130 | single report. This is useful for creating a coverage report for an entire suite of tests. 131 | -------------------------------------------------------------------------------- /docs/source/pseudo_op_support.rst: -------------------------------------------------------------------------------- 1 | ********************************* 2 | Pseudo-Ops Support for RISCV-ISAC 3 | ********************************* 4 | 5 | Coverpoints are defined in a CGF file under the ``opcode`` node in the CGF. This is a misnomer as ISAC and CTG 6 | deals with mnemonics of the instruction rather than the actual encoding. In order to deal with mnemonics of pseudo-Ops, 7 | and its congruent base instruction definition, changes are brought to the CGF format. 8 | 9 | Format 10 | ###### 11 | The ``opcode`` field is renamed to ``mnemonics``. To support pseudo-instructions two new fields ``base_op`` and ``p_op_cond`` 12 | are added to the covergroups. The ``base_op`` and ``p_op_cond`` are optional fields which specify the base operation and the 13 | condition over the different fields of the instruction which when satisfied results in the instruction being recognized as the 14 | pseudo-op mentioned in ``mnemonics``. As an example, ``zext.h`` is a pseudo-op of ``pack`` in RV32 and packw in RV64 with ``rs2`` 15 | equal to ``x0``. Covergroup for ``zext.h`` pseudo-op can be expressed as follows: :: 16 | 17 | zext.h_32: 18 | config: 19 | - check ISA:=regex(.*RV32.*B.*) 20 | - check ISA:=regex(.*RV32.*Zbb.*) 21 | mnemonics: 22 | zext.h: 0 23 | base_op: packw 24 | p_op_cond: rs2 == x0 25 | ... 26 | 27 | zext.h_64: 28 | config: 29 | - check ISA:=regex(.*RV64.*B.*) 30 | - check ISA:=regex(.*RV64.*Zbb.*) 31 | mnemonics: 32 | zext.h: 0 33 | base_op: pack 34 | p_op_cond: rs2 == x0 35 | ... 36 | 37 | The ``expand_cgf`` method defined in ``cgf_normalize.py`` goes through every covergroup in the working cgf dictionary. If it encounters 38 | ``opcode`` node, a deprecation warning is printed and ``opcode`` is renamed to ``mnemonics``. The method also facilitates checks to see 39 | if ``base_op`` and ``p_op_cond`` meets required conditions. 40 | 41 | While computing the coverage, if the decoded instruction under scrutiny is equal to the instruction mentioned in ``base_op`` of working 42 | covergroup, the conditions mentioned in ``p_op_cond`` are evaluated. If a match is found, the instruction defined in ``mnemonic`` field is 43 | assumed to be hit and the coverpoint hit statistics is updated accordingly. 44 | 45 | Note 46 | #### 47 | - The ``p_op_cond`` node is relevant only if the ``base_op`` node has been defined. 48 | - The ``mnemonics`` node is allowed to have multiple entries only if the ``base_op`` node is empty. 49 | -------------------------------------------------------------------------------- /docs/source/python_plugins.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Writing Your Own Plugins 3 | ======================== 4 | 5 | RISCV-ISAC uses the `pluggy `_ system for supporting plugins. The hooks are predefined and can be accessed by importing the ``riscv_isac.plugins`` module. The template for custom plugins is available :ref:`here.` 6 | 7 | Two classes of plugins are defined, namely: 8 | 9 | * Parser Plugin(``parserHookImpl``): Parse the execution trace file to yield instruction object with updated fields - instruction code, address, register commits, CSR commits and mnemonics, for each instruction. Currently, there are plugins for execution traces from 2 RISC V models - SPIKE and SAIL. 10 | * Decoder Plugin(``decoderHookImpl``): Decodes the information into a common instruction class object. 11 | 12 | .. note:: The name of the python file and the name of the class should be the same. 13 | 14 | .. warning:: Coverage reported by ISAC is based on the instructions reported in the trace file. Hence it is imperative that all instructions are reported in the trace file. Currently the coverage reporting using the SPIKE model and parser is inaccurate because instructions which trap are not reported in the trace file. Such problems will exist with all parsers/models which follow similar behaviour. 15 | 16 | Function Definitions 17 | ===================== 18 | 19 | Parser Plugin 20 | ~~~~~~~~~~~~~~~~~~ 21 | 22 | def setup(self, trace, arch): 23 | ------------------------------ 24 | 25 | This function initializes each instance of ``parserclass()`` (a subclass of ``ParserSpec``) of a given mode. 26 | 27 | * Arguments: (``trace``) file path of the execution trace file and (``arch``) architecture of the set. 28 | 29 | .. code-block:: python 30 | 31 | @plugins.parserHookImpl 32 | def setup(self, trace, arch): 33 | self.trace = trace 34 | self.arch = arch 35 | 36 | def __iter__(self): 37 | ------------------------ 38 | 39 | It converts the instance of ``parserclass()`` to an iterator. Thus, given an input trace file to the instance, this function will extract information from it line by line and generate an instruction object ``riscv_isac.InstructionObject.instructionObject`` . An example is shown below from the c_sail parser. 40 | 41 | * Arguments: ``self`` instance of the class that contains the input trace file. 42 | * Returns: Generates instruction object ``instrObj`` on each call. 43 | 44 | .. code-block:: python 45 | 46 | @plugins.parserHookImpl 47 | def __iter__(self): 48 | with open(self.trace) as fp: 49 | content = fp.read() 50 | instructions = content.split('\n\n') 51 | for line in instructions: 52 | instr, mnemonic = self.extractInstruction(line) 53 | addr = self.extractAddress(line) 54 | reg_commit = self.extractRegisterCommitVal(line) 55 | csr_commit = self.extractCsrCommitVal(line) 56 | instrObj = instructionObject(instr, 'None', addr, reg_commit = reg_commit, csr_commit = csr_commit, mnemonic = mnemonic ) 57 | yield instrObj 58 | 59 | Decoder Plugin 60 | ~~~~~~~~~~~~~~~~~~~~~~~ 61 | 62 | def setup(self, arch): 63 | ------------------------------ 64 | 65 | This function initializes each instance of ``decoderclass()`` (a subclass of ``DecoderSpec``). 66 | 67 | * Arguments- ``self`` instance of the class and ``arch`` architecture of the instruction set 68 | 69 | .. code-block:: python 70 | 71 | @plugins.decoderHookImpl 72 | def setup(self, arch): 73 | self.arch = arch 74 | 75 | def decode(self, instr, addr): 76 | -------------------------------- 77 | 78 | This function decodes the instruction and returns an instruction object ``riscv_isac.InstructionObject.instructionObject``. 79 | 80 | * Arguments: ``self`` instance of the class, ``instrObj_temp`` instruction object returned by the parsers. 81 | * Return value: The instruction object in the standard format - (instr_name, instr_addr, rd, rs1, rs2, rs3, imm, zimm, csr, shamt, reg_commit, csr_commit, mnemonic) 82 | 83 | .. code-block:: python 84 | 85 | @plugins.decoderHookImpl 86 | def decode(self, instrObj_temp): 87 | ''' Decodes the type of instruction 88 | Returns: instruction object 89 | ''' 90 | instr = instrObj_temp.instr 91 | first_two_bits = self.FIRST2_MASK & instr 92 | if first_two_bits == 0b11: 93 | instrObj = self.parseStandardInstruction(instrObj_temp) 94 | return instrObj 95 | 96 | else: 97 | instrObj = self.parseCompressedInstruction(instrObj_temp) 98 | return instrObj 99 | 100 | .. ``parseStandardInstruction`` and ``parseCompressedInstruction`` takes in the same arguments and return the instruction object in the 101 | .. above mentioned format. 102 | 103 | .. _Custom Plugin Usage: 104 | 105 | Using Custom Plugins with RISC-V ISAC 106 | ===================================== 107 | 108 | * Pass the path of the directory where the custom file is present with ``--parser-path`` or ``--decoder-path`` as needed. 109 | * The name of the class should be passed using the ``--parser-name`` or ``--decoder-name`` argument. An example setup is shown below. 110 | 111 | An example setup is shown below: 112 | 113 | .. tabs:: 114 | 115 | .. tab:: Directory Structure 116 | 117 | .. code-block:: console 118 | 119 | ($) tree ./ 120 | . 121 | ├── add-01.elf 122 | ├── add-01.log 123 | ├── dataset.cgf 124 | ├── decoder 125 | │   └── CustomDecoder.py 126 | ├── parser 127 | │   └── CustomParser.py 128 | └── rv32i.cgf 129 | 130 | 2 directories, 6 files 131 | 132 | .. tab:: Coverage Command 133 | 134 | .. code-block:: console 135 | 136 | riscv_isac --verbose info coverage -d -t add-01.log --parser-path ./parser/ --parser-name CustomParser --decoder-path ./decoder/ --decoder-name CustomDecoder -o coverage.rpt --sig-label begin_signature end_signature --test-label rvtest_code_begin rvtest_code_end -e add-01.elf -c dataset.cgf -c rv32i.cgf -x 32 -l add 137 | 138 | 139 | 140 | .. _Templates: 141 | 142 | Templates 143 | ========= 144 | 145 | Parser Plugin 146 | ~~~~~~~~~~~~~ 147 | 148 | .. code-block:: python 149 | 150 | #CustomParser.py 151 | 152 | import riscv_isac.plugins 153 | from riscv_isac.InstructionObject import instructionObject 154 | 155 | class CustomParser() 156 | 157 | @plugins.parserHookImpl 158 | def setup(self, trace, arch): 159 | self.trace = trace 160 | self.arch = arch 161 | 162 | @plugins.parserHookImpl 163 | def __iter__(self): 164 | #extract instruction, mnemonic, addr, commit values and yields instruction object 165 | yield instr_Obj 166 | 167 | Decoder Plugin 168 | ~~~~~~~~~~~~~~ 169 | 170 | .. code-block:: python 171 | 172 | #CustomDecoder.py 173 | 174 | from riscv_isac.plugins import decoderHookImpl 175 | 176 | class CustomDecoder() 177 | 178 | @decoderHookImpl 179 | def setup(self, arch): 180 | self.arch = arch 181 | 182 | @decoderHookImpl 183 | def decode(self, instr_Obj): 184 | # Update fields of Instruction Object and return 185 | -------------------------------------------------------------------------------- /docs/source/quickstart.rst: -------------------------------------------------------------------------------- 1 | .. See LICENSE.incore for details 2 | 3 | .. highlight:: shell 4 | 5 | ============ 6 | Quickstart 7 | ============ 8 | 9 | Install Python 10 | ============== 11 | 12 | .. tabs:: 13 | 14 | .. tab:: Ubuntu 15 | 16 | 17 | Ubuntu 17.10 and 18.04 by default come with python-3.6.9 which is sufficient for using riscv-isac. 18 | 19 | If you are are Ubuntu 16.10 and 17.04 you can directly install python3.6 using the Universe 20 | repository 21 | 22 | .. code-block:: shell-session 23 | 24 | $ sudo apt-get install python3.6 25 | $ pip3 install --upgrade pip 26 | 27 | If you are using Ubuntu 14.04 or 16.04 you need to get python3.6 from a Personal Package Archive 28 | (PPA) 29 | 30 | .. code-block:: shell-session 31 | 32 | $ sudo add-apt-repository ppa:deadsnakes/ppa 33 | $ sudo apt-get update 34 | $ sudo apt-get install python3.6 -y 35 | $ pip3 install --upgrade pip 36 | 37 | You should now have 2 binaries: ``python3`` and ``pip3`` available in your $PATH. 38 | You can check the versions as below 39 | 40 | .. code-block:: shell-session 41 | 42 | $ python3 --version 43 | Python 3.6.9 44 | $ pip3 --version 45 | pip 20.1 from .local/lib/python3.6/site-packages/pip (python 3.6) 46 | 47 | .. tab:: CentOS7 48 | 49 | The CentOS 7 Linux distribution includes Python 2 by default. However, as of CentOS 7.7, Python 3 50 | is available in the base package repository which can be installed using the following commands 51 | 52 | .. code-block:: shell-session 53 | 54 | $ sudo yum update -y 55 | $ sudo yum install -y python3 56 | $ pip3 install --upgrade pip 57 | 58 | For versions prior to 7.7 you can install python3.6 using third-party repositories, such as the 59 | IUS repository 60 | 61 | .. code-block:: shell-session 62 | 63 | $ sudo yum update -y 64 | $ sudo yum install yum-utils 65 | $ sudo yum install https://centos7.iuscommunity.org/ius-release.rpm 66 | $ sudo yum install python36u 67 | $ pip3 install --upgrade pip 68 | 69 | You can check the versions 70 | 71 | .. code-block:: shell-session 72 | 73 | $ python3 --version 74 | Python 3.6.8 75 | $ pip --version 76 | pip 20.1 from .local/lib/python3.6/site-packages/pip (python 3.6) 77 | 78 | Using Virtualenv for Python 79 | --------------------------- 80 | 81 | Many a times users face issues in installing and managing multiple python versions. This is actually 82 | a major issue as many gui elements in Linux use the default python versions, in which case installing 83 | python3.6 using the above methods might break other software. We thus advise the use of **pyenv** to 84 | install python3.6. 85 | 86 | For Ubuntu and CentosOS, please follow the steps here: https://github.com/pyenv/pyenv#basic-github-checkout 87 | 88 | RHEL users can find more detailed guides for virtual-env here: https://developers.redhat.com/blog/2018/08/13/install-python3-rhel/#create-env 89 | 90 | Once you have pyenv installed do the following to install python 3.6.0:: 91 | 92 | $ pyenv install 3.6.0 93 | $ pip3 install --upgrade pip 94 | $ pyenv shell 3.6.0 95 | 96 | You can check the version in the **same shell**:: 97 | 98 | $ python --version 99 | Python 3.6.0 100 | $ pip --version 101 | pip 20.1 from .local/lib/python3.6/site-packages/pip (python 3.6) 102 | 103 | 104 | Install RISC-V ISAC 105 | =================== 106 | .. tabs:: 107 | .. tab:: via git 108 | To install RISC-V ISA Coverage Tool, run this command in your terminal: 109 | 110 | .. code-block:: console 111 | 112 | $ python3 -m pip3 install git+https://github.com/riscv/riscv-isac.git 113 | 114 | This is the preferred method to install RISC-V ISA Coverage, as it will always install the most recent stable release. 115 | 116 | If you don't have `pip`_ installed, this `Python installation guide`_ can guide 117 | you through the process. 118 | 119 | .. _pip: https://pip.pypa.io 120 | .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ 121 | 122 | .. tab:: via pip 123 | 124 | .. note:: If you are using `pyenv` as mentioned above, make sure to enable that environment before 125 | performing the following steps. 126 | 127 | .. code-block:: bash 128 | 129 | $ pip3 install riscv_isac 130 | 131 | To update an already installed version of RISCV-ISAC to the latest version: 132 | 133 | .. code-block:: bash 134 | 135 | $ pip3 install -U riscv_isac 136 | 137 | To checkout a specific version of riscv_isac: 138 | 139 | .. code-block:: bash 140 | 141 | $ pip3 install riscv_isac==1.x.x 142 | 143 | .. tab:: for Dev 144 | 145 | The sources for RISC-V ISA Coverage Tool can be downloaded from the `Github repo`_. 146 | 147 | You can clone the repository: 148 | 149 | .. code-block:: console 150 | 151 | $ git clone https://github.com/riscv/riscv-isac 152 | 153 | 154 | Once you have a copy of the source, you can install it with: 155 | 156 | .. code-block:: console 157 | 158 | $ cd riscv_isac 159 | $ pip3 install --editable . 160 | 161 | 162 | .. _Github repo: https://github.com/riscv/riscv-isac 163 | 164 | Test RISC-V ISAC 165 | ================= 166 | 167 | Once you have RISCV-ISAC installed, executing ``riscv_isac --help`` should print the following on the terminal. :: 168 | 169 | Options: 170 | --version Show the version and exit. 171 | -v, --verbose [info|error|debug] 172 | Set verbose level 173 | --help Show this message and exit. 174 | 175 | Commands: 176 | coverage Run Coverage analysis on tracefile. 177 | merge Merge given coverage files. 178 | normalize Normalize the cgf. 179 | 180 | RISCV-ISAC has three commands : ``coverage``, ``merge`` and ``normalize`` which are described below. 181 | Help text for each command can be accessed by executing ``riscv_isac --help`` 182 | 183 | .. tabs:: 184 | 185 | .. tab:: Coverage 186 | 187 | .. code-block:: console 188 | 189 | Usage: riscv_isac coverage [OPTIONS] 190 | 191 | Run Coverage analysis on tracefile. 192 | 193 | Options: 194 | -e, --elf PATH ELF file 195 | -t, --trace-file PATH Instruction trace file to be analyzed 196 | [required] 197 | 198 | -h, --header-file PATH YAML macro file to include 199 | -cm, --cgf-macro CGF MACROS CGF macros to consider for this run. 200 | 201 | -c, --cgf-file PATH Coverage Group File(s). Multiple allowed. 202 | [required] 203 | 204 | -d, --detailed Select detailed mode of coverage printing 205 | --parser-name NAME Parser plugin name. Parsers shipped with 206 | ISAC - [c_sail, spike] [default: c_sail] 207 | 208 | --decoder-name NAME Decoder plugin name. Decoders shipped with 209 | ISAC - [internaldecoder] [default: 210 | internaldecoder] 211 | 212 | --parser-path PATH Parser file path 213 | --decoder-path PATH Decoder file path 214 | -o, --output-file PATH Coverage Group File 215 | --test-label LABEL_START LABEL_END 216 | Pair of labels denoting start and end points 217 | of the test region(s). Multiple allowed. 218 | 219 | --sig-label LABEL_START LABEL_END 220 | Pair of labels denoting start and end points 221 | of the signature region(s). Multiple 222 | allowed. 223 | 224 | --dump PATH Dump Normalized Coverage Group File 225 | -l, --cov-label COVERAGE LABEL Coverage labels to consider for this run. 226 | -x, --xlen [32|64] XLEN value for the ISA. 227 | --help Show this message and exit. 228 | 229 | 230 | .. tab:: Merge 231 | 232 | .. code-block:: console 233 | 234 | Usage: riscv_isac merge [OPTIONS] [FILES]... 235 | 236 | Merge given coverage files. 237 | 238 | Options: 239 | -d, --detailed Select detailed mode of coverage printing 240 | -p Number of processes 241 | -c, --cgf-file PATH Coverage Group File [required] 242 | -o, --output-file PATH Coverage Group File. 243 | --help Show this message and exit. 244 | 245 | .. tab:: Normalize 246 | 247 | .. code-block:: console 248 | 249 | Usage: riscv_isac normalize [OPTIONS] 250 | 251 | Normalize the cgf. 252 | 253 | Options: 254 | -c, --cgf-file PATH Coverage Group File [required] 255 | -o, --output-file PATH Coverage Group File [required] 256 | -x, --xlen [32|64] XLEN value for the ISA. 257 | --help Show this message and exit. 258 | 259 | Running RISC-V ISAC 260 | =================== 261 | 262 | There are 3 different operations which can be performed by RISC-V ISAC namely, 263 | 264 | 1. coverage - Calculate the coverage of a test using the given log and cgf file(s). 265 | 2. merge - Merge different coverage reports to produce a single report with all statistics. 266 | 3. normalize - Dump a cgf file without any yaml anchors and abstract functions. The output file will contain the elaborated coverpoints as specified by the input cgf file(s). 267 | 268 | 269 | The CGF file(s) used in these examples can be obtained from `here `_. 270 | 271 | .. _Cgf files: https://github.com/riscv/riscv-ctg/tree/master/sample_cgfs 272 | 273 | Example usage of each of the commands are given below: 274 | 275 | .. tabs :: 276 | 277 | .. tab:: Coverage 278 | 279 | RISC-V ISAC is shipped with the following standard plugins. 280 | 281 | 1. Parser Plugins: 282 | - `SAIL C Model `_ ``c_sail``: Parser for execution logs from the C model generated by SAIL. 283 | - `SPIKE`_ ``spike``: Parser for execution logs from riscv-isa-sim. 284 | 285 | 2. Decoder Plugins: 286 | - Native Python Decoder ``internaldecoder``: A decoder for the RISC-V isa written in python. 287 | 288 | The ``c_sail`` and the ``internaldecoder`` plugins are used by default. To use custom 289 | plugins with RISC-V ISAC refer :ref:`here`. 290 | 291 | For a log file generated after running a test from the `Architecture Test Suite`_ on the SAIL 292 | C Model, the following command can be used to compute coverage for the test: 293 | 294 | .. code-block:: console 295 | 296 | riscv_isac --verbose info coverage -d -t add-01.log --parser-name c_sail --decoder-name internaldecoder -o coverage.rpt --sig-label begin_signature end_signature --test-label rvtest_code_begin rvtest_code_end -e add-01.elf -c dataset.cgf -c rv32i.cgf -x 32 -l add 297 | 298 | .. note:: The command assumes that the cgf files are in the same directory. Modify paths to the ``-c`` argument accordingly. 299 | 300 | .. note:: The command assumes that the coverage is calculated for the add test. Modify paths to the ``-e`` and ``-t`` arguments accordingly. The label should also be changed based on requirements. 301 | 302 | .. note:: To use the spike parser use ``--parser-name spike``. 303 | 304 | .. warning:: Coverage reported by ISAC is based on the instructions reported in the trace file. Hence it is imperative that all instructions are reported in the trace file. Currently the coverage reporting using the SPIKE model is inaccurate because instructions which trap are not reported in the trace file. It is advisable to use the SAIL model for accurate coverage reporting. 305 | 306 | .. tab:: Merge 307 | 308 | Sample command to merge different coverage reports to a single report. 309 | 310 | .. code-block:: console 311 | 312 | riscv_isac --verbose info merge -c dataset.cgf -c rv32i.cgf -o merged_report 1.rpt 2.rpt 3.rpt 313 | 314 | .. note:: The command assumes that the cgf files are in the same directory. Modify paths to the ``-c`` argument accordingly. 315 | 316 | .. note:: Modify the paths `*.rpt` if the report files are not in the same directory. 317 | 318 | .. tab:: Normalize 319 | 320 | Sample command to normalize CGF file(s). 321 | 322 | .. code-block:: console 323 | 324 | riscv_isac --verbose info normalize -c dataset.cgf -c rv32i.cgf -o normalized.cgf -x 32 325 | 326 | .. note:: The command assumes that the cgf files are in the same directory. Modify paths to the ``-c`` argument accordingly. 327 | 328 | .. _SPIKE: https://github.com/riscv/riscv-isa-sim 329 | .. _SAIL: https://github.com/rems-project/sail-riscv 330 | .. _Architecture Test Suite: https://github.com/riscv/riscv-arch-test 331 | 332 | 333 | 334 | 335 | 336 | -------------------------------------------------------------------------------- /docs/source/refs.bib: -------------------------------------------------------------------------------- 1 | @article{riscvpriv, 2 | author = {RISC-V ISA Privileged Specification}, 3 | year = {2020}, 4 | title = {}, 5 | journal = {https://riscv.org/specifications/privileged-isa/}, 6 | } 7 | @article{riscv, 8 | author = {RISC-V ISA Unprivileged Specification}, 9 | year = {2020}, 10 | title = {}, 11 | journal = {https://riscv.org/specifications/isa-spec-pdf/}, 12 | } 13 | 14 | @article{riscvdebug, 15 | author = {RISC-V ISA Debug Specification}, 16 | year = {2020}, 17 | title = {}, 18 | journal = {https://riscv.org/specifications/debug-specification/} 19 | } 20 | -------------------------------------------------------------------------------- /docs/source/revisions.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \pagebreak 4 | 5 | .. _revisions: 6 | 7 | .. mdinclude:: ../../CHANGELOG.md 8 | -------------------------------------------------------------------------------- /docs/source/rvopcodesdecoder.rst: -------------------------------------------------------------------------------- 1 | .. _rvopcodes: 2 | 3 | Using the encodings from riscv-opcodes 4 | ====================================== 5 | 6 | The `rvopcodesdecoder` is a decoder plugin for RISCV-ISAC, dependent on the official `riscv-opcodes `_ repository. The `rvopcodesdecoder` plugin automatically builds the decode tree and decodes instructions based on the encodings specified in the repository. The plugin will support any instruction/extension as long as it is specified in the format adhereing to the official repository. 7 | 8 | Usage 9 | ~~~~~ 10 | 11 | Initial Setup 12 | ************* 13 | - **Standard version**: This use case is intended for users who want to use the rvopcodes repo as 14 | is from `riscv/riscv-opcodes `_. The command generates a 15 | ``rvop-plugin`` folder with all the necessary files needed for the plugin. This path will have to 16 | be passed via the CLI while running coverage. :: 17 | 18 | riscv_isac setup --plugin-path ./rvop-plugin 19 | 20 | - **Custom Version**: This use case is intended for users who have a custom/modified version of the 21 | rvopcodes encodings locally. The ```` in the following command should point to 22 | the path on the system where the custom/modified ``riscv-opcodes`` repository contents are located. 23 | The command generates a symlink to the path inside the plugin folder and hence all changes to 24 | the encodings are picked up automatically. To add an extension, the user has to create a file 25 | with the ``rv`` prefix followed by the extension name. The file can then be populated with 26 | the instruction encodings in the appropriate format. Similar steps can be followed for updating 27 | existing extensions too. :: 28 | 29 | riscv_isac setup --plugin-path ./rvop-plugin --rvop-path 30 | 31 | Using the decoder with ISAC for coverage 32 | **************************************** 33 | 34 | To use `rvopcodesdecoder` as the decoder in RISCV-ISAC, ``rvopcodesdecoder`` should be supplied as argument for ``--decoder-name`` option with the ``--decoder-path`` set to the path of ``rvop-plugin`` generated in the previous step.. For example, :: 35 | 36 | riscv_isac --verbose info coverage --decoder-name rvopcodesdecoder --decoder-path ./rvop-plugin -t trace.log --parser-name spike -o coverage.rpt -e add-01.out -c rv64i.cgf -x 64 37 | 38 | .. note:: Pseudo instructions are always decoded into the mnemonics of the base instruction in this plugin. For example, `zext.h` is always decoded as `pack` only. 39 | 40 | -------------------------------------------------------------------------------- /docs/sphinxext/cairosvgconverter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | """ 4 | from sphinx.errors import ExtensionError 5 | from sphinx.locale import _ 6 | from sphinx.transforms.post_transforms.images import ImageConverter 7 | from sphinx.util import logging 8 | from sphinx.util.osutil import ENOENT, EPIPE, EINVAL 9 | from cairosvg import svg2pdf 10 | 11 | logger = logging.getLogger(__name__) 12 | 13 | class CairoSvgConverter(ImageConverter): 14 | conversion_rules = [ 15 | ('image/svg+xml', 'application/pdf'), 16 | ] 17 | 18 | def is_available(self): 19 | # type: () -> bool 20 | return True 21 | 22 | def convert(self, _from, _to): 23 | # type: (unicode, unicode) -> bool 24 | """Converts the image to expected one.""" 25 | svg2pdf(url=_from, write_to=_to) 26 | 27 | return True 28 | 29 | 30 | def setup(app): 31 | # type: (Sphinx) -> Dict[unicode, Any] 32 | app.add_post_transform(CairoSvgConverter) 33 | 34 | return { 35 | 'version': 'builtin', 36 | 'parallel_read_safe': True, 37 | 'parallel_write_safe': True, 38 | } 39 | -------------------------------------------------------------------------------- /interface.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import pluggy 3 | from riscv_isac.plugins.specification import * 4 | import riscv_isac.plugins as plugins 5 | 6 | 7 | def interface (trace, arch, mode): 8 | 9 | ''' 10 | Arguments: 11 | Trace - Log_file_path 12 | Arch - Architecture 13 | Mode - Execution trace format 14 | 15 | ''' 16 | parser_pm = pluggy.PluginManager("parser") 17 | decoder_pm = pluggy.PluginManager("decoder") 18 | parser_pm.add_hookspecs(ParserSpec) 19 | decoder_pm.add_hookspecs(DecoderSpec) 20 | 21 | parserfile = importlib.import_module("riscv_isac.plugins."+mode) 22 | parserclass = getattr(parserfile, "mode_"+mode) 23 | parser_pm.register(parserclass()) 24 | parser = parser_pm.hook 25 | parser.setup(trace=trace,arch=arch) 26 | 27 | instructionObjectfile = importlib.import_module("riscv_isac.plugins.internalDecoder") 28 | decoderclass = getattr(instructionObjectfile, "disassembler") 29 | decoder_pm.register(decoderclass()) 30 | decoder = decoder_pm.hook 31 | decoder.setup(arch=arch) 32 | 33 | 34 | iterator = iter(parser.__iter__()[0]) 35 | 36 | for instr, mnemonic, addr, commitvalue in iterator: 37 | if instr is not None: 38 | instrObj = decoder.decode(instr=instr, addr=addr) -------------------------------------------------------------------------------- /riscv_isac/__init__.py: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | 3 | """Top-level package for RISC-V ISA Coverage.""" 4 | 5 | __author__ = """InCore Semiconductors Pvt Ltd""" 6 | __email__ = 'info@incoresemi.com' 7 | __version__ = '0.18.0' 8 | 9 | -------------------------------------------------------------------------------- /riscv_isac/cgf_normalize.py: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | from math import * 3 | import pprint 4 | import riscv_isac.utils as utils 5 | import itertools 6 | import random 7 | import copy 8 | from riscv_isac.fp_dataset import * 9 | 10 | import time 11 | 12 | def twos(val,bits): 13 | ''' 14 | Finds the twos complement of the number 15 | :param val: input to be complemented 16 | :param bits: size of the input 17 | 18 | :type val: str or int 19 | :type bits: int 20 | 21 | :result: two's complement version of the input 22 | 23 | ''' 24 | if isinstance(val,str): 25 | if '0x' in val: 26 | val = int(val,16) 27 | else: 28 | val = int(val,2) 29 | if (val & (1 << (bits - 1))) != 0: 30 | val = val - (1 << bits) 31 | return val 32 | 33 | def simd_val_comb(xlen, bit_width, signed=True): 34 | ''' 35 | This function returns coverpoints for operands rs1 and rs2 holding SIMD values. A set of coverpoints will be produced for each SIMD element. 36 | 37 | :param xlen: size of the integer registers 38 | :param bit_width: size of each SIMD element 39 | :param signed: whether the SIMD elements are signed or unsigned 40 | 41 | :type xlen: int 42 | :type bit_width: int 43 | :type signed: bool 44 | ''' 45 | 46 | fmt = {8: 'b', 16: 'h', 32: 'w', 64: 'd'} 47 | sz = fmt[bit_width] 48 | var_num = xlen//bit_width 49 | coverpoints = [] 50 | for i in range(var_num): 51 | var1 = f'rs1_{sz}{i}_val' 52 | var2 = f'rs2_{sz}{i}_val' 53 | if (signed): 54 | coverpoints += [(f'{var1} > 0 and {var2} > 0','simd_val_comb')] 55 | coverpoints += [(f'{var1} > 0 and {var2} < 0','simd_val_comb')] 56 | coverpoints += [(f'{var1} < 0 and {var2} < 0','simd_val_comb')] 57 | coverpoints += [(f'{var1} < 0 and {var2} > 0','simd_val_comb')] 58 | coverpoints += [(f'{var1} == {var2}','simd_val_comb')] 59 | coverpoints += [(f'{var1} != {var2}','simd_val_comb')] 60 | else: 61 | coverpoints += [(f'{var1} == {var2} and {var1} > 0 and {var2} > 0','simd_val_comb')] 62 | coverpoints += [(f'{var1} != {var2} and {var1} > 0 and {var2} > 0','simd_val_comb')] 63 | 64 | return coverpoints 65 | 66 | def simd_base_val(rs, xlen, bit_width, signed=True): 67 | ''' 68 | This function returns datasets for an operand holding SIMD values. One set of data will be produced for each SIMD element. 69 | 70 | :param rs: operand name: "rs1" or "rs2" 71 | :param xlen: size of the integer registers 72 | :param bit_width: size of each SIMD element 73 | :param signed: whether the SIMD elements are signed or unsigned 74 | 75 | :type rs: str 76 | :type xlen: int 77 | :type bit_width: int 78 | :type signed: bool 79 | ''' 80 | 81 | fmt = {8: 'b', 16: 'h', 32: 'w', 64: 'd'} 82 | 83 | sz = fmt[bit_width] 84 | var_num = xlen//bit_width 85 | sign_val = [(-2**(bit_width-1)), -1, 0, 1, int((2**(bit_width-1)-1))] 86 | usign_val = [0, 1, 2**bit_width-2, 2**bit_width-1] 87 | coverpoints = [] 88 | for i in range(var_num): 89 | var = f'{rs}_{sz}{i}_val' 90 | if (signed): 91 | for val in sign_val: 92 | coverpoints += [(f'{var} == {val}', 'signed_min_max_middle')] 93 | coverpoints += walking_ones(var, bit_width, True) 94 | coverpoints += walking_zeros(var, bit_width, True) 95 | coverpoints += alternate(var, bit_width, True) 96 | else: 97 | for val in usign_val: 98 | coverpoints += [(f'{var} == {val}','unsigned_min_max_middle')] 99 | coverpoints += walking_ones(var, bit_width, False) 100 | coverpoints += walking_zeros(var, bit_width, False) 101 | coverpoints += alternate(var, bit_width, False) 102 | return coverpoints 103 | 104 | def simd_imm_val(imm, bit_width): 105 | ''' 106 | This function returns coverpoints for unsigned immediate operands, between 0 .. ((2**bit_width)-1) 107 | 108 | :param imm: name of the immediate operand. 109 | :param bit_width: bit width of the immediate operand 110 | 111 | :type imm: str 112 | :type bit_width: int 113 | ''' 114 | usign_val = 2**bit_width 115 | coverpoints = [] 116 | for i in range(usign_val): 117 | coverpoints += [(f'{imm} == {i}','simd_imm_val')] 118 | return coverpoints 119 | 120 | def sp_vals(bit_width,signed): 121 | if signed: 122 | conv_func = lambda x: twos(x,bit_width) 123 | sqrt_min = int(-sqrt(2**(bit_width-1))) 124 | sqrt_max = int(sqrt((2**(bit_width-1)-1))) 125 | else: 126 | sqrt_min = 0 127 | sqrt_max = int(sqrt((2**bit_width)-1)) 128 | conv_func = lambda x: (int(x,16) if '0x' in x else int(x,2)) if isinstance(x,str) else x 129 | dataset = [3, "0x"+"".join(["5"]*int(bit_width/4)), "0x"+"".join(["a"]*int(bit_width/4)), 5, "0x"+"".join(["3"]*int(bit_width/4)), "0x"+"".join(["6"]*int(bit_width/4))] 130 | dataset = list(map(conv_func,dataset)) + [int(sqrt(abs(conv_func("0x8"+"".join(["0"]*int((bit_width/4)-1)))))*(-1 if signed else 1))] + [sqrt_min,sqrt_max] 131 | return dataset + [x - 1 if x>0 else 0 for x in dataset] + [x+1 for x in dataset] 132 | 133 | def bitmanip_dataset(bit_width,var_lst=["rs1_val","rs2_val"],signed=True): 134 | ''' 135 | Functions creates coverpoints for bitmanip instructions with following patterns 136 | 0x3, 0xc, 0x5,0xa,0x6,0x9,0 each of the pattern exenteding for bit_width 137 | for 32 bit 138 | 0x33333333,0xcccccccc,0x55555555, 0xaaaaaaaaa,0x66666666,0x99999999 139 | for 64 bit 140 | 0x3333333333333333,0xcccccccccccccccc,0x5555555555555555, 0xaaaaaaaaaaaaaaaaa, 141 | 0x6666666666666666,0x9999999999999999 142 | - +1 and -1 variants of the above pattern 143 | 144 | 145 | :param bit_width: Integer defining the size of the input 146 | :param sign: Boolen value specifying whether the dataset should be interpreted as signed numbers or not. 147 | :type sign: bool 148 | :type bit_width: int 149 | :return: dictionary of coverpoints 150 | ''' 151 | 152 | datasets = [] 153 | coverpoints = [] 154 | if signed: 155 | conv_func = lambda x: twos(x,bit_width) 156 | else: 157 | conv_func = lambda x: (int(x,16) if '0x' in x else int(x,2)) if isinstance(x,str) else x 158 | # dataset for 0x5, 0xa, 0x3, 0xc, 0x6, 0x9 patterns 159 | dataset = ["0x"+"".join(["5"]*int(bit_width/4)), "0x"+"".join(["a"]*int(bit_width/4)), "0x"+"".join(["3"]*int(bit_width/4)), "0x"+"".join(["c"]*int(bit_width/4)),"0x"+"".join(["6"]*int(bit_width/4)),"0x"+"".join(["9"]*int(bit_width/4))] 160 | dataset = list(map(conv_func,dataset)) 161 | 162 | # dataset0 is for 0,1 and 0xf pattern. 0xf pattern is added instead of -1 so that code for checking coverpoints in coverage.py 163 | # is kept simple. 164 | 165 | dataset0 = [0,1,"0x"+"".join(["f"]*int(bit_width/4))] 166 | dataset0 = list(map(conv_func,dataset0)) 167 | dataset = dataset + [x - 1 for x in dataset] + [x+1 for x in dataset] + dataset0 168 | for var in var_lst: 169 | datasets.append(dataset) 170 | dataset = itertools.product(*datasets) 171 | for entry in dataset: 172 | coverpoints.append(' and '.join([var_lst[i]+"=="+str(entry[i]) for i in range(len(var_lst))])) 173 | return [(coverpoint,"Bitmanip Dataset") for coverpoint in coverpoints] 174 | 175 | 176 | 177 | def sp_dataset(bit_width,var_lst=["rs1_val","rs2_val"],signed=True): 178 | coverpoints = [] 179 | datasets = [] 180 | var_names = [] 181 | for var in var_lst: 182 | if isinstance(var,tuple) or isinstance(var,list): 183 | if len(var) == 3: 184 | var_sgn = var[2] 185 | else: 186 | var_sgn = signed 187 | var_names.append(var[0]) 188 | datasets.append(sp_vals(int(var[1]),var_sgn)) 189 | else: 190 | var_names.append(var) 191 | datasets.append(sp_vals(bit_width,signed)) 192 | dataset = itertools.product(*datasets) 193 | for entry in dataset: 194 | coverpoints.append(' and '.join([var_names[i]+"=="+str(entry[i]) for i in range(len(var_names))])) 195 | return [(coverpoint,"Special Dataset") for coverpoint in coverpoints] 196 | 197 | def walking_ones(var, size, signed=True, fltr_func=None, scale_func=None): 198 | ''' 199 | This function converts an abstract walking-ones function into individual 200 | coverpoints that can be used by ISAC. The unrolling of the function accounts 201 | of the size, sign-bit, filters and scales. The unrolled coverpoints will 202 | contain a pattern a single one trickling down from LSB to MSB. The final 203 | coverpoints can vary depending on the filtering and scaling functions 204 | 205 | :param var: input variable that needs to be assigned the coverpoints 206 | :param size: size of the bit-vector to generate walking-1s 207 | :param signed: when true indicates that the unrolled points be treated as signed integers. 208 | :param fltr_func: a lambda function which defines a filtering routine to keep only a certain values from the unrolled coverpoints 209 | :param scale_func: a lambda function which defines the scaling that should be applied to the unrolled coverpoints that have been generated. 210 | 211 | :type var: str 212 | :type size: int 213 | :type signed: bool 214 | :type fltr_func: function 215 | :type scale_func: function 216 | :result: dictionary of unrolled filtered and scaled coverpoints 217 | ''' 218 | if not signed: 219 | dataset = [1 << exp for exp in range(size)] 220 | else: 221 | dataset = [twos(1 << exp,size) for exp in range(size)] 222 | if scale_func: 223 | dataset = [scale_func(x) for x in dataset] 224 | if fltr_func: 225 | dataset = filter(fltr_func,dataset) 226 | coverpoints =[] 227 | for d in dataset: 228 | coverpoints.append((var + ' == ' + str(d),'Walking Ones: '+str(hex(d)))) 229 | return coverpoints 230 | 231 | def walking_zeros(var, size,signed=True, fltr_func=None, scale_func=None): 232 | ''' 233 | This function converts an abstract walking-zeros function into individual 234 | coverpoints that can be used by ISAC. The unrolling of the function accounts 235 | of the size, sign-bit, filters and scales. The unrolled coverpoints will 236 | contain a pattern a single zero trickling down from LSB to MSB. The final 237 | coverpoints can vary depending on the filtering and scaling functions 238 | 239 | :param var: input variable that needs to be assigned the coverpoints 240 | :param size: size of the bit-vector to generate walking-1s 241 | :param signed: when true indicates that the unrolled points be treated as signed integers. 242 | :param fltr_func: a lambda function which defines a filtering routine to keep only a certain values from the unrolled coverpoints 243 | :param scale_func: a lambda function which defines the scaling that should be applied to the unrolled coverpoints that have been generated. 244 | 245 | :type var: str 246 | :type size: int 247 | :type signed: bool 248 | :type fltr_func: function 249 | :type scale_func: function 250 | :result: dictionary of unrolled filtered and scaled coverpoints 251 | ''' 252 | mask = 2**size -1 253 | if not signed: 254 | dataset = [(1 << exp)^mask for exp in range(size)] 255 | else: 256 | dataset = [twos((1 << exp)^mask,size) for exp in range(size)] 257 | if scale_func: 258 | dataset = [scale_func(x) for x in dataset] 259 | if fltr_func: 260 | dataset = filter(fltr_func,dataset) 261 | coverpoints =[] 262 | for d in dataset: 263 | coverpoints.append((var + ' == ' + str(d),'Walking Zeros: '+str(hex(d)))) 264 | return coverpoints 265 | 266 | def byte_count(xlen, variables=['rs1_val','rs2_val','imm_val'], overlap = "N"): 267 | ''' 268 | Test pattern 1: SBox Testing 269 | This uses the byte-count pattern described above. 270 | Generate a 256-byte sequence 0..255 and pack the sequence into 32-bit words. 271 | Each word in the sequence is the rs2 input. The rs1 input is set to zero so we do not alter the SBox output value. 272 | For each input word, generate 4 instructions, with bs=0..3. 273 | This will mean that every possible SBox input pattern is tested. 274 | 275 | :param xlen: size of the bit-vector to generate byte-count pattern 276 | :param variables: list of string variables indicating the operands 277 | :param overlap: Set "Y" to test byte-count pattern on lower word of the xlen-bit vector, else set "N". 278 | 279 | :type xlen: int 280 | :type variables: List[str] 281 | :type overlap: str 282 | 283 | ''' 284 | rs1 = 0 285 | rs2 = [] 286 | coverpoints = [] 287 | hex_str = "" 288 | i=0 289 | cvpt = "" 290 | max = 255 291 | if overlap == "Y": 292 | max += xlen/16 293 | while(i<=max): 294 | hex_str = "{:02x}".format(i % 256) + hex_str 295 | if((len(hex_str)/2)%(xlen/8) == 0): 296 | rs2.append('0x'+hex_str) 297 | hex_str = "" 298 | if(overlap == "Y"): 299 | i=int(i-(xlen/16)) 300 | i=i+1 301 | 302 | if xlen == 32: 303 | for i in range(len(rs2)): 304 | for j in range(4): 305 | coverpoints.append(variables[0] +' == '+ str(rs1) +' and '+ variables[1] +' == '+ rs2[i] + ' and '+ variables[2] +' == '+ str(j) + ' #nosat') 306 | else: 307 | if variables[1] == "rs2_val": 308 | for i in range(len(rs2)): 309 | if((i+1)%2==0): 310 | y = rs2[i-1] 311 | x = rs2[i] 312 | else: 313 | x = rs2[i] 314 | y = rs2[i+1] 315 | cvpt = variables[0] +' == '+ x +' and '+ variables[1] +' == '+ y 316 | if len(variables)==3: 317 | if variables[2] == "imm_val": 318 | for j in range(4): 319 | coverpoints.append(cvpt+' and imm_val == '+ str(j) + ' #nosat') 320 | else: 321 | coverpoints.append(cvpt + ' #nosat') 322 | cvpt = "" 323 | elif variables[1] == "imm_val": 324 | for i in range(len(rs2)): 325 | coverpoints.append(variables[0] +' == '+ rs2[i] +' and '+ variables[1] +' == 0xA' + ' #nosat') 326 | return [(coverpoint,"Byte Count") for coverpoint in coverpoints] 327 | 328 | def uniform_random(N=10, seed=9, variables=['rs1_val','rs2_val','imm_val'], size=[32,32,2]): 329 | ''' 330 | Test pattern 2: Uniform Random 331 | Generate uniform random values for rs1, rs2 and bs. 332 | Let register values be un-constrained: 0..31. 333 | Repeat N times for each instruction until sufficient coverage is reached. 334 | 335 | :param N: Number of random combinations to be generated 336 | :param seed: intial seed value of the random library 337 | :param variables: list of string variables indicating the operands 338 | :param size: list of bit-sizes of each variable defined in variables. 339 | 340 | :type N: int 341 | :type seed: int 342 | :type variables: List[str] 343 | :type size: List[int] 344 | 345 | ''' 346 | random.seed(seed) 347 | 348 | coverpoints = [] 349 | while N!= 0: 350 | random_vals = [] 351 | for v in range(len(variables)): 352 | val = random.randint(0,2**int(size[v])-1) 353 | random_vals.append(variables[v] + \ 354 | ' == {0:#0{1}x}'.format(val,int(size[v]/4)+2)) 355 | coverpoints.append((" and ".join(random_vals) + " #nosat",\ 356 | "Uniform Random "+str(N))) 357 | N = N-1 358 | 359 | return coverpoints 360 | 361 | def leading_ones(xlen, var = ['rs1_val','rs2_val'], sizes = [32,32], seed = 10): 362 | ''' 363 | For each variable in var, generate a random input value, and set the most-significant i bits. 364 | See the other rs input and set a random value. 365 | 366 | :param xlen: size of the bit-vector to generate leading-1s 367 | :param var: list of string variables indicating the operands 368 | :param sizes: list of sizes of the variables in var 369 | :param seed: intial seed value of the random library 370 | 371 | :type xlen: int 372 | :type var: List[str] 373 | :type sizes: List[int] 374 | :type seed: int 375 | ''' 376 | random.seed(seed) 377 | coverpoints = [] 378 | for i in range(0,len(var)): 379 | curr_var = var[i] 380 | curr_sz = sizes[i] 381 | default = 2**curr_sz-1 382 | for sz in range(0,curr_sz+1): 383 | cvpt = '' 384 | val = (default << sz) & default 385 | setval = (1 << sz-1) ^ default if sz!=0 else default 386 | val = (val | random.randrange(1,2**curr_sz)) & default & setval 387 | cvpt += curr_var + ' == 0x{0:0{1}X}'.format(val,int(ceil(curr_sz/4))) 388 | cmnt = '{1} Leading ones for {0}. Other operands are random'.\ 389 | format(curr_var, curr_sz-sz) 390 | for othervars in range(0,len(var)): 391 | if othervars != i: 392 | otherval = random.randrange(0,2**sizes[othervars]) 393 | cvpt += ' and ' + var[othervars] + ' == 0x{0:0{1}X}'.format(otherval,int(ceil(sizes[othervars]/4))) 394 | coverpoints.append((cvpt+ " #nosat", cmnt)) 395 | return coverpoints 396 | 397 | def leading_zeros(xlen, var = ['rs1_val','rs2_val'], sizes = [32,32], seed = 11): 398 | ''' 399 | For each rs register input, generate a random XLEN input value, and clear the most-significant i bits. 400 | See the other rs input, pick a random value. 401 | 402 | :param xlen: size of the bit-vector to generate leading-0s 403 | :param var: list of string variables indicating the operands 404 | :param sizes: list of sizes of the variables in var 405 | :param seed: intial seed value of the random library 406 | 407 | :type xlen: int 408 | :type var: List[str] 409 | :type sizes: List[int] 410 | :type seed: int 411 | 412 | ''' 413 | random.seed(seed) 414 | coverpoints = [] 415 | for i in range(0,len(var)): 416 | curr_var = var[i] 417 | curr_sz = sizes[i] 418 | default = 2**curr_sz-1 419 | for sz in range(0,curr_sz+1): 420 | cvpt = '' 421 | val = (1 << sz)-1 & default 422 | setval = 1 << (sz-1) if sz!=0 else 0 423 | val = (val & random.randrange(1,2**curr_sz)) & default | setval 424 | cvpt += curr_var + ' == 0x{0:0{1}X}'.format(val,int(ceil(curr_sz/4))) 425 | cmnt = '{1} Leading zeros for {0}. Other operands are random'.\ 426 | format(curr_var, curr_sz-sz) 427 | for othervars in range(0,len(var)): 428 | if othervars != i: 429 | otherval = random.randrange(0,2**sizes[othervars]) 430 | cvpt += ' and ' + var[othervars] + ' == 0x{0:0{1}X}'.format(otherval,int(ceil(sizes[othervars]/4))) 431 | coverpoints.append((cvpt+ " #nosat",cmnt)) 432 | return coverpoints 433 | 434 | 435 | def trailing_zeros(xlen, var = ['rs1_val','rs2_val'], sizes = [32,32], seed = 12): 436 | ''' 437 | For each rs register input, generate a random XLEN input value, and clear the least-significant i bits. 438 | See the other rs input, pick a random value. 439 | 440 | :param xlen: size of the bit-vector to generate trailing-0s 441 | :param var: list of string variables indicating the operands 442 | :param sizes: list of sizes of the variables in var 443 | :param seed: intial seed value of the random library 444 | 445 | :type xlen: int 446 | :type var: List[str] 447 | :type sizes: List[int] 448 | :type seed: int 449 | 450 | ''' 451 | random.seed(seed) 452 | coverpoints = [] 453 | for i in range(0,len(var)): 454 | curr_var = var[i] 455 | curr_sz = sizes[i] 456 | default = 2**curr_sz-1 457 | for sz in range(0,curr_sz+1): 458 | cvpt = '' 459 | val = (default << sz) & default 460 | setval = (1 << sz) & default 461 | val = (val & (random.randrange(1,2**curr_sz)<> sz) 500 | val = val & setval 501 | cvpt += curr_var + ' == 0x{0:0{1}X}'.format(val,int(ceil(curr_sz/4))) 502 | cmnt = '{1} Trailing ones for {0}. Other operands are random'.\ 503 | format(curr_var, curr_sz-sz) 504 | for othervars in range(0,len(var)): 505 | if othervars != i: 506 | otherval = random.randrange(0,2**sizes[othervars]) 507 | cvpt += ' and ' + var[othervars] + ' == 0x{0:0{1}X}'.format(otherval,int(ceil(sizes[othervars]/4))) 508 | coverpoints.append((cvpt+ " #nosat",cmnt)) 509 | return coverpoints 510 | 511 | 512 | def alternate(var, size, signed=True, fltr_func=None,scale_func=None): 513 | ''' 514 | This function converts an abstract alternate function into individual 515 | coverpoints that can be used by ISAC. The unrolling of the function accounts 516 | of the size, sign-bit, filters and scales. The unrolled coverpoints will 517 | contain a pattern of alternating 1s and 0s. The final 518 | coverpoints can vary depending on the filtering and scaling functions 519 | 520 | :param var: input variable that needs to be assigned the coverpoints 521 | :param size: size of the bit-vector to generate walking-1s 522 | :param signed: when true indicates that the unrolled points be treated as signed integers. 523 | :param fltr_func: a lambda function which defines a filtering routine to keep only a certain values from the unrolled coverpoints 524 | :param scale_func: a lambda function which defines the scaling that should be applied to the unrolled coverpoints that have been generated. 525 | 526 | :type var: str 527 | :type size: int 528 | :type signed: bool 529 | :type fltr_func: function 530 | :type scale_func: function 531 | 532 | :result: dictionary of unrolled filtered and scaled coverpoints 533 | ''' 534 | t1 =( '' if size%2 == 0 else '1') + ''.join(['01']*int(size/2)) 535 | t2 =( '' if size%2 == 0 else '0') + ''.join(['10']*int(size/2)) 536 | if not signed: 537 | dataset = [int(t1,2),int(t2,2)] 538 | else: 539 | dataset = [twos(t1,size),twos(t2,size)] 540 | if scale_func: 541 | dataset = [scale_func(x) for x in dataset] 542 | if fltr_func: 543 | dataset = filter(fltr_func,dataset) 544 | coverpoints =[] 545 | for d in dataset: 546 | coverpoints.append((var + ' == ' + str(d),'Alternate: '+str(hex(d)))) 547 | return coverpoints 548 | #coverpoints = [var + ' == ' + str(d) for d in dataset] 549 | #return [(coverpoint,"Alternate") for coverpoint in coverpoints] 550 | 551 | 552 | def expand_cgf(cgf_files, xlen,flen, log_redundant=False): 553 | ''' 554 | This function will replace all the abstract functions with their unrolled 555 | coverpoints. It replaces node 556 | 557 | :param cgf_files: list of yaml file paths which together define the coverpoints 558 | :param xlen: XLEN of the DUT/Configuration 559 | :param flen: FLEN of the DUT/Configuration 560 | 561 | :type cgf: list 562 | :type xlen: int 563 | :type flen: int 564 | ''' 565 | cgf = utils.load_cgf(cgf_files) 566 | for labels, cats in cgf.items(): 567 | if labels != 'datasets': 568 | # If 'opcode' found, rename it to 'mnemonics' 569 | if 'opcode' in cats: 570 | logger.warning("Deprecated node used: 'opcode'. Use 'mnemonics' instead") 571 | 572 | temp = cgf[labels]['opcode'] 573 | del cgf[labels]['opcode'] 574 | cgf[labels].insert(1, 'mnemonics', temp) 575 | 576 | if 'base_op' in cats: 577 | if 'p_op_cond' not in cats: 578 | logger.error(f'p_op_cond node not found in {labels} label.') 579 | 580 | if len(cgf[labels]['mnemonics'].keys()) > 1: 581 | logger.error(f'Multiple instruction mnemonics found when base_op label defined in {labels} label.') 582 | 583 | # Substitute instruction aliases with equivalent tuple of instructions 584 | if 'cross_comb' in cats: 585 | temp = cats['cross_comb'] 586 | 587 | for covp, covge in dict(temp).items(): 588 | data = covp.split('::') 589 | ops = data[0].replace(' ', '')[1:-1].split(':') 590 | # Substitute with tuple of instructions 591 | for i in range(len(ops)): 592 | exp_alias = utils.import_instr_alias(ops[i]) 593 | if exp_alias != None: 594 | ops[i] = tuple(exp_alias).__str__().replace("'", '').replace(" ", '') 595 | 596 | data[0] = '[' + ':'.join(ops) + ']' 597 | data = '::'.join(data) 598 | del temp[covp] 599 | temp[data] = covge 600 | 601 | cgf[labels].insert(1, 'cross_comb', temp) 602 | 603 | l = len(cats.items()) 604 | i = 0 605 | for label,node in cats.items(): 606 | if isinstance(node,dict): 607 | if 'abstract_comb' in node: 608 | temp = node['abstract_comb'] 609 | del node['abstract_comb'] 610 | for coverpoints, coverage in temp.items(): 611 | i = 0 612 | try: 613 | exp_cp = eval(coverpoints) 614 | except Exception as e: 615 | logger.error("Error evaluating abstract comb: "+(coverpoints)\ 616 | +" in "+labels+": "+str(e) ) 617 | else: 618 | for cp,comment in exp_cp: 619 | if log_redundant and cp in cgf[labels][label]: 620 | logger.warn(f'Redundant coverpoint during normalization: {cp}') 621 | cgf[labels][label].insert(l+i,cp,coverage,comment=comment) 622 | i += 1 623 | return dict(cgf) 624 | 625 | -------------------------------------------------------------------------------- /riscv_isac/constants.py: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | 3 | import os 4 | 5 | root = os.path.abspath(os.path.dirname(__file__)) 6 | 7 | cwd = os.getcwd() 8 | 9 | dpr_template = ''' 10 | # Data Propagation Report 11 | 12 | - **STAT1** : Number of instructions that hit unique coverpoints and update the signature 13 | - **STAT2** : Number of instructions that hit covepoints which are not unique but still update the signature (completely or partially) 14 | - **STAT3** : Number of instructions that hit a unique coverpoint but do not update the signature completely 15 | - **STAT4** : Number of multiple signature updates for the same coverpoint 16 | - **STAT5** : Number of times the signature was overwritten 17 | 18 | | Param | Value | 19 | |---------------------------|----------| 20 | | XLEN | {0} | 21 | | TEST_REGION | {1} | 22 | | SIG_REGION | {2} | 23 | | COV_LABELS | {3} | 24 | | TEST_NAME | {4}.S | 25 | | Total Number of coverpoints| {5} | 26 | | Total Coverpoints Hit | {7} | 27 | | Total Signature Updates | {6} | 28 | | STAT1 | {8} | 29 | | STAT2 | {9} | 30 | | STAT3 | {10} | 31 | | STAT4 | {11} | 32 | | STAT5 | {12} | 33 | 34 | ## Details for STAT2: 35 | 36 | ``` 37 | {13} 38 | 39 | ``` 40 | 41 | ## Details of STAT3 42 | 43 | ``` 44 | {14} 45 | 46 | ``` 47 | 48 | ## Details of STAT4: 49 | 50 | ``` 51 | {15} 52 | ``` 53 | 54 | ## Details of STAT5: 55 | 56 | {16} 57 | 58 | ## Details of STAT1: 59 | 60 | - The first column indicates the signature address(es) and the data at that location in hexadecimal in the following format: 61 | ``` 62 | [Address1] 63 | Data1 64 | 65 | [Address2] 66 | Data2 67 | 68 | ... 69 | ``` 70 | 71 | - The second column captures all the coverpoints which have been captured by that particular signature location 72 | 73 | - The third column captures all the insrtuctions since the time a coverpoint was 74 | hit to the point when a store to the signature was performed. Each line has 75 | the following format: 76 | ``` 77 | [PC of instruction] : mnemonic 78 | ``` 79 | - The order in the table is based on the order of signatures occuring in the 80 | test. These need not necessarily be in increasing or decreasing order of the 81 | address in the signature region. 82 | 83 | ''' 84 | -------------------------------------------------------------------------------- /riscv_isac/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riscv-software-src/riscv-isac/777d2b47623d7eebdb8bbed06dbddedc33722346/riscv_isac/data/__init__.py -------------------------------------------------------------------------------- /riscv_isac/data/constants.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | isa_regex = \ 5 | re.compile("^RV(32|64|128)[IE]+[ABCDEFGHJKLMNPQSTUVX]*(Zfinx|Zfh|Zicsr|Zifencei|Zihintpause|Zam|Ztso|Zkne|Zknd|Zknh|Zkse|Zksh|Zkg|Zkb|Zkr|Zks|Zkn|Zba|Zbc|Zbb|Zbp|Zbr|Zbm|Zbs|Zbe|Zbf|Zbt|Zmmul|Zbpbo){,1}(_Zicsr){,1}(_Zifencei){,1}(_Zihintpause){,1}(_Zfinx){,1}(_Zfh){,1}(_Zmmul){,1}(_Zam){,1}(_Zba){,1}(_Zbb){,1}(_Zbc){,1}(_Zbe){,1}(_Zbf){,1}(_Zbm){,1}(_Zbp){,1}(_Zbpbo){,1}(_Zbr){,1}(_Zbs){,1}(_Zbt){,1}(_Zkb){,1}(_Zkg){,1}(_Zkr){,1}(_Zks){,1}(_Zkn){,1}(_Zknd){,1}(_Zkne){,1}(_Zknh){,1}(_Zkse){,1}(_Zksh){,1}(_Ztso){,1}$") 6 | 7 | # regex to find ..= patterns in instruction 8 | fixed_ranges = re.compile( 9 | '\s*(?P\d+.?)\.\.(?P\d+.?)\s*=\s*(?P\d[\w]*)[\s$]*', re.M) 10 | 11 | # regex to find = patterns in instructions 12 | #single_fixed = re.compile('\s+(?P\d+)=(?P[\w\d]*)[\s$]*', re.M) 13 | single_fixed = re.compile('(?:^|[\s])(?P\d+)=(?P[\w]*)((?=\s|$))', re.M) 14 | 15 | # regex to find the overloading condition variable 16 | var_regex = re.compile('(?P[a-zA-Z][\w\d]*)\s*=\s*.*?[\s$]*', re.M) 17 | 18 | # regex for pseudo op instructions returns the dependent filename, dependent 19 | # instruction, the pseudo op name and the encoding string 20 | pseudo_regex = re.compile( 21 | '^\$pseudo_op\s+(?Prv[\d]*_[\w].*)::\s*(?P.*?)\s+(?P.*?)\s+(?P.*)$' 22 | , re.M) 23 | 24 | imported_regex = re.compile('^\s*\$import\s*(?P.*)\s*::\s*(?P.*)', re.M) 25 | 26 | # 27 | # Trap cause codes 28 | causes = [ 29 | (0x00, 'misaligned fetch'), 30 | (0x01, 'fetch access'), 31 | (0x02, 'illegal instruction'), 32 | (0x03, 'breakpoint'), 33 | (0x04, 'misaligned load'), 34 | (0x05, 'load access'), 35 | (0x06, 'misaligned store'), 36 | (0x07, 'store access'), 37 | (0x08, 'user_ecall'), 38 | (0x09, 'supervisor_ecall'), 39 | (0x0A, 'virtual_supervisor_ecall'), 40 | (0x0B, 'machine_ecall'), 41 | (0x0C, 'fetch page fault'), 42 | (0x0D, 'load page fault'), 43 | (0x0F, 'store page fault'), 44 | (0x14, 'fetch guest page fault'), 45 | (0x15, 'load guest page fault'), 46 | (0x16, 'virtual instruction'), 47 | (0x17, 'store guest page fault'), 48 | ] 49 | 50 | csrs = [ 51 | # Standard User R/W 52 | (0x001, 'fflags'), 53 | (0x002, 'frm'), 54 | (0x003, 'fcsr'), 55 | (0x008, 'vstart'), 56 | (0x009, 'vxsat'), 57 | (0x00A, 'vxrm'), 58 | (0x00F, 'vcsr'), 59 | (0x015, 'seed'), # Zkr 60 | 61 | # Standard User RO 62 | (0xC00, 'cycle'), 63 | (0xC01, 'time'), 64 | (0xC02, 'instret'), 65 | (0xC03, 'hpmcounter3'), 66 | (0xC04, 'hpmcounter4'), 67 | (0xC05, 'hpmcounter5'), 68 | (0xC06, 'hpmcounter6'), 69 | (0xC07, 'hpmcounter7'), 70 | (0xC08, 'hpmcounter8'), 71 | (0xC09, 'hpmcounter9'), 72 | (0xC0A, 'hpmcounter10'), 73 | (0xC0B, 'hpmcounter11'), 74 | (0xC0C, 'hpmcounter12'), 75 | (0xC0D, 'hpmcounter13'), 76 | (0xC0E, 'hpmcounter14'), 77 | (0xC0F, 'hpmcounter15'), 78 | (0xC10, 'hpmcounter16'), 79 | (0xC11, 'hpmcounter17'), 80 | (0xC12, 'hpmcounter18'), 81 | (0xC13, 'hpmcounter19'), 82 | (0xC14, 'hpmcounter20'), 83 | (0xC15, 'hpmcounter21'), 84 | (0xC16, 'hpmcounter22'), 85 | (0xC17, 'hpmcounter23'), 86 | (0xC18, 'hpmcounter24'), 87 | (0xC19, 'hpmcounter25'), 88 | (0xC1A, 'hpmcounter26'), 89 | (0xC1B, 'hpmcounter27'), 90 | (0xC1C, 'hpmcounter28'), 91 | (0xC1D, 'hpmcounter29'), 92 | (0xC1E, 'hpmcounter30'), 93 | (0xC1F, 'hpmcounter31'), 94 | (0xC20, 'vl'), 95 | (0xC21, 'vtype'), 96 | (0xC22, 'vlenb'), 97 | 98 | # Standard Supervisor R/W 99 | (0x100, 'sstatus'), 100 | (0x102, 'sedeleg'), 101 | (0x103, 'sideleg'), 102 | (0x104, 'sie'), 103 | (0x105, 'stvec'), 104 | (0x106, 'scounteren'), 105 | (0x10A, 'senvcfg'), 106 | (0x140, 'sscratch'), 107 | (0x141, 'sepc'), 108 | (0x142, 'scause'), 109 | (0x143, 'stval'), 110 | (0x144, 'sip'), 111 | (0x180, 'satp'), 112 | (0x5A8, 'scontext'), 113 | 114 | # Standard Hypervisor R/w 115 | (0x200, 'vsstatus'), 116 | (0x204, 'vsie'), 117 | (0x205, 'vstvec'), 118 | (0x240, 'vsscratch'), 119 | (0x241, 'vsepc'), 120 | (0x242, 'vscause'), 121 | (0x243, 'vstval'), 122 | (0x244, 'vsip'), 123 | (0x280, 'vsatp'), 124 | (0x600, 'hstatus'), 125 | (0x602, 'hedeleg'), 126 | (0x603, 'hideleg'), 127 | (0x604, 'hie'), 128 | (0x605, 'htimedelta'), 129 | (0x606, 'hcounteren'), 130 | (0x607, 'hgeie'), 131 | (0x60A, 'henvcfg'), 132 | (0x643, 'htval'), 133 | (0x644, 'hip'), 134 | (0x645, 'hvip'), 135 | (0x64A, 'htinst'), 136 | (0x680, 'hgatp'), 137 | (0x6A8, 'hcontext'), 138 | (0xE12, 'hgeip'), 139 | 140 | # Tentative CSR assignment for CLIC 141 | (0x007, 'utvt'), 142 | (0x045, 'unxti'), 143 | (0x046, 'uintstatus'), 144 | (0x048, 'uscratchcsw'), 145 | (0x049, 'uscratchcswl'), 146 | (0x107, 'stvt'), 147 | (0x145, 'snxti'), 148 | (0x146, 'sintstatus'), 149 | (0x148, 'sscratchcsw'), 150 | (0x149, 'sscratchcswl'), 151 | (0x307, 'mtvt'), 152 | (0x345, 'mnxti'), 153 | (0x346, 'mintstatus'), 154 | (0x348, 'mscratchcsw'), 155 | (0x349, 'mscratchcswl'), 156 | 157 | # Standard Machine R/W 158 | (0x300, 'mstatus'), 159 | (0x301, 'misa'), 160 | (0x302, 'medeleg'), 161 | (0x303, 'mideleg'), 162 | (0x304, 'mie'), 163 | (0x305, 'mtvec'), 164 | (0x306, 'mcounteren'), 165 | (0x30a, 'menvcfg'), 166 | (0x320, 'mcountinhibit'), 167 | (0x340, 'mscratch'), 168 | (0x341, 'mepc'), 169 | (0x342, 'mcause'), 170 | (0x343, 'mtval'), 171 | (0x344, 'mip'), 172 | (0x34a, 'mtinst'), 173 | (0x34b, 'mtval2'), 174 | (0x3a0, 'pmpcfg0'), 175 | (0x3a1, 'pmpcfg1'), 176 | (0x3a2, 'pmpcfg2'), 177 | (0x3a3, 'pmpcfg3'), 178 | (0x3a4, 'pmpcfg4'), 179 | (0x3a5, 'pmpcfg5'), 180 | (0x3a6, 'pmpcfg6'), 181 | (0x3a7, 'pmpcfg7'), 182 | (0x3a8, 'pmpcfg8'), 183 | (0x3a9, 'pmpcfg9'), 184 | (0x3aa, 'pmpcfg10'), 185 | (0x3ab, 'pmpcfg11'), 186 | (0x3ac, 'pmpcfg12'), 187 | (0x3ad, 'pmpcfg13'), 188 | (0x3ae, 'pmpcfg14'), 189 | (0x3af, 'pmpcfg15'), 190 | (0x3b0, 'pmpaddr0'), 191 | (0x3b1, 'pmpaddr1'), 192 | (0x3b2, 'pmpaddr2'), 193 | (0x3b3, 'pmpaddr3'), 194 | (0x3b4, 'pmpaddr4'), 195 | (0x3b5, 'pmpaddr5'), 196 | (0x3b6, 'pmpaddr6'), 197 | (0x3b7, 'pmpaddr7'), 198 | (0x3b8, 'pmpaddr8'), 199 | (0x3b9, 'pmpaddr9'), 200 | (0x3ba, 'pmpaddr10'), 201 | (0x3bb, 'pmpaddr11'), 202 | (0x3bc, 'pmpaddr12'), 203 | (0x3bd, 'pmpaddr13'), 204 | (0x3be, 'pmpaddr14'), 205 | (0x3bf, 'pmpaddr15'), 206 | (0x3c0, 'pmpaddr16'), 207 | (0x3c1, 'pmpaddr17'), 208 | (0x3c2, 'pmpaddr18'), 209 | (0x3c3, 'pmpaddr19'), 210 | (0x3c4, 'pmpaddr20'), 211 | (0x3c5, 'pmpaddr21'), 212 | (0x3c6, 'pmpaddr22'), 213 | (0x3c7, 'pmpaddr23'), 214 | (0x3c8, 'pmpaddr24'), 215 | (0x3c9, 'pmpaddr25'), 216 | (0x3ca, 'pmpaddr26'), 217 | (0x3cb, 'pmpaddr27'), 218 | (0x3cc, 'pmpaddr28'), 219 | (0x3cd, 'pmpaddr29'), 220 | (0x3ce, 'pmpaddr30'), 221 | (0x3cf, 'pmpaddr31'), 222 | (0x3d0, 'pmpaddr32'), 223 | (0x3d1, 'pmpaddr33'), 224 | (0x3d2, 'pmpaddr34'), 225 | (0x3d3, 'pmpaddr35'), 226 | (0x3d4, 'pmpaddr36'), 227 | (0x3d5, 'pmpaddr37'), 228 | (0x3d6, 'pmpaddr38'), 229 | (0x3d7, 'pmpaddr39'), 230 | (0x3d8, 'pmpaddr40'), 231 | (0x3d9, 'pmpaddr41'), 232 | (0x3da, 'pmpaddr42'), 233 | (0x3db, 'pmpaddr43'), 234 | (0x3dc, 'pmpaddr44'), 235 | (0x3dd, 'pmpaddr45'), 236 | (0x3de, 'pmpaddr46'), 237 | (0x3df, 'pmpaddr47'), 238 | (0x3e0, 'pmpaddr48'), 239 | (0x3e1, 'pmpaddr49'), 240 | (0x3e2, 'pmpaddr50'), 241 | (0x3e3, 'pmpaddr51'), 242 | (0x3e4, 'pmpaddr52'), 243 | (0x3e5, 'pmpaddr53'), 244 | (0x3e6, 'pmpaddr54'), 245 | (0x3e7, 'pmpaddr55'), 246 | (0x3e8, 'pmpaddr56'), 247 | (0x3e9, 'pmpaddr57'), 248 | (0x3ea, 'pmpaddr58'), 249 | (0x3eb, 'pmpaddr59'), 250 | (0x3ec, 'pmpaddr60'), 251 | (0x3ed, 'pmpaddr61'), 252 | (0x3ee, 'pmpaddr62'), 253 | (0x3ef, 'pmpaddr63'), 254 | (0x747, 'mseccfg'), 255 | (0x7a0, 'tselect'), 256 | (0x7a1, 'tdata1'), 257 | (0x7a2, 'tdata2'), 258 | (0x7a3, 'tdata3'), 259 | (0x7a4, 'tinfo'), 260 | (0x7a5, 'tcontrol'), 261 | (0x7a8, 'mcontext'), 262 | (0x7aa, 'mscontext'), 263 | (0x7b0, 'dcsr'), 264 | (0x7b1, 'dpc'), 265 | (0x7b2, 'dscratch0'), 266 | (0x7b3, 'dscratch1'), 267 | (0xB00, 'mcycle'), 268 | (0xB02, 'minstret'), 269 | (0xB03, 'mhpmcounter3'), 270 | (0xB04, 'mhpmcounter4'), 271 | (0xB05, 'mhpmcounter5'), 272 | (0xB06, 'mhpmcounter6'), 273 | (0xB07, 'mhpmcounter7'), 274 | (0xB08, 'mhpmcounter8'), 275 | (0xB09, 'mhpmcounter9'), 276 | (0xB0A, 'mhpmcounter10'), 277 | (0xB0B, 'mhpmcounter11'), 278 | (0xB0C, 'mhpmcounter12'), 279 | (0xB0D, 'mhpmcounter13'), 280 | (0xB0E, 'mhpmcounter14'), 281 | (0xB0F, 'mhpmcounter15'), 282 | (0xB10, 'mhpmcounter16'), 283 | (0xB11, 'mhpmcounter17'), 284 | (0xB12, 'mhpmcounter18'), 285 | (0xB13, 'mhpmcounter19'), 286 | (0xB14, 'mhpmcounter20'), 287 | (0xB15, 'mhpmcounter21'), 288 | (0xB16, 'mhpmcounter22'), 289 | (0xB17, 'mhpmcounter23'), 290 | (0xB18, 'mhpmcounter24'), 291 | (0xB19, 'mhpmcounter25'), 292 | (0xB1A, 'mhpmcounter26'), 293 | (0xB1B, 'mhpmcounter27'), 294 | (0xB1C, 'mhpmcounter28'), 295 | (0xB1D, 'mhpmcounter29'), 296 | (0xB1E, 'mhpmcounter30'), 297 | (0xB1F, 'mhpmcounter31'), 298 | (0x323, 'mhpmevent3'), 299 | (0x324, 'mhpmevent4'), 300 | (0x325, 'mhpmevent5'), 301 | (0x326, 'mhpmevent6'), 302 | (0x327, 'mhpmevent7'), 303 | (0x328, 'mhpmevent8'), 304 | (0x329, 'mhpmevent9'), 305 | (0x32A, 'mhpmevent10'), 306 | (0x32B, 'mhpmevent11'), 307 | (0x32C, 'mhpmevent12'), 308 | (0x32D, 'mhpmevent13'), 309 | (0x32E, 'mhpmevent14'), 310 | (0x32F, 'mhpmevent15'), 311 | (0x330, 'mhpmevent16'), 312 | (0x331, 'mhpmevent17'), 313 | (0x332, 'mhpmevent18'), 314 | (0x333, 'mhpmevent19'), 315 | (0x334, 'mhpmevent20'), 316 | (0x335, 'mhpmevent21'), 317 | (0x336, 'mhpmevent22'), 318 | (0x337, 'mhpmevent23'), 319 | (0x338, 'mhpmevent24'), 320 | (0x339, 'mhpmevent25'), 321 | (0x33A, 'mhpmevent26'), 322 | (0x33B, 'mhpmevent27'), 323 | (0x33C, 'mhpmevent28'), 324 | (0x33D, 'mhpmevent29'), 325 | (0x33E, 'mhpmevent30'), 326 | (0x33F, 'mhpmevent31'), 327 | 328 | # Standard Machine RO 329 | (0xF11, 'mvendorid'), 330 | (0xF12, 'marchid'), 331 | (0xF13, 'mimpid'), 332 | (0xF14, 'mhartid'), 333 | (0xF15, 'mconfigptr'), 334 | ] 335 | 336 | csrs32 = [ 337 | # Standard Hypervisor R/w 338 | (0x615, 'htimedeltah'), 339 | (0x61A, 'henvcfgh'), 340 | 341 | # Standard User RO 342 | (0xC80, 'cycleh'), 343 | (0xC81, 'timeh'), 344 | (0xC82, 'instreth'), 345 | (0xC83, 'hpmcounter3h'), 346 | (0xC84, 'hpmcounter4h'), 347 | (0xC85, 'hpmcounter5h'), 348 | (0xC86, 'hpmcounter6h'), 349 | (0xC87, 'hpmcounter7h'), 350 | (0xC88, 'hpmcounter8h'), 351 | (0xC89, 'hpmcounter9h'), 352 | (0xC8A, 'hpmcounter10h'), 353 | (0xC8B, 'hpmcounter11h'), 354 | (0xC8C, 'hpmcounter12h'), 355 | (0xC8D, 'hpmcounter13h'), 356 | (0xC8E, 'hpmcounter14h'), 357 | (0xC8F, 'hpmcounter15h'), 358 | (0xC90, 'hpmcounter16h'), 359 | (0xC91, 'hpmcounter17h'), 360 | (0xC92, 'hpmcounter18h'), 361 | (0xC93, 'hpmcounter19h'), 362 | (0xC94, 'hpmcounter20h'), 363 | (0xC95, 'hpmcounter21h'), 364 | (0xC96, 'hpmcounter22h'), 365 | (0xC97, 'hpmcounter23h'), 366 | (0xC98, 'hpmcounter24h'), 367 | (0xC99, 'hpmcounter25h'), 368 | (0xC9A, 'hpmcounter26h'), 369 | (0xC9B, 'hpmcounter27h'), 370 | (0xC9C, 'hpmcounter28h'), 371 | (0xC9D, 'hpmcounter29h'), 372 | (0xC9E, 'hpmcounter30h'), 373 | (0xC9F, 'hpmcounter31h'), 374 | 375 | # Standard Machine RW 376 | (0x310, 'mstatush'), 377 | (0x31A, 'menvcfgh'), 378 | (0x757, 'mseccfgh'), 379 | (0xB80, 'mcycleh'), 380 | (0xB82, 'minstreth'), 381 | (0xB83, 'mhpmcounter3h'), 382 | (0xB84, 'mhpmcounter4h'), 383 | (0xB85, 'mhpmcounter5h'), 384 | (0xB86, 'mhpmcounter6h'), 385 | (0xB87, 'mhpmcounter7h'), 386 | (0xB88, 'mhpmcounter8h'), 387 | (0xB89, 'mhpmcounter9h'), 388 | (0xB8A, 'mhpmcounter10h'), 389 | (0xB8B, 'mhpmcounter11h'), 390 | (0xB8C, 'mhpmcounter12h'), 391 | (0xB8D, 'mhpmcounter13h'), 392 | (0xB8E, 'mhpmcounter14h'), 393 | (0xB8F, 'mhpmcounter15h'), 394 | (0xB90, 'mhpmcounter16h'), 395 | (0xB91, 'mhpmcounter17h'), 396 | (0xB92, 'mhpmcounter18h'), 397 | (0xB93, 'mhpmcounter19h'), 398 | (0xB94, 'mhpmcounter20h'), 399 | (0xB95, 'mhpmcounter21h'), 400 | (0xB96, 'mhpmcounter22h'), 401 | (0xB97, 'mhpmcounter23h'), 402 | (0xB98, 'mhpmcounter24h'), 403 | (0xB99, 'mhpmcounter25h'), 404 | (0xB9A, 'mhpmcounter26h'), 405 | (0xB9B, 'mhpmcounter27h'), 406 | (0xB9C, 'mhpmcounter28h'), 407 | (0xB9D, 'mhpmcounter29h'), 408 | (0xB9E, 'mhpmcounter30h'), 409 | (0xB9F, 'mhpmcounter31h'), 410 | ] 411 | 412 | # look up table of position of various arguments that are used by the 413 | # instructions in the encoding files. 414 | arg_lut = {} 415 | arg_lut['rd'] = (11, 7) 416 | arg_lut['rt'] = (19, 15) # source+dest register address. Overlaps rs1. 417 | arg_lut['rs1'] = (19, 15) 418 | arg_lut['rs2'] = (24, 20) 419 | arg_lut['rs3'] = (31, 27) 420 | arg_lut['aqrl'] = (26, 25) 421 | arg_lut['aq'] = (26, 26) 422 | arg_lut['rl'] = (25, 25) 423 | arg_lut['fm'] = (31, 28) 424 | arg_lut['pred'] = (27, 24) 425 | arg_lut['succ'] = (23, 20) 426 | arg_lut['rm'] = (14, 12) 427 | arg_lut['funct3'] = (14, 12) 428 | arg_lut['funct2'] = (26, 25) 429 | arg_lut['imm20'] = (31, 12) 430 | arg_lut['jimm20'] = (31, 12) 431 | arg_lut['imm12'] = (31, 20) 432 | arg_lut['csr'] = (31, 20) 433 | arg_lut['imm12hi'] = (31, 25) 434 | arg_lut['bimm12hi'] = (31, 25) 435 | arg_lut['imm12lo'] = (11, 7) 436 | arg_lut['bimm12lo'] = (11, 7) 437 | arg_lut['zimm'] = (19, 15) 438 | arg_lut['shamt'] = (25, 20) 439 | arg_lut['shamtw'] = (24, 20) 440 | arg_lut['shamtw4'] = (23, 20) 441 | arg_lut['bs'] = (31, 30) # byte select for RV32K AES 442 | arg_lut['rnum'] = (23, 20) # round constant for RV64 AES 443 | arg_lut['rc'] = (29, 25) 444 | arg_lut['imm2'] = (21, 20) 445 | arg_lut['imm3'] = (22, 20) 446 | arg_lut['imm4'] = (23, 20) 447 | arg_lut['imm5'] = (24, 20) 448 | arg_lut['imm6'] = (25, 20) 449 | arg_lut['zimm'] = (19, 15) 450 | arg_lut['opcode'] = (6,0) 451 | arg_lut['funct7'] = (31,25) 452 | 453 | # for vectors 454 | arg_lut['vd'] = (11, 7) 455 | arg_lut['vs3'] = (11, 7) 456 | arg_lut['vs1'] = (19, 15) 457 | arg_lut['vs2'] = (24, 20) 458 | arg_lut['vm'] = (25, 25) 459 | arg_lut['wd'] = (26, 26) 460 | arg_lut['amoop'] = (31, 27) 461 | arg_lut['nf'] = (31, 29) 462 | arg_lut['simm5'] = (19, 15) 463 | arg_lut['zimm10'] = (29, 20) 464 | arg_lut['zimm11'] = (30, 20) 465 | 466 | 467 | #compressed immediates and fields 468 | arg_lut['c_nzuimm10'] = (12,5) 469 | arg_lut['c_uimm7lo'] = (6,5) 470 | arg_lut['c_uimm7hi'] = (12,10) 471 | arg_lut['c_uimm8lo'] = (6,5) 472 | arg_lut['c_uimm8hi'] = (12,10) 473 | arg_lut['c_uimm9lo'] = (6,5) 474 | arg_lut['c_uimm9hi'] = (12,10) 475 | arg_lut['c_nzimm6lo'] = (6,2) 476 | arg_lut['c_nzimm6hi'] = (12,12) 477 | arg_lut['c_imm6lo'] = (6,2) 478 | arg_lut['c_imm6hi'] = (12,12) 479 | arg_lut['c_nzimm10hi'] = (12,12) 480 | arg_lut['c_nzimm10lo'] = (6,2) 481 | arg_lut['c_nzimm18hi'] = (12,12) 482 | arg_lut['c_nzimm18lo'] = (6,2) 483 | arg_lut['c_imm12'] = (12,2) 484 | arg_lut['c_bimm9lo'] = (6,2) 485 | arg_lut['c_bimm9hi'] = (12,10) 486 | arg_lut['c_nzuimm5'] = (6,2) 487 | arg_lut['c_nzuimm6lo'] = (6,2) 488 | arg_lut['c_nzuimm6hi'] = (12, 12) 489 | arg_lut['c_uimm8splo'] = (6,2) 490 | arg_lut['c_uimm8sphi'] = (12, 12) 491 | arg_lut['c_uimm8sp_s'] = (12,7) 492 | arg_lut['c_uimm10splo'] = (6,2) 493 | arg_lut['c_uimm10sphi'] = (12, 12) 494 | arg_lut['c_uimm9splo'] = (6,2) 495 | arg_lut['c_uimm9sphi'] = (12, 12) 496 | arg_lut['c_uimm10sp_s'] = (12,7) 497 | arg_lut['c_uimm9sp_s'] = (12,7) 498 | arg_lut['c_uimm2'] = (6, 5) 499 | arg_lut['c_uimm1'] = (5, 5) 500 | 501 | arg_lut['rs1_p'] = (9,7) 502 | arg_lut['rs2_p'] = (4,2) 503 | arg_lut['rd_p'] = (4,2) 504 | arg_lut['rd_rs1_n0'] = (11,7) 505 | arg_lut['rd_rs1_p'] = (9,7) 506 | arg_lut['rd_rs1'] = (11,7) 507 | arg_lut['rd_n2'] = (11,7) 508 | arg_lut['rd_n0'] = (11,7) 509 | arg_lut['rs1_n0'] = (11,7) 510 | arg_lut['c_rs2_n0'] = (6,2) 511 | arg_lut['c_rs1_n0'] = (11,7) 512 | arg_lut['c_rs2'] = (6,2) 513 | 514 | # dictionary containing the mapping of the argument to the what the fields in 515 | # the latex table should be 516 | latex_mapping = {} 517 | latex_mapping['imm12'] = 'imm[11:0]' 518 | latex_mapping['rs1'] = 'rs1' 519 | latex_mapping['rs2'] = 'rs2' 520 | latex_mapping['rd'] = 'rd' 521 | latex_mapping['imm20'] = 'imm[31:12]' 522 | latex_mapping['bimm12hi'] = 'imm[12$\\vert$10:5]' 523 | latex_mapping['bimm12lo'] = 'imm[4:1$\\vert$11]' 524 | latex_mapping['imm12hi'] = 'imm[11:5]' 525 | latex_mapping['imm12lo'] = 'imm[4:0]' 526 | latex_mapping['jimm20'] = 'imm[20$\\vert$10:1$\\vert$11$\\vert$19:12]' 527 | latex_mapping['zimm'] = 'uimm' 528 | latex_mapping['shamtw'] = 'shamt' 529 | latex_mapping['rd_p'] = "rd\\,$'$" 530 | latex_mapping['rs1_p'] = "rs1\\,$'$" 531 | latex_mapping['rs2_p'] = "rs2\\,$'$" 532 | latex_mapping['rd_rs1_n0'] = 'rd/rs$\\neq$0' 533 | latex_mapping['rd_rs1_p'] = "rs1\\,$'$/rs2\\,$'$" 534 | latex_mapping['c_rs2'] = 'rs2' 535 | latex_mapping['c_rs2_n0'] = 'rs2$\\neq$0' 536 | latex_mapping['rd_n0'] = 'rd$\\neq$0' 537 | latex_mapping['rs1_n0'] = 'rs1$\\neq$0' 538 | latex_mapping['c_rs1_n0'] = 'rs1$\\neq$0' 539 | latex_mapping['rd_rs1'] = 'rd/rs1' 540 | latex_mapping['c_nzuimm10'] = "nzuimm[5:4$\\vert$9:6$\\vert$2$\\vert$3]" 541 | latex_mapping['c_uimm7lo'] = 'uimm[2$\\vert$6]' 542 | latex_mapping['c_uimm7hi'] = 'uimm[5:3]' 543 | latex_mapping['c_uimm8lo'] = 'uimm[7:6]' 544 | latex_mapping['c_uimm8hi'] = 'uimm[5:3]' 545 | latex_mapping['c_uimm9lo'] = 'uimm[7:6]' 546 | latex_mapping['c_uimm9hi'] = 'uimm[5:4$\\vert$8]' 547 | latex_mapping['c_nzimm6lo'] = 'nzimm[4:0]' 548 | latex_mapping['c_nzimm6hi'] = 'nzimm[5]' 549 | latex_mapping['c_imm6lo'] = 'imm[4:0]' 550 | latex_mapping['c_imm6hi'] = 'imm[5]' 551 | latex_mapping['c_nzimm10hi'] = 'nzimm[9]' 552 | latex_mapping['c_nzimm10lo'] = 'nzimm[4$\\vert$6$\\vert$8:7$\\vert$5]' 553 | latex_mapping['c_nzimm18hi'] = 'nzimm[17]' 554 | latex_mapping['c_nzimm18lo'] = 'nzimm[16:12]' 555 | latex_mapping['c_imm12'] = 'imm[11$\\vert$4$\\vert$9:8$\\vert$10$\\vert$6$\\vert$7$\\vert$3:1$\\vert$5]' 556 | latex_mapping['c_bimm9lo'] = 'imm[7:6$\\vert$2:1$\\vert$5]' 557 | latex_mapping['c_bimm9hi'] = 'imm[8$\\vert$4:3]' 558 | latex_mapping['c_nzuimm5'] = 'nzuimm[4:0]' 559 | latex_mapping['c_nzuimm6lo'] = 'nzuimm[4:0]' 560 | latex_mapping['c_nzuimm6hi'] = 'nzuimm[5]' 561 | latex_mapping['c_uimm8splo'] = 'uimm[4:2$\\vert$7:6]' 562 | latex_mapping['c_uimm8sphi'] = 'uimm[5]' 563 | latex_mapping['c_uimm8sp_s'] = 'uimm[5:2$\\vert$7:6]' 564 | latex_mapping['c_uimm10splo'] = 'uimm[4$\\vert$9:6]' 565 | latex_mapping['c_uimm10sphi'] = 'uimm[5]' 566 | latex_mapping['c_uimm9splo'] = 'uimm[4:3$\\vert$8:6]' 567 | latex_mapping['c_uimm9sphi'] = 'uimm[5]' 568 | latex_mapping['c_uimm10sp_s'] = 'uimm[5:4$\\vert$9:6]' 569 | latex_mapping['c_uimm9sp_s'] = 'uimm[5:3$\\vert$8:6]' 570 | 571 | # created a dummy instruction-dictionary like dictionary for all the instruction 572 | # types so that the same logic can be used to create their tables 573 | latex_inst_type = {} 574 | latex_inst_type['R-type'] = {} 575 | latex_inst_type['R-type']['variable_fields'] = ['opcode', 'rd', 'funct3', \ 576 | 'rs1', 'rs2', 'funct7'] 577 | latex_inst_type['R4-type'] = {} 578 | latex_inst_type['R4-type']['variable_fields'] = ['opcode', 'rd', 'funct3', \ 579 | 'rs1', 'rs2', 'funct2', 'rs3'] 580 | latex_inst_type['I-type'] = {} 581 | latex_inst_type['I-type']['variable_fields'] = ['opcode', 'rd', 'funct3', \ 582 | 'rs1', 'imm12'] 583 | latex_inst_type['S-type'] = {} 584 | latex_inst_type['S-type']['variable_fields'] = ['opcode', 'imm12lo', 'funct3', \ 585 | 'rs1', 'rs2', 'imm12hi'] 586 | latex_inst_type['B-type'] = {} 587 | latex_inst_type['B-type']['variable_fields'] = ['opcode', 'bimm12lo', 'funct3', \ 588 | 'rs1', 'rs2', 'bimm12hi'] 589 | latex_inst_type['U-type'] = {} 590 | latex_inst_type['U-type']['variable_fields'] = ['opcode', 'rd', 'imm20'] 591 | latex_inst_type['J-type'] = {} 592 | latex_inst_type['J-type']['variable_fields'] = ['opcode', 'rd', 'jimm20'] 593 | latex_fixed_fields = [] 594 | latex_fixed_fields.append((31,25)) 595 | latex_fixed_fields.append((24,20)) 596 | latex_fixed_fields.append((19,15)) 597 | latex_fixed_fields.append((14,12)) 598 | latex_fixed_fields.append((11,7)) 599 | latex_fixed_fields.append((6,0)) 600 | -------------------------------------------------------------------------------- /riscv_isac/data/instr_alias.yaml: -------------------------------------------------------------------------------- 1 | # This file holds aliases for groups of instructions 2 | 3 | rv32i_arith_reg: &rv32i_arith_reg 4 | - add 5 | - sub 6 | - slt 7 | - sltu 8 | - xor 9 | - or 10 | - and 11 | 12 | rv32i_arith_imm: &rv32i_arith_imm 13 | - addi 14 | - slti 15 | - sltiu 16 | - xori 17 | - ori 18 | - andi 19 | 20 | rv32i_shift_reg: &rv32i_shift_reg 21 | - sll 22 | - srl 23 | - sra 24 | 25 | rv32i_shift_imm: &rv32i_shift_imm 26 | - slli 27 | - srli 28 | - srai 29 | 30 | rv32i_arith: &rv32i_arith [*rv32i_arith_reg, *rv32i_arith_imm] 31 | 32 | rv32i_shift: &rv32i_shift [*rv32i_shift_reg, *rv32i_shift_imm] 33 | 34 | rv64i_arith_reg: &rv64i_arith_reg 35 | - *rv32i_arith_reg 36 | - addw 37 | - subw 38 | 39 | rv64i_arith_imm: &rv64i_arith_imm 40 | - *rv32i_arith_imm 41 | - addiw 42 | 43 | rv64i_shift_reg: &rv64i_shift_reg 44 | - *rv32i_shift_reg 45 | - sllw 46 | - srlw 47 | - sraw 48 | 49 | rv64i_shift_imm: &rv64i_shift_imm 50 | - *rv32i_shift_imm 51 | - slliw 52 | - srliw 53 | 54 | rv64i_arith: &rv64i_arith [*rv64i_arith_reg, *rv64i_arith_imm] 55 | 56 | rv64i_shift: &rv64i_shift [*rv64i_shift_reg, *rv64i_shift_imm] 57 | 58 | rv32i_branch: &rv32i_branch 59 | - beq 60 | - bge 61 | - bgeu 62 | - blt 63 | - bltu 64 | - bne 65 | 66 | rv64i_branch: &rv64i_branch [*rv32i_branch] 67 | 68 | rv32i_jal: &rv32i_jal 69 | - jal 70 | - jalr 71 | 72 | rv64i_jal: &rv64i_jal [*rv32i_jal] 73 | 74 | rv32i_load: &rv32i_load 75 | - lw 76 | - lhu 77 | - lh 78 | - lbu 79 | - lb 80 | 81 | rv64i_load: &rv364i_load 82 | - *rv32i_load 83 | - ld 84 | - lwu 85 | 86 | rv32i_store: &rv32i_store 87 | - sw 88 | - sh 89 | - sb 90 | 91 | rv64i_store: &rv64i_store 92 | - *rv32i_store 93 | - sd -------------------------------------------------------------------------------- /riscv_isac/isac.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | from riscv_isac.log import logger 4 | import riscv_isac.utils as utils 5 | import riscv_isac.coverage as cov 6 | from elftools.elf.elffile import ELFFile 7 | import re 8 | from ruamel.yaml import YAML 9 | from ruamel import yaml 10 | 11 | yaml = YAML(typ="rt") 12 | yaml.default_flow_style = False 13 | yaml.explicit_start = True 14 | yaml.allow_unicode = True 15 | yaml.allow_duplicate_keys = False 16 | 17 | safe_yaml = YAML(typ="safe") 18 | safe_yaml.default_flow_style = False 19 | safe_yaml.explicit_start = True 20 | safe_yaml.allow_unicode = True 21 | safe_yaml.allow_duplicate_keys = False 22 | 23 | def replace_values(obj, placeholder_data): 24 | if isinstance(obj, dict): 25 | updated_dict = {} 26 | for key, value in obj.items(): 27 | new_key = replace_values(key, placeholder_data) 28 | new_value = replace_values(value, placeholder_data) 29 | updated_dict[new_key] = new_value 30 | return updated_dict 31 | elif isinstance(obj, list): 32 | updated_list = [replace_values(item, placeholder_data) for item in obj] 33 | return updated_list 34 | elif isinstance(obj, str): 35 | # Check if the string matches the pattern "${.*}" 36 | matches = re.findall(r'\${(.*?)}', obj) 37 | for match in matches: 38 | if match in placeholder_data: 39 | obj = obj.replace(f'${{{match}}}', str(placeholder_data[match])) 40 | return obj 41 | return obj 42 | 43 | def preprocessing(cgf, header_file, cgf_macros): 44 | logger.info("Preprocessing") 45 | if header_file is not None: 46 | with open(header_file, "r") as file: 47 | from io import StringIO 48 | string_stream = StringIO() 49 | safe_yaml.dump(dict(safe_yaml.load(file)), string_stream) 50 | output_str = string_stream.getvalue() 51 | string_stream.close() 52 | placeholder_data = yaml.load(output_str) 53 | output_yaml = replace_values(cgf, placeholder_data['common']) 54 | for mac in cgf_macros: 55 | output_yaml = replace_values(output_yaml, placeholder_data[mac]) 56 | return output_yaml 57 | else: 58 | return cgf 59 | 60 | def isac(output_file,elf ,trace_file, window_size, cgf, parser_name, decoder_name, parser_path, decoder_path, detailed, test_labels, 61 | sig_labels, dump, cov_labels, xlen, flen, no_count, procs, inxFlg, logging=False): 62 | test_addr = [] 63 | sig_addr = [] 64 | if parser_path: 65 | sys.path.append(parser_path) 66 | if decoder_path: 67 | sys.path.append(decoder_path) 68 | sys.path.append(os.path.join(os.path.dirname(__file__), "plugins")) 69 | 70 | if elf is not None : 71 | test_name = elf.rsplit('.', 1)[0] 72 | if test_labels: 73 | for startlabel,endlabel in test_labels: 74 | start_address = utils.collect_label_address(elf, startlabel) 75 | end_address = utils.collect_label_address(elf, endlabel) 76 | logger.info('Start Test Label: ' + startlabel + ' @ ' + 77 | str(hex(start_address))) 78 | logger.info('End Test Label : ' + endlabel + ' @ ' + 79 | str(hex(end_address))) 80 | test_addr.append((start_address,end_address)) 81 | if sig_labels: 82 | for startlabel,endlabel in sig_labels: 83 | start_address = utils.collect_label_address(elf, startlabel) 84 | end_address = utils.collect_label_address(elf, endlabel) 85 | logger.info('Start Signature Label: ' + startlabel + ' @ ' + 86 | str(hex(start_address))) 87 | logger.info('End Signature Label : ' + endlabel + ' @ ' + 88 | str(hex(end_address))) 89 | sig_addr.append((start_address,end_address)) 90 | else: 91 | test_name = trace_file.rsplit(',',1)[0] 92 | rpt = cov.compute(trace_file, test_name, cgf, parser_name, decoder_name, detailed, xlen, flen, test_addr, dump, cov_labels, sig_addr, window_size, inxFlg, elf, no_count, procs) 93 | if output_file is not None and logging: 94 | logger.info('Coverage Report:') 95 | #logger.info('\n\n' + rpt) 96 | else: 97 | rpt_file = open(output_file,'w') 98 | utils.dump_yaml(rpt, rpt_file) 99 | rpt_file.close() 100 | logger.info('Report File Generated : ' + str(output_file)) 101 | -------------------------------------------------------------------------------- /riscv_isac/log.py: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | 3 | import logging 4 | import colorlog 5 | 6 | class Log: 7 | """ 8 | this class holds all the logic; see the end of the script to 9 | see how it's instantiated in order to have the line 10 | "from zenlog import log" work 11 | """ 12 | 13 | aliases = { 14 | logging.CRITICAL: ("critical", "crit", "fatal"), 15 | logging.ERROR: ("error", "err"), 16 | logging.WARNING: ("warning", "warn"), 17 | logging.INFO: ("info", "inf"), 18 | logging.DEBUG: ("debug", "dbg") 19 | } 20 | 21 | def __init__(self, format=None): 22 | if not format: 23 | format = "%(log_color)s%(levelname)8s%(reset)s | %(log_color)s%(message)s%(reset)s" 24 | self.format = format 25 | self.colors = { 26 | 'DEBUG': 'purple', 27 | 'INFO': 'green', 28 | 'WARNING': 'red', 29 | 'ERROR': 'bold_red', 30 | 'CRITICAL': 'bold_red', 31 | } 32 | self.logger = logging.getLogger() 33 | 34 | 35 | # the magic happens here: we use the "extra" argument documented in 36 | # https://docs.python.org/2/library/logging.html#logging.Logger.debug 37 | # to inject new items into the logging.LogRecord objects 38 | # we also create our convenience methods here 39 | def critical(self, message, *args, **kwargs): 40 | for line in str(message).splitlines(): 41 | self.logger.critical(line, 42 | *args, **kwargs) 43 | crit = c = fatal = critical 44 | 45 | def error(self, message, *args, **kwargs): 46 | for line in str(message).splitlines(): 47 | self.logger.error(line, 48 | *args, **kwargs) 49 | err = e = error 50 | 51 | def warn(self, message, *args, **kwargs): 52 | for line in str(message).splitlines(): 53 | self.logger.warning(line, 54 | *args, **kwargs) 55 | warning = w = warn 56 | 57 | def info(self, message, *args, **kwargs): 58 | for line in str(message).splitlines(): 59 | self.logger.info(line, 60 | *args, **kwargs) 61 | inf = nfo = i = info 62 | 63 | def debug(self, message, *args, **kwargs): 64 | for line in str(message).splitlines(): 65 | self.logger.debug(line, 66 | *args, **kwargs) 67 | dbg = d = debug 68 | 69 | # other convenience functions to set the global logging level 70 | def _parse_level(self, lvl): 71 | for log_level in self.aliases: 72 | if lvl == log_level or lvl in self.aliases[log_level]: 73 | return log_level 74 | print('Invalid log level passed. Please select from debug | info | warning | error') 75 | raise ValueError("{}-Invalid log level.".format(lvl)) 76 | 77 | def level(self, lvl=logging.CRITICAL): 78 | '''Setup the Logger.''' 79 | 80 | self._lvl = self._parse_level(lvl) 81 | 82 | self.stream = logging.StreamHandler() 83 | self.stream.setLevel(self._lvl) 84 | 85 | self.stream.setLevel(self._lvl) 86 | 87 | self.stream.setFormatter(colorlog.ColoredFormatter(self.format,log_colors=self.colors)) 88 | self.logger.setLevel(self._lvl) 89 | 90 | self.logger.addHandler(self.stream) 91 | logging.root.setLevel(self._lvl) 92 | logger = Log() 93 | -------------------------------------------------------------------------------- /riscv_isac/main.py: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | """Console script for riscv_isac.""" 3 | 4 | import os 5 | import click 6 | import shutil 7 | from git import Repo 8 | 9 | from riscv_isac.isac import isac 10 | from riscv_isac.isac import preprocessing 11 | from riscv_isac.__init__ import __version__ 12 | from riscv_isac.log import logger 13 | import riscv_isac.utils as utils 14 | from riscv_isac.cgf_normalize import * 15 | import riscv_isac.coverage as cov 16 | from riscv_isac.plugins.translator_cgf import Translate_cgf 17 | 18 | @click.group() 19 | @click.version_option(prog_name="RISC-V ISA Coverage Generator",version=__version__) 20 | @click.option('--verbose', '-v', default='info', help='Set verbose level', type=click.Choice(['info','error','debug'],case_sensitive=False)) 21 | def cli(verbose): 22 | logger.level(verbose) 23 | logger.info('****** RISC-V ISA Coverage {0} *******'.format(__version__ )) 24 | logger.info('Copyright (c) 2020, InCore Semiconductors Pvt. Ltd.') 25 | logger.info('All Rights Reserved.') 26 | 27 | @cli.command(help = "Run Coverage analysis on tracefile.") 28 | @click.option('--elf', '-e' , type=click.Path(exists=True,resolve_path=True),help="ELF file") 29 | @click.option( 30 | '--trace-file','-t', 31 | type=click.Path(resolve_path=True,readable=True,exists=True), 32 | help="Instruction trace file to be analyzed" 33 | ) 34 | 35 | @click.option( 36 | '--header-file','-h', 37 | type=click.Path(resolve_path=True,readable=True,exists=True), 38 | help="YAML macro file to include" 39 | ) 40 | @click.option( 41 | '--cgf-macro','-cm', 42 | metavar='CGF MACROS', 43 | type=str, 44 | multiple=True, 45 | help = "CGF macros to consider for this run." 46 | ) 47 | @click.option( 48 | '--window-size', 49 | type= int, 50 | default = 32, 51 | help="Maximum length of instructions to be evaluated for checking hazards" 52 | ) 53 | @click.option( 54 | '--cgf-file','-c',multiple=True, 55 | type=click.Path(resolve_path=True,readable=True,exists=True), 56 | help="Coverage Group File(s). Multiple allowed.",required=True 57 | ) 58 | @click.option( 59 | '--detailed', '-d', 60 | is_flag=True, 61 | help='Select detailed mode of coverage printing') 62 | 63 | @click.option( 64 | '--parser-name', 65 | type = str, 66 | default = 'c_sail', 67 | metavar = 'NAME', 68 | help='Parser plugin name' 69 | ) 70 | 71 | @click.option( 72 | '--decoder-name', 73 | type = str, 74 | default = 'internaldecoder', 75 | metavar = 'NAME', 76 | help = 'Decoder plugin name' 77 | ) 78 | 79 | @click.option( 80 | '--parser-path', 81 | type=click.Path(resolve_path=True,readable=True,exists=True), 82 | help="Parser file path" 83 | ) 84 | 85 | @click.option( 86 | '--decoder-path', 87 | type=click.Path(resolve_path=True,readable=True,exists=True), 88 | help="Decoder file path" 89 | ) 90 | 91 | @click.option( 92 | '--output-file','-o', 93 | type=click.Path(writable=True,resolve_path=True), 94 | help="Coverage Group File", 95 | required=True 96 | ) 97 | @click.option( 98 | '--test-label', 99 | type=(str,str), 100 | multiple=True, 101 | metavar='LABEL_START LABEL_END', 102 | default=None, 103 | help='Pair of labels denoting start and end points of the test region(s). Multiple allowed.' 104 | ) 105 | @click.option( 106 | '--sig-label', 107 | type=(str,str), 108 | multiple=True, 109 | metavar='LABEL_START LABEL_END', 110 | default=None, 111 | help='Pair of labels denoting start and end points of the signature region(s). Multiple allowed.' 112 | ) 113 | @click.option( 114 | '--dump', 115 | type=click.Path(writable=True,resolve_path=True), 116 | help="Dump Normalized Coverage Group File" 117 | ) 118 | @click.option( 119 | '--cov-label','-l', 120 | metavar='COVERAGE LABEL', 121 | type=str, 122 | multiple=True, 123 | help = "Coverage labels to consider for this run." 124 | ) 125 | @click.option('--xlen','-x', 126 | type=click.Choice(['32','64']), 127 | default='32', 128 | help="XLEN value for the ISA." 129 | ) 130 | @click.option('--flen','-f', 131 | type=click.Choice(['32','64']), 132 | default='32', 133 | help="FLEN value for the ISA." 134 | ) 135 | @click.option('--no-count', 136 | is_flag = True, 137 | help = "This option removes hit coverpoints during coverage computation" 138 | ) 139 | @click.option('--procs', '-p', 140 | default = 1, 141 | help = 'Set number of processes to calculate coverage' 142 | ) 143 | @click.option('--log-redundant', 144 | is_flag = True, 145 | help = "Log redundant coverpoints during normalization" 146 | ) 147 | @click.option('--inxFlg', 'inxFlg', 148 | type=bool, 149 | default = False, 150 | help="Enable inxFlg if the extension is Z*inx" 151 | ) 152 | 153 | def coverage(elf,trace_file, header_file, window_size, cgf_file, detailed,parser_name, decoder_name, parser_path, decoder_path,output_file, test_label, 154 | sig_label, dump,cov_label, cgf_macro, xlen, flen, no_count, procs, log_redundant, inxFlg): 155 | isac(output_file,elf,trace_file, window_size, preprocessing(Translate_cgf(expand_cgf(cgf_file,int(xlen),int(flen),log_redundant)), header_file, cgf_macro), parser_name, decoder_name, parser_path, decoder_path, detailed, test_label, 156 | sig_label, dump, cov_label, int(xlen), int(flen), no_count, procs, inxFlg) 157 | 158 | @cli.command(help = "Merge given coverage files.") 159 | @click.argument( 160 | 'files', 161 | type=click.Path(resolve_path=True,readable=True,exists=True), 162 | nargs=-1 163 | ) 164 | @click.option( 165 | '--detailed', '-d', 166 | is_flag=True, 167 | help='Select detailed mode of coverage printing') 168 | @click.option( 169 | '-p', 170 | type = int, 171 | default = 1, 172 | help='Number of processes' 173 | ) 174 | @click.option( 175 | '--cgf-file','-c',multiple=True, 176 | type=click.Path(resolve_path=True,readable=True,exists=True), 177 | help="Coverage Group File(s). Multiple allowed.",required=True 178 | ) 179 | @click.option( 180 | '--output-file','-o', 181 | type=click.Path(writable=True,resolve_path=True), 182 | help="Coverage Group File." 183 | ) 184 | @click.option('--flen','-f', 185 | type=click.Choice(['32','64']), 186 | default='32', 187 | help="FLEN value for the ISA." 188 | ) 189 | @click.option('--xlen','-x',type=click.Choice(['32','64']),default='32',help="XLEN value for the ISA.") 190 | @click.option('--log-redundant', 191 | is_flag = True, 192 | help = "Log redundant coverpoints during normalization" 193 | ) 194 | def merge(files,detailed,p,cgf_file,output_file,flen,xlen,log_redundant, header_file,cgf_macro): 195 | rpt = cov.merge_coverage( 196 | files,preprocessing(Translate_cgf(expand_cgf(cgf_file,int(xlen),int(flen),log_redundant)), header_file, cgf_macro),detailed,p) 197 | if output_file is None: 198 | logger.info('Coverage Report:') 199 | logger.info('\n\n' + rpt) 200 | else: 201 | rpt_file = open(output_file,'w') 202 | utils.dump_yaml(rpt,rpt_file) 203 | rpt_file.close() 204 | logger.info('Report File Generated : ' + str(output_file)) 205 | 206 | 207 | 208 | @cli.command(help = "Normalize the cgf.") 209 | @click.option( 210 | '--cgf-file','-c',multiple=True, 211 | type=click.Path(resolve_path=True,readable=True,exists=True), 212 | help="Coverage Group File(s). Multiple allowed.",required=True 213 | ) 214 | @click.option( 215 | '--output-file','-o', 216 | type=click.Path(writable=True,resolve_path=True), 217 | help="Coverage Group File", 218 | required = True 219 | ) 220 | @click.option('--xlen','-x',type=click.Choice(['32','64']),default='32',help="XLEN value for the ISA.") 221 | @click.option('--flen','-f',type=click.Choice(['32','64']),default='32',help="FLEN value for the ISA.") 222 | @click.option('--log-redundant', 223 | is_flag = True, 224 | help = "Log redundant coverpoints during normalization" 225 | ) 226 | def normalize(cgf_file,output_file,xlen,flen,log_redundant,header_file,cgf_macro): 227 | logger.info("Writing normalized CGF to "+str(output_file)) 228 | with open(output_file,"w") as outfile: 229 | utils.dump_yaml(preprocessing(Translate_cgf(expand_cgf(cgf_file,int(xlen),int(flen),log_redundant)), header_file, cgf_macro),outfile) 230 | 231 | @cli.command(help = 'Setup the plugin which uses the information from RISCV Opcodes repository to decode.') 232 | @click.option('--url', 233 | type = str, 234 | default='https://github.com/riscv/riscv-opcodes', 235 | required=False, 236 | help='URL to the riscv-opcodes repo') 237 | @click.option('--branch',type=str,default='master') 238 | @click.option('--plugin-path', 239 | type=click.Path(resolve_path=True,writable=True), 240 | help="Target folder to setup the plugin files in. [./]", 241 | default="./rvop_decoder") 242 | @click.option("--rvop-path", 243 | type=click.Path(resolve_path=True,writable=True), 244 | help="Path to RVOpcodes directory.") 245 | # Clone repo 246 | def setup(url,branch, plugin_path, rvop_path): 247 | # path = os.getcwd() + '/plugins/riscv_opcodes/' 248 | if not os.path.exists(plugin_path): 249 | logger.debug("Creating directory: "+str(plugin_path)) 250 | os.mkdir(plugin_path) 251 | target_dir = os.path.join(plugin_path,"riscv_opcodes/") 252 | repo = None 253 | if rvop_path is not None: 254 | if not os.path.exists(rvop_path): 255 | logger.warning("RISCV Opcodes folder not found at: "+rvop_path) 256 | clone = click.prompt("Do you wish to clone from git?", 257 | default='Y',type=click.Choice(['Y','n','y','N']),show_choices=True) 258 | if clone == 'Y' or clone == 'y': 259 | logger.debug("Cloning from Git.") 260 | repo = Repo.clone_from(url, rvop_path) 261 | repo.git.checkout(branch) 262 | else: 263 | logger.error("Exiting Setup.") 264 | raise SystemExit 265 | os.symlink(rvop_path,target_dir[:-1]) 266 | else: 267 | logger.debug("Cloning from Git.") 268 | repo = Repo.clone_from(url, target_dir) 269 | repo.git.checkout(branch) 270 | plugin_file = os.path.join(os.path.dirname(__file__), "data/rvopcodesdecoder.py") 271 | constants_file = os.path.join(os.path.dirname(__file__), "data/constants.py") 272 | logger.debug("Copying plugin files.") 273 | shutil.copy(plugin_file,plugin_path) 274 | shutil.copy(constants_file,plugin_path) 275 | -------------------------------------------------------------------------------- /riscv_isac/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | ## Plugins: __init__.py 2 | import pluggy 3 | 4 | decoderHookImpl = pluggy.HookimplMarker("decoder") 5 | parserHookImpl = pluggy.HookimplMarker("parser") 6 | -------------------------------------------------------------------------------- /riscv_isac/plugins/c_sail.py: -------------------------------------------------------------------------------- 1 | import re 2 | import riscv_isac.plugins as plugins 3 | import riscv_isac.plugins. specification as spec 4 | from riscv_isac.InstructionObject import instructionObject 5 | from riscv_isac.log import logger 6 | 7 | class c_sail(spec.ParserSpec): 8 | 9 | @plugins.parserHookImpl 10 | def setup(self, trace, arch): 11 | self.trace = trace 12 | self.arch = arch 13 | if arch[1] == 32: 14 | logger.warn('FLEN is set to 32. Commit values in the log will be terminated to 32 bits \ 15 | irrespective of their original size.') 16 | old_trap_dict = {"mode_change": None, "call_type": None, "exc_num": None, "tval": None} 17 | instr_pattern_c_sail= re.compile( 18 | '\[\d*\]\s\[(?P.*?)\]:\s(?P[0-9xABCDEF]+)\s\((?P[0-9xABCDEF]+)\)\s*(?P.*)') 19 | instr_pattern_c_sail_regt_reg_val = re.compile('(?P[xf])(?P[\d]+)\s<-\s(?P[0-9xABCDEF]+)') 20 | instr_pattern_c_sail_csr_reg_val = re.compile('(?PCSR|clint::tick)\s(?P[a-z0-9]+)\s<-\s(?P[0-9xABCDEF]+)(?:\s\(input:\s(?P[0-9xABCDEF]+)\))?') 21 | instr_pattern_c_sail_mem_val = re.compile('mem\[(?P[0-9xABCDEF]+)\]\s<-\s(?P[0-9xABCDEF]+)') 22 | instr_pattern_c_sail_trap = re.compile(r'trapping\sfrom\s(?P\w+\sto\s\w+)\sto\shandle\s(?P\w+.*)\shandling\sexc#(?P0x[0-9a-fA-F]+)\sat\spriv\s\w\swith\stval\s(?P0x[0-9a-fA-F]+)') 23 | def extractInstruction(self, line): 24 | instr_pattern = self.instr_pattern_c_sail 25 | re_search = instr_pattern.search(line) 26 | if re_search is not None: 27 | return int(re_search.group('instr'), 16),re_search.group('mnemonic'),re_search.group('mode') 28 | else: 29 | return None, None, None 30 | 31 | def extractAddress(self, line): 32 | instr_pattern = self.instr_pattern_c_sail 33 | re_search = instr_pattern.search(line) 34 | if re_search is not None: 35 | return int(re_search.group('addr'), 16) 36 | else: 37 | return 0 38 | 39 | def extractRegisterCommitVal(self, line): 40 | instr_pattern = self.instr_pattern_c_sail_regt_reg_val 41 | re_search = instr_pattern.search(line) 42 | if re_search is not None: 43 | rtype = re_search.group('regt') 44 | cval = re_search.group('val') 45 | if rtype =='f' and self.arch[1] == 32: 46 | cval = cval[0:2]+cval[-8:] 47 | return (rtype, re_search.group('reg'), cval) 48 | else: 49 | return None 50 | 51 | def extractCsrCommitVal(self, line): 52 | instr_pattern = self.instr_pattern_c_sail_csr_reg_val 53 | csr_commit = re.findall(instr_pattern,line) 54 | if (len(csr_commit)==0): 55 | return None 56 | else: 57 | return csr_commit 58 | 59 | def extractVirtualMemory(self, line): 60 | mem_r_pattern = re.compile(r'mem\[R,([0-9xABCDEF]+)\] -> 0x([0-9xABCDEF]+)') 61 | mem_x_pattern = re.compile(r'mem\[X,([0-9xABCDEF]+)\] -> 0x([0-9xABCDEF]+)') 62 | mem_depa_pattern = re.compile(r'mem\[([0-9xABCDEF]+)\]') 63 | 64 | match_search_mnemonic = self.instr_pattern_c_sail.search(line) 65 | depa, ieva, ieva_align, depa_align, iepa, iepa_align = None, None, None, None, None, None 66 | iptw_list, dptw_list = [], [] 67 | return_dict = {} 68 | 69 | if match_search_mnemonic: 70 | iepa_align, ieva_align = 0, 0 71 | line_upper_part, line_lower_part = line.split(match_search_mnemonic.group(0), 1) 72 | 73 | iepa_list=(mem_x_pattern.findall(line_upper_part)) 74 | if len(iepa_list) != 0: 75 | iepa = int(iepa_list[0][0], 16) 76 | 77 | ieva = int(match_search_mnemonic.group('addr'),16) 78 | iptw_list=(mem_r_pattern.findall(line_upper_part)) 79 | dptw_list=(mem_r_pattern.findall(line_lower_part)) 80 | 81 | if dptw_list is not None: 82 | if "lw" in match_search_mnemonic.group('mnemonic') and dptw_list: 83 | depa_list=dptw_list.pop() 84 | depa=int(depa_list[0],16) 85 | else: 86 | depa_list=mem_depa_pattern.findall(line_lower_part) 87 | if len(depa_list) != 0: 88 | depa=int(depa_list[0],16) 89 | 90 | ieva_align = 1 if ieva is not None and ieva & 0b11 == 0 else 0 91 | iepa_align = 1 if iepa is not None and iepa & 0b11 == 0 else 0 92 | depa_align = 1 if depa is not None and depa & 0b11 == 0 else 0 93 | 94 | return_dict['dptw_list'] = dptw_list 95 | return_dict['iptw_list'] = iptw_list 96 | return_dict['depa'] = depa 97 | return_dict['ieva'] = ieva 98 | return_dict['iepa'] = iepa 99 | return_dict['ieva_align'] = ieva_align 100 | return_dict['iepa_align'] = iepa_align 101 | return_dict['depa_align'] = depa_align 102 | 103 | return (return_dict) 104 | 105 | def extractMemVal(self, line): 106 | instr_pattern = self.instr_pattern_c_sail_mem_val 107 | mem_val = re.findall(instr_pattern, line) 108 | if(len(mem_val) == 0): 109 | return None 110 | else: 111 | return mem_val 112 | 113 | def extracttrapvals(self, line): 114 | instr_trap_pattern = self.instr_pattern_c_sail_trap.search(line) 115 | trap_dict = {"mode_change": None, "call_type": None, "exc_num": None, "tval": None} 116 | 117 | if instr_trap_pattern: 118 | trap_dict["mode_change"] = instr_trap_pattern.group("mode_change") 119 | trap_dict["call_type"] = instr_trap_pattern.group("call_type") 120 | trap_dict["exc_num"] = instr_trap_pattern.group("exc_num") 121 | trap_dict["tval"] = instr_trap_pattern.group("tval") 122 | self.old_trap_dict = trap_dict 123 | 124 | #maintain the value if None 125 | if instr_trap_pattern is None: 126 | trap_dict = self.old_trap_dict 127 | return trap_dict 128 | 129 | @plugins.parserHookImpl 130 | def __iter__(self): 131 | with open(self.trace) as fp: 132 | content = fp.read() 133 | instructions = content.split('\n\n') 134 | for line in instructions: 135 | instr, mnemonic, mode = self.extractInstruction(line) 136 | addr = self.extractAddress(line) 137 | reg_commit = self.extractRegisterCommitVal(line) 138 | csr_commit = self.extractCsrCommitVal(line) 139 | vm_addr_dict = self.extractVirtualMemory(line) 140 | mem_val = self.extractMemVal(line) 141 | trap_dict = self.extracttrapvals(line) 142 | instrObj = instructionObject(instr, 'None', addr, reg_commit = reg_commit, csr_commit = csr_commit, mnemonic = mnemonic, mode = mode, vm_addr_dict = vm_addr_dict, mem_val = mem_val, trap_dict = trap_dict) 143 | yield instrObj 144 | -------------------------------------------------------------------------------- /riscv_isac/plugins/specification.py: -------------------------------------------------------------------------------- 1 | import pluggy 2 | 3 | decoderHookSpec = pluggy.HookspecMarker("decoder") 4 | parserHookSpec = pluggy.HookspecMarker("parser") 5 | 6 | class DecoderSpec(object): 7 | @decoderHookSpec 8 | def setup(self,inxFlag,arch): 9 | pass 10 | 11 | @decoderHookSpec 12 | def decode(self, instrObj_temp): 13 | pass 14 | 15 | class ParserSpec(object): 16 | @parserHookSpec 17 | def setup(self,trace,arch): 18 | pass 19 | 20 | @parserHookSpec 21 | def __iter__(self): 22 | pass 23 | -------------------------------------------------------------------------------- /riscv_isac/plugins/spike.py: -------------------------------------------------------------------------------- 1 | import re 2 | from riscv_isac.log import logger 3 | import riscv_isac.plugins as plugins 4 | import riscv_isac.plugins.specification as spec 5 | from riscv_isac.InstructionObject import instructionObject 6 | 7 | class spike(spec.ParserSpec): 8 | 9 | @plugins.parserHookImpl 10 | def setup(self, trace, arch): 11 | self.trace = trace 12 | self.arch = arch 13 | 14 | instr_pattern_spike = re.compile( 15 | '[0-9]\s(?P[0-9abcdefx]+)\s\((?P[0-9abcdefx]+)\)') 16 | instr_pattern_spike_xd = re.compile( 17 | '[0-9]\s(?P[0-9abcdefx]+)\s\((?P[0-9abcdefx]+)\)' + 18 | '\s(?P[xf])(?P[\s|\d]+)\s(?P[0-9abcdefx]+)' 19 | ) 20 | 21 | def extractInstruction(self, line): 22 | instr_pattern = self.instr_pattern_spike 23 | re_search = instr_pattern.search(line) 24 | if re_search is not None: 25 | return int(re_search.group('instr'), 16), None 26 | else: 27 | return None, None 28 | 29 | def extractAddress(self, line): 30 | instr_pattern = self.instr_pattern_spike 31 | re_search = instr_pattern.search(line) 32 | if re_search is not None: 33 | return int(re_search.group('addr'), 16) 34 | else: 35 | return 0 36 | 37 | def extractRegisterCommitVal(self, line): 38 | 39 | instr_pattern = self.instr_pattern_spike_xd 40 | re_search = instr_pattern.search(line) 41 | if re_search is not None: 42 | return (re_search.group('regt'), re_search.group('reg'), re_search.group('val')) 43 | else: 44 | return None 45 | 46 | @plugins.parserHookImpl 47 | def __iter__(self): 48 | with open(self.trace) as fp: 49 | for line in fp: 50 | logger.debug('parsing ' + str(line)) 51 | instr, mnemonic = self.extractInstruction(line) 52 | addr = self.extractAddress(line) 53 | reg_commit = self.extractRegisterCommitVal(line) 54 | csr_commit = None 55 | instrObj = instructionObject(instr, 'None', addr, reg_commit = reg_commit, csr_commit = csr_commit, mnemonic = mnemonic ) 56 | yield instrObj 57 | -------------------------------------------------------------------------------- /riscv_isac/requirements.txt: -------------------------------------------------------------------------------- 1 | click 2 | colorlog 3 | gitpython 4 | pluggy 5 | pyelftools==0.26 6 | pytablewriter 7 | pyyaml 8 | ruamel.yaml>=0.16.0 9 | -------------------------------------------------------------------------------- /riscv_isac/test_requirements.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | -------------------------------------------------------------------------------- /riscv_isac/utils.py: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | 3 | """Common Utils """ 4 | import sys 5 | import os 6 | import subprocess 7 | import shlex 8 | import riscv_isac 9 | from riscv_isac.log import logger 10 | import ruamel 11 | from ruamel.yaml import YAML 12 | from ruamel.yaml.representer import RoundTripRepresenter,SafeRepresenter 13 | import yaml as pyyaml 14 | from elftools.elf.elffile import ELFFile 15 | 16 | yaml = YAML(typ="rt") 17 | yaml.default_flow_style = False 18 | yaml.explicit_start = True 19 | yaml.allow_unicode = True 20 | yaml.allow_duplicate_keys = False 21 | 22 | safe_yaml = YAML(typ="safe") 23 | safe_yaml.default_flow_style = False 24 | safe_yaml.explicit_start = True 25 | safe_yaml.allow_unicode = True 26 | safe_yaml.allow_duplicate_keys = False 27 | 28 | def collect_label_address(elf, label): 29 | with open(elf, 'rb') as f: 30 | elffile = ELFFile(f) 31 | # elfclass is a public attribute of ELFFile, read from its header 32 | symtab = elffile.get_section_by_name('.symtab') 33 | size = symtab.num_symbols() 34 | mains = symtab.get_symbol_by_name(label) 35 | main = mains[0] 36 | return int(main.entry['st_value']) 37 | 38 | def get_value_at_location(elf_path, location, bytes): 39 | with open(elf_path, 'rb') as f: 40 | elffile = ELFFile(f) 41 | # Iterate through the sections to find the relevant one (or use a specific section by name) 42 | for section in elffile.iter_sections(): 43 | if section['sh_addr'] <= location < section['sh_addr'] + section.data_size: 44 | offset = location - section['sh_addr'] 45 | f.seek(section['sh_offset'] + offset) 46 | value = f.read(bytes) # Assuming a 32-bit value, adjust if different 47 | return int.from_bytes(value, byteorder='little', signed=False) 48 | return None 49 | 50 | def dump_yaml(foo, outfile): 51 | yaml.dump(foo, outfile) 52 | 53 | def load_yaml_file(foo): 54 | try: 55 | with open(foo, "r") as file: 56 | return yaml.load(file) 57 | except ruamel.yaml.constructor.DuplicateKeyError as msg: 58 | logger = logging.getLogger(__name__) 59 | error = "\n".join(str(msg).split("\n")[2:-7]) 60 | logger.error(error) 61 | raise SystemExit 62 | 63 | class makeUtil(): 64 | """ 65 | Utility for ease of use of make commands like `make` and `pmake`. 66 | Supports automatic addition and execution of targets. Uses the class 67 | :py:class:`shellCommand` to execute commands. 68 | """ 69 | def __init__(self,makeCommand='make',makefilePath="./Makefile"): 70 | """ Constructor. 71 | 72 | :param makeCommand: The variant of make to be used with optional arguments. 73 | Ex - `pmake -j 8` 74 | 75 | :type makeCommand: str 76 | 77 | :param makefilePath: The path to the makefile to be used. 78 | 79 | :type makefilePath: str 80 | 81 | """ 82 | self.makeCommand=makeCommand 83 | self.makefilePath = makefilePath 84 | self.targets = [] 85 | def add_target(self,command,tname=""): 86 | """ 87 | Function to add a target to the makefile. 88 | 89 | :param command: The command to be executed when the target is run. 90 | 91 | :type command: str 92 | 93 | :param tname: The name of the target to be used. If not specified, TARGET is used as the name. 94 | 95 | :type tname: str 96 | """ 97 | if tname == "": 98 | tname = "TARGET"+str(len(self.targets)) 99 | with open(self.makefilePath,"a") as makefile: 100 | makefile.write("\n\n.PHONY : " + tname + "\n" + tname + " :\n\t"+command.replace("\n","\n\t")) 101 | self.targets.append(tname) 102 | def execute_target(self,tname,cwd="./"): 103 | """ 104 | Function to execute a particular target only. 105 | 106 | :param tname: Name of the target to execute. 107 | 108 | :type tname: str 109 | 110 | :param cwd: The working directory to be set while executing the make command. 111 | 112 | :type cwd: str 113 | 114 | :raise AssertionError: If target name is not present in the list of defined targets. 115 | 116 | """ 117 | assert tname in self.targets, "Target does not exist." 118 | shellCommand(self.makeCommand+" -f "+self.makefilePath+" "+tname).run(cwd=cwd) 119 | def execute_all(self,cwd): 120 | """ 121 | Function to execute all the defined targets. 122 | 123 | :param cwd: The working directory to be set while executing the make command. 124 | 125 | :type cwd: str 126 | 127 | """ 128 | shellCommand(self.makeCommand+" -f "+self.makefilePath+" "+" ".join(self.targets)).run(cwd=cwd) 129 | 130 | class combineReader(object): 131 | def __init__(self, file_names): 132 | self._to_do = list(file_names[:]) 133 | self._fp = None 134 | 135 | def __enter__(self): 136 | return self 137 | 138 | def __exit__(self, exception_type, exception_value, exception_traceback): 139 | if self._fp: 140 | self._fp.close() 141 | 142 | def read(self, size=None): 143 | res = '' 144 | while True: 145 | if self._fp is None: 146 | if not self._to_do: 147 | return res 148 | else: 149 | self._fp = open(self._to_do.pop(0)) 150 | if size is None: 151 | data = self._fp.read() 152 | else: 153 | data = self._fp.read(size) 154 | if size is None or not data: 155 | self._fp.close() 156 | self._fp = None 157 | res += data 158 | if size is None: 159 | continue 160 | size -= len(data) 161 | if size == 0: 162 | break 163 | return res 164 | 165 | def load_cgf(files): 166 | with combineReader(files) as fp: 167 | # Intermediate fix for no aliasing in output cgf. 168 | # Load in safe mode, dump to string and load in 169 | # rt mode to support comments. 170 | # TODO: Find a better way of doing this by 171 | # overloading functions from the original library 172 | # representers. 173 | from io import StringIO 174 | string_stream = StringIO() 175 | safe_yaml.dump(dict(safe_yaml.load(fp)),string_stream) 176 | output_str = string_stream.getvalue() 177 | string_stream.close() 178 | return yaml.load(output_str) 179 | 180 | class Command(): 181 | """ 182 | Class for command build which is supported 183 | by :py:mod:`suprocess` module. Supports automatic 184 | conversion of :py:class:`pathlib.Path` instances to 185 | valid format for :py:mod:`subprocess` functions. 186 | """ 187 | 188 | def __init__(self, *args, pathstyle='auto', ensure_absolute_paths=False): 189 | """Constructor. 190 | 191 | :param pathstyle: Determine the path style when adding instance of 192 | :py:class:`pathlib.Path`. Path style determines the slash type 193 | which separates the path components. If pathstyle is `auto`, then 194 | on Windows backslashes are used and on Linux forward slashes are used. 195 | When backslashes should be prevented on all systems, the pathstyle 196 | should be `posix`. No other values are allowed. 197 | 198 | :param ensure_absolute_paths: If true, then any passed path will be 199 | converted to absolute path. 200 | 201 | :param args: Initial command. 202 | 203 | :type pathstyle: str 204 | 205 | :type ensure_absolute_paths: bool 206 | """ 207 | self.ensure_absolute_paths = ensure_absolute_paths 208 | self.pathstyle = pathstyle 209 | self.args = [] 210 | 211 | for arg in args: 212 | self.append(arg) 213 | 214 | def append(self, arg): 215 | """Add new argument to command. 216 | 217 | :param arg: Argument to be added. It may be list, tuple, 218 | :py:class:`Command` instance or any instance which 219 | supports :py:func:`str`. 220 | """ 221 | to_add = [] 222 | if type(arg) is list: 223 | to_add = arg 224 | elif type(arg) is tuple: 225 | to_add = list(arg) 226 | elif isinstance(arg, type(self)): 227 | to_add = arg.args 228 | elif isinstance(arg, str) and not self._is_shell_command(): 229 | to_add = shlex.split(arg) 230 | else: 231 | # any object which will be converted into str. 232 | to_add.append(arg) 233 | 234 | # Convert all arguments to its string representation. 235 | # pathlib.Path instances 236 | to_add = [ 237 | self._path2str(el) if isinstance(el, pathlib.Path) else str(el) 238 | for el in to_add 239 | ] 240 | self.args.extend(to_add) 241 | 242 | def clear(self): 243 | """Clear arguments.""" 244 | self.args = [] 245 | 246 | def run(self, **kwargs): 247 | """Execute the current command. 248 | 249 | Uses :py:class:`subprocess.Popen` to execute the command. 250 | 251 | :return: The return code of the process . 252 | :raise subprocess.CalledProcessError: If `check` is set 253 | to true in `kwargs` and the process returns 254 | non-zero value. 255 | """ 256 | kwargs.setdefault('shell', self._is_shell_command()) 257 | cwd = self._path2str(kwargs.get( 258 | 'cwd')) if not kwargs.get('cwd') is None else self._path2str( 259 | os.getcwd()) 260 | kwargs.update({'cwd': cwd}) 261 | logger.debug(cwd) 262 | # When running as shell command, subprocess expects 263 | # The arguments to be string. 264 | logger.debug(str(self)) 265 | cmd = str(self) if kwargs['shell'] else self 266 | x = subprocess.Popen(cmd, 267 | stdout=subprocess.PIPE, 268 | stderr=subprocess.PIPE, 269 | **kwargs) 270 | out, err = x.communicate() 271 | out = out.rstrip() 272 | err = err.rstrip() 273 | if x.returncode != 0: 274 | if out: 275 | logger.error(out.decode("ascii")) 276 | if err: 277 | logger.error(err.decode("ascii")) 278 | else: 279 | if out: 280 | logger.warning(out.decode("ascii")) 281 | if err: 282 | logger.warning(err.decode("ascii")) 283 | return x.returncode 284 | 285 | def _is_shell_command(self): 286 | """ 287 | Return true if current command is supposed to be executed 288 | as shell script otherwise false. 289 | """ 290 | return any('|' in arg for arg in self.args) 291 | 292 | def _path2str(self, path): 293 | """Convert :py:class:`pathlib.Path` to string. 294 | 295 | The final form of the string is determined by the 296 | configuration of `Command` instance. 297 | 298 | :param path: Path-like object which will be converted 299 | into string. 300 | :return: String representation of `path` 301 | """ 302 | path = pathlib.Path(path) 303 | if self.ensure_absolute_paths and not path.is_absolute(): 304 | path = path.resolve() 305 | 306 | if self.pathstyle == 'posix': 307 | return path.as_posix() 308 | elif self.pathstyle == 'auto': 309 | return str(path) 310 | else: 311 | raise ValueError(f"Invalid pathstyle {self.pathstyle}") 312 | 313 | def __add__(self, other): 314 | cmd = Command(self, 315 | pathstyle=self.pathstyle, 316 | ensure_absolute_paths=self.ensure_absolute_paths) 317 | cmd += other 318 | return cmd 319 | 320 | def __iadd__(self, other): 321 | self.append(other) 322 | return self 323 | 324 | def __iter__(self): 325 | """ 326 | Support iteration so functions from :py:mod:`subprocess` module 327 | support `Command` instance. 328 | """ 329 | return iter(self.args) 330 | 331 | def __repr__(self): 332 | return f'<{self.__class__.__name__} args={self.args}>' 333 | 334 | def __str__(self): 335 | return ' '.join(self.args) 336 | 337 | class shellCommand(Command): 338 | """ 339 | Sub Class of the command class which always executes commands as shell commands. 340 | """ 341 | 342 | def __init__(self, *args, pathstyle='auto', ensure_absolute_paths=False): 343 | """ 344 | :param pathstyle: Determine the path style when adding instance of 345 | :py:class:`pathlib.Path`. Path style determines the slash type 346 | which separates the path components. If pathstyle is `auto`, then 347 | on Windows backslashes are used and on Linux forward slashes are used. 348 | When backslashes should be prevented on all systems, the pathstyle 349 | should be `posix`. No other values are allowed. 350 | 351 | :param ensure_absolute_paths: If true, then any passed path will be 352 | converted to absolute path. 353 | 354 | :param args: Initial command. 355 | 356 | :type pathstyle: str 357 | 358 | :type ensure_absolute_paths: bool 359 | 360 | """ 361 | return super().__init__(*args, 362 | pathstyle=pathstyle, 363 | ensure_absolute_paths=ensure_absolute_paths) 364 | 365 | def _is_shell_command(self): 366 | return True 367 | 368 | def sys_command(command): 369 | logger.warning('$ {0} '.format(' '.join(shlex.split(command)))) 370 | x = subprocess.Popen(shlex.split(command), 371 | stdout=subprocess.PIPE, 372 | stderr=subprocess.PIPE, 373 | ) 374 | try: 375 | out, err = x.communicate(timeout=5) 376 | except subprocess.TimeoutExpired: 377 | x.kill() 378 | out, err = x.communicate() 379 | 380 | out = out.rstrip() 381 | err = err.rstrip() 382 | if x.returncode != 0: 383 | if out: 384 | logger.error(out.decode("ascii")) 385 | if err: 386 | logger.error(err.decode("ascii")) 387 | else: 388 | if out: 389 | logger.debug(out.decode("ascii")) 390 | if err: 391 | logger.debug(err.decode("ascii")) 392 | return out.decode("ascii") 393 | 394 | def sys_command_file(command, filename): 395 | cmd = command.split(' ') 396 | cmd = [x.strip(' ') for x in cmd] 397 | cmd = [i for i in cmd if i] 398 | logger.debug('{0} > {1}'.format(' '.join(cmd), filename)) 399 | fp = open(filename, 'w') 400 | out = subprocess.Popen(cmd, stdout=fp, stderr=fp) 401 | stdout, stderr = out.communicate() 402 | fp.close() 403 | 404 | def import_instr_alias(alias): 405 | ''' 406 | Return instructions pertaining to a particular alias 407 | 408 | alias: (string) The alias to be imported 409 | 410 | ''' 411 | 412 | # Function to flatten nested lists 413 | from collections import Iterable 414 | def flatten(lis): 415 | for item in lis: 416 | if isinstance(item, Iterable) and not isinstance(item, str): 417 | for x in flatten(item): 418 | yield x 419 | else: 420 | yield item 421 | 422 | isac_path = os.path.dirname(riscv_isac.__file__) 423 | alias_dict = load_yaml_file(isac_path + '/data/instr_alias.yaml') 424 | if alias in alias_dict: 425 | return list(flatten(alias_dict[alias])) 426 | else: 427 | return None 428 | 429 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.18.0 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] 7 | search = version='{current_version}' 8 | replace = version='{new_version}' 9 | 10 | [bumpversion:file:riscv_isac/__init__.py] 11 | search = __version__ = '{current_version}' 12 | replace = __version__ = '{new_version}' 13 | 14 | [bdist_wheel] 15 | universal = 1 16 | 17 | [flake8] 18 | exclude = docs 19 | 20 | [aliases] 21 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # See LICENSE.incore for details 2 | 3 | """The setup script.""" 4 | 5 | import os 6 | from setuptools import setup, find_packages 7 | 8 | # Base directory of package 9 | here = os.path.abspath(os.path.dirname(__file__)) 10 | 11 | 12 | def read(*parts): 13 | with codecs.open(os.path.join(here, *parts), 'r') as fp: 14 | return fp.read() 15 | def read_requires(name): 16 | with open(os.path.join(here, "riscv_isac", name),"r") as reqfile: 17 | return reqfile.read().splitlines() 18 | 19 | #Long Description 20 | with open("README.rst", "r") as fh: 21 | readme = fh.read() 22 | 23 | setup_requirements = [ ] 24 | 25 | setup( 26 | name='riscv_isac', 27 | version='0.18.0', 28 | description="RISC-V ISAC", 29 | long_description=readme + '\n\n', 30 | classifiers=[ 31 | "Programming Language :: Python :: 3.6", 32 | "License :: OSI Approved :: BSD License", 33 | "Development Status :: 4 - Beta" 34 | ], 35 | url='https://github.com/riscv/riscv-isac', 36 | author="InCore Semiconductors Pvt. Ltd.", 37 | author_email='info@incoresemi.com', 38 | license="BSD-3-Clause", 39 | packages=find_packages(), 40 | package_dir={'riscv_isac': 'riscv_isac'}, 41 | package_data={ 42 | 'riscv_isac': [ 43 | 'requirements.txt' 44 | ] 45 | }, 46 | install_requires=read_requires("requirements.txt"), 47 | python_requires='>=3.6.0', 48 | entry_points={ 49 | 'console_scripts': [ 50 | 'riscv_isac=riscv_isac.main:cli', 51 | ], 52 | }, 53 | include_package_data=True, 54 | keywords='riscv_isac', 55 | test_suite='tests', 56 | tests_require=read_requires("test_requirements.txt"), 57 | zip_safe=False, 58 | ) 59 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # See License.incore for details. 2 | """Unit test package for riscv_isac.""" 3 | -------------------------------------------------------------------------------- /tests/test_riscv_isac.py: -------------------------------------------------------------------------------- 1 | # See License.incore for details. 2 | from click.testing import CliRunner 3 | from riscv_isac.main import cli 4 | import pytest 5 | 6 | @pytest.fixture 7 | def runner(): 8 | return CliRunner() 9 | 10 | #def test_clean(runner): 11 | # '''Testing clean option''' 12 | # result = runner.invoke(cli, ['--clean']) 13 | # assert result.exit_code == 0 14 | 15 | def test_version(runner): 16 | '''Testing version option''' 17 | result = runner.invoke(cli, ['--version']) 18 | assert result.exit_code == 0 19 | 20 | --------------------------------------------------------------------------------