├── .gitattributes ├── .gitconfig ├── .github ├── FUNDING.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── docs.yml │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── contrib ├── .flake8 ├── .gitignore ├── .mypy.ini ├── celllib.kicad_sch └── meson.build ├── docs ├── _static │ └── css │ │ └── styles.css ├── build.md ├── conf.py ├── index.md ├── requirements.txt ├── scripts.md ├── tutorial.md └── yosys_passes │ ├── index.md │ ├── synth_discretize.md │ └── write_kicad.md ├── meson.build ├── meson_options.txt ├── src ├── config.hh.in ├── meson.build └── techlib │ ├── cells_dffe.v │ ├── cells_map.v │ ├── cells_mod.v │ ├── cells_mux.v │ ├── discretize.lib │ ├── meson.build │ ├── synth_discretize.cc │ └── synth_discretize.ys └── tests ├── .gitignore ├── counter.v ├── inverter.v ├── meson.build └── picorv32.v /.gitattributes: -------------------------------------------------------------------------------- 1 | *.lib linguist-language=liberty 2 | tests/*.v linguist-vendored 3 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [pull] 2 | rebase = merges 3 | [rebase] 4 | autoStash = true 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: lethalbit 2 | patreon: lethalbit 3 | ko_fi: lethalbit 4 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **Your checklist for this pull request** 4 | - [ ] I've read the [code of conduct](https://github.com/lethalbit/discretize/blob/main/CODE_OF_CONDUCT.md) 5 | - [ ] I've read the [guidelines for contributing](https://github.com/lethalbit/discretize/blob/main/CONTRIBUTING.md) to this repository 6 | 7 | - [ ] I've updated the documentation with the relevant information (if needed) 8 | 9 | 10 | **Detailed description** 11 | 12 | 13 | 14 | **Test plan (required)** 15 | 16 | 17 | 18 | 19 | 20 | **Closing issues** 21 | 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: "discretize docs" 2 | on: 3 | push: 4 | branches: 5 | - 'main' 6 | jobs: 7 | document: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | contents: write 11 | pages: write 12 | steps: 13 | - name: Setup Python 14 | uses: actions/setup-python@v4 15 | with: 16 | python-version: 3.11 17 | - name: Initialize Environment 18 | shell: bash 19 | env: 20 | WORKSPACE: ${{ github.workspace }} 21 | run: | 22 | echo "$HOME/.local/bin:$PATH" >> $GITHUB_PATH 23 | echo "GITHUB_WORKSPACE=\"`pwd`\"" >> $GITHUB_ENV 24 | - name: Checkout 25 | uses: actions/checkout@v3 26 | with: 27 | lfs: true 28 | submodules: true 29 | - name: Setup 30 | shell: bash 31 | run: | 32 | sudo apt-get update 33 | sudo apt-get install graphviz 34 | sudo pip3 install --upgrade pip setuptools wheel 35 | pip3 install --user -r ./docs/requirements.txt 36 | 37 | - name: Build Docs 38 | shell: bash 39 | run: | 40 | sphinx-build -b html ./docs ./_build/ 41 | - name: Deploy 42 | uses: JamesIves/github-pages-deploy-action@3.7.1 43 | with: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | BRANCH: gh-pages 46 | FOLDER: _build 47 | CLEAN: true 48 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: "discretize Tests" 2 | on: 3 | push: {} 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Setup Python 10 | uses: actions/setup-python@v4 11 | with: 12 | python-version: '3.11' 13 | - name: Initialize Environment 14 | shell: bash 15 | env: 16 | WORKSPACE: ${{ github.workspace }} 17 | run: | 18 | echo "$HOME/.local/bin:$PATH" >> $GITHUB_PATH 19 | echo "GITHUB_WORKSPACE=\"`pwd`\"" >> $GITHUB_ENV 20 | 21 | - name: Setup GCC 22 | run: | 23 | sudo apt-add-repository ppa:ubuntu-toolchain-r/test 24 | sudo apt-get update 25 | sudo apt-get install gcc-11 g++-11 gcovr 26 | echo "CC=gcc-11" >> $GITHUB_ENV 27 | echo "CXX=g++-11" >> $GITHUB_ENV 28 | 29 | - name: Checkout 30 | uses: actions/checkout@v3 31 | 32 | - name: Setup OSS CAD Suite 33 | uses: YosysHQ/setup-oss-cad-suite@v2 34 | with: 35 | github-token: ${{ secrets.GITHUB_TOKEN }} 36 | 37 | - name: Setup Meson + Ninja 38 | shell: bash 39 | run: | 40 | python -m pip install --user --upgrade pip setuptools wheel setuptools_scm 41 | python -m pip install --user meson ninja 42 | 43 | - name: Setup Yosys deps 44 | run: | 45 | sudo apt-get update 46 | sudo apt-get install tcl-dev libffi-dev 47 | 48 | - name: Version tools 49 | run: | 50 | $CC --version 51 | $CXX --version 52 | meson --version 53 | ninja --version 54 | yosys --version 55 | 56 | - name: Configure 57 | run: meson setup build --prefix=$HOME/.local 58 | 59 | - name: Build 60 | run: meson compile -C build 61 | 62 | # - name: Test 63 | # run: meson test -C build 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | build/ 3 | *.o 4 | *.json 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | 19 | 20 | ## [Unreleased] 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, religion, or sexual identity 11 | and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the 27 | overall community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or 32 | advances of any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email 36 | address, without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | `aki@lethalbit.net`. 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series 87 | of actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or 94 | permanent ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within 114 | the community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.0, available at 120 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 121 | 122 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 123 | enforcement ladder](https://github.com/mozilla/diversity). 124 | 125 | [homepage]: https://www.contributor-covenant.org 126 | 127 | For answers to common questions about this code of conduct, see the FAQ at 128 | https://www.contributor-covenant.org/faq. Translations are available at 129 | https://www.contributor-covenant.org/translations. 130 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | > [!IMPORTANT] 4 | > Contributions that were generated in whole or in-part from any 5 | > language model or AI, such as GitHub Copilot, ChatGPT, BARD, or any other such tool 6 | > are explicitly forbidden and will result in your permanent ban from contributing 7 | > to this project. 8 | 9 | ## Contributing 10 | 11 | Contributions to this project are released under the [project's open source license](LICENSE). 12 | 13 | Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). 14 | By participating in this project you agree to abide by its terms. 15 | 16 | 17 | ## Submitting a Pull Request 18 | 19 | 1. [Fork](https://github.com/lethalbit/discretize/fork) and clone the repository 20 | 2. Create a new branch: `git switch -c branch-name` (`git checkout -b branch-name` in the old syntax) 21 | 3. Make your change, create unit tests and sure all tests new and old pass 22 | 4. Push to your fork and submit a [pull request](https://github.com/lethalbit/discretize/compare) 23 | 24 | Before your pull request will be accepted, please keep in mind that unless your change is a bugfix, writing unit tests to prove your new code is mandatory. 25 | 26 | Additionally, please write good and descriptive commit messages that both summarize the change and, 27 | if necessary, expand on the summary using description lines. 28 | "Patched the utility header" is, while terse and correct, an example of a bad commit message. 29 | "Fixed a bug in core/lang_standards.cc causing issues in C++ handling" is an example of a better commit message. 30 | 31 | We would like to be able to look back through the commit history and tell what happened, when, and why without having 32 | to dip into the commit descriptions as this improves the `git bisect` experience and improves everyone's lives. 33 | 34 | We use rebasing to merge pull requests, so please keep this in mind and aim to keep a linear history. 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Aki "lethalbit" Van Ness 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # discretize 2 | 3 | > [!WARNING] 4 | > This is still in the early alpha stages, the output logic, netlist, and 5 | > KiCad files may be sub-optimal, or require an obscene number of devices. 6 | 7 | discretize is a set of a [Yosys] plugin, [`synth_discretize`], and a set of [utility scripts](./contrib/) for synthesizing an HDL design into a netlist of discrete [MOSFET]s and generating a [KiCad] netlist and schematic for the design. 8 | 9 | ## How It Works 10 | 11 | TODO 12 | 13 | 14 | ## Usage 15 | 16 | To convert an HDL design into it's discrete representation [`synth_discretize`] is used like any other [Yosys] pass to apply technology mapping and optimization onto the design, converting it to an equivalent design made out of [MOSFET]s 17 | 18 | For example, the following yosys script will synthesize the [`counter.v`](./tests/counter.v) file 19 | into a discrete netlist, and then dump the statistics and generated module. 20 | 21 | ``` 22 | plugin -i ./build/src/techlib/synth_discretize.so 23 | read_verilog ./tests/counter.v 24 | synth_discretize -techlib ./src/techlib 25 | tee -o counter.stat.json stat -json 26 | write_verilog -noexpr counter.discrete.v 27 | ``` 28 | 29 | You can run that like `$ yosys -s counter.ys`, and you should two files `counter.stats.json` and `counter.discrete.v`. 30 | 31 | The first file, `counter.stats.json` describes the design statistics, in the case of the example above it would be something like: 32 | 33 | ```json 34 | "design": { 35 | "num_wires": 826, 36 | "num_wire_bits": 2066, 37 | "num_pub_wires": 5, 38 | "num_pub_wire_bits": 19, 39 | "num_memories": 0, 40 | "num_memory_bits": 0, 41 | "num_processes": 0, 42 | "num_cells": 478, 43 | "num_cells_by_type": { 44 | "$_SDFF_PN0_": 8, 45 | "GND": 1, 46 | "NFET": 246, 47 | "PFET": 222, 48 | "VCC": 1 49 | } 50 | } 51 | ``` 52 | 53 | Notice two cells called `GND` and `VCC` those are added to ensure that constant highs and lows are tied properly, in a fully implemented design, those would be a ground pour and a power pour on the board. 54 | 55 | The next file, `counter.discrete.v` contains the dumped verilog module with all of the logic broken into wires and instances of `PFET`'s or `NFET`s. 56 | 57 | 58 | ## Configuring and Building 59 | 60 | The following steps describe how to build discretize, it should be consistent for Linux, macOS, and Windows, but macOS and Windows remain untested. 61 | 62 | **NOTE:** The minimum C++ standard to build discretize is C++17. 63 | 64 | ### Prerequisites 65 | 66 | To build discretize, ensure you have the following build time dependencies: 67 | * git 68 | * meson 69 | * ninja 70 | * g++ >= 11 or clang++ >= 11 71 | * python >= 3.9 72 | * yosys >= 0.28 73 | 74 | 75 | ### Configuring 76 | 77 | You can build discretize with the default options, all of which can be found in [`meson_options.txt`](meson_options.txt). You can change these by specifying `-D=` at initial meson invocation time, or with `meson configure` in the build directory post initial configure. 78 | 79 | To change the install prefix, which is `/usr/local` by default ensure to pass `--prefix ` when running meson for the first time. 80 | 81 | In either case, simply running `meson build` from the root of the repository will be sufficient and place all of the build files in the `build` subdirectory. 82 | 83 | ### Building 84 | 85 | Once you have configured discretize appropriately, to simply build and install simply run the following: 86 | 87 | ``` 88 | $ ninja -C build 89 | $ ninja -C build test # Optional: Run Tests 90 | $ ninja -C build install 91 | ``` 92 | 93 | This will build and install discretize into the default prefix which is `/usr/local`, to change that see the configuration steps above. 94 | 95 | ### Notes to Package Maintainers 96 | 97 | If you are building discretize for inclusion in a distributions package system then ensure to set `DESTDIR` prior to running meson install. 98 | 99 | There is also a `bugreport_url` configuration option that is set to this repositories issues tracker by default, it is recommended to change it to your distributions bug tracking page. 100 | 101 | ## License 102 | 103 | Discretize is licensed under the [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html), the full text of which can be found in the [LICENSE](LICENSE) file. 104 | 105 | 106 | [yosys]: https://github.com/YosysHQ/yosys 107 | [kicad]: https://www.kicad.org/ 108 | 109 | [`synth_discretize`]: ./src/techlib 110 | [`write_kicad`]: https://github.com/lethalbit/write_kicad 111 | [MOSFET]: https://en.wikipedia.org/wiki/MOSFET 112 | -------------------------------------------------------------------------------- /contrib/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | 3 | exclude = 4 | .git, 5 | __pycache__, 6 | .eggs, 7 | build, 8 | _build, 9 | deps 10 | 11 | max-line-length = 120 12 | indent-size = 1 13 | statistics = True 14 | ignore = 15 | E124, 16 | E126, 17 | E128, 18 | E131, 19 | E201, 20 | E202, 21 | E203, 22 | E221, 23 | E226, 24 | E241, 25 | E251, 26 | E261, 27 | E262, 28 | E272, 29 | E302, 30 | E303, 31 | E305, 32 | E401, 33 | E402, 34 | F403, 35 | F405, 36 | W191, 37 | W504 38 | -------------------------------------------------------------------------------- /contrib/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !.flake8 4 | !.mypy.ini 5 | !celllib.kicad_sch 6 | !meson.build 7 | -------------------------------------------------------------------------------- /contrib/.mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | warn_return_any = True 3 | -------------------------------------------------------------------------------- /contrib/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | -------------------------------------------------------------------------------- /docs/_static/css/styles.css: -------------------------------------------------------------------------------- 1 | @import 'theme.css'; 2 | /* for the Read the Docs theme */ 3 | @import url('https://fonts.googleapis.com/css2?family=Overpass+Mono:wght@300;400&display=swap'); 4 | 5 | div.wy-nav-content { 6 | padding: 1.618em 3.236em; 7 | height: 100%; 8 | max-width: 1000px; 9 | margin: auto; 10 | } 11 | 12 | div.highlight { 13 | border-radius: 5px; 14 | } 15 | 16 | div.admonition { 17 | border-radius: 0px 0px 5px 5px; 18 | } 19 | 20 | p.admonition-title { 21 | border-radius: 5px 5px 0px 0px; 22 | } 23 | 24 | code.literal { 25 | border-radius: 5px; 26 | } 27 | -------------------------------------------------------------------------------- /docs/build.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | ```{todo} 4 | Write this 5 | ``` 6 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | import os, sys, datetime 3 | from pathlib import Path 4 | 5 | sys.path.insert(0, os.path.abspath('.')) 6 | 7 | REPO_ROOT = Path(__file__).parent.parent 8 | 9 | def version(): 10 | try: 11 | from setuptools_scm.git import parse as parse_git 12 | except ImportError: 13 | return '' 14 | 15 | git = parse_git(str(REPO_ROOT)) 16 | if not git: 17 | return '' 18 | elif git.exact: 19 | return git.format_with('{tag}') 20 | else: 21 | return 'latest' 22 | 23 | project = 'discretize' 24 | version = version() 25 | release = version.split('+')[0] 26 | copyright = f'{datetime.date.today().year}, Aki "lethalbit" Van Ness' 27 | language = 'en' 28 | 29 | extensions = [ 30 | 'sphinx.ext.autodoc', 31 | 'sphinx.ext.doctest', 32 | 'sphinx.ext.githubpages', 33 | 'sphinx.ext.graphviz', 34 | 'sphinx.ext.napoleon', 35 | 'sphinx.ext.todo', 36 | 'sphinxcontrib.platformpicker', 37 | 'myst_parser', 38 | 'sphinx_rtd_theme', 39 | ] 40 | 41 | source_suffix = { 42 | '.rst': 'restructuredtext', 43 | '.md': 'markdown', 44 | } 45 | 46 | pygments_style = 'monokai' 47 | autodoc_member_order = 'bysource' 48 | graphviz_output_format = 'svg' 49 | todo_include_todos = True 50 | 51 | 52 | napoleon_google_docstring = False 53 | napoleon_numpy_docstring = True 54 | napoleon_use_ivar = True 55 | napoleon_custom_sections = [ 56 | 'Platform overrides' 57 | ] 58 | 59 | myst_heading_anchors = 3 60 | 61 | html_baseurl = 'https://lethalbit.github.io/discretize/' 62 | html_theme = 'sphinx_rtd_theme' 63 | html_copy_source = False 64 | 65 | html_theme_options = { 66 | 'collapse_navigation' : False, 67 | 'style_external_links': True, 68 | } 69 | 70 | html_static_path = [ 71 | '_static' 72 | ] 73 | 74 | html_css_files = [ 75 | 'css/styles.css' 76 | ] 77 | 78 | html_style = 'css/styles.css' 79 | 80 | autosectionlabel_prefix_document = True 81 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ```{toctree} 2 | :hidden: 3 | 4 | build 5 | tutorial 6 | yosys_passes/index 7 | scripts 8 | 9 | Source Code 10 | 11 | ``` 12 | # discretize 13 | 14 | discretize is a set of two [Yosys] plugins; [`synth_discretize`], and [`write_kicad`], and a set of [utility scripts](./scripts.md) for synthesizing an HDL design into a netlist of discrete [MOSFET]s and generating a [KiCad] netlist and schematic for the design. 15 | 16 | 17 | 18 | 19 | ## License 20 | 21 | Discretize is licensed under the [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html), the full text of which can be found in the [LICENSE](LICENSE) file. 22 | 23 | 24 | [yosys]: https://github.com/YosysHQ/yosys 25 | [kicad]: https://www.kicad.org/ 26 | 27 | [`synth_discretize`]: ./synth_discretize.md 28 | [`write_kicad`]: ./write_kicad.md 29 | [MOSFET]: https://en.wikipedia.org/wiki/MOSFET 30 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | sphinx-rtd-theme 3 | sphinxcontrib-platformpicker 4 | myst-parser 5 | -------------------------------------------------------------------------------- /docs/scripts.md: -------------------------------------------------------------------------------- 1 | # Scripts 2 | 3 | ```{todo} 4 | Write this 5 | ``` 6 | -------------------------------------------------------------------------------- /docs/tutorial.md: -------------------------------------------------------------------------------- 1 | # Tutorial 2 | 3 | ```{todo} 4 | Write this 5 | ``` 6 | -------------------------------------------------------------------------------- /docs/yosys_passes/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Yosys Passes 3 | 4 | ```{toctree} 5 | :hidden: 6 | synth_discretize 7 | write_kicad 8 | 9 | ``` 10 | 11 | ```{todo} 12 | Write this 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/yosys_passes/synth_discretize.md: -------------------------------------------------------------------------------- 1 | # `synth_discretize` 2 | 3 | ```{todo} 4 | Write this 5 | ``` 6 | -------------------------------------------------------------------------------- /docs/yosys_passes/write_kicad.md: -------------------------------------------------------------------------------- 1 | # `write_kicad` 2 | 3 | ```{todo} 4 | Write this 5 | ``` 6 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | project( 3 | 'discretize', 4 | 'cpp', 5 | default_options: [ 6 | 'buildtype=release', 7 | 'cpp_std=c++17', 8 | 'warning_level=3', 9 | 'b_ndebug=if-release', 10 | 'b_lto=true', 11 | 'strip=true' 12 | ], 13 | license: 'BSD-3-Clause', 14 | version: '0.0.1', 15 | meson_version: '>= 1.0.0', 16 | subproject_dir: 'deps' 17 | ) 18 | 19 | cxx = meson.get_compiler('cpp') 20 | if get_option('cpp_std') not in ['c++17', 'c++20', 'c++23', 'gnu++17', 'gnu++20', 'gnu++23'] 21 | error('Unsupported C++ Version @0@, must be c++17/gnu++17 or newer'.format(get_option('cpp_std'))) 22 | endif 23 | 24 | extended_warnings = [ 25 | '-Wdouble-promotion', 26 | '-Wformat=2', 27 | '-Wformat-overflow=2', 28 | '-Wformat-signedness', 29 | '-Wformat-truncation', 30 | '-Wnull-dereference', 31 | '-Wmissing-attributes', 32 | '-Wmissing-braces', 33 | '-Wsequence-point', 34 | '-Wreturn-type', 35 | '-Wunused', 36 | '-Wunused-local-typedefs', 37 | '-Wunused-const-variable=2', 38 | '-Wmaybe-uninitialized', 39 | '-Wunknown-pragmas', 40 | '-Wstrict-aliasing', 41 | '-Wstrict-overflow=3', 42 | '-Wstring-compare', 43 | '-Wstringop-overflow', 44 | '-Warith-conversion', 45 | '-Wvla-parameter', 46 | '-Wduplicated-branches', 47 | '-Wshadow=local', 48 | '-Wunsafe-loop-optimizations', 49 | '-Wbad-function-cast', 50 | '-Wcast-qual', 51 | '-Wcast-align=strict', 52 | '-Wcast-function-type', 53 | '-Wconversion', 54 | '-Wdangling-else', 55 | '-Wsign-conversion', 56 | '-Wfloat-conversion', 57 | '-Wredundant-decls', 58 | '-Winline', 59 | '-Wvla', 60 | '-Wstack-protector', 61 | '-Wunsuffixed-float-constant', 62 | '-Wimplicit-fallthrough', 63 | ] 64 | 65 | add_project_arguments( 66 | cxx.get_supported_arguments(extended_warnings), 67 | language: 'cpp' 68 | ) 69 | 70 | is_clang = (cxx.get_id() == 'clang') 71 | is_gcc = (cxx.get_id() == 'gcc') 72 | compiler_version = cxx.version() 73 | yosys_datdir = get_option('yosys_datdir') 74 | yosys_cxxflags = '' 75 | 76 | if yosys_datdir == '' 77 | yosys_config = find_program('yosys-config', required: false) 78 | 79 | if yosys_config.found() 80 | yosys_datdir = run_command(yosys_config, '--datdir', check: true).stdout().strip() 81 | yosys_cxxflags = run_command(yosys_config, '--cxxflags', check: true).stdout().strip() 82 | endif 83 | endif 84 | 85 | yosys_incdir = yosys_datdir / 'include' 86 | yosys_plugindir = yosys_datdir / 'plugins' 87 | yosys_defines = [] 88 | yosys_incs = [] 89 | 90 | foreach elem : yosys_cxxflags.split() 91 | if elem.startswith('-D') 92 | yosys_defines += elem 93 | elif elem.startswith('-I') 94 | yosys_incs += elem.strip('-I').strip('"') 95 | endif 96 | endforeach 97 | 98 | message('Yosys data dir `@0@`'.format(yosys_datdir)) 99 | message('Yosys include dir `@0@`'.format(yosys_incdir)) 100 | message('Yosys plugin dir `@0@`'.format(yosys_plugindir)) 101 | 102 | subdir('contrib') 103 | subdir('src') 104 | 105 | if get_option('build_tests') 106 | subdir('tests') 107 | endif 108 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'bugreport_url', 3 | type: 'string', 4 | value: 'https://github.com/lethalbit/discretize/issues', 5 | description: 'URL for bug report submissions' 6 | ) 7 | 8 | option( 9 | 'yosys_datdir', 10 | type: 'string', 11 | value: '', 12 | description: 'The path to the yosys data dir. (if left empty `yosys-config --datdir` will be used)' 13 | ) 14 | 15 | option( 16 | 'build_tests', 17 | type: 'boolean', 18 | value: true, 19 | description: 'Build the tests' 20 | ) 21 | -------------------------------------------------------------------------------- /src/config.hh.in: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* config.hh - Build-time configuration */ 3 | @AUTOGEN_HEADER@ 4 | #pragma once 5 | #if !defined(DISCRETIZE_CONFIG_HH) 6 | #define DISCRETIZE_CONFIG_HH 7 | 8 | #include 9 | #include 10 | 11 | using namespace std::literals::string_view_literals; 12 | 13 | namespace discritize::config { 14 | /* Version Information */ 15 | [[maybe_unused]] 16 | constexpr static auto version{"@VERSION_NUMBER@"sv}; 17 | [[maybe_unused]] 18 | constexpr static auto git_hash{"@GIT_HASH@"sv}; 19 | [[maybe_unused]] 20 | constexpr static auto compiler_name{"@COMPILER_NAME@"sv}; 21 | [[maybe_unused]] 22 | constexpr static auto compiler_version{"@COMPILER_VERSION@"sv}; 23 | 24 | /* Platform Information */ 25 | [[maybe_unused]] 26 | constexpr static auto target_system{"@TARGET_SYS@"sv}; 27 | [[maybe_unused]] 28 | constexpr static auto target_arch{"@TARGET_ARCH@"sv}; 29 | [[maybe_unused]] 30 | 31 | [[maybe_unused]] 32 | constexpr static auto build_system{"@BUILD_SYS@"sv}; 33 | [[maybe_unused]] 34 | constexpr static auto build_arch{"@BUILD_ARCH@"sv}; 35 | 36 | /* Misc */ 37 | [[maybe_unused]] 38 | constexpr static auto bugreport_url{"@BUGREPORT_URL@"sv}; 39 | } 40 | 41 | #endif /* DISCRETIZE_CONFIG_HH */ 42 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | config = configuration_data() 4 | config.set('AUTOGEN_HEADER', '/* THIS FILE IS AUTOGENERATED, DO NOT EDIT */') 5 | ## Version Information 6 | config.set('COMPILER_NAME', cxx.get_id()) 7 | config.set('COMPILER_VERSION', cxx.version()) 8 | ## Platform information 9 | config.set('TARGET_SYS', target_machine.system()) 10 | config.set('TARGET_ARCH', target_machine.cpu()) 11 | 12 | config.set('BUILD_SYS', build_machine.system()) 13 | config.set('BUILD_ARCH', build_machine.cpu()) 14 | ## Misc 15 | config.set('BUGREPORT_URL', get_option('bugreport_url')) 16 | 17 | git = find_program('git', required: false, native: true) 18 | if git.found() 19 | git_hash = run_command(git, 'rev-parse', '--short', 'HEAD', check: false).stdout().strip() 20 | if run_command(git, 'diff', '--quiet', check: false).returncode() != 0 21 | git_hash += '-dirty' 22 | endif 23 | config.set('GIT_HASH', git_hash) 24 | describe = run_command(git, 'describe', '--tag', check: false) 25 | if describe.returncode() == 0 26 | config.set('VERSION_NUMBER', describe.stdout().strip()) 27 | else 28 | config.set('VERSION_NUMBER', '@0@-@1@'.format(meson.project_version(), git_hash)) 29 | endif 30 | else 31 | config.set('VERSION_NUMBER', meson.project_version()) 32 | endif 33 | 34 | config_header = configure_file( 35 | configuration: config, 36 | input: 'config.hh.in', 37 | output: 'config.hh' 38 | ) 39 | 40 | root_incs = include_directories('.', yosys_incdir, yosys_incs) 41 | 42 | subdir('techlib') 43 | -------------------------------------------------------------------------------- /src/techlib/cells_dffe.v: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | 3 | (* techmap_celltype = "$_DLATCH_P_" *) 4 | module _80_FET_dlatch_p (CLK, D, Q); 5 | input CLK; 6 | input D; 7 | output Q; 8 | 9 | endmodule 10 | 11 | (* techmap_celltype = "$_DLATCH_N_" *) 12 | module _80_FET_dlatch_n (CLK, D, Q); 13 | input CLK; 14 | input D; 15 | output Q; 16 | 17 | endmodule 18 | 19 | 20 | (* techmap_celltype = "$_DFF_N_" *) 21 | module _80_FET_dff_n (CLK, D, Q); 22 | input CLK; 23 | input D; 24 | output Q; 25 | 26 | 27 | endmodule 28 | 29 | (* techmap_celltype = "$_DFF_P_" *) 30 | module _80_FET_dff_p (CLK, D, Q); 31 | input CLK; 32 | input D; 33 | output Q; 34 | 35 | endmodule 36 | -------------------------------------------------------------------------------- /src/techlib/cells_map.v: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | 3 | (* techmap_celltype = "$_NOT_" *) 4 | module _80_FET_not (A, Y); 5 | input A; 6 | output Y; 7 | 8 | wire _0_; 9 | 10 | `ifdef DUAL_FETS 11 | // A more compact gate using a P/N FET pair 12 | \NFET_PFET_PAIR f0( 13 | .Gp(A), 14 | .Sp(1'b1), 15 | .Dp(_0_), 16 | .Gn(A), 17 | .Sn(_0_), 18 | .D(1'b0) 19 | ); 20 | `else 21 | \PFET p0( 22 | .G(A), 23 | .S(1'b1), 24 | .D(_0_) 25 | ); 26 | \NFET n0( 27 | .G(A), 28 | .S(_0_), 29 | .D(1'b0) 30 | ); 31 | `endif 32 | 33 | assign Y = _0_; 34 | endmodule 35 | 36 | (* techmap_celltype = "$_BUF_" *) 37 | module _80_FET_buf (A, Y); 38 | input A; 39 | output Y; 40 | 41 | wire _0_; 42 | 43 | \$_NOT_ not0( 44 | .A(A), 45 | .Y(_0_) 46 | ); 47 | \$_NOT_ not1( 48 | .A(_0_), 49 | .Y(Y) 50 | ); 51 | endmodule 52 | 53 | (* techmap_celltype = "$_NAND_" *) 54 | module _80_FET_nand (A, B, Y); 55 | input A; 56 | input B; 57 | output Y; 58 | wire _0_; 59 | wire _1_; 60 | 61 | 62 | \PFET p0( 63 | .G(A), 64 | .S(1'b1), 65 | .D(_0_) 66 | ); 67 | 68 | \PFET p1( 69 | .G(B), 70 | .S(1'b1), 71 | .D(_0_) 72 | ); 73 | 74 | \NFET n0( 75 | .G(B), 76 | .S(_0_), 77 | .D(_1_) 78 | ); 79 | 80 | \NFET n1( 81 | .G(A), 82 | .S(_1_), 83 | .D(1'b0) 84 | ); 85 | 86 | assign Y = _0_; 87 | endmodule 88 | 89 | 90 | (* techmap_celltype = "$_AND_" *) 91 | module _80_FET_and (A, B, Y); 92 | input A; 93 | input B; 94 | output Y; 95 | 96 | wire _0_; 97 | wire _1_; 98 | 99 | \$_NAND_ nand0( 100 | .A(A), 101 | .B(B), 102 | .Y(_0_), 103 | ); 104 | 105 | \$_NOT_ not0( 106 | .A(_0_), 107 | .Y(Y) 108 | ); 109 | endmodule 110 | 111 | (* techmap_celltype = "$_ANDNOT_" *) 112 | module _80_FET_andnot (A, B, Y); 113 | input A; 114 | input B; 115 | output Y; 116 | 117 | wire _0_; 118 | 119 | \$_NOT_ not0( 120 | .A(B), 121 | .Y(_0_) 122 | ); 123 | 124 | \$_AND_ and0( 125 | .A(A), 126 | .B(_0_), 127 | .Y(Y) 128 | ); 129 | endmodule 130 | 131 | (* techmap_celltype = "$_OR_" *) 132 | module _80_FET_or (A, B, Y); 133 | input A; 134 | input B; 135 | output Y; 136 | 137 | wire _0_; 138 | wire _1_; 139 | 140 | \NFET n0( 141 | .G(B), 142 | .S(_0_), 143 | .D(_1_) 144 | ); 145 | 146 | \NFET n1( 147 | .G(A), 148 | .S(_1_), 149 | .D(1'b0) 150 | ); 151 | endmodule 152 | 153 | (* techmap_celltype = "$_NOR_" *) 154 | module _80_FET_nor (A, B, Y); 155 | input A; 156 | input B; 157 | output Y; 158 | 159 | wire _0_; 160 | 161 | \$_OR_ or0( 162 | .A(A), 163 | .B(B), 164 | .Y(_0_) 165 | ); 166 | 167 | \$_NOT_ not0( 168 | .A(_0_), 169 | .Y(Y) 170 | ); 171 | endmodule 172 | 173 | (* techmap_celltype = "$_ORNOT_" *) 174 | module _80_FET_ornot (A, B, Y); 175 | input A; 176 | input B; 177 | output Y; 178 | 179 | wire _0_; 180 | 181 | \$_NOT_ not0( 182 | .A(B), 183 | .Y(_0_) 184 | ); 185 | 186 | \$_OR_ or0( 187 | .A(A), 188 | .B(_0_), 189 | .Y(Y) 190 | ); 191 | endmodule 192 | 193 | (* techmap_celltype = "$_XOR_" *) 194 | module _80_FET_xor (A, B, Y); 195 | input A; 196 | input B; 197 | output Y; 198 | 199 | wire _0_; 200 | wire _1_; 201 | wire _2_; 202 | wire _3_; 203 | 204 | wire _Y_; 205 | wire _A_; 206 | wire _B_; 207 | 208 | \$_NOT_ not0( 209 | .A(A), 210 | .Y(_A_) 211 | ); 212 | 213 | \$_NOT_ not1( 214 | .A(B), 215 | .Y(_B_) 216 | ); 217 | 218 | 219 | \PFET p0( 220 | .S(1'b1), 221 | .G(_A_), 222 | .D(_0_) 223 | ); 224 | \PFET p1( 225 | .S(_0_), 226 | .G(B), 227 | .D(_Y_) 228 | ); 229 | \PFET p2( 230 | .S(1'b1), 231 | .G(A), 232 | .D(_1_) 233 | ); 234 | \PFET p3( 235 | .S(_1_), 236 | .G(_B_), 237 | .D(_Y_) 238 | ); 239 | 240 | \NFET n0( 241 | .S(_Y_), 242 | .G(_B_), 243 | .D(_2_) 244 | ); 245 | \NFET n1( 246 | .S(_2_), 247 | .G(_A_), 248 | .D(1'b0) 249 | ); 250 | \NFET n2( 251 | .S(_Y_), 252 | .G(B), 253 | .S(_3_) 254 | ); 255 | \NFET n3( 256 | .S(_3_), 257 | .G(A), 258 | .D(1'b0) 259 | ); 260 | 261 | assign Y = _Y_; 262 | endmodule 263 | 264 | (* techmap_celltype = "$_XNOR_" *) 265 | module _80_FET_xnor (A, B, Y); 266 | input A; 267 | input B; 268 | output Y; 269 | 270 | wire _0_; 271 | 272 | \$_XOR_ xor0( 273 | .A(A), 274 | .B(B), 275 | .Y(_0_) 276 | ); 277 | 278 | \$_NOT_ not0( 279 | .A(_0_), 280 | .Y(Y) 281 | ); 282 | endmodule 283 | -------------------------------------------------------------------------------- /src/techlib/cells_mod.v: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | 3 | module \NFET (G, S, D); 4 | input G; 5 | input S; 6 | inout D; 7 | 8 | assign D = (G == 1'b1) ? S : 1'b0; 9 | 10 | `ifdef TIMING 11 | specify 12 | // TODO: Real-world generic-ish timing info 13 | endspecify 14 | `endif 15 | endmodule 16 | 17 | module \DUAL_NFET (G0, S0, D0, G1, S1, D1); 18 | input G0; 19 | input S0; 20 | inout D0; 21 | input G1; 22 | input S1; 23 | inout D1; 24 | 25 | assign D0 = (G0 == 1'b1) ? S0 : 1'b0; 26 | assign D1 = (G1 == 1'b1) ? S1 : 1'b0; 27 | 28 | `ifdef TIMING 29 | specify 30 | // TODO: Real-world generic-ish timing info 31 | endspecify 32 | `endif 33 | endmodule 34 | 35 | module \PFET (G, S, D); 36 | input G; 37 | input S; 38 | inout D; 39 | 40 | assign D = (G == 1'b0) ? S : 1'b0; 41 | 42 | `ifdef TIMING 43 | specify 44 | // TODO: Real-world generic-ish timing info 45 | endspecify 46 | `endif 47 | endmodule 48 | 49 | 50 | module \DUAL_PFET (G0, S0, D0, G1, S1, D1); 51 | input G0; 52 | input S0; 53 | inout D0; 54 | 55 | input G1; 56 | input S1; 57 | inout D1; 58 | 59 | assign D0 = (G0 == 1'b0) ? S0 : 1'b0; 60 | assign D1 = (G1 == 1'b0) ? S1 : 1'b0; 61 | 62 | `ifdef TIMING 63 | specify 64 | // TODO: Real-world generic-ish timing info 65 | endspecify 66 | `endif 67 | endmodule 68 | 69 | 70 | module \NFET_PFET_PAIR (Gn, Sn, Dn, Gp, Sp, Dp); 71 | input Gn; 72 | input Sn; 73 | inout Dn; 74 | input Gp; 75 | input Sp; 76 | inout Dp; 77 | 78 | assign Dn = (Gn == 1'b1) ? Sn : 1'b0; 79 | assign Dp = (Gp == 1'b0) ? Sp : 1'b0; 80 | 81 | `ifdef TIMING 82 | specify 83 | // TODO: Real-world generic-ish timing info 84 | endspecify 85 | `endif 86 | endmodule 87 | -------------------------------------------------------------------------------- /src/techlib/cells_mux.v: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | 3 | (* techmap_celltype = "$_MUX_" *) 4 | module _80_FET_mux (A, B, S, Y); 5 | input A; 6 | input B; 7 | input S; 8 | output Y; 9 | 10 | wire _0_; 11 | wire _1_; 12 | wire _2_; 13 | wire _3_; 14 | 15 | wire _S_; 16 | wire _Y_; 17 | 18 | \$_NOT_ not0( 19 | .A(S), 20 | .Y(_S_) 21 | ); 22 | 23 | 24 | \PFET p0( 25 | .S(1'b1), 26 | .G(A), 27 | .D(_0_) 28 | ); 29 | \PFET p1( 30 | .S(_0_), 31 | .G(S), 32 | .D(_Y_) 33 | ); 34 | \PFET p2( 35 | .S(1'b1), 36 | .G(B), 37 | .D(_1_) 38 | ); 39 | \PFET p3( 40 | .S(_1_), 41 | .G(_S_), 42 | .D(_Y_) 43 | ); 44 | 45 | \NFET n0( 46 | .S(_Y_), 47 | .G(_S_), 48 | .D(_2_), 49 | ); 50 | \NFET n1( 51 | .S(_2_), 52 | .G(A), 53 | .D(1'b0) 54 | ); 55 | \NFET n2( 56 | .S(_Y_), 57 | .G(S), 58 | .D(_3_) 59 | ); 60 | \NFET n3( 61 | .S(_3_), 62 | .G(B), 63 | .D(1'b0) 64 | ); 65 | 66 | assign Y = _Y_; 67 | 68 | endmodule 69 | 70 | (* techmap_celltype = "$_NMUX_" *) 71 | module _80_FET_nmux (A, B, S, Y); 72 | input A; 73 | input B; 74 | input S; 75 | output Y; 76 | 77 | wire _0_; 78 | 79 | 80 | \$_MUX_ mux0( 81 | .A(A), 82 | .B(B), 83 | .S(S), 84 | .Y(_0_) 85 | ); 86 | 87 | \$_NOT_ not0( 88 | .A(_0_), 89 | .Y(Y) 90 | ); 91 | 92 | endmodule 93 | -------------------------------------------------------------------------------- /src/techlib/discretize.lib: -------------------------------------------------------------------------------- 1 | library(discrete) { 2 | technology("cmos"); 3 | 4 | time_unit: "1ns"; 5 | voltage_unit: "1V"; 6 | current_unit: "1mA"; 7 | capacitive_load_unit(1, pf); 8 | 9 | slew_lower_threshold_pct_fall: 30; 10 | slew_upper_threshold_pct_fall: 30; 11 | slew_lower_threshold_pct_rise: 70; 12 | slew_upper_threshold_pct_rise: 70; 13 | 14 | nom_process: 1; 15 | nom_temperature: 25; 16 | nom_voltage: 5; 17 | 18 | // discrete transistors 19 | cell(DISCRETE_NFET) { 20 | area: 3; 21 | pin(G) { direction: input; } 22 | pin(S) { direction: input; } 23 | pin(D) { direction: output; function: "G"; } 24 | } 25 | cell(DISCRETE_PFET) { 26 | area: 3; 27 | pin(G) { direction: input; } 28 | pin(S) { direction: input; } 29 | pin(D) { direction: output; function: "G'"; } 30 | } 31 | 32 | /* cell(DISCRETE_FET_PAIR) { 33 | area: 6; 34 | pin(G1) { direction: input; } 35 | pin(S1) { direction: input; } 36 | pin(D1) { direction: output; function: "G1"; } 37 | pin(G2) { direction: input; } 38 | pin(S2) { direction: input; } 39 | pin(D2) { direction: output; function: "G2'"; } 40 | } */ 41 | 42 | // Basic bit-cells 43 | 44 | cell("$_NOT_") { 45 | area: 2; 46 | pin(A) { direction: input; } 47 | pin(Y) { direction: output; function: "A'"; } 48 | } 49 | 50 | cell("$_NAND_") { 51 | area: 2; 52 | pin(A) { direction: input; } 53 | pin(B) { direction: input; } 54 | pin(Y) { direction: output; function: "(A*B)'"; } 55 | } 56 | 57 | // To make ABC happy 58 | cell("$_BUF_") { 59 | area: 2; 60 | pin(A) { direction: input; } 61 | pin(Y) { direction: output; function: "A"; } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/techlib/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | synth_discretize_srcs = files([ 4 | 'synth_discretize.cc', 5 | ]) 6 | 7 | synth_discretize = shared_module( 8 | 'synth_discretize', 9 | synth_discretize_srcs, 10 | name_prefix: '', 11 | include_directories: [ 12 | root_incs, include_directories('.') 13 | ], 14 | dependencies: [ 15 | 16 | ], 17 | 18 | gnu_symbol_visibility: 'inlineshidden', 19 | implicit_include_directories: false, 20 | cpp_args: [ 21 | '-DDISCRETIZE_BUILD_INTERNAL' 22 | ] + yosys_defines, 23 | install: (not meson.is_subproject()), 24 | install_dir: yosys_plugindir 25 | ) 26 | 27 | if not meson.is_subproject() 28 | install_data(files([ 29 | # 'cells_dffe.v',# Not done yet 30 | 'cells_map.v', 31 | 'cells_mod.v', 32 | 'cells_mux.v', 33 | 'discretize.lib', 34 | ]), install_dir: yosys_datdir / 'discretize') 35 | endif 36 | -------------------------------------------------------------------------------- /src/techlib/synth_discretize.cc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | 3 | #include 4 | #include 5 | 6 | #pragma GCC diagnostic push 7 | #pragma GCC diagnostic ignored "-Wsign-conversion" 8 | #pragma GCC diagnostic ignored "-Warith-conversion" 9 | #pragma GCC diagnostic ignored "-Wconversion" 10 | #pragma GCC diagnostic ignored "-Wcast-qual" 11 | #pragma GCC diagnostic ignored "-Wformat" 12 | #pragma GCC diagnostic ignored "-Wdouble-promotion" 13 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 14 | #include "kernel/yosys.h" 15 | #pragma GCC diagnostic pop 16 | 17 | #include "config.hh" 18 | 19 | namespace cfg = discritize::config; 20 | 21 | USING_YOSYS_NAMESPACE 22 | PRIVATE_NAMESPACE_BEGIN 23 | 24 | struct SynthDiscretizePass : public ScriptPass { 25 | 26 | SynthDiscretizePass() : ScriptPass("synth_discretize", "synthesis for discrete transistors") { } 27 | 28 | void help() override { 29 | // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| 30 | log("\n"); 31 | log(" synth_discretize [options]\n"); 32 | log("\n"); 33 | log("This command runs synthesis for discrete transistors."); 34 | log("\n"); 35 | log(" -top \n"); 36 | log(" Use the specified top module.\n"); 37 | log("\n"); 38 | log(" -json \n"); 39 | log(" Write the design to the specified JSON file.\n"); 40 | log(" (Writing of an output file is omitted if this parameter is not set.)\n"); 41 | log("\n"); 42 | log(" -verilog \n"); 43 | log(" Write the design to the specified verilog file.\n"); 44 | log(" (Writing of an output file is omitted if this parameter is not set.)\n"); 45 | log("\n"); 46 | log(" -kicad \n"); 47 | log(" Write the design to the specified KiCad schematic file.\n"); 48 | log(" NOTE: The write_kicad plugin needs to be loaded to use this option.\n"); 49 | log(" (Writing of an output file is omitted if this parameter is not set.)\n"); 50 | log("\n"); 51 | log(" -stats \n"); 52 | log(" Write the design statistics to the specified json file.\n"); 53 | log(" (Writing of an output file is omitted if this parameter is not set.)\n"); 54 | log("\n"); 55 | log(" -noflatten\n"); 56 | log(" Don't flatten the design, when used with `write_kicad` modules will be\n"); 57 | log(" made into sub-sheets.\n"); 58 | log("\n"); 59 | log(" -techlib \n"); 60 | log(" Specify the directory where to look for the discretize technology library.\n"); 61 | log(" (default: +/discretize/)\n"); 62 | log(" This is used in the case where the 'synth_discretize' is built out of tree\n"); 63 | log(" from Yosys.\n"); 64 | log("\n"); 65 | log(" -dualfet\n"); 66 | log(" Combine FETs in gates into either matched P/N FETS or dual PFETs and NFETS\n"); 67 | log(" where appropriate.\n"); 68 | log("\n"); 69 | log(" -addties\n"); 70 | log(" Insert pullup/pulldown cells into the design where appropriate.\n"); 71 | log(" This is primarily used in conjunction with KiCad export for physical\n"); 72 | log(" implementation.\n"); 73 | log("\n"); 74 | log(" -decap\n"); 75 | log(" Insert decoupling capacitors roughly where appropriate.\n"); 76 | log("\n"); 77 | log(" -noautoname\n"); 78 | log(" Don't run 'autoname' on the design, as it takes a while on big designs.\n"); 79 | log("\n"); 80 | log(" -dff\n"); 81 | log(" Enable DFF mapping. (EXPERIMENTAL)\n"); 82 | log("\n"); 83 | log(" -mux\n"); 84 | log(" Enable more advanced mux mapping. (EXPERIMENTAL)\n"); 85 | log("\n"); 86 | log("\n"); 87 | log("The following commands are executed by this synthesis command:\n"); 88 | help_script(); 89 | log("\n"); 90 | log("about synth_discretize:\n"); 91 | log(" license: BSD-3-Clause\n"); 92 | log(" website: https://github.com/lethalbit/discretize\n"); 93 | log(" version: %s\n", cfg::version.data()); 94 | log(" bug reports: %s", cfg::bugreport_url.data()); 95 | log("\n"); 96 | } 97 | 98 | std::string top_opt{"-auto-top"}; 99 | std::string kicad_file{}; 100 | std::string json_file{}; 101 | std::string vlog_file{}; 102 | std::string stat_file{}; 103 | std::string techlib_path{"+/discretize"}; 104 | bool dual_fet{false}; 105 | bool add_ties{false}; 106 | bool fixup_names{true}; 107 | bool dff_map{false}; 108 | bool mux_map{false}; 109 | bool flatten{true}; 110 | bool decap{false}; 111 | 112 | void execute(std::vector args, RTLIL::Design *design) override { 113 | std::size_t argidx{1}; 114 | 115 | for (; argidx < args.size(); ++argidx) { 116 | 117 | if (args[argidx] == "-top" && argidx + 1 < args.size()) { 118 | top_opt = "-top " + args[++argidx]; 119 | continue; 120 | } 121 | 122 | if (args[argidx] == "-json" && argidx + 1 < args.size()) { 123 | json_file = args[++argidx]; 124 | continue; 125 | } 126 | 127 | if (args[argidx] == "-verilog" && argidx + 1 < args.size()) { 128 | vlog_file = args[++argidx]; 129 | continue; 130 | } 131 | 132 | if (args[argidx] == "-kicad" && argidx + 1 < args.size()) { 133 | kicad_file = args[++argidx]; 134 | continue; 135 | } 136 | 137 | if (args[argidx] == "-stats" && argidx + 1 < args.size()) { 138 | stat_file = args[++argidx]; 139 | continue; 140 | } 141 | 142 | if (args[argidx] == "-noflatten") { 143 | flatten = false; 144 | continue; 145 | } 146 | 147 | if (args[argidx] == "-techlib" && argidx + 1 < args.size()) { 148 | techlib_path = args[++argidx]; 149 | continue; 150 | } 151 | 152 | if (args[argidx] == "-dualfet") { 153 | dual_fet = true; 154 | continue; 155 | } 156 | 157 | if (args[argidx] == "-addties") { 158 | add_ties = true; 159 | continue; 160 | } 161 | 162 | if (args[argidx] == "-decap") { 163 | decap = true; 164 | continue; 165 | } 166 | 167 | if (args[argidx] == "-noautoname") { 168 | fixup_names = false; 169 | continue; 170 | } 171 | 172 | if (args[argidx] == "-dff") { 173 | dff_map = false; 174 | continue; 175 | } 176 | 177 | if (args[argidx] == "-mux") { 178 | mux_map = false; 179 | continue; 180 | } 181 | 182 | break; 183 | } 184 | 185 | extra_args(args, argidx, design); 186 | 187 | if (!design->full_selection()) 188 | log_cmd_error("This command only operates on fully selected designs!\n"); 189 | 190 | log_header(design, "Executing SYNTH_DISCRETIZE pass.\n"); 191 | log_push(); 192 | 193 | run_script(design, "", ""); 194 | 195 | log_pop(); 196 | } 197 | 198 | void script() override { 199 | std::string defs{}; 200 | 201 | if (dual_fet) 202 | defs += "-D DUAL_FETS"; 203 | 204 | if (add_ties) 205 | defs += " -D INSERT_TIES"; 206 | 207 | if (decap) 208 | defs += "-D DECAP"; 209 | 210 | if (check_label("begin")) { 211 | run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); 212 | run("proc"); 213 | } 214 | 215 | if (check_label("flatten", "(unless -noflatten)")) { 216 | if (flatten) { 217 | run("flatten"); 218 | run("deminout"); 219 | } 220 | } 221 | 222 | if (check_label("coarse")) { 223 | run("opt"); 224 | run("wreduce"); 225 | run("opt"); 226 | run("opt_merge"); 227 | run("peepopt"); 228 | } 229 | 230 | if (check_label("synth")) { 231 | run("synth -run :fine"); 232 | } 233 | 234 | if (check_label("map_cells")) { 235 | run(stringf("read_verilog %s -lib %s/cells_mod.v", defs.c_str(), techlib_path.c_str())); 236 | run(stringf("read_liberty -lib %s/discretize.lib", techlib_path.c_str())); 237 | run(stringf("techmap %s -map +/techmap.v -map %s/cells_map.v", defs.c_str(), techlib_path.c_str())); 238 | 239 | 240 | if (mux_map) { 241 | run("opt -full -mux_undef -mux_bool"); 242 | if (dff_map) { 243 | run(stringf("techmap %s -map +/techmap.v -map %s/cells_dffe.v", defs.c_str(), techlib_path.c_str())); 244 | } 245 | run("opt"); 246 | run("muxcover -mux4 -mux8"); 247 | run("opt_merge"); 248 | } 249 | 250 | run(stringf("techmap %s -map +/techmap.v -map %s/cells_map.v -map %s/cells_mux.v", defs.c_str(), techlib_path.c_str(), techlib_path.c_str())); 251 | 252 | if (dff_map) { 253 | run(stringf("dfflibmap -liberty %s/discretize.lib", techlib_path.c_str())); 254 | run(stringf("abc -liberty %s/discretize.lib", techlib_path.c_str())); 255 | run("opt -full"); 256 | run("opt_clean -purge"); 257 | } 258 | } 259 | 260 | if (check_label("fixup")) { 261 | run("hilomap -singleton -hicell VCC V -locell GND G"); 262 | if (fixup_names) { 263 | run("autoname"); 264 | } 265 | } 266 | 267 | if (check_label("check")) { 268 | run("stat"); 269 | } 270 | 271 | if (check_label("json")) { 272 | if (!json_file.empty() || help_mode) { 273 | run(stringf("write_json %s", help_mode ? "" : json_file.c_str())); 274 | } 275 | } 276 | 277 | if (check_label("verilog")) { 278 | if (!vlog_file.empty() || help_mode) { 279 | run(stringf("write_verilog -noexpr %s", help_mode ? "" : vlog_file.c_str())); 280 | } 281 | } 282 | 283 | if (check_label("kicad")) { 284 | if (!kicad_file.empty() || help_mode) { 285 | run(stringf("write_kicad %s", help_mode ? "" : kicad_file.c_str())); 286 | } 287 | } 288 | 289 | if (check_label("stat")) { 290 | if (!stat_file.empty() || help_mode) { 291 | run(stringf("tee -q -o %s stat -json", help_mode ? "" : stat_file.c_str())); 292 | } 293 | } 294 | } 295 | 296 | } SynthDiscretizePass; 297 | 298 | PRIVATE_NAMESPACE_END 299 | -------------------------------------------------------------------------------- /src/techlib/synth_discretize.ys: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # This script is used for rapid iteration on the pass 3 | # the proper implementation should go in the `synth_discretize.cc` 4 | # C++ implementation for the Yosys plugin. 5 | 6 | # == Begin == 7 | hierarchy -auto-top 8 | proc 9 | # == Flatten == 10 | flatten 11 | deminout 12 | opt 13 | wreduce 14 | opt 15 | # == Extract == 16 | # extract -map ./techlib/cells_extract.v 17 | opt_merge 18 | # == Misc Opt == 19 | peepopt 20 | # pmux2shiftx 21 | # == Synth == 22 | synth -run :fine 23 | # == Technology Mapping == 24 | read_verilog -lib ./techlib/cells_mod.v 25 | read_liberty -lib ./techlib/discretize.lib 26 | techmap -map +/techmap.v -map ./techlib/cells_map.v 27 | # == Mux/DFF mapping == 28 | # opt -full -mux_undef -mux_bool 29 | # techmap -map +/techmap.v -map ./techlib/cells_dffe.v 30 | # opt 31 | # muxcover -mux4 -mux8 32 | # opt_merge 33 | techmap -map +/techmap.v -map ./techlib/cells_map.v -map ./techlib/cells_mux.v 34 | # dfflibmap -liberty ./techlib/discrete.lib 35 | # abc -liberty ./techlib/discrete.lib 36 | # opt -full 37 | # opt_clean -purge 38 | # == Map VCC and Ground == 39 | hilomap -singleton -hicell VCC V -locell GND G 40 | # == Fixup Names == 41 | autoname 42 | # == Print Stats == 43 | stat 44 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !counter.v 4 | !inverter.v 5 | !picorv32.v 6 | !meson.build 7 | -------------------------------------------------------------------------------- /tests/counter.v: -------------------------------------------------------------------------------- 1 | module counter ( 2 | input rst, 3 | input clk, 4 | output led 5 | 6 | ); 7 | 8 | /* reg */ 9 | reg [7:0] counter = 0; 10 | reg state; 11 | 12 | /* assign */ 13 | assign led = counter[7]; 14 | 15 | /* always */ 16 | always @ (posedge clk) begin 17 | if (!rst) begin 18 | counter <= 8'b0; 19 | end else begin 20 | counter <= counter + 1'b1; 21 | end 22 | end 23 | 24 | endmodule 25 | -------------------------------------------------------------------------------- /tests/inverter.v: -------------------------------------------------------------------------------- 1 | module inverter (A, Y); 2 | input A; 3 | output Y; 4 | 5 | assign Y = ~A; 6 | 7 | endmodule 8 | -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | 3 | yosys = find_program('yosys', required: true) 4 | 5 | 6 | message('Building tests') 7 | 8 | test_srcs = [ 9 | 'counter', 10 | 'inverter', 11 | 'picorv32', 12 | ] 13 | 14 | foreach ex : test_srcs 15 | test(ex, yosys, args: [ 16 | '-m', synth_discretize, 17 | '-p', 'read_verilog @0@/@1@.v'.format(meson.current_source_dir(), ex), 18 | '-p', 'synth_discretize -techlib @0@'.format(meson.project_source_root() / 'src' / 'techlib'), 19 | '-p', 'tee -o @0@/@1@.stat.json stat -json'.format(meson.current_build_dir(), ex), 20 | '-p', 'write_verilog -noexpr @0@/@1@.dmp.v'.format(meson.current_build_dir(), ex), 21 | '-p', 'write_json @0@/@1@.net.json'.format(meson.current_build_dir(), ex) 22 | ], timeout: 300) 23 | endforeach 24 | -------------------------------------------------------------------------------- /tests/picorv32.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoRV32 -- A Small RISC-V (RV32I) Processor Core 3 | * 4 | * Copyright (C) 2015 Claire Xenia Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | /* verilator lint_off WIDTH */ 21 | /* verilator lint_off PINMISSING */ 22 | /* verilator lint_off CASEOVERLAP */ 23 | /* verilator lint_off CASEINCOMPLETE */ 24 | 25 | `timescale 1 ns / 1 ps 26 | // `default_nettype none 27 | // `define DEBUGNETS 28 | // `define DEBUGREGS 29 | // `define DEBUGASM 30 | // `define DEBUG 31 | 32 | `ifdef DEBUG 33 | `define debug(debug_command) debug_command 34 | `else 35 | `define debug(debug_command) 36 | `endif 37 | 38 | `ifdef FORMAL 39 | `define FORMAL_KEEP (* keep *) 40 | `define assert(assert_expr) assert(assert_expr) 41 | `else 42 | `ifdef DEBUGNETS 43 | `define FORMAL_KEEP (* keep *) 44 | `else 45 | `define FORMAL_KEEP 46 | `endif 47 | `define assert(assert_expr) empty_statement 48 | `endif 49 | 50 | // uncomment this for register file in extra module 51 | // `define PICORV32_REGS picorv32_regs 52 | 53 | // this macro can be used to check if the verilog files in your 54 | // design are read in the correct order. 55 | `define PICORV32_V 56 | 57 | 58 | /*************************************************************** 59 | * picorv32 60 | ***************************************************************/ 61 | 62 | module picorv32 #( 63 | parameter [ 0:0] ENABLE_COUNTERS = 1, 64 | parameter [ 0:0] ENABLE_COUNTERS64 = 1, 65 | parameter [ 0:0] ENABLE_REGS_16_31 = 1, 66 | parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, 67 | parameter [ 0:0] LATCHED_MEM_RDATA = 0, 68 | parameter [ 0:0] TWO_STAGE_SHIFT = 1, 69 | parameter [ 0:0] BARREL_SHIFTER = 0, 70 | parameter [ 0:0] TWO_CYCLE_COMPARE = 0, 71 | parameter [ 0:0] TWO_CYCLE_ALU = 0, 72 | parameter [ 0:0] COMPRESSED_ISA = 0, 73 | parameter [ 0:0] CATCH_MISALIGN = 1, 74 | parameter [ 0:0] CATCH_ILLINSN = 1, 75 | parameter [ 0:0] ENABLE_PCPI = 0, 76 | parameter [ 0:0] ENABLE_MUL = 0, 77 | parameter [ 0:0] ENABLE_FAST_MUL = 0, 78 | parameter [ 0:0] ENABLE_DIV = 0, 79 | parameter [ 0:0] ENABLE_IRQ = 0, 80 | parameter [ 0:0] ENABLE_IRQ_QREGS = 1, 81 | parameter [ 0:0] ENABLE_IRQ_TIMER = 1, 82 | parameter [ 0:0] ENABLE_TRACE = 0, 83 | parameter [ 0:0] REGS_INIT_ZERO = 0, 84 | parameter [31:0] MASKED_IRQ = 32'h 0000_0000, 85 | parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, 86 | parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, 87 | parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, 88 | parameter [31:0] STACKADDR = 32'h ffff_ffff 89 | ) ( 90 | input clk, resetn, 91 | output reg trap, 92 | 93 | output reg mem_valid, 94 | output reg mem_instr, 95 | input mem_ready, 96 | 97 | output reg [31:0] mem_addr, 98 | output reg [31:0] mem_wdata, 99 | output reg [ 3:0] mem_wstrb, 100 | input [31:0] mem_rdata, 101 | 102 | // Look-Ahead Interface 103 | output mem_la_read, 104 | output mem_la_write, 105 | output [31:0] mem_la_addr, 106 | output reg [31:0] mem_la_wdata, 107 | output reg [ 3:0] mem_la_wstrb, 108 | 109 | // Pico Co-Processor Interface (PCPI) 110 | output reg pcpi_valid, 111 | output reg [31:0] pcpi_insn, 112 | output [31:0] pcpi_rs1, 113 | output [31:0] pcpi_rs2, 114 | input pcpi_wr, 115 | input [31:0] pcpi_rd, 116 | input pcpi_wait, 117 | input pcpi_ready, 118 | 119 | // IRQ Interface 120 | input [31:0] irq, 121 | output reg [31:0] eoi, 122 | 123 | `ifdef RISCV_FORMAL 124 | output reg rvfi_valid, 125 | output reg [63:0] rvfi_order, 126 | output reg [31:0] rvfi_insn, 127 | output reg rvfi_trap, 128 | output reg rvfi_halt, 129 | output reg rvfi_intr, 130 | output reg [ 1:0] rvfi_mode, 131 | output reg [ 1:0] rvfi_ixl, 132 | output reg [ 4:0] rvfi_rs1_addr, 133 | output reg [ 4:0] rvfi_rs2_addr, 134 | output reg [31:0] rvfi_rs1_rdata, 135 | output reg [31:0] rvfi_rs2_rdata, 136 | output reg [ 4:0] rvfi_rd_addr, 137 | output reg [31:0] rvfi_rd_wdata, 138 | output reg [31:0] rvfi_pc_rdata, 139 | output reg [31:0] rvfi_pc_wdata, 140 | output reg [31:0] rvfi_mem_addr, 141 | output reg [ 3:0] rvfi_mem_rmask, 142 | output reg [ 3:0] rvfi_mem_wmask, 143 | output reg [31:0] rvfi_mem_rdata, 144 | output reg [31:0] rvfi_mem_wdata, 145 | 146 | output reg [63:0] rvfi_csr_mcycle_rmask, 147 | output reg [63:0] rvfi_csr_mcycle_wmask, 148 | output reg [63:0] rvfi_csr_mcycle_rdata, 149 | output reg [63:0] rvfi_csr_mcycle_wdata, 150 | 151 | output reg [63:0] rvfi_csr_minstret_rmask, 152 | output reg [63:0] rvfi_csr_minstret_wmask, 153 | output reg [63:0] rvfi_csr_minstret_rdata, 154 | output reg [63:0] rvfi_csr_minstret_wdata, 155 | `endif 156 | 157 | // Trace Interface 158 | output reg trace_valid, 159 | output reg [35:0] trace_data 160 | ); 161 | localparam integer irq_timer = 0; 162 | localparam integer irq_ebreak = 1; 163 | localparam integer irq_buserror = 2; 164 | 165 | localparam integer irqregs_offset = ENABLE_REGS_16_31 ? 32 : 16; 166 | localparam integer regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ*ENABLE_IRQ_QREGS; 167 | localparam integer regindex_bits = (ENABLE_REGS_16_31 ? 5 : 4) + ENABLE_IRQ*ENABLE_IRQ_QREGS; 168 | 169 | localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL || ENABLE_FAST_MUL || ENABLE_DIV; 170 | 171 | localparam [35:0] TRACE_BRANCH = {4'b 0001, 32'b 0}; 172 | localparam [35:0] TRACE_ADDR = {4'b 0010, 32'b 0}; 173 | localparam [35:0] TRACE_IRQ = {4'b 1000, 32'b 0}; 174 | 175 | reg [63:0] count_cycle, count_instr; 176 | reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out; 177 | reg [4:0] reg_sh; 178 | 179 | reg [31:0] next_insn_opcode; 180 | reg [31:0] dbg_insn_opcode; 181 | reg [31:0] dbg_insn_addr; 182 | 183 | wire dbg_mem_valid = mem_valid; 184 | wire dbg_mem_instr = mem_instr; 185 | wire dbg_mem_ready = mem_ready; 186 | wire [31:0] dbg_mem_addr = mem_addr; 187 | wire [31:0] dbg_mem_wdata = mem_wdata; 188 | wire [ 3:0] dbg_mem_wstrb = mem_wstrb; 189 | wire [31:0] dbg_mem_rdata = mem_rdata; 190 | 191 | assign pcpi_rs1 = reg_op1; 192 | assign pcpi_rs2 = reg_op2; 193 | 194 | wire [31:0] next_pc; 195 | 196 | reg irq_delay; 197 | reg irq_active; 198 | reg [31:0] irq_mask; 199 | reg [31:0] irq_pending; 200 | reg [31:0] timer; 201 | 202 | `ifndef PICORV32_REGS 203 | reg [31:0] cpuregs [0:regfile_size-1]; 204 | 205 | integer i; 206 | initial begin 207 | if (REGS_INIT_ZERO) begin 208 | for (i = 0; i < regfile_size; i = i+1) 209 | cpuregs[i] = 0; 210 | end 211 | end 212 | `endif 213 | 214 | task empty_statement; 215 | // This task is used by the `assert directive in non-formal mode to 216 | // avoid empty statement (which are unsupported by plain Verilog syntax). 217 | begin end 218 | endtask 219 | 220 | `ifdef DEBUGREGS 221 | wire [31:0] dbg_reg_x0 = 0; 222 | wire [31:0] dbg_reg_x1 = cpuregs[1]; 223 | wire [31:0] dbg_reg_x2 = cpuregs[2]; 224 | wire [31:0] dbg_reg_x3 = cpuregs[3]; 225 | wire [31:0] dbg_reg_x4 = cpuregs[4]; 226 | wire [31:0] dbg_reg_x5 = cpuregs[5]; 227 | wire [31:0] dbg_reg_x6 = cpuregs[6]; 228 | wire [31:0] dbg_reg_x7 = cpuregs[7]; 229 | wire [31:0] dbg_reg_x8 = cpuregs[8]; 230 | wire [31:0] dbg_reg_x9 = cpuregs[9]; 231 | wire [31:0] dbg_reg_x10 = cpuregs[10]; 232 | wire [31:0] dbg_reg_x11 = cpuregs[11]; 233 | wire [31:0] dbg_reg_x12 = cpuregs[12]; 234 | wire [31:0] dbg_reg_x13 = cpuregs[13]; 235 | wire [31:0] dbg_reg_x14 = cpuregs[14]; 236 | wire [31:0] dbg_reg_x15 = cpuregs[15]; 237 | wire [31:0] dbg_reg_x16 = cpuregs[16]; 238 | wire [31:0] dbg_reg_x17 = cpuregs[17]; 239 | wire [31:0] dbg_reg_x18 = cpuregs[18]; 240 | wire [31:0] dbg_reg_x19 = cpuregs[19]; 241 | wire [31:0] dbg_reg_x20 = cpuregs[20]; 242 | wire [31:0] dbg_reg_x21 = cpuregs[21]; 243 | wire [31:0] dbg_reg_x22 = cpuregs[22]; 244 | wire [31:0] dbg_reg_x23 = cpuregs[23]; 245 | wire [31:0] dbg_reg_x24 = cpuregs[24]; 246 | wire [31:0] dbg_reg_x25 = cpuregs[25]; 247 | wire [31:0] dbg_reg_x26 = cpuregs[26]; 248 | wire [31:0] dbg_reg_x27 = cpuregs[27]; 249 | wire [31:0] dbg_reg_x28 = cpuregs[28]; 250 | wire [31:0] dbg_reg_x29 = cpuregs[29]; 251 | wire [31:0] dbg_reg_x30 = cpuregs[30]; 252 | wire [31:0] dbg_reg_x31 = cpuregs[31]; 253 | `endif 254 | 255 | // Internal PCPI Cores 256 | 257 | wire pcpi_mul_wr; 258 | wire [31:0] pcpi_mul_rd; 259 | wire pcpi_mul_wait; 260 | wire pcpi_mul_ready; 261 | 262 | wire pcpi_div_wr; 263 | wire [31:0] pcpi_div_rd; 264 | wire pcpi_div_wait; 265 | wire pcpi_div_ready; 266 | 267 | reg pcpi_int_wr; 268 | reg [31:0] pcpi_int_rd; 269 | reg pcpi_int_wait; 270 | reg pcpi_int_ready; 271 | 272 | generate if (ENABLE_FAST_MUL) begin 273 | picorv32_pcpi_fast_mul pcpi_mul ( 274 | .clk (clk ), 275 | .resetn (resetn ), 276 | .pcpi_valid(pcpi_valid ), 277 | .pcpi_insn (pcpi_insn ), 278 | .pcpi_rs1 (pcpi_rs1 ), 279 | .pcpi_rs2 (pcpi_rs2 ), 280 | .pcpi_wr (pcpi_mul_wr ), 281 | .pcpi_rd (pcpi_mul_rd ), 282 | .pcpi_wait (pcpi_mul_wait ), 283 | .pcpi_ready(pcpi_mul_ready ) 284 | ); 285 | end else if (ENABLE_MUL) begin 286 | picorv32_pcpi_mul pcpi_mul ( 287 | .clk (clk ), 288 | .resetn (resetn ), 289 | .pcpi_valid(pcpi_valid ), 290 | .pcpi_insn (pcpi_insn ), 291 | .pcpi_rs1 (pcpi_rs1 ), 292 | .pcpi_rs2 (pcpi_rs2 ), 293 | .pcpi_wr (pcpi_mul_wr ), 294 | .pcpi_rd (pcpi_mul_rd ), 295 | .pcpi_wait (pcpi_mul_wait ), 296 | .pcpi_ready(pcpi_mul_ready ) 297 | ); 298 | end else begin 299 | assign pcpi_mul_wr = 0; 300 | assign pcpi_mul_rd = 32'bx; 301 | assign pcpi_mul_wait = 0; 302 | assign pcpi_mul_ready = 0; 303 | end endgenerate 304 | 305 | generate if (ENABLE_DIV) begin 306 | picorv32_pcpi_div pcpi_div ( 307 | .clk (clk ), 308 | .resetn (resetn ), 309 | .pcpi_valid(pcpi_valid ), 310 | .pcpi_insn (pcpi_insn ), 311 | .pcpi_rs1 (pcpi_rs1 ), 312 | .pcpi_rs2 (pcpi_rs2 ), 313 | .pcpi_wr (pcpi_div_wr ), 314 | .pcpi_rd (pcpi_div_rd ), 315 | .pcpi_wait (pcpi_div_wait ), 316 | .pcpi_ready(pcpi_div_ready ) 317 | ); 318 | end else begin 319 | assign pcpi_div_wr = 0; 320 | assign pcpi_div_rd = 32'bx; 321 | assign pcpi_div_wait = 0; 322 | assign pcpi_div_ready = 0; 323 | end endgenerate 324 | 325 | always @* begin 326 | pcpi_int_wr = 0; 327 | pcpi_int_rd = 32'bx; 328 | pcpi_int_wait = |{ENABLE_PCPI && pcpi_wait, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_wait, ENABLE_DIV && pcpi_div_wait}; 329 | pcpi_int_ready = |{ENABLE_PCPI && pcpi_ready, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready, ENABLE_DIV && pcpi_div_ready}; 330 | 331 | (* parallel_case *) 332 | case (1'b1) 333 | ENABLE_PCPI && pcpi_ready: begin 334 | pcpi_int_wr = ENABLE_PCPI ? pcpi_wr : 0; 335 | pcpi_int_rd = ENABLE_PCPI ? pcpi_rd : 0; 336 | end 337 | (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready: begin 338 | pcpi_int_wr = pcpi_mul_wr; 339 | pcpi_int_rd = pcpi_mul_rd; 340 | end 341 | ENABLE_DIV && pcpi_div_ready: begin 342 | pcpi_int_wr = pcpi_div_wr; 343 | pcpi_int_rd = pcpi_div_rd; 344 | end 345 | endcase 346 | end 347 | 348 | 349 | // Memory Interface 350 | 351 | reg [1:0] mem_state; 352 | reg [1:0] mem_wordsize; 353 | reg [31:0] mem_rdata_word; 354 | reg [31:0] mem_rdata_q; 355 | reg mem_do_prefetch; 356 | reg mem_do_rinst; 357 | reg mem_do_rdata; 358 | reg mem_do_wdata; 359 | 360 | wire mem_xfer; 361 | reg mem_la_secondword, mem_la_firstword_reg, last_mem_valid; 362 | wire mem_la_firstword = COMPRESSED_ISA && (mem_do_prefetch || mem_do_rinst) && next_pc[1] && !mem_la_secondword; 363 | wire mem_la_firstword_xfer = COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg); 364 | 365 | reg prefetched_high_word; 366 | reg clear_prefetched_high_word; 367 | reg [15:0] mem_16bit_buffer; 368 | 369 | wire [31:0] mem_rdata_latched_noshuffle; 370 | wire [31:0] mem_rdata_latched; 371 | 372 | wire mem_la_use_prefetched_high_word = COMPRESSED_ISA && mem_la_firstword && prefetched_high_word && !clear_prefetched_high_word; 373 | assign mem_xfer = (mem_valid && mem_ready) || (mem_la_use_prefetched_high_word && mem_do_rinst); 374 | 375 | wire mem_busy = |{mem_do_prefetch, mem_do_rinst, mem_do_rdata, mem_do_wdata}; 376 | wire mem_done = resetn && ((mem_xfer && |mem_state && (mem_do_rinst || mem_do_rdata || mem_do_wdata)) || (&mem_state && mem_do_rinst)) && 377 | (!mem_la_firstword || (~&mem_rdata_latched[1:0] && mem_xfer)); 378 | 379 | assign mem_la_write = resetn && !mem_state && mem_do_wdata; 380 | assign mem_la_read = resetn && ((!mem_la_use_prefetched_high_word && !mem_state && (mem_do_rinst || mem_do_prefetch || mem_do_rdata)) || 381 | (COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg) && !mem_la_secondword && &mem_rdata_latched[1:0])); 382 | assign mem_la_addr = (mem_do_prefetch || mem_do_rinst) ? {next_pc[31:2] + mem_la_firstword_xfer, 2'b00} : {reg_op1[31:2], 2'b00}; 383 | 384 | assign mem_rdata_latched_noshuffle = (mem_xfer || LATCHED_MEM_RDATA) ? mem_rdata : mem_rdata_q; 385 | 386 | assign mem_rdata_latched = COMPRESSED_ISA && mem_la_use_prefetched_high_word ? {16'bx, mem_16bit_buffer} : 387 | COMPRESSED_ISA && mem_la_secondword ? {mem_rdata_latched_noshuffle[15:0], mem_16bit_buffer} : 388 | COMPRESSED_ISA && mem_la_firstword ? {16'bx, mem_rdata_latched_noshuffle[31:16]} : mem_rdata_latched_noshuffle; 389 | 390 | always @(posedge clk) begin 391 | if (!resetn) begin 392 | mem_la_firstword_reg <= 0; 393 | last_mem_valid <= 0; 394 | end else begin 395 | if (!last_mem_valid) 396 | mem_la_firstword_reg <= mem_la_firstword; 397 | last_mem_valid <= mem_valid && !mem_ready; 398 | end 399 | end 400 | 401 | always @* begin 402 | (* full_case *) 403 | case (mem_wordsize) 404 | 0: begin 405 | mem_la_wdata = reg_op2; 406 | mem_la_wstrb = 4'b1111; 407 | mem_rdata_word = mem_rdata; 408 | end 409 | 1: begin 410 | mem_la_wdata = {2{reg_op2[15:0]}}; 411 | mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011; 412 | case (reg_op1[1]) 413 | 1'b0: mem_rdata_word = {16'b0, mem_rdata[15: 0]}; 414 | 1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]}; 415 | endcase 416 | end 417 | 2: begin 418 | mem_la_wdata = {4{reg_op2[7:0]}}; 419 | mem_la_wstrb = 4'b0001 << reg_op1[1:0]; 420 | case (reg_op1[1:0]) 421 | 2'b00: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]}; 422 | 2'b01: mem_rdata_word = {24'b0, mem_rdata[15: 8]}; 423 | 2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]}; 424 | 2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]}; 425 | endcase 426 | end 427 | endcase 428 | end 429 | 430 | always @(posedge clk) begin 431 | if (mem_xfer) begin 432 | mem_rdata_q <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; 433 | next_insn_opcode <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; 434 | end 435 | 436 | if (COMPRESSED_ISA && mem_done && (mem_do_prefetch || mem_do_rinst)) begin 437 | case (mem_rdata_latched[1:0]) 438 | 2'b00: begin // Quadrant 0 439 | case (mem_rdata_latched[15:13]) 440 | 3'b000: begin // C.ADDI4SPN 441 | mem_rdata_q[14:12] <= 3'b000; 442 | mem_rdata_q[31:20] <= {2'b0, mem_rdata_latched[10:7], mem_rdata_latched[12:11], mem_rdata_latched[5], mem_rdata_latched[6], 2'b00}; 443 | end 444 | 3'b010: begin // C.LW 445 | mem_rdata_q[31:20] <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00}; 446 | mem_rdata_q[14:12] <= 3'b 010; 447 | end 448 | 3'b 110: begin // C.SW 449 | {mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00}; 450 | mem_rdata_q[14:12] <= 3'b 010; 451 | end 452 | endcase 453 | end 454 | 2'b01: begin // Quadrant 1 455 | case (mem_rdata_latched[15:13]) 456 | 3'b 000: begin // C.ADDI 457 | mem_rdata_q[14:12] <= 3'b000; 458 | mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); 459 | end 460 | 3'b 010: begin // C.LI 461 | mem_rdata_q[14:12] <= 3'b000; 462 | mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); 463 | end 464 | 3'b 011: begin 465 | if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP 466 | mem_rdata_q[14:12] <= 3'b000; 467 | mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[4:3], 468 | mem_rdata_latched[5], mem_rdata_latched[2], mem_rdata_latched[6], 4'b 0000}); 469 | end else begin // C.LUI 470 | mem_rdata_q[31:12] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); 471 | end 472 | end 473 | 3'b100: begin 474 | if (mem_rdata_latched[11:10] == 2'b00) begin // C.SRLI 475 | mem_rdata_q[31:25] <= 7'b0000000; 476 | mem_rdata_q[14:12] <= 3'b 101; 477 | end 478 | if (mem_rdata_latched[11:10] == 2'b01) begin // C.SRAI 479 | mem_rdata_q[31:25] <= 7'b0100000; 480 | mem_rdata_q[14:12] <= 3'b 101; 481 | end 482 | if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI 483 | mem_rdata_q[14:12] <= 3'b111; 484 | mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); 485 | end 486 | if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND 487 | if (mem_rdata_latched[6:5] == 2'b00) mem_rdata_q[14:12] <= 3'b000; 488 | if (mem_rdata_latched[6:5] == 2'b01) mem_rdata_q[14:12] <= 3'b100; 489 | if (mem_rdata_latched[6:5] == 2'b10) mem_rdata_q[14:12] <= 3'b110; 490 | if (mem_rdata_latched[6:5] == 2'b11) mem_rdata_q[14:12] <= 3'b111; 491 | mem_rdata_q[31:25] <= mem_rdata_latched[6:5] == 2'b00 ? 7'b0100000 : 7'b0000000; 492 | end 493 | end 494 | 3'b 110: begin // C.BEQZ 495 | mem_rdata_q[14:12] <= 3'b000; 496 | { mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <= 497 | $signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2], 498 | mem_rdata_latched[11:10], mem_rdata_latched[4:3]}); 499 | end 500 | 3'b 111: begin // C.BNEZ 501 | mem_rdata_q[14:12] <= 3'b001; 502 | { mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <= 503 | $signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2], 504 | mem_rdata_latched[11:10], mem_rdata_latched[4:3]}); 505 | end 506 | endcase 507 | end 508 | 2'b10: begin // Quadrant 2 509 | case (mem_rdata_latched[15:13]) 510 | 3'b000: begin // C.SLLI 511 | mem_rdata_q[31:25] <= 7'b0000000; 512 | mem_rdata_q[14:12] <= 3'b 001; 513 | end 514 | 3'b010: begin // C.LWSP 515 | mem_rdata_q[31:20] <= {4'b0, mem_rdata_latched[3:2], mem_rdata_latched[12], mem_rdata_latched[6:4], 2'b00}; 516 | mem_rdata_q[14:12] <= 3'b 010; 517 | end 518 | 3'b100: begin 519 | if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] == 0) begin // C.JR 520 | mem_rdata_q[14:12] <= 3'b000; 521 | mem_rdata_q[31:20] <= 12'b0; 522 | end 523 | if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV 524 | mem_rdata_q[14:12] <= 3'b000; 525 | mem_rdata_q[31:25] <= 7'b0000000; 526 | end 527 | if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR 528 | mem_rdata_q[14:12] <= 3'b000; 529 | mem_rdata_q[31:20] <= 12'b0; 530 | end 531 | if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD 532 | mem_rdata_q[14:12] <= 3'b000; 533 | mem_rdata_q[31:25] <= 7'b0000000; 534 | end 535 | end 536 | 3'b110: begin // C.SWSP 537 | {mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {4'b0, mem_rdata_latched[8:7], mem_rdata_latched[12:9], 2'b00}; 538 | mem_rdata_q[14:12] <= 3'b 010; 539 | end 540 | endcase 541 | end 542 | endcase 543 | end 544 | end 545 | 546 | always @(posedge clk) begin 547 | if (resetn && !trap) begin 548 | if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) 549 | `assert(!mem_do_wdata); 550 | 551 | if (mem_do_prefetch || mem_do_rinst) 552 | `assert(!mem_do_rdata); 553 | 554 | if (mem_do_rdata) 555 | `assert(!mem_do_prefetch && !mem_do_rinst); 556 | 557 | if (mem_do_wdata) 558 | `assert(!(mem_do_prefetch || mem_do_rinst || mem_do_rdata)); 559 | 560 | if (mem_state == 2 || mem_state == 3) 561 | `assert(mem_valid || mem_do_prefetch); 562 | end 563 | end 564 | 565 | always @(posedge clk) begin 566 | if (!resetn || trap) begin 567 | if (!resetn) 568 | mem_state <= 0; 569 | if (!resetn || mem_ready) 570 | mem_valid <= 0; 571 | mem_la_secondword <= 0; 572 | prefetched_high_word <= 0; 573 | end else begin 574 | if (mem_la_read || mem_la_write) begin 575 | mem_addr <= mem_la_addr; 576 | mem_wstrb <= mem_la_wstrb & {4{mem_la_write}}; 577 | end 578 | if (mem_la_write) begin 579 | mem_wdata <= mem_la_wdata; 580 | end 581 | case (mem_state) 582 | 0: begin 583 | if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) begin 584 | mem_valid <= !mem_la_use_prefetched_high_word; 585 | mem_instr <= mem_do_prefetch || mem_do_rinst; 586 | mem_wstrb <= 0; 587 | mem_state <= 1; 588 | end 589 | if (mem_do_wdata) begin 590 | mem_valid <= 1; 591 | mem_instr <= 0; 592 | mem_state <= 2; 593 | end 594 | end 595 | 1: begin 596 | `assert(mem_wstrb == 0); 597 | `assert(mem_do_prefetch || mem_do_rinst || mem_do_rdata); 598 | `assert(mem_valid == !mem_la_use_prefetched_high_word); 599 | `assert(mem_instr == (mem_do_prefetch || mem_do_rinst)); 600 | if (mem_xfer) begin 601 | if (COMPRESSED_ISA && mem_la_read) begin 602 | mem_valid <= 1; 603 | mem_la_secondword <= 1; 604 | if (!mem_la_use_prefetched_high_word) 605 | mem_16bit_buffer <= mem_rdata[31:16]; 606 | end else begin 607 | mem_valid <= 0; 608 | mem_la_secondword <= 0; 609 | if (COMPRESSED_ISA && !mem_do_rdata) begin 610 | if (~&mem_rdata[1:0] || mem_la_secondword) begin 611 | mem_16bit_buffer <= mem_rdata[31:16]; 612 | prefetched_high_word <= 1; 613 | end else begin 614 | prefetched_high_word <= 0; 615 | end 616 | end 617 | mem_state <= mem_do_rinst || mem_do_rdata ? 0 : 3; 618 | end 619 | end 620 | end 621 | 2: begin 622 | `assert(mem_wstrb != 0); 623 | `assert(mem_do_wdata); 624 | if (mem_xfer) begin 625 | mem_valid <= 0; 626 | mem_state <= 0; 627 | end 628 | end 629 | 3: begin 630 | `assert(mem_wstrb == 0); 631 | `assert(mem_do_prefetch); 632 | if (mem_do_rinst) begin 633 | mem_state <= 0; 634 | end 635 | end 636 | endcase 637 | end 638 | 639 | if (clear_prefetched_high_word) 640 | prefetched_high_word <= 0; 641 | end 642 | 643 | 644 | // Instruction Decoder 645 | 646 | reg instr_lui, instr_auipc, instr_jal, instr_jalr; 647 | reg instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu; 648 | reg instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw; 649 | reg instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai; 650 | reg instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and; 651 | reg instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, instr_ecall_ebreak; 652 | reg instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer; 653 | wire instr_trap; 654 | 655 | reg [regindex_bits-1:0] decoded_rd, decoded_rs1, decoded_rs2; 656 | reg [31:0] decoded_imm, decoded_imm_j; 657 | reg decoder_trigger; 658 | reg decoder_trigger_q; 659 | reg decoder_pseudo_trigger; 660 | reg decoder_pseudo_trigger_q; 661 | reg compressed_instr; 662 | 663 | reg is_lui_auipc_jal; 664 | reg is_lb_lh_lw_lbu_lhu; 665 | reg is_slli_srli_srai; 666 | reg is_jalr_addi_slti_sltiu_xori_ori_andi; 667 | reg is_sb_sh_sw; 668 | reg is_sll_srl_sra; 669 | reg is_lui_auipc_jal_jalr_addi_add_sub; 670 | reg is_slti_blt_slt; 671 | reg is_sltiu_bltu_sltu; 672 | reg is_beq_bne_blt_bge_bltu_bgeu; 673 | reg is_lbu_lhu_lw; 674 | reg is_alu_reg_imm; 675 | reg is_alu_reg_reg; 676 | reg is_compare; 677 | 678 | assign instr_trap = (CATCH_ILLINSN || WITH_PCPI) && !{instr_lui, instr_auipc, instr_jal, instr_jalr, 679 | instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu, 680 | instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw, 681 | instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai, 682 | instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and, 683 | instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, 684 | instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer}; 685 | 686 | wire is_rdcycle_rdcycleh_rdinstr_rdinstrh; 687 | assign is_rdcycle_rdcycleh_rdinstr_rdinstrh = |{instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh}; 688 | 689 | reg [63:0] new_ascii_instr; 690 | `FORMAL_KEEP reg [63:0] dbg_ascii_instr; 691 | `FORMAL_KEEP reg [31:0] dbg_insn_imm; 692 | `FORMAL_KEEP reg [4:0] dbg_insn_rs1; 693 | `FORMAL_KEEP reg [4:0] dbg_insn_rs2; 694 | `FORMAL_KEEP reg [4:0] dbg_insn_rd; 695 | `FORMAL_KEEP reg [31:0] dbg_rs1val; 696 | `FORMAL_KEEP reg [31:0] dbg_rs2val; 697 | `FORMAL_KEEP reg dbg_rs1val_valid; 698 | `FORMAL_KEEP reg dbg_rs2val_valid; 699 | 700 | always @* begin 701 | new_ascii_instr = ""; 702 | 703 | if (instr_lui) new_ascii_instr = "lui"; 704 | if (instr_auipc) new_ascii_instr = "auipc"; 705 | if (instr_jal) new_ascii_instr = "jal"; 706 | if (instr_jalr) new_ascii_instr = "jalr"; 707 | 708 | if (instr_beq) new_ascii_instr = "beq"; 709 | if (instr_bne) new_ascii_instr = "bne"; 710 | if (instr_blt) new_ascii_instr = "blt"; 711 | if (instr_bge) new_ascii_instr = "bge"; 712 | if (instr_bltu) new_ascii_instr = "bltu"; 713 | if (instr_bgeu) new_ascii_instr = "bgeu"; 714 | 715 | if (instr_lb) new_ascii_instr = "lb"; 716 | if (instr_lh) new_ascii_instr = "lh"; 717 | if (instr_lw) new_ascii_instr = "lw"; 718 | if (instr_lbu) new_ascii_instr = "lbu"; 719 | if (instr_lhu) new_ascii_instr = "lhu"; 720 | if (instr_sb) new_ascii_instr = "sb"; 721 | if (instr_sh) new_ascii_instr = "sh"; 722 | if (instr_sw) new_ascii_instr = "sw"; 723 | 724 | if (instr_addi) new_ascii_instr = "addi"; 725 | if (instr_slti) new_ascii_instr = "slti"; 726 | if (instr_sltiu) new_ascii_instr = "sltiu"; 727 | if (instr_xori) new_ascii_instr = "xori"; 728 | if (instr_ori) new_ascii_instr = "ori"; 729 | if (instr_andi) new_ascii_instr = "andi"; 730 | if (instr_slli) new_ascii_instr = "slli"; 731 | if (instr_srli) new_ascii_instr = "srli"; 732 | if (instr_srai) new_ascii_instr = "srai"; 733 | 734 | if (instr_add) new_ascii_instr = "add"; 735 | if (instr_sub) new_ascii_instr = "sub"; 736 | if (instr_sll) new_ascii_instr = "sll"; 737 | if (instr_slt) new_ascii_instr = "slt"; 738 | if (instr_sltu) new_ascii_instr = "sltu"; 739 | if (instr_xor) new_ascii_instr = "xor"; 740 | if (instr_srl) new_ascii_instr = "srl"; 741 | if (instr_sra) new_ascii_instr = "sra"; 742 | if (instr_or) new_ascii_instr = "or"; 743 | if (instr_and) new_ascii_instr = "and"; 744 | 745 | if (instr_rdcycle) new_ascii_instr = "rdcycle"; 746 | if (instr_rdcycleh) new_ascii_instr = "rdcycleh"; 747 | if (instr_rdinstr) new_ascii_instr = "rdinstr"; 748 | if (instr_rdinstrh) new_ascii_instr = "rdinstrh"; 749 | 750 | if (instr_getq) new_ascii_instr = "getq"; 751 | if (instr_setq) new_ascii_instr = "setq"; 752 | if (instr_retirq) new_ascii_instr = "retirq"; 753 | if (instr_maskirq) new_ascii_instr = "maskirq"; 754 | if (instr_waitirq) new_ascii_instr = "waitirq"; 755 | if (instr_timer) new_ascii_instr = "timer"; 756 | end 757 | 758 | reg [63:0] q_ascii_instr; 759 | reg [31:0] q_insn_imm; 760 | reg [31:0] q_insn_opcode; 761 | reg [4:0] q_insn_rs1; 762 | reg [4:0] q_insn_rs2; 763 | reg [4:0] q_insn_rd; 764 | reg dbg_next; 765 | 766 | wire launch_next_insn; 767 | reg dbg_valid_insn; 768 | 769 | reg [63:0] cached_ascii_instr; 770 | reg [31:0] cached_insn_imm; 771 | reg [31:0] cached_insn_opcode; 772 | reg [4:0] cached_insn_rs1; 773 | reg [4:0] cached_insn_rs2; 774 | reg [4:0] cached_insn_rd; 775 | 776 | always @(posedge clk) begin 777 | q_ascii_instr <= dbg_ascii_instr; 778 | q_insn_imm <= dbg_insn_imm; 779 | q_insn_opcode <= dbg_insn_opcode; 780 | q_insn_rs1 <= dbg_insn_rs1; 781 | q_insn_rs2 <= dbg_insn_rs2; 782 | q_insn_rd <= dbg_insn_rd; 783 | dbg_next <= launch_next_insn; 784 | 785 | if (!resetn || trap) 786 | dbg_valid_insn <= 0; 787 | else if (launch_next_insn) 788 | dbg_valid_insn <= 1; 789 | 790 | if (decoder_trigger_q) begin 791 | cached_ascii_instr <= new_ascii_instr; 792 | cached_insn_imm <= decoded_imm; 793 | if (&next_insn_opcode[1:0]) 794 | cached_insn_opcode <= next_insn_opcode; 795 | else 796 | cached_insn_opcode <= {16'b0, next_insn_opcode[15:0]}; 797 | cached_insn_rs1 <= decoded_rs1; 798 | cached_insn_rs2 <= decoded_rs2; 799 | cached_insn_rd <= decoded_rd; 800 | end 801 | 802 | if (launch_next_insn) begin 803 | dbg_insn_addr <= next_pc; 804 | end 805 | end 806 | 807 | always @* begin 808 | dbg_ascii_instr = q_ascii_instr; 809 | dbg_insn_imm = q_insn_imm; 810 | dbg_insn_opcode = q_insn_opcode; 811 | dbg_insn_rs1 = q_insn_rs1; 812 | dbg_insn_rs2 = q_insn_rs2; 813 | dbg_insn_rd = q_insn_rd; 814 | 815 | if (dbg_next) begin 816 | if (decoder_pseudo_trigger_q) begin 817 | dbg_ascii_instr = cached_ascii_instr; 818 | dbg_insn_imm = cached_insn_imm; 819 | dbg_insn_opcode = cached_insn_opcode; 820 | dbg_insn_rs1 = cached_insn_rs1; 821 | dbg_insn_rs2 = cached_insn_rs2; 822 | dbg_insn_rd = cached_insn_rd; 823 | end else begin 824 | dbg_ascii_instr = new_ascii_instr; 825 | if (&next_insn_opcode[1:0]) 826 | dbg_insn_opcode = next_insn_opcode; 827 | else 828 | dbg_insn_opcode = {16'b0, next_insn_opcode[15:0]}; 829 | dbg_insn_imm = decoded_imm; 830 | dbg_insn_rs1 = decoded_rs1; 831 | dbg_insn_rs2 = decoded_rs2; 832 | dbg_insn_rd = decoded_rd; 833 | end 834 | end 835 | end 836 | 837 | `ifdef DEBUGASM 838 | always @(posedge clk) begin 839 | if (dbg_next) begin 840 | $display("debugasm %x %x %s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "*"); 841 | end 842 | end 843 | `endif 844 | 845 | `ifdef DEBUG 846 | always @(posedge clk) begin 847 | if (dbg_next) begin 848 | if (&dbg_insn_opcode[1:0]) 849 | $display("DECODE: 0x%08x 0x%08x %-0s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"); 850 | else 851 | $display("DECODE: 0x%08x 0x%04x %-0s", dbg_insn_addr, dbg_insn_opcode[15:0], dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"); 852 | end 853 | end 854 | `endif 855 | 856 | always @(posedge clk) begin 857 | is_lui_auipc_jal <= |{instr_lui, instr_auipc, instr_jal}; 858 | is_lui_auipc_jal_jalr_addi_add_sub <= |{instr_lui, instr_auipc, instr_jal, instr_jalr, instr_addi, instr_add, instr_sub}; 859 | is_slti_blt_slt <= |{instr_slti, instr_blt, instr_slt}; 860 | is_sltiu_bltu_sltu <= |{instr_sltiu, instr_bltu, instr_sltu}; 861 | is_lbu_lhu_lw <= |{instr_lbu, instr_lhu, instr_lw}; 862 | is_compare <= |{is_beq_bne_blt_bge_bltu_bgeu, instr_slti, instr_slt, instr_sltiu, instr_sltu}; 863 | 864 | if (mem_do_rinst && mem_done) begin 865 | instr_lui <= mem_rdata_latched[6:0] == 7'b0110111; 866 | instr_auipc <= mem_rdata_latched[6:0] == 7'b0010111; 867 | instr_jal <= mem_rdata_latched[6:0] == 7'b1101111; 868 | instr_jalr <= mem_rdata_latched[6:0] == 7'b1100111 && mem_rdata_latched[14:12] == 3'b000; 869 | instr_retirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ; 870 | instr_waitirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000100 && ENABLE_IRQ; 871 | 872 | is_beq_bne_blt_bge_bltu_bgeu <= mem_rdata_latched[6:0] == 7'b1100011; 873 | is_lb_lh_lw_lbu_lhu <= mem_rdata_latched[6:0] == 7'b0000011; 874 | is_sb_sh_sw <= mem_rdata_latched[6:0] == 7'b0100011; 875 | is_alu_reg_imm <= mem_rdata_latched[6:0] == 7'b0010011; 876 | is_alu_reg_reg <= mem_rdata_latched[6:0] == 7'b0110011; 877 | 878 | { decoded_imm_j[31:20], decoded_imm_j[10:1], decoded_imm_j[11], decoded_imm_j[19:12], decoded_imm_j[0] } <= $signed({mem_rdata_latched[31:12], 1'b0}); 879 | 880 | decoded_rd <= mem_rdata_latched[11:7]; 881 | decoded_rs1 <= mem_rdata_latched[19:15]; 882 | decoded_rs2 <= mem_rdata_latched[24:20]; 883 | 884 | if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS) 885 | decoded_rs1[regindex_bits-1] <= 1; // instr_getq 886 | 887 | if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ) 888 | decoded_rs1 <= ENABLE_IRQ_QREGS ? irqregs_offset : 3; // instr_retirq 889 | 890 | compressed_instr <= 0; 891 | if (COMPRESSED_ISA && mem_rdata_latched[1:0] != 2'b11) begin 892 | compressed_instr <= 1; 893 | decoded_rd <= 0; 894 | decoded_rs1 <= 0; 895 | decoded_rs2 <= 0; 896 | 897 | { decoded_imm_j[31:11], decoded_imm_j[4], decoded_imm_j[9:8], decoded_imm_j[10], decoded_imm_j[6], 898 | decoded_imm_j[7], decoded_imm_j[3:1], decoded_imm_j[5], decoded_imm_j[0] } <= $signed({mem_rdata_latched[12:2], 1'b0}); 899 | 900 | case (mem_rdata_latched[1:0]) 901 | 2'b00: begin // Quadrant 0 902 | case (mem_rdata_latched[15:13]) 903 | 3'b000: begin // C.ADDI4SPN 904 | is_alu_reg_imm <= |mem_rdata_latched[12:5]; 905 | decoded_rs1 <= 2; 906 | decoded_rd <= 8 + mem_rdata_latched[4:2]; 907 | end 908 | 3'b010: begin // C.LW 909 | is_lb_lh_lw_lbu_lhu <= 1; 910 | decoded_rs1 <= 8 + mem_rdata_latched[9:7]; 911 | decoded_rd <= 8 + mem_rdata_latched[4:2]; 912 | end 913 | 3'b110: begin // C.SW 914 | is_sb_sh_sw <= 1; 915 | decoded_rs1 <= 8 + mem_rdata_latched[9:7]; 916 | decoded_rs2 <= 8 + mem_rdata_latched[4:2]; 917 | end 918 | endcase 919 | end 920 | 2'b01: begin // Quadrant 1 921 | case (mem_rdata_latched[15:13]) 922 | 3'b000: begin // C.NOP / C.ADDI 923 | is_alu_reg_imm <= 1; 924 | decoded_rd <= mem_rdata_latched[11:7]; 925 | decoded_rs1 <= mem_rdata_latched[11:7]; 926 | end 927 | 3'b001: begin // C.JAL 928 | instr_jal <= 1; 929 | decoded_rd <= 1; 930 | end 931 | 3'b 010: begin // C.LI 932 | is_alu_reg_imm <= 1; 933 | decoded_rd <= mem_rdata_latched[11:7]; 934 | decoded_rs1 <= 0; 935 | end 936 | 3'b 011: begin 937 | if (mem_rdata_latched[12] || mem_rdata_latched[6:2]) begin 938 | if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP 939 | is_alu_reg_imm <= 1; 940 | decoded_rd <= mem_rdata_latched[11:7]; 941 | decoded_rs1 <= mem_rdata_latched[11:7]; 942 | end else begin // C.LUI 943 | instr_lui <= 1; 944 | decoded_rd <= mem_rdata_latched[11:7]; 945 | decoded_rs1 <= 0; 946 | end 947 | end 948 | end 949 | 3'b100: begin 950 | if (!mem_rdata_latched[11] && !mem_rdata_latched[12]) begin // C.SRLI, C.SRAI 951 | is_alu_reg_imm <= 1; 952 | decoded_rd <= 8 + mem_rdata_latched[9:7]; 953 | decoded_rs1 <= 8 + mem_rdata_latched[9:7]; 954 | decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]}; 955 | end 956 | if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI 957 | is_alu_reg_imm <= 1; 958 | decoded_rd <= 8 + mem_rdata_latched[9:7]; 959 | decoded_rs1 <= 8 + mem_rdata_latched[9:7]; 960 | end 961 | if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND 962 | is_alu_reg_reg <= 1; 963 | decoded_rd <= 8 + mem_rdata_latched[9:7]; 964 | decoded_rs1 <= 8 + mem_rdata_latched[9:7]; 965 | decoded_rs2 <= 8 + mem_rdata_latched[4:2]; 966 | end 967 | end 968 | 3'b101: begin // C.J 969 | instr_jal <= 1; 970 | end 971 | 3'b110: begin // C.BEQZ 972 | is_beq_bne_blt_bge_bltu_bgeu <= 1; 973 | decoded_rs1 <= 8 + mem_rdata_latched[9:7]; 974 | decoded_rs2 <= 0; 975 | end 976 | 3'b111: begin // C.BNEZ 977 | is_beq_bne_blt_bge_bltu_bgeu <= 1; 978 | decoded_rs1 <= 8 + mem_rdata_latched[9:7]; 979 | decoded_rs2 <= 0; 980 | end 981 | endcase 982 | end 983 | 2'b10: begin // Quadrant 2 984 | case (mem_rdata_latched[15:13]) 985 | 3'b000: begin // C.SLLI 986 | if (!mem_rdata_latched[12]) begin 987 | is_alu_reg_imm <= 1; 988 | decoded_rd <= mem_rdata_latched[11:7]; 989 | decoded_rs1 <= mem_rdata_latched[11:7]; 990 | decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]}; 991 | end 992 | end 993 | 3'b010: begin // C.LWSP 994 | if (mem_rdata_latched[11:7]) begin 995 | is_lb_lh_lw_lbu_lhu <= 1; 996 | decoded_rd <= mem_rdata_latched[11:7]; 997 | decoded_rs1 <= 2; 998 | end 999 | end 1000 | 3'b100: begin 1001 | if (mem_rdata_latched[12] == 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JR 1002 | instr_jalr <= 1; 1003 | decoded_rd <= 0; 1004 | decoded_rs1 <= mem_rdata_latched[11:7]; 1005 | end 1006 | if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV 1007 | is_alu_reg_reg <= 1; 1008 | decoded_rd <= mem_rdata_latched[11:7]; 1009 | decoded_rs1 <= 0; 1010 | decoded_rs2 <= mem_rdata_latched[6:2]; 1011 | end 1012 | if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR 1013 | instr_jalr <= 1; 1014 | decoded_rd <= 1; 1015 | decoded_rs1 <= mem_rdata_latched[11:7]; 1016 | end 1017 | if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD 1018 | is_alu_reg_reg <= 1; 1019 | decoded_rd <= mem_rdata_latched[11:7]; 1020 | decoded_rs1 <= mem_rdata_latched[11:7]; 1021 | decoded_rs2 <= mem_rdata_latched[6:2]; 1022 | end 1023 | end 1024 | 3'b110: begin // C.SWSP 1025 | is_sb_sh_sw <= 1; 1026 | decoded_rs1 <= 2; 1027 | decoded_rs2 <= mem_rdata_latched[6:2]; 1028 | end 1029 | endcase 1030 | end 1031 | endcase 1032 | end 1033 | end 1034 | 1035 | if (decoder_trigger && !decoder_pseudo_trigger) begin 1036 | pcpi_insn <= WITH_PCPI ? mem_rdata_q : 'bx; 1037 | 1038 | instr_beq <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b000; 1039 | instr_bne <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b001; 1040 | instr_blt <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b100; 1041 | instr_bge <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b101; 1042 | instr_bltu <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b110; 1043 | instr_bgeu <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b111; 1044 | 1045 | instr_lb <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b000; 1046 | instr_lh <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b001; 1047 | instr_lw <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b010; 1048 | instr_lbu <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b100; 1049 | instr_lhu <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b101; 1050 | 1051 | instr_sb <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b000; 1052 | instr_sh <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b001; 1053 | instr_sw <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b010; 1054 | 1055 | instr_addi <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b000; 1056 | instr_slti <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b010; 1057 | instr_sltiu <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b011; 1058 | instr_xori <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b100; 1059 | instr_ori <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b110; 1060 | instr_andi <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b111; 1061 | 1062 | instr_slli <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000; 1063 | instr_srli <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000; 1064 | instr_srai <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000; 1065 | 1066 | instr_add <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0000000; 1067 | instr_sub <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0100000; 1068 | instr_sll <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000; 1069 | instr_slt <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b010 && mem_rdata_q[31:25] == 7'b0000000; 1070 | instr_sltu <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b011 && mem_rdata_q[31:25] == 7'b0000000; 1071 | instr_xor <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b100 && mem_rdata_q[31:25] == 7'b0000000; 1072 | instr_srl <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000; 1073 | instr_sra <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000; 1074 | instr_or <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b110 && mem_rdata_q[31:25] == 7'b0000000; 1075 | instr_and <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b111 && mem_rdata_q[31:25] == 7'b0000000; 1076 | 1077 | instr_rdcycle <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000000000010) || 1078 | (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000100000010)) && ENABLE_COUNTERS; 1079 | instr_rdcycleh <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000000000010) || 1080 | (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000100000010)) && ENABLE_COUNTERS && ENABLE_COUNTERS64; 1081 | instr_rdinstr <= (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000001000000010) && ENABLE_COUNTERS; 1082 | instr_rdinstrh <= (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000001000000010) && ENABLE_COUNTERS && ENABLE_COUNTERS64; 1083 | 1084 | instr_ecall_ebreak <= ((mem_rdata_q[6:0] == 7'b1110011 && !mem_rdata_q[31:21] && !mem_rdata_q[19:7]) || 1085 | (COMPRESSED_ISA && mem_rdata_q[15:0] == 16'h9002)); 1086 | 1087 | instr_getq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS; 1088 | instr_setq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000001 && ENABLE_IRQ && ENABLE_IRQ_QREGS; 1089 | instr_maskirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000011 && ENABLE_IRQ; 1090 | instr_timer <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000101 && ENABLE_IRQ && ENABLE_IRQ_TIMER; 1091 | 1092 | is_slli_srli_srai <= is_alu_reg_imm && |{ 1093 | mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000, 1094 | mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000, 1095 | mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000 1096 | }; 1097 | 1098 | is_jalr_addi_slti_sltiu_xori_ori_andi <= instr_jalr || is_alu_reg_imm && |{ 1099 | mem_rdata_q[14:12] == 3'b000, 1100 | mem_rdata_q[14:12] == 3'b010, 1101 | mem_rdata_q[14:12] == 3'b011, 1102 | mem_rdata_q[14:12] == 3'b100, 1103 | mem_rdata_q[14:12] == 3'b110, 1104 | mem_rdata_q[14:12] == 3'b111 1105 | }; 1106 | 1107 | is_sll_srl_sra <= is_alu_reg_reg && |{ 1108 | mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000, 1109 | mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000, 1110 | mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000 1111 | }; 1112 | 1113 | is_lui_auipc_jal_jalr_addi_add_sub <= 0; 1114 | is_compare <= 0; 1115 | 1116 | (* parallel_case *) 1117 | case (1'b1) 1118 | instr_jal: 1119 | decoded_imm <= decoded_imm_j; 1120 | |{instr_lui, instr_auipc}: 1121 | decoded_imm <= mem_rdata_q[31:12] << 12; 1122 | |{instr_jalr, is_lb_lh_lw_lbu_lhu, is_alu_reg_imm}: 1123 | decoded_imm <= $signed(mem_rdata_q[31:20]); 1124 | is_beq_bne_blt_bge_bltu_bgeu: 1125 | decoded_imm <= $signed({mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8], 1'b0}); 1126 | is_sb_sh_sw: 1127 | decoded_imm <= $signed({mem_rdata_q[31:25], mem_rdata_q[11:7]}); 1128 | default: 1129 | decoded_imm <= 1'bx; 1130 | endcase 1131 | end 1132 | 1133 | if (!resetn) begin 1134 | is_beq_bne_blt_bge_bltu_bgeu <= 0; 1135 | is_compare <= 0; 1136 | 1137 | instr_beq <= 0; 1138 | instr_bne <= 0; 1139 | instr_blt <= 0; 1140 | instr_bge <= 0; 1141 | instr_bltu <= 0; 1142 | instr_bgeu <= 0; 1143 | 1144 | instr_addi <= 0; 1145 | instr_slti <= 0; 1146 | instr_sltiu <= 0; 1147 | instr_xori <= 0; 1148 | instr_ori <= 0; 1149 | instr_andi <= 0; 1150 | 1151 | instr_add <= 0; 1152 | instr_sub <= 0; 1153 | instr_sll <= 0; 1154 | instr_slt <= 0; 1155 | instr_sltu <= 0; 1156 | instr_xor <= 0; 1157 | instr_srl <= 0; 1158 | instr_sra <= 0; 1159 | instr_or <= 0; 1160 | instr_and <= 0; 1161 | end 1162 | end 1163 | 1164 | 1165 | // Main State Machine 1166 | 1167 | localparam cpu_state_trap = 8'b10000000; 1168 | localparam cpu_state_fetch = 8'b01000000; 1169 | localparam cpu_state_ld_rs1 = 8'b00100000; 1170 | localparam cpu_state_ld_rs2 = 8'b00010000; 1171 | localparam cpu_state_exec = 8'b00001000; 1172 | localparam cpu_state_shift = 8'b00000100; 1173 | localparam cpu_state_stmem = 8'b00000010; 1174 | localparam cpu_state_ldmem = 8'b00000001; 1175 | 1176 | reg [7:0] cpu_state; 1177 | reg [1:0] irq_state; 1178 | 1179 | `FORMAL_KEEP reg [127:0] dbg_ascii_state; 1180 | 1181 | always @* begin 1182 | dbg_ascii_state = ""; 1183 | if (cpu_state == cpu_state_trap) dbg_ascii_state = "trap"; 1184 | if (cpu_state == cpu_state_fetch) dbg_ascii_state = "fetch"; 1185 | if (cpu_state == cpu_state_ld_rs1) dbg_ascii_state = "ld_rs1"; 1186 | if (cpu_state == cpu_state_ld_rs2) dbg_ascii_state = "ld_rs2"; 1187 | if (cpu_state == cpu_state_exec) dbg_ascii_state = "exec"; 1188 | if (cpu_state == cpu_state_shift) dbg_ascii_state = "shift"; 1189 | if (cpu_state == cpu_state_stmem) dbg_ascii_state = "stmem"; 1190 | if (cpu_state == cpu_state_ldmem) dbg_ascii_state = "ldmem"; 1191 | end 1192 | 1193 | reg set_mem_do_rinst; 1194 | reg set_mem_do_rdata; 1195 | reg set_mem_do_wdata; 1196 | 1197 | reg latched_store; 1198 | reg latched_stalu; 1199 | reg latched_branch; 1200 | reg latched_compr; 1201 | reg latched_trace; 1202 | reg latched_is_lu; 1203 | reg latched_is_lh; 1204 | reg latched_is_lb; 1205 | reg [regindex_bits-1:0] latched_rd; 1206 | 1207 | reg [31:0] current_pc; 1208 | assign next_pc = latched_store && latched_branch ? reg_out & ~1 : reg_next_pc; 1209 | 1210 | reg [3:0] pcpi_timeout_counter; 1211 | reg pcpi_timeout; 1212 | 1213 | reg [31:0] next_irq_pending; 1214 | reg do_waitirq; 1215 | 1216 | reg [31:0] alu_out, alu_out_q; 1217 | reg alu_out_0, alu_out_0_q; 1218 | reg alu_wait, alu_wait_2; 1219 | 1220 | reg [31:0] alu_add_sub; 1221 | reg [31:0] alu_shl, alu_shr; 1222 | reg alu_eq, alu_ltu, alu_lts; 1223 | 1224 | generate if (TWO_CYCLE_ALU) begin 1225 | always @(posedge clk) begin 1226 | alu_add_sub <= instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; 1227 | alu_eq <= reg_op1 == reg_op2; 1228 | alu_lts <= $signed(reg_op1) < $signed(reg_op2); 1229 | alu_ltu <= reg_op1 < reg_op2; 1230 | alu_shl <= reg_op1 << reg_op2[4:0]; 1231 | alu_shr <= $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; 1232 | end 1233 | end else begin 1234 | always @* begin 1235 | alu_add_sub = instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; 1236 | alu_eq = reg_op1 == reg_op2; 1237 | alu_lts = $signed(reg_op1) < $signed(reg_op2); 1238 | alu_ltu = reg_op1 < reg_op2; 1239 | alu_shl = reg_op1 << reg_op2[4:0]; 1240 | alu_shr = $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; 1241 | end 1242 | end endgenerate 1243 | 1244 | always @* begin 1245 | alu_out_0 = 'bx; 1246 | (* parallel_case, full_case *) 1247 | case (1'b1) 1248 | instr_beq: 1249 | alu_out_0 = alu_eq; 1250 | instr_bne: 1251 | alu_out_0 = !alu_eq; 1252 | instr_bge: 1253 | alu_out_0 = !alu_lts; 1254 | instr_bgeu: 1255 | alu_out_0 = !alu_ltu; 1256 | is_slti_blt_slt && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}): 1257 | alu_out_0 = alu_lts; 1258 | is_sltiu_bltu_sltu && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}): 1259 | alu_out_0 = alu_ltu; 1260 | endcase 1261 | 1262 | alu_out = 'bx; 1263 | (* parallel_case, full_case *) 1264 | case (1'b1) 1265 | is_lui_auipc_jal_jalr_addi_add_sub: 1266 | alu_out = alu_add_sub; 1267 | is_compare: 1268 | alu_out = alu_out_0; 1269 | instr_xori || instr_xor: 1270 | alu_out = reg_op1 ^ reg_op2; 1271 | instr_ori || instr_or: 1272 | alu_out = reg_op1 | reg_op2; 1273 | instr_andi || instr_and: 1274 | alu_out = reg_op1 & reg_op2; 1275 | BARREL_SHIFTER && (instr_sll || instr_slli): 1276 | alu_out = alu_shl; 1277 | BARREL_SHIFTER && (instr_srl || instr_srli || instr_sra || instr_srai): 1278 | alu_out = alu_shr; 1279 | endcase 1280 | 1281 | `ifdef RISCV_FORMAL_BLACKBOX_ALU 1282 | alu_out_0 = $anyseq; 1283 | alu_out = $anyseq; 1284 | `endif 1285 | end 1286 | 1287 | reg clear_prefetched_high_word_q; 1288 | always @(posedge clk) clear_prefetched_high_word_q <= clear_prefetched_high_word; 1289 | 1290 | always @* begin 1291 | clear_prefetched_high_word = clear_prefetched_high_word_q; 1292 | if (!prefetched_high_word) 1293 | clear_prefetched_high_word = 0; 1294 | if (latched_branch || irq_state || !resetn) 1295 | clear_prefetched_high_word = COMPRESSED_ISA; 1296 | end 1297 | 1298 | reg cpuregs_write; 1299 | reg [31:0] cpuregs_wrdata; 1300 | reg [31:0] cpuregs_rs1; 1301 | reg [31:0] cpuregs_rs2; 1302 | reg [regindex_bits-1:0] decoded_rs; 1303 | 1304 | always @* begin 1305 | cpuregs_write = 0; 1306 | cpuregs_wrdata = 'bx; 1307 | 1308 | if (cpu_state == cpu_state_fetch) begin 1309 | (* parallel_case *) 1310 | case (1'b1) 1311 | latched_branch: begin 1312 | cpuregs_wrdata = reg_pc + (latched_compr ? 2 : 4); 1313 | cpuregs_write = 1; 1314 | end 1315 | latched_store && !latched_branch: begin 1316 | cpuregs_wrdata = latched_stalu ? alu_out_q : reg_out; 1317 | cpuregs_write = 1; 1318 | end 1319 | ENABLE_IRQ && irq_state[0]: begin 1320 | cpuregs_wrdata = reg_next_pc | latched_compr; 1321 | cpuregs_write = 1; 1322 | end 1323 | ENABLE_IRQ && irq_state[1]: begin 1324 | cpuregs_wrdata = irq_pending & ~irq_mask; 1325 | cpuregs_write = 1; 1326 | end 1327 | endcase 1328 | end 1329 | end 1330 | 1331 | `ifndef PICORV32_REGS 1332 | always @(posedge clk) begin 1333 | if (resetn && cpuregs_write && latched_rd) 1334 | `ifdef PICORV32_TESTBUG_001 1335 | cpuregs[latched_rd ^ 1] <= cpuregs_wrdata; 1336 | `elsif PICORV32_TESTBUG_002 1337 | cpuregs[latched_rd] <= cpuregs_wrdata ^ 1; 1338 | `else 1339 | cpuregs[latched_rd] <= cpuregs_wrdata; 1340 | `endif 1341 | end 1342 | 1343 | always @* begin 1344 | decoded_rs = 'bx; 1345 | if (ENABLE_REGS_DUALPORT) begin 1346 | `ifndef RISCV_FORMAL_BLACKBOX_REGS 1347 | cpuregs_rs1 = decoded_rs1 ? cpuregs[decoded_rs1] : 0; 1348 | cpuregs_rs2 = decoded_rs2 ? cpuregs[decoded_rs2] : 0; 1349 | `else 1350 | cpuregs_rs1 = decoded_rs1 ? $anyseq : 0; 1351 | cpuregs_rs2 = decoded_rs2 ? $anyseq : 0; 1352 | `endif 1353 | end else begin 1354 | decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1; 1355 | `ifndef RISCV_FORMAL_BLACKBOX_REGS 1356 | cpuregs_rs1 = decoded_rs ? cpuregs[decoded_rs] : 0; 1357 | `else 1358 | cpuregs_rs1 = decoded_rs ? $anyseq : 0; 1359 | `endif 1360 | cpuregs_rs2 = cpuregs_rs1; 1361 | end 1362 | end 1363 | `else 1364 | wire[31:0] cpuregs_rdata1; 1365 | wire[31:0] cpuregs_rdata2; 1366 | 1367 | wire [5:0] cpuregs_waddr = latched_rd; 1368 | wire [5:0] cpuregs_raddr1 = ENABLE_REGS_DUALPORT ? decoded_rs1 : decoded_rs; 1369 | wire [5:0] cpuregs_raddr2 = ENABLE_REGS_DUALPORT ? decoded_rs2 : 0; 1370 | 1371 | `PICORV32_REGS cpuregs ( 1372 | .clk(clk), 1373 | .wen(resetn && cpuregs_write && latched_rd), 1374 | .waddr(cpuregs_waddr), 1375 | .raddr1(cpuregs_raddr1), 1376 | .raddr2(cpuregs_raddr2), 1377 | .wdata(cpuregs_wrdata), 1378 | .rdata1(cpuregs_rdata1), 1379 | .rdata2(cpuregs_rdata2) 1380 | ); 1381 | 1382 | always @* begin 1383 | decoded_rs = 'bx; 1384 | if (ENABLE_REGS_DUALPORT) begin 1385 | cpuregs_rs1 = decoded_rs1 ? cpuregs_rdata1 : 0; 1386 | cpuregs_rs2 = decoded_rs2 ? cpuregs_rdata2 : 0; 1387 | end else begin 1388 | decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1; 1389 | cpuregs_rs1 = decoded_rs ? cpuregs_rdata1 : 0; 1390 | cpuregs_rs2 = cpuregs_rs1; 1391 | end 1392 | end 1393 | `endif 1394 | 1395 | assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask)); 1396 | 1397 | always @(posedge clk) begin 1398 | trap <= 0; 1399 | reg_sh <= 'bx; 1400 | reg_out <= 'bx; 1401 | set_mem_do_rinst = 0; 1402 | set_mem_do_rdata = 0; 1403 | set_mem_do_wdata = 0; 1404 | 1405 | alu_out_0_q <= alu_out_0; 1406 | alu_out_q <= alu_out; 1407 | 1408 | alu_wait <= 0; 1409 | alu_wait_2 <= 0; 1410 | 1411 | if (launch_next_insn) begin 1412 | dbg_rs1val <= 'bx; 1413 | dbg_rs2val <= 'bx; 1414 | dbg_rs1val_valid <= 0; 1415 | dbg_rs2val_valid <= 0; 1416 | end 1417 | 1418 | if (WITH_PCPI && CATCH_ILLINSN) begin 1419 | if (resetn && pcpi_valid && !pcpi_int_wait) begin 1420 | if (pcpi_timeout_counter) 1421 | pcpi_timeout_counter <= pcpi_timeout_counter - 1; 1422 | end else 1423 | pcpi_timeout_counter <= ~0; 1424 | pcpi_timeout <= !pcpi_timeout_counter; 1425 | end 1426 | 1427 | if (ENABLE_COUNTERS) begin 1428 | count_cycle <= resetn ? count_cycle + 1 : 0; 1429 | if (!ENABLE_COUNTERS64) count_cycle[63:32] <= 0; 1430 | end else begin 1431 | count_cycle <= 'bx; 1432 | count_instr <= 'bx; 1433 | end 1434 | 1435 | next_irq_pending = ENABLE_IRQ ? irq_pending & LATCHED_IRQ : 'bx; 1436 | 1437 | if (ENABLE_IRQ && ENABLE_IRQ_TIMER && timer) begin 1438 | timer <= timer - 1; 1439 | end 1440 | 1441 | decoder_trigger <= mem_do_rinst && mem_done; 1442 | decoder_trigger_q <= decoder_trigger; 1443 | decoder_pseudo_trigger <= 0; 1444 | decoder_pseudo_trigger_q <= decoder_pseudo_trigger; 1445 | do_waitirq <= 0; 1446 | 1447 | trace_valid <= 0; 1448 | 1449 | if (!ENABLE_TRACE) 1450 | trace_data <= 'bx; 1451 | 1452 | if (!resetn) begin 1453 | reg_pc <= PROGADDR_RESET; 1454 | reg_next_pc <= PROGADDR_RESET; 1455 | if (ENABLE_COUNTERS) 1456 | count_instr <= 0; 1457 | latched_store <= 0; 1458 | latched_stalu <= 0; 1459 | latched_branch <= 0; 1460 | latched_trace <= 0; 1461 | latched_is_lu <= 0; 1462 | latched_is_lh <= 0; 1463 | latched_is_lb <= 0; 1464 | pcpi_valid <= 0; 1465 | pcpi_timeout <= 0; 1466 | irq_active <= 0; 1467 | irq_delay <= 0; 1468 | irq_mask <= ~0; 1469 | next_irq_pending = 0; 1470 | irq_state <= 0; 1471 | eoi <= 0; 1472 | timer <= 0; 1473 | if (~STACKADDR) begin 1474 | latched_store <= 1; 1475 | latched_rd <= 2; 1476 | reg_out <= STACKADDR; 1477 | end 1478 | cpu_state <= cpu_state_fetch; 1479 | end else 1480 | (* parallel_case, full_case *) 1481 | case (cpu_state) 1482 | cpu_state_trap: begin 1483 | trap <= 1; 1484 | end 1485 | 1486 | cpu_state_fetch: begin 1487 | mem_do_rinst <= !decoder_trigger && !do_waitirq; 1488 | mem_wordsize <= 0; 1489 | 1490 | current_pc = reg_next_pc; 1491 | 1492 | (* parallel_case *) 1493 | case (1'b1) 1494 | latched_branch: begin 1495 | current_pc = latched_store ? (latched_stalu ? alu_out_q : reg_out) & ~1 : reg_next_pc; 1496 | `debug($display("ST_RD: %2d 0x%08x, BRANCH 0x%08x", latched_rd, reg_pc + (latched_compr ? 2 : 4), current_pc);) 1497 | end 1498 | latched_store && !latched_branch: begin 1499 | `debug($display("ST_RD: %2d 0x%08x", latched_rd, latched_stalu ? alu_out_q : reg_out);) 1500 | end 1501 | ENABLE_IRQ && irq_state[0]: begin 1502 | current_pc = PROGADDR_IRQ; 1503 | irq_active <= 1; 1504 | mem_do_rinst <= 1; 1505 | end 1506 | ENABLE_IRQ && irq_state[1]: begin 1507 | eoi <= irq_pending & ~irq_mask; 1508 | next_irq_pending = next_irq_pending & irq_mask; 1509 | end 1510 | endcase 1511 | 1512 | if (ENABLE_TRACE && latched_trace) begin 1513 | latched_trace <= 0; 1514 | trace_valid <= 1; 1515 | if (latched_branch) 1516 | trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_BRANCH | (current_pc & 32'hfffffffe); 1517 | else 1518 | trace_data <= (irq_active ? TRACE_IRQ : 0) | (latched_stalu ? alu_out_q : reg_out); 1519 | end 1520 | 1521 | reg_pc <= current_pc; 1522 | reg_next_pc <= current_pc; 1523 | 1524 | latched_store <= 0; 1525 | latched_stalu <= 0; 1526 | latched_branch <= 0; 1527 | latched_is_lu <= 0; 1528 | latched_is_lh <= 0; 1529 | latched_is_lb <= 0; 1530 | latched_rd <= decoded_rd; 1531 | latched_compr <= compressed_instr; 1532 | 1533 | if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin 1534 | irq_state <= 1535 | irq_state == 2'b00 ? 2'b01 : 1536 | irq_state == 2'b01 ? 2'b10 : 2'b00; 1537 | latched_compr <= latched_compr; 1538 | if (ENABLE_IRQ_QREGS) 1539 | latched_rd <= irqregs_offset | irq_state[0]; 1540 | else 1541 | latched_rd <= irq_state[0] ? 4 : 3; 1542 | end else 1543 | if (ENABLE_IRQ && (decoder_trigger || do_waitirq) && instr_waitirq) begin 1544 | if (irq_pending) begin 1545 | latched_store <= 1; 1546 | reg_out <= irq_pending; 1547 | reg_next_pc <= current_pc + (compressed_instr ? 2 : 4); 1548 | mem_do_rinst <= 1; 1549 | end else 1550 | do_waitirq <= 1; 1551 | end else 1552 | if (decoder_trigger) begin 1553 | `debug($display("-- %-0t", $time);) 1554 | irq_delay <= irq_active; 1555 | reg_next_pc <= current_pc + (compressed_instr ? 2 : 4); 1556 | if (ENABLE_TRACE) 1557 | latched_trace <= 1; 1558 | if (ENABLE_COUNTERS) begin 1559 | count_instr <= count_instr + 1; 1560 | if (!ENABLE_COUNTERS64) count_instr[63:32] <= 0; 1561 | end 1562 | if (instr_jal) begin 1563 | mem_do_rinst <= 1; 1564 | reg_next_pc <= current_pc + decoded_imm_j; 1565 | latched_branch <= 1; 1566 | end else begin 1567 | mem_do_rinst <= 0; 1568 | mem_do_prefetch <= !instr_jalr && !instr_retirq; 1569 | cpu_state <= cpu_state_ld_rs1; 1570 | end 1571 | end 1572 | end 1573 | 1574 | cpu_state_ld_rs1: begin 1575 | reg_op1 <= 'bx; 1576 | reg_op2 <= 'bx; 1577 | 1578 | (* parallel_case *) 1579 | case (1'b1) 1580 | (CATCH_ILLINSN || WITH_PCPI) && instr_trap: begin 1581 | if (WITH_PCPI) begin 1582 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1583 | reg_op1 <= cpuregs_rs1; 1584 | dbg_rs1val <= cpuregs_rs1; 1585 | dbg_rs1val_valid <= 1; 1586 | if (ENABLE_REGS_DUALPORT) begin 1587 | pcpi_valid <= 1; 1588 | `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) 1589 | reg_sh <= cpuregs_rs2; 1590 | reg_op2 <= cpuregs_rs2; 1591 | dbg_rs2val <= cpuregs_rs2; 1592 | dbg_rs2val_valid <= 1; 1593 | if (pcpi_int_ready) begin 1594 | mem_do_rinst <= 1; 1595 | pcpi_valid <= 0; 1596 | reg_out <= pcpi_int_rd; 1597 | latched_store <= pcpi_int_wr; 1598 | cpu_state <= cpu_state_fetch; 1599 | end else 1600 | if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin 1601 | pcpi_valid <= 0; 1602 | `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) 1603 | if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin 1604 | next_irq_pending[irq_ebreak] = 1; 1605 | cpu_state <= cpu_state_fetch; 1606 | end else 1607 | cpu_state <= cpu_state_trap; 1608 | end 1609 | end else begin 1610 | cpu_state <= cpu_state_ld_rs2; 1611 | end 1612 | end else begin 1613 | `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) 1614 | if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin 1615 | next_irq_pending[irq_ebreak] = 1; 1616 | cpu_state <= cpu_state_fetch; 1617 | end else 1618 | cpu_state <= cpu_state_trap; 1619 | end 1620 | end 1621 | ENABLE_COUNTERS && is_rdcycle_rdcycleh_rdinstr_rdinstrh: begin 1622 | (* parallel_case, full_case *) 1623 | case (1'b1) 1624 | instr_rdcycle: 1625 | reg_out <= count_cycle[31:0]; 1626 | instr_rdcycleh && ENABLE_COUNTERS64: 1627 | reg_out <= count_cycle[63:32]; 1628 | instr_rdinstr: 1629 | reg_out <= count_instr[31:0]; 1630 | instr_rdinstrh && ENABLE_COUNTERS64: 1631 | reg_out <= count_instr[63:32]; 1632 | endcase 1633 | latched_store <= 1; 1634 | cpu_state <= cpu_state_fetch; 1635 | end 1636 | is_lui_auipc_jal: begin 1637 | reg_op1 <= instr_lui ? 0 : reg_pc; 1638 | reg_op2 <= decoded_imm; 1639 | if (TWO_CYCLE_ALU) 1640 | alu_wait <= 1; 1641 | else 1642 | mem_do_rinst <= mem_do_prefetch; 1643 | cpu_state <= cpu_state_exec; 1644 | end 1645 | ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_getq: begin 1646 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1647 | reg_out <= cpuregs_rs1; 1648 | dbg_rs1val <= cpuregs_rs1; 1649 | dbg_rs1val_valid <= 1; 1650 | latched_store <= 1; 1651 | cpu_state <= cpu_state_fetch; 1652 | end 1653 | ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_setq: begin 1654 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1655 | reg_out <= cpuregs_rs1; 1656 | dbg_rs1val <= cpuregs_rs1; 1657 | dbg_rs1val_valid <= 1; 1658 | latched_rd <= latched_rd | irqregs_offset; 1659 | latched_store <= 1; 1660 | cpu_state <= cpu_state_fetch; 1661 | end 1662 | ENABLE_IRQ && instr_retirq: begin 1663 | eoi <= 0; 1664 | irq_active <= 0; 1665 | latched_branch <= 1; 1666 | latched_store <= 1; 1667 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1668 | reg_out <= CATCH_MISALIGN ? (cpuregs_rs1 & 32'h fffffffe) : cpuregs_rs1; 1669 | dbg_rs1val <= cpuregs_rs1; 1670 | dbg_rs1val_valid <= 1; 1671 | cpu_state <= cpu_state_fetch; 1672 | end 1673 | ENABLE_IRQ && instr_maskirq: begin 1674 | latched_store <= 1; 1675 | reg_out <= irq_mask; 1676 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1677 | irq_mask <= cpuregs_rs1 | MASKED_IRQ; 1678 | dbg_rs1val <= cpuregs_rs1; 1679 | dbg_rs1val_valid <= 1; 1680 | cpu_state <= cpu_state_fetch; 1681 | end 1682 | ENABLE_IRQ && ENABLE_IRQ_TIMER && instr_timer: begin 1683 | latched_store <= 1; 1684 | reg_out <= timer; 1685 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1686 | timer <= cpuregs_rs1; 1687 | dbg_rs1val <= cpuregs_rs1; 1688 | dbg_rs1val_valid <= 1; 1689 | cpu_state <= cpu_state_fetch; 1690 | end 1691 | is_lb_lh_lw_lbu_lhu && !instr_trap: begin 1692 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1693 | reg_op1 <= cpuregs_rs1; 1694 | dbg_rs1val <= cpuregs_rs1; 1695 | dbg_rs1val_valid <= 1; 1696 | cpu_state <= cpu_state_ldmem; 1697 | mem_do_rinst <= 1; 1698 | end 1699 | is_slli_srli_srai && !BARREL_SHIFTER: begin 1700 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1701 | reg_op1 <= cpuregs_rs1; 1702 | dbg_rs1val <= cpuregs_rs1; 1703 | dbg_rs1val_valid <= 1; 1704 | reg_sh <= decoded_rs2; 1705 | cpu_state <= cpu_state_shift; 1706 | end 1707 | is_jalr_addi_slti_sltiu_xori_ori_andi, is_slli_srli_srai && BARREL_SHIFTER: begin 1708 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1709 | reg_op1 <= cpuregs_rs1; 1710 | dbg_rs1val <= cpuregs_rs1; 1711 | dbg_rs1val_valid <= 1; 1712 | reg_op2 <= is_slli_srli_srai && BARREL_SHIFTER ? decoded_rs2 : decoded_imm; 1713 | if (TWO_CYCLE_ALU) 1714 | alu_wait <= 1; 1715 | else 1716 | mem_do_rinst <= mem_do_prefetch; 1717 | cpu_state <= cpu_state_exec; 1718 | end 1719 | default: begin 1720 | `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) 1721 | reg_op1 <= cpuregs_rs1; 1722 | dbg_rs1val <= cpuregs_rs1; 1723 | dbg_rs1val_valid <= 1; 1724 | if (ENABLE_REGS_DUALPORT) begin 1725 | `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) 1726 | reg_sh <= cpuregs_rs2; 1727 | reg_op2 <= cpuregs_rs2; 1728 | dbg_rs2val <= cpuregs_rs2; 1729 | dbg_rs2val_valid <= 1; 1730 | (* parallel_case *) 1731 | case (1'b1) 1732 | is_sb_sh_sw: begin 1733 | cpu_state <= cpu_state_stmem; 1734 | mem_do_rinst <= 1; 1735 | end 1736 | is_sll_srl_sra && !BARREL_SHIFTER: begin 1737 | cpu_state <= cpu_state_shift; 1738 | end 1739 | default: begin 1740 | if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin 1741 | alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu); 1742 | alu_wait <= 1; 1743 | end else 1744 | mem_do_rinst <= mem_do_prefetch; 1745 | cpu_state <= cpu_state_exec; 1746 | end 1747 | endcase 1748 | end else 1749 | cpu_state <= cpu_state_ld_rs2; 1750 | end 1751 | endcase 1752 | end 1753 | 1754 | cpu_state_ld_rs2: begin 1755 | `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) 1756 | reg_sh <= cpuregs_rs2; 1757 | reg_op2 <= cpuregs_rs2; 1758 | dbg_rs2val <= cpuregs_rs2; 1759 | dbg_rs2val_valid <= 1; 1760 | 1761 | (* parallel_case *) 1762 | case (1'b1) 1763 | WITH_PCPI && instr_trap: begin 1764 | pcpi_valid <= 1; 1765 | if (pcpi_int_ready) begin 1766 | mem_do_rinst <= 1; 1767 | pcpi_valid <= 0; 1768 | reg_out <= pcpi_int_rd; 1769 | latched_store <= pcpi_int_wr; 1770 | cpu_state <= cpu_state_fetch; 1771 | end else 1772 | if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin 1773 | pcpi_valid <= 0; 1774 | `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) 1775 | if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin 1776 | next_irq_pending[irq_ebreak] = 1; 1777 | cpu_state <= cpu_state_fetch; 1778 | end else 1779 | cpu_state <= cpu_state_trap; 1780 | end 1781 | end 1782 | is_sb_sh_sw: begin 1783 | cpu_state <= cpu_state_stmem; 1784 | mem_do_rinst <= 1; 1785 | end 1786 | is_sll_srl_sra && !BARREL_SHIFTER: begin 1787 | cpu_state <= cpu_state_shift; 1788 | end 1789 | default: begin 1790 | if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin 1791 | alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu); 1792 | alu_wait <= 1; 1793 | end else 1794 | mem_do_rinst <= mem_do_prefetch; 1795 | cpu_state <= cpu_state_exec; 1796 | end 1797 | endcase 1798 | end 1799 | 1800 | cpu_state_exec: begin 1801 | reg_out <= reg_pc + decoded_imm; 1802 | if ((TWO_CYCLE_ALU || TWO_CYCLE_COMPARE) && (alu_wait || alu_wait_2)) begin 1803 | mem_do_rinst <= mem_do_prefetch && !alu_wait_2; 1804 | alu_wait <= alu_wait_2; 1805 | end else 1806 | if (is_beq_bne_blt_bge_bltu_bgeu) begin 1807 | latched_rd <= 0; 1808 | latched_store <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0; 1809 | latched_branch <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0; 1810 | if (mem_done) 1811 | cpu_state <= cpu_state_fetch; 1812 | if (TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0) begin 1813 | decoder_trigger <= 0; 1814 | set_mem_do_rinst = 1; 1815 | end 1816 | end else begin 1817 | latched_branch <= instr_jalr; 1818 | latched_store <= 1; 1819 | latched_stalu <= 1; 1820 | cpu_state <= cpu_state_fetch; 1821 | end 1822 | end 1823 | 1824 | cpu_state_shift: begin 1825 | latched_store <= 1; 1826 | if (reg_sh == 0) begin 1827 | reg_out <= reg_op1; 1828 | mem_do_rinst <= mem_do_prefetch; 1829 | cpu_state <= cpu_state_fetch; 1830 | end else if (TWO_STAGE_SHIFT && reg_sh >= 4) begin 1831 | (* parallel_case, full_case *) 1832 | case (1'b1) 1833 | instr_slli || instr_sll: reg_op1 <= reg_op1 << 4; 1834 | instr_srli || instr_srl: reg_op1 <= reg_op1 >> 4; 1835 | instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 4; 1836 | endcase 1837 | reg_sh <= reg_sh - 4; 1838 | end else begin 1839 | (* parallel_case, full_case *) 1840 | case (1'b1) 1841 | instr_slli || instr_sll: reg_op1 <= reg_op1 << 1; 1842 | instr_srli || instr_srl: reg_op1 <= reg_op1 >> 1; 1843 | instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 1; 1844 | endcase 1845 | reg_sh <= reg_sh - 1; 1846 | end 1847 | end 1848 | 1849 | cpu_state_stmem: begin 1850 | if (ENABLE_TRACE) 1851 | reg_out <= reg_op2; 1852 | if (!mem_do_prefetch || mem_done) begin 1853 | if (!mem_do_wdata) begin 1854 | (* parallel_case, full_case *) 1855 | case (1'b1) 1856 | instr_sb: mem_wordsize <= 2; 1857 | instr_sh: mem_wordsize <= 1; 1858 | instr_sw: mem_wordsize <= 0; 1859 | endcase 1860 | if (ENABLE_TRACE) begin 1861 | trace_valid <= 1; 1862 | trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff); 1863 | end 1864 | reg_op1 <= reg_op1 + decoded_imm; 1865 | set_mem_do_wdata = 1; 1866 | end 1867 | if (!mem_do_prefetch && mem_done) begin 1868 | cpu_state <= cpu_state_fetch; 1869 | decoder_trigger <= 1; 1870 | decoder_pseudo_trigger <= 1; 1871 | end 1872 | end 1873 | end 1874 | 1875 | cpu_state_ldmem: begin 1876 | latched_store <= 1; 1877 | if (!mem_do_prefetch || mem_done) begin 1878 | if (!mem_do_rdata) begin 1879 | (* parallel_case, full_case *) 1880 | case (1'b1) 1881 | instr_lb || instr_lbu: mem_wordsize <= 2; 1882 | instr_lh || instr_lhu: mem_wordsize <= 1; 1883 | instr_lw: mem_wordsize <= 0; 1884 | endcase 1885 | latched_is_lu <= is_lbu_lhu_lw; 1886 | latched_is_lh <= instr_lh; 1887 | latched_is_lb <= instr_lb; 1888 | if (ENABLE_TRACE) begin 1889 | trace_valid <= 1; 1890 | trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff); 1891 | end 1892 | reg_op1 <= reg_op1 + decoded_imm; 1893 | set_mem_do_rdata = 1; 1894 | end 1895 | if (!mem_do_prefetch && mem_done) begin 1896 | (* parallel_case, full_case *) 1897 | case (1'b1) 1898 | latched_is_lu: reg_out <= mem_rdata_word; 1899 | latched_is_lh: reg_out <= $signed(mem_rdata_word[15:0]); 1900 | latched_is_lb: reg_out <= $signed(mem_rdata_word[7:0]); 1901 | endcase 1902 | decoder_trigger <= 1; 1903 | decoder_pseudo_trigger <= 1; 1904 | cpu_state <= cpu_state_fetch; 1905 | end 1906 | end 1907 | end 1908 | endcase 1909 | 1910 | if (ENABLE_IRQ) begin 1911 | next_irq_pending = next_irq_pending | irq; 1912 | if(ENABLE_IRQ_TIMER && timer) 1913 | if (timer - 1 == 0) 1914 | next_irq_pending[irq_timer] = 1; 1915 | end 1916 | 1917 | if (CATCH_MISALIGN && resetn && (mem_do_rdata || mem_do_wdata)) begin 1918 | if (mem_wordsize == 0 && reg_op1[1:0] != 0) begin 1919 | `debug($display("MISALIGNED WORD: 0x%08x", reg_op1);) 1920 | if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin 1921 | next_irq_pending[irq_buserror] = 1; 1922 | end else 1923 | cpu_state <= cpu_state_trap; 1924 | end 1925 | if (mem_wordsize == 1 && reg_op1[0] != 0) begin 1926 | `debug($display("MISALIGNED HALFWORD: 0x%08x", reg_op1);) 1927 | if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin 1928 | next_irq_pending[irq_buserror] = 1; 1929 | end else 1930 | cpu_state <= cpu_state_trap; 1931 | end 1932 | end 1933 | if (CATCH_MISALIGN && resetn && mem_do_rinst && (COMPRESSED_ISA ? reg_pc[0] : |reg_pc[1:0])) begin 1934 | `debug($display("MISALIGNED INSTRUCTION: 0x%08x", reg_pc);) 1935 | if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin 1936 | next_irq_pending[irq_buserror] = 1; 1937 | end else 1938 | cpu_state <= cpu_state_trap; 1939 | end 1940 | if (!CATCH_ILLINSN && decoder_trigger_q && !decoder_pseudo_trigger_q && instr_ecall_ebreak) begin 1941 | cpu_state <= cpu_state_trap; 1942 | end 1943 | 1944 | if (!resetn || mem_done) begin 1945 | mem_do_prefetch <= 0; 1946 | mem_do_rinst <= 0; 1947 | mem_do_rdata <= 0; 1948 | mem_do_wdata <= 0; 1949 | end 1950 | 1951 | if (set_mem_do_rinst) 1952 | mem_do_rinst <= 1; 1953 | if (set_mem_do_rdata) 1954 | mem_do_rdata <= 1; 1955 | if (set_mem_do_wdata) 1956 | mem_do_wdata <= 1; 1957 | 1958 | irq_pending <= next_irq_pending & ~MASKED_IRQ; 1959 | 1960 | if (!CATCH_MISALIGN) begin 1961 | if (COMPRESSED_ISA) begin 1962 | reg_pc[0] <= 0; 1963 | reg_next_pc[0] <= 0; 1964 | end else begin 1965 | reg_pc[1:0] <= 0; 1966 | reg_next_pc[1:0] <= 0; 1967 | end 1968 | end 1969 | current_pc = 'bx; 1970 | end 1971 | 1972 | `ifdef RISCV_FORMAL 1973 | reg dbg_irq_call; 1974 | reg dbg_irq_enter; 1975 | reg [31:0] dbg_irq_ret; 1976 | always @(posedge clk) begin 1977 | rvfi_valid <= resetn && (launch_next_insn || trap) && dbg_valid_insn; 1978 | rvfi_order <= resetn ? rvfi_order + rvfi_valid : 0; 1979 | 1980 | rvfi_insn <= dbg_insn_opcode; 1981 | rvfi_rs1_addr <= dbg_rs1val_valid ? dbg_insn_rs1 : 0; 1982 | rvfi_rs2_addr <= dbg_rs2val_valid ? dbg_insn_rs2 : 0; 1983 | rvfi_pc_rdata <= dbg_insn_addr; 1984 | rvfi_rs1_rdata <= dbg_rs1val_valid ? dbg_rs1val : 0; 1985 | rvfi_rs2_rdata <= dbg_rs2val_valid ? dbg_rs2val : 0; 1986 | rvfi_trap <= trap; 1987 | rvfi_halt <= trap; 1988 | rvfi_intr <= dbg_irq_enter; 1989 | rvfi_mode <= 3; 1990 | rvfi_ixl <= 1; 1991 | 1992 | if (!resetn) begin 1993 | dbg_irq_call <= 0; 1994 | dbg_irq_enter <= 0; 1995 | end else 1996 | if (rvfi_valid) begin 1997 | dbg_irq_call <= 0; 1998 | dbg_irq_enter <= dbg_irq_call; 1999 | end else 2000 | if (irq_state == 1) begin 2001 | dbg_irq_call <= 1; 2002 | dbg_irq_ret <= next_pc; 2003 | end 2004 | 2005 | if (!resetn) begin 2006 | rvfi_rd_addr <= 0; 2007 | rvfi_rd_wdata <= 0; 2008 | end else 2009 | if (cpuregs_write && !irq_state) begin 2010 | `ifdef PICORV32_TESTBUG_003 2011 | rvfi_rd_addr <= latched_rd ^ 1; 2012 | `else 2013 | rvfi_rd_addr <= latched_rd; 2014 | `endif 2015 | `ifdef PICORV32_TESTBUG_004 2016 | rvfi_rd_wdata <= latched_rd ? cpuregs_wrdata ^ 1 : 0; 2017 | `else 2018 | rvfi_rd_wdata <= latched_rd ? cpuregs_wrdata : 0; 2019 | `endif 2020 | end else 2021 | if (rvfi_valid) begin 2022 | rvfi_rd_addr <= 0; 2023 | rvfi_rd_wdata <= 0; 2024 | end 2025 | 2026 | casez (dbg_insn_opcode) 2027 | 32'b 0000000_?????_000??_???_?????_0001011: begin // getq 2028 | rvfi_rs1_addr <= 0; 2029 | rvfi_rs1_rdata <= 0; 2030 | end 2031 | 32'b 0000001_?????_?????_???_000??_0001011: begin // setq 2032 | rvfi_rd_addr <= 0; 2033 | rvfi_rd_wdata <= 0; 2034 | end 2035 | 32'b 0000010_?????_00000_???_00000_0001011: begin // retirq 2036 | rvfi_rs1_addr <= 0; 2037 | rvfi_rs1_rdata <= 0; 2038 | end 2039 | endcase 2040 | 2041 | if (!dbg_irq_call) begin 2042 | if (dbg_mem_instr) begin 2043 | rvfi_mem_addr <= 0; 2044 | rvfi_mem_rmask <= 0; 2045 | rvfi_mem_wmask <= 0; 2046 | rvfi_mem_rdata <= 0; 2047 | rvfi_mem_wdata <= 0; 2048 | end else 2049 | if (dbg_mem_valid && dbg_mem_ready) begin 2050 | rvfi_mem_addr <= dbg_mem_addr; 2051 | rvfi_mem_rmask <= dbg_mem_wstrb ? 0 : ~0; 2052 | rvfi_mem_wmask <= dbg_mem_wstrb; 2053 | rvfi_mem_rdata <= dbg_mem_rdata; 2054 | rvfi_mem_wdata <= dbg_mem_wdata; 2055 | end 2056 | end 2057 | end 2058 | 2059 | always @* begin 2060 | `ifdef PICORV32_TESTBUG_005 2061 | rvfi_pc_wdata = (dbg_irq_call ? dbg_irq_ret : dbg_insn_addr) ^ 4; 2062 | `else 2063 | rvfi_pc_wdata = dbg_irq_call ? dbg_irq_ret : dbg_insn_addr; 2064 | `endif 2065 | 2066 | rvfi_csr_mcycle_rmask = 0; 2067 | rvfi_csr_mcycle_wmask = 0; 2068 | rvfi_csr_mcycle_rdata = 0; 2069 | rvfi_csr_mcycle_wdata = 0; 2070 | 2071 | rvfi_csr_minstret_rmask = 0; 2072 | rvfi_csr_minstret_wmask = 0; 2073 | rvfi_csr_minstret_rdata = 0; 2074 | rvfi_csr_minstret_wdata = 0; 2075 | 2076 | if (rvfi_valid && rvfi_insn[6:0] == 7'b 1110011 && rvfi_insn[13:12] == 3'b010) begin 2077 | if (rvfi_insn[31:20] == 12'h C00) begin 2078 | rvfi_csr_mcycle_rmask = 64'h 0000_0000_FFFF_FFFF; 2079 | rvfi_csr_mcycle_rdata = {32'h 0000_0000, rvfi_rd_wdata}; 2080 | end 2081 | if (rvfi_insn[31:20] == 12'h C80) begin 2082 | rvfi_csr_mcycle_rmask = 64'h FFFF_FFFF_0000_0000; 2083 | rvfi_csr_mcycle_rdata = {rvfi_rd_wdata, 32'h 0000_0000}; 2084 | end 2085 | if (rvfi_insn[31:20] == 12'h C02) begin 2086 | rvfi_csr_minstret_rmask = 64'h 0000_0000_FFFF_FFFF; 2087 | rvfi_csr_minstret_rdata = {32'h 0000_0000, rvfi_rd_wdata}; 2088 | end 2089 | if (rvfi_insn[31:20] == 12'h C82) begin 2090 | rvfi_csr_minstret_rmask = 64'h FFFF_FFFF_0000_0000; 2091 | rvfi_csr_minstret_rdata = {rvfi_rd_wdata, 32'h 0000_0000}; 2092 | end 2093 | end 2094 | end 2095 | `endif 2096 | 2097 | // Formal Verification 2098 | `ifdef FORMAL 2099 | reg [3:0] last_mem_nowait; 2100 | always @(posedge clk) 2101 | last_mem_nowait <= {last_mem_nowait, mem_ready || !mem_valid}; 2102 | 2103 | // stall the memory interface for max 4 cycles 2104 | restrict property (|last_mem_nowait || mem_ready || !mem_valid); 2105 | 2106 | // resetn low in first cycle, after that resetn high 2107 | restrict property (resetn != $initstate); 2108 | 2109 | // this just makes it much easier to read traces. uncomment as needed. 2110 | // assume property (mem_valid || !mem_ready); 2111 | 2112 | reg ok; 2113 | always @* begin 2114 | if (resetn) begin 2115 | // instruction fetches are read-only 2116 | if (mem_valid && mem_instr) 2117 | assert (mem_wstrb == 0); 2118 | 2119 | // cpu_state must be valid 2120 | ok = 0; 2121 | if (cpu_state == cpu_state_trap) ok = 1; 2122 | if (cpu_state == cpu_state_fetch) ok = 1; 2123 | if (cpu_state == cpu_state_ld_rs1) ok = 1; 2124 | if (cpu_state == cpu_state_ld_rs2) ok = !ENABLE_REGS_DUALPORT; 2125 | if (cpu_state == cpu_state_exec) ok = 1; 2126 | if (cpu_state == cpu_state_shift) ok = 1; 2127 | if (cpu_state == cpu_state_stmem) ok = 1; 2128 | if (cpu_state == cpu_state_ldmem) ok = 1; 2129 | assert (ok); 2130 | end 2131 | end 2132 | 2133 | reg last_mem_la_read = 0; 2134 | reg last_mem_la_write = 0; 2135 | reg [31:0] last_mem_la_addr; 2136 | reg [31:0] last_mem_la_wdata; 2137 | reg [3:0] last_mem_la_wstrb = 0; 2138 | 2139 | always @(posedge clk) begin 2140 | last_mem_la_read <= mem_la_read; 2141 | last_mem_la_write <= mem_la_write; 2142 | last_mem_la_addr <= mem_la_addr; 2143 | last_mem_la_wdata <= mem_la_wdata; 2144 | last_mem_la_wstrb <= mem_la_wstrb; 2145 | 2146 | if (last_mem_la_read) begin 2147 | assert(mem_valid); 2148 | assert(mem_addr == last_mem_la_addr); 2149 | assert(mem_wstrb == 0); 2150 | end 2151 | if (last_mem_la_write) begin 2152 | assert(mem_valid); 2153 | assert(mem_addr == last_mem_la_addr); 2154 | assert(mem_wdata == last_mem_la_wdata); 2155 | assert(mem_wstrb == last_mem_la_wstrb); 2156 | end 2157 | if (mem_la_read || mem_la_write) begin 2158 | assert(!mem_valid || mem_ready); 2159 | end 2160 | end 2161 | `endif 2162 | endmodule 2163 | 2164 | // This is a simple example implementation of PICORV32_REGS. 2165 | // Use the PICORV32_REGS mechanism if you want to use custom 2166 | // memory resources to implement the processor register file. 2167 | // Note that your implementation must match the requirements of 2168 | // the PicoRV32 configuration. (e.g. QREGS, etc) 2169 | module picorv32_regs ( 2170 | input clk, wen, 2171 | input [5:0] waddr, 2172 | input [5:0] raddr1, 2173 | input [5:0] raddr2, 2174 | input [31:0] wdata, 2175 | output [31:0] rdata1, 2176 | output [31:0] rdata2 2177 | ); 2178 | reg [31:0] regs [0:30]; 2179 | 2180 | always @(posedge clk) 2181 | if (wen) regs[~waddr[4:0]] <= wdata; 2182 | 2183 | assign rdata1 = regs[~raddr1[4:0]]; 2184 | assign rdata2 = regs[~raddr2[4:0]]; 2185 | endmodule 2186 | 2187 | 2188 | /*************************************************************** 2189 | * picorv32_pcpi_mul 2190 | ***************************************************************/ 2191 | 2192 | module picorv32_pcpi_mul #( 2193 | parameter STEPS_AT_ONCE = 1, 2194 | parameter CARRY_CHAIN = 4 2195 | ) ( 2196 | input clk, resetn, 2197 | 2198 | input pcpi_valid, 2199 | input [31:0] pcpi_insn, 2200 | input [31:0] pcpi_rs1, 2201 | input [31:0] pcpi_rs2, 2202 | output reg pcpi_wr, 2203 | output reg [31:0] pcpi_rd, 2204 | output reg pcpi_wait, 2205 | output reg pcpi_ready 2206 | ); 2207 | reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu; 2208 | wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu}; 2209 | wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu}; 2210 | wire instr_rs1_signed = |{instr_mulh, instr_mulhsu}; 2211 | wire instr_rs2_signed = |{instr_mulh}; 2212 | 2213 | reg pcpi_wait_q; 2214 | wire mul_start = pcpi_wait && !pcpi_wait_q; 2215 | 2216 | always @(posedge clk) begin 2217 | instr_mul <= 0; 2218 | instr_mulh <= 0; 2219 | instr_mulhsu <= 0; 2220 | instr_mulhu <= 0; 2221 | 2222 | if (resetn && pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin 2223 | case (pcpi_insn[14:12]) 2224 | 3'b000: instr_mul <= 1; 2225 | 3'b001: instr_mulh <= 1; 2226 | 3'b010: instr_mulhsu <= 1; 2227 | 3'b011: instr_mulhu <= 1; 2228 | endcase 2229 | end 2230 | 2231 | pcpi_wait <= instr_any_mul; 2232 | pcpi_wait_q <= pcpi_wait; 2233 | end 2234 | 2235 | reg [63:0] rs1, rs2, rd, rdx; 2236 | reg [63:0] next_rs1, next_rs2, this_rs2; 2237 | reg [63:0] next_rd, next_rdx, next_rdt; 2238 | reg [6:0] mul_counter; 2239 | reg mul_waiting; 2240 | reg mul_finish; 2241 | integer i, j; 2242 | 2243 | // carry save accumulator 2244 | always @* begin 2245 | next_rd = rd; 2246 | next_rdx = rdx; 2247 | next_rs1 = rs1; 2248 | next_rs2 = rs2; 2249 | 2250 | for (i = 0; i < STEPS_AT_ONCE; i=i+1) begin 2251 | this_rs2 = next_rs1[0] ? next_rs2 : 0; 2252 | if (CARRY_CHAIN == 0) begin 2253 | next_rdt = next_rd ^ next_rdx ^ this_rs2; 2254 | next_rdx = ((next_rd & next_rdx) | (next_rd & this_rs2) | (next_rdx & this_rs2)) << 1; 2255 | next_rd = next_rdt; 2256 | end else begin 2257 | next_rdt = 0; 2258 | for (j = 0; j < 64; j = j + CARRY_CHAIN) 2259 | {next_rdt[j+CARRY_CHAIN-1], next_rd[j +: CARRY_CHAIN]} = 2260 | next_rd[j +: CARRY_CHAIN] + next_rdx[j +: CARRY_CHAIN] + this_rs2[j +: CARRY_CHAIN]; 2261 | next_rdx = next_rdt << 1; 2262 | end 2263 | next_rs1 = next_rs1 >> 1; 2264 | next_rs2 = next_rs2 << 1; 2265 | end 2266 | end 2267 | 2268 | always @(posedge clk) begin 2269 | mul_finish <= 0; 2270 | if (!resetn) begin 2271 | mul_waiting <= 1; 2272 | end else 2273 | if (mul_waiting) begin 2274 | if (instr_rs1_signed) 2275 | rs1 <= $signed(pcpi_rs1); 2276 | else 2277 | rs1 <= $unsigned(pcpi_rs1); 2278 | 2279 | if (instr_rs2_signed) 2280 | rs2 <= $signed(pcpi_rs2); 2281 | else 2282 | rs2 <= $unsigned(pcpi_rs2); 2283 | 2284 | rd <= 0; 2285 | rdx <= 0; 2286 | mul_counter <= (instr_any_mulh ? 63 - STEPS_AT_ONCE : 31 - STEPS_AT_ONCE); 2287 | mul_waiting <= !mul_start; 2288 | end else begin 2289 | rd <= next_rd; 2290 | rdx <= next_rdx; 2291 | rs1 <= next_rs1; 2292 | rs2 <= next_rs2; 2293 | 2294 | mul_counter <= mul_counter - STEPS_AT_ONCE; 2295 | if (mul_counter[6]) begin 2296 | mul_finish <= 1; 2297 | mul_waiting <= 1; 2298 | end 2299 | end 2300 | end 2301 | 2302 | always @(posedge clk) begin 2303 | pcpi_wr <= 0; 2304 | pcpi_ready <= 0; 2305 | if (mul_finish && resetn) begin 2306 | pcpi_wr <= 1; 2307 | pcpi_ready <= 1; 2308 | pcpi_rd <= instr_any_mulh ? rd >> 32 : rd; 2309 | end 2310 | end 2311 | endmodule 2312 | 2313 | module picorv32_pcpi_fast_mul #( 2314 | parameter EXTRA_MUL_FFS = 0, 2315 | parameter EXTRA_INSN_FFS = 0, 2316 | parameter MUL_CLKGATE = 0 2317 | ) ( 2318 | input clk, resetn, 2319 | 2320 | input pcpi_valid, 2321 | input [31:0] pcpi_insn, 2322 | input [31:0] pcpi_rs1, 2323 | input [31:0] pcpi_rs2, 2324 | output pcpi_wr, 2325 | output [31:0] pcpi_rd, 2326 | output pcpi_wait, 2327 | output pcpi_ready 2328 | ); 2329 | reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu; 2330 | wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu}; 2331 | wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu}; 2332 | wire instr_rs1_signed = |{instr_mulh, instr_mulhsu}; 2333 | wire instr_rs2_signed = |{instr_mulh}; 2334 | 2335 | reg shift_out; 2336 | reg [3:0] active; 2337 | reg [32:0] rs1, rs2, rs1_q, rs2_q; 2338 | reg [63:0] rd, rd_q; 2339 | 2340 | wire pcpi_insn_valid = pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001; 2341 | reg pcpi_insn_valid_q; 2342 | 2343 | always @* begin 2344 | instr_mul = 0; 2345 | instr_mulh = 0; 2346 | instr_mulhsu = 0; 2347 | instr_mulhu = 0; 2348 | 2349 | if (resetn && (EXTRA_INSN_FFS ? pcpi_insn_valid_q : pcpi_insn_valid)) begin 2350 | case (pcpi_insn[14:12]) 2351 | 3'b000: instr_mul = 1; 2352 | 3'b001: instr_mulh = 1; 2353 | 3'b010: instr_mulhsu = 1; 2354 | 3'b011: instr_mulhu = 1; 2355 | endcase 2356 | end 2357 | end 2358 | 2359 | always @(posedge clk) begin 2360 | pcpi_insn_valid_q <= pcpi_insn_valid; 2361 | if (!MUL_CLKGATE || active[0]) begin 2362 | rs1_q <= rs1; 2363 | rs2_q <= rs2; 2364 | end 2365 | if (!MUL_CLKGATE || active[1]) begin 2366 | rd <= $signed(EXTRA_MUL_FFS ? rs1_q : rs1) * $signed(EXTRA_MUL_FFS ? rs2_q : rs2); 2367 | end 2368 | if (!MUL_CLKGATE || active[2]) begin 2369 | rd_q <= rd; 2370 | end 2371 | end 2372 | 2373 | always @(posedge clk) begin 2374 | if (instr_any_mul && !(EXTRA_MUL_FFS ? active[3:0] : active[1:0])) begin 2375 | if (instr_rs1_signed) 2376 | rs1 <= $signed(pcpi_rs1); 2377 | else 2378 | rs1 <= $unsigned(pcpi_rs1); 2379 | 2380 | if (instr_rs2_signed) 2381 | rs2 <= $signed(pcpi_rs2); 2382 | else 2383 | rs2 <= $unsigned(pcpi_rs2); 2384 | active[0] <= 1; 2385 | end else begin 2386 | active[0] <= 0; 2387 | end 2388 | 2389 | active[3:1] <= active; 2390 | shift_out <= instr_any_mulh; 2391 | 2392 | if (!resetn) 2393 | active <= 0; 2394 | end 2395 | 2396 | assign pcpi_wr = active[EXTRA_MUL_FFS ? 3 : 1]; 2397 | assign pcpi_wait = 0; 2398 | assign pcpi_ready = active[EXTRA_MUL_FFS ? 3 : 1]; 2399 | `ifdef RISCV_FORMAL_ALTOPS 2400 | assign pcpi_rd = 2401 | instr_mul ? (pcpi_rs1 + pcpi_rs2) ^ 32'h5876063e : 2402 | instr_mulh ? (pcpi_rs1 + pcpi_rs2) ^ 32'hf6583fb7 : 2403 | instr_mulhsu ? (pcpi_rs1 - pcpi_rs2) ^ 32'hecfbe137 : 2404 | instr_mulhu ? (pcpi_rs1 + pcpi_rs2) ^ 32'h949ce5e8 : 1'bx; 2405 | `else 2406 | assign pcpi_rd = shift_out ? (EXTRA_MUL_FFS ? rd_q : rd) >> 32 : (EXTRA_MUL_FFS ? rd_q : rd); 2407 | `endif 2408 | endmodule 2409 | 2410 | 2411 | /*************************************************************** 2412 | * picorv32_pcpi_div 2413 | ***************************************************************/ 2414 | 2415 | module picorv32_pcpi_div ( 2416 | input clk, resetn, 2417 | 2418 | input pcpi_valid, 2419 | input [31:0] pcpi_insn, 2420 | input [31:0] pcpi_rs1, 2421 | input [31:0] pcpi_rs2, 2422 | output reg pcpi_wr, 2423 | output reg [31:0] pcpi_rd, 2424 | output reg pcpi_wait, 2425 | output reg pcpi_ready 2426 | ); 2427 | reg instr_div, instr_divu, instr_rem, instr_remu; 2428 | wire instr_any_div_rem = |{instr_div, instr_divu, instr_rem, instr_remu}; 2429 | 2430 | reg pcpi_wait_q; 2431 | wire start = pcpi_wait && !pcpi_wait_q; 2432 | 2433 | always @(posedge clk) begin 2434 | instr_div <= 0; 2435 | instr_divu <= 0; 2436 | instr_rem <= 0; 2437 | instr_remu <= 0; 2438 | 2439 | if (resetn && pcpi_valid && !pcpi_ready && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin 2440 | case (pcpi_insn[14:12]) 2441 | 3'b100: instr_div <= 1; 2442 | 3'b101: instr_divu <= 1; 2443 | 3'b110: instr_rem <= 1; 2444 | 3'b111: instr_remu <= 1; 2445 | endcase 2446 | end 2447 | 2448 | pcpi_wait <= instr_any_div_rem && resetn; 2449 | pcpi_wait_q <= pcpi_wait && resetn; 2450 | end 2451 | 2452 | reg [31:0] dividend; 2453 | reg [62:0] divisor; 2454 | reg [31:0] quotient; 2455 | reg [31:0] quotient_msk; 2456 | reg running; 2457 | reg outsign; 2458 | 2459 | always @(posedge clk) begin 2460 | pcpi_ready <= 0; 2461 | pcpi_wr <= 0; 2462 | pcpi_rd <= 'bx; 2463 | 2464 | if (!resetn) begin 2465 | running <= 0; 2466 | end else 2467 | if (start) begin 2468 | running <= 1; 2469 | dividend <= (instr_div || instr_rem) && pcpi_rs1[31] ? -pcpi_rs1 : pcpi_rs1; 2470 | divisor <= ((instr_div || instr_rem) && pcpi_rs2[31] ? -pcpi_rs2 : pcpi_rs2) << 31; 2471 | outsign <= (instr_div && (pcpi_rs1[31] != pcpi_rs2[31]) && |pcpi_rs2) || (instr_rem && pcpi_rs1[31]); 2472 | quotient <= 0; 2473 | quotient_msk <= 1 << 31; 2474 | end else 2475 | if (!quotient_msk && running) begin 2476 | running <= 0; 2477 | pcpi_ready <= 1; 2478 | pcpi_wr <= 1; 2479 | `ifdef RISCV_FORMAL_ALTOPS 2480 | case (1) 2481 | instr_div: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h7f8529ec; 2482 | instr_divu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h10e8fd70; 2483 | instr_rem: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h8da68fa5; 2484 | instr_remu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h3138d0e1; 2485 | endcase 2486 | `else 2487 | if (instr_div || instr_divu) 2488 | pcpi_rd <= outsign ? -quotient : quotient; 2489 | else 2490 | pcpi_rd <= outsign ? -dividend : dividend; 2491 | `endif 2492 | end else begin 2493 | if (divisor <= dividend) begin 2494 | dividend <= dividend - divisor; 2495 | quotient <= quotient | quotient_msk; 2496 | end 2497 | divisor <= divisor >> 1; 2498 | `ifdef RISCV_FORMAL_ALTOPS 2499 | quotient_msk <= quotient_msk >> 5; 2500 | `else 2501 | quotient_msk <= quotient_msk >> 1; 2502 | `endif 2503 | end 2504 | end 2505 | endmodule 2506 | 2507 | 2508 | /*************************************************************** 2509 | * picorv32_axi 2510 | ***************************************************************/ 2511 | 2512 | module picorv32_axi #( 2513 | parameter [ 0:0] ENABLE_COUNTERS = 1, 2514 | parameter [ 0:0] ENABLE_COUNTERS64 = 1, 2515 | parameter [ 0:0] ENABLE_REGS_16_31 = 1, 2516 | parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, 2517 | parameter [ 0:0] TWO_STAGE_SHIFT = 1, 2518 | parameter [ 0:0] BARREL_SHIFTER = 0, 2519 | parameter [ 0:0] TWO_CYCLE_COMPARE = 0, 2520 | parameter [ 0:0] TWO_CYCLE_ALU = 0, 2521 | parameter [ 0:0] COMPRESSED_ISA = 0, 2522 | parameter [ 0:0] CATCH_MISALIGN = 1, 2523 | parameter [ 0:0] CATCH_ILLINSN = 1, 2524 | parameter [ 0:0] ENABLE_PCPI = 0, 2525 | parameter [ 0:0] ENABLE_MUL = 0, 2526 | parameter [ 0:0] ENABLE_FAST_MUL = 0, 2527 | parameter [ 0:0] ENABLE_DIV = 0, 2528 | parameter [ 0:0] ENABLE_IRQ = 0, 2529 | parameter [ 0:0] ENABLE_IRQ_QREGS = 1, 2530 | parameter [ 0:0] ENABLE_IRQ_TIMER = 1, 2531 | parameter [ 0:0] ENABLE_TRACE = 0, 2532 | parameter [ 0:0] REGS_INIT_ZERO = 0, 2533 | parameter [31:0] MASKED_IRQ = 32'h 0000_0000, 2534 | parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, 2535 | parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, 2536 | parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, 2537 | parameter [31:0] STACKADDR = 32'h ffff_ffff 2538 | ) ( 2539 | input clk, resetn, 2540 | output trap, 2541 | 2542 | // AXI4-lite master memory interface 2543 | 2544 | output mem_axi_awvalid, 2545 | input mem_axi_awready, 2546 | output [31:0] mem_axi_awaddr, 2547 | output [ 2:0] mem_axi_awprot, 2548 | 2549 | output mem_axi_wvalid, 2550 | input mem_axi_wready, 2551 | output [31:0] mem_axi_wdata, 2552 | output [ 3:0] mem_axi_wstrb, 2553 | 2554 | input mem_axi_bvalid, 2555 | output mem_axi_bready, 2556 | 2557 | output mem_axi_arvalid, 2558 | input mem_axi_arready, 2559 | output [31:0] mem_axi_araddr, 2560 | output [ 2:0] mem_axi_arprot, 2561 | 2562 | input mem_axi_rvalid, 2563 | output mem_axi_rready, 2564 | input [31:0] mem_axi_rdata, 2565 | 2566 | // Pico Co-Processor Interface (PCPI) 2567 | output pcpi_valid, 2568 | output [31:0] pcpi_insn, 2569 | output [31:0] pcpi_rs1, 2570 | output [31:0] pcpi_rs2, 2571 | input pcpi_wr, 2572 | input [31:0] pcpi_rd, 2573 | input pcpi_wait, 2574 | input pcpi_ready, 2575 | 2576 | // IRQ interface 2577 | input [31:0] irq, 2578 | output [31:0] eoi, 2579 | 2580 | `ifdef RISCV_FORMAL 2581 | output rvfi_valid, 2582 | output [63:0] rvfi_order, 2583 | output [31:0] rvfi_insn, 2584 | output rvfi_trap, 2585 | output rvfi_halt, 2586 | output rvfi_intr, 2587 | output [ 4:0] rvfi_rs1_addr, 2588 | output [ 4:0] rvfi_rs2_addr, 2589 | output [31:0] rvfi_rs1_rdata, 2590 | output [31:0] rvfi_rs2_rdata, 2591 | output [ 4:0] rvfi_rd_addr, 2592 | output [31:0] rvfi_rd_wdata, 2593 | output [31:0] rvfi_pc_rdata, 2594 | output [31:0] rvfi_pc_wdata, 2595 | output [31:0] rvfi_mem_addr, 2596 | output [ 3:0] rvfi_mem_rmask, 2597 | output [ 3:0] rvfi_mem_wmask, 2598 | output [31:0] rvfi_mem_rdata, 2599 | output [31:0] rvfi_mem_wdata, 2600 | `endif 2601 | 2602 | // Trace Interface 2603 | output trace_valid, 2604 | output [35:0] trace_data 2605 | ); 2606 | wire mem_valid; 2607 | wire [31:0] mem_addr; 2608 | wire [31:0] mem_wdata; 2609 | wire [ 3:0] mem_wstrb; 2610 | wire mem_instr; 2611 | wire mem_ready; 2612 | wire [31:0] mem_rdata; 2613 | 2614 | picorv32_axi_adapter axi_adapter ( 2615 | .clk (clk ), 2616 | .resetn (resetn ), 2617 | .mem_axi_awvalid(mem_axi_awvalid), 2618 | .mem_axi_awready(mem_axi_awready), 2619 | .mem_axi_awaddr (mem_axi_awaddr ), 2620 | .mem_axi_awprot (mem_axi_awprot ), 2621 | .mem_axi_wvalid (mem_axi_wvalid ), 2622 | .mem_axi_wready (mem_axi_wready ), 2623 | .mem_axi_wdata (mem_axi_wdata ), 2624 | .mem_axi_wstrb (mem_axi_wstrb ), 2625 | .mem_axi_bvalid (mem_axi_bvalid ), 2626 | .mem_axi_bready (mem_axi_bready ), 2627 | .mem_axi_arvalid(mem_axi_arvalid), 2628 | .mem_axi_arready(mem_axi_arready), 2629 | .mem_axi_araddr (mem_axi_araddr ), 2630 | .mem_axi_arprot (mem_axi_arprot ), 2631 | .mem_axi_rvalid (mem_axi_rvalid ), 2632 | .mem_axi_rready (mem_axi_rready ), 2633 | .mem_axi_rdata (mem_axi_rdata ), 2634 | .mem_valid (mem_valid ), 2635 | .mem_instr (mem_instr ), 2636 | .mem_ready (mem_ready ), 2637 | .mem_addr (mem_addr ), 2638 | .mem_wdata (mem_wdata ), 2639 | .mem_wstrb (mem_wstrb ), 2640 | .mem_rdata (mem_rdata ) 2641 | ); 2642 | 2643 | picorv32 #( 2644 | .ENABLE_COUNTERS (ENABLE_COUNTERS ), 2645 | .ENABLE_COUNTERS64 (ENABLE_COUNTERS64 ), 2646 | .ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ), 2647 | .ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT), 2648 | .TWO_STAGE_SHIFT (TWO_STAGE_SHIFT ), 2649 | .BARREL_SHIFTER (BARREL_SHIFTER ), 2650 | .TWO_CYCLE_COMPARE (TWO_CYCLE_COMPARE ), 2651 | .TWO_CYCLE_ALU (TWO_CYCLE_ALU ), 2652 | .COMPRESSED_ISA (COMPRESSED_ISA ), 2653 | .CATCH_MISALIGN (CATCH_MISALIGN ), 2654 | .CATCH_ILLINSN (CATCH_ILLINSN ), 2655 | .ENABLE_PCPI (ENABLE_PCPI ), 2656 | .ENABLE_MUL (ENABLE_MUL ), 2657 | .ENABLE_FAST_MUL (ENABLE_FAST_MUL ), 2658 | .ENABLE_DIV (ENABLE_DIV ), 2659 | .ENABLE_IRQ (ENABLE_IRQ ), 2660 | .ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ), 2661 | .ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ), 2662 | .ENABLE_TRACE (ENABLE_TRACE ), 2663 | .REGS_INIT_ZERO (REGS_INIT_ZERO ), 2664 | .MASKED_IRQ (MASKED_IRQ ), 2665 | .LATCHED_IRQ (LATCHED_IRQ ), 2666 | .PROGADDR_RESET (PROGADDR_RESET ), 2667 | .PROGADDR_IRQ (PROGADDR_IRQ ), 2668 | .STACKADDR (STACKADDR ) 2669 | ) picorv32_core ( 2670 | .clk (clk ), 2671 | .resetn (resetn), 2672 | .trap (trap ), 2673 | 2674 | .mem_valid(mem_valid), 2675 | .mem_addr (mem_addr ), 2676 | .mem_wdata(mem_wdata), 2677 | .mem_wstrb(mem_wstrb), 2678 | .mem_instr(mem_instr), 2679 | .mem_ready(mem_ready), 2680 | .mem_rdata(mem_rdata), 2681 | 2682 | .pcpi_valid(pcpi_valid), 2683 | .pcpi_insn (pcpi_insn ), 2684 | .pcpi_rs1 (pcpi_rs1 ), 2685 | .pcpi_rs2 (pcpi_rs2 ), 2686 | .pcpi_wr (pcpi_wr ), 2687 | .pcpi_rd (pcpi_rd ), 2688 | .pcpi_wait (pcpi_wait ), 2689 | .pcpi_ready(pcpi_ready), 2690 | 2691 | .irq(irq), 2692 | .eoi(eoi), 2693 | 2694 | `ifdef RISCV_FORMAL 2695 | .rvfi_valid (rvfi_valid ), 2696 | .rvfi_order (rvfi_order ), 2697 | .rvfi_insn (rvfi_insn ), 2698 | .rvfi_trap (rvfi_trap ), 2699 | .rvfi_halt (rvfi_halt ), 2700 | .rvfi_intr (rvfi_intr ), 2701 | .rvfi_rs1_addr (rvfi_rs1_addr ), 2702 | .rvfi_rs2_addr (rvfi_rs2_addr ), 2703 | .rvfi_rs1_rdata(rvfi_rs1_rdata), 2704 | .rvfi_rs2_rdata(rvfi_rs2_rdata), 2705 | .rvfi_rd_addr (rvfi_rd_addr ), 2706 | .rvfi_rd_wdata (rvfi_rd_wdata ), 2707 | .rvfi_pc_rdata (rvfi_pc_rdata ), 2708 | .rvfi_pc_wdata (rvfi_pc_wdata ), 2709 | .rvfi_mem_addr (rvfi_mem_addr ), 2710 | .rvfi_mem_rmask(rvfi_mem_rmask), 2711 | .rvfi_mem_wmask(rvfi_mem_wmask), 2712 | .rvfi_mem_rdata(rvfi_mem_rdata), 2713 | .rvfi_mem_wdata(rvfi_mem_wdata), 2714 | `endif 2715 | 2716 | .trace_valid(trace_valid), 2717 | .trace_data (trace_data) 2718 | ); 2719 | endmodule 2720 | 2721 | 2722 | /*************************************************************** 2723 | * picorv32_axi_adapter 2724 | ***************************************************************/ 2725 | 2726 | module picorv32_axi_adapter ( 2727 | input clk, resetn, 2728 | 2729 | // AXI4-lite master memory interface 2730 | 2731 | output mem_axi_awvalid, 2732 | input mem_axi_awready, 2733 | output [31:0] mem_axi_awaddr, 2734 | output [ 2:0] mem_axi_awprot, 2735 | 2736 | output mem_axi_wvalid, 2737 | input mem_axi_wready, 2738 | output [31:0] mem_axi_wdata, 2739 | output [ 3:0] mem_axi_wstrb, 2740 | 2741 | input mem_axi_bvalid, 2742 | output mem_axi_bready, 2743 | 2744 | output mem_axi_arvalid, 2745 | input mem_axi_arready, 2746 | output [31:0] mem_axi_araddr, 2747 | output [ 2:0] mem_axi_arprot, 2748 | 2749 | input mem_axi_rvalid, 2750 | output mem_axi_rready, 2751 | input [31:0] mem_axi_rdata, 2752 | 2753 | // Native PicoRV32 memory interface 2754 | 2755 | input mem_valid, 2756 | input mem_instr, 2757 | output mem_ready, 2758 | input [31:0] mem_addr, 2759 | input [31:0] mem_wdata, 2760 | input [ 3:0] mem_wstrb, 2761 | output [31:0] mem_rdata 2762 | ); 2763 | reg ack_awvalid; 2764 | reg ack_arvalid; 2765 | reg ack_wvalid; 2766 | reg xfer_done; 2767 | 2768 | assign mem_axi_awvalid = mem_valid && |mem_wstrb && !ack_awvalid; 2769 | assign mem_axi_awaddr = mem_addr; 2770 | assign mem_axi_awprot = 0; 2771 | 2772 | assign mem_axi_arvalid = mem_valid && !mem_wstrb && !ack_arvalid; 2773 | assign mem_axi_araddr = mem_addr; 2774 | assign mem_axi_arprot = mem_instr ? 3'b100 : 3'b000; 2775 | 2776 | assign mem_axi_wvalid = mem_valid && |mem_wstrb && !ack_wvalid; 2777 | assign mem_axi_wdata = mem_wdata; 2778 | assign mem_axi_wstrb = mem_wstrb; 2779 | 2780 | assign mem_ready = mem_axi_bvalid || mem_axi_rvalid; 2781 | assign mem_axi_bready = mem_valid && |mem_wstrb; 2782 | assign mem_axi_rready = mem_valid && !mem_wstrb; 2783 | assign mem_rdata = mem_axi_rdata; 2784 | 2785 | always @(posedge clk) begin 2786 | if (!resetn) begin 2787 | ack_awvalid <= 0; 2788 | end else begin 2789 | xfer_done <= mem_valid && mem_ready; 2790 | if (mem_axi_awready && mem_axi_awvalid) 2791 | ack_awvalid <= 1; 2792 | if (mem_axi_arready && mem_axi_arvalid) 2793 | ack_arvalid <= 1; 2794 | if (mem_axi_wready && mem_axi_wvalid) 2795 | ack_wvalid <= 1; 2796 | if (xfer_done || !mem_valid) begin 2797 | ack_awvalid <= 0; 2798 | ack_arvalid <= 0; 2799 | ack_wvalid <= 0; 2800 | end 2801 | end 2802 | end 2803 | endmodule 2804 | 2805 | 2806 | /*************************************************************** 2807 | * picorv32_wb 2808 | ***************************************************************/ 2809 | 2810 | module picorv32_wb #( 2811 | parameter [ 0:0] ENABLE_COUNTERS = 1, 2812 | parameter [ 0:0] ENABLE_COUNTERS64 = 1, 2813 | parameter [ 0:0] ENABLE_REGS_16_31 = 1, 2814 | parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, 2815 | parameter [ 0:0] TWO_STAGE_SHIFT = 1, 2816 | parameter [ 0:0] BARREL_SHIFTER = 0, 2817 | parameter [ 0:0] TWO_CYCLE_COMPARE = 0, 2818 | parameter [ 0:0] TWO_CYCLE_ALU = 0, 2819 | parameter [ 0:0] COMPRESSED_ISA = 0, 2820 | parameter [ 0:0] CATCH_MISALIGN = 1, 2821 | parameter [ 0:0] CATCH_ILLINSN = 1, 2822 | parameter [ 0:0] ENABLE_PCPI = 0, 2823 | parameter [ 0:0] ENABLE_MUL = 0, 2824 | parameter [ 0:0] ENABLE_FAST_MUL = 0, 2825 | parameter [ 0:0] ENABLE_DIV = 0, 2826 | parameter [ 0:0] ENABLE_IRQ = 0, 2827 | parameter [ 0:0] ENABLE_IRQ_QREGS = 1, 2828 | parameter [ 0:0] ENABLE_IRQ_TIMER = 1, 2829 | parameter [ 0:0] ENABLE_TRACE = 0, 2830 | parameter [ 0:0] REGS_INIT_ZERO = 0, 2831 | parameter [31:0] MASKED_IRQ = 32'h 0000_0000, 2832 | parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, 2833 | parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, 2834 | parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, 2835 | parameter [31:0] STACKADDR = 32'h ffff_ffff 2836 | ) ( 2837 | output trap, 2838 | 2839 | // Wishbone interfaces 2840 | input wb_rst_i, 2841 | input wb_clk_i, 2842 | 2843 | output reg [31:0] wbm_adr_o, 2844 | output reg [31:0] wbm_dat_o, 2845 | input [31:0] wbm_dat_i, 2846 | output reg wbm_we_o, 2847 | output reg [3:0] wbm_sel_o, 2848 | output reg wbm_stb_o, 2849 | input wbm_ack_i, 2850 | output reg wbm_cyc_o, 2851 | 2852 | // Pico Co-Processor Interface (PCPI) 2853 | output pcpi_valid, 2854 | output [31:0] pcpi_insn, 2855 | output [31:0] pcpi_rs1, 2856 | output [31:0] pcpi_rs2, 2857 | input pcpi_wr, 2858 | input [31:0] pcpi_rd, 2859 | input pcpi_wait, 2860 | input pcpi_ready, 2861 | 2862 | // IRQ interface 2863 | input [31:0] irq, 2864 | output [31:0] eoi, 2865 | 2866 | `ifdef RISCV_FORMAL 2867 | output rvfi_valid, 2868 | output [63:0] rvfi_order, 2869 | output [31:0] rvfi_insn, 2870 | output rvfi_trap, 2871 | output rvfi_halt, 2872 | output rvfi_intr, 2873 | output [ 4:0] rvfi_rs1_addr, 2874 | output [ 4:0] rvfi_rs2_addr, 2875 | output [31:0] rvfi_rs1_rdata, 2876 | output [31:0] rvfi_rs2_rdata, 2877 | output [ 4:0] rvfi_rd_addr, 2878 | output [31:0] rvfi_rd_wdata, 2879 | output [31:0] rvfi_pc_rdata, 2880 | output [31:0] rvfi_pc_wdata, 2881 | output [31:0] rvfi_mem_addr, 2882 | output [ 3:0] rvfi_mem_rmask, 2883 | output [ 3:0] rvfi_mem_wmask, 2884 | output [31:0] rvfi_mem_rdata, 2885 | output [31:0] rvfi_mem_wdata, 2886 | `endif 2887 | 2888 | // Trace Interface 2889 | output trace_valid, 2890 | output [35:0] trace_data, 2891 | 2892 | output mem_instr 2893 | ); 2894 | wire mem_valid; 2895 | wire [31:0] mem_addr; 2896 | wire [31:0] mem_wdata; 2897 | wire [ 3:0] mem_wstrb; 2898 | reg mem_ready; 2899 | reg [31:0] mem_rdata; 2900 | 2901 | wire clk; 2902 | wire resetn; 2903 | 2904 | assign clk = wb_clk_i; 2905 | assign resetn = ~wb_rst_i; 2906 | 2907 | picorv32 #( 2908 | .ENABLE_COUNTERS (ENABLE_COUNTERS ), 2909 | .ENABLE_COUNTERS64 (ENABLE_COUNTERS64 ), 2910 | .ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ), 2911 | .ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT), 2912 | .TWO_STAGE_SHIFT (TWO_STAGE_SHIFT ), 2913 | .BARREL_SHIFTER (BARREL_SHIFTER ), 2914 | .TWO_CYCLE_COMPARE (TWO_CYCLE_COMPARE ), 2915 | .TWO_CYCLE_ALU (TWO_CYCLE_ALU ), 2916 | .COMPRESSED_ISA (COMPRESSED_ISA ), 2917 | .CATCH_MISALIGN (CATCH_MISALIGN ), 2918 | .CATCH_ILLINSN (CATCH_ILLINSN ), 2919 | .ENABLE_PCPI (ENABLE_PCPI ), 2920 | .ENABLE_MUL (ENABLE_MUL ), 2921 | .ENABLE_FAST_MUL (ENABLE_FAST_MUL ), 2922 | .ENABLE_DIV (ENABLE_DIV ), 2923 | .ENABLE_IRQ (ENABLE_IRQ ), 2924 | .ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ), 2925 | .ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ), 2926 | .ENABLE_TRACE (ENABLE_TRACE ), 2927 | .REGS_INIT_ZERO (REGS_INIT_ZERO ), 2928 | .MASKED_IRQ (MASKED_IRQ ), 2929 | .LATCHED_IRQ (LATCHED_IRQ ), 2930 | .PROGADDR_RESET (PROGADDR_RESET ), 2931 | .PROGADDR_IRQ (PROGADDR_IRQ ), 2932 | .STACKADDR (STACKADDR ) 2933 | ) picorv32_core ( 2934 | .clk (clk ), 2935 | .resetn (resetn), 2936 | .trap (trap ), 2937 | 2938 | .mem_valid(mem_valid), 2939 | .mem_addr (mem_addr ), 2940 | .mem_wdata(mem_wdata), 2941 | .mem_wstrb(mem_wstrb), 2942 | .mem_instr(mem_instr), 2943 | .mem_ready(mem_ready), 2944 | .mem_rdata(mem_rdata), 2945 | 2946 | .pcpi_valid(pcpi_valid), 2947 | .pcpi_insn (pcpi_insn ), 2948 | .pcpi_rs1 (pcpi_rs1 ), 2949 | .pcpi_rs2 (pcpi_rs2 ), 2950 | .pcpi_wr (pcpi_wr ), 2951 | .pcpi_rd (pcpi_rd ), 2952 | .pcpi_wait (pcpi_wait ), 2953 | .pcpi_ready(pcpi_ready), 2954 | 2955 | .irq(irq), 2956 | .eoi(eoi), 2957 | 2958 | `ifdef RISCV_FORMAL 2959 | .rvfi_valid (rvfi_valid ), 2960 | .rvfi_order (rvfi_order ), 2961 | .rvfi_insn (rvfi_insn ), 2962 | .rvfi_trap (rvfi_trap ), 2963 | .rvfi_halt (rvfi_halt ), 2964 | .rvfi_intr (rvfi_intr ), 2965 | .rvfi_rs1_addr (rvfi_rs1_addr ), 2966 | .rvfi_rs2_addr (rvfi_rs2_addr ), 2967 | .rvfi_rs1_rdata(rvfi_rs1_rdata), 2968 | .rvfi_rs2_rdata(rvfi_rs2_rdata), 2969 | .rvfi_rd_addr (rvfi_rd_addr ), 2970 | .rvfi_rd_wdata (rvfi_rd_wdata ), 2971 | .rvfi_pc_rdata (rvfi_pc_rdata ), 2972 | .rvfi_pc_wdata (rvfi_pc_wdata ), 2973 | .rvfi_mem_addr (rvfi_mem_addr ), 2974 | .rvfi_mem_rmask(rvfi_mem_rmask), 2975 | .rvfi_mem_wmask(rvfi_mem_wmask), 2976 | .rvfi_mem_rdata(rvfi_mem_rdata), 2977 | .rvfi_mem_wdata(rvfi_mem_wdata), 2978 | `endif 2979 | 2980 | .trace_valid(trace_valid), 2981 | .trace_data (trace_data) 2982 | ); 2983 | 2984 | localparam IDLE = 2'b00; 2985 | localparam WBSTART = 2'b01; 2986 | localparam WBEND = 2'b10; 2987 | 2988 | reg [1:0] state; 2989 | 2990 | wire we; 2991 | assign we = (mem_wstrb[0] | mem_wstrb[1] | mem_wstrb[2] | mem_wstrb[3]); 2992 | 2993 | always @(posedge wb_clk_i) begin 2994 | if (wb_rst_i) begin 2995 | wbm_adr_o <= 0; 2996 | wbm_dat_o <= 0; 2997 | wbm_we_o <= 0; 2998 | wbm_sel_o <= 0; 2999 | wbm_stb_o <= 0; 3000 | wbm_cyc_o <= 0; 3001 | state <= IDLE; 3002 | end else begin 3003 | case (state) 3004 | IDLE: begin 3005 | if (mem_valid) begin 3006 | wbm_adr_o <= mem_addr; 3007 | wbm_dat_o <= mem_wdata; 3008 | wbm_we_o <= we; 3009 | wbm_sel_o <= mem_wstrb; 3010 | 3011 | wbm_stb_o <= 1'b1; 3012 | wbm_cyc_o <= 1'b1; 3013 | state <= WBSTART; 3014 | end else begin 3015 | mem_ready <= 1'b0; 3016 | 3017 | wbm_stb_o <= 1'b0; 3018 | wbm_cyc_o <= 1'b0; 3019 | wbm_we_o <= 1'b0; 3020 | end 3021 | end 3022 | WBSTART:begin 3023 | if (wbm_ack_i) begin 3024 | mem_rdata <= wbm_dat_i; 3025 | mem_ready <= 1'b1; 3026 | 3027 | state <= WBEND; 3028 | 3029 | wbm_stb_o <= 1'b0; 3030 | wbm_cyc_o <= 1'b0; 3031 | wbm_we_o <= 1'b0; 3032 | end 3033 | end 3034 | WBEND: begin 3035 | mem_ready <= 1'b0; 3036 | 3037 | state <= IDLE; 3038 | end 3039 | default: 3040 | state <= IDLE; 3041 | endcase 3042 | end 3043 | end 3044 | endmodule 3045 | --------------------------------------------------------------------------------